<|start_filename|>src/DotVVM.Samples.Common/ViewModels/ControlSamples/RouteLink/RouteLinkQueryParametersViewModel.cs<|end_filename|>
﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DotVVM.Framework.ViewModel;

namespace DotVVM.Samples.Common.ViewModels.ControlSamples.RouteLink
{
    public class RouteLinkQueryParametersViewModel : DotvvmViewModelBase
    {
        public int TestInteger { get; set; } = 5;
        public string TestString { get; set; } = "default";
    }
}



<|start_filename|>src/DotVVM.Framework/Compilation/Parser/TextRange.cs<|end_filename|>
using System.Diagnostics;

namespace DotVVM.Framework.Compilation.Parser
{
    [DebuggerDisplay("{DebuggerDisplay,nq}")]
    public class TextRange : ITextRange
    {
        public int StartPosition { get; private set; }
        public int Length { get; private set; }
        public int EndPosition => StartPosition + Length;

        private string DebuggerDisplay => $"[{StartPosition}..{EndPosition}), Length={Length}";

        public TextRange(int startPosition, int length)
        {
            StartPosition = startPosition;
            Length = length;
        }

        public static TextRange FromBounds(int start, int end)
            => new TextRange(start, end - start);
    }
}


<|start_filename|>src/DotVVM.Samples.Tests/Feature/AttachedPropertiesTests.cs<|end_filename|>
﻿using System;
using System.Collections.Generic;
using System.Linq;
using DotVVM.Samples.Tests.Base;
using DotVVM.Testing.Abstractions;
using OpenQA.Selenium;
using Riganti.Selenium.Core;
using Xunit;

namespace DotVVM.Samples.Tests.Feature
{
    public class AttachedPropertiesTests : AppSeleniumTest
    {
        public AttachedPropertiesTests(Xunit.Abstractions.ITestOutputHelper output) : base(output)
        {
        }

        [Fact]
        public void Feature_AttachedProperties_AttachedProperties()
        {
            RunInAllBrowsers(browser => {
                browser.NavigateToUrl(SamplesRouteUrls.FeatureSamples_AttachedProperties_AttachedProperties);

                var div = browser.Single(".div");
                AssertUI.Attribute(div, "bind:value", a => a == "test");
                AssertUI.Attribute(div, "bind:value2", a => a == "aaa");

                var txb = browser.Single("input[type=text]");
                txb.Clear().SendKeys("bbb").SendKeys(Keys.Tab);

                AssertUI.Attribute(div, "bind:value2", a => a == "bbb");
            });
        }
    }
}


<|start_filename|>src/DotVVM.Core/Controls/Options/ISortingOptions.cs<|end_filename|>
namespace DotVVM.Framework.Controls
{
    /// <summary>
    /// Represents settings for sorting.
    /// </summary>
    public interface ISortingOptions
    {
        /// <summary>
        /// Gets or sets whether the sort order should be descending.
        /// </summary>
        bool SortDescending { get; set; }

        /// <summary>
        /// Gets or sets the name of the property that is used for sorting. Null means the grid should not be sorted.
        /// </summary>
        string? SortExpression { get; set; }
    }
}


<|start_filename|>src/DotVVM.Samples.Common/ViewModels/ComplexSamples/EmptyDataTemplate/RepeaterGridViewViewModel.cs<|end_filename|>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DotVVM.Framework.ViewModel;

namespace DotVVM.Samples.BasicSamples.ViewModels.ComplexSamples.EmptyDataTemplate
{
    public class RepeaterGridViewViewModel : DotvvmViewModelBase
    {
        public List<Customer> Null => null;

        public List<Customer> Empty => new List<Customer>();

        public bool Visible { get; set; } = true;

        public List<Customer> NonEmpty => new List<Customer>()
        {
            new Customer() { FirstName = "Tomas" }
        };
    }

    public class Customer
    {
        public string FirstName { get; set; }
    }
}


<|start_filename|>src/DotVVM.Samples.Tests/Feature/ConditionalCssClass.cs<|end_filename|>
﻿using DotVVM.Samples.Tests.Base;
using DotVVM.Testing.Abstractions;
using Riganti.Selenium.Core;
using Xunit;
using Xunit.Abstractions;

namespace DotVVM.Samples.Tests.Feature
{
    public class ConditionalCssClass : AppSeleniumTest
    {
        [Fact]
        public void Feature_ConditionalCssClasses_ConditionalCssClasses()
        {
            RunInAllBrowsers(browser => {
                browser.NavigateToUrl(SamplesRouteUrls.FeatureSamples_ConditionalCssClasses_ConditionalCssClasses);

                AssertUI.HasNotClass(browser.First("div"), "italic");
                browser.First("input[type=button][value=\"Switch Italic\"]").Click();
                AssertUI.HasClass(browser.First("div"), "italic");

                AssertUI.HasNotClass(browser.First("div"), "bordered");
                browser.First("input[type=button][value=\"Switch Bordered\"]").Click();
                AssertUI.HasClass(browser.First("div"), "bordered");

                AssertUI.HasNotClass(browser.First("div"), "blue");
                browser.First("input[type=button][value=\"Switch Blue\"]").Click();
                AssertUI.HasClass(browser.First("div"), "blue");
            });
        }

        public ConditionalCssClass(ITestOutputHelper output) : base(output)
        {
        }
    }
}


<|start_filename|>src/DotVVM.Samples.Common/ViewModels/FeatureSamples/Validation/CustomValidationViewModel.cs<|end_filename|>
﻿using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
using DotVVM.Framework.ViewModel;
using DotVVM.Framework.ViewModel.Validation;

namespace DotVVM.Samples.Common.ViewModels.FeatureSamples.Validation
{
    public class CustomValidationViewModel : DotvvmViewModelBase
    {
        private readonly string[] allowedNames = new[]
        {
            "John",
            "James",
            "Ted"
        };

        public Customer Detail { get; set; } = new Customer { Name = "Ted", Age = 42 };

        public bool UseKnockoutNotation { get; set; }

        public override Task PreRender()
        {
            if (!allowedNames.Contains(Detail.Name))
            {
                if (UseKnockoutNotation)
                {
                    Context.ModelState.Errors.Add(
                        new ViewModelValidationError
                        {
                            ErrorMessage = "This error uses the Knockout JS notation.",
                            PropertyPath = "Detail().Name"
                        });
                }
                else
                {
                    this.AddModelError(t => t.Detail.Name, "This error uses C# extension method AddModelError");
                }
            }
            Context.FailOnInvalidModelState();
            return base.PreRender();
        }

        public class Customer
        {
            [Required]
            public int Age { get; set; }

            [Required]
            public string Name { get; set; }
        }
    }
}


<|start_filename|>src/DotVVM.Framework.Hosting.AspNetCore/Hosting/DotvvmHeaderCollection.cs<|end_filename|>
﻿using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;
using System;

namespace DotVVM.Framework.Hosting
{
    public class DotvvmHeaderCollection : IHeaderCollection
    {
        public DotvvmHeaderCollection(IHeaderDictionary originalHeaders)
        {
            OriginalHeaders = originalHeaders;
        }

        public IHeaderDictionary OriginalHeaders { get; }

        public string this[string key]
        {
            get { return OriginalHeaders[key]; }
            set { OriginalHeaders[key] = value; }
        }

        public void Append(string key, string value)
        {
            OriginalHeaders[key] = OriginalHeaders[key].Concat(new[] { value }).ToArray();
        }

        #region IDictionary bridge
        public IEnumerator<KeyValuePair<string, string[]>> GetEnumerator()
        {
            foreach (var item in OriginalHeaders)
            {
                yield return new KeyValuePair<string, string[]>(item.Key, item.Value.ToArray());
            }
        }

        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();

        public void Add(KeyValuePair<string, string[]> item)
        {
            OriginalHeaders.Add(ConvertKeyValuePair(item));
        }

        public void Clear()
        {
            OriginalHeaders.Clear();
        }

        public bool Contains(KeyValuePair<string, string[]> item)
        {
            return OriginalHeaders.Contains(ConvertKeyValuePair(item));
        }

        public void CopyTo(KeyValuePair<string, string[]>[] array, int arrayIndex)
        {
            throw new NotImplementedException();
        }

        public bool Remove(KeyValuePair<string, string[]> item)
        {
            return OriginalHeaders.Remove(ConvertKeyValuePair(item));
        }

        public int Count => OriginalHeaders.Count;

        public bool IsReadOnly => OriginalHeaders.IsReadOnly;
        public void Add(string key, string[] value)
        {
            OriginalHeaders.Add(key, new StringValues(value));
        }

        public bool ContainsKey(string key)
        {
            return OriginalHeaders.ContainsKey(key);
        }

        public bool Remove(string key)
        {
            return OriginalHeaders.Remove(key);
        }

        public bool TryGetValue(string key, out string[] value)
        {
            StringValues tmp;
            var result = OriginalHeaders.TryGetValue(key, out tmp);
            if (result) value = tmp.ToArray();
            else value = null;
            return result;
        }

        public ICollection<string> Keys => OriginalHeaders.Keys;

        public ICollection<string[]> Values
        {
            get { return OriginalHeaders.Values.Select(e => e.ToArray()).ToList(); }
        }

        string[] IDictionary<string, string[]>.this[string key]
        {
            get { return ((IDictionary<string, string[]>)OriginalHeaders)[key]; }
            set { ((IDictionary<string, string[]>)OriginalHeaders)[key] = value; }
        }

        protected static KeyValuePair<string, StringValues> ConvertKeyValuePair(KeyValuePair<string, string[]> toConvert) => 
            new KeyValuePair<string, StringValues>(toConvert.Key, new StringValues(toConvert.Value));
        #endregion
    }
}

<|start_filename|>src/DotVVM.Samples.Common/Views/FeatureSamples/MarkupControl/ComboBoxDataSourceBoundToStaticCollection.cs<|end_filename|>
﻿using System.Collections.Generic;
using System.Linq;
using DotVVM.Framework.Binding;
using DotVVM.Framework.Controls;
using DotVVM.Framework.Hosting;

namespace DotVVM.Samples.Common.Views.FeatureSamples.MarkupControl
{
    public class ComboBoxDataSourceBoundToStaticCollection : DotvvmMarkupControl
    {
        public List<Detail> DataSource
        {
            get { return (List<Detail>)GetValue(DataSourceProperty); }
            set { SetValue(DataSourceProperty, value); }
        }
        public static readonly DotvvmProperty DataSourceProperty
            = DotvvmProperty.Register<List<Detail>, ComboBoxDataSourceBoundToStaticCollection>(c => c.DataSource, null);

        public int SelectedValue
        {
            get { return (int)GetValue(SelectedValueProperty); }
            set { SetValue(SelectedValueProperty, value); }
        }
        public static readonly DotvvmProperty SelectedValueProperty
            = DotvvmProperty.Register<int, ComboBoxDataSourceBoundToStaticCollection>(c => c.SelectedValue, default(int));

        public Detail Item
        {
            get { return (Detail)GetValue(ItemProperty); }
            set { SetValue(ItemProperty, value); }
        }
        public static readonly DotvvmProperty ItemProperty
            = DotvvmProperty.Register<Detail, ComboBoxDataSourceBoundToStaticCollection>(c => c.Item);

        protected override void OnInit(IDotvvmRequestContext context)
        {
            base.OnInit(context);

            DataSource = Enumerable.Range(0, 3)
                .Select(x => new Detail {
                    Id = x,
                    InnerText = new Detail.InnerItem { Text = string.Format("Number {0}", x) }
                }).ToList();

            Item = new Detail { Id = 0, InnerText = new Detail.InnerItem { Text = "Default item" } };
        }

        public class Detail
        {
            public int Id { get; set; }

            public InnerItem InnerText { get; set; }

            public class InnerItem
            {
                public string Text { get; set; }
            }
        }
    }
}


<|start_filename|>src/DotVVM.Framework/ViewModel/Serialization/DefaultViewModelServerCache.cs<|end_filename|>
﻿using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using DotVVM.Framework.Hosting;
using DotVVM.Framework.Utils;
using Newtonsoft.Json.Bson;
using Newtonsoft.Json.Linq;

namespace DotVVM.Framework.ViewModel.Serialization
{
    public class DefaultViewModelServerCache : IViewModelServerCache
    {
        private readonly IViewModelServerStore viewModelStore;

        public DefaultViewModelServerCache(IViewModelServerStore viewModelStore)
        {
            this.viewModelStore = viewModelStore;
        }

        public string StoreViewModel(IDotvvmRequestContext context, JObject viewModelToken)
        {
            var cacheData = PackViewModel(viewModelToken);
            var hash = Convert.ToBase64String(SHA256.Create().ComputeHash(cacheData));
            viewModelStore.Store(hash, cacheData);
            return hash;
        }

        public JObject TryRestoreViewModel(IDotvvmRequestContext context, string viewModelCacheId, JObject viewModelDiffToken)
        {
            var cachedData = viewModelStore.Retrieve(viewModelCacheId);
            if (cachedData == null)
            {
                throw new DotvvmInterruptRequestExecutionException(InterruptReason.CachedViewModelMissing);
            }

            var result = UnpackViewModel(cachedData);
            JsonUtils.Patch(result, viewModelDiffToken);
            return result;
        }

        protected virtual byte[] PackViewModel(JObject viewModelToken)
        {
            using (var ms = new MemoryStream())
            using (var bsonWriter = new BsonDataWriter(ms))
            {
                viewModelToken.WriteTo(bsonWriter);
                bsonWriter.Flush();

                return ms.ToArray();
            }
        }

        protected virtual JObject UnpackViewModel(byte[] cachedData)
        {
            using (var ms = new MemoryStream(cachedData))
            using (var bsonReader = new BsonDataReader(ms))
            {
                return (JObject)JToken.ReadFrom(bsonReader);                
            }
        }
    }
}


<|start_filename|>src/DotVVM.Core/Controls/IBaseGridViewDataSet.cs<|end_filename|>
using System.Collections;
using System.Collections.Generic;

namespace DotVVM.Framework.Controls
{
    /// <summary>
    /// Defines the basic contract for DataSets.
    /// </summary>
    /// <typeparam name="T">The type of the <see cref="Items" /> elements.</typeparam>
    public interface IBaseGridViewDataSet<T> : IBaseGridViewDataSet
    {
        /// <summary>
        /// Gets the items for the current page.
        /// </summary>
        new IList<T> Items { get; }
    }

    /// <summary>
    /// Defines the basic contract for DataSets.
    /// </summary>
    public interface IBaseGridViewDataSet
    {
        /// <summary>
        /// Gets the items for the current page.
        /// </summary>
        IList Items { get; }
    }
}