Skip to content
This repository was archived by the owner on Sep 2, 2021. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<ScrollViewer>
<StackPanel>
<TextBlock Text="BBCODEBLOCK" Style="{StaticResource Heading2}" Margin="0,0,0,8" />
<mui:BBCodeBlock BBCode="Simple rich text formatting using BBCode. Supporting [b]bold[/b], [i]italic[/i], [b][i]bold italic[/i][/b], [u]underline[/u], [color=#ff4500]colors[/color], [size=10]different[/size] [size=16]sizes[/size] and support for [url=http://xamlspy.com]navigable urls[/url].&#13;&#10;&#13;&#10;BBCode formatted text works great with MVVM.&#13;&#10;&#13;&#10;To learn more about link navigation see the [url=/Pages/Navigation.xaml|_top]navigation page[/url]." />
<mui:BBCodeBlock BBCodeQuoteBackground="{DynamicResource WindowBorder}" BBCode="Simple rich text formatting using BBCode. Supporting [b]bold[/b], [i]italic[/i], [b][i]bold italic[/i][/b], [u]underline[/u], [s]strikethrough[/s], [quote][b]John Muir:[/b] The power of imagination makes us infinite.[/quote], [\escaped], [color=#ff4500]colors[/color], [size=10]different[/size] [size=16]sizes[/size] and support for [url=http://xamlspy.com]navigable urls[/url].&#13;&#10;&#13;&#10;Ordered list:[ol][li]Item [b]one[/b][/li][li]Item [i]two[/i][/li][li]Item [color=#ff0045]three[/color][/li][/ol]&#13;&#10;Unordered list:[list][li]Item one[/li][li]Item two[/li][/list]&#13;&#10;BBCode formatted text works great with MVVM.&#13;&#10;&#13;&#10;To learn more about link navigation see the [url=/Pages/Navigation.xaml|_top]navigation page[/url]." />
</StackPanel>
</ScrollViewer>
</Grid>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace FirstFloor.ModernUI.App.Content
{
/// <summary>
/// Interaction logic for ControlsModernBBCodeBlock.xaml
/// </summary>
public partial class ControlsModernBBCodeBlock : UserControl
{
public ControlsModernBBCodeBlock()
{
InitializeComponent();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace FirstFloor.ModernUI.App.Content
{
/// <summary>
/// Interaction logic for ControlsModernBBCodeBlock.xaml
/// </summary>
public partial class ControlsModernBBCodeBlock : UserControl
{
public ControlsModernBBCodeBlock()
{
InitializeComponent();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mui="http://firstfloorsoftware.com/ModernUI"
xmlns:app="clr-namespace:FirstFloor.ModernUI.App"
Title="Modern UI for WPF Demo" IsTitleVisible="True"
Title="Modern UI for WPF Demo"
BBCodeTitle="[b]Modern UI[/b] for [b]WPF[/b] [i]Demo[/i]"
IsTitleVisible="True"
LogoData="F1 M 24.9015,43.0378L 25.0963,43.4298C 26.1685,49.5853 31.5377,54.2651 38,54.2651C 44.4623,54.2651 49.8315,49.5854 50.9037,43.4299L 51.0985,43.0379C 51.0985,40.7643 52.6921,39.2955 54.9656,39.2955C 56.9428,39.2955 58.1863,41.1792 58.5833,43.0379C 57.6384,52.7654 47.9756,61.75 38,61.75C 28.0244,61.75 18.3616,52.7654 17.4167,43.0378C 17.8137,41.1792 19.0572,39.2954 21.0344,39.2954C 23.3079,39.2954 24.9015,40.7643 24.9015,43.0378 Z M 26.7727,20.5833C 29.8731,20.5833 32.3864,23.0966 32.3864,26.197C 32.3864,29.2973 29.8731,31.8106 26.7727,31.8106C 23.6724,31.8106 21.1591,29.2973 21.1591,26.197C 21.1591,23.0966 23.6724,20.5833 26.7727,20.5833 Z M 49.2273,20.5833C 52.3276,20.5833 54.8409,23.0966 54.8409,26.197C 54.8409,29.2973 52.3276,31.8106 49.2273,31.8106C 46.127,31.8106 43.6136,29.2973 43.6136,26.197C 43.6136,23.0966 46.127,20.5833 49.2273,20.5833 Z"
LogoCommand="mui:LinkCommands.NavigateLink"
LogoCommandParameter="https://github.com/firstfloorsoftware/mui"
ContentSource="/Pages/Introduction.xaml"
Width="800" Height="700">

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,23 @@
</Grid.ColumnDefinitions>

<!-- title -->
<TextBlock Text="{TemplateBinding Title}" Margin="8,0" VerticalAlignment="Center" Style="{StaticResource ModernWindowTitle}"
DataContext="{TemplateBinding IsTitleVisible}"
Visibility="{Binding Converter={StaticResource BooleanToVisibilityConverter}}"/>
<controls:BBCodeBlock Margin="8,0" VerticalAlignment="Center">
<controls:BBCodeBlock.Style>
<Style TargetType="{x:Type controls:BBCodeBlock}">
<Setter Property="TextWrapping" Value="NoWrap"></Setter>
<Setter Property="Visibility" Value="{Binding IsTitleVisible, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource BooleanToVisibilityConverter}}" ></Setter>
<Setter Property="BBCode" Value="{Binding BBCodeTitle, RelativeSource={RelativeSource TemplatedParent}}" ></Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding BBCodeTitle, RelativeSource={RelativeSource TemplatedParent}}" Value="{x:Null}">
<DataTrigger.Setters>
<Setter Property="Text" Value="{Binding Title, RelativeSource={RelativeSource TemplatedParent}}"></Setter>
<Setter Property="FontWeight" Value="Bold"></Setter>
</DataTrigger.Setters>
</DataTrigger>
</Style.Triggers>
</Style>
</controls:BBCodeBlock.Style>
</controls:BBCodeBlock>

<!-- title links -->
<ItemsControl Grid.Column="1" ItemsSource="{TemplateBinding TitleLinks}" Margin="0,0,24,0" WindowChrome.IsHitTestVisibleInChrome="True">
Expand Down Expand Up @@ -91,11 +105,33 @@
</ItemsControl>

<!-- logo (visible only when LogoData is not null) -->
<Border Grid.Column="2" Background="{DynamicResource Accent}" Width="36" Height="36" Margin="8,0"
<Button Grid.Column="2" WindowChrome.IsHitTestVisibleInChrome="True" Width="36" Height="36" Margin="8,0"
DataContext="{TemplateBinding LogoData}"
Command="{Binding LogoCommand, RelativeSource={RelativeSource TemplatedParent}}"
CommandParameter="{Binding LogoCommandParameter, RelativeSource={RelativeSource TemplatedParent}}"
Visibility="{Binding Converter={StaticResource NullToVisibilityConverter}, ConverterParameter=inverse}">
<Path Data="{Binding}" Stretch="Fill" Fill="White" Width="24" Height="24" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
<Button.Style>
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{DynamicResource Accent}">
<Path Data="{Binding}" Stretch="Fill" Fill="White" Width="24" Height="24" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding LogoCommand, RelativeSource={RelativeSource TemplatedParent}}" Value="{x:Null}">
<Setter Property="IsEnabled" Value="False"/>
<Setter Property="Cursor" Value="{x:Null}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>

</Button>

<!-- window system buttons-->
<StackPanel Grid.Column="3" Orientation="Horizontal" VerticalAlignment="Top" WindowChrome.IsHitTestVisibleInChrome="True">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,17 @@ private Token Text()
return new Token(GetMark(), TokenText);
}

private Token EscapedTag()
{
Mark();
Consume();
while (LA(1) != '[' && LA(1) != char.MaxValue && !IsInRange(NewlineChars)) {
Consume();
}
var result = GetMark();
return new Token(result.Substring(0, 1) + result.Substring(2), TokenText);
}

private Token Attribute()
{
Match('=');
Expand Down Expand Up @@ -153,6 +164,9 @@ public override Token NextToken()

if (State == StateNormal) {
if (LA(1) == '[') {
if (LA(2) == '\\') {
return EscapedTag();
}
if (LA(2) == '/') {
return CloseTag();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ internal class BBCodeParser
private const string TagSize = "size";
private const string TagUnderline = "u";
private const string TagUrl = "url";
private const string TagStrikethrough = "s";
private const string TagQuote = "quote";
private const string TagList = "list";
private const string TagOrderedList = "ol";
private const string TagListItem = "li";

class ParseContext
{
Expand All @@ -36,8 +41,14 @@ public ParseContext(Span parent)
public FontWeight? FontWeight { get; set; }
public FontStyle? FontStyle { get; set; }
public Brush Foreground { get; set; }
public Brush Background { get; set; }
public TextDecorationCollection TextDecorations { get; set; }
public string NavigateUri { get; set; }
public bool IsList { get; set; }
public bool IsOrderedList { get; set; }
public int ListCounter { get; set; }
public bool IsListItem { get; set; }
public bool IsFirstListItem { get; set; }

/// <summary>
/// Creates a run reflecting the current context settings.
Expand All @@ -58,26 +69,33 @@ public Run CreateRun(string text)
if (this.Foreground != null) {
run.Foreground = this.Foreground;
}
if (this.Background != null)
{
run.Background = this.Background;
}
run.TextDecorations = this.TextDecorations;

return run;
}
}

private FrameworkElement source;
private Brush quoteBrush;

/// <summary>
/// Initializes a new instance of the <see cref="T:BBCodeParser"/> class.
/// </summary>
/// <param name="value">The value.</param>
/// <param name="source">The framework source element this parser operates in.</param>
public BBCodeParser(string value, FrameworkElement source)
/// <param name="quoteBrush">The Brush used for quoting</param>
public BBCodeParser(string value, FrameworkElement source, Brush quoteBrush = null)
: base(new BBCodeLexer(value))
{
if (source == null) {
throw new ArgumentNullException("source");
}
this.source = source;
this.quoteBrush = quoteBrush;
}

/// <summary>
Expand Down Expand Up @@ -131,6 +149,10 @@ private void ParseTag(string tag, bool start, ParseContext context)
else if (tag == TagUnderline) {
context.TextDecorations = start ? TextDecorations.Underline : null;
}
else if (tag == TagStrikethrough)
{
context.TextDecorations = start ? TextDecorations.Strikethrough : null;
}
else if (tag == TagUrl) {
if (start) {
Token token = LA(1);
Expand All @@ -143,20 +165,59 @@ private void ParseTag(string tag, bool start, ParseContext context)
context.NavigateUri = null;
}
}
else if (tag == TagQuote) {
if (start) {
context.Background = quoteBrush;
}
else {
context.Background = null;
}
}
else if (tag == TagList) {
context.IsList = start;
context.IsFirstListItem = true;
}
else if (tag == TagOrderedList) {
context.IsOrderedList = start;
context.ListCounter = 0;
context.IsFirstListItem = true;
}
else if (tag == TagListItem) {
context.IsListItem = start;
}
}

private void Parse(Span span)
{
var context = new ParseContext(span);

while (true) {
Token token = LA(1);
Consume();

if (token.TokenType == BBCodeLexer.TokenStartTag) {
var parent = span;
if (token.Value == TagListItem)
{
if (context.IsFirstListItem)
{
context.IsFirstListItem = false;
parent.Inlines.Add(new LineBreak());
}

parent.Inlines.Add(
new Run(string.Format("\u0020\u0020{0}\u0020\u0020",
context.IsOrderedList ? string.Format("{0}.", ++context.ListCounter) : "\u2022")));
}

ParseTag(token.Value, true, context);
}
else if (token.TokenType == BBCodeLexer.TokenEndTag) {
var parent = span;
if (context.IsListItem && token.Value == TagListItem)
{
parent.Inlines.Add(new LineBreak());
}
ParseTag(token.Value, false, context);
}
else if (token.TokenType == BBCodeLexer.TokenText) {
Expand All @@ -183,10 +244,20 @@ private void Parse(Span span)
link.TargetName = parameter;
}
parent = link;
if (context.Foreground != null) {
link.Foreground = context.Foreground;
}
span.Inlines.Add(parent);
}
var run = context.CreateRun(token.Value);
parent.Inlines.Add(run);

if (context.IsListItem) {
parent.Inlines.Add(context.CreateRun(token.Value));
}
else {
var run = context.CreateRun(token.Value);
parent.Inlines.Add(run);
}

}
else if (token.TokenType == BBCodeLexer.TokenLineBreak) {
span.Inlines.Add(new LineBreak());
Expand Down
22 changes: 21 additions & 1 deletion 1.0/FirstFloor.ModernUI/Shared/Windows/Controls/BBCodeBlock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ public class BBCodeBlock
/// Identifies the LinkNavigator dependency property.
/// </summary>
public static DependencyProperty LinkNavigatorProperty = DependencyProperty.Register("LinkNavigator", typeof(ILinkNavigator), typeof(BBCodeBlock), new PropertyMetadata(new DefaultLinkNavigator(), OnLinkNavigatorChanged));
/// <summary>
/// Identifies the BBCodeQuote dependency property.
/// </summary>
public static DependencyProperty BBCodeQuoteBackgroundProperty = DependencyProperty.Register("BBCodeQuoteBackground", typeof(Brush), typeof(BBCodeBlock), new PropertyMetadata(new PropertyChangedCallback(OnBBCodeQuoteBackgroundChanged)));

private bool dirty = false;

Expand All @@ -52,6 +56,11 @@ private static void OnBBCodeChanged(DependencyObject o, DependencyPropertyChange
((BBCodeBlock)o).UpdateDirty();
}

private static void OnBBCodeQuoteBackgroundChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
((BBCodeBlock)o).UpdateDirty();
}

private static void OnLinkNavigatorChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue == null) {
Expand Down Expand Up @@ -86,7 +95,7 @@ private void Update()
if (!string.IsNullOrWhiteSpace(bbcode)) {
Inline inline;
try {
var parser = new BBCodeParser(bbcode, this) {
var parser = new BBCodeParser(bbcode, this, BBCodeQuoteBackground) {
Commands = this.LinkNavigator.Commands
};
inline = parser.Parse();
Expand Down Expand Up @@ -131,5 +140,16 @@ public ILinkNavigator LinkNavigator
get { return (ILinkNavigator)GetValue(LinkNavigatorProperty); }
set { SetValue(LinkNavigatorProperty, value); }
}

/// <summary>
/// Gets or sets the BB quote background.
/// </summary>
/// <value>The BB code.</value>
public Brush BBCodeQuoteBackground
{
get { return (Brush)GetValue(BBCodeQuoteBackgroundProperty); }
set { SetValue(BBCodeQuoteBackgroundProperty, value); }
}

}
}
Loading