/// <summary> /// Creates a <see cref="FlexiCardsBlock"/> from a <see cref="ProxyFlexiCardsBlock"/>. /// </summary> /// <param name="proxyFencedBlock">The <see cref="ProxyFlexiCardsBlock"/> containing data for the <see cref="FlexiCardsBlock"/>.</param> /// <param name="blockProcessor">The <see cref="BlockProcessor"/> processing the <see cref="FlexiCardsBlock"/>.</param> /// <exception cref="ArgumentNullException">Thrown if <paramref name="proxyFencedBlock"/> is <c>null</c>.</exception> /// <exception cref="OptionsException">Thrown if an option is invalid.</exception> public override FlexiCardsBlock Create(ProxyFlexiCardsBlock proxyFencedBlock, BlockProcessor blockProcessor) { if (proxyFencedBlock == null) { throw new ArgumentNullException(nameof(proxyFencedBlock)); } IFlexiCardsBlockOptions flexiCardsBlockOptions = proxyFencedBlock.FlexiCardsBlockOptions; // Block name string blockName = ResolveBlockName(flexiCardsBlockOptions.BlockName); // Card size FlexiCardBlockSize cardSize = flexiCardsBlockOptions.CardSize; ValidateCardSize(cardSize); // Create block var flexiCardsBlock = new FlexiCardsBlock(blockName, cardSize, flexiCardsBlockOptions.Attributes, proxyFencedBlock.Parser) { Line = proxyFencedBlock.Line, Column = proxyFencedBlock.Column, Span = proxyFencedBlock.Span }; MoveChildren(proxyFencedBlock, flexiCardsBlock); return(flexiCardsBlock); }
/// <summary> /// Creates a <see cref="FlexiCardBlockOptions"/>. /// </summary> /// <param name="blockName"> /// <para>The <see cref="FlexiCardsBlock"/>'s <a href="https://en.bem.info/methodology/naming-convention/#block-name">BEM block name</a>.</para> /// <para>In compliance with <a href="https://en.bem.info">BEM methodology</a>, this value is the <see cref="FlexiCardsBlock"/>'s root element's class as well as the prefix for all other classes in the block.</para> /// <para>This value should contain only valid <a href="https://www.w3.org/TR/CSS21/syndata.html#characters">CSS class characters</a>.</para> /// <para>If this value is <c>null</c>, whitespace or an empty string, the <see cref="FlexiCardsBlock"/>'s block name is "flexi-cards".</para> /// <para>Defaults to "flexi-cards".</para> /// </param> /// <param name="cardSize"> /// <para>The display size of contained <see cref="FlexiCardBlock"/>s.</para> /// <para>A class attribute with value "<<paramref name="blockName"/>>_size_<<paramref name="cardSize"/>>" is added to the <see cref="FlexiCardsBlock"/>'s root element.</para> /// <para>Defaults to <see cref="FlexiCardBlockSize.Small"/>.</para> /// </param> /// <param name="defaultCardOptions"> /// <para>The default <see cref="IFlexiCardBlockOptions"/> for contained <see cref="FlexiCardBlock"/>s.</para> /// <para>If this value is <c>null</c>, a <see cref="FlexiCardBlockOptions"/> with default values is used.</para> /// <para>Defaults to <c>null</c>.</para> /// </param> /// <param name="attributes"> /// <para>The HTML attributes for the <see cref="FlexiCardsBlock"/>'s root element.</para> /// <para>Attribute names must be lowercase.</para> /// <para>If the class attribute is specified, its value is appended to default classes. This facilitates <a href="https://en.bem.info/methodology/quick-start/#mix">BEM mixes</a>.</para> /// <para>If this value is <c>null</c>, default classes are still assigned to the root element.</para> /// <para>Defaults to <c>null</c>.</para> /// </param> public FlexiCardsBlockOptions( string blockName = "flexi-cards", FlexiCardBlockSize cardSize = FlexiCardBlockSize.Small, IFlexiCardBlockOptions defaultCardOptions = default, IDictionary <string, string> attributes = default) : base(blockName, attributes) { CardSize = cardSize; DefaultCardOptions = defaultCardOptions ?? new FlexiCardBlockOptions(); }
/// <summary> /// Creates a <see cref="FlexiCardsBlock"/>. /// </summary> /// <param name="blockName">The <see cref="FlexiCardsBlock"/>'s BEM block name.</param> /// <param name="cardSize">The display size of contained <see cref="FlexiCardBlock"/>s.</param> /// <param name="attributes">HTML attributes for the <see cref="FlexiCardsBlock"/>'s root element.</param> /// <param name="blockParser">The <see cref="BlockParser"/> parsing the <see cref="FlexiCardsBlock"/>.</param> public FlexiCardsBlock(string blockName, FlexiCardBlockSize cardSize, ReadOnlyDictionary <string, string> attributes, BlockParser blockParser) : base(blockParser) { BlockName = blockName; CardSize = cardSize; Attributes = attributes; }
internal virtual void ValidateCardSize(FlexiCardBlockSize cardSize) { if (!Enum.IsDefined(typeof(FlexiCardBlockSize), cardSize)) { throw new OptionsException(nameof(IFlexiCardsBlockOptions.CardSize), string.Format(Strings.OptionsException_Shared_ValueMustBeAValidEnumValue, cardSize, nameof(FlexiCardBlockSize))); } }
public void ValidateCardSize_ThrowsOptionsExceptionIfCardSizeIsInvalid() { // Arrange FlexiCardsBlockFactory testSubject = CreateFlexiCardsBlockFactory(); const FlexiCardBlockSize dummyCardSize = (FlexiCardBlockSize)9; // Act and assert OptionsException result = Assert.Throws <OptionsException>(() => testSubject.ValidateCardSize(dummyCardSize)); Assert.Equal(string.Format(Strings.OptionsException_OptionsException_InvalidOption, nameof(IFlexiCardsBlockOptions.CardSize), string.Format(Strings.OptionsException_Shared_ValueMustBeAValidEnumValue, dummyCardSize, nameof(FlexiCardBlockSize))), result.Message); }
private static FlexiCardsBlock CreateFlexiCardsBlock(string blockName = default, FlexiCardBlockSize cardSize = default, ReadOnlyDictionary <string, string> attributes = default, BlockParser blockParser = default, List <FlexiCardBlock> children = default) { var result = new FlexiCardsBlock(blockName, cardSize, attributes, blockParser); if (children != null) { foreach (FlexiCardBlock child in children) { result.Add(child); } } return(result); }
public void Create_CreatesFlexiCardsBlock() { // Arrange var dummySpan = new SourceSpan(6, 19); const int dummyLine = 5; const int dummyColumn = 2; BlockParser dummyBlockParser = _mockRepository.Create <BlockParser>().Object; const string dummyBlockName = "dummyBlockName"; const string dummyResolvedBlockName = "dummyResolvedBlockName"; const FlexiCardBlockSize dummyCardSize = FlexiCardBlockSize.Medium; var dummyAttributes = new ReadOnlyDictionary <string, string>(new Dictionary <string, string>()); Mock <IFlexiCardsBlockOptions> mockFlexiCardsBlockOptions = _mockRepository.Create <IFlexiCardsBlockOptions>(); mockFlexiCardsBlockOptions.Setup(f => f.BlockName).Returns(dummyBlockName); mockFlexiCardsBlockOptions.Setup(f => f.CardSize).Returns(dummyCardSize); mockFlexiCardsBlockOptions.Setup(f => f.Attributes).Returns(dummyAttributes); ProxyFlexiCardsBlock dummyProxyFlexiCardsBlock = CreateProxyFlexiCardsBlock(mockFlexiCardsBlockOptions.Object, blockParser: dummyBlockParser); dummyProxyFlexiCardsBlock.Line = dummyLine; dummyProxyFlexiCardsBlock.Column = dummyColumn; dummyProxyFlexiCardsBlock.Span = dummySpan; Mock <FlexiCardsBlockFactory> mockTestSubject = CreateMockFlexiCardsBlockFactory(); mockTestSubject.CallBase = true; mockTestSubject.Setup(t => t.ResolveBlockName(dummyBlockName)).Returns(dummyResolvedBlockName); mockTestSubject.Setup(t => t.ValidateCardSize(dummyCardSize)); mockTestSubject.Protected().Setup("MoveChildren", dummyProxyFlexiCardsBlock, ItExpr.IsAny <FlexiCardsBlock>()); // Act FlexiCardsBlock result = mockTestSubject.Object.Create(dummyProxyFlexiCardsBlock, null); // Assert _mockRepository.VerifyAll(); Assert.Equal(dummyResolvedBlockName, result.BlockName); Assert.Equal(dummyCardSize, result.CardSize); Assert.Same(dummyAttributes, result.Attributes); Assert.Same(dummyBlockParser, result.Parser); Assert.Equal(dummyColumn, result.Column); Assert.Equal(dummyLine, result.Line); Assert.Equal(dummySpan, result.Span); }
public static IEnumerable <object[]> WriteBlock_WritesBlock_Data() { const string dummyBlockName = "dummyBlockName"; const FlexiCardBlockSize dummyCardSize = FlexiCardBlockSize.Medium; const string dummyAttributeKey1 = "dummyAttributeKey1"; const string dummyAttributeValue1 = "dummyAttributeValue1"; const string dummyAttributeKey2 = "dummyAttributeKey2"; const string dummyAttributeValue2 = "dummyAttributeValue2"; const string dummyClass = "dummyClass"; // Dummy title part const string dummyTitle = "dummyTitle"; var dummyTitleContainerInline = new ContainerInline(); dummyTitleContainerInline.AppendChild(new LiteralInline(dummyTitle)); var dummyTitlePartBlock = new PlainLeafBlock(null); dummyTitlePartBlock.Inline = dummyTitleContainerInline; // Dummy content part const string dummyContent = "dummyContent"; var dummyContentContainerInline = new ContainerInline(); dummyContentContainerInline.AppendChild(new LiteralInline(dummyContent)); var dummyContentParagraphBlock = new ParagraphBlock() { Inline = dummyContentContainerInline }; var dummyContentPartBlock = new PlainContainerBlock(null); dummyContentPartBlock.Add(dummyContentParagraphBlock); // Dummy footnote part const string dummyFootnote = "dummyFootnote"; var dummyFootnoteContainerInline = new ContainerInline(); dummyFootnoteContainerInline.AppendChild(new LiteralInline(dummyFootnote)); var dummyFootnotePartBlock = new PlainLeafBlock(null); dummyFootnotePartBlock.Inline = dummyFootnoteContainerInline; return(new object[][] { // BlockName is assigned as a class of the root element and all default classes are prepended with it new object[] { CreateFlexiCardsBlock(dummyBlockName), $@"<div class=""{dummyBlockName} {dummyBlockName}_size_small""> </div> " }, // CardSize is rendered in a modifier class of the root element new object[] { CreateFlexiCardsBlock(cardSize: dummyCardSize), $@"<div class="" _size_{dummyCardSize.ToString().ToLower()}""> </div> " }, // If attributes are specified, they're written new object[] { CreateFlexiCardsBlock(attributes: new ReadOnlyDictionary <string, string>(new Dictionary <string, string> { { dummyAttributeKey1, dummyAttributeValue1 }, { dummyAttributeKey2, dummyAttributeValue2 } })), $@"<div class="" _size_small"" {dummyAttributeKey1}=""{dummyAttributeValue1}"" {dummyAttributeKey2}=""{dummyAttributeValue2}""> </div> " }, // If classes are specified, they're appended to default classes new object[] { CreateFlexiCardsBlock(attributes: new ReadOnlyDictionary <string, string>(new Dictionary <string, string> { { "class", dummyClass } })), $@"<div class="" _size_small {dummyClass}""> </div> " }, // Child FlexiCardBlocks are rendered new object[] { CreateFlexiCardsBlock(children: new List <FlexiCardBlock> { CreateFlexiCardBlock(titlePart: dummyTitlePartBlock, contentPart: dummyContentPartBlock, footnotePart: dummyFootnotePartBlock) }), $@"<div class="" _size_small""> <div class=""__card __card_not-link __card_no-background-icon""> <p class=""__card-title"">{dummyTitle}</p> <div class=""__card-content""> <p>{dummyContent}</p> </div> <p class=""__card-footnote"">{dummyFootnote}</p> </div> </div> " } }); }
public static IEnumerable <object[]> FlexiCardsBlockOptions_CanBePopulated_Data() { const string dummyBlockName = "dummyBlockName"; const FlexiCardBlockSize dummyCardSize = FlexiCardBlockSize.Medium; const string dummyUrl = "dummyUrl"; const string dummyBackgroundIcon = "dummyBackgroundIcon"; const string dummyAttribute1 = "dummyAttribute1"; const string dummyAttributeValue1 = "dummyAttributeValue1"; var dummyCardsAttributes1 = new Dictionary <string, string> { { dummyAttribute1, dummyAttributeValue1 } }; var dummyCardAttributes1 = new Dictionary <string, string> { { dummyAttribute1, dummyAttributeValue1 } }; const string dummyAttribute2 = "dummyAttribute2"; const string dummyAttributeValue2 = "dummyAttributeValue2"; var dummyCardsAttributes2 = new Dictionary <string, string> { { dummyAttribute2, dummyAttributeValue2 } }; return(new object[][] { // Each new value should overwrite its corresponding existing value new object[] { new FlexiCardsBlockOptions(), new FlexiCardsBlockOptions(dummyBlockName, dummyCardSize, new FlexiCardBlockOptions(dummyUrl, dummyBackgroundIcon, dummyCardAttributes1), dummyCardsAttributes1), $@"{{ ""{nameof(FlexiCardsBlockOptions.BlockName)}"": ""{dummyBlockName}"", ""{nameof(FlexiCardsBlockOptions.CardSize)}"": ""{dummyCardSize}"", ""{nameof(FlexiCardsBlockOptions.DefaultCardOptions)}"": {{ ""{nameof(FlexiCardBlockOptions.Url)}"": ""{dummyUrl}"", ""{nameof(FlexiCardBlockOptions.BackgroundIcon)}"": ""{dummyBackgroundIcon}"", ""{nameof(FlexiCardBlockOptions.Attributes)}"": {{ ""{dummyAttribute1}"": ""{dummyAttributeValue1}"" }} }}, ""{nameof(FlexiCardsBlockOptions.Attributes)}"": {{ ""{dummyAttribute1}"": ""{dummyAttributeValue1}"" }} }}" }, // Existing values should not be overwritten if no corresponding new value new object[] { new FlexiCardsBlockOptions(dummyBlockName), new FlexiCardsBlockOptions(dummyBlockName, dummyCardSize), // Block name should stay the same $@"{{ ""{nameof(FlexiCardsBlockOptions.CardSize)}"": ""{dummyCardSize}"" }}" }, // Populating FlexiCardsBlockOptions with an existing attributes collection should replace the entire collection new object[] { new FlexiCardsBlockOptions(attributes: dummyCardsAttributes1), new FlexiCardsBlockOptions(attributes: dummyCardsAttributes2), $@"{{ ""{nameof(FlexiCardsBlockOptions.Attributes)}"": {{ ""{dummyAttribute2}"": ""{dummyAttributeValue2}"" }} }}" } }); }