rendering namespace in XSLT functions

Topics: General
Oct 24, 2011 at 9:24 PM

Hi

Working on "generic/parametric" XSLT function for 960gs... See discussion: http://compositec1.codeplex.com/discussions/274961?ProjectName=compositec1

So came up with

  1. XSLT function as wrapper for 960gs container with paramters Layout960gsContainer
    1. NumberOfColumns 12 | 16
    2. LayoutType = fluid | fixed 
    3. JavascriptLibrary= JQuery | MooTools | None
      which javascript libs are used if any... 
    4. PageSpeedOptimized = true | false
      use minimized and merged css and javascript or original sets of css and js

Now I would add 5th parameter which would be name of XSLT function containing bunch of 960gs
layout difs containing Composite C1 conent placeholders :

 

			<div class="grid_8" id="r1_c1_g8">
				<rendering:placeholder id="content_r1_c1_g8" title="Header Left" default="false" />
			</div>
			<div class="grid_8" id="r1_c2_g8">
				<rendering:placeholder id="content_r1_c2_g8" title="Header Right" default="false" />
			</div>
			<div class="clear">
			</div>

			<div class="grid_4" id="r2_c1_g4">
				<rendering:placeholder id="content_r1_c1_g4" title="Content Left" default="false" />
			</div>
			<div class="grid_12" id="r2_c2_g12">
				<rendering:placeholder id="content_r2_c2_g12" title="Content Right" default="true" />
			</div>
			<div class="clear">
			</div>

			<div class="grid_4" id="r3_c1_g4">
				<rendering:placeholder id="content_r3_c1_g4" title="Footer Left" default="false" />
			</div>
			<div class="grid_8" id="r3_c2_g8">
				<rendering:placeholder id="content_r3_c2_g8" title="Footer Center" default="false" />
			</div>
			<div class="grid_4" id="r3_c3_g4">
				<rendering:placeholder id="content_r3_c3_g4" title="Footer Right" default="false" />
			</div>

If the XSLT function name parameter is empty or undefined it will call simple XSLT fn containing code below or
just insert this code:

 
				<rendering:placeholder id="Content" title="Content" default="true" />

This second approach would place/reserve single rendering placeholder and enable inserting raw 960gs html code
w/o xhtml, head, body tags...

Now some questions:

  1. during saving rendering is undeclared, what to include in XSLT preamble
    (<xsl:stylesheet>) if possible to use?
  2. what would be either better practice or possible to call in XSLT fn Layout960gsContainer 
    XSLT function Layout960gsGridWithContentPlaceholders like C1 fn or
    XSLT function call (apply template).
    Example:
    	  <f:function name="HolisticWare.Layout.CSSFramework960gs.Layout960gsGridWithSingleContentPlaceholder" xmlns:f="http://www.composite.net/ns/function/1.0">
    	  </f:function>

Thanks and regards

 

mel

Oct 26, 2011 at 8:52 AM
Edited Oct 26, 2011 at 8:52 AM

Hello,

If I've understood you correctly you want to have some general XSLT function to generate Layout templates. You have 4 parameters (NumberOfColumns, LayoutType ...) and now you want to add 5th parameter named "XSLT function name" (typed String) and then call this XSTL by its name inside the general XSLT. The XSLT function name from 5th parameter should render some layout <rendering:placeholders...

BUT, this approach will not work in C1 as it is not possible to use <rendering:placeholders in XSLT functions, they should be in Layout Template by design (one of cases: to see page's content placeholders while editing in Visual editor)

I think your general XSLT should  have parameters for each possible <rendering:placeholders and then process them. In Layout you will have call for this XSLT something like this:

 

              <f:function name="Layout.Container">
              <f:param name="NumberOfColumns" value="12">
              <f:param name="ContentRight">
                   <rendering:placeholder id="content_r2_c2_g12" title="Content Right" default="true" />
              </f:param>
              <f:param name="ContentLeft">
                   <rendering:placeholder id="content_r1_c1_g4" title="Content Left" default="flase" />
              </f:param>  
             </f:function>
Oct 26, 2011 at 9:33 AM
Edited Oct 26, 2011 at 9:34 AM

its true that you cant use <rendering:placeholder /> in a Xslt-function, but... its just a keyword without any real logic behind it and you're 100% free to make your own function that does exactly the same as <rendering:placeholder />

Lets say the function markup is like this

<f:function name="Layout.RenderPlaceholder">
  <f:param name="PlaceHolderName" value="something">
</f:function>

You could implement the function like this in a MethodBased function (this relies an a class from the CompositeC1Contrib.Core since its a functionality im using all the time

 

using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Xml.Linq;

using Composite.Core.WebClient.Renderings.Page;
using Composite.Data;
using Composite.Data.Types;
using Composite.Functions;
using CompositeC1Contrib.Web.UI;

namespace Composite.App_Code
{
    public static class Layout
    {
        [FunctionParameterDescription("placeholderName", "Placeholder name", "Name of the placeholder to render")]
        public static Control RenderPlaceholder(string placeholderName)
        {
            var plc = new PlaceHolder();

            var content = DataFacade.GetData<IPagePlaceholderContent>().Single(p => p.PageId == PageRenderer.CurrentPageId && p.PlaceHolderId == placeholderName);

            var helper = new PageRendererHelper();
            var mapper = (IXElementToControlMapper)helper.FunctionContext.XEmbedableMapper;
            var doc = helper.RenderDocument(content);
            var body = PageRendererHelper.GetDocumentPart(doc, "body");

            addNodesAsControls(body.Nodes(), plc, mapper);

            var page = HttpContext.Current.CurrentHandler as Page;

            if (page != null)
            {
                if (page.Header != null)
                {
                    var head = PageRendererHelper.GetDocumentPart(doc, "head");
                    if (head != null)
                    {
                        addNodesAsControls(head.Nodes(), page.Header, mapper);
                    }
                }
            }

            return plc;
        }

        private static void addNodesAsControls(IEnumerable<XNode> nodes, Control parent, IXElementToControlMapper mapper)
        {
            foreach (var node in nodes)
            {
                var c = node.AsAspNetControl(mapper);
                parent.Controls.Add(c);
            }
        }
    }
}

 

Oct 26, 2011 at 10:25 PM

Hi 

@Inna
yup I'm trying to design set/library of C1 XSLT functions to generate layout, some kind of XSLT layout framework..
Something what was discussed with Marcus http://compositec1.codeplex.com/discussions/274961

Design idea:

  1. Outer XSLT (takes parameters) for css, and javascript + container (960gs has container_12 and container_16)
    Outer XSLT functions could be latter extended one for 960gs, one for blueprint, one for yaml etc.
    Later on this could be merged into one XSLT with framework as parameter.
    Outer XSLT calls one of bunch of Inner XSLT functions - actual layouts header, footer, content_left, content_right
    in css system notation (960gs grid_6 etc)
    This way one could build sets of layouts ... 
  2. Inner XSLT that inserts layout with placeholders and css classes according to chosen css framework...

To simplify problem here is use-case which would help me think further.
Can one define XSLT function that inserts rendering:placeholder element?!?
Just like burningice said it is just keyword - better text (tried with CDATA to fool verification but no use) 

So came up with this one "C1PlaceholderInserter":

 

<!--?xml version="1.0" encoding="UTF-8"?-->
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet 
	version="1.0" 
	xmlns:rendering="http://www.composite.net/ns/rendering/1.0"
	xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
	xmlns:in="http://www.composite.net/ns/transformation/input/1.0"
	xmlns:lang="http://www.composite.net/ns/localization/1.0"
	xmlns:f="http://www.composite.net/ns/function/1.0"
	xmlns="http://www.w3.org/1999/xhtml"
	exclude-result-prefixes="xsl in lang f rendering"
	>
	<!--
	XSLT namespace added to shut verification up!
	xmlns:rendering="http://www.composite.net/ns/rendering/1.0"
	-->
	<!--
	XSLT function to transform any Composite C1 placeholder into 960gs grid
	function call: 
	
		<f:function 
			name="HolisticWare.Layout.C1PlaceholderInserter"
			xmlns:f="http://www.composite.net/ns/function/1.0"
			>
		<f:param name="CSSId" value="css_id_" />
		<f:param name="Title" value="Title_" />
		<f:param name="Default" value="false" />
		</f:function>
	-->
	<xsl:param name="cssid" select="/in:inputs/in:param[@name='CSSId']" />
	<xsl:param name="title" select="/in:inputs/in:param[@name='Title']" />
	<xsl:param name="isdefault" select="/in:inputs/in:param[@name='IsDefault']" />

	<xsl:template match="/">
		<html>
			<head>
				<!-- markup placed here will be shown in the head section of the rendered page -->
			</head>

			<body>
				<!-- markup placed here will be the output of this rendering -->
				<!--
				Debugging
				<div>
					Value of input parameter 'CSSId':
					<xsl:value-of select="/in:inputs/in:param[@name='CSSId']" />
				</div>
				<div>
					Value of function call 'Title':
					<xsl:value-of select="/in:inputs/in:result[@name='Title']" />
				</div>
				<div>
					Value of function call 'Default':
					<xsl:value-of select="/in:inputs/in:result[@name='IsDefault']" />
				</div>
				-->
				<rendering:placeholder id="{$cssid}" title="{$title}" default="{$isdefault}" />
			</body>
		</html>
	</xsl:template>

</xsl:stylesheet>
Note: I added rendering namespace and excluded it in rendering prefixes!
Input:
<in:inputs xmlns:in="http://www.composite.net/ns/transformation/input/1.0">
    <!-- Input Parameter, XPath /in:inputs/in:param[@name='CSSId'] -->
    <in:param name="CSSId">idcss_</in:param>
    <!-- Input Parameter, XPath /in:inputs/in:param[@name='Title'] -->
    <in:param name="Title">Title_</in:param>
    <!-- Input Parameter, XPath /in:inputs/in:param[@name='IsDefault'] -->
    <in:param name="IsDefault">false</in:param>
</in:inputs>
Output:
<html xmlns="http://www.w3.org/1999/xhtml">
    <head/>
     <body>
        <rendering:placeholder id="idcss_" title="Title_" default="false" xmlns:rendering="http://www.composite.net/ns/rendering/1.0"/>
    </body>
</html>

So this is almost that except (always except) this namespace in output, although it is in exclusion...
Header/preamble stylesheet element check exclude-result-prefixes="xsl in lang f rendering":
<xsl:stylesheet 
	version="1.0" 
	xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
	xmlns:in="http://www.composite.net/ns/transformation/input/1.0"
	xmlns:lang="http://www.composite.net/ns/localization/1.0"
	xmlns:f="http://www.composite.net/ns/function/1.0"
	xmlns="http://www.w3.org/1999/xhtml"
	xmlns:rendering="http://www.composite.net/ns/rendering/1.0"
	exclude-result-prefixes="xsl in lang f rendering"
	>

@burningice: So this cannot be done in XSLT?
and for 3 params c# code should I presume like this:
 
        [FunctionParameterDescription("placeholderName", "Placeholder name", "Name of the placeholder to render")]
        [FunctionParameterDescription("placeholderTitle", "Placeholder title", "Title of the placeholder to render")]
        [FunctionParameterDescription("placeholderCSSClass", "Placeholder CSS Class", "CSS class of the placeholder to render")]
        [FunctionParameterDescription("placeholderISDefault", "Placeholder Default", "If the placeholder to render is default")]
        public static Control RenderPlaceholder(
string placeholderName,
string placeholderTitle,
string placeholderCSSStyle,
bool  placeholderIsDefault
)
        {


will try that tomorrow...


regards

mel 
Oct 26, 2011 at 10:50 PM
Edited Oct 26, 2011 at 10:52 PM

Of course you can do it in xslt. But the function you call to insert placeholder content has to be implemented in .Net and return a Control. This is due to the implementation detail where C1 will recursively execute all functions and functions they contains (and functions they contain etc etc) and in the end wrap it all up in a asp.net control to be able to support ie. UserControls.

But since <rendering:placeholder /> is not a function in itself (which is a bad design-decision but thats a whole different story), it won't be executed and you would have to do what C1 does behind the scene manually. And what C1 does behind the scene is basically the code i posted.

About your extra parameters it looks allright. But you won't be needing the PlaceholderTitle and PlaceholderIsDefault for anything since its only used to populate the list of placeholders in the contenteditor and nothing else.

Oct 27, 2011 at 12:19 PM

Hi again

It is I Leclerc again... 

Did some fixing of Contrib package Sorting project had postbuild problems
(see... http://compositec1contrib.codeplex.com/discussions)

Added class (just for fun with more param to learn something new):

using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Xml.Linq;

using Composite.Core.WebClient.Renderings.Page;
using Composite.Data;
using Composite.Data.Types;
using Composite.Functions;
using CompositeC1Contrib.Web.UI;

namespace HolisticWare.Layout
{
	public 
		static 
		class 
		C1PlaceholderInserter
	{
		[FunctionParameterDescription("placeholderName", "Placeholder name", "Name of the placeholder to render")]
		[FunctionParameterDescription("placeholderTitle", "Placeholder title", "Title in Console of the placeholder to render")]
		[FunctionParameterDescription("placeholderCSSId", "Placeholder CSSId", "CSS Id of the placeholder to render")]
		[FunctionParameterDescription("placeholderDefault", "Placeholder Default", "Whether the placeholder to render is default or not")]
		public 
			static 
			Control RenderPlaceholder
			(
			  string placeholderName
			, string placeholderTitle
			, string placeholderCSSId
			, bool placeholderDefault
			)
		{
			var plc = new PlaceHolder();

			var content = DataFacade.GetData<IPagePlaceholderContent>().Single
				(
				p => p.PageId 
				== 
				PageRenderer.CurrentPageId && p.PlaceHolderId == placeholderName
				);

			var helper = new PageRendererHelper();
			var mapper = (IXElementToControlMapper)helper.FunctionContext.XEmbedableMapper;
			var doc = helper.RenderDocument(content);
			var body = PageRendererHelper.GetDocumentPart(doc, "body");

			addNodesAsControls(body.Nodes(), plc, mapper);

			var page = HttpContext.Current.CurrentHandler as Page;

			if (page != null)
			{
				if (page.Header != null)
				{
					var head = PageRendererHelper.GetDocumentPart(doc, "head");
					if (head != null)
					{
						addNodesAsControls(head.Nodes(), page.Header, mapper);
					}
				}
			}

			return plc;
		}

		private static void addNodesAsControls(IEnumerable<XNode> nodes, Control parent, IXElementToControlMapper mapper)
		{
			foreach (var node in nodes)
			{
				var c = node.AsAspNetControl(mapper);
				parent.Controls.Add(c);
			}
		}
	}
}

Added new C# external function with method name RenderPlaceholder, everything went ok.

Inserted C1 call into template (asked me for all params and recognized 4th one as boolean, great):

<f:function 
            xmlns:f="http://www.composite.net/ns/function/1.0" 
          name="HolisticWare.Layout.C1PlaceholderInserter.RenderPlaceholder">
  <f:param name="placeholderName" value="name" />
  <f:param name="placeholderTitle" value="title" />
  <f:param name="placeholderCSSId" value="css_id" />
  <f:param name="placeholderDefault" value="True" />
</f:function>

Went to Content page/published based on this page type (template) and got:

Error: Cannot create an abstract class.
Error details:
Failed to get value for function 'HolisticWare.Layout.C1PlaceholderInserter.RenderPlaceholder'
Cannot create an abstract class.

 

Any ideas? I'm sure You have

regards

Oct 27, 2011 at 12:24 PM

can you see which line that is failing?

Nov 8, 2011 at 11:06 AM

Hi

Sorry for delay...

In html source (did a bit pretty editingso the stack-trace is VS-like...):

<div class="c1errordetails" style="border: 2px solid red; padding: 2px 6px 2px 6px; background-color: InfoBackground; color: InfoText; -moz-border-radius: 4px; -moz-box-shadow: 1px 1px 3px 0 rgba(0,0,0,0.75);">
			<strong>Error: Cannot create an abstract class.</strong>
			<div style="font-size: 0.7em">Error details:
				<div style="padding-left: 10px;" title="
at Composite.Functions.FunctionRuntimeTreeNode.GetValue(FunctionContextContainer contextContainer) 
	in .\CompositeC1\Composite\Functions\FunctionRuntimeTreeNode.cs:line 141    
at Composite.Core.WebClient.Renderings.Page.PageRenderer.&lt;&gt;c__DisplayClass19.&lt;ExecuteEmbeddedFunctions&gt;b__15(Int32 i) 
	in .\CompositeC1\Composite\Core\WebClient\Renderings\Page\PageRenderer.cs:line 433
				">
			Failed to get value for function 'HolisticWare.Layout.C1PlaceholderInserter.RenderPlaceholder'
			<div style="padding-left: 10px;" title="
at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean&amp; canBeCached, RuntimeMethodHandleInternal&amp; ctor, Boolean&amp; bNeedSecurityCheck)    
at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache)    
at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipVisibilityChecks, Boolean skipCheckThis, Boolean fillCache)    
at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly)    
at System.Activator.CreateInstance(Type type, Boolean nonPublic)    
at System.Activator.CreateInstance(Type type)
at Composite.Plugins.Functions.FunctionProviders.MethodBasedFunctionProvider.MethodBasedFunction.get_Object() 
	in .\CompositeC1\Composite\Plugins\Functions\FunctionProviders\MethodBasedFunctionProvider\MethodBasedFunction.cs:line 222    
at Composite.Plugins.Functions.FunctionProviders.MethodBasedFunctionProvider.MethodBasedFunction.Execute(ParameterList parameters, FunctionContextContainer context) 
	in .\CompositeC1\Composite\Plugins\Functions\FunctionProviders\MethodBasedFunctionProvider\MethodBasedFunction.cs:line 104    
at Composite.Functions.Foundation.PluginFacades.FunctionWrapper.Execute(ParameterList parameters, FunctionContextContainer context) 
	in .\CompositeC1\Composite\Functions\Foundation\PluginFacades\FunctionWrapper.cs:line 102    
at Composite.Functions.FunctionRuntimeTreeNode.GetValue(FunctionContextContainer contextContainer) 
	in .\CompositeC1\Composite\Functions\FunctionRuntimeTreeNode.cs:line 126
			">
			Cannot create an abstract class.
			</div>

regards

mel

Nov 8, 2011 at 11:14 AM

and whats the source for HolisticWare.Layout.C1PlaceholderInserter.RenderPlaceholder ?

Apr 11, 2012 at 11:52 AM

Hi burningice

I'm back on this problem and having come issues with Contrib package:

  • took Composite C1 v.3.2. preview
  • pulled out CompositeContrib package from bitbucket
  • set all references to compile contrib package
  • but got compile error in Core (contrib) project file ToggleSuperInterfaceActionExecutor.cs line 45
GeneratedTypesFacade.UpdateType(descriptor, newDataTypeDescriptor, true);

Error 8
No overload for method 'UpdateType' takes 3 arguments contrib\Core\ToggleSuperInterfaceActionExecutor.cs 45 4 Core
In GeneratedTypesFacade (GeneratedTypesFacade in Composite projcet)
there is only:
        public static void UpdateType(UpdateDataTypeDescriptor updateDataTypeDescriptor) //line 194
and the other two overloads are commented out!
        ///// <exclude />
        //public static void UpdateType(DataTypeDescriptor oldDataTypeDescriptor, DataTypeDescriptor newDataTypeDescriptor, bool originalTypeHasData)
        //{
        //    UpdateType(DataProviderRegistry.DefaultDynamicTypeDataProviderName, oldDataTypeDescriptor, newDataTypeDescriptor, originalTypeHasData);
        //}
 
 
 
        ///// <exclude />
        //public static void UpdateType(DataTypeDescriptor oldDataTypeDescriptor, DataTypeDescriptor newDataTypeDescriptor)
        //{
        //    UpdateType(DataProviderRegistry.DefaultDynamicTypeDataProviderName, oldDataTypeDescriptor, newDataTypeDescriptor, true);
        //}


Is Contrib Core out of sync with new versions of Composite C1?

regards

mel
Apr 11, 2012 at 6:04 PM

looks like someone at the Composite Team finds it funny to change their API's all the time :)

Since there haven't been any new Official release of 3.2, i have not updated the Contrib project for it yet. What you can do if you need it to compile against 3.2 is either to remove the ToggleSuperInterfaceActionExecutor and related classes (in most cases you won't need it), or you would have to update the code for that class. I haven't looked at what has changed in the Composite API so i can't help you there, but if you managed to figure it out you're most welcome to post the code changes needed here.

Apr 11, 2012 at 6:10 PM
Edited Apr 11, 2012 at 6:11 PM

but hey, something is not right here... what changeset from BitBucket did you actually download?

Line 45 of the .cs file in question doesn't match what you're describing here https://bitbucket.org/burningice/compositec1contrib/src/11156b90e9c5/Core/ToggleSuperInterfaceActionExecutor.cs#cl-45

I do remember this API change in C1, it happened a while ago and the ToggleSuperInterfaceActionExecutor-class was indeed updated. Already back in November last year actually https://bitbucket.org/burningice/compositec1contrib/changeset/cc2a2543558f#chg-Core/ToggleSuperInterfaceActionExecutor.cs

Apr 11, 2012 at 9:03 PM

It says rev 35.

Will pull one more time and see...

in few minutes

Apr 11, 2012 at 9:16 PM

pulled it one more time and right now it is rev 65 and it seems like in this second url ou have sent

thanks + regards

mel

Apr 11, 2012 at 9:19 PM

what url have i sent?... always make sure to get the newest revision by cloning this url https://bitbucket.org/burningice/compositec1contrib - its version independent and will always contain the newest :)

Apr 11, 2012 at 10:36 PM

I ment this one for file changeset:

https://bitbucket.org/burningice/compositec1contrib/changeset/cc2a2543558f#chg-Core/ToggleSuperInterfaceActionExecutor.cs

and I have downloaded with TortoiseHg (I think few weeks ago) this one:
 https://bitbucket.org/burningice/compositec1contrib 

But  I'm not sure what has happened with revisions.

thanks

good night

Apr 12, 2012 at 11:08 AM

Hi

Got it to compile, but cannot get function to be called...

  1. Web page output (first error is regarding rendering:placeholder, rest is just debug output through nested xslts and on purpose mismatched name for layout function - XXXX). This is when function is called from xslt - error bubbles to html
    Grid System 960gs
    Error: 
    The Function named 'HolisticWare.Layout.CSSFrameworksGridSystems.Rendering.Placeholder' is not known. 
    Ensure it exists with the exact spelling and casing you provided. 
    Error details: 
    The Function named 'HolisticWare.Layout.CSSFrameworksGridSystems.Rendering.Placeholder' is not known. 
    Ensure it exists with the exact spelling and casing you provided.
    Value of input parameter 'NumberOfColumns': 
    16
    16
    Value of input parameter 'LayoutType': 
    Fluid
    Fluid
    Value of input parameter 'JavaScriptLibrary': 
    JQuery
    JQuery
    Value of input parameter 'PageSpeedOptimized': 
    true
    true
    Value of input parameter 'LayoutDefinitionFunction': 
    HolisticWare.Layout.CSSFrameworksGridSystems.XXXXX
    HolisticWare.Layout.CSSFrameworksGridSystems.XXXXX
    Error: The Function named 'HolisticWare.Layout.CSSFrameworksGridSystems.XXXXX' is not known. 
    Ensure it exists with the exact spelling and casing you provided. 
    Error details: 
    The Function named 'HolisticWare.Layout.CSSFrameworksGridSystems.XXXXX' is not known. 
    Ensure it exists with the exact spelling and casing you provided.
    
     
  2. Function call tried from template:
    	Template did not validate.
    	The Function named 'HolisticWare.Layout.CSSFrameworksGridSystems.Rendering.Placeholder' is not known. 
    	Ensure it exists with the exact spelling and casing you provided. 
     
  3. Actual c# function call from xslt and page-template
    <f:function
     name="HolisticWare.Layout.CSSFrameworksGridSystems.Rendering.Placeholder"
      xmlns:f="http://www.composite.net/ns/function/1.0">
        <f:param name="PlaceholderName" value="something"> 
        </f:param>
    </f:function>
    
     
  4. c# class + function (code)
 
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Xml.Linq;

using Composite.Core.WebClient.Renderings.Page;
using Composite.Data;
using Composite.Data.Types;
using Composite.Functions;


using CompositeC1Contrib.Web.UI;

namespace HolisticWare.Layout.CSSFrameworksGridSystems
{
	/// <summary>
	/// 
	/// </summary>
	/// <see cref="http://docs.composite.net/ASP-NET/CSharpFunctions/Creating-External-C-Functions"/>
	/// <f:function 
	///		name="HolisticWare.Layout.CSSFrameworksGridSystems.RenderingPlaceholder" 
	///		xmlns:f="http://www.composite.net/ns/function/1.0"
	///		>
	///	</f:function>
	public 
		static 
		class 
		Rendering 
	{
		[
		  FunctionParameterDescription
			(
			  "PlaceholderName"						// TODO: comment this
			, "Placeholder name"					// TODO: comment this
			, "Name of the placeholder to render"	// TODO: comment this
			)
		]
		public static Control Placeholder(string placeholder_name)
		{
			var plc = new PlaceHolder();

			var content = DataFacade.GetData<IPagePlaceholderContent>().Single
				(
				  p => 
					  (
					    p.PageId == PageRenderer.CurrentPageId 
						&&
						p.PlaceHolderId == placeholder_name
					  )
				);
			
			var helper = new PageRendererHelper();
			var mapper = (IXElementToControlMapper)helper.FunctionContext.XEmbedableMapper;
			var doc = helper.RenderDocument(content);
			var body = PageRendererHelper.GetDocumentPart(doc, "body");

			addNodesAsControls(body.Nodes(), plc, mapper);

			var page = HttpContext.Current.CurrentHandler as Page;

			if (page != null)
			{
				if (page.Header != null)
				{
					var head = PageRendererHelper.GetDocumentPart(doc, "head");
					if (head != null)
					{
						addNodesAsControls(head.Nodes(), page.Header, mapper);
					}
				}
			}

			return plc;
		}

		private static void addNodesAsControls(IEnumerable<XNode> nodes, Control parent, IXElementToControlMapper mapper)
		{
			foreach (var node in nodes)
			{
				var c = node.AsAspNetControl(mapper);
				parent.Controls.Add(c);
			}
		}
	}
}

what am I doing wrong?

thanks

m

Apr 12, 2012 at 11:45 AM

i have to be honest with you here and say that i have no idea what it is you're trying to do. But obviously the function named "HolisticWare.Layout.CSSFrameworksGridSystems.RenderingPlaceholder" is not known to C1 so you have to fix that first. Check your serverlog if there is any errors regarding loading this function.

Apr 12, 2012 at 2:02 PM

OK.

As You stated (Oct 26 2011 at 11:50 PM) that I cannot use <rendering:placeholder> from XSLT functions, but I need placeholders
in Content perspective. The reason is that  <rendering:placeholder> is not a C1 function (design issue) and one needs to use C1
function. This C1 function returns Control to replace <rendering:placeholder> in subsequent/recursive calls.

For function call used Your sample code from Oct 26 2011 at 10:33 AM (slightly modified <param> tag was not terminated).

<f:function name="Layout.RenderPlaceholder">
  <f:param name="PlaceHolderName" value="something" />
</f:function>
In c# code Layout is class amd RenderPlaceholder is public+static method decorated with attribute and takes one string arg.

Bottom Line: I'd like to replace <rendering:placeholder> with some c1-function call so I can get the same functionality.

This c# code is in App_Code sub folder, class is public, method static, decorated with attribute for description.

I just tried :

  • to remove namespace bu no use, still the function is not known.
  • server restart (to load dlls and code from App_Code)

Haven't tried touching web.config to restart app.

Apr 12, 2012 at 2:10 PM

From page template I can call function (no namespace, no f: prefix) function gets called w/o error, but in content perspective far right where page templates
dropdown is and content placeholders are my placehloder does not show up.

Call that works:

<function name="Rendering.Placeholder">
	<param name="PlaceholderName" value="something"/>
</function>

What is interesting, there are breakpoints in this function, bute never hit...

Apr 12, 2012 at 2:53 PM

okay, now im back on track. Lots have happened since October 26th and actually i would suggest you to implement this with a Razor function, it would be much easier. The source for the Razor functions would be this, super simple :)

@using Composite.Data;

@using CompositeC1Contrib.RazorFunctions;
@using CompositeC1Contrib.RazorFunctions.Html;

@inherits CompositeC1WebPage

@functions 
{
    public string PlaceholderId { get; set; }
}

@{
    var placeholder = PageManager.GetPlaceholderContent(CurrentPageNode.Id).SingleOrDefault(p => p.PlaceHolderId == PlaceholderId);
}

@if (placeholder != null) 
{
    <text>@Html.Raw(placeholder.Content)</text>
}

Save the code in a file called RenderPlaceholder.cshtml, and you should be able to call it like

<function name="RenderPlaceholder">
	<param name="PlaceholderId" value="something"/>
</function>

Apr 12, 2012 at 8:37 PM

Hi

Don't worry. I'll do that tommorow or this weekend. I know it was quite a time since October. 

This looks simple, though I'd like to see other way just to get into it.

Right now I have to test migration to web app for Marcus. I have promised.

keep in touch

mel

Apr 17, 2012 at 9:25 PM

Hi

Tried Razor approach:

  1. created  Razor function RenderingPlaceholder.cshtml in App_Data\Razor\
  2. rebulit +started
  3. function does not appear
  4. stoped app (debugging) 
  5. clean
    1. distclean removed everything in %USERPROFILE%\AppData\Local\Temp\Temporary ASP.NET Files\
  6. built again
  7. started
  8. Razor function seems not to be loaded (breakpoint is set but not loaded) 
  9. during running tried
    1. composite c1 console server restart
      no use 
    2. making web.config dirty to reload everything
      no use 

So few general questions:

  1. what is the best approach to reload/restart C1 in order to get dlls loaded
    1. in production
      1. server restart
      2. web.config dirty
      3. changing files in App_Code?
    2. during development
      1. clean
      2. temp files removal
      3. anything C1 specific?

thanks

 

mel

Apr 17, 2012 at 9:27 PM

Razor functions appear in Functions perspective don't they?

How can I force loading and check for errors/problems?

 

thx

 

m

Apr 17, 2012 at 9:29 PM

seems like you have tried anything but checking the Server Log? The function can't be loaded if there are any compilation or errors in regards to parameters.

Apr 17, 2012 at 9:46 PM

au contraire as I was investigating I saw small formatting glitch in server log.
see: http://compositec1.codeplex.com/discussions/352590 

In log no exceptions but 2 regarding misssing png's

20120417 21:15:54.4935 5 29 Error Application Error  Failed to process 'GET' request to url '/Composite/skins/system/controls/vista/control-minimize-default.png'20120417 21:15:54.4955 5 29 Critical Application Error  System.Web.HttpException (0x80004005): File does not exist.   at System.Web.StaticFileHandler.GetFileInfo(String virtualPathWithPathInfo, String physicalPath, HttpResponse response)   at System.Web.StaticFileHandler.ProcessRequestInternal(HttpContext context, String overrideVirtualPath)   at System.Web.DefaultHttpHandler.BeginProcessRequest(HttpContext context, AsyncCallback callback, Object state)   at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)20120417 21:15:54.7005 5 29 Error Application Error  Failed to process 'GET' request to url '/Composite/skins/system/controls/vista/control-maximize-default.png'20120417 21:15:54.7015 5 29 Critical Application Error  System.Web.HttpException (0x80004005): File does not exist.   at System.Web.StaticFileHandler.GetFileInfo(String virtualPathWithPathInfo, String physicalPath, HttpResponse response)   at System.Web.StaticFileHandler.ProcessRequestInternal(HttpContext context, String overrideVirtualPath)   at System.Web.DefaultHttpHandler.BeginProcessRequest(HttpContext context, AsyncCallback callback, Object state)   at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

Apr 17, 2012 at 9:49 PM

Ah, try put the .cshtml in a subfolder under ~/App_Data/Razor. You cant have a function that is not in a namespace, so this is a requirement.

Apr 19, 2012 at 10:55 AM

To broaden my knowledge I have just installed Contrib package with Razor function samples and for those functions there is no problems, while in my file
on first occurence of @using there is a warning:

Warning 7 D:\SRC\CoreCompositeC1\Website\App_Data\Razor\HolisticWare\Rendering.cshtml: ASP.NET runtime error: There is no build provider registered for the extension '.cshtml'. You can register one in the <compilation><buildProviders> section in machine.config or web.config. Make sure is has a BuildProviderAppliesToAttribute attribute which includes the value 'Web' or 'All'. D:\SRC\CoreCompositeC1\Website\App_Data\Razor\HolisticWare\Rendering.cshtml 1 1 WebSite

Changed build action from none to Content (Your samples are Content), but cannot get rid of this warrning.

 

 

Apr 19, 2012 at 1:16 PM

@moljac could you maybe start a new discussion on this topic, or catch me on http://jabbr.net/#/rooms/compositec1

Apr 19, 2012 at 1:50 PM

server log



20120419�14:31:06.6485�2� 6�Error�Error instantiating Razor function��System.Web.HttpCompileException (0x80004005): c:\Users\moljac\AppData\Local\Temp\Temporary ASP.NET Files\root\ae4820cc\62d38d07\App_Web_rendering.cshtml.f013ecdc.ir5kl6-r.0.cs(19): error CS0234: The type or namespace name 'Helpers' does not exist in the namespace 'System.Web' (are you missing an assembly reference?)
   at System.Web.Compilation.AssemblyBuilder.Compile()
   at System.Web.Compilation.BuildProvidersCompiler.PerformBuild()
   at System.Web.Compilation.BuildManager.CompileWebFile(VirtualPath virtualPath)
   at System.Web.Compilation.BuildManager.GetVPathBuildResultInternal(VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile, Boolean throwIfNotFound, Boolean ensureIsUpToDate)
   at System.Web.Compilation.BuildManager.GetVPathBuildResultWithNoAssert(HttpContext context, VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile, Boolean throwIfNotFound, Boolean ensureIsUpToDate)
   at System.Web.Compilation.BuildManager.GetVirtualPathObjectFactory(VirtualPath virtualPath, HttpContext context, Boolean allowCrossApp, Boolean throwIfNotFound)
   at System.Web.Compilation.BuildManager.GetVirtualPathObjectFactory(VirtualPath virtualPath, HttpContext context, Boolean allowCrossApp)
   at System.Web.Compilation.BuildManager.CreateInstanceFromVirtualPath(VirtualPath virtualPath, Type requiredBaseType, HttpContext context, Boolean allowCrossApp)
   at System.Web.Compilation.BuildManager.CreateInstanceFromVirtualPath(String virtualPath, Type requiredBaseType)
   at System.Web.WebPages.VirtualPathFactoryManager.CreateInstance[T](String virtualPath)
   at System.Web.WebPages.WebPageBase.CreateInstanceFromVirtualPath(String virtualPath, VirtualPathFactoryManager virtualPathFactoryManager)
   at System.Web.WebPages.WebPageBase.CreateInstanceFromVirtualPath(String virtualPath)
   at CompositeC1Contrib.RazorFunctions.FunctionProvider.RazorFunctionProvider.InstantiateFile(String virtualPath) in D:\SRC\CoreCompositeC1\CompositeC1Contrib\RazorFunctions\FunctionProvider\RazorFunctionProvider.cs:line 42
   at CompositeC1Contrib.FunctionProvider.FileBasedFunctionProvider`1.get_Functions() in D:\SRC\CoreCompositeC1\CompositeC1Contrib\Core\FunctionProvider\FileBasedFunctionProvider.cs:line 64

Apr 19, 2012 at 2:04 PM

try checking your <assemblies> element under <compilation> in web.config. Mine looks like this

<assemblies>
        <add assembly="System.Security, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A" />
        <add assembly="System.Workflow.ComponentModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="System.Workflow.Activities, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        <add assembly="System.Transactions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
        <add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="Microsoft.Web.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="System.Web.Helpers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="System.Web.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
      </assemblies>

Apr 20, 2012 at 5:45 AM

Hi

Got it.

Added

				<!-- Burningice -->
				<add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
				<add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
				<add assembly="Microsoft.Web.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
				<add assembly="System.Web.Helpers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
				<add assembly="System.Web.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
				<add assembly="System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
				<add assembly="System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />

Sample Razor fncs and mine appear in Composite Functions, but I cannot get placeholder to appear in the right pane in Content perspective when my
template is chosen.

used in template generated html looks like (it is the same as function call):

		<function name="HolisticWare.Rendering">
			<param name="PlaceholderId" value="something" />
		</function>

Any ideas about next steps.

Apr 20, 2012 at 5:58 PM

does your template.xml file still contain the rendering:placeholder tags?

Apr 20, 2012 at 10:29 PM

Tried both with and without classic <rendering:placehloder>.

When absent there is message: No placeholders in template

when present everything is ok, only our Razor injected placeholder does not apppear.

So the Razor function call in template:

<function name="HolisticWare.Rendering">
	<param name="PlaceholderId" value="something"/>
</function>

 appear literally like that in generated xhtml.

What is interesting, another function that was earlier attempt (first one w/o Razor) - right now cs file is excluded from project/website and renamed to txt.
So function should not be found. This function is literally emited into xhtml too.
I did that in order to induce some sort of error, cos I have noticed that hints how to proceed further...

I tought that maybe html <text></text> so I removed that too, but still no placeholder....

Apr 20, 2012 at 10:32 PM

are you able to zip your site, i have a hard time getting my head around exactly where the problem would be located.

Apr 20, 2012 at 11:25 PM

Hi

I'll try few more things and tommorow will do the minimal sample, zip it, put on our site and send You a link

thanks a lot

mel

Apr 20, 2012 at 11:25 PM

Hi

I'll try few more things and tommorow will do the minimal sample, zip it, put on our site and send You a link

thanks a lot

mel

Apr 20, 2012 at 11:30 PM

maybe i'm misunderstanding, but are you trying to not have the <rendering:placeholder /> tag in the template but output the content in a function instead?

The only way to get content-placeholders to show up in the visual editor is to have them defined in the markup of your template. If you don't want to output the content there, you would basically wrap them in a dummy-function that takes the placeholder as input but doesn't do anything with it. Then you're free to access and output the placeholder from whatever function you'd like anywhere you'd like.

Apr 23, 2012 at 9:40 AM

No You are not misunderstanding it at all. The idea was to prepare small xslt framework (sort of) and even library of layouts for
css frameworks, grid systems and responsive layouts.

So the idea was that

  1. layout contains xslt function (lets call it Setup.xslt) with (several params)
    1. the 2 most important are the 
      1. param for framework (960gsFluid, 960gsFixed, 960gsAdapt, MQFramework) etc
      2. param for xslt function name that actually define design (divs and ids for columns, rows) and Outputs content placeholders
        let's call it My16coulmnMainPageLayout.xslt
        so the Setup.xslt function calls My16coulmnMainPageLayout.xslt
        User would have to define and edit several  xslt fncs similar to My16coulmnMainPageLayout.xslt and
        start building sort of library
    2. not so important params
      1. pagespeed optimized true/false
        switch between optimized (merged and minifyed) and non-optimized (for testing) css and js  
      2. some other params like (to use or not resizable images etc)

So it would look like this: template contains function call to Grid960Setup.xslt and in this call user decides which layout function
will be called - My16coulmnMainPageLayout.xslt 

I was hoping that Visual Editor can pick-up placeholders "dynamically" generated (from some c1 functions - preferably xslt).

When everything is in template setup + layout design then the number of templates just explodes>
For example for grid system 960gs we have ended up with 20+ templates and most of it was copy+paste - no code reuse.
And I'd like to reuse partly cos I'm lazy and partly to give user minimal chances to make mistakes... 

Samples: http://cc1960gs.holisticwarez.net/

 But with this limitation that placeholders must be deined in template, I feel We were so close, but this last obstacle is showstopper.
I have one more idea, not so nice that I'll try ... and maybe ask another question ...

thanks a lot for Your help

mc 

Apr 24, 2012 at 5:47 AM

in that case, its not gonna happen. you HAVE to define the <rendering:placeholder>-tags in the template. IMO its a weird and undesirable pattern not being able to define the placeholders you need in some kind of list which is unrelated to the actual template-implementation, but that's just how it is. You see this as well when using MasterPages, here you still need the template.xml files containing nothing else but the <rendering:placeholder>-tags, only for telling the Visual Editor which placeholders it should populate.

You would need to follow a pattern similar to what i mentioned, about defining the placeholders in your template.xml but wrap them in some function that just swallows the content and writes it into /dev/null :)

May 8, 2012 at 9:17 AM

Hi BurningIce

I have reorganized thoughts and ideas in my head and managed to implement this stuff I wanted. It is not as I wanted, but it will help me to
implement some sort of layout library as set of templates and XSLT functions.

Regarding template weirdness - I'm aware that it is impossible to predict all use-cases that users might think of and that almost every
initial design might have flaws, but that's life.
The problem is that I'm not too deep into Composite C1 details, but digging through as I have idea or task -  and everything is not documented yet.

I'll look at MasterPages as soon as I get some time to learn the internals.

So in template there are

  • xslt function for grid setup called at top (something like including namespaces with using or header file in c/c++) 
  • set of placeholders for Visual designer
    still writing samples for several grids (960gsFixed, 960gsFluid, 960gsAdaptive  and oter to come)
    caveat is larger number of templates what I wanted to avoid (my idea was to have XSLT fncts instead), but complexity must be somwhere (space or time)

 

thanks a lot for You help

mel

 

May 8, 2012 at 9:39 AM

I'm working with a big site at the moment which is interesting in ways of how templates, version control, continuous integration and deployment needs to work. 

I don't know if you're really fond of XSLT or if its just the road you happened to walk down on, but in this project i found it 10s of times easier to work with a combination of MasterPages and Razor/UserControl functions. MasterPages allow an easy inheritance of templates which the xml-templates in C1 doesn't support, while Razor and UserControl functions doesn't require tedious registration and configuration in the system. And since its all code and compilable, you get feedback right away if there are any errors in any of the MasterPages (.master), Razor (.cshtml) or UserControl (.ascx) files.

Don't hesitate to contact me if you need more information about MasterPages and how to easily implement it in your workflows.

May 8, 2012 at 10:03 AM

Hi 

Thanks for invitation and helping me around.
I'm not fond of XSLT, but I started with it did some stuff, had not too much time to dive into other details, so decided to implement templates this way.
I'' finish this up, create package and send it to Marcus and co for checkup then I'll go to dive more into C1 functions and those deeper/inner secrets. 

Oh yeah and before just to finish proof-of-concept Twitter like client fore reading/adding News through OData (currently we can read News on iOS with
MonoTouc and Android with MonoForAndroid), but need to see how to push them  (add them) through OData into CompositeC1.
I'd like to make Composite C1 first CSM with mobile integration and proof-of-concept would be News for the beginning...
And everything in c#... Nice huh?

I'll dive into MasterPages+Razor+UserControls, as soon as I finish those ideas above and I hope this should be this month.

 

regards

mel

May 9, 2012 at 5:51 PM

I saw a demo today of what could be the new way to handle templates and content-placeholders, and it looks promising. So with that new thing you should be able to achieve what your aiming for here! - just hang in there! :)

May 17, 2012 at 9:06 AM

Hi @burningice

Don't worry I'm hanging in there and thanks for good news. In the meantime I have come up with semi-satisfactory solution and working on
it...

bye

mel

PS

I'm going to bomb You with bunch of questions and some answers on Contrib project right now...