Microsoft AJAX specific implementation of ExoWeb.Templates.Page that supports parsing and loading templates using the Microsoft AJAX syntax.
Inheritance: Page
Example #1
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="page"></param>
        /// <returns></returns>
        internal bool IsTemplate(AjaxPage page)
        {
            bool result = false;

            if (Action != null)
            {
                // action is literal render/dispose
                if (Action.Expression == "render" || Action.Expression == "dispose")
                {
                    result = true;
                }
                else
                {
                    // if not within a dataview or template, then any binding expressions
                    // for toggle action would not be dependent on template context data,
                    // so use the newly created page instance with a null context
                    var action = Action.Evaluate(page == null ? Page.Current as AjaxPage : page);
                    if (action.IsValid && (action.DisplayValue == "render" || action.DisplayValue == "dispose"))
                    {
                        result = true;
                    }
                }
            }

            return(result);
        }
Example #2
0
        internal override void Render(AjaxPage page, string[] templateNames, System.IO.TextWriter writer)
        {
            bool canRender;
            AttributeBinding ifBinding;
            if (!TryRenderIf(page, templateNames, writer, out ifBinding, out canRender))
            {
                Abort(page, templateNames, writer);
                return;
            }

            if (!canRender)
                return;

            AttributeBinding contentTemplateBinding;
            if (!TryContentTemplate(page, templateNames, writer, out contentTemplateBinding))
            {
                Abort(page, templateNames, writer);
                return;
            }

            var ownTemplateNames = contentTemplateBinding != null ?
                ((string) contentTemplateBinding.Value).Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries) :
                new string[0];

            RenderStartTag(page, writer, ifBinding, contentTemplateBinding);

            foreach (var block in Blocks)
                block.Render(page, templateNames.Concat(ownTemplateNames).ToArray(), writer);

            RenderEndTag(writer);
        }
Example #3
0
        protected bool TryContentTemplate(AjaxPage page, IEnumerable <string> templateNames, System.IO.TextWriter writer, out AttributeBinding contentTemplateBinding)
        {
            if (ContentTemplate == null)
            {
                contentTemplateBinding = null;
                return(true);
            }

            contentTemplateBinding = ContentTemplate.Evaluate(page);
            return(contentTemplateBinding.IsValid && contentTemplateBinding.Value is string);
        }
Example #4
0
            internal override AttributeBinding Evaluate(AjaxPage page)
            {
                var path = Path;

                string sourcePath;

                if (Parameters.TryGetValue("source", out sourcePath) && sourcePath.Length > 0)
                {
                    path = sourcePath + "." + path;
                }

                var result = page.EvaluatePath(path);

                if (result.IsValid)
                {
                    if (result.Value == null)
                    {
                        string nullValue;
                        if (Parameters.TryGetValue("nullValue", out nullValue))
                        {
                            result.Value = nullValue;
                        }
                    }
                    else
                    {
                        string format;
                        if (Parameters.TryGetValue("format", out format) && !string.IsNullOrEmpty(format) && result.Value is IFormattable)
                        {
                            result.Value = ((IFormattable)result.Value).ToString(format, null);
                        }
                        else
                        {
                            string transformText;
                            if (transform == null && Parameters.TryGetValue("transform", out transformText) && transformText.Length > 0)
                            {
                                transform = Transform.Compile(transformText);
                            }

                            if (result.IsValid && transform != null)
                            {
                                IEnumerable transformed;
                                result.IsValid = transform.TryExecute(page, (IEnumerable)result.Value, out transformed);
                                result.Value   = result.IsValid ? transformed : null;
                            }
                        }
                    }
                }

                return(new AttributeBinding(Attribute, result));
            }
Example #5
0
            internal override AttributeBinding Evaluate(AjaxPage page)
            {
                // Evaluate the binding path
                var result = page.EvaluatePath(Path);

                // Invalid result
                if (result.Property == null)
                {
                    result.IsValid = false;
                }

                // # syntax
                else if (Extension == "#")
                {
                    string format = null;
                    Parameters.TryGetValue("format", out format);

                    string value;
                    result.IsValid = Adapter.TryGetDisplayValue(result.Property, format, result.Value, out value);
                    result.Value   = value;
                }

                // @ syntax
                else if (Extension == "@")
                {
                    if (string.IsNullOrEmpty(Path))
                    {
                        if (!(page.Context.DataItem is Adapter))
                        {
                            throw new ApplicationException("No path was specified for the \"@\" markup extension, and the source is not an adapter.");
                        }
                        result.Value = page.Context.DataItem;
                    }
                    else
                    {
                        ExoWeb.OnBeforeCreateAdapter(this, result.Source, result.Property);

                        result = new BindingResult()
                        {
                            Value    = new Adapter(result, Parameters),
                            IsValid  = result.IsValid,
                            Property = result.Property,
                            Source   = result.Source
                        };
                    }
                }

                return(new AttributeBinding(Attribute, result));
            }
Example #6
0
 internal override void Render(AjaxPage page, string[] templateNames, TextWriter writer)
 {
     try
     {
         ExoWeb.OnBeginRender(page, this);
         foreach (var block in Blocks)
         {
             block.Render(page, templateNames.Concat(ContentTemplateNames).ToArray(), writer);
         }
     }
     finally
     {
         ExoWeb.OnEndRender(page, this);
     }
 }
Example #7
0
        internal override void Abort(AjaxPage page, string[] templateNames, System.IO.TextWriter writer)
        {
            // Write out a render/dispose toggle since it will be interpreted as a template
            // and conditionally render.  Otherwise, the content within the toggle is not affected
            // by the toggle from a rendering perspective.
            if (IsTemplate(page))
            {
                base.Abort(page, templateNames, writer);
            }
            else
            {
                AttributeBinding contentTemplateBinding;
                if (!TryContentTemplate(page, templateNames, writer, out contentTemplateBinding))
                {
                    base.Abort(page, templateNames, writer);
                    return;
                }

                var ownTemplateNames = contentTemplateBinding != null ?
                                       ((string)contentTemplateBinding.Value).Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries) :
                                       new string[0];

                RenderStartTag(page, writer,
                               // replace data-sys-attach attribute with sys:attach and add data-continue attribute to notify client that children were allowed to render
                               attributes => MergeAttribute(AbortSysAttachDataAttribute(attributes), "data-continue", value => "data-continue"),
                               // abort rendering
                               true,
                               // pass in all binding attributes
                               If == null ? null : If.Evaluate(page),
                               On == null ? null : On.Evaluate(page),
                               ClassName == null ? null : ClassName.Evaluate(page),
                               Action == null ? null : Action.Evaluate(page),
                               GroupName == null ? null : GroupName.Evaluate(page),
                               StrictMode == null ? null : StrictMode.Evaluate(page),
                               When == null ? null : When.Evaluate(page),
                               contentTemplateBinding);

                // continue rendering child blocks in the same data context
                foreach (var block in Blocks)
                {
                    block.Render(page, templateNames.Concat(ownTemplateNames).ToArray(), writer);
                }

                RenderEndTag(writer);
            }
        }
Example #8
0
        protected bool TryRenderIf(AjaxPage page, IEnumerable <string> templateNames, System.IO.TextWriter writer, out AttributeBinding ifBinding, out bool canRender)
        {
            if (If == null)
            {
                ifBinding = null;
                canRender = true;
                return(true);
            }

            ifBinding = If.Evaluate(page);

            if (!ifBinding.IsValid)
            {
                canRender = false;
                return(false);
            }

            canRender = JavaScriptHelpers.IsTruthy(ifBinding.Value);
            return(true);
        }
Example #9
0
            internal override AttributeBinding Evaluate(AjaxPage page)
            {
                IEnumerable <KeyValuePair <string, object> > arguments = page.Context.Variables.Concat(new KeyValuePair <string, object>[] {
                    new KeyValuePair <string, object>("$dataItem", page.Context.DataItem),
                    new KeyValuePair <string, object>("$index", page.Context.Index),
                    new KeyValuePair <string, object>("$context", page.Context),
                    new KeyValuePair <string, object>("$id", (Func <string, string>)(id => page.Context.GetInstanceId(id))),
                });

                if (!isValid)
                {
                    return(new AttributeBinding(Attribute, BindingResult.Invalid));
                }
                else
                {
                    if (script == null)
                    {
                        lock (this)
                        {
                            if (script == null)
                            {
                                script = new JavaScript.ScriptFunction(Page.ScriptEngineFactory, arguments.Select(a => a.Key), Path);
                            }
                        }
                    }

                    try
                    {
                        return(new AttributeBinding(Attribute, new BindingResult()
                        {
                            Value = script.Evaluate(arguments.Select(a => a.Value), Page.ScriptMarshaller), IsValid = true
                        }));
                    }
                    catch
                    {
                        isValid = false;
                        return(new AttributeBinding(Attribute, BindingResult.Invalid));
                    }
                }
            }
Example #10
0
        internal override void Render(AjaxPage page, string[] templateNames, System.IO.TextWriter writer)
        {
            bool             canRender;
            AttributeBinding ifBinding;

            if (!TryRenderIf(page, templateNames, writer, out ifBinding, out canRender))
            {
                Abort(page, templateNames, writer);
                return;
            }

            if (!canRender)
            {
                return;
            }

            AttributeBinding contentTemplateBinding;

            if (!TryContentTemplate(page, templateNames, writer, out contentTemplateBinding))
            {
                Abort(page, templateNames, writer);
                return;
            }

            var ownTemplateNames = contentTemplateBinding != null ?
                                   ((string)contentTemplateBinding.Value).Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries) :
                                   new string[0];

            RenderStartTag(page, writer, ifBinding, contentTemplateBinding);

            foreach (var block in Blocks)
            {
                block.Render(page, templateNames.Concat(ownTemplateNames).ToArray(), writer);
            }

            RenderEndTag(writer);
        }
Example #11
0
 protected void RenderStartTag(AjaxPage page, System.IO.TextWriter writer, params AttributeBinding[] bindings)
 {
     RenderStartTag(page, writer, null, bindings);
 }
Example #12
0
 internal override AttributeBinding Evaluate(AjaxPage page)
 {
     return binding;
 }
Example #13
0
        protected bool TryRenderIf(AjaxPage page, IEnumerable<string> templateNames, System.IO.TextWriter writer, out AttributeBinding ifBinding, out bool canRender)
        {
            if (If == null)
            {
                ifBinding = null;
                canRender = true;
                return true;
            }

            ifBinding = If.Evaluate(page);

            if (!ifBinding.IsValid)
            {
                canRender = false;
                return false;
            }

            canRender = JavaScriptHelpers.IsTruthy(ifBinding.Value);
            return true;
        }
Example #14
0
File: Block.cs Project: vc3/ExoWeb
		/// <summary>
		/// Renders the block to the specified writer in the context of the specified page.
		/// </summary>
		/// <param name="page"></param>
		/// <param name="templateNames"></param>
		/// <param name="writer"></param>
		internal virtual void Render(AjaxPage page, string[] templateNames, TextWriter writer)
		{
			writer.Write(Markup);
		}
Example #15
0
            internal override AttributeBinding Evaluate(AjaxPage page)
            {
                IEnumerable<KeyValuePair<string, object>> arguments = page.Context.Variables.Concat( new KeyValuePair<string, object>[] {
                    new KeyValuePair<string, object>("$dataItem", page.Context.DataItem),
                    new KeyValuePair<string, object>("$index", page.Context.Index),
                    new KeyValuePair<string, object>("$context", page.Context),
                    new KeyValuePair<string, object>("$id", (Func<string, string>)(id => page.Context.GetInstanceId(id))),
                });

                if (!isValid)
                    return new AttributeBinding(Attribute, BindingResult.Invalid);
                else
                {
                    if (script == null)
                    {
                        lock (this)
                        {
                            if (script == null)
                                script = new JavaScript.ScriptFunction(Page.ScriptEngineFactory, arguments.Select(a => a.Key), Path);
                        }
                    }

                    try
                    {
                        return new AttributeBinding(Attribute, new BindingResult() { Value = script.Evaluate(arguments.Select(a => a.Value), Page.ScriptMarshaller), IsValid = true });
                    }
                    catch
                    {
                        isValid = false;
                        return new AttributeBinding(Attribute, BindingResult.Invalid);
                    }
                }
            }
Example #16
0
File: Toggle.cs Project: vc3/ExoWeb
        internal override void Render(AjaxPage page, string[] templateNames, System.IO.TextWriter writer)
        {
            bool canRender;
            AttributeBinding ifBinding;
            if (!TryRenderIf(page, templateNames, writer, out ifBinding, out canRender))
            {
                Abort(page, templateNames, writer);
                return;
            }

            if (!canRender)
                return;

            // Output the original template if toggle on was not specified
            if (On == null)
            {
                Abort(page, templateNames, writer);
                return;
            }

            // Get the data associated with the data view
            var onBinding = On.Evaluate(page);

            // Output the original template if no data for on was found
            if (!onBinding.IsValid)
            {
                Abort(page, templateNames, writer);
                return;
            }

            var onValue = onBinding.Value;

            var classValue = "";
            var classBinding = (AttributeBinding)null;

            if (ClassName != null)
            {
                classBinding = ClassName.Evaluate(page);

                // Output the original template if no data for class was found
                if (!classBinding.IsValid)
                {
                    Abort(page, templateNames, writer);
                    return;
                }

                classValue = (string)classBinding.Value;
            }

            ToggleAction? actionValue;

            var actionBinding = (AttributeBinding)null;

            // Get the value of the toggle action (i.e.: show, hide, etc.)
            if (Action != null)
            {
                actionBinding = Action.Evaluate(page);

                // Output the original template if no data for action was found
                if (!actionBinding.IsValid)
                {
                    Abort(page, templateNames, writer);
                    return;
                }

                actionValue = (ToggleAction)Enum.Parse(typeof(ToggleAction), (string)actionBinding.Value, true);
            }
            else if (!string.IsNullOrEmpty(classValue))
                actionValue = ToggleAction.AddClass;
            else
                actionValue = ToggleAction.Show;

            var groupNameBinding = (AttributeBinding)null;

            if (GroupName != null)
            {
                groupNameBinding = GroupName.Evaluate(page);

                // Output the original template if no data for group name was found
                if (!groupNameBinding.IsValid)
                {
                    Abort(page, templateNames, writer);
                    return;
                }
            }

            var strictModeValue = false;
            var strictModeBinding = (AttributeBinding)null;

            if (StrictMode != null)
            {
                strictModeBinding = StrictMode.Evaluate(page);

                // Output the original template if no data for strict mode was found
                if (!strictModeBinding.IsValid)
                {
                    Abort(page, templateNames, writer);
                    return;
                }

                if (strictModeBinding.Value is bool)
                    strictModeValue = (bool)strictModeBinding.Value;
                else
                    strictModeValue = bool.Parse((string)strictModeBinding.Value);
            }

            bool? equals;

            var whenBinding = (AttributeBinding)null;

            // Evaluate whether the on and when conditions are equal or
            // satisified, which determines whether the toggle is on or off
            if (When == null)
            {
                if (strictModeValue)
                {
                    // In strict mode the on value must be a boolean true
                    if (!(onValue is bool))
                        throw new ApplicationException(string.Format("With strict mode enabled, toggle:on should be a value of type Boolean, actual type \"{0}\".", onValue == null ? "null" : onValue.GetType().Name));

                    equals = (bool) onValue;
                }
                else if (onValue is System.Collections.IEnumerable)
                {
                    equals = false;

                    // Satisfied if there are any items
                    foreach (object o in (System.Collections.IEnumerable)onValue)
                    {
                        equals = true;
                        break;
                    }
                }
                else
                {
                    // Otherwise, check to see that the on value is "truthy"
                    equals = JavaScriptHelpers.IsTruthy(onValue);
                }
            }
            else
            {
                whenBinding = When.Evaluate(page);

                var whenValue = whenBinding.Value;

                if (whenValue == null)
                    equals = (onValue == null);
                else if (whenValue is FunctionInstance)
                {
                    object result;

                    try
                    {
                        result = Page.ScriptMarshaller.Unwrap(((FunctionInstance)whenValue).Call(null, Page.ScriptMarshaller.Wrap(onValue)));
                    }
                    catch
                    {
                        Abort(page, templateNames, writer);
                        return;
                    }

                    if (strictModeValue)
                    {
                        if (!(result is bool))
                            throw new ApplicationException(string.Format("With strict mode enabled, toggle:when function should return a value of type Boolean, found type \"{0}\".", result == null ? "null" : result.GetType().Name));
                        equals = (bool)result;
                    }
                    else
                    {
                        equals = JavaScriptHelpers.IsTruthy(result);
                    }
                }
                else
                {
                    equals = whenValue.Equals(onValue);
                }
            }

            // If no class value is defined then abort
            if ((actionValue == ToggleAction.AddClass || actionValue == ToggleAction.RemoveClass) && string.IsNullOrEmpty(classValue))
            {
                Abort(page, templateNames, writer);
                return;
            }

            bool render = actionValue == ToggleAction.Render || actionValue == ToggleAction.Dispose;

            AttributeBinding contentTemplateBinding;
            if (!TryContentTemplate(page, templateNames, writer, out contentTemplateBinding))
            {
                Abort(page, templateNames, writer);
                return;
            }

            var ownTemplateNames = contentTemplateBinding != null ?
                ((string) contentTemplateBinding.Value).Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries) :
                new string[0];

            using (var context = render ? page.BeginContext(page.Context.DataItem, null) : null)
            {
                RenderStartTag(page, writer, attrs => MergeAttribute(MergeAttribute(MergeAttribute(attrs,
                    "class", value =>
                    {
                        if (actionValue == ToggleAction.AddClass || actionValue == ToggleAction.RemoveClass)
                        {
                            if ((actionValue == ToggleAction.AddClass && equals.Value) || (actionValue == ToggleAction.RemoveClass && !equals.Value))
                                value = AttributeHelper.EnsureClassName(value, classValue);
                            else
                                value = AttributeHelper.RemoveClassName(value, classValue);
                        }

                        // Add/remove the "toggle-on" and "toggle-off" classes based on state
                        value = AttributeHelper.EnsureClassName(value, equals.Value ? "toggle-on" : "toggle-off");
                        value = AttributeHelper.RemoveClassName(value, equals.Value ? "toggle-off" : "toggle-on");

                        return value;
                    }).ToArray(),
                    "style", value =>
                    {
                        if (actionValue == ToggleAction.Show || actionValue == ToggleAction.Hide ||
                            actionValue == ToggleAction.Render || actionValue == ToggleAction.Dispose)
                        {
                            if (((actionValue == ToggleAction.Show || actionValue == ToggleAction.Render) && equals.Value) ||
                                ((actionValue == ToggleAction.Hide || actionValue == ToggleAction.Dispose) && !equals.Value))
                            {
                                if (AttributeHelper.GetCssStyle(value, "display") == "none")
                                    value = AttributeHelper.RemoveCssStyle(value, "display");
                            }
                            else
                                value = AttributeHelper.EnsureCssStyle(value, "display", "none");
                        }

                        return value;
                    }).ToArray(),
                    "disabled", value =>
                    {
                        if (actionValue == ToggleAction.Enable || actionValue == ToggleAction.Disable)
                        {
                            if ((actionValue == ToggleAction.Enable && equals.Value) || (actionValue == ToggleAction.Disable && !equals.Value))
                                value = null;
                            else
                                value = "disabled";
                        }

                        return value;
                    }), ifBinding, onBinding, classBinding, actionBinding, groupNameBinding, strictModeBinding, whenBinding, contentTemplateBinding,
                    // If this is render/dispose, include the nested template index as a special attribute
                    render ? new AttributeBinding(new Attribute() { Name = "data-sys-tmplidx", Value = NestedTemplateIndex.ToString() }, null) : null,
                    render ? new AttributeBinding(new Attribute() { Name = "data-sys-tcindex", Value = context.Id }, null) : null);

                // Only render the inner blocks if the template would be rendered client-side
                if (!render || (actionValue == ToggleAction.Render && equals.Value) || (actionValue == ToggleAction.Dispose && !equals.Value))
                {
                    foreach (var block in Blocks)
                        block.Render(page, templateNames.Concat(ownTemplateNames).ToArray(), writer);
                }

                RenderEndTag(writer);
            }
        }
Example #17
0
File: Toggle.cs Project: vc3/ExoWeb
        internal override void Abort(AjaxPage page, string[] templateNames, System.IO.TextWriter writer)
        {
            // Write out a render/dispose toggle since it will be interpreted as a template
            // and conditionally render.  Otherwise, the content within the toggle is not affected
            // by the toggle from a rendering perspective.
            if (IsTemplate(page))
                base.Abort(page, templateNames, writer);
            else
            {
                AttributeBinding contentTemplateBinding;
                if (!TryContentTemplate(page, templateNames, writer, out contentTemplateBinding))
                {
                    base.Abort(page, templateNames, writer);
                    return;
                }

                var ownTemplateNames = contentTemplateBinding != null ?
                    ((string) contentTemplateBinding.Value).Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries) :
                    new string[0];

                RenderStartTag(page, writer,
                    // replace data-sys-attach attribute with sys:attach and add data-continue attribute to notify client that children were allowed to render
                    attributes => MergeAttribute(AbortSysAttachDataAttribute(attributes), "data-continue", value => "data-continue"),
                    // abort rendering
                    true,
                    // pass in all binding attributes
                    If == null ? null : If.Evaluate(page),
                    On == null ? null : On.Evaluate(page),
                    ClassName == null ? null : ClassName.Evaluate(page),
                    Action == null ? null : Action.Evaluate(page),
                    GroupName == null ? null : GroupName.Evaluate(page),
                    StrictMode == null ? null : StrictMode.Evaluate(page),
                    When == null ? null : When.Evaluate(page),
                    contentTemplateBinding);

                // continue rendering child blocks in the same data context
                foreach (var block in Blocks)
                    block.Render(page, templateNames.Concat(ownTemplateNames).ToArray(), writer);

                RenderEndTag(writer);
            }
        }
Example #18
0
 internal abstract AttributeBinding Evaluate(AjaxPage page);
Example #19
0
 internal override void Render(AjaxPage page, string[] templateNames, System.IO.TextWriter writer)
 {
     RenderStartTag(page, writer);
 }
Example #20
0
        /// <summary>
        /// Render the data view to the output for the current page.
        /// </summary>
        /// <param name="page"></param>
        /// <param name="templateNames"></param>
        /// <param name="writer"></param>
        internal override void Render(AjaxPage page, string[] templateNames, System.IO.TextWriter writer)
        {
            bool canRender;
            AttributeBinding ifBinding;
            if (!TryRenderIf(page, templateNames, writer, out ifBinding, out canRender))
            {
                Abort(page, templateNames, writer);
                return;
            }

            if (!canRender)
                return;

            // Output the original template if data source was not specified
            if (Data == null)
            {
                Abort(page, templateNames, writer);
                return;
            }

            // Get the data associated with the data view
            var dataBinding = Data.Evaluate(page);

            // Output the original template if no data was found
            if (!dataBinding.IsValid)
            {
                Abort(page, templateNames, writer);
                return;
            }

            // Render the inline template for top level dataviews
            string templateId = null;
            string controlId = null;
            bool renderControlId = false;
            if (page.Context.IsGlobal)
            {
                templateId = page.NextControlId;
                controlId = Attributes.Where(a => a.Name == "id").Select(a => a.Value).FirstOrDefault();
                if (controlId == null)
                {
                    renderControlId = true;
                    controlId = page.NextControlId;
                }
                writer.Write("<");
                writer.Write(Tag);
                writer.Write(" class='sys-template' id='");
                writer.Write(templateId);
                writer.Write("'>");
                writer.Write(Template);
                writer.Write("</");
                writer.Write(Tag);
                writer.Write(">");
            }

            AttributeBinding contentTemplateBinding;
            if (!TryContentTemplate(page, templateNames, writer, out contentTemplateBinding))
            {
                Abort(page, templateNames, writer);
                return;
            }

            var ownTemplateNames = contentTemplateBinding != null ?
                ((string) contentTemplateBinding.Value).Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries) :
                new string[0];

            RenderStartTag(page, writer, ifBinding, dataBinding, contentTemplateBinding,
                // Include the nested template index as a special attribute
                new AttributeBinding(new Attribute() { Name = "data-sys-tmplidx", Value = NestedTemplateIndex.ToString() }, null),
                // If this is a top-level dataview then we will need to ensure an id so that linking can occur
                renderControlId ? new AttributeBinding(new Attribute() { Name = "id", Value = controlId }, null) : null);

            // Convert the data into a list
            IEnumerable list;
            if (dataBinding.Value == null)
                list = new object[0];
            else if (dataBinding.Value is IEnumerable && !(dataBinding.Value is string))
                list = (IEnumerable) dataBinding.Value;
            else
                list = new[] {dataBinding.Value};

            // Process the template for each list item
            var index = 0;
            foreach (var item in list)
            {
                // Begin a new template context
                using (var context = page.BeginContext(item, index++, null))
                {
                    RenderContextBeginMarker(context, Tag, writer);

                    foreach (var block in Blocks)
                        block.Render(page, templateNames.Concat(ownTemplateNames).ToArray(), writer);

                    RenderContextEndMarker(context, Tag, writer);
                }
            }

            RenderEndTag(writer);

            // Render script linking logic
            if (page.Context.IsGlobal)
                writer.Write("<script type=\"text/javascript\">$exoweb({{ domReady: function() {{ Sys.Application.linkElement(document.getElementById(\"{0}\"), document.getElementById(\"{1}\")); }} }});</script>", controlId, templateId);
        }
Example #21
0
 /// <summary>
 /// Renders the block to the specified writer in the context of the specified page.
 /// </summary>
 /// <param name="page"></param>
 /// <param name="templateNames"></param>
 /// <param name="writer"></param>
 internal virtual void Render(AjaxPage page, string[] templateNames, TextWriter writer)
 {
     writer.Write(Markup);
 }
Example #22
0
        public void Render(AjaxPage page, System.IO.TextWriter writer, bool isHtmlBool, bool generateIds, bool isTextArea)
        {
            // Bound attribute
            if (binding != null)
            {
                // Valid binding
                if (binding.IsValid)
                {
                    // Render the binding value for sys attributes
                    if (attribute.Name.StartsWith("sys:"))
                    {
                        var attributeName = attribute.Name.Substring(4);

                        // Render two-way binding expressions
                        if (attribute.Binding.IsTwoWay)
                        {
                            RenderAttribute(writer, "data-sys-" + attributeName, attribute.Binding.Expression);
                        }

                        if (binding.Value != null)
                        {
                            if (attributeName != "if" && attributeName != "innerhtml" && attributeName != "innertext" && !(isTextArea && attributeName == "value") && !attribute.Name.StartsWith("sys:class-"))
                            {
                                if (isHtmlBool)
                                {
                                    if (JavaScriptHelpers.IsTruthy(binding.Value))
                                    {
                                        RenderAttribute(writer, attributeName, attributeName);
                                    }
                                }
                                else
                                {
                                    RenderAttribute(writer, attributeName, binding.Value.ToString());
                                }
                            }
                        }
                    }
                    else
                    {
                        RenderAttribute(writer, "data-" + attribute.Name.Replace(':', '-'), attribute.Binding.Expression);
                    }
                }

                // Invalid binding
                else
                {
                    RenderAttribute(writer, attribute.Name, attribute.Binding.Expression);
                }
            }
            else if (generateIds && (attribute.Name == "id" || attribute.Name == "sys:id"))
            {
                RenderAttribute(writer, "id", page.Context.GetInstanceId(attribute.Value));
            }
            // Simple attribute
            else if (attribute.Name.Contains(":") && attribute.Name != "sys:id")
            {
                RenderAttribute(writer, "data-" + attribute.Name.Replace(':', '-'), attribute.Value);
            }
            else if (isHtmlBool)
            {
                if (JavaScriptHelpers.IsTruthy(attribute.Value))
                {
                    RenderAttribute(writer, attribute.Name, attribute.Name);
                }
            }
            else
            {
                RenderAttribute(writer, attribute.Name, attribute.Value);
            }
        }
Example #23
0
 internal abstract AttributeBinding Evaluate(AjaxPage page);
Example #24
0
            internal override AttributeBinding Evaluate(AjaxPage page)
            {
                var path = Path;

                string sourcePath;
                if (Parameters.TryGetValue("source", out sourcePath) && sourcePath.Length > 0)
                    path = sourcePath + "." + path;

                var result = page.EvaluatePath(path);

                if (result.IsValid)
                {
                    if (result.Value == null)
                    {
                        string nullValue;
                        if (Parameters.TryGetValue("nullValue", out nullValue))
                            result.Value = nullValue;
                    }
                    else
                    {
                        string format;
                        if (Parameters.TryGetValue("format", out format) && !string.IsNullOrEmpty(format) && result.Value is IFormattable)
                            result.Value = ((IFormattable)result.Value).ToString(format, null);
                        else
                        {
                            string transformText;
                            if (transform == null && Parameters.TryGetValue("transform", out transformText) && transformText.Length > 0)
                                transform = Transform.Compile(transformText);

                            if (result.IsValid && transform != null)
                            {
                                IEnumerable transformed;
                                result.IsValid = transform.TryExecute(page, (IEnumerable)result.Value, out transformed);
                                result.Value = result.IsValid ? transformed : null;
                            }
                        }
                    }
                }

                return new AttributeBinding(Attribute, result);
            }
Example #25
0
 protected void RenderStartTag(AjaxPage page, System.IO.TextWriter writer, Func <IEnumerable <AttributeBinding>, IEnumerable <AttributeBinding> > attributeTransform, params AttributeBinding[] bindings)
 {
     RenderStartTag(page, writer, attributeTransform, false, bindings);
 }
Example #26
0
        protected void RenderStartTag(AjaxPage page, System.IO.TextWriter writer, Func <IEnumerable <AttributeBinding>, IEnumerable <AttributeBinding> > attributeTransform, bool abort, params AttributeBinding[] bindings)
        {
            // Immediately abort if no tag name
            if (Tag == null)
            {
                return;
            }

            // Open Tag
            writer.Write("<" + Tag);

            // Attributes
            string innerContent = null;
            var    attributes   = (Attributes ?? new List <Attribute>())
                                  .Select(attribute => attribute.Binding == null ? new AttributeBinding(attribute, null) : attribute.Binding.Evaluate(page));

            // Adding binding attributes if necessary
            if (bindings != null && bindings.Length > 0)
            {
                attributes = attributes.Concat(bindings.Where(b => b != null));
            }

            // Transform the attributes if necessary
            if (attributeTransform != null)
            {
                attributes = attributeTransform(attributes);
            }

            string classNames = null;
            bool   foundId    = false;
            bool   isTextArea = Tag.Equals("textarea", StringComparison.InvariantCultureIgnoreCase);

            var attrs = attributes.ToArray();

            // Write the attributes to the output stream
            foreach (var attribute in attrs)
            {
                // Ensure that multiple id attributes are not specified
                if (!page.Context.IsGlobal && (attribute.Name == "id" || attribute.Name == "sys:id"))
                {
                    if (foundId)
                    {
                        throw new ApplicationException("Found multiple id attributes: " + Markup);
                    }
                    foundId = true;
                }

                // Determine if the attribute represents bound element content
                if (attribute.IsBound)
                {
                    if (attribute.Name == "sys:innerhtml" || (isTextArea && attribute.Name == "sys:value"))
                    {
                        innerContent = (attribute.DisplayValue ?? "");
                    }
                    else if (attribute.Name == "sys:innertext")
                    {
                        innerContent = HttpUtility.HtmlEncode(attribute.DisplayValue ?? "");
                    }
                }

                bool isHtmlBoolean;
                var  attributeName = attribute.Name.StartsWith("sys:") ? attribute.Name.Substring(4) : attribute.Name;
                if (Tag.Equals("input", StringComparison.InvariantCultureIgnoreCase))
                {
                    var attr = attrs.SingleOrDefault(a => a.Name.Equals("type", StringComparison.InvariantCultureIgnoreCase) && a.IsValid && a.Value != null);
                    if (attr == null)
                    {
                        isHtmlBoolean = HtmlHelpers.IsBooleanAttribute(attributeName, Tag, null, true);
                    }
                    else
                    {
                        isHtmlBoolean = HtmlHelpers.IsBooleanAttribute(attributeName, Tag, attr.Value.ToString());
                    }
                }
                else
                {
                    isHtmlBoolean = HtmlHelpers.IsBooleanAttribute(attributeName, Tag);
                }

                if (abort)
                {
                    attribute.Abort(writer, isHtmlBoolean);
                }
                else
                {
                    if (attribute.Name == "class")
                    {
                        if (classNames == null)
                        {
                            classNames = (string)attribute.Value;
                        }
                        else
                        {
                            classNames += " " + (string)attribute.Value;
                        }
                    }
                    else
                    {
                        if (attribute.Name.StartsWith("sys:class-"))
                        {
                            // If binding evaluates as truthy, then render the store the class name
                            if (JavaScriptHelpers.IsTruthy(attribute.Value))
                            {
                                string sysClassValue = attribute.Name.Substring(10);
                                if (classNames == null)
                                {
                                    classNames = sysClassValue;
                                }
                                else
                                {
                                    classNames += (classNames.Length > 0 ? " " : "") + sysClassValue;
                                }
                            }
                        }
                        attribute.Render(page, writer, isHtmlBoolean, !page.Context.IsGlobal, isTextArea);
                    }
                }
            }

            // Write direct class and sys:class- attribute values together. Note: by checking
            // for null we may be avoiding writing a class attribute altogether whereas the
            // client framework would have produced an empty class attribute.
            if (classNames != null)
            {
                writer.Write(" class=\"");
                HttpUtility.HtmlAttributeEncode(classNames, writer);
                writer.Write("\"");
            }

            // Close Tag
            if (IsEmpty)
            {
                if (!string.IsNullOrEmpty(innerContent))
                {
                    writer.Write(">" + innerContent + "</" + Tag + ">");
                }
                else if (HtmlHelpers.IsSelfClosing(Tag))
                {
                    writer.Write(" />");
                }
                else
                {
                    writer.Write("></" + Tag + ">");
                }
            }
            else if (!string.IsNullOrEmpty(innerContent))
            {
                writer.Write(">" + innerContent);
            }
            else
            {
                writer.Write(">");
            }
        }
Example #27
0
 internal override void Render(AjaxPage page, string[] templateNames, TextWriter writer)
 {
     try
     {
         ExoWeb.OnBeginRender(page, this);
         foreach (var block in Blocks)
             block.Render(page, templateNames.Concat(ContentTemplateNames).ToArray(), writer);
     }
     finally
     {
         ExoWeb.OnEndRender(page, this);
     }
 }
Example #28
0
        /// <summary>
        /// Render the data view to the output for the current page.
        /// </summary>
        /// <param name="page"></param>
        /// <param name="templateNames"></param>
        /// <param name="writer"></param>
        internal override void Render(AjaxPage page, string[] templateNames, System.IO.TextWriter writer)
        {
            bool             canRender;
            AttributeBinding ifBinding;

            if (!TryRenderIf(page, templateNames, writer, out ifBinding, out canRender))
            {
                Abort(page, templateNames, writer);
                return;
            }

            if (!canRender)
            {
                return;
            }

            // Output the original template if data source was not specified
            if (Data == null)
            {
                Abort(page, templateNames, writer);
                return;
            }

            // Get the data associated with the data view
            var dataBinding = Data.Evaluate(page);

            // Output the original template if no data was found
            if (!dataBinding.IsValid)
            {
                Abort(page, templateNames, writer);
                return;
            }

            // Render the inline template for top level dataviews
            string templateId      = null;
            string controlId       = null;
            bool   renderControlId = false;

            if (page.Context.IsGlobal)
            {
                templateId = page.NextControlId;
                controlId  = Attributes.Where(a => a.Name == "id").Select(a => a.Value).FirstOrDefault();
                if (controlId == null)
                {
                    renderControlId = true;
                    controlId       = page.NextControlId;
                }
                writer.Write("<");
                writer.Write(Tag);
                writer.Write(" class='sys-template' id='");
                writer.Write(templateId);
                writer.Write("'>");
                writer.Write(Template);
                writer.Write("</");
                writer.Write(Tag);
                writer.Write(">");
            }

            AttributeBinding contentTemplateBinding;

            if (!TryContentTemplate(page, templateNames, writer, out contentTemplateBinding))
            {
                Abort(page, templateNames, writer);
                return;
            }

            var ownTemplateNames = contentTemplateBinding != null ?
                                   ((string)contentTemplateBinding.Value).Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries) :
                                   new string[0];

            RenderStartTag(page, writer, ifBinding, dataBinding, contentTemplateBinding,
                           // Include the nested template index as a special attribute
                           new AttributeBinding(new Attribute()
            {
                Name = "data-sys-tmplidx", Value = NestedTemplateIndex.ToString()
            }, null),
                           // If this is a top-level dataview then we will need to ensure an id so that linking can occur
                           renderControlId ? new AttributeBinding(new Attribute()
            {
                Name = "id", Value = controlId
            }, null) : null);

            // Convert the data into a list
            IEnumerable list;

            if (dataBinding.Value == null)
            {
                list = new object[0];
            }
            else if (dataBinding.Value is IEnumerable && !(dataBinding.Value is string))
            {
                list = (IEnumerable)dataBinding.Value;
            }
            else
            {
                list = new[] { dataBinding.Value }
            };

            // Process the template for each list item
            var index = 0;

            foreach (var item in list)
            {
                // Begin a new template context
                using (var context = page.BeginContext(item, index++, null))
                {
                    RenderContextBeginMarker(context, Tag, writer);

                    foreach (var block in Blocks)
                    {
                        block.Render(page, templateNames.Concat(ownTemplateNames).ToArray(), writer);
                    }

                    RenderContextEndMarker(context, Tag, writer);
                }
            }

            RenderEndTag(writer);

            // Render script linking logic
            if (page.Context.IsGlobal)
            {
                writer.Write("<script type=\"text/javascript\">$exoweb({{ domReady: function() {{ Sys.Application.linkElement(document.getElementById(\"{0}\"), document.getElementById(\"{1}\")); }} }});</script>", controlId, templateId);
            }
        }
Example #29
0
File: Toggle.cs Project: vc3/ExoWeb
        /// <summary>
        /// 
        /// </summary>
        /// <param name="page"></param>
        /// <returns></returns>
        internal bool IsTemplate(AjaxPage page)
        {
            bool result = false;

            if (Action != null)
            {
                // action is literal render/dispose
                if (Action.Expression == "render" || Action.Expression == "dispose")
                    result = true;
                else
                {
                    // if not within a dataview or template, then any binding expressions
                    // for toggle action would not be dependent on template context data,
                    // so use the newly created page instance with a null context
                    var action = Action.Evaluate(page == null ? Page.Current as AjaxPage : page);
                    if (action.IsValid && (action.DisplayValue == "render" || action.DisplayValue == "dispose"))
                        result = true;
                }
            }

            return result;
        }
Example #30
0
 internal override void Render(AjaxPage page, string[] templateNames, System.IO.TextWriter writer)
 {
     RenderStartTag(page, writer);
 }
Example #31
0
        internal override void Render(AjaxPage page, string[] templateNames, System.IO.TextWriter writer)
        {
            bool canRender;
            AttributeBinding ifBinding;
            if (!TryRenderIf(page, templateNames, writer, out ifBinding, out canRender))
            {
                Abort(page, templateNames, writer);
                return;
            }

            if (!canRender)
                return;

            // Output the original template if data source was not specified
            if (Data == null)
            {
                Abort(page, templateNames, writer);
                return;
            }

            // Get the data associated with the content control
            var dataBinding = Data.Evaluate(page);
            var templateBinding = Template != null ? Template.Evaluate(page) : null;
            var dataTypeBinding = DataType != null ? DataType.Evaluate(page) : null;

            // Output the original template if the data binding expression could not be evaluated
            if ((!dataBinding.IsValid && (dataTypeBinding == null || !dataTypeBinding.IsValid)) || (templateBinding != null && !templateBinding.IsValid))
            {
                Abort(page, templateNames, writer);
                return;
            }

            AttributeBinding contentTemplateBinding;
            if (!TryContentTemplate(page, templateNames, writer, out contentTemplateBinding))
            {
                Abort(page, templateNames, writer);
                return;
            }

            var ownTemplateNames = contentTemplateBinding != null ?
                ((string) contentTemplateBinding.Value).Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries) :
                new string[0];

            // Just render an empty content element if the data is null
            if (dataBinding.IsValid && dataBinding.Value == null)
            {
                RenderStartTag(page, writer, ifBinding, dataBinding, contentTemplateBinding);
                RenderEndTag(writer);
                return;
            }

            // Get the binding data
            object data;
            bool isAdapter;
            ModelType referenceType;
            Type valueType;
            bool isList;

            // Valid binding
            if (dataBinding.IsValid)
            {
                data = dataBinding.Value;
                isAdapter = data is Adapter;
                object realData = isAdapter ? ((Adapter)data).RawValue : data;
                ModelProperty property = dataBinding.Property;
                referenceType = realData is ModelInstance ? ((ModelInstance)realData).Type :
                                property is ModelReferenceProperty ? ((ModelReferenceProperty)property).PropertyType : null;
                valueType = realData != null && !(realData is ModelInstance || realData is IEnumerable<ModelInstance>) ? realData.GetType() :
                            property is ModelValueProperty ? ((ModelValueProperty)property).PropertyType : null;
                isList = (property != null && property.IsList) || (realData is IEnumerable && !(realData is string));
            }

            // Datatype hint only
            else
            {
                var dataType = (string)dataTypeBinding.Value;
                isAdapter = Data is Binding.AdapterExtension || dataType == "ExoWeb.View.Adapter";
                isList = dataType.EndsWith("[]");
                if (isList)
                    dataType = dataType.Substring(0, dataType.Length - 2);
                valueType =	dataType == "String" ? typeof(string) :	dataType == "Number" ? typeof(decimal) : dataType == "Date" ? typeof(DateTime) : dataType == "Boolean" ? typeof(bool) : null;
                referenceType = valueType == null ? ModelContext.Current.GetModelType(dataType) : null;
                data = null;
            }

            // Evaluate content:template binding to get this content control's declare template(s)
            var templates = templateBinding != null && templateBinding.DisplayValue != null ? templateBinding.DisplayValue.Split(' ') : new string[0];

            // Join in the ContentTemplateNames value (sys:content-template) and the context's template names
            templates = templateNames.Concat(templates).Concat(ownTemplateNames).Distinct().ToArray();

            // Find the correct template
            var template = FindTemplate(page, isAdapter, referenceType, valueType, isList, templates);

            // Output the original template if a matching template could not be found
            if (template == null)
            {
                writer.Write("<!-- A template could not be found matching the specified criteria (TagName={0}, Adapter={1}, Type={2}{3}, IsList={4}, Names='{5}') -->", Tag, isAdapter, referenceType, valueType, isList, string.Join(", ", templates));
                Abort(page, templateNames, writer);
                return;
            }

            // Render the template inside a new template context
            using (var context = page.BeginContext(data, null))
            {
                // Render the original content start tag
                RenderStartTag(page, writer, attributes => template.Class.Length > 0 ? MergeClassName(attributes, template) : attributes, ifBinding, dataBinding, contentTemplateBinding, templateBinding, new AttributeBinding(new Attribute() { Name = "data-sys-tcindex", Value = context.Id }, null));

                // Render the content template
                template.Render(page, templates.Where(t => !template.Name.Contains(t)).Concat(template.ContentTemplateNames).ToArray(), writer);

                // Render the original content end tag
                RenderEndTag(writer);
            }
        }
Example #32
0
 protected void RenderStartTag(AjaxPage page, System.IO.TextWriter writer, Func<IEnumerable<AttributeBinding>, IEnumerable<AttributeBinding>> attributeTransform, params AttributeBinding[] bindings)
 {
     RenderStartTag(page, writer, attributeTransform, false, bindings);
 }
Example #33
0
        internal override void Render(AjaxPage page, string[] templateNames, System.IO.TextWriter writer)
        {
            bool             canRender;
            AttributeBinding ifBinding;

            if (!TryRenderIf(page, templateNames, writer, out ifBinding, out canRender))
            {
                Abort(page, templateNames, writer);
                return;
            }

            if (!canRender)
            {
                return;
            }

            // Output the original template if toggle on was not specified
            if (On == null)
            {
                Abort(page, templateNames, writer);
                return;
            }

            // Get the data associated with the data view
            var onBinding = On.Evaluate(page);

            // Output the original template if no data for on was found
            if (!onBinding.IsValid)
            {
                Abort(page, templateNames, writer);
                return;
            }

            var onValue = onBinding.Value;

            var classValue   = "";
            var classBinding = (AttributeBinding)null;

            if (ClassName != null)
            {
                classBinding = ClassName.Evaluate(page);

                // Output the original template if no data for class was found
                if (!classBinding.IsValid)
                {
                    Abort(page, templateNames, writer);
                    return;
                }

                classValue = (string)classBinding.Value;
            }

            ToggleAction?actionValue;

            var actionBinding = (AttributeBinding)null;

            // Get the value of the toggle action (i.e.: show, hide, etc.)
            if (Action != null)
            {
                actionBinding = Action.Evaluate(page);

                // Output the original template if no data for action was found
                if (!actionBinding.IsValid)
                {
                    Abort(page, templateNames, writer);
                    return;
                }

                actionValue = (ToggleAction)Enum.Parse(typeof(ToggleAction), (string)actionBinding.Value, true);
            }
            else if (!string.IsNullOrEmpty(classValue))
            {
                actionValue = ToggleAction.AddClass;
            }
            else
            {
                actionValue = ToggleAction.Show;
            }

            var groupNameBinding = (AttributeBinding)null;

            if (GroupName != null)
            {
                groupNameBinding = GroupName.Evaluate(page);

                // Output the original template if no data for group name was found
                if (!groupNameBinding.IsValid)
                {
                    Abort(page, templateNames, writer);
                    return;
                }
            }

            var strictModeValue   = false;
            var strictModeBinding = (AttributeBinding)null;

            if (StrictMode != null)
            {
                strictModeBinding = StrictMode.Evaluate(page);

                // Output the original template if no data for strict mode was found
                if (!strictModeBinding.IsValid)
                {
                    Abort(page, templateNames, writer);
                    return;
                }

                if (strictModeBinding.Value is bool)
                {
                    strictModeValue = (bool)strictModeBinding.Value;
                }
                else
                {
                    strictModeValue = bool.Parse((string)strictModeBinding.Value);
                }
            }

            bool?equals;

            var whenBinding = (AttributeBinding)null;

            // Evaluate whether the on and when conditions are equal or
            // satisified, which determines whether the toggle is on or off
            if (When == null)
            {
                if (strictModeValue)
                {
                    // In strict mode the on value must be a boolean true
                    if (!(onValue is bool))
                    {
                        throw new ApplicationException(string.Format("With strict mode enabled, toggle:on should be a value of type Boolean, actual type \"{0}\".", onValue == null ? "null" : onValue.GetType().Name));
                    }

                    equals = (bool)onValue;
                }
                else if (onValue is System.Collections.IEnumerable)
                {
                    equals = false;

                    // Satisfied if there are any items
                    foreach (object o in (System.Collections.IEnumerable)onValue)
                    {
                        equals = true;
                        break;
                    }
                }
                else
                {
                    // Otherwise, check to see that the on value is "truthy"
                    equals = JavaScriptHelpers.IsTruthy(onValue);
                }
            }
            else
            {
                whenBinding = When.Evaluate(page);

                var whenValue = whenBinding.Value;

                if (whenValue == null)
                {
                    equals = (onValue == null);
                }
                else if (whenValue is FunctionInstance)
                {
                    object result;

                    try
                    {
                        result = Page.ScriptMarshaller.Unwrap(((FunctionInstance)whenValue).Call(null, Page.ScriptMarshaller.Wrap(onValue)));
                    }
                    catch
                    {
                        Abort(page, templateNames, writer);
                        return;
                    }

                    if (strictModeValue)
                    {
                        if (!(result is bool))
                        {
                            throw new ApplicationException(string.Format("With strict mode enabled, toggle:when function should return a value of type Boolean, found type \"{0}\".", result == null ? "null" : result.GetType().Name));
                        }
                        equals = (bool)result;
                    }
                    else
                    {
                        equals = JavaScriptHelpers.IsTruthy(result);
                    }
                }
                else
                {
                    equals = whenValue.Equals(onValue);
                }
            }

            // If no class value is defined then abort
            if ((actionValue == ToggleAction.AddClass || actionValue == ToggleAction.RemoveClass) && string.IsNullOrEmpty(classValue))
            {
                Abort(page, templateNames, writer);
                return;
            }

            bool render = actionValue == ToggleAction.Render || actionValue == ToggleAction.Dispose;

            AttributeBinding contentTemplateBinding;

            if (!TryContentTemplate(page, templateNames, writer, out contentTemplateBinding))
            {
                Abort(page, templateNames, writer);
                return;
            }

            var ownTemplateNames = contentTemplateBinding != null ?
                                   ((string)contentTemplateBinding.Value).Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries) :
                                   new string[0];

            using (var context = render ? page.BeginContext(page.Context.DataItem, null) : null)
            {
                RenderStartTag(page, writer, attrs => MergeAttribute(MergeAttribute(MergeAttribute(attrs,
                                                                                                   "class", value =>
                {
                    if (actionValue == ToggleAction.AddClass || actionValue == ToggleAction.RemoveClass)
                    {
                        if ((actionValue == ToggleAction.AddClass && equals.Value) || (actionValue == ToggleAction.RemoveClass && !equals.Value))
                        {
                            value = AttributeHelper.EnsureClassName(value, classValue);
                        }
                        else
                        {
                            value = AttributeHelper.RemoveClassName(value, classValue);
                        }
                    }

                    // Add/remove the "toggle-on" and "toggle-off" classes based on state
                    value = AttributeHelper.EnsureClassName(value, equals.Value ? "toggle-on" : "toggle-off");
                    value = AttributeHelper.RemoveClassName(value, equals.Value ? "toggle-off" : "toggle-on");

                    return(value);
                }).ToArray(),
                                                                                    "style", value =>
                {
                    if (actionValue == ToggleAction.Show || actionValue == ToggleAction.Hide ||
                        actionValue == ToggleAction.Render || actionValue == ToggleAction.Dispose)
                    {
                        if (((actionValue == ToggleAction.Show || actionValue == ToggleAction.Render) && equals.Value) ||
                            ((actionValue == ToggleAction.Hide || actionValue == ToggleAction.Dispose) && !equals.Value))
                        {
                            if (AttributeHelper.GetCssStyle(value, "display") == "none")
                            {
                                value = AttributeHelper.RemoveCssStyle(value, "display");
                            }
                        }
                        else
                        {
                            value = AttributeHelper.EnsureCssStyle(value, "display", "none");
                        }
                    }

                    return(value);
                }).ToArray(),
                                                                     "disabled", value =>
                {
                    if (actionValue == ToggleAction.Enable || actionValue == ToggleAction.Disable)
                    {
                        if ((actionValue == ToggleAction.Enable && equals.Value) || (actionValue == ToggleAction.Disable && !equals.Value))
                        {
                            value = null;
                        }
                        else
                        {
                            value = "disabled";
                        }
                    }

                    return(value);
                }), ifBinding, onBinding, classBinding, actionBinding, groupNameBinding, strictModeBinding, whenBinding, contentTemplateBinding,
                               // If this is render/dispose, include the nested template index as a special attribute
                               render ? new AttributeBinding(new Attribute()
                {
                    Name = "data-sys-tmplidx", Value = NestedTemplateIndex.ToString()
                }, null) : null,
                               render ? new AttributeBinding(new Attribute()
                {
                    Name = "data-sys-tcindex", Value = context.Id
                }, null) : null);

                // Only render the inner blocks if the template would be rendered client-side
                if (!render || (actionValue == ToggleAction.Render && equals.Value) || (actionValue == ToggleAction.Dispose && !equals.Value))
                {
                    foreach (var block in Blocks)
                    {
                        block.Render(page, templateNames.Concat(ownTemplateNames).ToArray(), writer);
                    }
                }

                RenderEndTag(writer);
            }
        }
Example #34
0
        Template FindTemplate(AjaxPage page, bool isAdapter, ModelType entityType, Type valueType, bool isList, string[] names)
        {
            // Find the appropriate template
            var results = page.Templates.OfType<Template>().Reverse().Where(
                t =>
                {
                    // First ensure the template tags match
                    if (t.Tag != Tag)
                        return false;

                    // Then see if the template is for adapter bindings
                    if (isAdapter != t.IsAdapter)
                        return false;

                    // Then verify the datatypes
                    if (!String.IsNullOrEmpty(t.DataType))
                    {
                        // Reference
                        if (entityType != null)
                        {
                            // Verify the type matches if it is not the base type
                            var type = entityType;
                            while (type != null && type.Name != t.DataType)
                                type = type.BaseType;
                            if (type == null)
                                return false;
                        }

                        // Value
                        else
                        {
                            string type = JsonConverter.GetJsonValueType(valueType);

                            // Use "Array" as the type name for template matching for value types that are IEnumerable and not string.
                            // JsonConverter is primarily used for serialization of instance data and so the type returned will be
                            // the declared type of the property. Currently value type arrays are not fully supported but can be
                            // represented as "Object" for minimal functionality. For template matching we really want "Array" instead,
                            // since even in the case of custom serialization the value would be deserialized as an Array client-side
                            // and so if used in template matching the type name would be "Array".
                            if ((type == null || type == "Object") && typeof(IEnumerable).IsAssignableFrom(valueType))
                                type = "Array";

                            if (type == null || type != t.DataType)
                                return false;
                        }
                    }

                    // Check whether the template is specific to references
                    if (t.IsReference != null && t.IsReference != (entityType != null))
                        return false;

                    // Check whether the template is specific to lists
                    if (t.IsList != null && t.IsList != isList)
                        return false;

                    // Finally, verify that the template names match sufficiently
                    foreach (var name in t.Name)
                    {
                        if (!names.Contains(name))
                            return false;
                    }

                    return true;
                });

            return results.FirstOrDefault();
        }
Example #35
0
        protected bool TryContentTemplate(AjaxPage page, IEnumerable<string> templateNames, System.IO.TextWriter writer, out AttributeBinding contentTemplateBinding)
        {
            if (ContentTemplate == null)
            {
                contentTemplateBinding = null;
                return true;
            }

            contentTemplateBinding = ContentTemplate.Evaluate(page);
            return contentTemplateBinding.IsValid && contentTemplateBinding.Value is string;
        }
Example #36
0
 internal override AttributeBinding Evaluate(AjaxPage page)
 {
     return(binding);
 }
Example #37
0
        Template FindTemplate(AjaxPage page, bool isAdapter, ModelType entityType, Type valueType, bool isList, string[] names)
        {
            // Find the appropriate template
            return(page.Templates.OfType <Template>().Reverse().FirstOrDefault(
                       t =>
            {
                // First ensure the template tags match
                if (t.Tag != Tag)
                {
                    return false;
                }

                // Then see if the template is for adapter bindings
                if (isAdapter != t.IsAdapter)
                {
                    return false;
                }

                // Then verify the datatypes
                if (!String.IsNullOrEmpty(t.DataType))
                {
                    // Reference
                    if (entityType != null)
                    {
                        // Verify the type matches if it is not the base type
                        var type = entityType;
                        while (type != null && type.Name != t.DataType)
                        {
                            type = type.BaseType;
                        }
                        if (type == null)
                        {
                            return false;
                        }
                    }

                    // Value
                    else
                    {
                        string type = JsonConverter.GetJsonValueType(valueType);

                        // Use "Array" as the type name for template matching for value types that are IEnumerable and not string.
                        // JsonConverter is primarily used for serialization of instance data and so the type returned will be
                        // the declared type of the property. Currently value type arrays are not fully supported but can be
                        // represented as "Object" for minimal functionality. For template matching we really want "Array" instead,
                        // since even in the case of custom serialization the value would be deserialized as an Array client-side
                        // and so if used in template matching the type name would be "Array".
                        if ((type == null || type == "Object") && typeof(IEnumerable).IsAssignableFrom(valueType))
                        {
                            type = "Array";
                        }

                        if (type == null || type != t.DataType)
                        {
                            return false;
                        }
                    }
                }

                // Check whether the template is specific to references
                if (t.IsReference != null && t.IsReference != (entityType != null))
                {
                    return false;
                }

                // Check whether the template is specific to lists
                if (t.IsList != null && t.IsList != isList)
                {
                    return false;
                }

                // Finally, verify that the template names match sufficiently
                foreach (var name in t.Name)
                {
                    if (!names.Contains(name))
                    {
                        return false;
                    }
                }

                return true;
            }));
        }
Example #38
0
            internal override AttributeBinding Evaluate(AjaxPage page)
            {
                // Evaluate the binding path
                var result = page.EvaluatePath(Path);

                // Invalid result
                if (result.Property == null)
                    result.IsValid = false;

                // # syntax
                else if (Extension == "#")
                {
                    string format = null;
                    Parameters.TryGetValue("format", out format);

                    string value;
                    result.IsValid = Adapter.TryGetDisplayValue(result.Property, format, result.Value, out value);
                    result.Value = value;
                }

                // @ syntax
                else if (Extension == "@")
                {
                    if (string.IsNullOrEmpty(Path))
                    {
                        if (!(page.Context.DataItem is Adapter))
                            throw new ApplicationException("No path was specified for the \"@\" markup extension, and the source is not an adapter.");
                        result.Value = page.Context.DataItem;
                    }
                    else
                    {
                        var args = ExoWeb.OnBeforeCreateAdapter(this, result.Source, result.Property);

                        result = new BindingResult()
                        {
                            Value = new Adapter(result, args != null ? args.ModifiedParameters ?? Parameters : Parameters),
                            IsValid = result.IsValid,
                            Property = result.Property,
                            Source = result.Source
                        };
                    }
                }

                return new AttributeBinding(Attribute, result);
            }
Example #39
0
 protected void RenderStartTag(AjaxPage page, System.IO.TextWriter writer, params AttributeBinding[] bindings)
 {
     RenderStartTag(page, writer, null, bindings);
 }
Example #40
0
        internal override void Render(AjaxPage page, string[] templateNames, System.IO.TextWriter writer)
        {
            bool             canRender;
            AttributeBinding ifBinding;

            if (!TryRenderIf(page, templateNames, writer, out ifBinding, out canRender))
            {
                Abort(page, templateNames, writer);
                return;
            }

            if (!canRender)
            {
                return;
            }

            // Output the original template if data source was not specified
            if (Data == null)
            {
                Abort(page, templateNames, writer);
                return;
            }

            // Get the data associated with the content control
            var dataBinding     = Data.Evaluate(page);
            var templateBinding = Template != null?Template.Evaluate(page) : null;

            var dataTypeBinding = DataType != null?DataType.Evaluate(page) : null;

            // Output the original template if the data binding expression could not be evaluated
            if ((!dataBinding.IsValid && (dataTypeBinding == null || !dataTypeBinding.IsValid)) || (templateBinding != null && !templateBinding.IsValid))
            {
                Abort(page, templateNames, writer);
                return;
            }

            AttributeBinding contentTemplateBinding;

            if (!TryContentTemplate(page, templateNames, writer, out contentTemplateBinding))
            {
                Abort(page, templateNames, writer);
                return;
            }

            var ownTemplateNames = contentTemplateBinding != null ?
                                   ((string)contentTemplateBinding.Value).Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries) :
                                   new string[0];

            // Just render an empty content element if the data is null
            if (dataBinding.IsValid && dataBinding.Value == null)
            {
                RenderStartTag(page, writer, ifBinding, dataBinding, contentTemplateBinding);
                RenderEndTag(writer);
                return;
            }

            // Get the binding data
            object    data;
            bool      isAdapter;
            ModelType referenceType;
            Type      valueType;
            bool      isList;

            // Valid binding
            if (dataBinding.IsValid)
            {
                data      = dataBinding.Value;
                isAdapter = data is Adapter;
                object        realData = isAdapter ? ((Adapter)data).RawValue : data;
                ModelProperty property = dataBinding.Property;
                referenceType = realData is ModelInstance ? ((ModelInstance)realData).Type :
                                property is ModelReferenceProperty ? ((ModelReferenceProperty)property).PropertyType : null;
                valueType = realData != null && !(realData is ModelInstance || realData is IEnumerable <ModelInstance>) ? realData.GetType() :
                            property is ModelValueProperty ? ((ModelValueProperty)property).PropertyType : null;
                isList = (property != null && property.IsList) || (realData is IEnumerable && !(realData is string));
            }

            // Datatype hint only
            else
            {
                var dataType = (string)dataTypeBinding.Value;
                isAdapter = Data is Binding.AdapterExtension || dataType == "ExoWeb.View.Adapter";
                isList    = dataType.EndsWith("[]");
                if (isList)
                {
                    dataType = dataType.Substring(0, dataType.Length - 2);
                }
                valueType     = dataType == "String" ? typeof(string) : dataType == "Number" ? typeof(decimal) : dataType == "Date" ? typeof(DateTime) : dataType == "Boolean" ? typeof(bool) : null;
                referenceType = valueType == null?ModelContext.Current.GetModelType(dataType) : null;

                data = null;
            }

            // Evaluate content:template binding to get this content control's declare template(s)
            var templates = templateBinding != null && templateBinding.DisplayValue != null?templateBinding.DisplayValue.Split(' ') : new string[0];

            // Join in the ContentTemplateNames value (sys:content-template) and the context's template names
            templates = templateNames.Concat(templates).Concat(ownTemplateNames).Distinct().ToArray();

            // Find the correct template
            var template = FindTemplate(page, isAdapter, referenceType, valueType, isList, templates);

            // Output the original template if a matching template could not be found
            if (template == null)
            {
                writer.Write("<!-- A template could not be found matching the specified criteria (TagName={0}, Adapter={1}, Type={2}{3}, IsList={4}, Names='{5}') -->", Tag, isAdapter, referenceType, valueType, isList, string.Join(", ", templates));
                Abort(page, templateNames, writer);
                return;
            }

            // Render the template inside a new template context
            using (var context = page.BeginContext(data, null))
            {
                // Render the original content start tag
                RenderStartTag(page, writer, attributes => template.Class.Length > 0 ? MergeClassName(attributes, template) : attributes, ifBinding, dataBinding, contentTemplateBinding, templateBinding, new AttributeBinding(new Attribute()
                {
                    Name = "data-sys-tcindex", Value = context.Id
                }, null));

                // Render the content template
                template.Render(page, templates.Where(t => !template.Name.Contains(t)).Concat(template.ContentTemplateNames).ToArray(), writer);

                // Render the original content end tag
                RenderEndTag(writer);
            }
        }
Example #41
0
        protected void RenderStartTag(AjaxPage page, System.IO.TextWriter writer, Func<IEnumerable<AttributeBinding>, IEnumerable<AttributeBinding>> attributeTransform, bool abort, params AttributeBinding[] bindings)
        {
            // Immediately abort if no tag name
            if (Tag == null)
                return;

            // Open Tag
            writer.Write("<" + Tag);

            // Attributes
            string innerContent = null;
            var attributes = (Attributes ?? new List<Attribute>())
                .Select(attribute => attribute.Binding == null ? new AttributeBinding(attribute, null) : attribute.Binding.Evaluate(page));

            // Adding binding attributes if necessary
            if (bindings != null && bindings.Length > 0)
                attributes = attributes.Concat(bindings.Where(b => b != null));

            // Transform the attributes if necessary
            if (attributeTransform != null)
                attributes = attributeTransform(attributes);

            string classNames = null;
            bool foundId = false;
            bool isTextArea = Tag.Equals("textarea", StringComparison.InvariantCultureIgnoreCase);

            var attrs = attributes.ToArray();

            // Write the attributes to the output stream
            foreach (var attribute in attrs)
            {
                // Ensure that multiple id attributes are not specified
                if (!page.Context.IsGlobal && (attribute.Name == "id" || attribute.Name == "sys:id"))
                {
                    if (foundId)
                        throw new ApplicationException("Found multiple id attributes: " + Markup);
                    foundId = true;
                }

                // Determine if the attribute represents bound element content
                if (attribute.IsBound)
                {
                    if (attribute.Name == "sys:innerhtml" || (isTextArea && attribute.Name == "sys:value"))
                        innerContent = (attribute.DisplayValue ?? "");
                    else if (attribute.Name == "sys:innertext")
                        innerContent = HttpUtility.HtmlEncode(attribute.DisplayValue ?? "");
                }

                bool isHtmlBoolean;
                var attributeName = attribute.Name.StartsWith("sys:") ? attribute.Name.Substring(4) : attribute.Name;
                if (Tag.Equals("input", StringComparison.InvariantCultureIgnoreCase))
                {
                    var attr = attrs.SingleOrDefault(a => a.Name.Equals("type", StringComparison.InvariantCultureIgnoreCase) && a.IsValid && a.Value != null);
                    if (attr == null)
                        isHtmlBoolean = HtmlHelpers.IsBooleanAttribute(attributeName, Tag, null, true);
                    else
                        isHtmlBoolean = HtmlHelpers.IsBooleanAttribute(attributeName, Tag, attr.Value.ToString());
                }
                else
                    isHtmlBoolean = HtmlHelpers.IsBooleanAttribute(attributeName, Tag);

                if (abort)
                    attribute.Abort(writer, isHtmlBoolean);
                else
                {
                    if (attribute.Name == "class")
                    {
                        if (classNames == null)
                            classNames = (string)attribute.Value;
                        else
                            classNames += " " + (string)attribute.Value;
                    }
                    else
                    {
                        if (attribute.Name.StartsWith("sys:class-"))
                        {
                            // If binding evaluates as truthy, then render the store the class name
                            if (JavaScriptHelpers.IsTruthy(attribute.Value))
                            {
                                string sysClassValue = attribute.Name.Substring(10);
                                if (classNames == null)
                                    classNames = sysClassValue;
                                else
                                    classNames += (classNames.Length > 0 ? " " : "") + sysClassValue;
                            }
                        }
                        attribute.Render(page, writer, isHtmlBoolean, !page.Context.IsGlobal, isTextArea);
                    }
                }
            }

            // Write direct class and sys:class- attribute values together. Note: by checking
            // for null we may be avoiding writing a class attribute altogether whereas the
            // client framework would have produced an empty class attribute.
            if (classNames != null)
            {
                writer.Write(" class=\"");
                HttpUtility.HtmlAttributeEncode(classNames, writer);
                writer.Write("\"");
            }

            // Close Tag
            if (IsEmpty)
            {
                if (!string.IsNullOrEmpty(innerContent))
                    writer.Write(">" + innerContent + "</" + Tag + ">");
                else if (HtmlHelpers.IsSelfClosing(Tag))
                    writer.Write(" />");
                else
                    writer.Write("></" + Tag + ">");
            }
            else if (!string.IsNullOrEmpty(innerContent))
                writer.Write(">" + innerContent);
            else
                writer.Write(">");
        }
Example #42
0
        public void Render(AjaxPage page, System.IO.TextWriter writer, bool isHtmlBool, bool generateIds, bool isTextArea)
        {
            // Bound attribute
            if (binding != null)
            {
                // Valid binding
                if (binding.IsValid)
                {
                    // Render the binding value for sys attributes
                    if (attribute.Name.StartsWith("sys:"))
                    {
                        var attributeName = attribute.Name.Substring(4);

                        // Render two-way binding expressions
                        if (attribute.Binding.IsTwoWay)
                            RenderAttribute(writer, "data-sys-" + attributeName, attribute.Binding.Expression);

                        if (binding.Value != null)
                        {
                            if (attributeName != "if" && attributeName != "innerhtml" && attributeName != "innertext" && !(isTextArea && attributeName == "value") && !attribute.Name.StartsWith("sys:class-"))
                            {
                                if (isHtmlBool)
                                {
                                    if (JavaScriptHelpers.IsTruthy(binding.Value))
                                        RenderAttribute(writer, attributeName, attributeName);
                                }
                                else
                                    RenderAttribute(writer, attributeName, binding.Value.ToString());
                            }
                        }
                    }
                    else
                        RenderAttribute(writer, "data-" + attribute.Name.Replace(':', '-'), attribute.Binding.Expression);
                }

                // Invalid binding
                else
                    RenderAttribute(writer, attribute.Name, attribute.Binding.Expression);
            }
            else if (generateIds && (attribute.Name == "id" || attribute.Name == "sys:id"))
                RenderAttribute(writer, "id", page.Context.GetInstanceId(attribute.Value));
            // Simple attribute
            else if (attribute.Name.Contains(":") && attribute.Name != "sys:id")
                RenderAttribute(writer, "data-" + attribute.Name.Replace(':', '-'), attribute.Value);
            else if (isHtmlBool)
            {
                if (JavaScriptHelpers.IsTruthy(attribute.Value))
                    RenderAttribute(writer, attribute.Name, attribute.Name);
            }
            else
                RenderAttribute(writer, attribute.Name, attribute.Value);
        }