Пример #1
0
        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);
        }
Пример #2
0
        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));
            }
        }
Пример #3
0
        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;
            }
        }
Пример #4
0
        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;
            }
        }
Пример #6
0
        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));
            }
        }
Пример #7
0
        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;
            }
        }
Пример #8
0
        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;
            }
        }
Пример #10
0
        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;
            }
        }
Пример #11
0
        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));
            }
        }
Пример #12
0
        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));
            }
        }
Пример #13
0
        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;
            }
        }
Пример #14
0
        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));
            }
        }
Пример #15
0
        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));
        }
Пример #17
0
        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;
            }
        }
Пример #18
0
        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;
                }
            }
        }