Merge pull request #2702 from nathanwoulfe/temp-U4-4732
U4-4732 Anchor missing in TinyMCE of Umbraco 7.x
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -3,10 +3,24 @@
|
||||
// --------------------------------------------------
|
||||
.umb-editor {
|
||||
min-width:66.6%;
|
||||
|
||||
&-pull {
|
||||
float:left;
|
||||
width:66.6%;
|
||||
}
|
||||
|
||||
&-push {
|
||||
float:right;
|
||||
}
|
||||
}
|
||||
|
||||
.umb-editor-tiny {
|
||||
width: 60px;
|
||||
|
||||
&.umb-editor-push {
|
||||
width:30%;
|
||||
min-width:0;
|
||||
}
|
||||
}
|
||||
|
||||
.umb-editor-small {
|
||||
@@ -28,6 +42,27 @@
|
||||
width: 99%;
|
||||
}
|
||||
|
||||
// displays property inline with preceeding
|
||||
.umb-property {
|
||||
&--pull {
|
||||
float:left;
|
||||
width:60%;
|
||||
}
|
||||
|
||||
&--push {
|
||||
float:right;
|
||||
width:35%;
|
||||
}
|
||||
|
||||
&--pull, &--push {
|
||||
.umb-editor {
|
||||
min-width:0;
|
||||
width:100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Content picker
|
||||
// --------------------------------------------------
|
||||
|
||||
@@ -1,149 +1,163 @@
|
||||
//used for the media picker dialog
|
||||
angular.module("umbraco").controller("Umbraco.Dialogs.LinkPickerController",
|
||||
function ($scope, eventsService, dialogService, entityResource, contentResource, mediaHelper, userService, localizationService) {
|
||||
var dialogOptions = $scope.dialogOptions;
|
||||
function ($scope, eventsService, dialogService, entityResource, contentResource, mediaHelper, userService, localizationService, tinyMceService) {
|
||||
var dialogOptions = $scope.dialogOptions;
|
||||
|
||||
var searchText = "Search...";
|
||||
localizationService.localize("general_search").then(function (value) {
|
||||
searchText = value + "...";
|
||||
});
|
||||
var searchText = "Search...";
|
||||
localizationService.localize("general_search").then(function (value) {
|
||||
searchText = value + "...";
|
||||
});
|
||||
|
||||
$scope.dialogTreeEventHandler = $({});
|
||||
$scope.target = {};
|
||||
$scope.searchInfo = {
|
||||
searchFromId: null,
|
||||
searchFromName: null,
|
||||
showSearch: false,
|
||||
results: [],
|
||||
selectedSearchResults: []
|
||||
}
|
||||
$scope.dialogTreeEventHandler = $({});
|
||||
$scope.target = {};
|
||||
$scope.searchInfo = {
|
||||
searchFromId: null,
|
||||
searchFromName: null,
|
||||
showSearch: false,
|
||||
results: [],
|
||||
selectedSearchResults: []
|
||||
}
|
||||
|
||||
if (dialogOptions.currentTarget) {
|
||||
$scope.target = dialogOptions.currentTarget;
|
||||
if (dialogOptions.currentTarget) {
|
||||
$scope.target = dialogOptions.currentTarget;
|
||||
|
||||
//if we have a node ID, we fetch the current node to build the form data
|
||||
if ($scope.target.id || $scope.target.udi) {
|
||||
//if we have a node ID, we fetch the current node to build the form data
|
||||
if ($scope.target.id || $scope.target.udi) {
|
||||
|
||||
var id = $scope.target.udi ? $scope.target.udi : $scope.target.id;
|
||||
var id = $scope.target.udi ? $scope.target.udi : $scope.target.id;
|
||||
|
||||
if (!$scope.target.path) {
|
||||
entityResource.getPath(id, "Document").then(function (path) {
|
||||
$scope.target.path = path;
|
||||
//now sync the tree to this path
|
||||
$scope.dialogTreeEventHandler.syncTree({ path: $scope.target.path, tree: "content" });
|
||||
});
|
||||
}
|
||||
if (!$scope.target.path) {
|
||||
entityResource.getPath(id, "Document").then(function (path) {
|
||||
$scope.target.path = path;
|
||||
//now sync the tree to this path
|
||||
$scope.dialogTreeEventHandler.syncTree({
|
||||
path: $scope.target.path,
|
||||
tree: "content"
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
contentResource.getNiceUrl(id).then(function (url) {
|
||||
$scope.target.url = url;
|
||||
});
|
||||
}
|
||||
}
|
||||
// if a link exists, get the properties to build the anchor name list
|
||||
contentResource.getById(id).then(function (resp) {
|
||||
$scope.anchorValues = tinyMceService.getAnchorNames(JSON.stringify(resp.properties));
|
||||
$scope.model.target.url = resp.urls[0];
|
||||
});
|
||||
} else if ($scope.target.url.length) {
|
||||
// a url but no id/udi indicates an external link - trim the url to remove the anchor/qs
|
||||
$scope.target.url = $scope.model.url.substring(0, $scope.model.url.search(/(#|\?)/));
|
||||
}
|
||||
}
|
||||
|
||||
function nodeSelectHandler(ev, args) {
|
||||
args.event.preventDefault();
|
||||
args.event.stopPropagation();
|
||||
if (dialogOptions.anchors) {
|
||||
$scope.anchorValues = dialogOptions.anchors;
|
||||
}
|
||||
|
||||
if (args.node.metaData.listViewNode) {
|
||||
//check if list view 'search' node was selected
|
||||
function nodeSelectHandler(ev, args) {
|
||||
args.event.preventDefault();
|
||||
args.event.stopPropagation();
|
||||
|
||||
$scope.searchInfo.showSearch = true;
|
||||
$scope.searchInfo.searchFromId = args.node.metaData.listViewNode.id;
|
||||
$scope.searchInfo.searchFromName = args.node.metaData.listViewNode.name;
|
||||
}
|
||||
else {
|
||||
eventsService.emit("dialogs.linkPicker.select", args);
|
||||
if (args.node.metaData.listViewNode) {
|
||||
//check if list view 'search' node was selected
|
||||
|
||||
if ($scope.currentNode) {
|
||||
//un-select if there's a current one selected
|
||||
$scope.currentNode.selected = false;
|
||||
}
|
||||
$scope.searchInfo.showSearch = true;
|
||||
$scope.searchInfo.searchFromId = args.node.metaData.listViewNode.id;
|
||||
$scope.searchInfo.searchFromName = args.node.metaData.listViewNode.name;
|
||||
} else {
|
||||
eventsService.emit("dialogs.linkPicker.select", args);
|
||||
|
||||
$scope.currentNode = args.node;
|
||||
$scope.currentNode.selected = true;
|
||||
$scope.target.id = args.node.id;
|
||||
$scope.target.udi = args.node.udi;
|
||||
$scope.target.name = args.node.name;
|
||||
if ($scope.currentNode) {
|
||||
//un-select if there's a current one selected
|
||||
$scope.currentNode.selected = false;
|
||||
}
|
||||
|
||||
if (args.node.id < 0) {
|
||||
$scope.target.url = "/";
|
||||
}
|
||||
else {
|
||||
contentResource.getNiceUrl(args.node.id).then(function (url) {
|
||||
$scope.target.url = url;
|
||||
});
|
||||
}
|
||||
$scope.currentNode = args.node;
|
||||
$scope.currentNode.selected = true;
|
||||
$scope.target.id = args.node.id;
|
||||
$scope.target.udi = args.node.udi;
|
||||
$scope.target.name = args.node.name;
|
||||
|
||||
if (!angular.isUndefined($scope.target.isMedia)) {
|
||||
delete $scope.target.isMedia;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (args.node.id < 0) {
|
||||
$scope.target.url = "/";
|
||||
} else {
|
||||
contentResource.getById(args.node.id).then(function (resp) {
|
||||
$scope.anchorValues = tinyMceService.getAnchorNames(JSON.stringify(resp.properties));
|
||||
$scope.model.target.url = resp.urls[0];
|
||||
});
|
||||
}
|
||||
|
||||
function nodeExpandedHandler(ev, args) {
|
||||
if (angular.isArray(args.children)) {
|
||||
if (!angular.isUndefined($scope.target.isMedia)) {
|
||||
delete $scope.target.isMedia;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//iterate children
|
||||
_.each(args.children, function (child) {
|
||||
//check if any of the items are list views, if so we need to add a custom
|
||||
// child: A node to activate the search
|
||||
if (child.metaData.isContainer) {
|
||||
child.hasChildren = true;
|
||||
child.children = [
|
||||
{
|
||||
level: child.level + 1,
|
||||
hasChildren: false,
|
||||
name: searchText,
|
||||
metaData: {
|
||||
listViewNode: child,
|
||||
},
|
||||
cssClass: "icon umb-tree-icon sprTree icon-search",
|
||||
cssClasses: ["not-published"]
|
||||
function nodeExpandedHandler(ev, args) {
|
||||
if (angular.isArray(args.children)) {
|
||||
|
||||
//iterate children
|
||||
_.each(args.children, function (child) {
|
||||
//check if any of the items are list views, if so we need to add a custom
|
||||
// child: A node to activate the search
|
||||
if (child.metaData.isContainer) {
|
||||
child.hasChildren = true;
|
||||
child.children = [
|
||||
{
|
||||
level: child.level + 1,
|
||||
hasChildren: false,
|
||||
name: searchText,
|
||||
metaData: {
|
||||
listViewNode: child,
|
||||
},
|
||||
cssClass: "icon umb-tree-icon sprTree icon-search",
|
||||
cssClasses: ["not-published"]
|
||||
}
|
||||
];
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$scope.switchToMediaPicker = function () {
|
||||
userService.getCurrentUser().then(function (userData) {
|
||||
dialogService.mediaPicker({
|
||||
startNodeId: userData.startMediaIds.length == 0 ? -1 : userData.startMediaIds[0],
|
||||
callback: function(media) {
|
||||
$scope.target.id = media.id;
|
||||
$scope.target.isMedia = true;
|
||||
$scope.target.name = media.name;
|
||||
$scope.target.url = mediaHelper.resolveFile(media);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
$scope.switchToMediaPicker = function () {
|
||||
userService.getCurrentUser().then(function (userData) {
|
||||
dialogService.mediaPicker({
|
||||
startNodeId: userData.startMediaIds.length == 0 ? -1 : userData.startMediaIds[0],
|
||||
callback: function (media) {
|
||||
$scope.target.id = media.id;
|
||||
$scope.target.isMedia = true;
|
||||
$scope.target.name = media.name;
|
||||
$scope.target.url = mediaHelper.resolveFile(media);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$scope.hideSearch = function () {
|
||||
$scope.searchInfo.showSearch = false;
|
||||
$scope.searchInfo.searchFromId = null;
|
||||
$scope.searchInfo.searchFromName = null;
|
||||
$scope.searchInfo.results = [];
|
||||
}
|
||||
$scope.hideSearch = function () {
|
||||
$scope.searchInfo.showSearch = false;
|
||||
$scope.searchInfo.searchFromId = null;
|
||||
$scope.searchInfo.searchFromName = null;
|
||||
$scope.searchInfo.results = [];
|
||||
}
|
||||
|
||||
// method to select a search result
|
||||
$scope.selectResult = function (evt, result) {
|
||||
result.selected = result.selected === true ? false : true;
|
||||
nodeSelectHandler(evt, {event: evt, node: result});
|
||||
};
|
||||
// method to select a search result
|
||||
$scope.selectResult = function (evt, result) {
|
||||
result.selected = result.selected === true ? false : true;
|
||||
nodeSelectHandler(evt, {
|
||||
event: evt,
|
||||
node: result
|
||||
});
|
||||
};
|
||||
|
||||
//callback when there are search results
|
||||
$scope.onSearchResults = function (results) {
|
||||
$scope.searchInfo.results = results;
|
||||
$scope.searchInfo.showSearch = true;
|
||||
};
|
||||
//callback when there are search results
|
||||
$scope.onSearchResults = function (results) {
|
||||
$scope.searchInfo.results = results;
|
||||
$scope.searchInfo.showSearch = true;
|
||||
};
|
||||
|
||||
$scope.dialogTreeEventHandler.bind("treeNodeSelect", nodeSelectHandler);
|
||||
$scope.dialogTreeEventHandler.bind("treeNodeExpanded", nodeExpandedHandler);
|
||||
$scope.dialogTreeEventHandler.bind("treeNodeSelect", nodeSelectHandler);
|
||||
$scope.dialogTreeEventHandler.bind("treeNodeExpanded", nodeExpandedHandler);
|
||||
|
||||
$scope.$on('$destroy', function () {
|
||||
$scope.dialogTreeEventHandler.unbind("treeNodeSelect", nodeSelectHandler);
|
||||
$scope.dialogTreeEventHandler.unbind("treeNodeExpanded", nodeExpandedHandler);
|
||||
});
|
||||
});
|
||||
$scope.$on('$destroy', function () {
|
||||
$scope.dialogTreeEventHandler.unbind("treeNodeSelect", nodeSelectHandler);
|
||||
$scope.dialogTreeEventHandler.unbind("treeNodeExpanded", nodeExpandedHandler);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
<div class="umb-panel" ng-controller="Umbraco.Dialogs.LinkPickerController">
|
||||
<div class="umb-panel-body no-header with-footer compact">
|
||||
<umb-pane>
|
||||
<umb-control-group label="@defaultdialogs_urlLinkPicker">
|
||||
<input type="text"
|
||||
localize="placeholder"
|
||||
placeholder="@general_url"
|
||||
class="umb-editor umb-textstring"
|
||||
ng-model="target.url"
|
||||
ng-disabled="target.id"
|
||||
/>
|
||||
</umb-control-group>
|
||||
<umb-control-group label="@defaultdialogs_urlLinkPicker" class="umb-property--pull">
|
||||
<input type="text" localize="placeholder" placeholder="@general_url" class="umb-editor umb-textstring" ng-model="target.url" ng-disabled="target.id" />
|
||||
</umb-control-group>
|
||||
|
||||
<umb-control-group label="@defaultdialogs_anchorLinkPicker" class="umb-property--push">
|
||||
<input type="text" list="anchors" localize="placeholder" placeholder="@placeholders_anchor" class="umb-editor umb-textstring" ng-model="target.anchor" />
|
||||
|
||||
<datalist id="anchors">
|
||||
<option value="{{a}}" ng-repeat="a in anchorValues"></option>
|
||||
</datalist>
|
||||
</umb-control-group>
|
||||
|
||||
<umb-control-group label="@defaultdialogs_nodeNameLinkPicker">
|
||||
<input type="text"
|
||||
|
||||
@@ -1,56 +1,66 @@
|
||||
//used for the media picker dialog
|
||||
angular.module("umbraco").controller("Umbraco.Overlays.LinkPickerController",
|
||||
function ($scope, eventsService, dialogService, entityResource, contentResource, mediaHelper, userService, localizationService) {
|
||||
var dialogOptions = $scope.model;
|
||||
function ($scope, eventsService, dialogService, entityResource, contentResource, mediaHelper, userService, localizationService, tinyMceService) {
|
||||
var dialogOptions = $scope.model;
|
||||
|
||||
var searchText = "Search...";
|
||||
localizationService.localize("general_search").then(function (value) {
|
||||
searchText = value + "...";
|
||||
});
|
||||
var anchorPattern = /<a id=\\"(.*?)\\">/gi;
|
||||
|
||||
if(!$scope.model.title) {
|
||||
$scope.model.title = localizationService.localize("defaultdialogs_selectLink");
|
||||
var searchText = "Search...";
|
||||
localizationService.localize("general_search").then(function (value) {
|
||||
searchText = value + "...";
|
||||
});
|
||||
|
||||
if (!$scope.model.title) {
|
||||
$scope.model.title = localizationService.localize("defaultdialogs_selectLink");
|
||||
}
|
||||
|
||||
$scope.dialogTreeEventHandler = $({});
|
||||
$scope.model.target = {};
|
||||
$scope.searchInfo = {
|
||||
searchFromId: null,
|
||||
searchFromName: null,
|
||||
showSearch: false,
|
||||
results: [],
|
||||
selectedSearchResults: []
|
||||
};
|
||||
$scope.dialogTreeEventHandler = $({});
|
||||
$scope.model.target = {};
|
||||
$scope.searchInfo = {
|
||||
searchFromId: null,
|
||||
searchFromName: null,
|
||||
showSearch: false,
|
||||
results: [],
|
||||
selectedSearchResults: []
|
||||
};
|
||||
|
||||
$scope.showTarget = $scope.model.hideTarget !== true;
|
||||
$scope.showTarget = $scope.model.hideTarget !== true;
|
||||
|
||||
if (dialogOptions.currentTarget) {
|
||||
$scope.model.target = dialogOptions.currentTarget;
|
||||
if (dialogOptions.currentTarget) {
|
||||
$scope.model.target = dialogOptions.currentTarget;
|
||||
//if we have a node ID, we fetch the current node to build the form data
|
||||
if ($scope.model.target.id || $scope.model.target.udi) {
|
||||
|
||||
//if we have a node ID, we fetch the current node to build the form data
|
||||
if ($scope.model.target.id || $scope.model.target.udi) {
|
||||
//will be either a udi or an int
|
||||
var id = $scope.model.target.udi ? $scope.model.target.udi : $scope.model.target.id;
|
||||
|
||||
//will be either a udi or an int
|
||||
var id = $scope.model.target.udi ? $scope.model.target.udi : $scope.model.target.id;
|
||||
if (!$scope.model.target.path) {
|
||||
|
||||
if (!$scope.model.target.path) {
|
||||
|
||||
entityResource.getPath(id, "Document").then(function (path) {
|
||||
$scope.model.target.path = path;
|
||||
//now sync the tree to this path
|
||||
$scope.dialogTreeEventHandler.syncTree({ path: $scope.model.target.path, tree: "content" });
|
||||
});
|
||||
}
|
||||
entityResource.getPath(id, "Document").then(function (path) {
|
||||
$scope.model.target.path = path;
|
||||
//now sync the tree to this path
|
||||
$scope.dialogTreeEventHandler.syncTree({
|
||||
path: $scope.model.target.path,
|
||||
tree: "content"
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
contentResource.getNiceUrl(id).then(function (url) {
|
||||
$scope.model.target.url = url;
|
||||
});
|
||||
}
|
||||
}
|
||||
// if a link exists, get the properties to build the anchor name list
|
||||
contentResource.getById(id).then(function (resp) {
|
||||
$scope.anchorValues = tinyMceService.getAnchorNames(JSON.stringify(resp.properties));
|
||||
$scope.model.target.url = resp.urls[0];
|
||||
});
|
||||
} else if ($scope.model.target.url.length) {
|
||||
// a url but no id/udi indicates an external link - trim the url to remove the anchor/qs
|
||||
$scope.model.target.url = $scope.model.target.url.substring(0, $scope.model.target.url.search(/(#|\?)/));
|
||||
}
|
||||
} else if (dialogOptions.anchors) {
|
||||
$scope.anchorValues = dialogOptions.anchors;
|
||||
}
|
||||
|
||||
function nodeSelectHandler(ev, args) {
|
||||
|
||||
if(args && args.event) {
|
||||
function nodeSelectHandler(ev, args) {
|
||||
if (args && args.event) {
|
||||
args.event.preventDefault();
|
||||
args.event.stopPropagation();
|
||||
}
|
||||
@@ -70,79 +80,86 @@ angular.module("umbraco").controller("Umbraco.Overlays.LinkPickerController",
|
||||
|
||||
if (args.node.id < 0) {
|
||||
$scope.model.target.url = "/";
|
||||
}
|
||||
else {
|
||||
contentResource.getNiceUrl(args.node.id).then(function (url) {
|
||||
$scope.model.target.url = url;
|
||||
} else {
|
||||
contentResource.getById(args.node.id).then(function (resp) {
|
||||
$scope.anchorValues = tinyMceService.getAnchorNames(JSON.stringify(resp.properties));
|
||||
$scope.model.target.url = resp.urls[0];
|
||||
});
|
||||
}
|
||||
|
||||
if (!angular.isUndefined($scope.model.target.isMedia)) {
|
||||
delete $scope.model.target.isMedia;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function nodeExpandedHandler(ev, args) {
|
||||
function nodeExpandedHandler(ev, args) {
|
||||
// open mini list view for list views
|
||||
if (args.node.metaData.isContainer) {
|
||||
openMiniListView(args.node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$scope.switchToMediaPicker = function () {
|
||||
userService.getCurrentUser().then(function (userData) {
|
||||
$scope.mediaPickerOverlay = {
|
||||
view: "mediapicker",
|
||||
startNodeId: userData.startMediaIds.length !== 1 ? -1 : userData.startMediaIds[0],
|
||||
startNodeIsVirtual: userData.startMediaIds.length !== 1,
|
||||
show: true,
|
||||
submit: function(model) {
|
||||
var media = model.selectedImages[0];
|
||||
$scope.switchToMediaPicker = function () {
|
||||
userService.getCurrentUser().then(function (userData) {
|
||||
$scope.mediaPickerOverlay = {
|
||||
view: "mediapicker",
|
||||
startNodeId: userData.startMediaIds.length !== 1 ? -1 : userData.startMediaIds[0],
|
||||
startNodeIsVirtual: userData.startMediaIds.length !== 1,
|
||||
show: true,
|
||||
submit: function (model) {
|
||||
var media = model.selectedImages[0];
|
||||
|
||||
$scope.model.target.id = media.id;
|
||||
$scope.model.target.udi = media.udi;
|
||||
$scope.model.target.isMedia = true;
|
||||
$scope.model.target.name = media.name;
|
||||
$scope.model.target.url = mediaHelper.resolveFile(media);
|
||||
$scope.model.target.id = media.id;
|
||||
$scope.model.target.udi = media.udi;
|
||||
$scope.model.target.isMedia = true;
|
||||
$scope.model.target.name = media.name;
|
||||
$scope.model.target.url = mediaHelper.resolveFile(media);
|
||||
|
||||
debugger;
|
||||
|
||||
$scope.mediaPickerOverlay.show = false;
|
||||
$scope.mediaPickerOverlay = null;
|
||||
}
|
||||
};
|
||||
});
|
||||
};
|
||||
$scope.mediaPickerOverlay.show = false;
|
||||
$scope.mediaPickerOverlay = null;
|
||||
}
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
$scope.hideSearch = function () {
|
||||
$scope.searchInfo.showSearch = false;
|
||||
$scope.searchInfo.searchFromId = null;
|
||||
$scope.searchInfo.searchFromName = null;
|
||||
$scope.searchInfo.results = [];
|
||||
}
|
||||
$scope.hideSearch = function () {
|
||||
$scope.searchInfo.showSearch = false;
|
||||
$scope.searchInfo.searchFromId = null;
|
||||
$scope.searchInfo.searchFromName = null;
|
||||
$scope.searchInfo.results = [];
|
||||
}
|
||||
|
||||
// method to select a search result
|
||||
$scope.selectResult = function (evt, result) {
|
||||
result.selected = result.selected === true ? false : true;
|
||||
nodeSelectHandler(evt, {event: evt, node: result});
|
||||
};
|
||||
// method to select a search result
|
||||
$scope.selectResult = function (evt, result) {
|
||||
result.selected = result.selected === true ? false : true;
|
||||
nodeSelectHandler(evt, {
|
||||
event: evt,
|
||||
node: result
|
||||
});
|
||||
};
|
||||
|
||||
//callback when there are search results
|
||||
$scope.onSearchResults = function (results) {
|
||||
$scope.searchInfo.results = results;
|
||||
$scope.searchInfo.showSearch = true;
|
||||
};
|
||||
//callback when there are search results
|
||||
$scope.onSearchResults = function (results) {
|
||||
$scope.searchInfo.results = results;
|
||||
$scope.searchInfo.showSearch = true;
|
||||
};
|
||||
|
||||
$scope.dialogTreeEventHandler.bind("treeNodeSelect", nodeSelectHandler);
|
||||
$scope.dialogTreeEventHandler.bind("treeNodeExpanded", nodeExpandedHandler);
|
||||
$scope.dialogTreeEventHandler.bind("treeNodeSelect", nodeSelectHandler);
|
||||
$scope.dialogTreeEventHandler.bind("treeNodeExpanded", nodeExpandedHandler);
|
||||
|
||||
$scope.$on('$destroy', function () {
|
||||
$scope.dialogTreeEventHandler.unbind("treeNodeSelect", nodeSelectHandler);
|
||||
$scope.dialogTreeEventHandler.unbind("treeNodeExpanded", nodeExpandedHandler);
|
||||
});
|
||||
$scope.$on('$destroy', function () {
|
||||
$scope.dialogTreeEventHandler.unbind("treeNodeSelect", nodeSelectHandler);
|
||||
$scope.dialogTreeEventHandler.unbind("treeNodeExpanded", nodeExpandedHandler);
|
||||
});
|
||||
|
||||
// Mini list view
|
||||
$scope.selectListViewNode = function (node) {
|
||||
node.selected = node.selected === true ? false : true;
|
||||
nodeSelectHandler({}, { node: node });
|
||||
nodeSelectHandler({}, {
|
||||
node: node
|
||||
});
|
||||
};
|
||||
|
||||
$scope.closeMiniListView = function () {
|
||||
|
||||
@@ -1,89 +1,62 @@
|
||||
<div ng-controller="Umbraco.Overlays.LinkPickerController">
|
||||
|
||||
<umb-control-group label="@defaultdialogs_urlLinkPicker">
|
||||
<input type="text"
|
||||
localize="placeholder"
|
||||
placeholder="@general_url"
|
||||
class="umb-editor umb-textstring"
|
||||
ng-model="model.target.url"
|
||||
ng-disabled="model.target.id"
|
||||
focus-when="{{true}} "/>
|
||||
</umb-control-group>
|
||||
<umb-control-group label="@defaultdialogs_urlLinkPicker" class="umb-property--pull">
|
||||
<input type="text" localize="placeholder" placeholder="@general_url" class="umb-editor umb-textstring" ng-model="model.target.url" ng-disabled="model.target.id" />
|
||||
</umb-control-group>
|
||||
|
||||
<umb-control-group label="@defaultdialogs_nodeNameLinkPicker">
|
||||
<input type="text"
|
||||
localize="placeholder"
|
||||
placeholder="@placeholders_entername"
|
||||
class="umb-editor umb-textstring"
|
||||
ng-model="model.target.name" />
|
||||
</umb-control-group>
|
||||
<umb-control-group label="@defaultdialogs_anchorLinkPicker" class="umb-property--push">
|
||||
<input type="text" list="anchors" localize="placeholder" placeholder="@placeholders_anchor" class="umb-editor umb-textstring" ng-model="model.target.anchor" />
|
||||
|
||||
<umb-control-group ng-if="showTarget" label="@content_target">
|
||||
<label class="checkbox no-indent">
|
||||
<datalist id="anchors">
|
||||
<option value="{{a}}" ng-repeat="a in anchorValues"></option>
|
||||
</datalist>
|
||||
</umb-control-group>
|
||||
|
||||
<umb-control-group label="@defaultdialogs_nodeNameLinkPicker">
|
||||
<input type="text" localize="placeholder" placeholder="@placeholders_entername" class="umb-editor umb-textstring" ng-model="model.target.name" />
|
||||
</umb-control-group>
|
||||
|
||||
<umb-control-group ng-if="showTarget" label="@content_target">
|
||||
<label class="checkbox no-indent">
|
||||
<input type="checkbox" ng-model="model.target.target" ng-true-value="_blank" ng-false-value="" /> <localize key="defaultdialogs_openInNewWindow">Opens the linked document in a new window or tab</localize>
|
||||
</label>
|
||||
</umb-control-group>
|
||||
</umb-control-group>
|
||||
|
||||
<div class="umb-control-group">
|
||||
<h5>
|
||||
<localize key="defaultdialogs_linkToPage">Link to page</localize>
|
||||
</h5>
|
||||
<div class="umb-control-group">
|
||||
<h5>
|
||||
<localize key="defaultdialogs_linkToPage">Link to page</localize>
|
||||
</h5>
|
||||
|
||||
<div ng-hide="miniListView">
|
||||
<umb-tree-search-box
|
||||
hide-search-callback="hideSearch"
|
||||
search-callback="onSearchResults"
|
||||
search-from-id="{{searchInfo.searchFromId}}"
|
||||
search-from-name="{{searchInfo.searchFromName}}"
|
||||
show-search="{{searchInfo.showSearch}}"
|
||||
section="{{section}}">
|
||||
</umb-tree-search-box>
|
||||
<div ng-hide="miniListView">
|
||||
<umb-tree-search-box hide-search-callback="hideSearch" search-callback="onSearchResults" search-from-id="{{searchInfo.searchFromId}}" search-from-name="{{searchInfo.searchFromName}}" show-search="{{searchInfo.showSearch}}" section="{{section}}">
|
||||
</umb-tree-search-box>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<umb-tree-search-results
|
||||
ng-if="searchInfo.showSearch"
|
||||
results="searchInfo.results"
|
||||
select-result-callback="selectResult">
|
||||
</umb-tree-search-results>
|
||||
<umb-tree-search-results ng-if="searchInfo.showSearch" results="searchInfo.results" select-result-callback="selectResult">
|
||||
</umb-tree-search-results>
|
||||
|
||||
<div ng-hide="searchInfo.showSearch">
|
||||
<umb-tree
|
||||
section="content"
|
||||
hideheader="true"
|
||||
hideoptions="true"
|
||||
eventhandler="dialogTreeEventHandler"
|
||||
enablelistviewexpand="true"
|
||||
isdialog="true"
|
||||
enablecheckboxes="true">
|
||||
</umb-tree>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-hide="searchInfo.showSearch">
|
||||
<umb-tree section="content" hideheader="true" hideoptions="true" eventhandler="dialogTreeEventHandler" enablelistviewexpand="true" isdialog="true" enablecheckboxes="true">
|
||||
</umb-tree>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<umb-mini-list-view
|
||||
ng-if="miniListView"
|
||||
node="miniListView"
|
||||
entity-type="Document"
|
||||
on-select="selectListViewNode(node)"
|
||||
on-close="closeMiniListView()">
|
||||
</umb-mini-list-view>
|
||||
<umb-mini-list-view ng-if="miniListView" node="miniListView" entity-type="Document" on-select="selectListViewNode(node)" on-close="closeMiniListView()">
|
||||
</umb-mini-list-view>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="umb-control-group">
|
||||
<h5>
|
||||
<localize key="defaultdialogs_linkToMedia">Link to media</localize>
|
||||
</h5>
|
||||
<a href ng-click="switchToMediaPicker()" class="btn">
|
||||
<localize key="defaultdialogs_selectMedia">Select media</localize>
|
||||
</a>
|
||||
</div>
|
||||
<div class="umb-control-group">
|
||||
<h5>
|
||||
<localize key="defaultdialogs_linkToMedia">Link to media</localize>
|
||||
</h5>
|
||||
<a href ng-click="switchToMediaPicker()" class="btn">
|
||||
<localize key="defaultdialogs_selectMedia">Select media</localize>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<umb-overlay
|
||||
ng-if="mediaPickerOverlay.show"
|
||||
model="mediaPickerOverlay"
|
||||
view="mediaPickerOverlay.view"
|
||||
position="right">
|
||||
</umb-overlay>
|
||||
<umb-overlay ng-if="mediaPickerOverlay.show" model="mediaPickerOverlay" view="mediaPickerOverlay.view" position="right">
|
||||
</umb-overlay>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
|
||||
function GridRichTextEditorController($scope, tinyMceService, macroService) {
|
||||
function GridRichTextEditorController($scope, tinyMceService, macroService, editorState) {
|
||||
|
||||
var vm = this;
|
||||
|
||||
@@ -11,9 +11,11 @@
|
||||
vm.openEmbed = openEmbed;
|
||||
|
||||
function openLinkPicker(editor, currentTarget, anchorElement) {
|
||||
|
||||
vm.linkPickerOverlay = {
|
||||
view: "linkpicker",
|
||||
currentTarget: currentTarget,
|
||||
anchors: tinyMceService.getAnchorNames(JSON.stringify(editorState.current.properties)),
|
||||
show: true,
|
||||
submit: function(model) {
|
||||
tinyMceService.insertLinkInEditor(editor, model.target, anchorElement);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
angular.module("umbraco")
|
||||
.controller("Umbraco.PropertyEditors.RTEController",
|
||||
function ($rootScope, $scope, $q, $locale, dialogService, $log, imageHelper, assetsService, $timeout, tinyMceService, angularHelper, stylesheetResource, macroService) {
|
||||
function ($rootScope, $scope, $q, $locale, dialogService, $log, imageHelper, assetsService, $timeout, tinyMceService, angularHelper, stylesheetResource, macroService, editorState) {
|
||||
|
||||
$scope.isLoading = true;
|
||||
|
||||
@@ -273,11 +273,12 @@ angular.module("umbraco")
|
||||
|
||||
syncContent(editor);
|
||||
});
|
||||
|
||||
|
||||
tinyMceService.createLinkPicker(editor, $scope, function(currentTarget, anchorElement) {
|
||||
$scope.linkPickerOverlay = {
|
||||
view: "linkpicker",
|
||||
currentTarget: currentTarget,
|
||||
anchors: tinyMceService.getAnchorNames(JSON.stringify(editorState.current.properties)),
|
||||
show: true,
|
||||
submit: function(model) {
|
||||
tinyMceService.insertLinkInEditor(editor, model.target, anchorElement);
|
||||
|
||||
@@ -338,6 +338,7 @@
|
||||
<area alias="defaultdialogs">
|
||||
<key alias="nodeNameLinkPicker">Link title</key>
|
||||
<key alias="urlLinkPicker">Link</key>
|
||||
<key alias="anchorLinkPicker">Anchor / querystring</key>
|
||||
<key alias="anchorInsert">Name</key>
|
||||
<key alias="assignDomain">Manage hostnames</key>
|
||||
<key alias="closeThisWindow">Close this window</key>
|
||||
@@ -456,6 +457,7 @@
|
||||
<key alias="email">Enter your email...</key>
|
||||
<key alias="enterMessage">Enter a message...</key>
|
||||
<key alias="usernameHint">Your username is usually your email</key>
|
||||
<key alias="anchor">#value or ?key=value</key>
|
||||
</area>
|
||||
<area alias="editcontenttype">
|
||||
<key alias="allowAtRoot" version="7.2">Allow at root</key>
|
||||
|
||||
@@ -339,6 +339,7 @@
|
||||
<area alias="defaultdialogs">
|
||||
<key alias="nodeNameLinkPicker">Link title</key>
|
||||
<key alias="urlLinkPicker">Link</key>
|
||||
<key alias="anchorLinkPicker">Anchor / querystring</key>
|
||||
<key alias="anchorInsert">Name</key>
|
||||
<key alias="closeThisWindow">Close this window</key>
|
||||
<key alias="confirmdelete">Are you sure you want to delete</key>
|
||||
@@ -456,6 +457,7 @@
|
||||
<key alias="email">Enter your email...</key>
|
||||
<key alias="enterMessage">Enter a message...</key>
|
||||
<key alias="usernameHint">Your username is usually your email</key>
|
||||
<key alias="anchor">#value or ?key=value</key>
|
||||
</area>
|
||||
<area alias="editcontenttype">
|
||||
<key alias="allowAtRoot" version="7.2">Allow at root</key>
|
||||
|
||||
@@ -67,7 +67,9 @@ namespace Umbraco.Web.Editors
|
||||
public void Initialize(HttpControllerSettings controllerSettings, HttpControllerDescriptor controllerDescriptor)
|
||||
{
|
||||
controllerSettings.Services.Replace(typeof(IHttpActionSelector), new ParameterSwapControllerActionSelector(
|
||||
new ParameterSwapControllerActionSelector.ParameterSwapInfo("GetNiceUrl", "id", typeof(int), typeof(Guid), typeof(Udi))));
|
||||
new ParameterSwapControllerActionSelector.ParameterSwapInfo("GetNiceUrl", "id", typeof(int), typeof(Guid), typeof(Udi)),
|
||||
new ParameterSwapControllerActionSelector.ParameterSwapInfo("GetById", "id", typeof(int), typeof(Guid), typeof(Udi))
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,7 +102,7 @@ namespace Umbraco.Web.Editors
|
||||
|
||||
var content = Services.ContentService.GetById(saveModel.ContentId);
|
||||
if (content == null) throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
|
||||
|
||||
|
||||
//current permissions explicitly assigned to this content item
|
||||
var contentPermissions = Services.ContentService.GetPermissionsForEntity(content)
|
||||
.ToDictionary(x => x.UserGroupId, x => x);
|
||||
@@ -136,10 +138,10 @@ namespace Umbraco.Web.Editors
|
||||
//if they are different we need to update, otherwise there's nothing to update
|
||||
else if (contentPermissions.ContainsKey(userGroup.Id) == false || contentPermissions[userGroup.Id].AssignedPermissions.UnsortedSequenceEqual(groupPermissionCodes) == false)
|
||||
{
|
||||
|
||||
|
||||
Services.UserService.ReplaceUserGroupPermissions(userGroup.Id, groupPermissionCodes.Select(x => x[0]), content.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return GetDetailedPermissions(content, allUserGroups);
|
||||
@@ -158,7 +160,7 @@ namespace Umbraco.Web.Editors
|
||||
{
|
||||
if (contentId <= 0) throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
|
||||
var content = Services.ContentService.GetById(contentId);
|
||||
if (content == null) throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
|
||||
if (content == null) throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
|
||||
|
||||
//TODO: Should non-admins be able to see detailed permissions?
|
||||
|
||||
@@ -195,9 +197,9 @@ namespace Umbraco.Web.Editors
|
||||
permission.Checked = false;
|
||||
permission.Checked = assignedGroupPermission.AssignedPermissions.Contains(permission.PermissionCode, StringComparer.InvariantCulture);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
return defaultPermissionsByGroup;
|
||||
}
|
||||
|
||||
@@ -246,10 +248,10 @@ namespace Umbraco.Web.Editors
|
||||
//set a custom path since the tree that renders this has the content type id as the parent
|
||||
content.Path = string.Format("-1,{0},{1}", persistedContent.ContentTypeId, content.Id);
|
||||
|
||||
content.AllowedActions = new[] {"A"};
|
||||
content.AllowedActions = new[] { "A" };
|
||||
content.IsBlueprint = true;
|
||||
|
||||
var excludeProps = new[] {"_umb_urls", "_umb_releasedate", "_umb_expiredate", "_umb_template"};
|
||||
var excludeProps = new[] { "_umb_urls", "_umb_releasedate", "_umb_expiredate", "_umb_template" };
|
||||
var propsTab = content.Tabs.Last();
|
||||
propsTab.Properties = propsTab.Properties
|
||||
.Where(p => excludeProps.Contains(p.Alias) == false);
|
||||
@@ -274,6 +276,43 @@ namespace Umbraco.Web.Editors
|
||||
return content;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the content json for the content id
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
[OutgoingEditorModelEvent]
|
||||
[EnsureUserPermissionForContent("id")]
|
||||
public ContentItemDisplay GetById(Guid id)
|
||||
{
|
||||
var foundContent = GetObjectFromRequest(() => Services.ContentService.GetById(id));
|
||||
if (foundContent == null)
|
||||
{
|
||||
HandleContentNotFound(id);
|
||||
}
|
||||
|
||||
var content = AutoMapperExtensions.MapWithUmbracoContext<IContent, ContentItemDisplay>(foundContent, UmbracoContext);
|
||||
return content;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the content json for the content id
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
[OutgoingEditorModelEvent]
|
||||
[EnsureUserPermissionForContent("id")]
|
||||
public ContentItemDisplay GetById(Udi id)
|
||||
{
|
||||
var guidUdi = id as GuidUdi;
|
||||
if (guidUdi != null)
|
||||
{
|
||||
return GetById(guidUdi.Guid);
|
||||
}
|
||||
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
}
|
||||
|
||||
[EnsureUserPermissionForContent("id")]
|
||||
public ContentItemDisplay GetWithTreeDefinition(int id)
|
||||
{
|
||||
@@ -373,7 +412,7 @@ namespace Umbraco.Web.Editors
|
||||
{
|
||||
return GetNiceUrl(guidUdi.Guid);
|
||||
}
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -459,7 +498,7 @@ namespace Umbraco.Web.Editors
|
||||
{
|
||||
var permissions = Services.UserService
|
||||
.GetPermissions(Security.CurrentUser, nodeIds);
|
||||
|
||||
|
||||
var permissionsDictionary = new Dictionary<int, string[]>();
|
||||
foreach (var nodeId in nodeIds)
|
||||
{
|
||||
@@ -513,7 +552,7 @@ namespace Umbraco.Web.Editors
|
||||
var notificationModel = new SimpleNotificationModel();
|
||||
notificationModel.AddSuccessNotification(
|
||||
Services.TextService.Localize("blueprints/createdBlueprintHeading"),
|
||||
Services.TextService.Localize("blueprints/createdBlueprintMessage", new[]{ content.Name})
|
||||
Services.TextService.Localize("blueprints/createdBlueprintMessage", new[] { content.Name })
|
||||
);
|
||||
|
||||
return notificationModel;
|
||||
@@ -563,7 +602,7 @@ namespace Umbraco.Web.Editors
|
||||
[ModelBinder(typeof(ContentItemBinder))]
|
||||
ContentItemSave contentItem)
|
||||
{
|
||||
return PostSaveInternal(contentItem,
|
||||
return PostSaveInternal(contentItem,
|
||||
content => Services.ContentService.WithResult().Save(contentItem.PersistedContent, Security.CurrentUser.Id));
|
||||
}
|
||||
|
||||
@@ -1083,7 +1122,7 @@ namespace Umbraco.Web.Editors
|
||||
{
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
}
|
||||
|
||||
|
||||
var hasPathAccess = (nodeId == Constants.System.Root)
|
||||
? user.HasContentRootAccess(entityService)
|
||||
: (nodeId == Constants.System.RecycleBinContent)
|
||||
@@ -1108,7 +1147,7 @@ namespace Umbraco.Web.Editors
|
||||
var allowed = true;
|
||||
foreach (var p in permissionsToCheck)
|
||||
{
|
||||
if (permission == null
|
||||
if (permission == null
|
||||
|| permission.GetAllPermissions().Contains(p.ToString(CultureInfo.InvariantCulture)) == false)
|
||||
{
|
||||
allowed = false;
|
||||
|
||||
@@ -79,7 +79,23 @@ namespace Umbraco.Web.WebApi.Filters
|
||||
|
||||
if (parts.Length == 1)
|
||||
{
|
||||
nodeId = (int)actionContext.ActionArguments[parts[0]];
|
||||
var argument = actionContext.ActionArguments[parts[0]].ToString();
|
||||
// if the argument is an int, it will parse and can be assigned to nodeId
|
||||
// if might be a udi, so check that next
|
||||
// otherwise treat it as a guid - unlikely we ever get here
|
||||
if (int.TryParse(argument, out int parsedId))
|
||||
{
|
||||
nodeId = parsedId;
|
||||
}
|
||||
else if (Udi.TryParse(argument, true, out Udi udi))
|
||||
{
|
||||
nodeId = ApplicationContext.Current.Services.EntityService.GetIdForUdi(udi).Result;
|
||||
}
|
||||
else
|
||||
{
|
||||
Guid.TryParse(argument, out Guid key);
|
||||
nodeId = ApplicationContext.Current.Services.EntityService.GetIdForKey(key, UmbracoObjectTypes.Document).Result;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -118,4 +134,4 @@ namespace Umbraco.Web.WebApi.Filters
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user