Kentico 9 - Add content to an Editable Image Region (CMSEditableImage) programatically - kentico

We are looking for information on how to add content to an Editable Image programatically (with the Kentico C# API). Essentially, the equivalent of this Editable Region article for an Editable Image.
Any suggestions?
Thanks,
Victor
References:
CMSEditableImage Docs
Devnet Update EditableRegion Programatically
CMSEditableImage Class

You Sure Can
Each individual editable cms page control is stored in the document's DocumentContent field and can be accessed using an indexer field. For example:
TreeNode document = DocumentContext.CurrentDocument;
string editableImageControlId = "EditableImage1";
// get the field value
string editableImageContent = document.DocumentContent.EditableRegions[editableImageControlId];
// set it to something new
document.DocumentContent.EditableRegions[editableImageControlId] = newValue;
HOWEVER
If you look at the DocumentContent field in CMS_Document in the database you'll notice that all of the content is XML. That's because each control is serialized into XML and then nested inside this field. Thus, in this case, the value of the editableImageContent variable is an XML string:
<image>
<property name="imagepath">
~/Folder/ImageName.png
</property>
</image>
I wouldn't recommend trying to modify this directly since there's no telling if Kentico would ever change this code, or the individual control would ever change its serialization output.
But if you really must
You've got a couple of options:
1. Per #josh, you could create a new control that wraps the existing one and do some method override magic so that the control continues to do the serialization on your behalf and you just modify it after the fact. However this requires that the control is currently loading.
2. You could just hard code the beast and deal with it if it ever changes (which it likely will). Try:
// get the node from wherever you need to get the node
TreeNode document = DocumentHelper.GetDocuments().TopN(1).FirstObject;
var relativeMediaFilePath = "~/NewImage.png";
var xmlImage = string.Format("<image><property name=\"imagepath\">{0}</property></image>", relativeMediaFilePath);
var cmsControlId = "editableImage1";
if (document.DocumentContent.EditableRegions.ContainsKey(cmsControlId)) {
document.DocumentContent.EditableRegions[cmsControlId] = xmlImage;
}
else {
document.DocumentContent.EditableRegions.Add(cmsControlId, xmlImage);
}
// a little hack to get this field to be indicated as updated
document.SetValue("DocumentContent", document.DocumentContent.GetContentXml());
document.Update(true);

You could clone the editableimage webpart and then work in the prerender or change the override for the GetContent() method and add your own part of the string or do a string replace and add your code.

What is that you want to add to an Editable Image? - image path?! Not sure why you'd do that, but I'd take another direction: I'd add a field to a page type, which makes it much easier to work with through API. Having this field set up with API is should be quite easy to get it on the page... e.g. place editable image and use a macro to get field value.

Use
node.DocumentContent.EditableWebParts
and
node.DocumentContent.EditableRegions
collections to programmatically update editable content.
The best code example can be spotted at \CMS\CMSModules\Content\CMSDesk\Properties\Advanced\EditableContent\Main.aspx.cs
It's the dialog under Pages->General->Advanced->Edit regions & web parts.

Related

Alternate shape for EditorTemplate of Field is not being recognized

I need an alternate for the EditorTemplate of an Enumerator Field that's used when the Field has a particular name (PublishingMethod).
Based on the docs, I created a view with the pattern [ShapeType__FieldName] in the same folder as the original shape:
This is not working and still uses the original. I've thought of changing the Editor method in the Driver, but I think that defeats the purpose of alternates, which is that Orchard automatically detects the correct shape as I understand from the docs:
The Orchard framework automatically creates many alternates that you can use in your application. However, you can create templates for these alternate shapes.
Note: I can't use the Shape Tracing module, it never worked even with a clean Orchard install.
The editors in Orchard work different to how Display works. I guess it is so you get a MVC-style experience. Basically, the actual shape returned is of type EditorTemplate, which then binds your model and prefix then renders a partial view with the template name you gave it. What this means is alternates wont work as expected, or as the docs state. The alternates for your field name are actually added to the EditorTemplate shape. So what you can do is add a view called EditorTemplate-PublishingMethod.cshtml with contents like:
#{
var m = (Orchard.Fields.Fields.EnumerationField)Model.Model;
}
#Html.Partial("PublishingMethodEditor", m, new ViewDataDictionary {
TemplateInfo = new TemplateInfo { HtmlFieldPrefix = Model.Prefix }
})
Then add another view called PublishingMethodEditor.cshtml with the overrides you want for your editor. All these views should go in the root of your Views folder.
Another approach would be to implement the IShapeTableProvider interface and adjust the TemplateName property on a certain condition but, meh, that requires code...
Edit 1
If you have that field name on other content types that you don't want to override you can use the override EditorTemplate-ContentTypeName-PublishingMethod.cshtml

OrchardCMS: How to access Content Menu Item boolean field in cshtml view

In orchard, I've added a boolean field called "IsDone" to the built in Content Menu Item content part via that Admin interface. I've then picked an item in Navigation and set the option to "yes" for the corresponding field i added.
In my custom theme, I've copied over MenuItem.cshtml.
How would I get the value of my custom "IsDone" field here?
I've tried something like
dynamic item = Model.ContentItem;
var myValue = item.MenuItem.IsDone.Value;
but I'm pretty sure my syntax is incorrect (because i get null binding errors at runtime).
thanks in advance!
First i suggest you use the shape alternate MenuItemLink-ContentMenuItem.cshtml instead of MenuItem.cshtml to target the content menu item directly.
Secondly, the field is attached to the ContentPart of the menu item. The following code retrieves the boolean field from this content part:
#using Orchard.ContentManagement;
#using System.Linq;
#{
Orchard.ContentManagement.ContentItem lContentItem = Model.Content.ContentItem;
var lBooleanField = lContentItem
.Parts
.Where(p => p.PartDefinition.Name == "ContentMenuItem") // *1
.SelectMany(p => p.Fields.Where(f => f.Name == "IsDone"))
.FirstOrDefault() as Orchard.Fields.Fields.BooleanField;
if (lBooleanField != null)
{
bool? v = lBooleanField.Value;
if (v.HasValue)
{
if (v.Value)
{
#("done")
}
else
{
#("not done")
}
}
else
{
#("not done")
}
}
}
*1
Sadly you cannot simply write lContentItem.As<Orchard.ContentManagement.ContentPart>() here as the first part in the part list is derived from this type, thus you would receive the wrong part.
While #ViRuSTriNiTy's answer is probably correct, it doesn't take advantage of the power of the dynamic objects that Orchard provides.
This is working for me but is a much shorter version:
#Model.Text
#{
bool? IsDone = Model.Content.ContentMenuItem.IsDone.Value;
var IsItDoneThough = (IsDone.HasValue ? IsDone.Value : false);
}
<p>Is it done? #IsItDoneThough</p>
You can see that in the first line I pull in the IsDone field using the dynamic nature of the Model.
For some reason (I'm sure there is a good one somewhere) the BooleanField uses a bool? as its backing value. This means that if you create the new menu item and just leave the checkbox blank it will be null when you query it. After you have saved it as checked it will be true and then if you go back and uncheck it then it will have the value false.
The second line that I've provided IsItDoneThough checks if it has a value yet. If it does then it uses that, otherwise it assumes it to be false.
Shape Alternate
#ViRuSTriNiTy's other advice, to change it to use the MenuItemLink-ContentMenuItem.cshtml instead of MenuItem.cshtml is also important.
The field doesn't exist on other menu items so it will crash if you try to access it. Just rename the .cshtml file to fix this.
Dynamic Model
Just to wrap this up with a little bit of insight as to how I got there (I'm still learning this as well) the way I figured it out is as follows:
.Content is a way of casting the current content item to dynamic, so you can use the dynamic advantages with the rest of line;
When you add the field in the admin panel it looks like it should be right there on the ContentItem, however it actually creates an invisible ContentPart to contain them and calls it whatever the ContentItem's type is.
So if you had added this field to a Page content type you would have used Model.Content.Page.IsDone.Value. If you had made a new content type called banana it would be Model.Content.Banana.IsDone.Value, etc.
Once you are inside the "invisible" part which holds the fields you can finally get at IsDone. This won't give you the actual value yet though. Each Field has its own properties which you can look up in the source code. the IsDone is actually a BooleanField and it exposes its data via the Value property.
Try doing a solution-wide search for : ContentField to see the classes for each of the fields you have available.
Hopefully this will have explained things clearly but I have actually written about using fields in a blog post and as part of my getting started with modules course over on the official docs (its way down in part 3 if you're curious).
Using built-in features instead of IsDone
This seems like a strange approach to do it this way. If you have a Content Item like a Page then you can just use the "Show on a menu" setting on the page.
Go to admin > content > open the page > down near the bottom you will find "Show on a menu":
This will automatically put it into your navigation and then you can move it around to where you want:
After it "IsDone" you can just go back and untick the "Show on a menu" option.
Setting up the alternative .cshtml
To clarify your comments about how to use the alternative, you need to
Copy the file you have at Orchard.Core/Shapes/Views/MenuItem.cshtml over to your theme's view folder so its /Views/MenuItem.cshtml
Rename the copy in your theme to MenuItem-ContentMenuItem.cshtml
Delete probably everything in it and paste in my sample at the start of this post. You don't want most of the original MenuItem.cshtml code in there as it is doing some special tricks to change itself into a different shape which isn't what you want.
Reset your original Orchard.Core/Shapes/Views/MenuItem.cshtml back to the factory default, grab it from the official Orchard repository
Understanding the view names
From your comments you asked about creating more specific views (known as alternates). You can use something call the Shape Tracer to view these. The name of them follows a certain pattern which makes them more and more specific.
You can learn about the alternates on the official docs site:
Accessing and Rendering Shapes
Alternates
To figure out what shape is being used and what alternates are available you can use the shape tracing module which is documented here:
Getting Started with Shape Tracing

Opening different xpages forms from a view panel

I have an Xpages application that pulls data from another .nsf file. I have a view panel linked to a view in that db. The view has documents with several different forms in it. I want to be able to open each document in it's own form(xpage).
How do I write a computed At Runtime, open selected document using: statement that will select the correct Xpage to present the document.
If you use the Data View component instead of a View Panel, you can compute the pageName attribute, referencing the var attribute to return a different value for each row based on the document that row represents. The flexibility of the Data View component also makes it easier to make your app look more like a modern web application and less like an Excel spreadsheet. As an additional bonus, the mobile theme invokes a renderer that makes each Data View instance look like a native mobile list, so using Data Views instead of View Panels simplifies mobile development.
You have 2 options:
use "use xpage associated with form" and edit the form's property
use a SSJS formula to compute the Form. You provide a variable name in the view control var to access a view row as XSPViewEntry. If the Form is in a view column even one you don't display you use .getColumnValue otherwise getDocument.getItemValueString
Does that work for you?
Maybe this mothed can help you: Unable to get document page name for
Hope this helps
Mark
I had a similar problem today. I use only one form but 3 different xpages for associated with this form. I have 3 different document types in the view. I used rowData the get the type of the document.
try{
var v=rowData.getColumnValue("form");
if(v.indexOf("x")> -1){var page ="x.xsp"}
else if(v.indexOf("y") > -1){var page = "y.xsp"}
else{var page = "z.xsp"}
}catch(e){
var page = "x.xsp"
}
So to your view you can create a column with the value of the form and you can use it.
I have used the extension library Dynamic View control which has an event you can code to get a handle to the NotesViewEntry which was selected. See the demo database page Domino_DynamicView.xsp and the Custom Event Handler tab for an example.
Note, in 8.5.3 (I have not upgraded yet) if you add or edit the eventHandler for onColumnClick it will be added to the XPages source as an xe:eventHandler. It needs to be an xp:eventHandler to work. The way to do it is to copy the code in the source from the exiting event and delete it. Recreate the event and update the code. Then go back into the source and change the tags within the eventHandler to xp:.

Sharepoint-customizing usercontrol property in smartpart

If anyone is having idea how to customize properties in a smartpart. I have created usercontrol and i m wrappin it in a smartpart.I want to upload my xml from Document library.
private string feedXML;
[Browsable(true),
Personalizable(true) ]
public string FeedXML
{
get
{ return feedXML; }
set
{ feedXML = value; }
}
and I am using this like
//
feedXML="\customxml.xml";
XPathDocument doc = new XPathDocument(Server.MapPath(feedXML));
but this thing is not working . When I am clicking on modify shared webpart of sharepoint page is not rendering. Any clue where I m getting wrong.
You might want to verify the result of your server.mappath statement. It will be something like C:\Inetpub...
So your code is trying to retrieve a file from the filesystem that really lives in SharePoint because you have uploaded it to a Document Library.
If you want that file you'll have to retrieve it using the SharePoint object model, have a look at the GetFileAsString method.
I agree with Denni..
Seems like Smartpart is only making it more difficult? What advantages does it have?
I make my own webpart containers for ascx controls.. very little work and all the control you need. No problems with trust settings either.
Are you sure this is correct?
feedXML="\customxml.xml";
Perhaps, what you want is:
feedXML="\\customxml.xml"; //escape the back-slash.
or
feedXML="/customxml.xml"; // use the forward-slash.
Anyway, if you just want to wrap your user control inside a Web part, you don't need the SmartPart. You can write your custom Web part yourself quite easily.

Person & Group custom field type sharepoint

I have created a custom field type as it is there in sharepoint OOTB, the difference is only that the end user does not need to check the name i.e I have replaced it with DropDownList. The dropdownlist suggest the no. of users available in the web site for that I have created a FieldClass which inherits from SPFieldUser and a FieldControlClass which inherits from UserField. It is working fine in all conditions i.e when I create a List or Document Libarary it shows me the DropDownList
with respective users after saying OK it creates an item for me. I have overriden a Value property in FieldControlClass as follows,
public override object Value
{
get
{
SPUserCollection userscollection = rootWeb.SiteUsers;
//ddlInfoBox is a DropDownList to which I have Binded the collection of users in the form of string
SPUser user = userscollection.Web.EnsureUser(this.ddlInfoBox.SelectedValue);
SPFieldUserValue userval = new SPFieldUserValue(user.ParentWeb, user.ID, user.LoginName);
return userval;
}
set
{
SPFieldUserValue userval = (SPFieldUserValue) this.ItemFieldValue;
this.ddlInfoBox.SelectedValue = userval.Lookupvalue; //Here look up value is nothing but a Login name e.g In-Wai-Svr2\tjagtap
}
}
Due to above property the Custom Field's Value for this current ListItem will be stored as SPFieldUserValue e.g 27#;In-Wai-Svr2\tjagtap.
The main problem is here, when this particular ListItem is shown in the list page views e.g on AllItems.aspx or the custom view pages associated with it, it shows the
number as 27 as a FieldValue insted of HyperLink with text as "In-Wai-Svr2\tjagtap" and PostBackURL as "/_layouts/userdisp.aspx?ID=27".
When I edit this Item it makes the respective value selected in the dropdownlist, also while viewing this item i.e on DispForm.aspx it also shows the hyperlink. I have
acheived it by writting a custom logic in createchildcontrol() method i.e by using ControlMode if it is New or Edit then fill the dropdown list, if it is Display then get the ItemFieldValue Type Cast it into SPFieldUserValue and get corresponding lookupid and value for making the URL and showing Text of the HyperLink.
I have spent a lot of time on searching and bringing the HyperLink as the user name with navigation insted of UserID (27) as a string on the list view pages e.g AllItem.aspx but to no avail, then after a lot of research I found that there might be a way of achieving such kind of functionality by using field type definition xml file where there is a provision to define a DisplayPatteren as you wish by specifying the html code. But here is a problem How can I get the UserID (27) with respective UserName e.g In-Wai-Svr2\tjagtap inorder to make an anchor tag like In-Wai-Svr2\tjagtap which will solve my problem. I have hard coded this anchor tag within the Default case statement of a switch under DisplayPatteren but it shows me the field value on AllItems.aspx as
In-Wai-Svr2\tjagtap27 i.e the value defined in xml file is concatenating with the string value (27).
Please help me to resolve the above mentioned 2 issue. I am really in need of solving this problem ASAP.
Thanks & Regards,
Tejas Jagtap
Have u tried to override the GetFieldValueAsHtml() method in the the custom field class or maybe the RenderFieldForDisplay() method in the custom field control class.
Can you use the DisplayPattern CAML from the User field type?

Resources