Orchard CMS: Custom Taxonomy View Template not working - taxonomy

I'm using a taxonomy part in one of my custom content types, and using the shape tracer, I was able to create a custom view template for that control (Fields.Contrib.TaxonomyField.cshtml).
When I shape trace the element on the page, under template it indeed shows my custom template exactly as I have it on the external file:
#using Orchard.Utility.Extensions;
#using Orchard.ContentManagement;
#{
var terms = (IEnumerable<Contrib.Taxonomies.Models.TermPart>)Model.Terms;
string name = #Model.ContentField.Name;
}
#if (Model.Terms.Count > 0) {
#(new HtmlString( string.Join(", ", terms.Select(t => Html.ItemDisplayLink(Html.Encode(t.Name), t.ContentItem ).ToString()).ToArray()) ))
}
<div>TEST TEXT</div>
However, when I tab over to the actual outputted HTML, it is showing the standard, built in template, and isn't using my customizations.
<p class="taxonomy-field">
Coffee Shop
</p>
According to the shape tracer, it is using my custom template:
Shape Fields_Contrib_TaxonomyField
Active Template
~/Themes/Continuum/Views/Fields.Contrib.TaxonomyField.cshtml
Display Type Detail
this feels like a bug... everything looks like it's wired up correctly... is there something else I need to do to use my custom view template for taxonomy?
Many thanks!

I figured out the problem. Turns out there was another template created (likely by accident) which was url-specific:
Fields.Contrib.TaxonomyField-url-venues.cshtml
that's the url I was on, and this had the default template still in it. After deleting it, it finally used my custom template.
User error, sorry!!

Related

Is it possible to allow user to edit and save html template in angularjs application

I have an traditional asp.net application which reads HTML template and renders it inside div control. Using bootstrap xeditable user can edit certain parts of the template (only text). This template is later used to send emails. This functionality is working fine. Now I am rewriting this application using AngularJs and WebApi. I am using angular route to route to different pages (plain html) of the application. I am able to load the template using directive. now I want to allow user to edit the text and save the complete template so that it can be used later for sending email.
MyTemplate.html
<p>this is some text</p>
<p>this is some more text</p>
<p>this is some another text</p>
Directive
myapp.directive("customDirective", function () {
return {
templateUrl: 'MyTemplate.html'
};
});
Notify.html
<div>
<h2>{{message}}</h2>
<input type="button" ng-click="Redirect()" value="Report" />
</div>
<custom-directive></custom-directive>
I want that user should be able to edit the text in MyTemplate.html and save it as complete template for later use. Is this achievable?
Do not store it in file. Store the template in your database. Provide a default value there, so something shows if the user has not modified it yet.
In you directive, load the template from your database through your API. After you do that, append the template to the contents of your directive inside your link callback function and compile the directive (if needed).
myapp.directive("customDirective", ($compile, yourService) => {
return {
link: (scope, elem) => {
yourService.fetchTemplate().then(template => {
elem.html(template);
$compile(elem.contents())(scope);
});
}
}
});
Please make sure to sanitise your data properly. It could be fairly dangerous injecting and compiling template created by the user.
I hope this points you in the right direction.
Edit
You might not event need the $compile step. It depends on what kind of template you have in mind. If it is just a simple element without any connection to angular, simply skip the $compile line.
Edit 2 - Display the template on click
Please note the following is just a very simplified version, but it should point you in the right direction.
In your parent controller
$scope.state = {
displayTemplate: false
};
In your template
<my-template-directive ng-if="state.displayTemplate"></my-template-directive>
<button ng-click="state.displayTemplate = true">Show Template</button>

Simplifying ASP.Net MVC Razor Code

I'm looking for suggestions on how to simplify/optimize a piece of code in one of my view files in my ASP.Net MVC project. The code works, but I'm not sure if I've written it the best way.
Basically, the code is used to display a list of links to documents, with little thumbnails to the left of each link. The main problem, is that there are two different types of documents, and each type has to have it's thumbnail image stored in a different location, this is a project requirement and can't be changed.
I'm currently accomplishing this with the view code shown below.
// Display a link to every document.
foreach (var document in documentList)
{
<a href="#Url.Content("~/Document/DownloadDocument/" +
document.documentid)" target="_blank">
#{
// This will be the root of all the paths.
var path = "~/Document/DisplayImage/";
// If it's a Type 1 document, we need to use a different path.
if (document.documentType == "Type 1") {
path += "Path/To/Image/Folder";
<img id="imageHolder" src="#Url.Content(path)"
onerror="imgError(this);" />
#document.documentname
}
else {
path += "Path/To/Different/Image/Folder";
<img src="#Url.Content(path)" />
#document.documentname
}
}
</a>
<br />
}
Like I said, the code works, but I'm not too happy with how it's written. Does anyone have any suggestions?
When working with MVC, it's best to keep your Views dumb (no logic, simply rendering).
You can accomplish this by using a strongly-typed View and performing all of the logic in the Controller. It looks like you may already be doing this since you have a documentList.
In this case, documentList should be a list of View Model objects that already have the appropriate image path already set on them from the controller.
I would suggest moving the path to your document image into your model. That way you can just display the image from the path in the model and you wouldn't have to put any logic in your view.

GSP Template fails to retrieve passed template from another template

I'm working on a Grails 2.4.4 project. I have the following code on my gsp page (not a template) that calls a sub template that calls another template: main gsp page > gsp template > yet another gsp template:
main.gsp
...
<g:render template="/details" model="[param_one:'param_one', param_two:'param_two']" />
...
_details.gsp
...
<p>On details: ${param_one}</p>
<g:render template="/segments/segment-one" model="[param_two:'${param_two}']" />
...
_segment-one.gsp
<p>Segment One: ${param_two}</p>
Now when it renders the whole page, it only shows something like this:
On details: param_one
Segment One: ${param_two}
Why does _segment-one.gsp fails to render the passed param_two? Is it not allowed to have template from another template rendering? Thanks guys.
First, you are allowed to have gsp pages call templates that call templates indefinitely. When you call a template, you are literally including the code of the template into the including page at runtime; in other words, a template is part of the caller and it would have access by default to all objects visible to the caller. All you have to do is to change your second inclusion to:
<g:render template="/segments/segment-one" />
Now, template segment-one will already have access to param_one and param_two. You only need to use your model tag again if you are passing something new created in the local template (or gsp) you are in.
I fixed the code in _segment-one.gsp by adding the params keyword:
<p>Segment One: ${params.param_two}</p>
^^^^^^

Orchard - Add an additional shape name (i.e. an alternate) for the main List shape

Introduce the Problem
I would like to profoundly modify the layout of the Orchard CMS Tags list.
Here is an example page with Shape Tracing enabled.
The only alternate that it suggests for the List shape is ~/Themes/TheThemeMachine/Views/List.cshtml, because the page is rendering the default List shape. I would like to have other alternates that are specific to the page.
After reading Orchard list customization, I have been able to implement the default List.cshtml in razor. What I would like to do, though, is to add another alternate, such as ~/Themes/TheThemeMachine/Views/Parts.Tags.List.cshtml instead of implementing the default List.cshtml template.
The problem seems to be that the page is rendering the generic List shape.
In contrast, the blog post list page is rendering a Parts_Blogs_BlogPost_List shape, which means that a ~/Themes/TheThemeMachine/Views/Parts.Blogs.BlogPost.List.cshtml is available.
Search and Research
All quotes below are from the Orchard list customization blog post, which explains how to add a list item alternate (whereas I would like to add a list alternate).
What we really want is an alternate template... aptly called Shape
Alternates... [so] enable Shape Tracing... and select a post in the list...
[you will see that] we already have some possible alternates.
My example page also has some possible alternates for the List Content. Cool.
we need to somehow get into list rendering... [t]he default is defined
in code... [which] can be override by a new [cshtml] template in our
theme.
Okay. That makes sense. We can override the list rendering.
As Shape Tracing can show, we can override the list rendering for a
blog by creating a Parts.Blog.BlogPost.List.cshtml template.
This works for alog but not for the blog Tag page (example page). You see, the blog displays a **Parts_Blogs_BlogPost_List shape and suggests an appropriate alternate but the blog tags page displays the default List shape with no alternates other than List.cshtml.
Blog Page with alternates galore
Blog Tags Page with one alternate List.cshtml
So, I created a List.cshtml not a Parts.Blog.BlogPost.List.cshtml template, and save it in my theme's Views directory. (One problem here is that, once we get it working, we will b overriding the default List rendering.)
Then I add the Razor code (copy and pasted from Bertrand's post) to override the default rendering for Lists. When I refresh the site, the browser renders a blank page. It isn't working. Here's the code:
This Does NOT Work in List.cshtml
#using Orchard.DisplayManagement.Shapes;
#{
var list = Model.ContentItems;
var items = list.Items;
var count = items.Count;
var listTag = Tag(list, "ul");
listTag.AddCssClass("content-items");
listTag.AddCssClass("blog-posts");
var index = 0;
}
#listTag.StartElement
#foreach (var item in items) {
var itemTag = Tag(item, "li");
if (index == 0) {
itemTag.AddCssClass("first");
}
else if (index == count - 1) {
itemTag.AddCssClass("last");
}
#itemTag.StartElement
#Display(item)
#itemTag.EndElement
++index;
}
#listTag.EndElement
As a trouble shooting step, I replace the List.cshtml with <p>Hello world.</p>. Orchard renders the markup as expected. So, something is incompatible between the Razor code from Bertrand's blog and the Tags List.
To find out what exactly is incompatible, I try Betrand's code one line at time to see where it breaks (yup, VS would be better than WM here). At each change, I restart WebMatrix and view the results. This is the minimal code that breaks it.
The Culprit
#using Orchard.DisplayManagement.Shapes;
#{
var list = Model.ContentItems;
var items = list.Items;
}
list.Items isn't appropriate here. So I comment it out again and run the <p>Hello World</p> version again. Also, Shape Tracing reveals that on my Tags/tagname page, the Content Zone is now rendering the List twice. Is that normal?
As another step, I replace Model.ContentItems just with Model. It works. It seems that, to override the List.cshtml template, we cannot use the ContentItems property of Model. Here is the new, working code:
This Does Work in List.cshtml
#using Orchard.DisplayManagement.Shapes;
#{
//var list = Model.ContentItems;
//var items = list.Items;
var items = Model.Items;
var count = items.Count;
//var listTag = Tag(list, "ul");
var listTag = Tag(Model, "ul");
listTag.AddCssClass("content-items");
listTag.AddCssClass("blog-posts");
var index = 0;
}
#listTag.StartElement
#foreach (var item in items) {
var itemTag = Tag(item, "li");
if (index == 0) {
itemTag.AddCssClass("first");
}
else if (index == count - 1) {
itemTag.AddCssClass("last");
}
#itemTag.StartElement
#Display(item)
#itemTag.EndElement
++index;
}
#listTag.EndElement
Onward through the article.
So far so good, we have effectively taken over the rendering of the
list, but the actual HTML [will] be... identical to what we had before
[except for] the implementation.
Okay. I'm following. We want to modify the rendering not just re-implement it.
Alternates are a collection of strings that describe additional shape
names for the current shape... in the Metadata.Alternates property of any shape.
Gotcha. Now, why doesn't the Tags/tagname page show an alternate other than just List.cshtml for the rendering of the List shape?
All we need to do is add to this list [of alternates]... [and make sure] to respect the lifecycle...
Great. Maybe we can we add another alternate for the List shape on the Tags/tagname page. But, doing that is different from what Betrand is explaining. While Betrand's blog post is excellent, it is explaining how to add an alternate for an item, whereas I would like to add an alternate for the list.
The List.cshtml template is where I would add an alternate for a List Item as follows:
ShapeMetadata metadata = item.Metadata;
string alternate = metadata.Type + "_" +
metadata.DisplayType + "__" +
item.ContentItem.ContentType +
"_First";
metadata.OnDisplaying(ctx => {
metadata.Alternates.Add(alternate);
});
So that...
[t]he list of alternates from Shape Tracing now contains a new item.
Where and how, though, would I add an alternate for the List shape? Bertrand has recommended to check out the Shape Table Providers blog post for this. The quotes below are from that post.
But what if you want to change another shape template for specific
pages, for example the main Content shape on the home page?
This looks like a fit, because my example is the main List shape on the tags page. To do this we...
... handle an event that is triggered every time a shape named "Content"
[in our case "List"] is about to be displayed. [It] is implemented in a shape table provider which is where you do all shape related site-wide operations.
Great! Here is my implementation for adding another template for the main List shape.
TheThemeMachine > ListShapeProvider.cs
namespace Themes.TheThemeMachine
{
using Orchard.DisplayManagement.Descriptors;
public class ListShapeProvider : IShapeTableProvider
{
public void Discover(ShapeTableBuilder builder)
{
System.Diagnostics.Debugger.Break(); // break not hit
builder.Describe("List").OnDisplaying(displaying => {
// do stuff to the shape
displaying.ShapeMetadata.Alternates.Add("Tags__List");
});
}
}
}
The above builds and runs but does not hit the breakpoint nor add an alternate for the List shape on the /tags page. So I looked into the Orchard.Azure.MediaServices module and its CloudVideoPlayerShape which implements IShapeTableProvider. Its breakpoint does get hit. How is my code for ListShapeProvider fundamentally different than the code for the CloudVideoPlayerShape?
Also, I installed the Orchard.Themes.CustomLayoutMachine.1.0.nupkg as suggested in Bertrand's blog post. It unfortunately no longer contains an implementation of IShapeTableProvider.
I have also looked at this szmyd post, which does not explain where to put the IShapeTableProvider code.
Further, I installed the Contoso theme from the Orchard Gallery. It works and builds after adding a reference to Microsoft.CSharp. It also includes an implementation of the IShapeTableProvider. Hooray! Comparing its ContentShapeProvider with my ListShapeProvider reveals a subtle but important difference:
Contoso.csproj
<ItemGroup>
<Compile Include="Code\ContentShapeProvider.cs" />
</ItemGroup>
My implementation didn't include the .cs file in the compilation, because my theme has neither a .csproj nor a App_Code folder. So, I recreated my theme with the following code generation:
orchard.exe
feature enable Orchard.CodeGeneration
codegen theme My.FirstTheme /CreateProject:true
theme enable My.FirstTheme
feature enable Orchard.DesignerTools
When adding the ListShapeProvider.cs file, Visual Studio automatically added a ItemGroup/Compile entry for the file, which included the code in compilation. Hooray!
These two posts will help.
Shape Shifting
List Customization
Here are steps of my own minimum solution.
Download and unzip Orchard.Source.1.8.zip.
Open "\Downloads\Orchard.Source.1.8\src\Orchard.sln" in Visual Studio.
Build the solution to create orchard.exe.
Generate a new theme with orchard.exe. Use CreateProject:true because you will need a csproj to include your .cs file.
orchard.exe
setup /SiteName:SITE /AdminUsername:ME /AdminPassword:PWD /DatabaseProvider:SqlCe
feature enable Orchard.CodeGeneration
codegen theme My.FirstTheme /CreateProject:true
theme enable My.FirstTheme
In VS, add a ListShapeProvier.cs file to the root (or any folder) in your theme.
Add the following code to ListShapeProvider.cs.
namespace My.FirstTheme
{
using Orchard.DisplayManagement.Descriptors;
public class ListShapeProvider : IShapeTableProvider
{
public void Discover(ShapeTableBuilder builder)
{
System.Diagnostics.Debugger.Break();
// implementation here
}
}
}
Build the solution.
Run Orchard.Web.
Visual Studio will break at System.Diagnostics.Debugger.Break(). If it doesn't, go to the Orchard Dashboard and make My.FirstTheme the Current Theme.
Now read Shape Shifting to implement public void Discover(ShapeTableBuilder builder).
This post should give you a full response: http://weblogs.asp.net/bleroy/archive/2011/05/23/orchard-list-customization-first-item-template.aspx

Razor: Retrieving variable from component template on page template

Hi all,
I've been working on a set of Razor templates that is either Site Editable with the Experience Manager and at the same time is fully responsive for several screenwidths with the Twitter bootstrap. As a result, I need to dynamically manipulate the DOM output based on what the Experience Manager editor adds or deletes but still maintain the responsive design. Part of this construction is adhering to the rules the twitter bootstrap dictates.
The twitter bootstrap allows for excellent responsive design by introducing dynamically calculated div widths using classes. A <div class="span12> uses the entire width of the wrapper, for example. A "span6" effectively uses half, with a certain margin calculated as well to allow for another div with "span6". However, this only works if the preceding class is called <div class="row-fluid">,and as long as the span<numbers> actually add up to exactly 12. The problem arises when I need to close the <div class="row-fluid"> when this number is actually reached.
To clarify: it has to output like this
<div class="row-fluid">
<div class="span6">..code</div>
<div class="span4">..code</div>
<div class="span2">..code</div>
</div>
The <div class="span[#]"> are rendered with a component template, in order to allow for multiple components within the <div class="row-fluid>, which the Page Template renders.
However, from a component template level I cannot seem to retrieve the actual amount of components of this template actually exist on the Page itself. I calculate the width of the component used based on a schema option of the component itself. I use the following Component Template code to render it correctly:
#{
var spanClass = String.Empty;
if (Fields.HasField("component_width") && Fields.component_width != null) {
if (Fields.component_width.ToLower() == "full") {
spanClass = "span12";
} else if (Fields.component_width.ToLower() == "half") {
spanClass = "span6";
} else if (Fields.component_width == "40%") {
spanClass = "span5";
} else if (Fields.component_width == "35%") {
spanClass = "span4";
} else if (Fields.component_width == "25%") {
spanClass = "span3";
}
}
}
<div class="#spanClass">...code
To get to my question: I need to be able to close the <row-fluid> div if the number 12 has been reached. So if one component with the options 'Full' (width) is selected, the following output code needs to appear:
<div class="row-fluid">
<div class="span12">..code</div>
</div>
If there are two components on the page with the option "half" are selected, it must allow
<div class="row-fluid">
<div class="span6">..code</div>
<div class="span6">..code</div>
</div>
mind the closing div on the end. Is there some way I can reach the variable i created on the Component Template var spanClass = String.Empty; from Page Template? Something like:
#foreach (var cp in GetComponentPresentationsByTemplate("XM_Generic Content")) {
#if (cp.Component.spanClass == "span6") {
<div class="row-fluid">
#cp.RenderComponentPresentation()
#if (cp.Index == 1) {
</div>
}
}
}
I'm still getting to know Razor templates, the practicalities of Responsive design and ofcourse StackOverflow. Chances are that I completely missed something, made dumb errors in my code of just asked a silly question. By all means, let me know.
The package is not shared between template runtimes, so this behavior is normal (not being able to see variables set in one template from a different instance).
There are ways around this, but you should consider that perhaps there is a good reason why Tridion chose to isolate the template execution.
See here for one of the ways to go around this.
Standard techniques using the ContextVariables dictionary don't allow you to set something in the CT and access it from the PT. Effectively, each time a Component is rendered, the render context gets a fresh copy of the variables from the page render context. Writing back to them, therefore isn't effective. There is a technique that gets round this, which is described in detail on tridion-practice. As already noted, resorting to these kinds of techniques shouldn't be your first option, but sometimes you need to.
Currently, its seems, the user is defining the width position in the component field. I think, its quite typical, but if you create 5 Component Template which will call a same Razor TBB, and also define, a parameter schema on component Template where can set the width of component then afterwards you can easily call these different CTs in the page template.