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); } }
/// <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); } }