Dynamically set starting node of media picker in richtext editor
Hi,
is there a way in the richtext editor dynamically set the starting node of the image picker?
For example: I set a Media Folder ID in each content node. If I use the Media Picker it would be nice if this media folder is then used as the starting node so you do not have to click through a very extensive media structure.
the above requirement for the rich text editor is not related to the uMediaSync package. This was only once a special request for a customer project in which uMediaSync but not used. I did this not also implemented in uMediaSync and currently have unfortunately no time for it, because I'm still busy with other larger projects. But if you can integrate this, of course, I can gladly update the package with your solution.
I "solved" it for the media picker in the native RTE the following way. I basically get the id of the media node being loaded - if it is the root, I redirect to another media node id before the root one is loaded. In the example below I hardcoded the "custom root" - irl I use a variable that defines which root I want. I also have some logic to prevent uploading to different media folders, that is not shown in the simplified example below.
public class MyApiHandler : System.Net.Http.DelegatingHandler { protectedoverrideTask<HttpResponseMessage>SendAsync(HttpRequestMessage request,CancellationToken cancellationToken) { var user =UmbracoContext.Current.Security.CurrentUser;
// If current user is not admin if(user !=null&& user.Name!="admin") { // Catch content tree load events switch(request.RequestUri.AbsolutePath.ToLower()) { // Content of RTE media picker case "/umbraco/backoffice/umbracoapi/media/getchildren": return FilterAllowedRteMedia(request, cancellationToken, user); case "/umbraco/backoffice/umbracoapi/entity/getancestors": return FilterAllowedRteMedia(request, cancellationToken, user); default: returnbase.SendAsync(request, cancellationToken); } }
// Set media root for RTEs if (selectedNodeId == "-1") { request.RequestUri = new Uri(request.RequestUri.ToString().Replace(String.Format("?id={0}&", selectedNodeId), String.Format("?id={0}&", 1061))); }
I didnt mean as direct integration, I am ok to enter the media node ids for the top level nodes inside a property - as they wont change moving forward.
I was trying to figure if there is a complete .cs file(s) that I can drop to App_Code and change the property name to read the media root ID.
Is there a quick patch that once can add to that code, to make it read the media root id (1061) from the CurrentPage's Parent at Level 2 property like mediaRootID ?
Would be interested to see the complete code you mentioned, where prevention of certain nodes is handled - its very helpfull in the learning curve.
A bit off-topic, I was reading another post on protecting media, i.e. allowing only certain media to be downloaded on the front-end only if a user logged in. Looking at the way these event interrupts handled in v7, do you think there is an easy way to accomplish such? i.e. only allow media download if Membership.GetUser()!=null
I'm not sure I understand the "from the CurrentPage's Parent at Level 2 property like mediaRootID" part - I didn't find a way to get the current content node id though, so if that is part of what you want to do, I'd be very interested in seeing how you get about it :)
About members vs. media - I don't know of any best practices, but I guess one could implement some logic in the views. If the current user is part of a certain member group, show download link?
I understand Soren has figured out a way to get the Media Root ID from the current page (at least thats what i grasp from his post above) and was wondering if there is a complete example that we can refer to.
In regards to "CurrentPage's Parent at Level x", assuming we manage to read the property from the current node, and we have a structure like;
A (Level 2) - custom property mediaRootID
a1 (level 3)
a2
a21 (level 4)
a211 (level 5)
a2111 (level 6)
....
On any of the the sub-nodes like a211 (doesnt matter how deep it is), we will read the custom property MediaRootID of its parent at Level 2 (A).
Say we capture the media root id for all pages at Level 2, and all sub-levels pages of Level 2 will be opening the Media Root folder (id) that is defined in their parent node at Level 2.
It's perfectly clear now; as long as one finds a way of getting the current content node, this should be possible. As mentioned I did not find a way with the time I had, but I too would be keen to see if anyone else has solved it.
Hi, Kelio.
I am not sure, what's your requirements.
If I understood correctly, You would like to set Media picker's start node id to the id that you defined on a Content page "A (Level 2) - custom property mediaRootID"
I assume that mediaRootID = Integer (Id of media folder) and media picker that used as a picker is a "Media picker".
"Media picker" and "Legacy media picker" are different.
Here is my approach. You can use this for an idea,
public class MediaPickerExtension : DelegatingHandler
{
/// <summary>
/// Sends an HTTP request to the inner handler to send to the server as an asynchronous operation.
/// </summary>
/// <param name="request">The HTTP request message to send to the server.</param>
/// <param name="cancellationToken">A cancellation token to cancel operation.</param>
/// <returns>
/// Returns <see cref="T:System.Threading.Tasks.Task`1" />. The task object representing the asynchronous operation.
/// </returns>
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var path = request.RequestUri.AbsolutePath.ToLower();
switch (path)
{
case "/umbraco/backoffice/umbracoapi/content/getempty":
case "/umbraco/backoffice/umbracoapi/content/getbyid":
return SetMediaRootStartNode(request, cancellationToken);
default:
return base.SendAsync(request, cancellationToken);
}
}
/// <summary>
/// Sets the media root start node.
/// </summary>
/// <param name="request">The request.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns></returns>
private Task<HttpResponseMessage> SetMediaRootStartNode(HttpRequestMessage request, CancellationToken cancellationToken)
{
return base.SendAsync(request, cancellationToken)
.ContinueWith(task =>
{
var response = task.Result;
try
{
//Get the current content
var d = response.Content;
var c = ((ObjectContent)(d)).Value as ContentItemDisplay;
if (c != null)
SetStartNode(request, Convert.ToInt32(c.Id), c.ContentTypeAlias, c.Properties);
}
catch (Exception ex)
{
//
// "Error:: picker start node."
}
return response;
}, cancellationToken);
}
/// <summary>
/// Sets the start node.
/// </summary>
/// <param name="request">The request.</param>
/// <param name="toInt32">To int32.</param>
/// <param name="contentTypeAlias">The content type alias.</param>
/// <param name="properties">The properties.</param>
private void SetStartNode(HttpRequestMessage request, int toInt32, string contentTypeAlias, IEnumerable<ContentPropertyDisplay> properties)
{
var mediaNodePickers = properties.Where(x =>
Constants.PropertyEditors.MultipleMediaPickerAlias.InvariantEquals(x.Editor)).ToList();
if (!mediaNodePickers.Any()) return;
var contextNode = ApplicationContext.Current.Services.ContentService.GetById(toInt32);
if (contextNode == null || contextNode.Level < 2) return;
// here you get the node (A-level 2 custom property mediaRootID)
var m =
contextNode.Ancestors()
.FirstOrDefault(
x =>
x.HasProperty("mediaRootId") && !string.IsNullOrEmpty(x.GetValue<string>("mediaRootId")));
if(m==null) return;
// find media start node, specified on level 2
var startMediaRootId = m.GetValue<int>("mediaRootId");
var contentPropertyDisplay = mediaNodePickers.FirstOrDefault();
if (contentPropertyDisplay != null)
{
var configs = contentPropertyDisplay.Config;
if (configs.ContainsKey("startNodeId"))
{
configs["startNodeId"] = startMediaRootId;
}
else
{
configs.Add("startNodeId", startMediaRootId);
}
}
}
}
And finally hookup on Umbraco application starting
public class UmbracoStartUp : IApplicationEventHandler
{
public void OnApplicationInitialized(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
{
// throw new NotImplementedException();
}
public void OnApplicationStarting(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
{
//hookup the MediaPickerExtension
GlobalConfiguration.Configuration.MessageHandlers.Add(new MediaPickerExtension());
}
public void OnApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
{
// throw new NotImplementedException();
}
}
Thank you for the example! Sorry for the convoluted description. I guess what Im trying to do can be explained simly 'how to retrieve media picker root folder from current page's parent x and open media picker at that folder'. Thinking about it, actually one can retrieve that value recursively too, like .GetProperty("mediaRootID",true) so it climbs up the tree until it finds a mediaRootID - this way one can define mediaroot overrides at any level.
You assumption is correct, mediaRootID is integer and MediaPicker datatype used in pages are of "Media picker" and not legacy picker.
I have tried to run you code on the remote system by placing it under App_Code folder. Since I dont have access to Visual Studio at this time, I have tried to add the references below, but i think missing obvious ones;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using System.Linq;
using System.Net.Http;
using Umbraco.Core;
using Umbraco.Web;
compilation error:
'Umbraco.Core.Models.IContent' does not contain a definition for 'Ancestors' and the best extension method overload 'Umbraco.Web.PublishedContentExtensions.Ancestors(Umbraco.Core.Models.IPublishedContent)
on
var m =
contextNode.Ancestors()
.FirstOrDefault(
x =>
What would be the complete using references I should be adding?
Here are the references i have used.
// for MediaPickerExtension class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using Umbraco.Core;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Web.Models.ContentEditing;
I have tested on Umbraco 7.1.8
Here are the references i have used.
// for MediaPickerExtension class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using Umbraco.Core;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Web.Models.ContentEditing;
I have tested on Umbraco 7.1.8
Here are the references i have used.
// for MediaPickerExtension class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using Umbraco.Core;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Web.Models.ContentEditing;
Many thanks for the quick reply. added references to both accordingly and no errors. I am using 7.1.8 too.
I have double checked; at level 2 node ,i have property mediaRootID (alias matches) is of Numeric data type, with value of media folder ID like 1325 (media->Doc/Images/Gallery2). and sub-pages of this node contain Media Picker (not legacy).
When i open the sub-page (tried children, also descendant) of level-2 node, of above, and select media picker, it doesnt change the root folder in the dialog.
Dynamically set starting node of media picker in richtext editor
Hi,
is there a way in the richtext editor dynamically set the starting node of the image picker?
For example:
I set a Media Folder ID in each content node. If I use the Media Picker it would be nice if this media folder is then used as the starting node so you do not have to click through a very extensive media structure.
Is this possible?
Best regards
Sören
Hey Sören - did you ever solve this?
Hi Dr. Sugus,
no, I have not.
Sören
Hi, Soren, It may be possible by overriding a method
Create a class that inherits from "DelegatingHandler".
This may help you, http://our.umbraco.org/forum/developers/extending-umbraco/57576-How-to-get-context-node-id-in-Custom-Property-Editor
Hi Jivan,
great :-) Thank you!
Hi Soren
I am using the MediaSync package and I can see how this can be very handy coupled with that package.
Is there a finalized script that I can drop to App_Code for this to work, or is your final solution too customized?
cheers
Hi keilo,
the above requirement for the rich text editor is not related to the uMediaSync package. This was only once a special request for a customer project in which uMediaSync but not used. I did this not also implemented in uMediaSync and currently have unfortunately no time for it, because I'm still busy with other larger projects. But if you can integrate this, of course, I can gladly update the package with your solution.
Sören
I "solved" it for the media picker in the native RTE the following way. I basically get the id of the media node being loaded - if it is the root, I redirect to another media node id before the root one is loaded. In the example below I hardcoded the "custom root" - irl I use a variable that defines which root I want. I also have some logic to prevent uploading to different media folders, that is not shown in the simplified example below.
Hi Soren
I didnt mean as direct integration, I am ok to enter the media node ids for the top level nodes inside a property - as they wont change moving forward.
I was trying to figure if there is a complete .cs file(s) that I can drop to App_Code and change the property name to read the media root ID.
Hi Dr Sugus
Is there a quick patch that once can add to that code, to make it read the media root id (1061) from the CurrentPage's Parent at Level 2 property like mediaRootID ?
Would be interested to see the complete code you mentioned, where prevention of certain nodes is handled - its very helpfull in the learning curve.
A bit off-topic, I was reading another post on protecting media, i.e. allowing only certain media to be downloaded on the front-end only if a user logged in. Looking at the way these event interrupts handled in v7, do you think there is an easy way to accomplish such? i.e. only allow media download if Membership.GetUser()!=null
Hi Keilo
I'm not sure I understand the "from the CurrentPage's Parent at Level 2 property like mediaRootID" part - I didn't find a way to get the current content node id though, so if that is part of what you want to do, I'd be very interested in seeing how you get about it :)
About members vs. media - I don't know of any best practices, but I guess one could implement some logic in the views. If the current user is part of a certain member group, show download link?
Hi Dr Sugus
I understand Soren has figured out a way to get the Media Root ID from the current page (at least thats what i grasp from his post above) and was wondering if there is a complete example that we can refer to.
In regards to "CurrentPage's Parent at Level x", assuming we manage to read the property from the current node, and we have a structure like;
A (Level 2) - custom property mediaRootID
a1 (level 3)
a2
a21 (level 4)
a211 (level 5)
a2111 (level 6)
....
On any of the the sub-nodes like a211 (doesnt matter how deep it is), we will read the custom property MediaRootID of its parent at Level 2 (A).
Say we capture the media root id for all pages at Level 2, and all sub-levels pages of Level 2 will be opening the Media Root folder (id) that is defined in their parent node at Level 2.
like @Model.AncestorOrSelf(2) as discussed here http://our.umbraco.org/forum/developers/razor/18203-Best-way-of-getting-ancestor-of-specific-level
Let me know i managed to clarify.
Hi Keilo
It's perfectly clear now; as long as one finds a way of getting the current content node, this should be possible. As mentioned I did not find a way with the time I had, but I too would be keen to see if anyone else has solved it.
Hi, Kelio. I am not sure, what's your requirements. If I understood correctly, You would like to set Media picker's start node id to the id that you defined on a Content page "A (Level 2) - custom property mediaRootID"
I assume that mediaRootID = Integer (Id of media folder) and media picker that used as a picker is a "Media picker". "Media picker" and "Legacy media picker" are different.
Here is my approach. You can use this for an idea,
And finally hookup on Umbraco application starting
Hi Jivan
Thank you for the example! Sorry for the convoluted description. I guess what Im trying to do can be explained simly 'how to retrieve media picker root folder from current page's parent x and open media picker at that folder'. Thinking about it, actually one can retrieve that value recursively too, like .GetProperty("mediaRootID",true) so it climbs up the tree until it finds a mediaRootID - this way one can define mediaroot overrides at any level.
You assumption is correct, mediaRootID is integer and MediaPicker datatype used in pages are of "Media picker" and not legacy picker.
I have tried to run you code on the remote system by placing it under App_Code folder. Since I dont have access to Visual Studio at this time, I have tried to add the references below, but i think missing obvious ones;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using System.Linq;
using System.Net.Http;
using Umbraco.Core;
using Umbraco.Web;
compilation error:
'Umbraco.Core.Models.IContent' does not contain a definition for 'Ancestors' and the best extension method overload 'Umbraco.Web.PublishedContentExtensions.Ancestors(Umbraco.Core.Models.IPublishedContent)
on
var m =
contextNode.Ancestors()
.FirstOrDefault(
x =>
What would be the complete using references I should be adding?
Here are the references i have used. // for MediaPickerExtension class
// for UmbracoStartUp : IApplicationEventHandler
I have tested on Umbraco 7.1.8 Here are the references i have used. // for MediaPickerExtension class
// for UmbracoStartUp : IApplicationEventHandler
I have tested on Umbraco 7.1.8 Here are the references i have used. // for MediaPickerExtension class
// for UmbracoStartUp : IApplicationEventHandler
Hi again Jivan
Many thanks for the quick reply. added references to both accordingly and no errors. I am using 7.1.8 too.
I have double checked; at level 2 node ,i have property mediaRootID (alias matches) is of Numeric data type, with value of media folder ID like 1325 (media->Doc/Images/Gallery2). and sub-pages of this node contain Media Picker (not legacy).
When i open the sub-page (tried children, also descendant) of level-2 node, of above, and select media picker, it doesnt change the root folder in the dialog.
Is there something I might be missing?
HI, Kello, Could you try changing uppercase D to lowercase d. I guess mediaRootID => mediaRootId
Ahh.. that was it. I could swear I checked that.
Its working smooth! Can this logic be adapted if one wants to incorporate this to the RichText Editor Image dialog?
Many thanks again for the great help!
Hi Everyone, did anyone managed to implement this in umbraco 8.1?
is working on a reply...