/// <summary> /// Persist the container's controls list matches the tag's attributes' state /// </summary> public void PersistControls() { var doc = Parse(); foreach (XNode node in doc.XDocument.RootElement.AllDescendentElements) { if (!(node is XElement)) { continue; } var element = node as XElement; if (element.Name.HasPrefix || XDocumentHelper.IsRunAtServer(element)) { string id = XDocumentHelper.GetAttributeValueCI(element.Attributes, "id"); bool checkDefaults; IComponent comp = host.GetComponent(id); if (comp == null) { // the tag does not have a matching component in the // container so create one comp = ProcessControl(element); if (comp == null) { continue; } // assuming that we have an id already from the initial controls parse host.Container.Add(comp, id); // no need to check for defaults as we have a new component checkDefaults = false; } else { // check if the tag's attributes and the component's attributes match checkDefaults = true; } ProcessControlProperties(element, comp, checkDefaults); } } }
/// <summary> /// Gets the control tag's XElement instance. /// </summary> /// <returns> /// The control tag. /// </returns> /// <param name='container'> /// The Xelement that contains the control's XElement instance /// </param> /// <param name='id'> /// Identifier of the control. /// </param> XElement GetControlTag(XElement container, string id) { XElement controlTag = null; foreach (XNode node in container.Nodes) { if (controlTag != null) { break; } if (node is XElement) { XElement el = node as XElement; string currId = XDocumentHelper.GetAttributeValueCI(el.Attributes, "id"); if (XDocumentHelper.IsRunAtServer(el) && (string.Compare(currId, id, true) == 0)) { controlTag = el; break; } controlTag = GetControlTag(el, id); } } return(controlTag); }
/// <summary> /// Gets the type of the html control. /// </summary> /// <returns> /// The html control type. /// </returns> /// <param name='el'> /// The supposed html control's tag XElement /// </param> private Type GetHtmlControlType(XElement el) { // query the htmlControlTags dict for the type string nameLowered = el.Name.Name.ToLower(); if (!htmlControlTags.ContainsKey(nameLowered)) { return(null); } Type compType = htmlControlTags[nameLowered]; // for the input tag we have different types depending on the type attribute // so in the dict its type is marked with null if (compType == null) { string typeAttr = XDocumentHelper.GetAttributeValueCI(el.Attributes, "type"); // get the Type depending on the type attribute switch (typeAttr.ToLower()) { case "button": compType = typeof(HtmlInputButton); break; case "checkbox": compType = typeof(HtmlInputCheckBox); break; case "file": compType = typeof(HtmlInputFile); break; case "hidden": compType = typeof(HtmlInputHidden); break; case "image": compType = typeof(HtmlInputImage); break; case "password": compType = typeof(HtmlInputPassword); break; case "radio": compType = typeof(HtmlInputRadioButton); break; case "reset": compType = typeof(HtmlInputReset); break; case "submit": compType = typeof(HtmlInputSubmit); break; case "text": compType = typeof(HtmlInputText); break; } } return(compType); }
/// <summary> /// Checks the document for control tags, creates components and adds the to the IContainer. /// Adds an id attributes to tags that are server controls but doesn't have an id attribute. /// </summary> void ParseControls() { // no need to serialize the document, if we add just an id attribute to a control suppressSerialization = true; // if an id tag was added the document changes // so we parse the document each time it does do { // get a fresh new AspNetParsedDocument var doc = Parse(); // go through all the nodes of the document foreach (XNode node in doc.XDocument.RootElement.AllDescendentElements) { // if a node is not a XElement, no need to check if it's a control if (!(node is XElement)) { continue; } var element = node as XElement; // the controls have a tag prefix or runat="server" attribute if (element.Name.HasPrefix || XDocumentHelper.IsRunAtServer(element)) { string id = XDocumentHelper.GetAttributeValueCI(element.Attributes, "id"); // check the DesignContainer if a component for that node already exists if (host.GetComponent(id) == null) { // create a component of type depending of the element IComponent comp = ProcessControl(element); if (comp == null) { continue; } // add id to the component, for later recognition if it has no ID attribute if (String.IsNullOrEmpty(id)) { var nameServ = host.GetService(typeof(INameCreationService)) as INameCreationService; if (nameServ == null) { throw new Exception("Could not obtain INameCreationService from the DesignerHost."); } // insert the attribute to the element host.AspNetSerializer.SetAttribtue(element, "id", nameServ.CreateName(host.Container, comp.GetType())); updateEditorContent.WaitOne(); // wait until the changes have been applied to the document break; } // we have a control component, add it to the container this.host.Container.Add(comp, id); // and parse its attributes for component properties ProcessControlProperties(element, comp); } } } } while (txtDocDirty); suppressSerialization = false; }
/// <summary> /// Serializes a XNode to a HTML tag. This is a recursive method. /// </summary> /// <param name='node'> /// Node. /// </param> /// <param name='sb'> /// A string builder instance. /// </param> void SerializeNode(XNode node, StringBuilder sb) { prevTagLocation = node.Region.End; var element = node as XElement; if (element == null) { return; } string id = XDocumentHelper.GetAttributeValueCI(element.Attributes, "id"); // Controls are runat="server" and have unique id in the Container if (element.Name.HasPrefix || XDocumentHelper.IsRunAtServer(element)) { IComponent component = host.GetComponent(id); // HTML controls, doesn't need special rendering var control = component as Control; // genarete placeholder if (control != null) { StringWriter strWriter = new StringWriter(); HtmlTextWriter writer = new HtmlTextWriter(strWriter); control.RenderControl(writer); writer.Close(); strWriter.Flush(); sb.Append(strWriter.ToString()); strWriter.Close(); if (!element.IsSelfClosing) { prevTagLocation = element.ClosingTag.Region.End; } return; } } // strip script tags if (element.Name.Name.ToLower() == "script") { return; } // the node is a html element sb.AppendFormat("<{0}", element.Name.FullName); // print the attributes foreach (MonoDevelop.Xml.StateEngine.XAttribute attr in element.Attributes) { string name = attr.Name.Name.ToLower(); // strip runat and on* event attributes if ((name != "runat") && (name.Substring(0, 2).ToLower() != "on")) { sb.AppendFormat(" {0}=\"{1}\"", attr.Name.FullName, attr.Value); } } if (element.IsSelfClosing) { sb.Append(" />"); } else { sb.Append(">"); // we are currentyl on the head tag // add designer content - js and css if (element.Name.Name.ToLower() == "head") { sb.Append(designerContext); } if (element.Name.Name.ToLower() == "body") { GetDesignerInitParams(sb); } // serializing the childnodes if any foreach (MonoDevelop.Xml.StateEngine.XNode nd in element.Nodes) { // get the text before the openning tag of the child element sb.Append(document.GetTextFromEditor(prevTagLocation, nd.Region.Begin)); // and the element itself SerializeNode(nd, sb); } // printing the text after the closing tag of the child elements int lastChildEndLine = element.Region.EndLine; int lastChildEndColumn = element.Region.EndColumn; // if the element have 1+ children if (element.LastChild != null) { var lastChild = element.LastChild as MonoDevelop.Xml.StateEngine.XElement; // the last child is an XML tag if (lastChild != null) { // the tag is selfclosing if (lastChild.IsSelfClosing) { lastChildEndLine = lastChild.Region.EndLine; lastChildEndColumn = lastChild.Region.EndColumn; // the tag is not selfclosing and has a closing tag } else if (lastChild.ClosingTag != null) { lastChildEndLine = lastChild.ClosingTag.Region.EndLine; lastChildEndColumn = lastChild.ClosingTag.Region.EndColumn; } else { // TODO: the element is not closed. Warn the user } // the last child is not a XML element. Probably AspNet tag. TODO: find the end location of that tag } else { lastChildEndLine = element.LastChild.Region.EndLine; lastChildEndLine = element.LastChild.Region.EndLine; } } if (element.ClosingTag != null) { sb.Append(document.GetTextFromEditor(new TextLocation(lastChildEndLine, lastChildEndColumn), element.ClosingTag.Region.Begin)); prevTagLocation = element.ClosingTag.Region.End; } else { // TODO: the element is not closed. Warn the user } sb.AppendFormat("</{0}>", element.Name.FullName); } }