allow complex layouts in NC templates
This commit is contained in:
@@ -1,4 +1,121 @@
|
||||
angular.module("umbraco").controller("Umbraco.PropertyEditors.NestedContent.PropertyEditorController", [
|
||||
angular.module("umbraco").controller("Umbraco.PropertyEditors.NestedContent.DocTypePickerController", [
|
||||
|
||||
"$scope",
|
||||
"Umbraco.PropertyEditors.NestedContent.Resources",
|
||||
|
||||
function ($scope, ncResources)
|
||||
{
|
||||
|
||||
$scope.add = function ()
|
||||
{
|
||||
$scope.model.value.push({
|
||||
// As per PR #4, all stored content type aliases must be prefixed "nc" for easier recognition.
|
||||
// For good measure we'll also prefix the tab alias "nc"
|
||||
ncAlias: "",
|
||||
ncTabAlias: "",
|
||||
nameTemplate: ""
|
||||
});
|
||||
}
|
||||
|
||||
$scope.canAdd = function ()
|
||||
{
|
||||
return !$scope.model.docTypes || !$scope.model.value || $scope.model.value.length < $scope.model.docTypes.length;
|
||||
}
|
||||
|
||||
$scope.remove = function (index)
|
||||
{
|
||||
$scope.model.value.splice(index, 1);
|
||||
}
|
||||
|
||||
$scope.sortableOptions = {
|
||||
axis: "y",
|
||||
cursor: "move",
|
||||
handle: ".handle",
|
||||
placeholder: 'sortable-placeholder',
|
||||
forcePlaceholderSize: true,
|
||||
helper: function (e, ui)
|
||||
{
|
||||
// When sorting table rows, the cells collapse. This helper fixes that: https://www.foliotek.com/devblog/make-table-rows-sortable-using-jquery-ui-sortable/
|
||||
ui.children().each(function ()
|
||||
{
|
||||
$(this).width($(this).width());
|
||||
});
|
||||
return ui;
|
||||
},
|
||||
start: function (e, ui)
|
||||
{
|
||||
|
||||
var cellHeight = ui.item.height();
|
||||
|
||||
// Build a placeholder cell that spans all the cells in the row: https://stackoverflow.com/questions/25845310/jquery-ui-sortable-and-table-cell-size
|
||||
var cellCount = 0;
|
||||
$('td, th', ui.helper).each(function ()
|
||||
{
|
||||
// For each td or th try and get it's colspan attribute, and add that or 1 to the total
|
||||
var colspan = 1;
|
||||
var colspanAttr = $(this).attr('colspan');
|
||||
if (colspanAttr > 1)
|
||||
{
|
||||
colspan = colspanAttr;
|
||||
}
|
||||
cellCount += colspan;
|
||||
});
|
||||
|
||||
// Add the placeholder UI - note that this is the item's content, so td rather than tr - and set height of tr
|
||||
ui.placeholder.html('<td colspan="' + cellCount + '"></td>').height(cellHeight);
|
||||
}
|
||||
};
|
||||
|
||||
$scope.docTypeTabs = {};
|
||||
|
||||
ncResources.getContentTypes().then(function (docTypes)
|
||||
{
|
||||
$scope.model.docTypes = docTypes;
|
||||
|
||||
// Count doctype name occurrences
|
||||
var docTypeNameOccurrences = _.countBy(docTypes, 'name');
|
||||
|
||||
// Populate document type tab dictionary
|
||||
// And append alias to name if multiple doctypes have the same name
|
||||
docTypes.forEach(function (value)
|
||||
{
|
||||
$scope.docTypeTabs[value.alias] = value.tabs;
|
||||
|
||||
value.displayName = value.name;
|
||||
|
||||
if (docTypeNameOccurrences[value.name] > 1)
|
||||
{
|
||||
value.displayName += " (" + value.alias + ")";
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$scope.selectableDocTypesFor = function (config)
|
||||
{
|
||||
// return all doctypes that are:
|
||||
// 1. either already selected for this config, or
|
||||
// 2. not selected in any other config
|
||||
return _.filter($scope.model.docTypes, function (docType)
|
||||
{
|
||||
return docType.alias === config.ncAlias || !_.find($scope.model.value, function (c)
|
||||
{
|
||||
return docType.alias === c.ncAlias;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (!$scope.model.value)
|
||||
{
|
||||
$scope.model.value = [];
|
||||
$scope.add();
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
|
||||
|
||||
|
||||
angular.module("umbraco").controller("Umbraco.PropertyEditors.NestedContent.PropertyEditorController", [
|
||||
|
||||
"$scope",
|
||||
"$interpolate",
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"text": {
|
||||
"html": "text"
|
||||
},
|
||||
"button": {
|
||||
"text": "text",
|
||||
"link": "url"
|
||||
},
|
||||
"images": {
|
||||
"items": "media"
|
||||
},
|
||||
"xblocks": {
|
||||
"items": "list"
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
angular.module('umbraco.services').config(['$httpProvider', function ($httpProvider)
|
||||
{
|
||||
$httpProvider.interceptors.push(['$q', '$injector', 'notificationsService', function ($q, $injector, notificationsService)
|
||||
{
|
||||
return {
|
||||
'request': function (request)
|
||||
{
|
||||
if (request.url.indexOf("views/propertyeditors/nestedcontent/nestedcontent.html") === 0)
|
||||
{
|
||||
request.url = '/App_Plugins/brothers.uNesting/uNesting.html';
|
||||
}
|
||||
|
||||
return request || $q.when(request);
|
||||
}
|
||||
};
|
||||
}]);
|
||||
}]);
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"javascript": [
|
||||
"~/App_Plugins/brothers.uNesting/interceptor.js",
|
||||
"~/App_Plugins/brothers.uNesting/uNesting.controller.js"
|
||||
"~/App_Plugins/brothers.uNesting/uNesting.js"
|
||||
],
|
||||
"css": [
|
||||
"~/App_Plugins/brothers.uNesting/uNesting.css"
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
|
||||
angular.module("umbraco").controller("brothers.uNesting.PropertyEditorController", function ($scope, $controller, $http)
|
||||
{
|
||||
angular.extend(this, $controller('Umbraco.PropertyEditors.NestedContent.PropertyEditorController', { $scope: $scope }));
|
||||
|
||||
var elementsConfig = {};
|
||||
|
||||
var init = function ()
|
||||
{
|
||||
$http.get("/App_Plugins/brothers.uNesting/elements.json").then(function (res)
|
||||
{
|
||||
elementsConfig = res.data;
|
||||
|
||||
_.each($scope.nodes, function (node, idx)
|
||||
{
|
||||
node.uNestingContent = getContent(node, $scope.model.value[idx], elementsConfig[node.contentTypeAlias]);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$scope.$watch("inited", function (newVal)
|
||||
{
|
||||
if (newVal)
|
||||
{
|
||||
init();
|
||||
}
|
||||
});
|
||||
|
||||
var getContent = function (node, item, config)
|
||||
{
|
||||
if (!item)
|
||||
{
|
||||
return '';
|
||||
}
|
||||
if (!config)
|
||||
{
|
||||
return node.documentType.description;
|
||||
}
|
||||
|
||||
var lines = [];
|
||||
|
||||
_.each(config, function (type, alias)
|
||||
{
|
||||
var value = item[alias];
|
||||
if (value)
|
||||
{
|
||||
if (type === 'text')
|
||||
{
|
||||
lines.push(stripHtml(value));
|
||||
}
|
||||
if (type === 'url')
|
||||
{
|
||||
lines.push(value[0].url);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (lines.length < 1)
|
||||
{
|
||||
return node.documentType.description;
|
||||
}
|
||||
else
|
||||
{
|
||||
return lines.join('<br>');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
var stripHtml = function (html)
|
||||
{
|
||||
if (!html)
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
var stripped = html.replace('<br>', ' ').replace('<br />', ' ').replace('<br/>', ' ').replace(/<[^>]+>/gm, '');
|
||||
|
||||
return stripped.length > 120 ? (stripped.substring(0, 120) + '...') : stripped;
|
||||
};
|
||||
|
||||
//$scope.getView = function (node, idx)
|
||||
//{
|
||||
// if ($scope.model.value[idx])
|
||||
// {
|
||||
// var contentType = $scope.getContentTypeConfig($scope.model.value[idx].ncContentTypeAlias);
|
||||
|
||||
// if (contentType !== null && contentType.nameExp)
|
||||
// {
|
||||
// // Run the expression against the stored dictionary value, NOT the node object
|
||||
// var item = $scope.model.value[idx];
|
||||
// var newName = contentType.nameExp(item);
|
||||
|
||||
// if (newName && (newName = $.trim(newName)))
|
||||
// {
|
||||
// return newName;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return node.documentType.description || 'Enter data ...';
|
||||
//};
|
||||
});
|
||||
@@ -18,14 +18,48 @@
|
||||
margin-top: -1px;
|
||||
}
|
||||
|
||||
.unesting-items
|
||||
{
|
||||
margin-top: -15px;
|
||||
}
|
||||
/*.unesting-item .unesting-items
|
||||
{
|
||||
background-color: #f9f7f7;
|
||||
box-shadow: 0 1px 1px 0 rgba(0,0,0,.16);
|
||||
}*/
|
||||
/* header */
|
||||
|
||||
.unesting-item-header
|
||||
{
|
||||
border-bottom: 1px solid #e9e9eb;
|
||||
border-bottom: 1px solid #f6f6f7;
|
||||
cursor: pointer;
|
||||
background-color: #fff;
|
||||
user-select: none;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.unesting-item.is-active > .unesting-item-header:after,
|
||||
.unesting-item.is-active > .unesting-item-header:before
|
||||
{
|
||||
position: absolute;
|
||||
content: ' ';
|
||||
display: inline-block;
|
||||
left: 5px;
|
||||
bottom: -19px;
|
||||
border: 10px solid transparent;
|
||||
border-top-color: white;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.unesting-item.is-active > .unesting-item-header:before
|
||||
{
|
||||
bottom: -21px;
|
||||
border-top-color: #e9e9eb;
|
||||
}
|
||||
|
||||
.unesting-item:last-child .unesting-item-header
|
||||
{
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.unesting-item-header-inner
|
||||
@@ -36,19 +70,42 @@
|
||||
padding: 15px 5px;
|
||||
color: #1b264f;
|
||||
border-radius: 3px 3px 0 0;
|
||||
border-bottom: none;
|
||||
background: none;
|
||||
}
|
||||
|
||||
.unesting-item-header-inner i
|
||||
/*.unesting-item:nth-child(2n+1) .unesting-item-header-inner
|
||||
{
|
||||
background: #faf9f9;
|
||||
}*/
|
||||
|
||||
.unesting-item-header-inner > i
|
||||
{
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
margin-top: -11px;
|
||||
font-size: 1.2rem;
|
||||
margin-top: -13px;
|
||||
left: 3px;
|
||||
font-size: 1.4rem;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.unesting-item-header-content.--has-icon
|
||||
{
|
||||
padding-left: 40px;
|
||||
margin-left: 40px;
|
||||
padding-left: 20px;
|
||||
border-left: 1px solid #f6f6f7;
|
||||
}
|
||||
|
||||
.unesting-item-header-content-iconbg
|
||||
{
|
||||
display: none;
|
||||
position: absolute;
|
||||
left: -46px;
|
||||
width: 46px;
|
||||
top: -16px;
|
||||
background: #faf9f9;
|
||||
z-index: 0;
|
||||
bottom: -15px;
|
||||
}
|
||||
|
||||
.unesting-item-header:hover .unesting-item-header-inner .unesting-item-header-content
|
||||
@@ -61,11 +118,14 @@
|
||||
line-height: 20px;
|
||||
color: #1b264f;
|
||||
white-space: nowrap;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.unesting-item-header-content-name
|
||||
{
|
||||
max-height: 20px;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.unesting-item-header-content-text
|
||||
@@ -73,6 +133,9 @@
|
||||
color: #817f85;
|
||||
font-size: 13px;
|
||||
overflow: hidden;
|
||||
margin-top: 4px;
|
||||
display: block;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
/* icons */
|
||||
@@ -83,9 +146,9 @@
|
||||
transition: opacity .12s ease-in-out;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 3px;
|
||||
top: 50%;
|
||||
padding: 5px;
|
||||
margin-top: 8px;
|
||||
margin-top: -22px;
|
||||
display: flex;
|
||||
grid-gap: 8px;
|
||||
}
|
||||
@@ -128,6 +191,7 @@
|
||||
display: inline-block;
|
||||
margin: 0 1px;
|
||||
opacity: .6;
|
||||
position: static;
|
||||
}
|
||||
|
||||
.unesting-icon .icon
|
||||
@@ -160,11 +224,91 @@
|
||||
background: none;
|
||||
}
|
||||
|
||||
.unesting-content > .umb-pane
|
||||
{
|
||||
margin: 30px 20px;
|
||||
}
|
||||
|
||||
.unesting-item.is-active > .unesting-content
|
||||
{
|
||||
background: #faf9f9;
|
||||
margin: 0 -20px;
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
border-radius: 0;
|
||||
border-top: 1px solid #e9e9eb;
|
||||
}
|
||||
|
||||
.unesting-content .unesting-item.is-active > .unesting-content
|
||||
{
|
||||
background: white;
|
||||
margin: 0 -20px;
|
||||
border-left: 1px solid #e9e9eb;
|
||||
}
|
||||
|
||||
.unesting-item.is-active > .unesting-item-header
|
||||
{
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
|
||||
/* media */
|
||||
.unesting-media
|
||||
{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.unesting-media-item
|
||||
{
|
||||
border-radius: 3px;
|
||||
margin-right: 6px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.unesting-media-item.has-title
|
||||
{
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.unesting-media-item-image
|
||||
{
|
||||
background: #f6f4f4;
|
||||
border-radius: 3px;
|
||||
border: 1px solid #f6f6f7;
|
||||
}
|
||||
|
||||
.unesting-media-item-text
|
||||
{
|
||||
padding: 0 10px;
|
||||
max-width: 100px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.unesting-media-more
|
||||
{
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
vertical-align: middle;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
background: #f6f4f4;
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 12px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
|
||||
/* footer */
|
||||
|
||||
.unesting-footer
|
||||
{
|
||||
{
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
@@ -174,11 +318,22 @@
|
||||
}
|
||||
|
||||
|
||||
/* data type overrides */
|
||||
/* doctypepicker */
|
||||
.unesting-doctype-textarea
|
||||
{
|
||||
width: 100%;
|
||||
height: 32px;
|
||||
max-height: 200px;
|
||||
min-height: 32px;
|
||||
padding-top: 6px;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
|
||||
/* data type overrides */
|
||||
.unesting-item .umb-sortable-thumbnails li
|
||||
{
|
||||
background: none;
|
||||
/*background: none;*/
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
<div id="{{model.alias}}" class="umb-nested-content__doctypepicker" ng-controller="brothers.uNesting.DocTypePickerController">
|
||||
<div>
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th />
|
||||
<th>
|
||||
<localize key="contentTypeEditor_elementType">Element Type</localize>
|
||||
</th>
|
||||
<th>
|
||||
<localize key="general_group">Group</localize>
|
||||
</th>
|
||||
<th>
|
||||
<localize key="template_template">Template</localize>
|
||||
</th>
|
||||
<th />
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody ui-sortable="sortableOptions" ng-model="model.value">
|
||||
<tr ng-repeat="config in model.value">
|
||||
<td>
|
||||
<i class="icon icon-navigation handle"></i>
|
||||
</td>
|
||||
<td>
|
||||
<select id="{{model.alias}}_doctype_select"
|
||||
ng-options="dt.alias as dt.name for dt in selectableDocTypesFor(config) | orderBy: 'name'"
|
||||
ng-model="config.ncAlias" required></select>
|
||||
</td>
|
||||
<td>
|
||||
<select id="{{model.alias}}_tab_select"
|
||||
ng-options="t for t in docTypeTabs[config.ncAlias]"
|
||||
ng-model="config.ncTabAlias" required></select>
|
||||
</td>
|
||||
<td>
|
||||
<textarea class="unesting-doctype-textarea" ng-model="config.nameTemplate" rows="1" cols="40"></textarea>
|
||||
</td>
|
||||
<td>
|
||||
<button type="button" class="btn btn-danger" ng-click="remove($index)">
|
||||
<localize key="general_delete">Delete</localize>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div>
|
||||
<button type="button" class="btn" ng-click="add()" ng-disabled="!canAdd()">
|
||||
<localize key="general_add">Add</localize>
|
||||
</button>
|
||||
<i class="icon icon-help-alt medium umb-nested-content__help-icon" ng-click="showHelpText = !showHelpText"></i>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<div class="umb-nested-content__help-text" ng-show="showHelpText">
|
||||
<p>
|
||||
<b><localize key="general_group">Group</localize>:</b><br />
|
||||
Select the group whose properties should be displayed. If left blank, the first group on the element type will be used.
|
||||
</p>
|
||||
<p>
|
||||
<b><localize key="template_template">Template</localize>:</b><br />
|
||||
Enter an angular expression to evaluate against each item for its name. Use <code ng-non-bindable>{{$index}}</code> to display the item index
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -14,50 +14,53 @@
|
||||
|
||||
<div class="unesting-items" ng-hide="nodes.length === 0" ng-class="{ 'is-hidden': nodes.length === 0 }" ui-sortable="sortableOptions" ng-model="nodes">
|
||||
|
||||
<div class="unesting-item" ng-repeat="node in nodes" ng-class="{ 'umb-nested-content__item--active' : $parent.realCurrentNode.key === node.key, 'umb-nested-content__item--single' : $parent.singleMode, 'is-hidden': $index === 1 }">
|
||||
<div class="unesting-item" ng-repeat="node in nodes" ng-class="{ 'is-active' : $parent.realCurrentNode.key === node.key, 'umb-nested-content__item--single' : $parent.singleMode, 'is-hidden': $index === 1 }">
|
||||
|
||||
<div class="unesting-item-header" ng-click="$parent.editNode($index)" ng-hide="$parent.singleMode">
|
||||
|
||||
<div class="unesting-item-header-inner">
|
||||
<div class="umb-nested-content__header-bar unesting-item-header-inner">
|
||||
<i ng-if="showIcons" class="icon" ng-class="$parent.getIcon($index)"></i>
|
||||
<div class="unesting-item-header-content" ng-class="{'--has-icon': showIcons}">
|
||||
<span class="unesting-item-header-content-iconbg" ng-if="showIcons"></span>
|
||||
<div class="unesting-item-header-content-name" ng-bind="node.contentTypeName"></div>
|
||||
<div class="unesting-item-header-content-text" ng-if="node.uNestingContent" ng-bind-html="node.uNestingContent"></div>
|
||||
<un-content class="unesting-item-header-content-text" item="model.value[$index]" node="node" config="getContentTypeConfig(node.documentType.alias)"></un-content>
|
||||
<!--<div class="unesting-item-header-content-text" ng-if="!$parent.hasTemplate(node, $index)" ng-bind-html="$parent.getPlainContent(node, $index)"></div>-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="unesting-icons">
|
||||
<div class="unesting-more-container">
|
||||
<a class="unesting-icon is-more" ng-click="node._showMenu=!node._showMenu; $event.stopPropagation();" prevent-default>
|
||||
<i></i><i></i><i></i>
|
||||
<div class="unesting-icons">
|
||||
<div class="unesting-more-container">
|
||||
<a class="unesting-icon is-more" ng-click="node._showMenu=!node._showMenu; $event.stopPropagation();" prevent-default>
|
||||
<i></i><i></i><i></i>
|
||||
</a>
|
||||
|
||||
<ul class="dropdown-menu umb-actions unesting-more-dropdown" ng-if="node._showMenu">
|
||||
<li class="umb-action">
|
||||
<a ng-click="" prevent-default>
|
||||
<i class="icon icon-add"></i>
|
||||
<span class="menu-label">Create</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="umb-action">
|
||||
<a ng-click="" prevent-default>
|
||||
<i class="icon icon-eye"></i>
|
||||
<span class="menu-label">Hide</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<a class="unesting-icon" localize="title" title="general_visibility" ng-click="" prevent-default>
|
||||
<i class="icon icon-lock"></i>
|
||||
</a>
|
||||
|
||||
<ul class="dropdown-menu umb-actions unesting-more-dropdown" ng-if="node._showMenu">
|
||||
<li class="umb-action">
|
||||
<a ng-click="" prevent-default>
|
||||
<i class="icon icon-add"></i>
|
||||
<span class="menu-label">Create</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="umb-action">
|
||||
<a ng-click="" prevent-default>
|
||||
<i class="icon icon-eye"></i>
|
||||
<span class="menu-label">Hide</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<a class="unesting-icon" localize="title" title="general_delete"
|
||||
ng-class="{ 'umb-nested-content__icon--disabled': $parent.nodes.length <= $parent.minItems }"
|
||||
ng-click="$parent.requestDeleteNode($index); $event.stopPropagation();" prevent-default>
|
||||
<i class="icon icon-trash-alt"></i>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<a class="unesting-icon" localize="title" title="general_visibility" ng-click="" prevent-default>
|
||||
<i class="icon icon-lock"></i>
|
||||
</a>
|
||||
|
||||
<a class="unesting-icon" localize="title" title="general_delete"
|
||||
ng-class="{ 'umb-nested-content__icon--disabled': $parent.nodes.length <= $parent.minItems }"
|
||||
ng-click="$parent.requestDeleteNode($index); $event.stopPropagation();" prevent-default>
|
||||
<i class="icon icon-trash-alt"></i>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!--<div class="umb-nested-content__icons">
|
||||
<a class="umb-nested-content__icon umb-nested-content__icon--copy" title="{{copyIconTitle}}" ng-click="clickCopy($event, node);" ng-if="showCopy" prevent-default>
|
||||
<i class="icon icon-documents"></i>
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
|
||||
angular.module('umbraco.services').config(['$httpProvider', function ($httpProvider)
|
||||
{
|
||||
$httpProvider.interceptors.push(['$q', '$injector', 'notificationsService', function ($q, $injector, notificationsService)
|
||||
{
|
||||
return {
|
||||
'request': function (request)
|
||||
{
|
||||
if (request.url.indexOf("views/propertyeditors/nestedcontent/nestedcontent.html") === 0)
|
||||
{
|
||||
request.url = '/App_Plugins/brothers.uNesting/uNesting.html';
|
||||
}
|
||||
else if (request.url.indexOf("views/propertyeditors/nestedcontent/nestedcontent.doctypepicker.html") === 0)
|
||||
{
|
||||
request.url = '/App_Plugins/brothers.uNesting/uNesting.doctypepicker.html';
|
||||
}
|
||||
|
||||
return request || $q.when(request);
|
||||
}
|
||||
};
|
||||
}]);
|
||||
}]);
|
||||
|
||||
|
||||
|
||||
|
||||
angular.module("umbraco").controller("brothers.uNesting.DocTypePickerController", function ($scope)
|
||||
{
|
||||
angular.extend(this, $controller('Umbraco.PropertyEditors.NestedContent.DocTypePickerController', { $scope: $scope }));
|
||||
});
|
||||
|
||||
|
||||
angular.module("umbraco").controller("brothers.uNesting.PropertyEditorController", function ($scope, $controller, $http, $compile)
|
||||
{
|
||||
angular.extend(this, $controller('Umbraco.PropertyEditors.NestedContent.PropertyEditorController', { $scope: $scope }));
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
angular.module('umbraco.directives').directive('unContent', function ($compile)
|
||||
{
|
||||
return {
|
||||
restrict: 'E',
|
||||
scope: {
|
||||
item: '=',
|
||||
node: '=',
|
||||
config: '='
|
||||
},
|
||||
link: function (scope, element)
|
||||
{
|
||||
// get template
|
||||
var template = scope.config && scope.config.nameTemplate ? scope.config.nameTemplate : null;
|
||||
|
||||
// compile & render template
|
||||
function render()
|
||||
{
|
||||
// merge element values into local scope
|
||||
angular.merge(scope, scope.item);
|
||||
|
||||
// nothing when no template is specified
|
||||
if (!template)
|
||||
{
|
||||
element.html('');
|
||||
//element.html(scope.node.documentType.description);
|
||||
return;
|
||||
}
|
||||
|
||||
// create html and compile
|
||||
element.html(template);
|
||||
$compile(element.contents())(scope);
|
||||
}
|
||||
|
||||
//scope.$watch('item', function (value)
|
||||
//{
|
||||
// render();
|
||||
//});
|
||||
|
||||
// first-time rendering
|
||||
render();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
angular.module('umbraco.directives').directive('unMedia', function ($http, $compile, umbRequestHelper)
|
||||
{
|
||||
return {
|
||||
restrict: 'E',
|
||||
scope: {
|
||||
items: '=',
|
||||
key: '@',
|
||||
titleKey: '@',
|
||||
limit: '@'
|
||||
},
|
||||
template: '' +
|
||||
'<div class= "unesting-media" ng- class="{\'has-title\': !!item.title}">' +
|
||||
'<div class="unesting-media-item" ng-repeat="item in media">' +
|
||||
'<img src="{{item.src}}" title="{{item.title}}" class="unesting-media-item-image" />' +
|
||||
'<span class="unesting-media-item-text" ng-if="item.title">{{item.title | unHtml }}</span>' +
|
||||
'</div>' +
|
||||
'<span class="unesting-media-more" ng-if="count > media.length">+{{count - media.length}}</span>' +
|
||||
'</div>',
|
||||
link: function (scope, element)
|
||||
{
|
||||
var resize = 'width=50&height=50&mode=crop&quality=60';
|
||||
var limit = scope.limit || 5;
|
||||
scope.media = [];
|
||||
|
||||
var titleCache = {};
|
||||
|
||||
// compile & render template
|
||||
function render()
|
||||
{
|
||||
var ids = scope.items;
|
||||
|
||||
if (!scope.items)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (_.isArray(scope.items))
|
||||
{
|
||||
if (!scope.key)
|
||||
{
|
||||
console.error("You need the <un-media key='my_key' /> property for nested media");
|
||||
return;
|
||||
}
|
||||
|
||||
ids = _.map(scope.items, function (item)
|
||||
{
|
||||
var value = item[scope.key];
|
||||
|
||||
if (scope.titleKey)
|
||||
{
|
||||
titleCache[value] = item[scope.titleKey];
|
||||
}
|
||||
|
||||
return value;
|
||||
}).join(',');
|
||||
}
|
||||
|
||||
ids = ids.split(',');
|
||||
scope.count = ids.length;
|
||||
|
||||
var query = "ids=" + ids.slice(0, limit).join('&ids=');
|
||||
var url = $http.get(umbRequestHelper.getApiUrl("mediaApiBaseUrl", "GetByUdis", query).replace("/Media/", "/MediaExtended/"));
|
||||
// TODO we have to implement this method in a controller
|
||||
umbRequestHelper.resourcePromise(url, 'Failed to retrieve data for media ids').then(function (result)
|
||||
{
|
||||
_.each(result, function (src, id)
|
||||
{
|
||||
scope.media.push({
|
||||
id: id,
|
||||
src: src + "?" + resize,
|
||||
title: titleCache[id]
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
render();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
|
||||
angular.module('umbraco').filter('unHtml', function ()
|
||||
{
|
||||
return function (html, maxLength)
|
||||
{
|
||||
if (!html)
|
||||
{
|
||||
return '';
|
||||
}
|
||||
if (!maxLength)
|
||||
{
|
||||
maxLength = 120;
|
||||
}
|
||||
|
||||
var stripped = html.replace('<br>', ' ').replace('<br />', ' ').replace('<br/>', ' ').replace(/<[^>]+>/gm, '');
|
||||
|
||||
return stripped.length > maxLength ? (stripped.substring(0, maxLength) + '...') : stripped;
|
||||
};
|
||||
});
|
||||
Reference in New Issue
Block a user