Skip to content

Commit 2744ce8

Browse files
committed
Working prototype
1 parent d74747a commit 2744ce8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+2029
-0
lines changed

Umbraco Relation Editor.sln

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio 2013
4+
VisualStudioVersion = 12.0.21005.1
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Umbraco.RelationEditor.Web", "Umbraco.RelationEditor.Web\Umbraco.RelationEditor.Web.csproj", "{ECF870ED-CFF0-4C65-90F6-1B85C5BC4A93}"
7+
EndProject
8+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Umbraco.RelationEditor", "Umbraco.RelationEditor\Umbraco.RelationEditor.csproj", "{CD233AE0-2E7F-4A97-A45E-B6A759B41F67}"
9+
EndProject
10+
Global
11+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
12+
Debug|Any CPU = Debug|Any CPU
13+
Release|Any CPU = Release|Any CPU
14+
EndGlobalSection
15+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
16+
{ECF870ED-CFF0-4C65-90F6-1B85C5BC4A93}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17+
{ECF870ED-CFF0-4C65-90F6-1B85C5BC4A93}.Debug|Any CPU.Build.0 = Debug|Any CPU
18+
{ECF870ED-CFF0-4C65-90F6-1B85C5BC4A93}.Release|Any CPU.ActiveCfg = Release|Any CPU
19+
{ECF870ED-CFF0-4C65-90F6-1B85C5BC4A93}.Release|Any CPU.Build.0 = Release|Any CPU
20+
{CD233AE0-2E7F-4A97-A45E-B6A759B41F67}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21+
{CD233AE0-2E7F-4A97-A45E-B6A759B41F67}.Debug|Any CPU.Build.0 = Debug|Any CPU
22+
{CD233AE0-2E7F-4A97-A45E-B6A759B41F67}.Release|Any CPU.ActiveCfg = Release|Any CPU
23+
{CD233AE0-2E7F-4A97-A45E-B6A759B41F67}.Release|Any CPU.Build.0 = Release|Any CPU
24+
EndGlobalSection
25+
GlobalSection(SolutionProperties) = preSolution
26+
HideSolutionNode = FALSE
27+
EndGlobalSection
28+
EndGlobal
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<div ng-controller="RelationEditor.EditRelationsController">
2+
<div class="umb-dialog-body">
3+
<div class="umb-pane">
4+
<p class="abstract" ng-hide="success">
5+
Assign related content to {{currentNode.name}} below.
6+
</p>
7+
8+
<div class="sortableFrame" ng-repeat="resourceSet in resourceSets">
9+
<h4>{{resourceSet.Name}}</h4>
10+
<table class="sortableNodes">
11+
<thead>
12+
<tr>
13+
<th style="width:15%;">ID</th>
14+
<th style="width:75%;">Name</th>
15+
<th style="width:10%">&nbsp;</th>
16+
</tr>
17+
</thead>
18+
<tbody reledit-sortable="{containment:'parent'}" ng-model="resourceSet.Relations">
19+
<tr ng-repeat="relation in resourceSet.Relations" ng-show="isActive(relation)">
20+
<td style="width:15%;">{{relation.ChildId}}</td>
21+
<td style="width:75%;">{{relation.ChildName}}</td>
22+
<td style="width:10%;"><button class="btn btn-danger" ng-click="remove(relation)">Remove</button></td>
23+
</tr>
24+
</tbody>
25+
<tfoot>
26+
<tr>
27+
<td colspan="2">
28+
<button class="btn btn-primary" ng-click="pickRelation($index)">Add</button>
29+
</td>
30+
</tr>
31+
</tfoot>
32+
</table>
33+
</div>
34+
35+
</div>
36+
</div>
37+
38+
<div class="umb-dialog-footer btn-toolbar umb-btn-toolbar" ng-show="ready">
39+
<a class="btn btn-link" ng-click="nav.hideDialog()">Cancel</a>
40+
<button class="btn btn-primary" ng-click="save()">Save</button>
41+
</div>
42+
</div>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
javascript: [
3+
"~/App_Plugins/RelationEditor/relationeditor.js"
4+
]
5+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
.sortableFrame
2+
{
3+
width: 100%;
4+
overflow: auto;
5+
display: table;
6+
}
7+
8+
.sortableNodes
9+
{
10+
width: 100%;
11+
padding: 4px;
12+
display: block;
13+
border-spacing:0;
14+
border-collapse:collapse;
15+
}
16+
17+
.sortableNodes thead,
18+
.sortableNodes tbody,
19+
.sortableNodes tfoot {
20+
width: 100%;
21+
display: table;
22+
}
23+
24+
.sortableNodes thead tr th
25+
{
26+
border-bottom: 1px solid #ccc;
27+
padding: 4px;
28+
padding-right: 25px;
29+
background-image: url(../../umbraco_client/tableSorting/img/bg.gif);
30+
font-weight: bold;
31+
background-repeat: no-repeat;
32+
background-position: center right;
33+
}
34+
35+
.sortableNodes tbody tr td
36+
{
37+
border-bottom: 1px solid #efefef;
38+
}
39+
40+
.sortableNodes td
41+
{
42+
padding: 4px;
43+
cursor: move;
44+
}
45+
46+
tr.tDnD_whileDrag, tr.tDnD_whileDrag td
47+
{
48+
background: #dcecf3;
49+
border-color: #a8d8eb !Important;
50+
margin-top: 20px;
51+
}
52+
53+
.sortableNodes .nowrap
54+
{
55+
white-space: nowrap;
56+
}
Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
(function () {
2+
function EditRelationsController($scope, dialogService, relationsResources, assetsService, navigationService) {
3+
var dialog;
4+
5+
function relationPicked(index, data) {
6+
var set = $scope.resourceSets[index],
7+
relations = set.Relations,
8+
existingIndex = -1,
9+
existing = $.grep(relations, function(e, i) {
10+
var isIt = e.ChildId === data.id;
11+
if (isIt) {
12+
existingIndex = i;
13+
}
14+
return isIt;
15+
});
16+
17+
if (existing.length > 0) {
18+
if (existing[0].State === "Deleted") {
19+
existing[0].State = existing[0].OldState;
20+
relations.splice(existingIndex, 1);
21+
relations.push(existing[0]);
22+
}
23+
return;
24+
}
25+
26+
$scope.resourceSets[index].Relations.push({
27+
ChildId: data.id,
28+
ChildName: data.name,
29+
State: "New"
30+
});
31+
}
32+
33+
$scope.ready = false;
34+
$scope.data = {};
35+
36+
$scope.pickRelation = function (index) {
37+
dialogService.close(dialog);
38+
dialog = dialogService.treePicker({
39+
treeAlias: "content",
40+
section: "content",
41+
customTreeParams: "test=tast",
42+
callback: function (data) {
43+
relationPicked(index, data);
44+
}
45+
});
46+
};
47+
48+
$scope.remove = function (relation) {
49+
relation.OldState = relation.State;
50+
relation.State = "Deleted";
51+
};
52+
53+
$scope.isActive = function(relation) {
54+
return relation.State !== "Deleted";
55+
};
56+
57+
$scope.save = function () {
58+
$scope.ready = false;
59+
relationsResources.save($scope.data)
60+
.then(function() {
61+
navigationService.hideDialog();
62+
});
63+
};
64+
65+
assetsService.loadCss(Umbraco.Sys.ServerVariables.umbracoSettings.appPluginsPath + "/RelationEditor/relationeditor.css");
66+
67+
var promise = relationsResources.getById($scope.currentNode.id);
68+
promise.then(function (data) {
69+
$scope.data = data;
70+
$scope.resourceSets = data.Sets;
71+
$scope.ready = true;
72+
});
73+
}
74+
75+
function RelationsResources($q, $http, umbDataFormatter, umbRequestHelper) {
76+
return {
77+
getById: function(id) {
78+
return umbRequestHelper.resourcePromise(
79+
$http.get(
80+
Umbraco.Sys.ServerVariables.umbracoSettings.umbracoPath + "/relationseditor/relations/getrelations", {
81+
params: {
82+
from: "Document",
83+
to: "Document",
84+
parentId: id
85+
}
86+
}),
87+
'Failed to retreive relations for content id ' + id);
88+
},
89+
save: function(set) {
90+
return umbRequestHelper.resourcePromise(
91+
$http.post(
92+
Umbraco.Sys.ServerVariables.umbracoSettings.umbracoPath + "/relationseditor/relations/saverelations", set),
93+
"Failed to save relations for content id " + set.ParentId
94+
);
95+
}
96+
};
97+
}
98+
99+
angular.module("umbraco")
100+
.factory("RelationEditor.RelationResources", ["$q", "$http", "umbDataFormatter", "umbRequestHelper", RelationsResources])
101+
.controller("RelationEditor.EditRelationsController", [
102+
"$scope",
103+
"dialogService",
104+
"RelationEditor.RelationResources",
105+
"assetsService",
106+
"navigationService",
107+
EditRelationsController]);
108+
109+
/*
110+
jQuery UI Sortable plugin wrapper
111+
112+
113+
@param [ui-sortable] {object} Options to pass to $.fn.sortable() merged onto ui.config
114+
*/
115+
angular.module('umbraco')
116+
.value('releditSortableConfig', {})
117+
.directive('releditSortable', ['releditSortableConfig', '$log',
118+
function (releditSortableConfig, log) {
119+
return {
120+
require: '?ngModel',
121+
link: function (scope, element, attrs, ngModel) {
122+
123+
124+
function combineCallbacks(first, second) {
125+
if (second && (typeof second === 'function')) {
126+
return function (e, ui) {
127+
first(e, ui);
128+
second(e, ui);
129+
};
130+
}
131+
return first;
132+
}
133+
134+
135+
var opts = {}; //scope.$eval(element.attr('reledit-sortable')) || {};}
136+
137+
138+
var callbacks = {
139+
receive: null,
140+
remove: null,
141+
start: null,
142+
stop: null,
143+
update: null
144+
};
145+
146+
147+
var apply = function (e, ui) {
148+
if (ui.item.sortable.resort || ui.item.sortable.relocate) {
149+
scope.$apply();
150+
}
151+
};
152+
153+
154+
angular.extend(opts, releditSortableConfig);
155+
156+
157+
if (ngModel) {
158+
159+
160+
ngModel.$render = function () {
161+
element.sortable('refresh');
162+
};
163+
164+
165+
callbacks.start = function (e, ui) {
166+
// Save position of dragged item
167+
ui.item.sortable = { index: ui.item.index() };
168+
};
169+
170+
171+
callbacks.update = function (e, ui) {
172+
// For some reason the reference to ngModel in stop() is wrong
173+
ui.item.sortable.resort = ngModel;
174+
};
175+
176+
177+
callbacks.receive = function (e, ui) {
178+
ui.item.sortable.relocate = true;
179+
// if the item still exists (it has not been cancelled)
180+
if ('moved' in ui.item.sortable) {
181+
// added item to array into correct position and set up flag
182+
ngModel.$modelValue.splice(ui.item.index(), 0, ui.item.sortable.moved);
183+
}
184+
};
185+
186+
187+
callbacks.remove = function (e, ui) {
188+
// copy data into item
189+
if (ngModel.$modelValue.length === 1) {
190+
ui.item.sortable.moved = ngModel.$modelValue.splice(0, 1)[0];
191+
} else {
192+
ui.item.sortable.moved = ngModel.$modelValue.splice(ui.item.sortable.index, 1)[0];
193+
}
194+
};
195+
196+
197+
callbacks.stop = function (e, ui) {
198+
// digest all prepared changes
199+
if (ui.item.sortable.resort && !ui.item.sortable.relocate) {
200+
201+
202+
// Fetch saved and current position of dropped element
203+
var end, start;
204+
start = ui.item.sortable.index;
205+
end = ui.item.index();
206+
207+
208+
// Reorder array and apply change to scope
209+
ui.item.sortable.resort.$modelValue.splice(end, 0, ui.item.sortable.resort.$modelValue.splice(start, 1)[0]);
210+
211+
212+
}
213+
};
214+
215+
216+
scope.$watch(attrs.releditSortable, function (newVal) {
217+
angular.forEach(newVal, function (value, key) {
218+
219+
220+
if (callbacks[key]) {
221+
// wrap the callback
222+
value = combineCallbacks(callbacks[key], value);
223+
224+
225+
if (key === 'stop') {
226+
// call apply after stop
227+
value = combineCallbacks(value, apply);
228+
}
229+
}
230+
231+
232+
element.sortable('option', key, value);
233+
});
234+
}, true);
235+
236+
237+
angular.forEach(callbacks, function (value, key) {
238+
239+
240+
opts[key] = combineCallbacks(value, opts[key]);
241+
});
242+
243+
244+
// call apply after stop
245+
opts.stop = combineCallbacks(opts.stop, apply);
246+
247+
248+
} else {
249+
log.info('ui.sortable: ngModel not provided!', element);
250+
}
251+
252+
253+
// Create sortable
254+
element.sortable(opts);
255+
}
256+
};
257+
}
258+
]);
259+
260+
261+
}());

0 commit comments

Comments
 (0)