I'm trying to get the simple example to work, here is the sample code .stg file
group list-demo;
htmListExample(xmen) ::= <<
Example 5:
<html>
<body>
<h1>Original X-Men</h1>
<ul>
$xmen:listItem()$
</ul>
</body>
</html>
>>
listItem() ::= <<
<li>$it$</li>
>>
My Java code:
STGroup group = new STGroupFile("/myTemplate2.stg",'$','$');
ST template = group.getInstanceOf("htmListExample");
List<String> xmen = Arrays.asList("Jean Gray", "Cyclops");
template.add("xmen", xmen);
System.out.println(template.render().toString());
And the output:
context [/htmListExample] 6:18 passed 1 arg(s) to template /listItem with 0 declared arg(s)
context [/htmListExample] 6:13 passed 1 arg(s) to template /listItem with 0 declared arg(s)
context [/htmListExample] 6:13 passed 1 arg(s) to template /listItem with 0 declared arg(s)
context [/htmListExample /listItem] 2:5 attribute it isn't defined
context [/htmListExample /listItem] 2:5 attribute it isn't defined
Example 5:
<html>
<body>
<h1>Original X-Men</h1>
<ul>
<li></li>
<li></li>
</ul>
</body>
</html>
Can anyone shed some light as to why the listItem() is not recognized? I'm using the ST-4.0.7.jar.
Thanks
In StringTemplate 4, the map operator : maps a collection to a template that takes one argument. You need to declare the it argument for the listItem template:
listItem(it) ::= <<
<li>$it$</li>
>>
The warnings which you saw in the output say this:
ST4 expected a template with 1 parameter, but you passed it listItem which takes 0 parameters.
You didn't declare the it parameter, but you referenced it within listItem.
Related
i'm trying to add a few classes to a listitem object in my html using razor and a helper method.
I defined a #functions{} section with a method :
public string AddClasses()
{
return "classes=\"class1 class2\"";
}
when using in razor
<li #AddClasses()>tekst</li>
the result is:
<li class=""class1" class2"">tekst</li>
what am i doing wrong?
Razor automatically html encodes any string so it turns your " into ".
To turn off the html encoding you need to use the Html.Raw method (MSDN):
<li #Html.Raw(AddClasses())>tekst</li>
Hello guys I have this weird problem with Razor Syntax.
I have written the same code nuggets in Razor syntax ,having only difference in Inline expression and Multi-statement block.
About.cshtml
<!-- Single statement blocks -->
<p>
Put content here.
#Html.SubmitButton("You are in About")
</p>
Rendered Output:
Index.cshtml
<!-- Inline expressions BUT DOESNT WORKS-->
#{ Html.SubmitButton("okay in Index");}
<!-- Multi-statement block BUT DOESNT WORKS-->
#{
Html.SubmitButton("You are in Index");
Html.CheckBox("A Check Box");
}
Rendered Output:
P.S: Ignore the input button text in the snapshot.
The htmlhelpers only return values.
Even inside code blocks, you still need the # to tell Razor what to do with those values (print them to the HTML buffer).
So never-mind with the code block in this case, it would be redundant, as there's no other code in there but the html-helpers.
But even if there were other code to be placed within the block, you'd still need to preface the helpers with #:
#{
var myVar = "something";
// and so on ...
#Html.SubmitButton("You are in Index");
#Html.CheckBox("A Check Box");
}
I have a page template that outputs three component presentations in a div down the bottom of the page. All three of these component presentations use the same schema and Dreamweaver component template.
I'd like to style these component presentations slightly differently based on whether they're the first component in that div, or the last - basically I'd like to add "first" and "last" CSS classes to each component presentation.
I'm trying to set "arguments" for the component presentations dynamically, in a template building block. Below is what I've got so far (doesn't work, but just to give you an idea of what I'm trying to do):
public override void Transform(Engine engine, Package package)
{
var page = GetPage();
var wantComponents =
from c in page.ComponentPresentations
where c.ComponentTemplate.Title == "Content highlight"
select c;
if (wantComponents.Count() > 0)
{
// pseudocode - won't compile!
wantComponents.First().ComponentTemplate.Parameters["myCssClass"] = "first";
wantComponents.Last().ComponentTemplate.Parameters["myCssClass"] = "last";
}
...
In my Dreamweaver template (again, doesn't work, just to give you an idea of what I'm trying to do):
<div class="block ##Parameters.myCssClass##">
...
</div>
How do I dynamically add the "first" CSS class to the first component presentation on the page, and the "last" CSS class to the last component presentation on the page?
Not a bad question at all George.
If you take your divs out of the Component Template and put them into the Page Template then you don't need to pass the arguments from the Page template into the Component Template. Then setting the CSS class to the first component presentation is easy:
<div class="<!-- TemplateBeginIf cond="TemplateRepeatIndex==0" -->myFirstCssClass<!-- TemplateEndIf -->"></div>
Setting a class on the last Component Presentation is a bit more fun and there are a couple of ways this can be achieved:
A custom Dreamweaver function, for example TemplateRepeatCount(). Then you can do stuff like this inside your Page Template:
<!-- TemplateBeginRepeat name="Components" --><div class="<!-- TemplateBeginIf cond="TemplateRepeatIndex==TemplateRepeatCount()-1" -->lastCssClass<!-- TemplateEndIf -->">##RenderComponentPresentation()##</div><!-- TemplateEndRepeat -->.
The other approach is to write a basic TBB that counts up the component presentations and drops the total number onto the package, and then you can compare your TemplateRepeatIndex against this number.
Both #1 and #2 above are described in my article here: http://www.tridiondeveloper.com/more-fun-with-dreamweaver-templates-templaterepeatcount
Finally, here is an approach more inline with specifically what you were asking where a Component Template actually looks up into the Page's scope to determine if it's the last Component Presentation in the list. It's not my favourite because it's not so easy to debug with TemplateBuilder (since when you're running through a CT you don't have a PT, hence the component presentation count doesn't exist in this scope).
public class IsLastCP : TemplateBase
{
private string MY_SCHEMA = "My Component's Schema Title";
public override void Transform(Engine engine, Package package)
{
this.Initialize(engine, package);
//in the page template.
Page page = this.GetPage();
if (page == null)
{
//this TBB is being executed either in Template Builder or a dynamic component presentation.
// so we just don't do anything.
}
else
{
IList<ComponentPresentation> cpList = page.ComponentPresentations;
int cpCount = 0;
int thisCPIndex = -1;
Component thisComponent = this.GetComponent();
foreach (ComponentPresentation cp in cpList)
{
Component comp = cp.Component;
if (comp.Schema.Title == MY_SCHEMA)
{
if (comp.Id.Equals(thisComponent.Id))
thisCPIndex = cpCount;
cpCount++;
}
}
if (thisCPIndex == cpCount-1)
{
package.PushItem("IsLastCP", package.CreateStringItem(ContentType.Text, "true"));
}
}
}
For this you'll need Will's famous TemplateBase class which you can get from his "Useful Building Blocks" extension available from SDLTridionWorld. Obviously you'll need to tweak the code I provided to your schema name, etc.
Drop this TBB ahead of your Dreamweaver TBB in your Component Template then use its output like this: <!-- TemplateBeginRepeat name="IsLastCP" -->class="myLastCSSClass"<!-- TemplateEndRepeat -->
Note: you don't need to do a TemplateBeginIf here and check explicitly for true/false on IsLastCP. If the CP in question is last, then this variable will be present in the package, and the TemplateBeginRepeat clause will enter.
You can also do this kind of thing using Context Variables. You can't do this directly from a DWT, so this would mean perhaps writing a function source, or perhaps replacing the DWT with an assembly TBB that writes to output. If this kind of approach fits your design you can just write a variable into engine.PublishingContext.RenderContext.ContextVariables from the page template, indicating whether the Component render is the first or not, and then have the component template read it to determine what output to produce.
In general, the idea is to write variables in the page template and read them in component templates. This should be enough to let you avoid moving component template concerns into the page template, although, of course, the amount of plumbing might put you off. For more extreme cases, it's possible to get values from the component template to the page template, but then you've got even more plumbing, so wanting to do that at all might be a design smell.
There seems to be no documentation on the codeplex page and for some reason intellisense doesn't show me available methods or anything at all for htmlagilitypack (for example when I type MyHtmlDocument.DocumentNode. - there is no intellisense to tell me what I can do next)
I need to know how to remove ALL < a > tags and their content from the body of the HTML document I cannot just use Node.InnerText on the Body because that still returns content from A tags.
Here is example HTML
<html>
<body>
I was born in <a name=BC>Toronto</a> and now I live in barrie
</body>
</html>
I need to return
I was born in and now I live in barrie
Thanks, I appreciate the help!
Thomas
Something along the lines of (sorry my code is C# but I hope it will help nonetheless)
HtmlDocument doc = new HtmlDocument();
doc.LoadHtml("some html markup here");
HtmlNodeCollection links = doc.DocumentNode.SelectNodes("//a[#name]");
foreach(HtmlNode link in links)
{
link.Remove();
}
//then one of the many doc.Save(...) overrides to actually get the result of the operation.
This gets you the result you require. This uses Recursive method to drill down all your html nodes and you can simply remove more nodes by adding a new if statment.
Public Sub Test()
Dim document = New HtmlDocument() With { _
Key .OptionOutputAsXml = True _
}
document.LoadHtml("<html><body>I was born in <a name=BC>Toronto</a> and now I live in barrie</body></html>")
For i As var = 0 To document.DocumentNode.ChildNodes.Count - 1
RecursiveMethod(document.DocumentNode.ChildNodes(i))
Next
Console.Out.WriteLine(document.DocumentNode.InnerHtml.Replace(" ", " "))
End Sub
Public Sub RecursiveMethod(child As HtmlNode)
For x As var = 0 To child.ChildNodes.Count - 1
Dim node = child.ChildNodes(x)
If node.Name = "a" Then
node.RemoveAll() //removes all the child nodes of "a"
node.Remove() //removes the actual "a" node
Else
If node.HasChildNodes Then
RecursiveMethod(node)
End If
End If
Next
End Sub
I've got a list of objects that have a Name and a list of values and another property representing the SelectedValue.
I wanted to display the Name and then have a drop down - but not sure how to do it!
Can anyone assist please?
With the following example p.Name works, its the p.Values and p.SelectedValues bits that don't!
<div id="gridProps">
<ul id="props">
#foreach (var p in Model.AvailableProperties)
{
<li>#p.Name : #Html.DropDownListFor(p.SelectedValue, p.Values)</li>
}
</ul>
</div>
I think what you are looking for is #Html.DropDownList instead of #Html.DropDownListFor
#Html.DropDownList actually has the overload that you're looking for:
#Html.DropDownList(string name, IEnumerable<SelectListItem> selectList)
All of the #Html.DropDownListFor overloads take an Expression<Func<...>> as the first parameter, and it doesn't look like that's what you're passing in your call.