internal bool TryParseEnum <TEnum>(ParseResult result, AttributesHelper attributes, string attributeName, out TEnum answer, bool caseSensitive = true) where TEnum : struct, IConvertible { XAttribute attr = attributes.PopAttribute(attributeName, caseSensitive); // If it has the attribute if (attr != null) { // And the attribute has a value if (attr.Value != null) { if (TryParseEnum(attr.Value, out answer)) { return(true); } // Couldn't find matching enum result.AddWarning($@"Unknown value ""{attr.Value}"" on {attributeName} attribute", GetErrorPositionInfo(attr)); if (TryGetUnknownEnum(out answer)) { return(true); } } // Attribute doesn't have a value else { result.AddWarning($@"Attribute {attributeName} has no value specified", GetErrorPositionInfo(attr)); } } // Attribute isn't found, no warning answer = default(TEnum); return(false); }
private void HandleChild(ParseResult result, XElement child) { if (child.IsType("visual")) { if (Visual != null) { result.AddWarning("A visual element was already provided. Only the first one will be used.", GetErrorPositionInfo(child)); return; } Visual visual = new Visual(NotificationType.Cortana, SupportedFeatures); visual.Parse(result, child); Visual = visual; } else if (child.IsType("actionDefinitions")) { if (ActionDefinitions != null) { result.AddWarning("An actionDefinitions element was already provided. Only the first one will be used.", GetErrorPositionInfo(child)); return; } ActionDefinitions actions = new ActionDefinitions(NotificationType.Cortana, SupportedFeatures); actions.Parse(result, child); ActionDefinitions = actions; } else { result.AddError($"Invalid child {child.Name.LocalName} under toast element.", GetErrorPositionInfo(child)); } }
protected override void ParseKnownAttributes(XElement node, AttributesHelper attributes, ParseResult result, string baseUri, bool addImageQuery) { base.ParseKnownAttributes(node, attributes, result, baseUri, addImageQuery); // Template is required XAttribute attrTemplate = attributes.PopAttribute(ATTR_BINDING_TEMPLATE); if (attrTemplate == null) { result.AddWarning("template attribute wasn't provided on binding element.", GetErrorPositionInfo(node)); throw new IncompleteElementException(); } // If template is unknown, stop there Template template; if (!TryParseEnum(attrTemplate.Value, out template)) { result.AddWarning($"template attribute \"{attrTemplate.Value}\" is not supported.", GetErrorPositionInfo(attrTemplate)); throw new IncompleteElementException(); } this.Template = template; // Branding is optional Branding branding; if (TryParseEnum(result, attributes, ATTR_BINDING_BRANDING, out branding, false)) // not case-sensitive { this.Branding = branding; } // Display name is optional XAttribute attrDisplayName = attributes.PopAttribute(ATTR_BINDING_DISPLAY_NAME, false); // not case-sensitive if (attrDisplayName != null) { this.DisplayName = attrDisplayName.Value; } // hint-overlay is optional double hintOverlay; if (TryParse(result, attributes, ATTR_BINDING_HINT_OVERLAY, out hintOverlay)) { this.HintOverlay = hintOverlay; } // hint-textStacking is optional HintTextStacking hintTextStacking; if (TryParseEnum(result, attributes, ATTR_BINDING_HINT_TEXT_STACKING, out hintTextStacking)) { this.HintTextStacking = hintTextStacking; } }
protected virtual void HandleChild(ParseResult result, XElement child) { switch (child.Name.LocalName.ToLower()) { case AdaptiveSetter.ELEMENT_NAME: var setter = new AdaptiveSetter(Context, SupportedFeatures); setter.Parse(result, child); if (!result.IsOkForRender()) { return; } Setters.Add(setter); setter.Parent = this; break; default: result.AddWarning($"Invalid child {child.Name.LocalName} under {ELEMENT_NAME} element.", GetErrorPositionInfo(child)); break; } }
protected virtual void HandleChild(ParseResult result, XElement child) { switch (child.Name.LocalName.ToLower()) { case "action": var action = new ActionDefinition(Context, SupportedFeatures); action.Parse(result, child); if (!result.IsOkForRender()) { return; } Definitions.Add(action); action.Parent = this; break; default: result.AddWarning($"Invalid child {child.Name.LocalName} under actions element.", GetErrorPositionInfo(child)); break; } }
protected void HandleChild(ParseResult result, XElement child) { if (Type != InputType.Selection) { result.AddWarning($"Invalid child '{child.Name.LocalName}' found in an input. Only inputs of type 'selection' can contain children.", GetErrorPositionInfo(child)); return; } if (child.IsType("selection")) { Selection selection = new Selection(Context, SupportedFeatures); selection.Parse(result, child); if (!result.IsOkForRender()) { throw new IncompleteElementException(); } Children.Add(selection); selection.Parent = this; } else { result.AddError($@"Invalid child ""{child.Name.LocalName}"" found in an input. Selection inputs can only contain selection elements.", GetErrorPositionInfo(child)); } }
internal virtual void ParseKnownAttributes(XElement node, AttributesHelper attributes, ParseResult result) { // src is optional var srcAttr = attributes.PopAttribute(ATTR_SRC); if (srcAttr != null) { Uri srcUri; if (Uri.TryCreate(srcAttr.Value, UriKind.RelativeOrAbsolute, out srcUri)) { Src = srcUri; } else { result.AddWarning("Audio src value must be a valid Uri.", XmlTemplateParser.GetErrorPositionInfo(node)); } } // loop is optional, must be bool bool boolean; if (TryParse(result, attributes, ATTR_LOOP, out boolean)) { Loop = boolean; } if (TryParse(result, attributes, ATTR_SILENT, out boolean)) { Silent = boolean; } }
protected virtual void HandleChild(ParseResult result, XElement child) { switch (child.Name.LocalName.ToLower()) { case "input": var input = new Input(Context, SupportedFeatures); input.Parse(result, child); if (!result.IsOkForRender()) { return; } if (Context == NotificationType.Toast) { if (Inputs.Count >= 5) { result.AddErrorButRenderAllowed("Toasts can only display up to 5 inputs.", GetErrorPositionInfo(child)); return; } } Inputs.Add(input); input.Parent = this; break; case "action": var action = new Action(Context, SupportedFeatures); action.Parse(result, child); if (!result.IsOkForRender()) { return; } if (Context == NotificationType.Toast) { if (ActionElements.Count >= 5) { result.AddErrorButRenderAllowed("Toasts can only display up to 5 actions.", GetErrorPositionInfo(child)); return; } } ActionElements.Add(action); action.Parent = this; break; default: result.AddWarning($"Invalid child {child.Name.LocalName} under actions element.", GetErrorPositionInfo(child)); break; } }
protected void HandleChild(ParseResult result, XElement child, string baseUri, bool addImageQuery) { switch (child.Name.LocalName.ToLower()) { case "text": AdaptiveTextField text = new AdaptiveTextField(Context, SupportedFeatures); text.Parse(result, child, false); if (!result.IsOkForRender()) { throw new IncompleteElementException(); } if (text != null) { this.Add(text); } break; case "image": AdaptiveImage image = new AdaptiveImage(Context, SupportedFeatures); image.Parse(result, child, baseUri, addImageQuery); if (!result.IsOkForRender()) { throw new IncompleteElementException(); } if (image != null) { if (image.Placement != Placement.Inline) { result.AddErrorButRenderAllowed("You cannot place a non-inline image element inside a subgroup.", GetErrorPositionInfo(child)); } this.Add(image); } break; default: result.AddWarning($"Invalid child \"{child.Name.LocalName}\" under subgroup element. It will be ignored.", GetErrorPositionInfo(child)); break; } }
protected override void HandleChild(ParseResult result, XElement child, string baseUri, bool addImageQuery) { switch (child.Name.LocalName.ToLower()) { case "text": TileTextField text = new TileTextField(); text.Parse(result, child); if (!result.IsOkForRender()) { throw new IncompleteElementException(); } if (text != null) { this.Add(text); } break; case "image": TileImage image = new TileImage(); image.Parse(result, child, baseUri, addImageQuery); if (!result.IsOkForRender()) { throw new IncompleteElementException(); } if (image != null) { this.Add(image); } break; default: result.AddWarning($"Invalid child \"{child.Name.LocalName}\" under subgroup element. It will be ignored.", GetErrorPositionInfo(child)); break; } }
protected void HandleChild(ParseResult result, XElement child, string baseUri, bool addImageQuery) { if (child.IsType("binding")) { AdaptiveBinding binding = new AdaptiveBinding(Context, SupportedFeatures); binding.Parse(result, child, baseUri, addImageQuery); if (!result.IsOkForRender()) { throw new IncompleteElementException(); } this.Add(binding); } else { result.AddWarning($"Invalid child {child.Name.LocalName} under visual element.", GetErrorPositionInfo(child)); } }
private void HandleChild(ParseResult result, XElement child) { if (child.IsType("visual")) { if (Visual != null) { result.AddWarning("A visual element was already provided. Only the first one will be used.", GetErrorPositionInfo(child)); return; } Visual visual = new Visual(NotificationType.NewsFeed, SupportedFeatures); visual.Parse(result, child); Visual = visual; } else { result.AddError($"Invalid child {child.Name.LocalName} under newsFeed element.", GetErrorPositionInfo(child)); } }
internal void ParseKnownAttributes(XElement node, AttributesHelper attributes, ParseResult result) { // We parse title first, and we only completely fail on title, since if id isn't provided, // we can at least still render something for the preview (we still display error though). // We'll assume that the developer will add the id before they send the toast. // title is required XAttribute attrTitle = attributes.PopAttribute(ATTR_TITLE); if (attrTitle == null) { result.AddErrorButRenderAllowed("title attribute on header element is required.", XmlTemplateParser.GetErrorPositionInfo(node)); // We'll fail without a title throw new IncompleteElementException(); } else { if (string.IsNullOrWhiteSpace(attrTitle.Value)) { result.AddWarning("title attribute in header element must contain a string. The header will be dropped.", XmlTemplateParser.GetErrorPositionInfo(attrTitle)); throw new IncompleteElementException(); } else { Title = attrTitle.Value; } } // id is required XAttribute attrId = attributes.PopAttribute(ATTR_ID); if (attrId == null) { result.AddErrorButRenderAllowed("id attribute on header element is required.", XmlTemplateParser.GetErrorPositionInfo(node)); } else { if (string.IsNullOrWhiteSpace(attrId.Value)) { result.AddWarning("id attribute in header element must contain a string. The header will be dropped.", XmlTemplateParser.GetErrorPositionInfo(attrId)); throw new IncompleteElementException(); } else { Id = attrId.Value; } } // arguments is required XAttribute attrArguments = attributes.PopAttribute(ATTR_ARGUMENTS); if (attrArguments == null) { result.AddErrorButRenderAllowed("arguments attribute on header element is required.", XmlTemplateParser.GetErrorPositionInfo(node)); } else { // Empty string in arguments is allowed Arguments = attrArguments.Value; } // activationType is optional ActivationType type; if (TryParseEnum(result, attributes, ATTR_ACTIVATIONTYPE, out type)) { ActivationType = type; } }
private void HandleChild(ParseResult result, XElement child) { if (child.IsType("visual")) { if (Visual != null) { result.AddWarning("A visual element was already provided. Only the first one will be used.", GetErrorPositionInfo(child)); return; } Visual visual = new Visual(NotificationType.Toast, SupportedFeatures); visual.Parse(result, child); Visual = visual; } else if (child.IsType("actions")) { if (Actions != null) { result.AddWarning("An actions element was already provided. Only the first one will be used.", GetErrorPositionInfo(child)); return; } Actions actions = new Actions(NotificationType.Toast, SupportedFeatures); actions.Parse(result, child); Actions = actions; } else if (child.IsType("audio")) { if (Audio != null) { result.AddWarning("An audio element was already provided. Only the first one will be used.", GetErrorPositionInfo(child)); return; } Audio audio = new Audio(NotificationType.Toast, SupportedFeatures); audio.Parse(result, child); Audio = audio; } else if (SupportedFeatures.ToastHeaders && child.IsType("header")) { if (Header != null) { result.AddErrorButRenderAllowed("A header element was already provided. Only one header is allowed.", GetErrorPositionInfo(child)); return; } Header header = new Header(NotificationType.Toast, SupportedFeatures); header.Parse(result, child); Header = header; } else { result.AddError($"Invalid child {child.Name.LocalName} under toast element.", GetErrorPositionInfo(child)); } }
private void ParseKnownAttributes(AttributesHelper attributes, ParseResult result) { // Launch is optional var attrLaunc = attributes.PopAttribute(ATTR_LAUNCH); if (attrLaunc != null) { Launch = attrLaunc.Value; } // TODO - check duration is valid // activationType is optional ActivationType activationType; if (TryParseEnum <ActivationType>(result, attributes, ATTR_ACTIVATIONTYPE, out activationType)) { ActivationType = activationType; } // scenario is optional Scenario scenario; if (TryParseEnum(result, attributes, ATTR_SCENARIO, out scenario)) { Scenario = scenario; } // duration is optional Duration duration; if (TryParseEnum(result, attributes, ATTR_DURATION, out duration)) { Duration = duration; } // hint-people is optional var attrPeople = attributes.PopAttribute(ATTR_HINT_PEOPLE); if (attrPeople != null) { People = attrPeople.Value; } // displayTimestamp is optional if (SupportedFeatures.ToastDisplayTimestamp) { var attrDisplayTimestamp = attributes.PopAttribute(ATTR_DISPLAYTIMESTAMP); if (attrDisplayTimestamp != null) { try { DisplayTimestamp = System.Xml.XmlConvert.ToDateTime(attrDisplayTimestamp.Value, System.Xml.XmlDateTimeSerializationMode.RoundtripKind); } catch (FormatException) { result.AddWarning(ATTR_DISPLAYTIMESTAMP + " must be specified in ISO 8601 format.", GetErrorPositionInfo(attrDisplayTimestamp)); } } } }
protected void HandleChild(ParseResult result, XElement child, string baseUri, bool addImageQuery) { switch (child.Name.LocalName.ToLower()) { case "text": AdaptiveTextField text = new AdaptiveTextField(Context, SupportedFeatures); text.Parse(result, child, true); if (!result.IsOkForRender()) { return; } if (text.Placement == TextPlacement.Inline && Context == NotificationType.Toast) { if (Children.OfType <AdaptiveTextField>().Where(i => i.Placement == TextPlacement.Inline).Count() >= 3) { if (!_hasWarnedAboutTooManyTextElements) { string warningMessage; if (SupportedFeatures.RS1_Style_Toasts) { warningMessage = "Toasts can only display up to 3 text elements outside of a group/subgroup. Place your additional text elements inside a group/subgroup."; } else { warningMessage = "Toasts can only display up to 3 text elements."; } result.AddWarning(warningMessage, GetErrorPositionInfo(child)); _hasWarnedAboutTooManyTextElements = true; } return; } } this.Add(text); return; case "image": AdaptiveImage image = new AdaptiveImage(Context, SupportedFeatures); image.Parse(result, child, baseUri, addImageQuery); if (!result.IsOkForRender()) { return; } if (Context == NotificationType.Toast && !SupportedFeatures.AdaptiveToasts && image.Placement == Placement.Inline ) { if (Children.OfType <AdaptiveImage>().Where(i => i.Placement == Placement.Inline).Count() >= 6) { if (!_hasWarnedAboutTooManyInlineImages) { result.AddWarning("Toasts can only display up to 6 inline images.", GetErrorPositionInfo(child)); _hasWarnedAboutTooManyInlineImages = true; } return; } } this.Add(image); return; case "group": if (Context != NotificationType.Toast || SupportedFeatures.AdaptiveToasts ) { AdaptiveGroup group = new AdaptiveGroup(Context, SupportedFeatures); group.Parse(result, child, baseUri, addImageQuery); if (!result.IsOkForRender()) { return; } if (group != null) { this.Add(group); } return; } break; case "progress": if (Context == NotificationType.Toast && SupportedFeatures.ToastProgressBar) { AdaptiveProgress progress = new AdaptiveProgress(Context, SupportedFeatures); progress.Parse(result, child); if (!result.IsOkForRender()) { return; } this.Add(progress); return; } break; } result.AddWarning($"Invalid child \"{child.Name.LocalName}\" under binding element. It will be ignored.", GetErrorPositionInfo(child)); }
protected override void HandleChild(ParseResult result, XElement child, string baseUri, bool addImageQuery) { switch (child.Name.LocalName.ToLower()) { case "text": TileTextField text = new TileTextField(); text.Parse(result, child); if (!result.IsOkForRender()) { return; } this.Add(text); break; case "image": TileImage image = new TileImage(); image.Parse(result, child, baseUri, addImageQuery); if (!result.IsOkForRender()) { return; } switch (image.Placement) { case Placement.Peek: if (this.PeekImage != null) { result.AddWarning("Multiple peek images were supplied inside a binding. Only the first will be used.", GetErrorPositionInfo(child)); } else { this.PeekImage = image; } break; case Placement.Background: if (this.BackgroundImage != null) { result.AddWarning("Multiple background images were supplied inside a binding. Only the first will be used.", GetErrorPositionInfo(child)); } else { this.BackgroundImage = image; } break; default: Add(image); break; } break; case "group": TileGroup group = new TileGroup(); group.Parse(result, child, baseUri, addImageQuery); if (!result.IsOkForRender()) { return; } if (group != null) { this.Add(group); } break; default: result.AddWarning($"Invalid child \"{child.Name.LocalName}\" under binding element. It will be ignored.", GetErrorPositionInfo(child)); break; } }
protected virtual void ParseKnownAttributes(XElement node, AttributesHelper attributes, ParseResult result, string baseUri, bool addImageQuery) { // Template is required XAttribute attrTemplate = attributes.PopAttribute(ATTR_BINDING_TEMPLATE); if (attrTemplate == null) { result.AddWarning("template attribute wasn't provided on binding element.", GetErrorPositionInfo(node)); throw new IncompleteElementException(); } // If template is unknown, stop there Template template; if (!TryParseEnum(attrTemplate.Value, out template)) { result.AddWarning($"template attribute \"{attrTemplate.Value}\" is not supported.", GetErrorPositionInfo(attrTemplate)); throw new IncompleteElementException(); } this.Template = template; switch (Template) { case Template.TileLarge: case Template.TileMedium: case Template.TileWide: case Template.TileSmall: Context = NotificationType.Tile; break; case Template.ToastGeneric: Context = NotificationType.Toast; break; #if EXPERIMENTAL case Template.CortanaGeneric: Context = NotificationType.Cortana; break; case Template.NewsFeedGeneric: Context = NotificationType.NewsFeed; break; #endif } if (Context != NotificationType.Toast) { // Branding is optional Branding branding; if (TryParseEnum(result, attributes, ATTR_BINDING_BRANDING, out branding, false)) // not case-sensitive { this.Branding = branding; } // Display name is optional XAttribute attrDisplayName = attributes.PopAttribute(ATTR_BINDING_DISPLAY_NAME, false); // not case-sensitive if (attrDisplayName != null) { this.DisplayName = attrDisplayName.Value; } // hint-overlay is optional double hintOverlay; if (TryParse(result, attributes, ATTR_BINDING_HINT_OVERLAY, out hintOverlay)) { this.HintOverlay = hintOverlay; } } if (Context == NotificationType.Tile) { if (SupportedFeatures.ChaseableTiles) { // attributes is optional XAttribute attrArguments = attributes.PopAttribute(ATTR_ARGUMENTS); if (attrArguments != null) { this.Arguments = attrArguments.Value; } } if (Template == Template.TileWide) { HintLockDetailedStatus1 = attributes.PopAttributeValue(ATTR_BINDING_HINTLOCK1); HintLockDetailedStatus2 = attributes.PopAttributeValue(ATTR_BINDING_HINTLOCK2); HintLockDetailedStatus3 = attributes.PopAttributeValue(ATTR_BINDING_HINTLOCK3); } } // BaseUri is optional { XAttribute attrBaseUri = attributes.PopAttribute(ATTR_BINDING_BASEURI); if (attrBaseUri != null) { baseUri = attrBaseUri.Value; // Overwrite cascaded value if it was specified Uri uri; if (Uri.TryCreate(baseUri, UriKind.RelativeOrAbsolute, out uri)) { BaseUri = uri; } } } // AddImageQuery is optional { bool val; if (TryParse(result, attributes, ATTR_BINDING_ADDIMAGEQUERY, out val)) { addImageQuery = val; // Overwrite cascaded value if it was specified AddImageQuery = val; } } }