From ecdf7569db7a171e8acb3c85bbb64750dfafc18e Mon Sep 17 00:00:00 2001 From: Thomas Hounsell Date: Mon, 13 Jun 2016 22:43:26 +0100 Subject: [PATCH] Begin developing new UI --- BuildFeed/App_Start/BundleConfig.cs | 20 - BuildFeed/BuildFeed.csproj | 60 +- BuildFeed/Code/DisplayHelpers.cs | 63 +- BuildFeed/Code/Options/Locale.cs | 48 + BuildFeed/Code/Options/Theme.cs | 30 + BuildFeed/Code/SiteLocale.cs | 49 - BuildFeed/Controllers/apiController.cs | 3 +- BuildFeed/Controllers/frontController.cs | 4 +- BuildFeed/Controllers/supportController.cs | 76 +- BuildFeed/Global.asax.cs | 2 - BuildFeed/Local/Common.Designer.cs | 36 + BuildFeed/Local/Common.resx | 12 + BuildFeed/Scripts/Chart.js | 3477 ----------------- BuildFeed/Scripts/Chart.min.js | 11 - BuildFeed/Scripts/_references.js | 4 - BuildFeed/Scripts/bfs.js | 70 +- BuildFeed/Scripts/bfs.js.map | 1 + BuildFeed/Scripts/bfs.min.js | 1 + BuildFeed/Scripts/bfs.ts | 35 + BuildFeed/Scripts/excanvas.compiled.js | 35 - BuildFeed/Scripts/excanvas.js | 924 ----- BuildFeed/Scripts/jsrender.js | 1712 -------- BuildFeed/Scripts/jsrender.min.js | 6 - BuildFeed/Scripts/jsrender.min.js.map | 8 - BuildFeed/Views/Web.config | 1 - BuildFeed/Views/front/index.cshtml | 25 +- BuildFeed/Views/front/viewBuild.cshtml | 5 +- BuildFeed/Views/front/viewGroup.cshtml | 1 + BuildFeed/Views/front/viewLab.cshtml | 1 + BuildFeed/Views/front/viewSource.cshtml | 1 + BuildFeed/Views/front/viewVersion.cshtml | 1 + BuildFeed/Views/front/viewYear.cshtml | 3 +- .../DisplayTemplates/Enumeration.cshtml | 3 +- BuildFeed/Views/shared/_default.cshtml | 252 +- BuildFeed/Web.config | 3 +- BuildFeed/bundleconfig.json | 10 +- BuildFeed/compilerconfig.json | 14 + BuildFeed/compilerconfig.json.defaults | 49 + BuildFeed/content/dark.css | 34 + BuildFeed/content/dark.min.css | 1 + BuildFeed/content/dark.scss | 63 + BuildFeed/content/default.css | 119 + BuildFeed/content/default.min.css | 1 + BuildFeed/content/default.scss | 200 + BuildFeed/content/rtl.css | 42 +- BuildFeed/content/rtl.min.css | 2 +- BuildFeed/content/rtl.scss | 2 + BuildFeed/content/style.css | 261 -- BuildFeed/content/style.min.css | 1 - BuildFeed/packages.config | 4 - 50 files changed, 912 insertions(+), 6874 deletions(-) delete mode 100644 BuildFeed/App_Start/BundleConfig.cs create mode 100644 BuildFeed/Code/Options/Locale.cs create mode 100644 BuildFeed/Code/Options/Theme.cs delete mode 100644 BuildFeed/Code/SiteLocale.cs delete mode 100644 BuildFeed/Scripts/Chart.js delete mode 100644 BuildFeed/Scripts/Chart.min.js create mode 100644 BuildFeed/Scripts/bfs.js.map create mode 100644 BuildFeed/Scripts/bfs.min.js create mode 100644 BuildFeed/Scripts/bfs.ts delete mode 100644 BuildFeed/Scripts/excanvas.compiled.js delete mode 100644 BuildFeed/Scripts/excanvas.js delete mode 100644 BuildFeed/Scripts/jsrender.js delete mode 100644 BuildFeed/Scripts/jsrender.min.js delete mode 100644 BuildFeed/Scripts/jsrender.min.js.map create mode 100644 BuildFeed/compilerconfig.json create mode 100644 BuildFeed/compilerconfig.json.defaults create mode 100644 BuildFeed/content/dark.css create mode 100644 BuildFeed/content/dark.min.css create mode 100644 BuildFeed/content/dark.scss create mode 100644 BuildFeed/content/default.css create mode 100644 BuildFeed/content/default.min.css create mode 100644 BuildFeed/content/default.scss create mode 100644 BuildFeed/content/rtl.scss delete mode 100644 BuildFeed/content/style.css delete mode 100644 BuildFeed/content/style.min.css diff --git a/BuildFeed/App_Start/BundleConfig.cs b/BuildFeed/App_Start/BundleConfig.cs deleted file mode 100644 index 30ac48c..0000000 --- a/BuildFeed/App_Start/BundleConfig.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Web.Optimization; - -namespace BuildFeed -{ - public class BundleConfig - { - // For more information on bundling, visit http://go.microsoft.com/fwlink/?LinkId=301862 - public static void RegisterBundles(BundleCollection bundles) - { - bundles.Add(new ScriptBundle("~/bundles/jquery").Include( - "~/Scripts/jquery-{version}.js")); - - bundles.Add(new ScriptBundle("~/bundles/jsrender").Include( - "~/Scripts/jsrender*")); - - bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include( - "~/Scripts/jquery.validate*")); - } - } -} \ No newline at end of file diff --git a/BuildFeed/BuildFeed.csproj b/BuildFeed/BuildFeed.csproj index 6a96a49..056d1c6 100644 --- a/BuildFeed/BuildFeed.csproj +++ b/BuildFeed/BuildFeed.csproj @@ -48,10 +48,6 @@ 4 - - False - ..\packages\Antlr.3.5.0.2\lib\Antlr3.Runtime.dll - ..\packages\HtmlAgilityPack.1.4.9\lib\Net45\HtmlAgilityPack.dll True @@ -171,14 +167,7 @@ - - ..\packages\Microsoft.AspNet.Web.Optimization.1.1.3\lib\net40\System.Web.Optimization.dll - - - False - ..\packages\WebGrease.1.6.0\lib\WebGrease.dll - ..\packages\xwebrss.1.2.1.130\lib\net40-client\X.Web.RSS.dll @@ -190,15 +179,15 @@ - - + + @@ -781,22 +770,32 @@ + + dark.scss + + + dark.css + + + default.scss + + + default.css + + + rtl.scss + rtl.css - - style.css - - - @@ -810,12 +809,26 @@ - - + + + + compilerconfig.json + + + + + bfs.ts + + + bfs.ts + + + bfs.js + @@ -890,11 +903,6 @@ - - - - - Designer @@ -918,7 +926,6 @@ - Designer @@ -958,6 +965,7 @@ + diff --git a/BuildFeed/Code/DisplayHelpers.cs b/BuildFeed/Code/DisplayHelpers.cs index f05c701..d453858 100644 --- a/BuildFeed/Code/DisplayHelpers.cs +++ b/BuildFeed/Code/DisplayHelpers.cs @@ -2,19 +2,64 @@ using System.ComponentModel.DataAnnotations; using System.Globalization; using System.Linq; +using System.Text; +using System.Web; +using System.Web.Mvc; -namespace BuildFeed +namespace BuildFeed.Code { - public static class DisplayHelpers + public static class MvcExtensions { + public static IHtmlString CheckboxListForEnum(this HtmlHelper html, string id, T currentItem) where T : struct + { + StringBuilder sb = new StringBuilder(); + + foreach (T enumItem in Enum.GetValues(typeof(T)).Cast()) + { + long enumValue = Convert.ToInt64(enumItem); + long currentValue = Convert.ToInt64(currentItem); + + if (enumValue == 0) + { + // skip 0-valued bitflags, they're for display only. + continue; + } + + TagBuilder wrapper = new TagBuilder("div"); + wrapper.Attributes.Add("class", "checkbox"); + + TagBuilder label = new TagBuilder("label"); + + TagBuilder input = new TagBuilder("input"); + if ((enumValue & currentValue) != 0) + { + input.MergeAttribute("checked", "checked"); + } + input.MergeAttribute("type", "checkbox"); + input.MergeAttribute("value", enumValue.ToString()); + input.MergeAttribute("name", id); + + label.InnerHtml = input.ToString(TagRenderMode.SelfClosing); + label.InnerHtml += GetDisplayTextForEnum(enumItem); + + wrapper.InnerHtml = label.ToString(TagRenderMode.Normal); + + sb.Append(wrapper.ToString(TagRenderMode.Normal)); + } + + return new HtmlString(sb.ToString()); + } + public static string GetDisplayTextForEnum(object o) { - string result = null as string; - DisplayAttribute display = o.GetType() - .GetMember(o.ToString()).First() - .GetCustomAttributes(false) - .OfType() - .LastOrDefault(); + string result = null; + DisplayAttribute display = + o.GetType() + .GetMember(o.ToString()) + .First() + .GetCustomAttributes(false) + .OfType() + .LastOrDefault(); if (display != null) { @@ -28,7 +73,7 @@ public static string ToLongDateWithoutDay(this DateTime dt) { string s = CultureInfo.CurrentUICulture.DateTimeFormat.LongDatePattern; s = s.Replace("dddd", "").Replace("ddd", ""); - s = s.Trim(new char[] { ' ', ',' }); + s = s.Trim(' ', ','); return dt.ToString(s); } diff --git a/BuildFeed/Code/Options/Locale.cs b/BuildFeed/Code/Options/Locale.cs new file mode 100644 index 0000000..f63f3e3 --- /dev/null +++ b/BuildFeed/Code/Options/Locale.cs @@ -0,0 +1,48 @@ +using System.Globalization; + +namespace BuildFeed.Code.Options +{ + public class Locale + { + public static readonly Locale[] AvailableLocales = { + new Locale("ar"), + new Locale("bn"), + new Locale("cs"), + new Locale("de"), + new Locale("el"), + new Locale("en"), + new Locale("es"), + new Locale("fi"), + new Locale("fr"), + new Locale("he"), + new Locale("hr"), + new Locale("id"), + new Locale("it"), + new Locale("ko"), + new Locale("nl"), + new Locale("pl"), + new Locale("pt"), + new Locale("pt-br"), + new Locale("qps-ploc"), + new Locale("ro"), + new Locale("ru"), + new Locale("sk"), + new Locale("sl"), + new Locale("sv"), + new Locale("tr"), + new Locale("zh-cn"), + new Locale("zh-tw") + }; + + public string DisplayName => Info.NativeName; + + public CultureInfo Info { get; set; } + public string LocaleId { get; set; } + + public Locale(string localeId) + { + LocaleId = localeId; + Info = CultureInfo.GetCultureInfo(localeId); + } + } +} \ No newline at end of file diff --git a/BuildFeed/Code/Options/Theme.cs b/BuildFeed/Code/Options/Theme.cs new file mode 100644 index 0000000..27ef3f0 --- /dev/null +++ b/BuildFeed/Code/Options/Theme.cs @@ -0,0 +1,30 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using BuildFeed.Local; + +namespace BuildFeed.Code.Options +{ + public class Theme + { + public static Theme[] AvailableThemes = (from st in Enum.GetValues(typeof(SiteTheme)).Cast() + select new Theme(st)).ToArray(); + + private readonly SiteTheme _siteTheme; + + public string CookieValue => _siteTheme.ToString(); + public string CssPath => $"~/content/{_siteTheme.ToString().ToLower()}.min.css"; + public string DisplayName => MvcExtensions.GetDisplayTextForEnum(_siteTheme); + + public Theme(SiteTheme st) { _siteTheme = st; } + } + + public enum SiteTheme + { + [Display(ResourceType = typeof(Common), Name = nameof(Common.ThemeLight))] + Light = 0, + + [Display(ResourceType = typeof(Common), Name = nameof(Common.ThemeDark))] + Dark + } +} \ No newline at end of file diff --git a/BuildFeed/Code/SiteLocale.cs b/BuildFeed/Code/SiteLocale.cs deleted file mode 100644 index e51458b..0000000 --- a/BuildFeed/Code/SiteLocale.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System.Globalization; - -namespace BuildFeed.Code -{ - public class SiteLocale - { - public static readonly SiteLocale[] AvailableLocales = new SiteLocale[] - { - new SiteLocale("ar"), - new SiteLocale("bn"), - new SiteLocale("cs"), - new SiteLocale("de"), - new SiteLocale("el"), - new SiteLocale("en"), - new SiteLocale("es"), - new SiteLocale("fi"), - new SiteLocale("fr"), - new SiteLocale("he"), - new SiteLocale("hr"), - new SiteLocale("id"), - new SiteLocale("it"), - new SiteLocale("ko"), - new SiteLocale("nl"), - new SiteLocale("pl"), - new SiteLocale("pt"), - new SiteLocale("pt-br"), - new SiteLocale("qps-ploc"), - new SiteLocale("ro"), - new SiteLocale("ru"), - new SiteLocale("sk"), - new SiteLocale("sl"), - new SiteLocale("sv"), - new SiteLocale("tr"), - new SiteLocale("zh-cn"), - new SiteLocale("zh-tw") - }; - - public CultureInfo Info { get; set; } - public string LocaleId { get; set; } - - public string DisplayName => Info.NativeName; - - public SiteLocale(string localeId) - { - LocaleId = localeId; - Info = CultureInfo.GetCultureInfo(localeId); - } - } -} \ No newline at end of file diff --git a/BuildFeed/Controllers/apiController.cs b/BuildFeed/Controllers/apiController.cs index e9457a6..26e956a 100644 --- a/BuildFeed/Controllers/apiController.cs +++ b/BuildFeed/Controllers/apiController.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using System.Web.Http; using System.Web.Security; +using BuildFeed.Code; namespace BuildFeed.Controllers { @@ -100,7 +101,7 @@ public async Task> GetSearchResult(string id) List results = new List(); - var sourceResults = from s in Enum.GetValues(typeof(TypeOfSource)).Cast().Select(s => new { Text = DisplayHelpers.GetDisplayTextForEnum(s), Value = s }) + var sourceResults = from s in Enum.GetValues(typeof(TypeOfSource)).Cast().Select(s => new { Text = MvcExtensions.GetDisplayTextForEnum(s), Value = s }) where s.Text.ToLower().Contains(id.ToLower()) orderby s.Text.ToLower().IndexOf(id.ToLower(), StringComparison.Ordinal) ascending select new SearchResult() diff --git a/BuildFeed/Controllers/frontController.cs b/BuildFeed/Controllers/frontController.cs index 8988a88..21155a1 100644 --- a/BuildFeed/Controllers/frontController.cs +++ b/BuildFeed/Controllers/frontController.cs @@ -142,7 +142,7 @@ public async Task TwitterCard(Guid id) gp.AddString("BUILDFEED", new FontFamily("Segoe UI"), (int) FontStyle.Bold, 32, new Point(40, 32), StringFormat.GenericTypographic); - gp.AddString($"{DisplayHelpers.GetDisplayTextForEnum(b.Family)} (WinNT {b.MajorVersion}.{b.MinorVersion})", + gp.AddString($"{MvcExtensions.GetDisplayTextForEnum(b.Family)} (WinNT {b.MajorVersion}.{b.MinorVersion})", new FontFamily("Segoe UI"), 0, 48, new Point(40, 80), StringFormat.GenericTypographic); gp.AddString(b.Number.ToString(), new FontFamily("Segoe UI Light"), 0, 280, new Point(32, 96), StringFormat.GenericTypographic); @@ -222,7 +222,7 @@ public async Task ViewSourcePage(TypeOfSource source, int page) Type = MetaType.Source, Value = source.ToString() }); - ViewBag.ItemId = DisplayHelpers.GetDisplayTextForEnum(source); + ViewBag.ItemId = MvcExtensions.GetDisplayTextForEnum(source); var builds = await _bModel.SelectSource(source, PageSize, (page - 1) * PageSize); diff --git a/BuildFeed/Controllers/supportController.cs b/BuildFeed/Controllers/supportController.cs index 7ef4bd1..9f1e45a 100644 --- a/BuildFeed/Controllers/supportController.cs +++ b/BuildFeed/Controllers/supportController.cs @@ -24,10 +24,7 @@ public SupportController() : base() } [Route("login/")] - public ActionResult Login() - { - return View(); - } + public ActionResult Login() => View(); [HttpPost, Route("login/")] public ActionResult Login(LoginUser ru) @@ -226,7 +223,7 @@ into bv orderby bv.Key select new SitemapPagedAction() { - Name = DisplayHelpers.GetDisplayTextForEnum(bv.Key), + Name = MvcExtensions.GetDisplayTextForEnum(bv.Key), UrlParams = new RouteValueDictionary(new { controller = "Front", @@ -320,75 +317,6 @@ public async Task XmlSitemap() return new EmptyResult(); } - [Route("statistics/")] -#if !DEBUG -// [OutputCache(Duration = 3600, VaryByParam = "none", VaryByCustom = "userName")] -#endif - public async Task Stats() - { - var builds = await _bModel.Select(); - - List additions = new List(); - var rawAdditions = (from b in builds - where b.Added > DateTime.Now.AddYears(-1) - group b by new - { - Year = b.Added.Year, - Week = Convert.ToInt32(Math.Floor(b.Added.DayOfYear / 7m)) - } into bm - select new MonthCount() - { - Month = bm.Key.Week, - Year = bm.Key.Year, - Count = bm.Count() - }).ToArray(); - - for (int i = -52; i <= 0; i++) - { - DateTime dt = DateTime.Now.AddDays(i * 7); - additions.Add(new MonthCount() - { - Month = Convert.ToInt32(Math.Floor(dt.DayOfYear / 7m)), - Year = dt.Year, - Count = rawAdditions.SingleOrDefault(a => a.Month == Convert.ToInt32(Math.Floor(dt.DayOfYear / 7m)) && a.Year == dt.Year).Count - }); - } - - List compiles = new List(); - double logScale = 1.0 / Math.E; - var rawCompiles = from b in builds - where b.BuildTime.HasValue - group b by new - { - Year = b.BuildTime.Value.Year, - Month = Convert.ToInt32(Math.Floor((b.BuildTime.Value.Month - 0.1m) / 3m) * 3) + 1 - } into bm - select new MonthCount() - { - Month = bm.Key.Month, - Year = bm.Key.Year, - Count = Math.Pow(Convert.ToDouble(bm.Count()), logScale) - }; - - - var rawLabCounts = from bl in (from b in builds - where !string.IsNullOrEmpty(b.Lab) - group b by b.Lab into bl - select bl) - where bl.Count() > 99 - orderby bl.Count() descending - select new Tuple(bl.Key, bl.Count()); - - StatsPage m = new StatsPage() - { - AdditionsByMonth = additions, - CompilesByMonth = rawCompiles.OrderBy(r => r.Year).ThenBy(r => r.Month), - BuildsByLab = rawLabCounts - }; - - return View(m); - } - [Route("credits/")] public ActionResult Credits() => View(); } diff --git a/BuildFeed/Global.asax.cs b/BuildFeed/Global.asax.cs index 0e8fb6f..3cc9c3b 100644 --- a/BuildFeed/Global.asax.cs +++ b/BuildFeed/Global.asax.cs @@ -2,7 +2,6 @@ using System.Globalization; using System.Web; using System.Web.Mvc; -using System.Web.Optimization; using System.Web.Routing; namespace BuildFeed @@ -21,7 +20,6 @@ protected void Application_Start() AreaRegistration.RegisterAllAreas(); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); - BundleConfig.RegisterBundles(BundleTable.Bundles); DateTimeModelBinder db = new DateTimeModelBinder(); diff --git a/BuildFeed/Local/Common.Designer.cs b/BuildFeed/Local/Common.Designer.cs index d7ece2e..efdacbe 100644 --- a/BuildFeed/Local/Common.Designer.cs +++ b/BuildFeed/Local/Common.Designer.cs @@ -132,6 +132,24 @@ public static string LogOut { } } + /// + /// Looks up a localized string similar to Language. + /// + public static string NavigationLanguage { + get { + return ResourceManager.GetString("NavigationLanguage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Theme. + /// + public static string NavigationTheme { + get { + return ResourceManager.GetString("NavigationTheme", resourceCulture); + } + } + /// /// Looks up a localized string similar to | Page {0}. /// @@ -267,6 +285,24 @@ public static string Statistics { } } + /// + /// Looks up a localized string similar to Dark. + /// + public static string ThemeDark { + get { + return ResourceManager.GetString("ThemeDark", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Light. + /// + public static string ThemeLight { + get { + return ResourceManager.GetString("ThemeLight", resourceCulture); + } + } + /// /// Looks up a localized string similar to Toggle navigation. /// diff --git a/BuildFeed/Local/Common.resx b/BuildFeed/Local/Common.resx index 21e5e67..3405a4d 100644 --- a/BuildFeed/Local/Common.resx +++ b/BuildFeed/Local/Common.resx @@ -195,4 +195,16 @@ type to search... + + Dark + + + Light + + + Theme + + + Language + \ No newline at end of file diff --git a/BuildFeed/Scripts/Chart.js b/BuildFeed/Scripts/Chart.js deleted file mode 100644 index c264262..0000000 --- a/BuildFeed/Scripts/Chart.js +++ /dev/null @@ -1,3477 +0,0 @@ -/*! - * Chart.js - * http://chartjs.org/ - * Version: 1.0.2 - * - * Copyright 2015 Nick Downie - * Released under the MIT license - * https://github.com/nnnick/Chart.js/blob/master/LICENSE.md - */ - - -(function(){ - - "use strict"; - - //Declare root variable - window in the browser, global on the server - var root = this, - previous = root.Chart; - - //Occupy the global variable of Chart, and create a simple base class - var Chart = function(context){ - var chart = this; - this.canvas = context.canvas; - - this.ctx = context; - - //Variables global to the chart - var computeDimension = function(element,dimension) - { - if (element['offset'+dimension]) - { - return element['offset'+dimension]; - } - else - { - return document.defaultView.getComputedStyle(element).getPropertyValue(dimension); - } - } - - var width = this.width = computeDimension(context.canvas,'Width'); - var height = this.height = computeDimension(context.canvas,'Height'); - - // Firefox requires this to work correctly - context.canvas.width = width; - context.canvas.height = height; - - var width = this.width = context.canvas.width; - var height = this.height = context.canvas.height; - this.aspectRatio = this.width / this.height; - //High pixel density displays - multiply the size of the canvas height/width by the device pixel ratio, then scale. - helpers.retinaScale(this); - - return this; - }; - //Globally expose the defaults to allow for user updating/changing - Chart.defaults = { - global: { - // Boolean - Whether to animate the chart - animation: true, - - // Number - Number of animation steps - animationSteps: 60, - - // String - Animation easing effect - animationEasing: "easeOutQuart", - - // Boolean - If we should show the scale at all - showScale: true, - - // Boolean - If we want to override with a hard coded scale - scaleOverride: false, - - // ** Required if scaleOverride is true ** - // Number - The number of steps in a hard coded scale - scaleSteps: null, - // Number - The value jump in the hard coded scale - scaleStepWidth: null, - // Number - The scale starting value - scaleStartValue: null, - - // String - Colour of the scale line - scaleLineColor: "rgba(0,0,0,.1)", - - // Number - Pixel width of the scale line - scaleLineWidth: 1, - - // Boolean - Whether to show labels on the scale - scaleShowLabels: true, - - // Interpolated JS string - can access value - scaleLabel: "<%=value%>", - - // Boolean - Whether the scale should stick to integers, and not show any floats even if drawing space is there - scaleIntegersOnly: true, - - // Boolean - Whether the scale should start at zero, or an order of magnitude down from the lowest value - scaleBeginAtZero: false, - - // String - Scale label font declaration for the scale label - scaleFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif", - - // Number - Scale label font size in pixels - scaleFontSize: 12, - - // String - Scale label font weight style - scaleFontStyle: "normal", - - // String - Scale label font colour - scaleFontColor: "#666", - - // Boolean - whether or not the chart should be responsive and resize when the browser does. - responsive: false, - - // Boolean - whether to maintain the starting aspect ratio or not when responsive, if set to false, will take up entire container - maintainAspectRatio: true, - - // Boolean - Determines whether to draw tooltips on the canvas or not - attaches events to touchmove & mousemove - showTooltips: true, - - // Boolean - Determines whether to draw built-in tooltip or call custom tooltip function - customTooltips: false, - - // Array - Array of string names to attach tooltip events - tooltipEvents: ["mousemove", "touchstart", "touchmove", "mouseout"], - - // String - Tooltip background colour - tooltipFillColor: "rgba(0,0,0,0.8)", - - // String - Tooltip label font declaration for the scale label - tooltipFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif", - - // Number - Tooltip label font size in pixels - tooltipFontSize: 14, - - // String - Tooltip font weight style - tooltipFontStyle: "normal", - - // String - Tooltip label font colour - tooltipFontColor: "#fff", - - // String - Tooltip title font declaration for the scale label - tooltipTitleFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif", - - // Number - Tooltip title font size in pixels - tooltipTitleFontSize: 14, - - // String - Tooltip title font weight style - tooltipTitleFontStyle: "bold", - - // String - Tooltip title font colour - tooltipTitleFontColor: "#fff", - - // Number - pixel width of padding around tooltip text - tooltipYPadding: 6, - - // Number - pixel width of padding around tooltip text - tooltipXPadding: 6, - - // Number - Size of the caret on the tooltip - tooltipCaretSize: 8, - - // Number - Pixel radius of the tooltip border - tooltipCornerRadius: 6, - - // Number - Pixel offset from point x to tooltip edge - tooltipXOffset: 10, - - // String - Template string for single tooltips - tooltipTemplate: "<%if (label){%><%=label%>: <%}%><%= value %>", - - // String - Template string for single tooltips - multiTooltipTemplate: "<%= value %>", - - // String - Colour behind the legend colour block - multiTooltipKeyBackground: '#fff', - - // Function - Will fire on animation progression. - onAnimationProgress: function(){}, - - // Function - Will fire on animation completion. - onAnimationComplete: function(){} - - } - }; - - //Create a dictionary of chart types, to allow for extension of existing types - Chart.types = {}; - - //Global Chart helpers object for utility methods and classes - var helpers = Chart.helpers = {}; - - //-- Basic js utility methods - var each = helpers.each = function(loopable,callback,self){ - var additionalArgs = Array.prototype.slice.call(arguments, 3); - // Check to see if null or undefined firstly. - if (loopable){ - if (loopable.length === +loopable.length){ - var i; - for (i=0; i= 0; i--) { - var currentItem = arrayToSearch[i]; - if (filterCallback(currentItem)){ - return currentItem; - } - } - }, - inherits = helpers.inherits = function(extensions){ - //Basic javascript inheritance based on the model created in Backbone.js - var parent = this; - var ChartElement = (extensions && extensions.hasOwnProperty("constructor")) ? extensions.constructor : function(){ return parent.apply(this, arguments); }; - - var Surrogate = function(){ this.constructor = ChartElement;}; - Surrogate.prototype = parent.prototype; - ChartElement.prototype = new Surrogate(); - - ChartElement.extend = inherits; - - if (extensions) extend(ChartElement.prototype, extensions); - - ChartElement.__super__ = parent.prototype; - - return ChartElement; - }, - noop = helpers.noop = function(){}, - uid = helpers.uid = (function(){ - var id=0; - return function(){ - return "chart-" + id++; - }; - })(), - warn = helpers.warn = function(str){ - //Method for warning of errors - if (window.console && typeof window.console.warn == "function") console.warn(str); - }, - amd = helpers.amd = (typeof define == 'function' && define.amd), - //-- Math methods - isNumber = helpers.isNumber = function(n){ - return !isNaN(parseFloat(n)) && isFinite(n); - }, - max = helpers.max = function(array){ - return Math.max.apply( Math, array ); - }, - min = helpers.min = function(array){ - return Math.min.apply( Math, array ); - }, - cap = helpers.cap = function(valueToCap,maxValue,minValue){ - if(isNumber(maxValue)) { - if( valueToCap > maxValue ) { - return maxValue; - } - } - else if(isNumber(minValue)){ - if ( valueToCap < minValue ){ - return minValue; - } - } - return valueToCap; - }, - getDecimalPlaces = helpers.getDecimalPlaces = function(num){ - if (num%1!==0 && isNumber(num)){ - return num.toString().split(".")[1].length; - } - else { - return 0; - } - }, - toRadians = helpers.radians = function(degrees){ - return degrees * (Math.PI/180); - }, - // Gets the angle from vertical upright to the point about a centre. - getAngleFromPoint = helpers.getAngleFromPoint = function(centrePoint, anglePoint){ - var distanceFromXCenter = anglePoint.x - centrePoint.x, - distanceFromYCenter = anglePoint.y - centrePoint.y, - radialDistanceFromCenter = Math.sqrt( distanceFromXCenter * distanceFromXCenter + distanceFromYCenter * distanceFromYCenter); - - - var angle = Math.PI * 2 + Math.atan2(distanceFromYCenter, distanceFromXCenter); - - //If the segment is in the top left quadrant, we need to add another rotation to the angle - if (distanceFromXCenter < 0 && distanceFromYCenter < 0){ - angle += Math.PI*2; - } - - return { - angle: angle, - distance: radialDistanceFromCenter - }; - }, - aliasPixel = helpers.aliasPixel = function(pixelWidth){ - return (pixelWidth % 2 === 0) ? 0 : 0.5; - }, - splineCurve = helpers.splineCurve = function(FirstPoint,MiddlePoint,AfterPoint,t){ - //Props to Rob Spencer at scaled innovation for his post on splining between points - //http://scaledinnovation.com/analytics/splines/aboutSplines.html - var d01=Math.sqrt(Math.pow(MiddlePoint.x-FirstPoint.x,2)+Math.pow(MiddlePoint.y-FirstPoint.y,2)), - d12=Math.sqrt(Math.pow(AfterPoint.x-MiddlePoint.x,2)+Math.pow(AfterPoint.y-MiddlePoint.y,2)), - fa=t*d01/(d01+d12),// scaling factor for triangle Ta - fb=t*d12/(d01+d12); - return { - inner : { - x : MiddlePoint.x-fa*(AfterPoint.x-FirstPoint.x), - y : MiddlePoint.y-fa*(AfterPoint.y-FirstPoint.y) - }, - outer : { - x: MiddlePoint.x+fb*(AfterPoint.x-FirstPoint.x), - y : MiddlePoint.y+fb*(AfterPoint.y-FirstPoint.y) - } - }; - }, - calculateOrderOfMagnitude = helpers.calculateOrderOfMagnitude = function(val){ - return Math.floor(Math.log(val) / Math.LN10); - }, - calculateScaleRange = helpers.calculateScaleRange = function(valuesArray, drawingSize, textSize, startFromZero, integersOnly){ - - //Set a minimum step of two - a point at the top of the graph, and a point at the base - var minSteps = 2, - maxSteps = Math.floor(drawingSize/(textSize * 1.5)), - skipFitting = (minSteps >= maxSteps); - - var maxValue = max(valuesArray), - minValue = min(valuesArray); - - // We need some degree of seperation here to calculate the scales if all the values are the same - // Adding/minusing 0.5 will give us a range of 1. - if (maxValue === minValue){ - maxValue += 0.5; - // So we don't end up with a graph with a negative start value if we've said always start from zero - if (minValue >= 0.5 && !startFromZero){ - minValue -= 0.5; - } - else{ - // Make up a whole number above the values - maxValue += 0.5; - } - } - - var valueRange = Math.abs(maxValue - minValue), - rangeOrderOfMagnitude = calculateOrderOfMagnitude(valueRange), - graphMax = Math.ceil(maxValue / (1 * Math.pow(10, rangeOrderOfMagnitude))) * Math.pow(10, rangeOrderOfMagnitude), - graphMin = (startFromZero) ? 0 : Math.floor(minValue / (1 * Math.pow(10, rangeOrderOfMagnitude))) * Math.pow(10, rangeOrderOfMagnitude), - graphRange = graphMax - graphMin, - stepValue = Math.pow(10, rangeOrderOfMagnitude), - numberOfSteps = Math.round(graphRange / stepValue); - - //If we have more space on the graph we'll use it to give more definition to the data - while((numberOfSteps > maxSteps || (numberOfSteps * 2) < maxSteps) && !skipFitting) { - if(numberOfSteps > maxSteps){ - stepValue *=2; - numberOfSteps = Math.round(graphRange/stepValue); - // Don't ever deal with a decimal number of steps - cancel fitting and just use the minimum number of steps. - if (numberOfSteps % 1 !== 0){ - skipFitting = true; - } - } - //We can fit in double the amount of scale points on the scale - else{ - //If user has declared ints only, and the step value isn't a decimal - if (integersOnly && rangeOrderOfMagnitude >= 0){ - //If the user has said integers only, we need to check that making the scale more granular wouldn't make it a float - if(stepValue/2 % 1 === 0){ - stepValue /=2; - numberOfSteps = Math.round(graphRange/stepValue); - } - //If it would make it a float break out of the loop - else{ - break; - } - } - //If the scale doesn't have to be an int, make the scale more granular anyway. - else{ - stepValue /=2; - numberOfSteps = Math.round(graphRange/stepValue); - } - - } - } - - if (skipFitting){ - numberOfSteps = minSteps; - stepValue = graphRange / numberOfSteps; - } - - return { - steps : numberOfSteps, - stepValue : stepValue, - min : graphMin, - max : graphMin + (numberOfSteps * stepValue) - }; - - }, - /* jshint ignore:start */ - // Blows up jshint errors based on the new Function constructor - //Templating methods - //Javascript micro templating by John Resig - source at http://ejohn.org/blog/javascript-micro-templating/ - template = helpers.template = function(templateString, valuesObject){ - - // If templateString is function rather than string-template - call the function for valuesObject - - if(templateString instanceof Function){ - return templateString(valuesObject); - } - - var cache = {}; - function tmpl(str, data){ - // Figure out if we're getting a template, or if we need to - // load the template - and be sure to cache the result. - var fn = !/\W/.test(str) ? - cache[str] = cache[str] : - - // Generate a reusable function that will serve as a template - // generator (and which will be cached). - new Function("obj", - "var p=[],print=function(){p.push.apply(p,arguments);};" + - - // Introduce the data as local variables using with(){} - "with(obj){p.push('" + - - // Convert the template into pure JavaScript - str - .replace(/[\r\t\n]/g, " ") - .split("<%").join("\t") - .replace(/((^|%>)[^\t]*)'/g, "$1\r") - .replace(/\t=(.*?)%>/g, "',$1,'") - .split("\t").join("');") - .split("%>").join("p.push('") - .split("\r").join("\\'") + - "');}return p.join('');" - ); - - // Provide some basic currying to the user - return data ? fn( data ) : fn; - } - return tmpl(templateString,valuesObject); - }, - /* jshint ignore:end */ - generateLabels = helpers.generateLabels = function(templateString,numberOfSteps,graphMin,stepValue){ - var labelsArray = new Array(numberOfSteps); - if (labelTemplateString){ - each(labelsArray,function(val,index){ - labelsArray[index] = template(templateString,{value: (graphMin + (stepValue*(index+1)))}); - }); - } - return labelsArray; - }, - //--Animation methods - //Easing functions adapted from Robert Penner's easing equations - //http://www.robertpenner.com/easing/ - easingEffects = helpers.easingEffects = { - linear: function (t) { - return t; - }, - easeInQuad: function (t) { - return t * t; - }, - easeOutQuad: function (t) { - return -1 * t * (t - 2); - }, - easeInOutQuad: function (t) { - if ((t /= 1 / 2) < 1) return 1 / 2 * t * t; - return -1 / 2 * ((--t) * (t - 2) - 1); - }, - easeInCubic: function (t) { - return t * t * t; - }, - easeOutCubic: function (t) { - return 1 * ((t = t / 1 - 1) * t * t + 1); - }, - easeInOutCubic: function (t) { - if ((t /= 1 / 2) < 1) return 1 / 2 * t * t * t; - return 1 / 2 * ((t -= 2) * t * t + 2); - }, - easeInQuart: function (t) { - return t * t * t * t; - }, - easeOutQuart: function (t) { - return -1 * ((t = t / 1 - 1) * t * t * t - 1); - }, - easeInOutQuart: function (t) { - if ((t /= 1 / 2) < 1) return 1 / 2 * t * t * t * t; - return -1 / 2 * ((t -= 2) * t * t * t - 2); - }, - easeInQuint: function (t) { - return 1 * (t /= 1) * t * t * t * t; - }, - easeOutQuint: function (t) { - return 1 * ((t = t / 1 - 1) * t * t * t * t + 1); - }, - easeInOutQuint: function (t) { - if ((t /= 1 / 2) < 1) return 1 / 2 * t * t * t * t * t; - return 1 / 2 * ((t -= 2) * t * t * t * t + 2); - }, - easeInSine: function (t) { - return -1 * Math.cos(t / 1 * (Math.PI / 2)) + 1; - }, - easeOutSine: function (t) { - return 1 * Math.sin(t / 1 * (Math.PI / 2)); - }, - easeInOutSine: function (t) { - return -1 / 2 * (Math.cos(Math.PI * t / 1) - 1); - }, - easeInExpo: function (t) { - return (t === 0) ? 1 : 1 * Math.pow(2, 10 * (t / 1 - 1)); - }, - easeOutExpo: function (t) { - return (t === 1) ? 1 : 1 * (-Math.pow(2, -10 * t / 1) + 1); - }, - easeInOutExpo: function (t) { - if (t === 0) return 0; - if (t === 1) return 1; - if ((t /= 1 / 2) < 1) return 1 / 2 * Math.pow(2, 10 * (t - 1)); - return 1 / 2 * (-Math.pow(2, -10 * --t) + 2); - }, - easeInCirc: function (t) { - if (t >= 1) return t; - return -1 * (Math.sqrt(1 - (t /= 1) * t) - 1); - }, - easeOutCirc: function (t) { - return 1 * Math.sqrt(1 - (t = t / 1 - 1) * t); - }, - easeInOutCirc: function (t) { - if ((t /= 1 / 2) < 1) return -1 / 2 * (Math.sqrt(1 - t * t) - 1); - return 1 / 2 * (Math.sqrt(1 - (t -= 2) * t) + 1); - }, - easeInElastic: function (t) { - var s = 1.70158; - var p = 0; - var a = 1; - if (t === 0) return 0; - if ((t /= 1) == 1) return 1; - if (!p) p = 1 * 0.3; - if (a < Math.abs(1)) { - a = 1; - s = p / 4; - } else s = p / (2 * Math.PI) * Math.asin(1 / a); - return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * 1 - s) * (2 * Math.PI) / p)); - }, - easeOutElastic: function (t) { - var s = 1.70158; - var p = 0; - var a = 1; - if (t === 0) return 0; - if ((t /= 1) == 1) return 1; - if (!p) p = 1 * 0.3; - if (a < Math.abs(1)) { - a = 1; - s = p / 4; - } else s = p / (2 * Math.PI) * Math.asin(1 / a); - return a * Math.pow(2, -10 * t) * Math.sin((t * 1 - s) * (2 * Math.PI) / p) + 1; - }, - easeInOutElastic: function (t) { - var s = 1.70158; - var p = 0; - var a = 1; - if (t === 0) return 0; - if ((t /= 1 / 2) == 2) return 1; - if (!p) p = 1 * (0.3 * 1.5); - if (a < Math.abs(1)) { - a = 1; - s = p / 4; - } else s = p / (2 * Math.PI) * Math.asin(1 / a); - if (t < 1) return -0.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * 1 - s) * (2 * Math.PI) / p)); - return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t * 1 - s) * (2 * Math.PI) / p) * 0.5 + 1; - }, - easeInBack: function (t) { - var s = 1.70158; - return 1 * (t /= 1) * t * ((s + 1) * t - s); - }, - easeOutBack: function (t) { - var s = 1.70158; - return 1 * ((t = t / 1 - 1) * t * ((s + 1) * t + s) + 1); - }, - easeInOutBack: function (t) { - var s = 1.70158; - if ((t /= 1 / 2) < 1) return 1 / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)); - return 1 / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2); - }, - easeInBounce: function (t) { - return 1 - easingEffects.easeOutBounce(1 - t); - }, - easeOutBounce: function (t) { - if ((t /= 1) < (1 / 2.75)) { - return 1 * (7.5625 * t * t); - } else if (t < (2 / 2.75)) { - return 1 * (7.5625 * (t -= (1.5 / 2.75)) * t + 0.75); - } else if (t < (2.5 / 2.75)) { - return 1 * (7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375); - } else { - return 1 * (7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375); - } - }, - easeInOutBounce: function (t) { - if (t < 1 / 2) return easingEffects.easeInBounce(t * 2) * 0.5; - return easingEffects.easeOutBounce(t * 2 - 1) * 0.5 + 1 * 0.5; - } - }, - //Request animation polyfill - http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/ - requestAnimFrame = helpers.requestAnimFrame = (function(){ - return window.requestAnimationFrame || - window.webkitRequestAnimationFrame || - window.mozRequestAnimationFrame || - window.oRequestAnimationFrame || - window.msRequestAnimationFrame || - function(callback) { - return window.setTimeout(callback, 1000 / 60); - }; - })(), - cancelAnimFrame = helpers.cancelAnimFrame = (function(){ - return window.cancelAnimationFrame || - window.webkitCancelAnimationFrame || - window.mozCancelAnimationFrame || - window.oCancelAnimationFrame || - window.msCancelAnimationFrame || - function(callback) { - return window.clearTimeout(callback, 1000 / 60); - }; - })(), - animationLoop = helpers.animationLoop = function(callback,totalSteps,easingString,onProgress,onComplete,chartInstance){ - - var currentStep = 0, - easingFunction = easingEffects[easingString] || easingEffects.linear; - - var animationFrame = function(){ - currentStep++; - var stepDecimal = currentStep/totalSteps; - var easeDecimal = easingFunction(stepDecimal); - - callback.call(chartInstance,easeDecimal,stepDecimal, currentStep); - onProgress.call(chartInstance,easeDecimal,stepDecimal); - if (currentStep < totalSteps){ - chartInstance.animationFrame = requestAnimFrame(animationFrame); - } else{ - onComplete.apply(chartInstance); - } - }; - requestAnimFrame(animationFrame); - }, - //-- DOM methods - getRelativePosition = helpers.getRelativePosition = function(evt){ - var mouseX, mouseY; - var e = evt.originalEvent || evt, - canvas = evt.currentTarget || evt.srcElement, - boundingRect = canvas.getBoundingClientRect(); - - if (e.touches){ - mouseX = e.touches[0].clientX - boundingRect.left; - mouseY = e.touches[0].clientY - boundingRect.top; - - } - else{ - mouseX = e.clientX - boundingRect.left; - mouseY = e.clientY - boundingRect.top; - } - - return { - x : mouseX, - y : mouseY - }; - - }, - addEvent = helpers.addEvent = function(node,eventType,method){ - if (node.addEventListener){ - node.addEventListener(eventType,method); - } else if (node.attachEvent){ - node.attachEvent("on"+eventType, method); - } else { - node["on"+eventType] = method; - } - }, - removeEvent = helpers.removeEvent = function(node, eventType, handler){ - if (node.removeEventListener){ - node.removeEventListener(eventType, handler, false); - } else if (node.detachEvent){ - node.detachEvent("on"+eventType,handler); - } else{ - node["on" + eventType] = noop; - } - }, - bindEvents = helpers.bindEvents = function(chartInstance, arrayOfEvents, handler){ - // Create the events object if it's not already present - if (!chartInstance.events) chartInstance.events = {}; - - each(arrayOfEvents,function(eventName){ - chartInstance.events[eventName] = function(){ - handler.apply(chartInstance, arguments); - }; - addEvent(chartInstance.chart.canvas,eventName,chartInstance.events[eventName]); - }); - }, - unbindEvents = helpers.unbindEvents = function (chartInstance, arrayOfEvents) { - each(arrayOfEvents, function(handler,eventName){ - removeEvent(chartInstance.chart.canvas, eventName, handler); - }); - }, - getMaximumWidth = helpers.getMaximumWidth = function(domNode){ - var container = domNode.parentNode; - // TODO = check cross browser stuff with this. - return container.clientWidth; - }, - getMaximumHeight = helpers.getMaximumHeight = function(domNode){ - var container = domNode.parentNode; - // TODO = check cross browser stuff with this. - return container.clientHeight; - }, - getMaximumSize = helpers.getMaximumSize = helpers.getMaximumWidth, // legacy support - retinaScale = helpers.retinaScale = function(chart){ - var ctx = chart.ctx, - width = chart.canvas.width, - height = chart.canvas.height; - - if (window.devicePixelRatio) { - ctx.canvas.style.width = width + "px"; - ctx.canvas.style.height = height + "px"; - ctx.canvas.height = height * window.devicePixelRatio; - ctx.canvas.width = width * window.devicePixelRatio; - ctx.scale(window.devicePixelRatio, window.devicePixelRatio); - } - }, - //-- Canvas methods - clear = helpers.clear = function(chart){ - chart.ctx.clearRect(0,0,chart.width,chart.height); - }, - fontString = helpers.fontString = function(pixelSize,fontStyle,fontFamily){ - return fontStyle + " " + pixelSize+"px " + fontFamily; - }, - longestText = helpers.longestText = function(ctx,font,arrayOfStrings){ - ctx.font = font; - var longest = 0; - each(arrayOfStrings,function(string){ - var textWidth = ctx.measureText(string).width; - longest = (textWidth > longest) ? textWidth : longest; - }); - return longest; - }, - drawRoundedRectangle = helpers.drawRoundedRectangle = function(ctx,x,y,width,height,radius){ - ctx.beginPath(); - ctx.moveTo(x + radius, y); - ctx.lineTo(x + width - radius, y); - ctx.quadraticCurveTo(x + width, y, x + width, y + radius); - ctx.lineTo(x + width, y + height - radius); - ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height); - ctx.lineTo(x + radius, y + height); - ctx.quadraticCurveTo(x, y + height, x, y + height - radius); - ctx.lineTo(x, y + radius); - ctx.quadraticCurveTo(x, y, x + radius, y); - ctx.closePath(); - }; - - - //Store a reference to each instance - allowing us to globally resize chart instances on window resize. - //Destroy method on the chart will remove the instance of the chart from this reference. - Chart.instances = {}; - - Chart.Type = function(data,options,chart){ - this.options = options; - this.chart = chart; - this.id = uid(); - //Add the chart instance to the global namespace - Chart.instances[this.id] = this; - - // Initialize is always called when a chart type is created - // By default it is a no op, but it should be extended - if (options.responsive){ - this.resize(); - } - this.initialize.call(this,data); - }; - - //Core methods that'll be a part of every chart type - extend(Chart.Type.prototype,{ - initialize : function(){return this;}, - clear : function(){ - clear(this.chart); - return this; - }, - stop : function(){ - // Stops any current animation loop occuring - cancelAnimFrame(this.animationFrame); - return this; - }, - resize : function(callback){ - this.stop(); - var canvas = this.chart.canvas, - newWidth = getMaximumWidth(this.chart.canvas), - newHeight = this.options.maintainAspectRatio ? newWidth / this.chart.aspectRatio : getMaximumHeight(this.chart.canvas); - - canvas.width = this.chart.width = newWidth; - canvas.height = this.chart.height = newHeight; - - retinaScale(this.chart); - - if (typeof callback === "function"){ - callback.apply(this, Array.prototype.slice.call(arguments, 1)); - } - return this; - }, - reflow : noop, - render : function(reflow){ - if (reflow){ - this.reflow(); - } - if (this.options.animation && !reflow){ - helpers.animationLoop( - this.draw, - this.options.animationSteps, - this.options.animationEasing, - this.options.onAnimationProgress, - this.options.onAnimationComplete, - this - ); - } - else{ - this.draw(); - this.options.onAnimationComplete.call(this); - } - return this; - }, - generateLegend : function(){ - return template(this.options.legendTemplate,this); - }, - destroy : function(){ - this.clear(); - unbindEvents(this, this.events); - var canvas = this.chart.canvas; - - // Reset canvas height/width attributes starts a fresh with the canvas context - canvas.width = this.chart.width; - canvas.height = this.chart.height; - - // < IE9 doesn't support removeProperty - if (canvas.style.removeProperty) { - canvas.style.removeProperty('width'); - canvas.style.removeProperty('height'); - } else { - canvas.style.removeAttribute('width'); - canvas.style.removeAttribute('height'); - } - - delete Chart.instances[this.id]; - }, - showTooltip : function(ChartElements, forceRedraw){ - // Only redraw the chart if we've actually changed what we're hovering on. - if (typeof this.activeElements === 'undefined') this.activeElements = []; - - var isChanged = (function(Elements){ - var changed = false; - - if (Elements.length !== this.activeElements.length){ - changed = true; - return changed; - } - - each(Elements, function(element, index){ - if (element !== this.activeElements[index]){ - changed = true; - } - }, this); - return changed; - }).call(this, ChartElements); - - if (!isChanged && !forceRedraw){ - return; - } - else{ - this.activeElements = ChartElements; - } - this.draw(); - if(this.options.customTooltips){ - this.options.customTooltips(false); - } - if (ChartElements.length > 0){ - // If we have multiple datasets, show a MultiTooltip for all of the data points at that index - if (this.datasets && this.datasets.length > 1) { - var dataArray, - dataIndex; - - for (var i = this.datasets.length - 1; i >= 0; i--) { - dataArray = this.datasets[i].points || this.datasets[i].bars || this.datasets[i].segments; - dataIndex = indexOf(dataArray, ChartElements[0]); - if (dataIndex !== -1){ - break; - } - } - var tooltipLabels = [], - tooltipColors = [], - medianPosition = (function(index) { - - // Get all the points at that particular index - var Elements = [], - dataCollection, - xPositions = [], - yPositions = [], - xMax, - yMax, - xMin, - yMin; - helpers.each(this.datasets, function(dataset){ - dataCollection = dataset.points || dataset.bars || dataset.segments; - if (dataCollection[dataIndex] && dataCollection[dataIndex].hasValue()){ - Elements.push(dataCollection[dataIndex]); - } - }); - - helpers.each(Elements, function(element) { - xPositions.push(element.x); - yPositions.push(element.y); - - - //Include any colour information about the element - tooltipLabels.push(helpers.template(this.options.multiTooltipTemplate, element)); - tooltipColors.push({ - fill: element._saved.fillColor || element.fillColor, - stroke: element._saved.strokeColor || element.strokeColor - }); - - }, this); - - yMin = min(yPositions); - yMax = max(yPositions); - - xMin = min(xPositions); - xMax = max(xPositions); - - return { - x: (xMin > this.chart.width/2) ? xMin : xMax, - y: (yMin + yMax)/2 - }; - }).call(this, dataIndex); - - new Chart.MultiTooltip({ - x: medianPosition.x, - y: medianPosition.y, - xPadding: this.options.tooltipXPadding, - yPadding: this.options.tooltipYPadding, - xOffset: this.options.tooltipXOffset, - fillColor: this.options.tooltipFillColor, - textColor: this.options.tooltipFontColor, - fontFamily: this.options.tooltipFontFamily, - fontStyle: this.options.tooltipFontStyle, - fontSize: this.options.tooltipFontSize, - titleTextColor: this.options.tooltipTitleFontColor, - titleFontFamily: this.options.tooltipTitleFontFamily, - titleFontStyle: this.options.tooltipTitleFontStyle, - titleFontSize: this.options.tooltipTitleFontSize, - cornerRadius: this.options.tooltipCornerRadius, - labels: tooltipLabels, - legendColors: tooltipColors, - legendColorBackground : this.options.multiTooltipKeyBackground, - title: ChartElements[0].label, - chart: this.chart, - ctx: this.chart.ctx, - custom: this.options.customTooltips - }).draw(); - - } else { - each(ChartElements, function(Element) { - var tooltipPosition = Element.tooltipPosition(); - new Chart.Tooltip({ - x: Math.round(tooltipPosition.x), - y: Math.round(tooltipPosition.y), - xPadding: this.options.tooltipXPadding, - yPadding: this.options.tooltipYPadding, - fillColor: this.options.tooltipFillColor, - textColor: this.options.tooltipFontColor, - fontFamily: this.options.tooltipFontFamily, - fontStyle: this.options.tooltipFontStyle, - fontSize: this.options.tooltipFontSize, - caretHeight: this.options.tooltipCaretSize, - cornerRadius: this.options.tooltipCornerRadius, - text: template(this.options.tooltipTemplate, Element), - chart: this.chart, - custom: this.options.customTooltips - }).draw(); - }, this); - } - } - return this; - }, - toBase64Image : function(){ - return this.chart.canvas.toDataURL.apply(this.chart.canvas, arguments); - } - }); - - Chart.Type.extend = function(extensions){ - - var parent = this; - - var ChartType = function(){ - return parent.apply(this,arguments); - }; - - //Copy the prototype object of the this class - ChartType.prototype = clone(parent.prototype); - //Now overwrite some of the properties in the base class with the new extensions - extend(ChartType.prototype, extensions); - - ChartType.extend = Chart.Type.extend; - - if (extensions.name || parent.prototype.name){ - - var chartName = extensions.name || parent.prototype.name; - //Assign any potential default values of the new chart type - - //If none are defined, we'll use a clone of the chart type this is being extended from. - //I.e. if we extend a line chart, we'll use the defaults from the line chart if our new chart - //doesn't define some defaults of their own. - - var baseDefaults = (Chart.defaults[parent.prototype.name]) ? clone(Chart.defaults[parent.prototype.name]) : {}; - - Chart.defaults[chartName] = extend(baseDefaults,extensions.defaults); - - Chart.types[chartName] = ChartType; - - //Register this new chart type in the Chart prototype - Chart.prototype[chartName] = function(data,options){ - var config = merge(Chart.defaults.global, Chart.defaults[chartName], options || {}); - return new ChartType(data,config,this); - }; - } else{ - warn("Name not provided for this chart, so it hasn't been registered"); - } - return parent; - }; - - Chart.Element = function(configuration){ - extend(this,configuration); - this.initialize.apply(this,arguments); - this.save(); - }; - extend(Chart.Element.prototype,{ - initialize : function(){}, - restore : function(props){ - if (!props){ - extend(this,this._saved); - } else { - each(props,function(key){ - this[key] = this._saved[key]; - },this); - } - return this; - }, - save : function(){ - this._saved = clone(this); - delete this._saved._saved; - return this; - }, - update : function(newProps){ - each(newProps,function(value,key){ - this._saved[key] = this[key]; - this[key] = value; - },this); - return this; - }, - transition : function(props,ease){ - each(props,function(value,key){ - this[key] = ((value - this._saved[key]) * ease) + this._saved[key]; - },this); - return this; - }, - tooltipPosition : function(){ - return { - x : this.x, - y : this.y - }; - }, - hasValue: function(){ - return isNumber(this.value); - } - }); - - Chart.Element.extend = inherits; - - - Chart.Point = Chart.Element.extend({ - display: true, - inRange: function(chartX,chartY){ - var hitDetectionRange = this.hitDetectionRadius + this.radius; - return ((Math.pow(chartX-this.x, 2)+Math.pow(chartY-this.y, 2)) < Math.pow(hitDetectionRange,2)); - }, - draw : function(){ - if (this.display){ - var ctx = this.ctx; - ctx.beginPath(); - - ctx.arc(this.x, this.y, this.radius, 0, Math.PI*2); - ctx.closePath(); - - ctx.strokeStyle = this.strokeColor; - ctx.lineWidth = this.strokeWidth; - - ctx.fillStyle = this.fillColor; - - ctx.fill(); - ctx.stroke(); - } - - - //Quick debug for bezier curve splining - //Highlights control points and the line between them. - //Handy for dev - stripped in the min version. - - // ctx.save(); - // ctx.fillStyle = "black"; - // ctx.strokeStyle = "black" - // ctx.beginPath(); - // ctx.arc(this.controlPoints.inner.x,this.controlPoints.inner.y, 2, 0, Math.PI*2); - // ctx.fill(); - - // ctx.beginPath(); - // ctx.arc(this.controlPoints.outer.x,this.controlPoints.outer.y, 2, 0, Math.PI*2); - // ctx.fill(); - - // ctx.moveTo(this.controlPoints.inner.x,this.controlPoints.inner.y); - // ctx.lineTo(this.x, this.y); - // ctx.lineTo(this.controlPoints.outer.x,this.controlPoints.outer.y); - // ctx.stroke(); - - // ctx.restore(); - - - - } - }); - - Chart.Arc = Chart.Element.extend({ - inRange : function(chartX,chartY){ - - var pointRelativePosition = helpers.getAngleFromPoint(this, { - x: chartX, - y: chartY - }); - - //Check if within the range of the open/close angle - var betweenAngles = (pointRelativePosition.angle >= this.startAngle && pointRelativePosition.angle <= this.endAngle), - withinRadius = (pointRelativePosition.distance >= this.innerRadius && pointRelativePosition.distance <= this.outerRadius); - - return (betweenAngles && withinRadius); - //Ensure within the outside of the arc centre, but inside arc outer - }, - tooltipPosition : function(){ - var centreAngle = this.startAngle + ((this.endAngle - this.startAngle) / 2), - rangeFromCentre = (this.outerRadius - this.innerRadius) / 2 + this.innerRadius; - return { - x : this.x + (Math.cos(centreAngle) * rangeFromCentre), - y : this.y + (Math.sin(centreAngle) * rangeFromCentre) - }; - }, - draw : function(animationPercent){ - - var easingDecimal = animationPercent || 1; - - var ctx = this.ctx; - - ctx.beginPath(); - - ctx.arc(this.x, this.y, this.outerRadius, this.startAngle, this.endAngle); - - ctx.arc(this.x, this.y, this.innerRadius, this.endAngle, this.startAngle, true); - - ctx.closePath(); - ctx.strokeStyle = this.strokeColor; - ctx.lineWidth = this.strokeWidth; - - ctx.fillStyle = this.fillColor; - - ctx.fill(); - ctx.lineJoin = 'bevel'; - - if (this.showStroke){ - ctx.stroke(); - } - } - }); - - Chart.Rectangle = Chart.Element.extend({ - draw : function(){ - var ctx = this.ctx, - halfWidth = this.width/2, - leftX = this.x - halfWidth, - rightX = this.x + halfWidth, - top = this.base - (this.base - this.y), - halfStroke = this.strokeWidth / 2; - - // Canvas doesn't allow us to stroke inside the width so we can - // adjust the sizes to fit if we're setting a stroke on the line - if (this.showStroke){ - leftX += halfStroke; - rightX -= halfStroke; - top += halfStroke; - } - - ctx.beginPath(); - - ctx.fillStyle = this.fillColor; - ctx.strokeStyle = this.strokeColor; - ctx.lineWidth = this.strokeWidth; - - // It'd be nice to keep this class totally generic to any rectangle - // and simply specify which border to miss out. - ctx.moveTo(leftX, this.base); - ctx.lineTo(leftX, top); - ctx.lineTo(rightX, top); - ctx.lineTo(rightX, this.base); - ctx.fill(); - if (this.showStroke){ - ctx.stroke(); - } - }, - height : function(){ - return this.base - this.y; - }, - inRange : function(chartX,chartY){ - return (chartX >= this.x - this.width/2 && chartX <= this.x + this.width/2) && (chartY >= this.y && chartY <= this.base); - } - }); - - Chart.Tooltip = Chart.Element.extend({ - draw : function(){ - - var ctx = this.chart.ctx; - - ctx.font = fontString(this.fontSize,this.fontStyle,this.fontFamily); - - this.xAlign = "center"; - this.yAlign = "above"; - - //Distance between the actual element.y position and the start of the tooltip caret - var caretPadding = this.caretPadding = 2; - - var tooltipWidth = ctx.measureText(this.text).width + 2*this.xPadding, - tooltipRectHeight = this.fontSize + 2*this.yPadding, - tooltipHeight = tooltipRectHeight + this.caretHeight + caretPadding; - - if (this.x + tooltipWidth/2 >this.chart.width){ - this.xAlign = "left"; - } else if (this.x - tooltipWidth/2 < 0){ - this.xAlign = "right"; - } - - if (this.y - tooltipHeight < 0){ - this.yAlign = "below"; - } - - - var tooltipX = this.x - tooltipWidth/2, - tooltipY = this.y - tooltipHeight; - - ctx.fillStyle = this.fillColor; - - // Custom Tooltips - if(this.custom){ - this.custom(this); - } - else{ - switch(this.yAlign) - { - case "above": - //Draw a caret above the x/y - ctx.beginPath(); - ctx.moveTo(this.x,this.y - caretPadding); - ctx.lineTo(this.x + this.caretHeight, this.y - (caretPadding + this.caretHeight)); - ctx.lineTo(this.x - this.caretHeight, this.y - (caretPadding + this.caretHeight)); - ctx.closePath(); - ctx.fill(); - break; - case "below": - tooltipY = this.y + caretPadding + this.caretHeight; - //Draw a caret below the x/y - ctx.beginPath(); - ctx.moveTo(this.x, this.y + caretPadding); - ctx.lineTo(this.x + this.caretHeight, this.y + caretPadding + this.caretHeight); - ctx.lineTo(this.x - this.caretHeight, this.y + caretPadding + this.caretHeight); - ctx.closePath(); - ctx.fill(); - break; - } - - switch(this.xAlign) - { - case "left": - tooltipX = this.x - tooltipWidth + (this.cornerRadius + this.caretHeight); - break; - case "right": - tooltipX = this.x - (this.cornerRadius + this.caretHeight); - break; - } - - drawRoundedRectangle(ctx,tooltipX,tooltipY,tooltipWidth,tooltipRectHeight,this.cornerRadius); - - ctx.fill(); - - ctx.fillStyle = this.textColor; - ctx.textAlign = "center"; - ctx.textBaseline = "middle"; - ctx.fillText(this.text, tooltipX + tooltipWidth/2, tooltipY + tooltipRectHeight/2); - } - } - }); - - Chart.MultiTooltip = Chart.Element.extend({ - initialize : function(){ - this.font = fontString(this.fontSize,this.fontStyle,this.fontFamily); - - this.titleFont = fontString(this.titleFontSize,this.titleFontStyle,this.titleFontFamily); - - this.height = (this.labels.length * this.fontSize) + ((this.labels.length-1) * (this.fontSize/2)) + (this.yPadding*2) + this.titleFontSize *1.5; - - this.ctx.font = this.titleFont; - - var titleWidth = this.ctx.measureText(this.title).width, - //Label has a legend square as well so account for this. - labelWidth = longestText(this.ctx,this.font,this.labels) + this.fontSize + 3, - longestTextWidth = max([labelWidth,titleWidth]); - - this.width = longestTextWidth + (this.xPadding*2); - - - var halfHeight = this.height/2; - - //Check to ensure the height will fit on the canvas - if (this.y - halfHeight < 0 ){ - this.y = halfHeight; - } else if (this.y + halfHeight > this.chart.height){ - this.y = this.chart.height - halfHeight; - } - - //Decide whether to align left or right based on position on canvas - if (this.x > this.chart.width/2){ - this.x -= this.xOffset + this.width; - } else { - this.x += this.xOffset; - } - - - }, - getLineHeight : function(index){ - var baseLineHeight = this.y - (this.height/2) + this.yPadding, - afterTitleIndex = index-1; - - //If the index is zero, we're getting the title - if (index === 0){ - return baseLineHeight + this.titleFontSize/2; - } else{ - return baseLineHeight + ((this.fontSize*1.5*afterTitleIndex) + this.fontSize/2) + this.titleFontSize * 1.5; - } - - }, - draw : function(){ - // Custom Tooltips - if(this.custom){ - this.custom(this); - } - else{ - drawRoundedRectangle(this.ctx,this.x,this.y - this.height/2,this.width,this.height,this.cornerRadius); - var ctx = this.ctx; - ctx.fillStyle = this.fillColor; - ctx.fill(); - ctx.closePath(); - - ctx.textAlign = "left"; - ctx.textBaseline = "middle"; - ctx.fillStyle = this.titleTextColor; - ctx.font = this.titleFont; - - ctx.fillText(this.title,this.x + this.xPadding, this.getLineHeight(0)); - - ctx.font = this.font; - helpers.each(this.labels,function(label,index){ - ctx.fillStyle = this.textColor; - ctx.fillText(label,this.x + this.xPadding + this.fontSize + 3, this.getLineHeight(index + 1)); - - //A bit gnarly, but clearing this rectangle breaks when using explorercanvas (clears whole canvas) - //ctx.clearRect(this.x + this.xPadding, this.getLineHeight(index + 1) - this.fontSize/2, this.fontSize, this.fontSize); - //Instead we'll make a white filled block to put the legendColour palette over. - - ctx.fillStyle = this.legendColorBackground; - ctx.fillRect(this.x + this.xPadding, this.getLineHeight(index + 1) - this.fontSize/2, this.fontSize, this.fontSize); - - ctx.fillStyle = this.legendColors[index].fill; - ctx.fillRect(this.x + this.xPadding, this.getLineHeight(index + 1) - this.fontSize/2, this.fontSize, this.fontSize); - - - },this); - } - } - }); - - Chart.Scale = Chart.Element.extend({ - initialize : function(){ - this.fit(); - }, - buildYLabels : function(){ - this.yLabels = []; - - var stepDecimalPlaces = getDecimalPlaces(this.stepValue); - - for (var i=0; i<=this.steps; i++){ - this.yLabels.push(template(this.templateString,{value:(this.min + (i * this.stepValue)).toFixed(stepDecimalPlaces)})); - } - this.yLabelWidth = (this.display && this.showLabels) ? longestText(this.ctx,this.font,this.yLabels) : 0; - }, - addXLabel : function(label){ - this.xLabels.push(label); - this.valuesCount++; - this.fit(); - }, - removeXLabel : function(){ - this.xLabels.shift(); - this.valuesCount--; - this.fit(); - }, - // Fitting loop to rotate x Labels and figure out what fits there, and also calculate how many Y steps to use - fit: function(){ - // First we need the width of the yLabels, assuming the xLabels aren't rotated - - // To do that we need the base line at the top and base of the chart, assuming there is no x label rotation - this.startPoint = (this.display) ? this.fontSize : 0; - this.endPoint = (this.display) ? this.height - (this.fontSize * 1.5) - 5 : this.height; // -5 to pad labels - - // Apply padding settings to the start and end point. - this.startPoint += this.padding; - this.endPoint -= this.padding; - - // Cache the starting height, so can determine if we need to recalculate the scale yAxis - var cachedHeight = this.endPoint - this.startPoint, - cachedYLabelWidth; - - // Build the current yLabels so we have an idea of what size they'll be to start - /* - * This sets what is returned from calculateScaleRange as static properties of this class: - * - this.steps; - this.stepValue; - this.min; - this.max; - * - */ - this.calculateYRange(cachedHeight); - - // With these properties set we can now build the array of yLabels - // and also the width of the largest yLabel - this.buildYLabels(); - - this.calculateXLabelRotation(); - - while((cachedHeight > this.endPoint - this.startPoint)){ - cachedHeight = this.endPoint - this.startPoint; - cachedYLabelWidth = this.yLabelWidth; - - this.calculateYRange(cachedHeight); - this.buildYLabels(); - - // Only go through the xLabel loop again if the yLabel width has changed - if (cachedYLabelWidth < this.yLabelWidth){ - this.calculateXLabelRotation(); - } - } - - }, - calculateXLabelRotation : function(){ - //Get the width of each grid by calculating the difference - //between x offsets between 0 and 1. - - this.ctx.font = this.font; - - var firstWidth = this.ctx.measureText(this.xLabels[0]).width, - lastWidth = this.ctx.measureText(this.xLabels[this.xLabels.length - 1]).width, - firstRotated, - lastRotated; - - - this.xScalePaddingRight = lastWidth/2 + 3; - this.xScalePaddingLeft = (firstWidth/2 > this.yLabelWidth + 10) ? firstWidth/2 : this.yLabelWidth + 10; - - this.xLabelRotation = 0; - if (this.display){ - var originalLabelWidth = longestText(this.ctx,this.font,this.xLabels), - cosRotation, - firstRotatedWidth; - this.xLabelWidth = originalLabelWidth; - //Allow 3 pixels x2 padding either side for label readability - var xGridWidth = Math.floor(this.calculateX(1) - this.calculateX(0)) - 6; - - //Max label rotate should be 90 - also act as a loop counter - while ((this.xLabelWidth > xGridWidth && this.xLabelRotation === 0) || (this.xLabelWidth > xGridWidth && this.xLabelRotation <= 90 && this.xLabelRotation > 0)){ - cosRotation = Math.cos(toRadians(this.xLabelRotation)); - - firstRotated = cosRotation * firstWidth; - lastRotated = cosRotation * lastWidth; - - // We're right aligning the text now. - if (firstRotated + this.fontSize / 2 > this.yLabelWidth + 8){ - this.xScalePaddingLeft = firstRotated + this.fontSize / 2; - } - this.xScalePaddingRight = this.fontSize/2; - - - this.xLabelRotation++; - this.xLabelWidth = cosRotation * originalLabelWidth; - - } - if (this.xLabelRotation > 0){ - this.endPoint -= Math.sin(toRadians(this.xLabelRotation))*originalLabelWidth + 3; - } - } - else{ - this.xLabelWidth = 0; - this.xScalePaddingRight = this.padding; - this.xScalePaddingLeft = this.padding; - } - - }, - // Needs to be overidden in each Chart type - // Otherwise we need to pass all the data into the scale class - calculateYRange: noop, - drawingArea: function(){ - return this.startPoint - this.endPoint; - }, - calculateY : function(value){ - var scalingFactor = this.drawingArea() / (this.min - this.max); - return this.endPoint - (scalingFactor * (value - this.min)); - }, - calculateX : function(index){ - var isRotated = (this.xLabelRotation > 0), - // innerWidth = (this.offsetGridLines) ? this.width - offsetLeft - this.padding : this.width - (offsetLeft + halfLabelWidth * 2) - this.padding, - innerWidth = this.width - (this.xScalePaddingLeft + this.xScalePaddingRight), - valueWidth = innerWidth/Math.max((this.valuesCount - ((this.offsetGridLines) ? 0 : 1)), 1), - valueOffset = (valueWidth * index) + this.xScalePaddingLeft; - - if (this.offsetGridLines){ - valueOffset += (valueWidth/2); - } - - return Math.round(valueOffset); - }, - update : function(newProps){ - helpers.extend(this, newProps); - this.fit(); - }, - draw : function(){ - var ctx = this.ctx, - yLabelGap = (this.endPoint - this.startPoint) / this.steps, - xStart = Math.round(this.xScalePaddingLeft); - if (this.display){ - ctx.fillStyle = this.textColor; - ctx.font = this.font; - each(this.yLabels,function(labelString,index){ - var yLabelCenter = this.endPoint - (yLabelGap * index), - linePositionY = Math.round(yLabelCenter), - drawHorizontalLine = this.showHorizontalLines; - - ctx.textAlign = "right"; - ctx.textBaseline = "middle"; - if (this.showLabels){ - ctx.fillText(labelString,xStart - 10,yLabelCenter); - } - - // This is X axis, so draw it - if (index === 0 && !drawHorizontalLine){ - drawHorizontalLine = true; - } - - if (drawHorizontalLine){ - ctx.beginPath(); - } - - if (index > 0){ - // This is a grid line in the centre, so drop that - ctx.lineWidth = this.gridLineWidth; - ctx.strokeStyle = this.gridLineColor; - } else { - // This is the first line on the scale - ctx.lineWidth = this.lineWidth; - ctx.strokeStyle = this.lineColor; - } - - linePositionY += helpers.aliasPixel(ctx.lineWidth); - - if(drawHorizontalLine){ - ctx.moveTo(xStart, linePositionY); - ctx.lineTo(this.width, linePositionY); - ctx.stroke(); - ctx.closePath(); - } - - ctx.lineWidth = this.lineWidth; - ctx.strokeStyle = this.lineColor; - ctx.beginPath(); - ctx.moveTo(xStart - 5, linePositionY); - ctx.lineTo(xStart, linePositionY); - ctx.stroke(); - ctx.closePath(); - - },this); - - each(this.xLabels,function(label,index){ - var xPos = this.calculateX(index) + aliasPixel(this.lineWidth), - // Check to see if line/bar here and decide where to place the line - linePos = this.calculateX(index - (this.offsetGridLines ? 0.5 : 0)) + aliasPixel(this.lineWidth), - isRotated = (this.xLabelRotation > 0), - drawVerticalLine = this.showVerticalLines; - - // This is Y axis, so draw it - if (index === 0 && !drawVerticalLine){ - drawVerticalLine = true; - } - - if (drawVerticalLine){ - ctx.beginPath(); - } - - if (index > 0){ - // This is a grid line in the centre, so drop that - ctx.lineWidth = this.gridLineWidth; - ctx.strokeStyle = this.gridLineColor; - } else { - // This is the first line on the scale - ctx.lineWidth = this.lineWidth; - ctx.strokeStyle = this.lineColor; - } - - if (drawVerticalLine){ - ctx.moveTo(linePos,this.endPoint); - ctx.lineTo(linePos,this.startPoint - 3); - ctx.stroke(); - ctx.closePath(); - } - - - ctx.lineWidth = this.lineWidth; - ctx.strokeStyle = this.lineColor; - - - // Small lines at the bottom of the base grid line - ctx.beginPath(); - ctx.moveTo(linePos,this.endPoint); - ctx.lineTo(linePos,this.endPoint + 5); - ctx.stroke(); - ctx.closePath(); - - ctx.save(); - ctx.translate(xPos,(isRotated) ? this.endPoint + 12 : this.endPoint + 8); - ctx.rotate(toRadians(this.xLabelRotation)*-1); - ctx.font = this.font; - ctx.textAlign = (isRotated) ? "right" : "center"; - ctx.textBaseline = (isRotated) ? "middle" : "top"; - ctx.fillText(label, 0, 0); - ctx.restore(); - },this); - - } - } - - }); - - Chart.RadialScale = Chart.Element.extend({ - initialize: function(){ - this.size = min([this.height, this.width]); - this.drawingArea = (this.display) ? (this.size/2) - (this.fontSize/2 + this.backdropPaddingY) : (this.size/2); - }, - calculateCenterOffset: function(value){ - // Take into account half font size + the yPadding of the top value - var scalingFactor = this.drawingArea / (this.max - this.min); - - return (value - this.min) * scalingFactor; - }, - update : function(){ - if (!this.lineArc){ - this.setScaleSize(); - } else { - this.drawingArea = (this.display) ? (this.size/2) - (this.fontSize/2 + this.backdropPaddingY) : (this.size/2); - } - this.buildYLabels(); - }, - buildYLabels: function(){ - this.yLabels = []; - - var stepDecimalPlaces = getDecimalPlaces(this.stepValue); - - for (var i=0; i<=this.steps; i++){ - this.yLabels.push(template(this.templateString,{value:(this.min + (i * this.stepValue)).toFixed(stepDecimalPlaces)})); - } - }, - getCircumference : function(){ - return ((Math.PI*2) / this.valuesCount); - }, - setScaleSize: function(){ - /* - * Right, this is really confusing and there is a lot of maths going on here - * The gist of the problem is here: https://gist.github.com/nnnick/696cc9c55f4b0beb8fe9 - * - * Reaction: https://dl.dropboxusercontent.com/u/34601363/toomuchscience.gif - * - * Solution: - * - * We assume the radius of the polygon is half the size of the canvas at first - * at each index we check if the text overlaps. - * - * Where it does, we store that angle and that index. - * - * After finding the largest index and angle we calculate how much we need to remove - * from the shape radius to move the point inwards by that x. - * - * We average the left and right distances to get the maximum shape radius that can fit in the box - * along with labels. - * - * Once we have that, we can find the centre point for the chart, by taking the x text protrusion - * on each side, removing that from the size, halving it and adding the left x protrusion width. - * - * This will mean we have a shape fitted to the canvas, as large as it can be with the labels - * and position it in the most space efficient manner - * - * https://dl.dropboxusercontent.com/u/34601363/yeahscience.gif - */ - - - // Get maximum radius of the polygon. Either half the height (minus the text width) or half the width. - // Use this to calculate the offset + change. - Make sure L/R protrusion is at least 0 to stop issues with centre points - var largestPossibleRadius = min([(this.height/2 - this.pointLabelFontSize - 5), this.width/2]), - pointPosition, - i, - textWidth, - halfTextWidth, - furthestRight = this.width, - furthestRightIndex, - furthestRightAngle, - furthestLeft = 0, - furthestLeftIndex, - furthestLeftAngle, - xProtrusionLeft, - xProtrusionRight, - radiusReductionRight, - radiusReductionLeft, - maxWidthRadius; - this.ctx.font = fontString(this.pointLabelFontSize,this.pointLabelFontStyle,this.pointLabelFontFamily); - for (i=0;i furthestRight) { - furthestRight = pointPosition.x + halfTextWidth; - furthestRightIndex = i; - } - if (pointPosition.x - halfTextWidth < furthestLeft) { - furthestLeft = pointPosition.x - halfTextWidth; - furthestLeftIndex = i; - } - } - else if (i < this.valuesCount/2) { - // Less than half the values means we'll left align the text - if (pointPosition.x + textWidth > furthestRight) { - furthestRight = pointPosition.x + textWidth; - furthestRightIndex = i; - } - } - else if (i > this.valuesCount/2){ - // More than half the values means we'll right align the text - if (pointPosition.x - textWidth < furthestLeft) { - furthestLeft = pointPosition.x - textWidth; - furthestLeftIndex = i; - } - } - } - - xProtrusionLeft = furthestLeft; - - xProtrusionRight = Math.ceil(furthestRight - this.width); - - furthestRightAngle = this.getIndexAngle(furthestRightIndex); - - furthestLeftAngle = this.getIndexAngle(furthestLeftIndex); - - radiusReductionRight = xProtrusionRight / Math.sin(furthestRightAngle + Math.PI/2); - - radiusReductionLeft = xProtrusionLeft / Math.sin(furthestLeftAngle + Math.PI/2); - - // Ensure we actually need to reduce the size of the chart - radiusReductionRight = (isNumber(radiusReductionRight)) ? radiusReductionRight : 0; - radiusReductionLeft = (isNumber(radiusReductionLeft)) ? radiusReductionLeft : 0; - - this.drawingArea = largestPossibleRadius - (radiusReductionLeft + radiusReductionRight)/2; - - //this.drawingArea = min([maxWidthRadius, (this.height - (2 * (this.pointLabelFontSize + 5)))/2]) - this.setCenterPoint(radiusReductionLeft, radiusReductionRight); - - }, - setCenterPoint: function(leftMovement, rightMovement){ - - var maxRight = this.width - rightMovement - this.drawingArea, - maxLeft = leftMovement + this.drawingArea; - - this.xCenter = (maxLeft + maxRight)/2; - // Always vertically in the centre as the text height doesn't change - this.yCenter = (this.height/2); - }, - - getIndexAngle : function(index){ - var angleMultiplier = (Math.PI * 2) / this.valuesCount; - // Start from the top instead of right, so remove a quarter of the circle - - return index * angleMultiplier - (Math.PI/2); - }, - getPointPosition : function(index, distanceFromCenter){ - var thisAngle = this.getIndexAngle(index); - return { - x : (Math.cos(thisAngle) * distanceFromCenter) + this.xCenter, - y : (Math.sin(thisAngle) * distanceFromCenter) + this.yCenter - }; - }, - draw: function(){ - if (this.display){ - var ctx = this.ctx; - each(this.yLabels, function(label, index){ - // Don't draw a centre value - if (index > 0){ - var yCenterOffset = index * (this.drawingArea/this.steps), - yHeight = this.yCenter - yCenterOffset, - pointPosition; - - // Draw circular lines around the scale - if (this.lineWidth > 0){ - ctx.strokeStyle = this.lineColor; - ctx.lineWidth = this.lineWidth; - - if(this.lineArc){ - ctx.beginPath(); - ctx.arc(this.xCenter, this.yCenter, yCenterOffset, 0, Math.PI*2); - ctx.closePath(); - ctx.stroke(); - } else{ - ctx.beginPath(); - for (var i=0;i= 0; i--) { - if (this.angleLineWidth > 0){ - var outerPosition = this.getPointPosition(i, this.calculateCenterOffset(this.max)); - ctx.beginPath(); - ctx.moveTo(this.xCenter, this.yCenter); - ctx.lineTo(outerPosition.x, outerPosition.y); - ctx.stroke(); - ctx.closePath(); - } - // Extra 3px out for some label spacing - var pointLabelPosition = this.getPointPosition(i, this.calculateCenterOffset(this.max) + 5); - ctx.font = fontString(this.pointLabelFontSize,this.pointLabelFontStyle,this.pointLabelFontFamily); - ctx.fillStyle = this.pointLabelFontColor; - - var labelsCount = this.labels.length, - halfLabelsCount = this.labels.length/2, - quarterLabelsCount = halfLabelsCount/2, - upperHalf = (i < quarterLabelsCount || i > labelsCount - quarterLabelsCount), - exactQuarter = (i === quarterLabelsCount || i === labelsCount - quarterLabelsCount); - if (i === 0){ - ctx.textAlign = 'center'; - } else if(i === halfLabelsCount){ - ctx.textAlign = 'center'; - } else if (i < halfLabelsCount){ - ctx.textAlign = 'left'; - } else { - ctx.textAlign = 'right'; - } - - // Set the correct text baseline based on outer positioning - if (exactQuarter){ - ctx.textBaseline = 'middle'; - } else if (upperHalf){ - ctx.textBaseline = 'bottom'; - } else { - ctx.textBaseline = 'top'; - } - - ctx.fillText(this.labels[i], pointLabelPosition.x, pointLabelPosition.y); - } - } - } - } - }); - - // Attach global event to resize each chart instance when the browser resizes - helpers.addEvent(window, "resize", (function(){ - // Basic debounce of resize function so it doesn't hurt performance when resizing browser. - var timeout; - return function(){ - clearTimeout(timeout); - timeout = setTimeout(function(){ - each(Chart.instances,function(instance){ - // If the responsive flag is set in the chart instance config - // Cascade the resize event down to the chart. - if (instance.options.responsive){ - instance.resize(instance.render, true); - } - }); - }, 50); - }; - })()); - - - if (amd) { - define(function(){ - return Chart; - }); - } else if (typeof module === 'object' && module.exports) { - module.exports = Chart; - } - - root.Chart = Chart; - - Chart.noConflict = function(){ - root.Chart = previous; - return Chart; - }; - -}).call(this); - -(function(){ - "use strict"; - - var root = this, - Chart = root.Chart, - helpers = Chart.helpers; - - - var defaultConfig = { - //Boolean - Whether the scale should start at zero, or an order of magnitude down from the lowest value - scaleBeginAtZero : true, - - //Boolean - Whether grid lines are shown across the chart - scaleShowGridLines : true, - - //String - Colour of the grid lines - scaleGridLineColor : "rgba(0,0,0,.05)", - - //Number - Width of the grid lines - scaleGridLineWidth : 1, - - //Boolean - Whether to show horizontal lines (except X axis) - scaleShowHorizontalLines: true, - - //Boolean - Whether to show vertical lines (except Y axis) - scaleShowVerticalLines: true, - - //Boolean - If there is a stroke on each bar - barShowStroke : true, - - //Number - Pixel width of the bar stroke - barStrokeWidth : 2, - - //Number - Spacing between each of the X value sets - barValueSpacing : 5, - - //Number - Spacing between data sets within X values - barDatasetSpacing : 1, - - //String - A legend template - legendTemplate : "
    -legend\"><% for (var i=0; i
  • \"><%if(datasets[i].label){%><%=datasets[i].label%><%}%>
  • <%}%>
" - - }; - - - Chart.Type.extend({ - name: "Bar", - defaults : defaultConfig, - initialize: function(data){ - - //Expose options as a scope variable here so we can access it in the ScaleClass - var options = this.options; - - this.ScaleClass = Chart.Scale.extend({ - offsetGridLines : true, - calculateBarX : function(datasetCount, datasetIndex, barIndex){ - //Reusable method for calculating the xPosition of a given bar based on datasetIndex & width of the bar - var xWidth = this.calculateBaseWidth(), - xAbsolute = this.calculateX(barIndex) - (xWidth/2), - barWidth = this.calculateBarWidth(datasetCount); - - return xAbsolute + (barWidth * datasetIndex) + (datasetIndex * options.barDatasetSpacing) + barWidth/2; - }, - calculateBaseWidth : function(){ - return (this.calculateX(1) - this.calculateX(0)) - (2*options.barValueSpacing); - }, - calculateBarWidth : function(datasetCount){ - //The padding between datasets is to the right of each bar, providing that there are more than 1 dataset - var baseWidth = this.calculateBaseWidth() - ((datasetCount - 1) * options.barDatasetSpacing); - - return (baseWidth / datasetCount); - } - }); - - this.datasets = []; - - //Set up tooltip events on the chart - if (this.options.showTooltips){ - helpers.bindEvents(this, this.options.tooltipEvents, function(evt){ - var activeBars = (evt.type !== 'mouseout') ? this.getBarsAtEvent(evt) : []; - - this.eachBars(function(bar){ - bar.restore(['fillColor', 'strokeColor']); - }); - helpers.each(activeBars, function(activeBar){ - activeBar.fillColor = activeBar.highlightFill; - activeBar.strokeColor = activeBar.highlightStroke; - }); - this.showTooltip(activeBars); - }); - } - - //Declare the extension of the default point, to cater for the options passed in to the constructor - this.BarClass = Chart.Rectangle.extend({ - strokeWidth : this.options.barStrokeWidth, - showStroke : this.options.barShowStroke, - ctx : this.chart.ctx - }); - - //Iterate through each of the datasets, and build this into a property of the chart - helpers.each(data.datasets,function(dataset,datasetIndex){ - - var datasetObject = { - label : dataset.label || null, - fillColor : dataset.fillColor, - strokeColor : dataset.strokeColor, - bars : [] - }; - - this.datasets.push(datasetObject); - - helpers.each(dataset.data,function(dataPoint,index){ - //Add a new point for each piece of data, passing any required data to draw. - datasetObject.bars.push(new this.BarClass({ - value : dataPoint, - label : data.labels[index], - datasetLabel: dataset.label, - strokeColor : dataset.strokeColor, - fillColor : dataset.fillColor, - highlightFill : dataset.highlightFill || dataset.fillColor, - highlightStroke : dataset.highlightStroke || dataset.strokeColor - })); - },this); - - },this); - - this.buildScale(data.labels); - - this.BarClass.prototype.base = this.scale.endPoint; - - this.eachBars(function(bar, index, datasetIndex){ - helpers.extend(bar, { - width : this.scale.calculateBarWidth(this.datasets.length), - x: this.scale.calculateBarX(this.datasets.length, datasetIndex, index), - y: this.scale.endPoint - }); - bar.save(); - }, this); - - this.render(); - }, - update : function(){ - this.scale.update(); - // Reset any highlight colours before updating. - helpers.each(this.activeElements, function(activeElement){ - activeElement.restore(['fillColor', 'strokeColor']); - }); - - this.eachBars(function(bar){ - bar.save(); - }); - this.render(); - }, - eachBars : function(callback){ - helpers.each(this.datasets,function(dataset, datasetIndex){ - helpers.each(dataset.bars, callback, this, datasetIndex); - },this); - }, - getBarsAtEvent : function(e){ - var barsArray = [], - eventPosition = helpers.getRelativePosition(e), - datasetIterator = function(dataset){ - barsArray.push(dataset.bars[barIndex]); - }, - barIndex; - - for (var datasetIndex = 0; datasetIndex < this.datasets.length; datasetIndex++) { - for (barIndex = 0; barIndex < this.datasets[datasetIndex].bars.length; barIndex++) { - if (this.datasets[datasetIndex].bars[barIndex].inRange(eventPosition.x,eventPosition.y)){ - helpers.each(this.datasets, datasetIterator); - return barsArray; - } - } - } - - return barsArray; - }, - buildScale : function(labels){ - var self = this; - - var dataTotal = function(){ - var values = []; - self.eachBars(function(bar){ - values.push(bar.value); - }); - return values; - }; - - var scaleOptions = { - templateString : this.options.scaleLabel, - height : this.chart.height, - width : this.chart.width, - ctx : this.chart.ctx, - textColor : this.options.scaleFontColor, - fontSize : this.options.scaleFontSize, - fontStyle : this.options.scaleFontStyle, - fontFamily : this.options.scaleFontFamily, - valuesCount : labels.length, - beginAtZero : this.options.scaleBeginAtZero, - integersOnly : this.options.scaleIntegersOnly, - calculateYRange: function(currentHeight){ - var updatedRanges = helpers.calculateScaleRange( - dataTotal(), - currentHeight, - this.fontSize, - this.beginAtZero, - this.integersOnly - ); - helpers.extend(this, updatedRanges); - }, - xLabels : labels, - font : helpers.fontString(this.options.scaleFontSize, this.options.scaleFontStyle, this.options.scaleFontFamily), - lineWidth : this.options.scaleLineWidth, - lineColor : this.options.scaleLineColor, - showHorizontalLines : this.options.scaleShowHorizontalLines, - showVerticalLines : this.options.scaleShowVerticalLines, - gridLineWidth : (this.options.scaleShowGridLines) ? this.options.scaleGridLineWidth : 0, - gridLineColor : (this.options.scaleShowGridLines) ? this.options.scaleGridLineColor : "rgba(0,0,0,0)", - padding : (this.options.showScale) ? 0 : (this.options.barShowStroke) ? this.options.barStrokeWidth : 0, - showLabels : this.options.scaleShowLabels, - display : this.options.showScale - }; - - if (this.options.scaleOverride){ - helpers.extend(scaleOptions, { - calculateYRange: helpers.noop, - steps: this.options.scaleSteps, - stepValue: this.options.scaleStepWidth, - min: this.options.scaleStartValue, - max: this.options.scaleStartValue + (this.options.scaleSteps * this.options.scaleStepWidth) - }); - } - - this.scale = new this.ScaleClass(scaleOptions); - }, - addData : function(valuesArray,label){ - //Map the values array for each of the datasets - helpers.each(valuesArray,function(value,datasetIndex){ - //Add a new point for each piece of data, passing any required data to draw. - this.datasets[datasetIndex].bars.push(new this.BarClass({ - value : value, - label : label, - x: this.scale.calculateBarX(this.datasets.length, datasetIndex, this.scale.valuesCount+1), - y: this.scale.endPoint, - width : this.scale.calculateBarWidth(this.datasets.length), - base : this.scale.endPoint, - strokeColor : this.datasets[datasetIndex].strokeColor, - fillColor : this.datasets[datasetIndex].fillColor - })); - },this); - - this.scale.addXLabel(label); - //Then re-render the chart. - this.update(); - }, - removeData : function(){ - this.scale.removeXLabel(); - //Then re-render the chart. - helpers.each(this.datasets,function(dataset){ - dataset.bars.shift(); - },this); - this.update(); - }, - reflow : function(){ - helpers.extend(this.BarClass.prototype,{ - y: this.scale.endPoint, - base : this.scale.endPoint - }); - var newScaleProps = helpers.extend({ - height : this.chart.height, - width : this.chart.width - }); - this.scale.update(newScaleProps); - }, - draw : function(ease){ - var easingDecimal = ease || 1; - this.clear(); - - var ctx = this.chart.ctx; - - this.scale.draw(easingDecimal); - - //Draw all the bars for each dataset - helpers.each(this.datasets,function(dataset,datasetIndex){ - helpers.each(dataset.bars,function(bar,index){ - if (bar.hasValue()){ - bar.base = this.scale.endPoint; - //Transition then draw - bar.transition({ - x : this.scale.calculateBarX(this.datasets.length, datasetIndex, index), - y : this.scale.calculateY(bar.value), - width : this.scale.calculateBarWidth(this.datasets.length) - }, easingDecimal).draw(); - } - },this); - - },this); - } - }); - - -}).call(this); - -(function(){ - "use strict"; - - var root = this, - Chart = root.Chart, - //Cache a local reference to Chart.helpers - helpers = Chart.helpers; - - var defaultConfig = { - //Boolean - Whether we should show a stroke on each segment - segmentShowStroke : true, - - //String - The colour of each segment stroke - segmentStrokeColor : "#fff", - - //Number - The width of each segment stroke - segmentStrokeWidth : 2, - - //The percentage of the chart that we cut out of the middle. - percentageInnerCutout : 50, - - //Number - Amount of animation steps - animationSteps : 100, - - //String - Animation easing effect - animationEasing : "easeOutBounce", - - //Boolean - Whether we animate the rotation of the Doughnut - animateRotate : true, - - //Boolean - Whether we animate scaling the Doughnut from the centre - animateScale : false, - - //String - A legend template - legendTemplate : "
    -legend\"><% for (var i=0; i
  • \"><%if(segments[i].label){%><%=segments[i].label%><%}%>
  • <%}%>
" - - }; - - - Chart.Type.extend({ - //Passing in a name registers this chart in the Chart namespace - name: "Doughnut", - //Providing a defaults will also register the deafults in the chart namespace - defaults : defaultConfig, - //Initialize is fired when the chart is initialized - Data is passed in as a parameter - //Config is automatically merged by the core of Chart.js, and is available at this.options - initialize: function(data){ - - //Declare segments as a static property to prevent inheriting across the Chart type prototype - this.segments = []; - this.outerRadius = (helpers.min([this.chart.width,this.chart.height]) - this.options.segmentStrokeWidth/2)/2; - - this.SegmentArc = Chart.Arc.extend({ - ctx : this.chart.ctx, - x : this.chart.width/2, - y : this.chart.height/2 - }); - - //Set up tooltip events on the chart - if (this.options.showTooltips){ - helpers.bindEvents(this, this.options.tooltipEvents, function(evt){ - var activeSegments = (evt.type !== 'mouseout') ? this.getSegmentsAtEvent(evt) : []; - - helpers.each(this.segments,function(segment){ - segment.restore(["fillColor"]); - }); - helpers.each(activeSegments,function(activeSegment){ - activeSegment.fillColor = activeSegment.highlightColor; - }); - this.showTooltip(activeSegments); - }); - } - this.calculateTotal(data); - - helpers.each(data,function(datapoint, index){ - this.addData(datapoint, index, true); - },this); - - this.render(); - }, - getSegmentsAtEvent : function(e){ - var segmentsArray = []; - - var location = helpers.getRelativePosition(e); - - helpers.each(this.segments,function(segment){ - if (segment.inRange(location.x,location.y)) segmentsArray.push(segment); - },this); - return segmentsArray; - }, - addData : function(segment, atIndex, silent){ - var index = atIndex || this.segments.length; - this.segments.splice(index, 0, new this.SegmentArc({ - value : segment.value, - outerRadius : (this.options.animateScale) ? 0 : this.outerRadius, - innerRadius : (this.options.animateScale) ? 0 : (this.outerRadius/100) * this.options.percentageInnerCutout, - fillColor : segment.color, - highlightColor : segment.highlight || segment.color, - showStroke : this.options.segmentShowStroke, - strokeWidth : this.options.segmentStrokeWidth, - strokeColor : this.options.segmentStrokeColor, - startAngle : Math.PI * 1.5, - circumference : (this.options.animateRotate) ? 0 : this.calculateCircumference(segment.value), - label : segment.label - })); - if (!silent){ - this.reflow(); - this.update(); - } - }, - calculateCircumference : function(value){ - return (Math.PI*2)*(Math.abs(value) / this.total); - }, - calculateTotal : function(data){ - this.total = 0; - helpers.each(data,function(segment){ - this.total += Math.abs(segment.value); - },this); - }, - update : function(){ - this.calculateTotal(this.segments); - - // Reset any highlight colours before updating. - helpers.each(this.activeElements, function(activeElement){ - activeElement.restore(['fillColor']); - }); - - helpers.each(this.segments,function(segment){ - segment.save(); - }); - this.render(); - }, - - removeData: function(atIndex){ - var indexToDelete = (helpers.isNumber(atIndex)) ? atIndex : this.segments.length-1; - this.segments.splice(indexToDelete, 1); - this.reflow(); - this.update(); - }, - - reflow : function(){ - helpers.extend(this.SegmentArc.prototype,{ - x : this.chart.width/2, - y : this.chart.height/2 - }); - this.outerRadius = (helpers.min([this.chart.width,this.chart.height]) - this.options.segmentStrokeWidth/2)/2; - helpers.each(this.segments, function(segment){ - segment.update({ - outerRadius : this.outerRadius, - innerRadius : (this.outerRadius/100) * this.options.percentageInnerCutout - }); - }, this); - }, - draw : function(easeDecimal){ - var animDecimal = (easeDecimal) ? easeDecimal : 1; - this.clear(); - helpers.each(this.segments,function(segment,index){ - segment.transition({ - circumference : this.calculateCircumference(segment.value), - outerRadius : this.outerRadius, - innerRadius : (this.outerRadius/100) * this.options.percentageInnerCutout - },animDecimal); - - segment.endAngle = segment.startAngle + segment.circumference; - - segment.draw(); - if (index === 0){ - segment.startAngle = Math.PI * 1.5; - } - //Check to see if it's the last segment, if not get the next and update the start angle - if (index < this.segments.length-1){ - this.segments[index+1].startAngle = segment.endAngle; - } - },this); - - } - }); - - Chart.types.Doughnut.extend({ - name : "Pie", - defaults : helpers.merge(defaultConfig,{percentageInnerCutout : 0}) - }); - -}).call(this); -(function(){ - "use strict"; - - var root = this, - Chart = root.Chart, - helpers = Chart.helpers; - - var defaultConfig = { - - ///Boolean - Whether grid lines are shown across the chart - scaleShowGridLines : true, - - //String - Colour of the grid lines - scaleGridLineColor : "rgba(0,0,0,.05)", - - //Number - Width of the grid lines - scaleGridLineWidth : 1, - - //Boolean - Whether to show horizontal lines (except X axis) - scaleShowHorizontalLines: true, - - //Boolean - Whether to show vertical lines (except Y axis) - scaleShowVerticalLines: true, - - //Boolean - Whether the line is curved between points - bezierCurve : true, - - //Number - Tension of the bezier curve between points - bezierCurveTension : 0.4, - - //Boolean - Whether to show a dot for each point - pointDot : true, - - //Number - Radius of each point dot in pixels - pointDotRadius : 4, - - //Number - Pixel width of point dot stroke - pointDotStrokeWidth : 1, - - //Number - amount extra to add to the radius to cater for hit detection outside the drawn point - pointHitDetectionRadius : 20, - - //Boolean - Whether to show a stroke for datasets - datasetStroke : true, - - //Number - Pixel width of dataset stroke - datasetStrokeWidth : 2, - - //Boolean - Whether to fill the dataset with a colour - datasetFill : true, - - //String - A legend template - legendTemplate : "
    -legend\"><% for (var i=0; i
  • \"><%if(datasets[i].label){%><%=datasets[i].label%><%}%>
  • <%}%>
" - - }; - - - Chart.Type.extend({ - name: "Line", - defaults : defaultConfig, - initialize: function(data){ - //Declare the extension of the default point, to cater for the options passed in to the constructor - this.PointClass = Chart.Point.extend({ - strokeWidth : this.options.pointDotStrokeWidth, - radius : this.options.pointDotRadius, - display: this.options.pointDot, - hitDetectionRadius : this.options.pointHitDetectionRadius, - ctx : this.chart.ctx, - inRange : function(mouseX){ - return (Math.pow(mouseX-this.x, 2) < Math.pow(this.radius + this.hitDetectionRadius,2)); - } - }); - - this.datasets = []; - - //Set up tooltip events on the chart - if (this.options.showTooltips){ - helpers.bindEvents(this, this.options.tooltipEvents, function(evt){ - var activePoints = (evt.type !== 'mouseout') ? this.getPointsAtEvent(evt) : []; - this.eachPoints(function(point){ - point.restore(['fillColor', 'strokeColor']); - }); - helpers.each(activePoints, function(activePoint){ - activePoint.fillColor = activePoint.highlightFill; - activePoint.strokeColor = activePoint.highlightStroke; - }); - this.showTooltip(activePoints); - }); - } - - //Iterate through each of the datasets, and build this into a property of the chart - helpers.each(data.datasets,function(dataset){ - - var datasetObject = { - label : dataset.label || null, - fillColor : dataset.fillColor, - strokeColor : dataset.strokeColor, - pointColor : dataset.pointColor, - pointStrokeColor : dataset.pointStrokeColor, - points : [] - }; - - this.datasets.push(datasetObject); - - - helpers.each(dataset.data,function(dataPoint,index){ - //Add a new point for each piece of data, passing any required data to draw. - datasetObject.points.push(new this.PointClass({ - value : dataPoint, - label : data.labels[index], - datasetLabel: dataset.label, - strokeColor : dataset.pointStrokeColor, - fillColor : dataset.pointColor, - highlightFill : dataset.pointHighlightFill || dataset.pointColor, - highlightStroke : dataset.pointHighlightStroke || dataset.pointStrokeColor - })); - },this); - - this.buildScale(data.labels); - - - this.eachPoints(function(point, index){ - helpers.extend(point, { - x: this.scale.calculateX(index), - y: this.scale.endPoint - }); - point.save(); - }, this); - - },this); - - - this.render(); - }, - update : function(){ - this.scale.update(); - // Reset any highlight colours before updating. - helpers.each(this.activeElements, function(activeElement){ - activeElement.restore(['fillColor', 'strokeColor']); - }); - this.eachPoints(function(point){ - point.save(); - }); - this.render(); - }, - eachPoints : function(callback){ - helpers.each(this.datasets,function(dataset){ - helpers.each(dataset.points,callback,this); - },this); - }, - getPointsAtEvent : function(e){ - var pointsArray = [], - eventPosition = helpers.getRelativePosition(e); - helpers.each(this.datasets,function(dataset){ - helpers.each(dataset.points,function(point){ - if (point.inRange(eventPosition.x,eventPosition.y)) pointsArray.push(point); - }); - },this); - return pointsArray; - }, - buildScale : function(labels){ - var self = this; - - var dataTotal = function(){ - var values = []; - self.eachPoints(function(point){ - values.push(point.value); - }); - - return values; - }; - - var scaleOptions = { - templateString : this.options.scaleLabel, - height : this.chart.height, - width : this.chart.width, - ctx : this.chart.ctx, - textColor : this.options.scaleFontColor, - fontSize : this.options.scaleFontSize, - fontStyle : this.options.scaleFontStyle, - fontFamily : this.options.scaleFontFamily, - valuesCount : labels.length, - beginAtZero : this.options.scaleBeginAtZero, - integersOnly : this.options.scaleIntegersOnly, - calculateYRange : function(currentHeight){ - var updatedRanges = helpers.calculateScaleRange( - dataTotal(), - currentHeight, - this.fontSize, - this.beginAtZero, - this.integersOnly - ); - helpers.extend(this, updatedRanges); - }, - xLabels : labels, - font : helpers.fontString(this.options.scaleFontSize, this.options.scaleFontStyle, this.options.scaleFontFamily), - lineWidth : this.options.scaleLineWidth, - lineColor : this.options.scaleLineColor, - showHorizontalLines : this.options.scaleShowHorizontalLines, - showVerticalLines : this.options.scaleShowVerticalLines, - gridLineWidth : (this.options.scaleShowGridLines) ? this.options.scaleGridLineWidth : 0, - gridLineColor : (this.options.scaleShowGridLines) ? this.options.scaleGridLineColor : "rgba(0,0,0,0)", - padding: (this.options.showScale) ? 0 : this.options.pointDotRadius + this.options.pointDotStrokeWidth, - showLabels : this.options.scaleShowLabels, - display : this.options.showScale - }; - - if (this.options.scaleOverride){ - helpers.extend(scaleOptions, { - calculateYRange: helpers.noop, - steps: this.options.scaleSteps, - stepValue: this.options.scaleStepWidth, - min: this.options.scaleStartValue, - max: this.options.scaleStartValue + (this.options.scaleSteps * this.options.scaleStepWidth) - }); - } - - - this.scale = new Chart.Scale(scaleOptions); - }, - addData : function(valuesArray,label){ - //Map the values array for each of the datasets - - helpers.each(valuesArray,function(value,datasetIndex){ - //Add a new point for each piece of data, passing any required data to draw. - this.datasets[datasetIndex].points.push(new this.PointClass({ - value : value, - label : label, - x: this.scale.calculateX(this.scale.valuesCount+1), - y: this.scale.endPoint, - strokeColor : this.datasets[datasetIndex].pointStrokeColor, - fillColor : this.datasets[datasetIndex].pointColor - })); - },this); - - this.scale.addXLabel(label); - //Then re-render the chart. - this.update(); - }, - removeData : function(){ - this.scale.removeXLabel(); - //Then re-render the chart. - helpers.each(this.datasets,function(dataset){ - dataset.points.shift(); - },this); - this.update(); - }, - reflow : function(){ - var newScaleProps = helpers.extend({ - height : this.chart.height, - width : this.chart.width - }); - this.scale.update(newScaleProps); - }, - draw : function(ease){ - var easingDecimal = ease || 1; - this.clear(); - - var ctx = this.chart.ctx; - - // Some helper methods for getting the next/prev points - var hasValue = function(item){ - return item.value !== null; - }, - nextPoint = function(point, collection, index){ - return helpers.findNextWhere(collection, hasValue, index) || point; - }, - previousPoint = function(point, collection, index){ - return helpers.findPreviousWhere(collection, hasValue, index) || point; - }; - - this.scale.draw(easingDecimal); - - - helpers.each(this.datasets,function(dataset){ - var pointsWithValues = helpers.where(dataset.points, hasValue); - - //Transition each point first so that the line and point drawing isn't out of sync - //We can use this extra loop to calculate the control points of this dataset also in this loop - - helpers.each(dataset.points, function(point, index){ - if (point.hasValue()){ - point.transition({ - y : this.scale.calculateY(point.value), - x : this.scale.calculateX(index) - }, easingDecimal); - } - },this); - - - // Control points need to be calculated in a seperate loop, because we need to know the current x/y of the point - // This would cause issues when there is no animation, because the y of the next point would be 0, so beziers would be skewed - if (this.options.bezierCurve){ - helpers.each(pointsWithValues, function(point, index){ - var tension = (index > 0 && index < pointsWithValues.length - 1) ? this.options.bezierCurveTension : 0; - point.controlPoints = helpers.splineCurve( - previousPoint(point, pointsWithValues, index), - point, - nextPoint(point, pointsWithValues, index), - tension - ); - - // Prevent the bezier going outside of the bounds of the graph - - // Cap puter bezier handles to the upper/lower scale bounds - if (point.controlPoints.outer.y > this.scale.endPoint){ - point.controlPoints.outer.y = this.scale.endPoint; - } - else if (point.controlPoints.outer.y < this.scale.startPoint){ - point.controlPoints.outer.y = this.scale.startPoint; - } - - // Cap inner bezier handles to the upper/lower scale bounds - if (point.controlPoints.inner.y > this.scale.endPoint){ - point.controlPoints.inner.y = this.scale.endPoint; - } - else if (point.controlPoints.inner.y < this.scale.startPoint){ - point.controlPoints.inner.y = this.scale.startPoint; - } - },this); - } - - - //Draw the line between all the points - ctx.lineWidth = this.options.datasetStrokeWidth; - ctx.strokeStyle = dataset.strokeColor; - ctx.beginPath(); - - helpers.each(pointsWithValues, function(point, index){ - if (index === 0){ - ctx.moveTo(point.x, point.y); - } - else{ - if(this.options.bezierCurve){ - var previous = previousPoint(point, pointsWithValues, index); - - ctx.bezierCurveTo( - previous.controlPoints.outer.x, - previous.controlPoints.outer.y, - point.controlPoints.inner.x, - point.controlPoints.inner.y, - point.x, - point.y - ); - } - else{ - ctx.lineTo(point.x,point.y); - } - } - }, this); - - ctx.stroke(); - - if (this.options.datasetFill && pointsWithValues.length > 0){ - //Round off the line by going to the base of the chart, back to the start, then fill. - ctx.lineTo(pointsWithValues[pointsWithValues.length - 1].x, this.scale.endPoint); - ctx.lineTo(pointsWithValues[0].x, this.scale.endPoint); - ctx.fillStyle = dataset.fillColor; - ctx.closePath(); - ctx.fill(); - } - - //Now draw the points over the line - //A little inefficient double looping, but better than the line - //lagging behind the point positions - helpers.each(pointsWithValues,function(point){ - point.draw(); - }); - },this); - } - }); - - -}).call(this); - -(function(){ - "use strict"; - - var root = this, - Chart = root.Chart, - //Cache a local reference to Chart.helpers - helpers = Chart.helpers; - - var defaultConfig = { - //Boolean - Show a backdrop to the scale label - scaleShowLabelBackdrop : true, - - //String - The colour of the label backdrop - scaleBackdropColor : "rgba(255,255,255,0.75)", - - // Boolean - Whether the scale should begin at zero - scaleBeginAtZero : true, - - //Number - The backdrop padding above & below the label in pixels - scaleBackdropPaddingY : 2, - - //Number - The backdrop padding to the side of the label in pixels - scaleBackdropPaddingX : 2, - - //Boolean - Show line for each value in the scale - scaleShowLine : true, - - //Boolean - Stroke a line around each segment in the chart - segmentShowStroke : true, - - //String - The colour of the stroke on each segement. - segmentStrokeColor : "#fff", - - //Number - The width of the stroke value in pixels - segmentStrokeWidth : 2, - - //Number - Amount of animation steps - animationSteps : 100, - - //String - Animation easing effect. - animationEasing : "easeOutBounce", - - //Boolean - Whether to animate the rotation of the chart - animateRotate : true, - - //Boolean - Whether to animate scaling the chart from the centre - animateScale : false, - - //String - A legend template - legendTemplate : "
    -legend\"><% for (var i=0; i
  • \"><%if(segments[i].label){%><%=segments[i].label%><%}%>
  • <%}%>
" - }; - - - Chart.Type.extend({ - //Passing in a name registers this chart in the Chart namespace - name: "PolarArea", - //Providing a defaults will also register the deafults in the chart namespace - defaults : defaultConfig, - //Initialize is fired when the chart is initialized - Data is passed in as a parameter - //Config is automatically merged by the core of Chart.js, and is available at this.options - initialize: function(data){ - this.segments = []; - //Declare segment class as a chart instance specific class, so it can share props for this instance - this.SegmentArc = Chart.Arc.extend({ - showStroke : this.options.segmentShowStroke, - strokeWidth : this.options.segmentStrokeWidth, - strokeColor : this.options.segmentStrokeColor, - ctx : this.chart.ctx, - innerRadius : 0, - x : this.chart.width/2, - y : this.chart.height/2 - }); - this.scale = new Chart.RadialScale({ - display: this.options.showScale, - fontStyle: this.options.scaleFontStyle, - fontSize: this.options.scaleFontSize, - fontFamily: this.options.scaleFontFamily, - fontColor: this.options.scaleFontColor, - showLabels: this.options.scaleShowLabels, - showLabelBackdrop: this.options.scaleShowLabelBackdrop, - backdropColor: this.options.scaleBackdropColor, - backdropPaddingY : this.options.scaleBackdropPaddingY, - backdropPaddingX: this.options.scaleBackdropPaddingX, - lineWidth: (this.options.scaleShowLine) ? this.options.scaleLineWidth : 0, - lineColor: this.options.scaleLineColor, - lineArc: true, - width: this.chart.width, - height: this.chart.height, - xCenter: this.chart.width/2, - yCenter: this.chart.height/2, - ctx : this.chart.ctx, - templateString: this.options.scaleLabel, - valuesCount: data.length - }); - - this.updateScaleRange(data); - - this.scale.update(); - - helpers.each(data,function(segment,index){ - this.addData(segment,index,true); - },this); - - //Set up tooltip events on the chart - if (this.options.showTooltips){ - helpers.bindEvents(this, this.options.tooltipEvents, function(evt){ - var activeSegments = (evt.type !== 'mouseout') ? this.getSegmentsAtEvent(evt) : []; - helpers.each(this.segments,function(segment){ - segment.restore(["fillColor"]); - }); - helpers.each(activeSegments,function(activeSegment){ - activeSegment.fillColor = activeSegment.highlightColor; - }); - this.showTooltip(activeSegments); - }); - } - - this.render(); - }, - getSegmentsAtEvent : function(e){ - var segmentsArray = []; - - var location = helpers.getRelativePosition(e); - - helpers.each(this.segments,function(segment){ - if (segment.inRange(location.x,location.y)) segmentsArray.push(segment); - },this); - return segmentsArray; - }, - addData : function(segment, atIndex, silent){ - var index = atIndex || this.segments.length; - - this.segments.splice(index, 0, new this.SegmentArc({ - fillColor: segment.color, - highlightColor: segment.highlight || segment.color, - label: segment.label, - value: segment.value, - outerRadius: (this.options.animateScale) ? 0 : this.scale.calculateCenterOffset(segment.value), - circumference: (this.options.animateRotate) ? 0 : this.scale.getCircumference(), - startAngle: Math.PI * 1.5 - })); - if (!silent){ - this.reflow(); - this.update(); - } - }, - removeData: function(atIndex){ - var indexToDelete = (helpers.isNumber(atIndex)) ? atIndex : this.segments.length-1; - this.segments.splice(indexToDelete, 1); - this.reflow(); - this.update(); - }, - calculateTotal: function(data){ - this.total = 0; - helpers.each(data,function(segment){ - this.total += segment.value; - },this); - this.scale.valuesCount = this.segments.length; - }, - updateScaleRange: function(datapoints){ - var valuesArray = []; - helpers.each(datapoints,function(segment){ - valuesArray.push(segment.value); - }); - - var scaleSizes = (this.options.scaleOverride) ? - { - steps: this.options.scaleSteps, - stepValue: this.options.scaleStepWidth, - min: this.options.scaleStartValue, - max: this.options.scaleStartValue + (this.options.scaleSteps * this.options.scaleStepWidth) - } : - helpers.calculateScaleRange( - valuesArray, - helpers.min([this.chart.width, this.chart.height])/2, - this.options.scaleFontSize, - this.options.scaleBeginAtZero, - this.options.scaleIntegersOnly - ); - - helpers.extend( - this.scale, - scaleSizes, - { - size: helpers.min([this.chart.width, this.chart.height]), - xCenter: this.chart.width/2, - yCenter: this.chart.height/2 - } - ); - - }, - update : function(){ - this.calculateTotal(this.segments); - - helpers.each(this.segments,function(segment){ - segment.save(); - }); - - this.reflow(); - this.render(); - }, - reflow : function(){ - helpers.extend(this.SegmentArc.prototype,{ - x : this.chart.width/2, - y : this.chart.height/2 - }); - this.updateScaleRange(this.segments); - this.scale.update(); - - helpers.extend(this.scale,{ - xCenter: this.chart.width/2, - yCenter: this.chart.height/2 - }); - - helpers.each(this.segments, function(segment){ - segment.update({ - outerRadius : this.scale.calculateCenterOffset(segment.value) - }); - }, this); - - }, - draw : function(ease){ - var easingDecimal = ease || 1; - //Clear & draw the canvas - this.clear(); - helpers.each(this.segments,function(segment, index){ - segment.transition({ - circumference : this.scale.getCircumference(), - outerRadius : this.scale.calculateCenterOffset(segment.value) - },easingDecimal); - - segment.endAngle = segment.startAngle + segment.circumference; - - // If we've removed the first segment we need to set the first one to - // start at the top. - if (index === 0){ - segment.startAngle = Math.PI * 1.5; - } - - //Check to see if it's the last segment, if not get the next and update the start angle - if (index < this.segments.length - 1){ - this.segments[index+1].startAngle = segment.endAngle; - } - segment.draw(); - }, this); - this.scale.draw(); - } - }); - -}).call(this); -(function(){ - "use strict"; - - var root = this, - Chart = root.Chart, - helpers = Chart.helpers; - - - - Chart.Type.extend({ - name: "Radar", - defaults:{ - //Boolean - Whether to show lines for each scale point - scaleShowLine : true, - - //Boolean - Whether we show the angle lines out of the radar - angleShowLineOut : true, - - //Boolean - Whether to show labels on the scale - scaleShowLabels : false, - - // Boolean - Whether the scale should begin at zero - scaleBeginAtZero : true, - - //String - Colour of the angle line - angleLineColor : "rgba(0,0,0,.1)", - - //Number - Pixel width of the angle line - angleLineWidth : 1, - - //String - Point label font declaration - pointLabelFontFamily : "'Arial'", - - //String - Point label font weight - pointLabelFontStyle : "normal", - - //Number - Point label font size in pixels - pointLabelFontSize : 10, - - //String - Point label font colour - pointLabelFontColor : "#666", - - //Boolean - Whether to show a dot for each point - pointDot : true, - - //Number - Radius of each point dot in pixels - pointDotRadius : 3, - - //Number - Pixel width of point dot stroke - pointDotStrokeWidth : 1, - - //Number - amount extra to add to the radius to cater for hit detection outside the drawn point - pointHitDetectionRadius : 20, - - //Boolean - Whether to show a stroke for datasets - datasetStroke : true, - - //Number - Pixel width of dataset stroke - datasetStrokeWidth : 2, - - //Boolean - Whether to fill the dataset with a colour - datasetFill : true, - - //String - A legend template - legendTemplate : "
    -legend\"><% for (var i=0; i
  • \"><%if(datasets[i].label){%><%=datasets[i].label%><%}%>
  • <%}%>
" - - }, - - initialize: function(data){ - this.PointClass = Chart.Point.extend({ - strokeWidth : this.options.pointDotStrokeWidth, - radius : this.options.pointDotRadius, - display: this.options.pointDot, - hitDetectionRadius : this.options.pointHitDetectionRadius, - ctx : this.chart.ctx - }); - - this.datasets = []; - - this.buildScale(data); - - //Set up tooltip events on the chart - if (this.options.showTooltips){ - helpers.bindEvents(this, this.options.tooltipEvents, function(evt){ - var activePointsCollection = (evt.type !== 'mouseout') ? this.getPointsAtEvent(evt) : []; - - this.eachPoints(function(point){ - point.restore(['fillColor', 'strokeColor']); - }); - helpers.each(activePointsCollection, function(activePoint){ - activePoint.fillColor = activePoint.highlightFill; - activePoint.strokeColor = activePoint.highlightStroke; - }); - - this.showTooltip(activePointsCollection); - }); - } - - //Iterate through each of the datasets, and build this into a property of the chart - helpers.each(data.datasets,function(dataset){ - - var datasetObject = { - label: dataset.label || null, - fillColor : dataset.fillColor, - strokeColor : dataset.strokeColor, - pointColor : dataset.pointColor, - pointStrokeColor : dataset.pointStrokeColor, - points : [] - }; - - this.datasets.push(datasetObject); - - helpers.each(dataset.data,function(dataPoint,index){ - //Add a new point for each piece of data, passing any required data to draw. - var pointPosition; - if (!this.scale.animation){ - pointPosition = this.scale.getPointPosition(index, this.scale.calculateCenterOffset(dataPoint)); - } - datasetObject.points.push(new this.PointClass({ - value : dataPoint, - label : data.labels[index], - datasetLabel: dataset.label, - x: (this.options.animation) ? this.scale.xCenter : pointPosition.x, - y: (this.options.animation) ? this.scale.yCenter : pointPosition.y, - strokeColor : dataset.pointStrokeColor, - fillColor : dataset.pointColor, - highlightFill : dataset.pointHighlightFill || dataset.pointColor, - highlightStroke : dataset.pointHighlightStroke || dataset.pointStrokeColor - })); - },this); - - },this); - - this.render(); - }, - eachPoints : function(callback){ - helpers.each(this.datasets,function(dataset){ - helpers.each(dataset.points,callback,this); - },this); - }, - - getPointsAtEvent : function(evt){ - var mousePosition = helpers.getRelativePosition(evt), - fromCenter = helpers.getAngleFromPoint({ - x: this.scale.xCenter, - y: this.scale.yCenter - }, mousePosition); - - var anglePerIndex = (Math.PI * 2) /this.scale.valuesCount, - pointIndex = Math.round((fromCenter.angle - Math.PI * 1.5) / anglePerIndex), - activePointsCollection = []; - - // If we're at the top, make the pointIndex 0 to get the first of the array. - if (pointIndex >= this.scale.valuesCount || pointIndex < 0){ - pointIndex = 0; - } - - if (fromCenter.distance <= this.scale.drawingArea){ - helpers.each(this.datasets, function(dataset){ - activePointsCollection.push(dataset.points[pointIndex]); - }); - } - - return activePointsCollection; - }, - - buildScale : function(data){ - this.scale = new Chart.RadialScale({ - display: this.options.showScale, - fontStyle: this.options.scaleFontStyle, - fontSize: this.options.scaleFontSize, - fontFamily: this.options.scaleFontFamily, - fontColor: this.options.scaleFontColor, - showLabels: this.options.scaleShowLabels, - showLabelBackdrop: this.options.scaleShowLabelBackdrop, - backdropColor: this.options.scaleBackdropColor, - backdropPaddingY : this.options.scaleBackdropPaddingY, - backdropPaddingX: this.options.scaleBackdropPaddingX, - lineWidth: (this.options.scaleShowLine) ? this.options.scaleLineWidth : 0, - lineColor: this.options.scaleLineColor, - angleLineColor : this.options.angleLineColor, - angleLineWidth : (this.options.angleShowLineOut) ? this.options.angleLineWidth : 0, - // Point labels at the edge of each line - pointLabelFontColor : this.options.pointLabelFontColor, - pointLabelFontSize : this.options.pointLabelFontSize, - pointLabelFontFamily : this.options.pointLabelFontFamily, - pointLabelFontStyle : this.options.pointLabelFontStyle, - height : this.chart.height, - width: this.chart.width, - xCenter: this.chart.width/2, - yCenter: this.chart.height/2, - ctx : this.chart.ctx, - templateString: this.options.scaleLabel, - labels: data.labels, - valuesCount: data.datasets[0].data.length - }); - - this.scale.setScaleSize(); - this.updateScaleRange(data.datasets); - this.scale.buildYLabels(); - }, - updateScaleRange: function(datasets){ - var valuesArray = (function(){ - var totalDataArray = []; - helpers.each(datasets,function(dataset){ - if (dataset.data){ - totalDataArray = totalDataArray.concat(dataset.data); - } - else { - helpers.each(dataset.points, function(point){ - totalDataArray.push(point.value); - }); - } - }); - return totalDataArray; - })(); - - - var scaleSizes = (this.options.scaleOverride) ? - { - steps: this.options.scaleSteps, - stepValue: this.options.scaleStepWidth, - min: this.options.scaleStartValue, - max: this.options.scaleStartValue + (this.options.scaleSteps * this.options.scaleStepWidth) - } : - helpers.calculateScaleRange( - valuesArray, - helpers.min([this.chart.width, this.chart.height])/2, - this.options.scaleFontSize, - this.options.scaleBeginAtZero, - this.options.scaleIntegersOnly - ); - - helpers.extend( - this.scale, - scaleSizes - ); - - }, - addData : function(valuesArray,label){ - //Map the values array for each of the datasets - this.scale.valuesCount++; - helpers.each(valuesArray,function(value,datasetIndex){ - var pointPosition = this.scale.getPointPosition(this.scale.valuesCount, this.scale.calculateCenterOffset(value)); - this.datasets[datasetIndex].points.push(new this.PointClass({ - value : value, - label : label, - x: pointPosition.x, - y: pointPosition.y, - strokeColor : this.datasets[datasetIndex].pointStrokeColor, - fillColor : this.datasets[datasetIndex].pointColor - })); - },this); - - this.scale.labels.push(label); - - this.reflow(); - - this.update(); - }, - removeData : function(){ - this.scale.valuesCount--; - this.scale.labels.shift(); - helpers.each(this.datasets,function(dataset){ - dataset.points.shift(); - },this); - this.reflow(); - this.update(); - }, - update : function(){ - this.eachPoints(function(point){ - point.save(); - }); - this.reflow(); - this.render(); - }, - reflow: function(){ - helpers.extend(this.scale, { - width : this.chart.width, - height: this.chart.height, - size : helpers.min([this.chart.width, this.chart.height]), - xCenter: this.chart.width/2, - yCenter: this.chart.height/2 - }); - this.updateScaleRange(this.datasets); - this.scale.setScaleSize(); - this.scale.buildYLabels(); - }, - draw : function(ease){ - var easeDecimal = ease || 1, - ctx = this.chart.ctx; - this.clear(); - this.scale.draw(); - - helpers.each(this.datasets,function(dataset){ - - //Transition each point first so that the line and point drawing isn't out of sync - helpers.each(dataset.points,function(point,index){ - if (point.hasValue()){ - point.transition(this.scale.getPointPosition(index, this.scale.calculateCenterOffset(point.value)), easeDecimal); - } - },this); - - - - //Draw the line between all the points - ctx.lineWidth = this.options.datasetStrokeWidth; - ctx.strokeStyle = dataset.strokeColor; - ctx.beginPath(); - helpers.each(dataset.points,function(point,index){ - if (index === 0){ - ctx.moveTo(point.x,point.y); - } - else{ - ctx.lineTo(point.x,point.y); - } - },this); - ctx.closePath(); - ctx.stroke(); - - ctx.fillStyle = dataset.fillColor; - ctx.fill(); - - //Now draw the points over the line - //A little inefficient double looping, but better than the line - //lagging behind the point positions - helpers.each(dataset.points,function(point){ - if (point.hasValue()){ - point.draw(); - } - }); - - },this); - - } - - }); - - - - - -}).call(this); \ No newline at end of file diff --git a/BuildFeed/Scripts/Chart.min.js b/BuildFeed/Scripts/Chart.min.js deleted file mode 100644 index 3a0a2c8..0000000 --- a/BuildFeed/Scripts/Chart.min.js +++ /dev/null @@ -1,11 +0,0 @@ -/*! - * Chart.js - * http://chartjs.org/ - * Version: 1.0.2 - * - * Copyright 2015 Nick Downie - * Released under the MIT license - * https://github.com/nnnick/Chart.js/blob/master/LICENSE.md - */ -(function(){"use strict";var t=this,i=t.Chart,e=function(t){this.canvas=t.canvas,this.ctx=t;var i=function(t,i){return t["offset"+i]?t["offset"+i]:document.defaultView.getComputedStyle(t).getPropertyValue(i)},e=this.width=i(t.canvas,"Width"),n=this.height=i(t.canvas,"Height");t.canvas.width=e,t.canvas.height=n;var e=this.width=t.canvas.width,n=this.height=t.canvas.height;return this.aspectRatio=this.width/this.height,s.retinaScale(this),this};e.defaults={global:{animation:!0,animationSteps:60,animationEasing:"easeOutQuart",showScale:!0,scaleOverride:!1,scaleSteps:null,scaleStepWidth:null,scaleStartValue:null,scaleLineColor:"rgba(0,0,0,.1)",scaleLineWidth:1,scaleShowLabels:!0,scaleLabel:"<%=value%>",scaleIntegersOnly:!0,scaleBeginAtZero:!1,scaleFontFamily:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",scaleFontSize:12,scaleFontStyle:"normal",scaleFontColor:"#666",responsive:!1,maintainAspectRatio:!0,showTooltips:!0,customTooltips:!1,tooltipEvents:["mousemove","touchstart","touchmove","mouseout"],tooltipFillColor:"rgba(0,0,0,0.8)",tooltipFontFamily:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",tooltipFontSize:14,tooltipFontStyle:"normal",tooltipFontColor:"#fff",tooltipTitleFontFamily:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",tooltipTitleFontSize:14,tooltipTitleFontStyle:"bold",tooltipTitleFontColor:"#fff",tooltipYPadding:6,tooltipXPadding:6,tooltipCaretSize:8,tooltipCornerRadius:6,tooltipXOffset:10,tooltipTemplate:"<%if (label){%><%=label%>: <%}%><%= value %>",multiTooltipTemplate:"<%= value %>",multiTooltipKeyBackground:"#fff",onAnimationProgress:function(){},onAnimationComplete:function(){}}},e.types={};var s=e.helpers={},n=s.each=function(t,i,e){var s=Array.prototype.slice.call(arguments,3);if(t)if(t.length===+t.length){var n;for(n=0;n=0;s--){var n=t[s];if(i(n))return n}},s.inherits=function(t){var i=this,e=t&&t.hasOwnProperty("constructor")?t.constructor:function(){return i.apply(this,arguments)},s=function(){this.constructor=e};return s.prototype=i.prototype,e.prototype=new s,e.extend=r,t&&a(e.prototype,t),e.__super__=i.prototype,e}),c=s.noop=function(){},u=s.uid=function(){var t=0;return function(){return"chart-"+t++}}(),d=s.warn=function(t){window.console&&"function"==typeof window.console.warn&&console.warn(t)},p=s.amd="function"==typeof define&&define.amd,f=s.isNumber=function(t){return!isNaN(parseFloat(t))&&isFinite(t)},g=s.max=function(t){return Math.max.apply(Math,t)},m=s.min=function(t){return Math.min.apply(Math,t)},v=(s.cap=function(t,i,e){if(f(i)){if(t>i)return i}else if(f(e)&&e>t)return e;return t},s.getDecimalPlaces=function(t){return t%1!==0&&f(t)?t.toString().split(".")[1].length:0}),S=s.radians=function(t){return t*(Math.PI/180)},x=(s.getAngleFromPoint=function(t,i){var e=i.x-t.x,s=i.y-t.y,n=Math.sqrt(e*e+s*s),o=2*Math.PI+Math.atan2(s,e);return 0>e&&0>s&&(o+=2*Math.PI),{angle:o,distance:n}},s.aliasPixel=function(t){return t%2===0?0:.5}),y=(s.splineCurve=function(t,i,e,s){var n=Math.sqrt(Math.pow(i.x-t.x,2)+Math.pow(i.y-t.y,2)),o=Math.sqrt(Math.pow(e.x-i.x,2)+Math.pow(e.y-i.y,2)),a=s*n/(n+o),h=s*o/(n+o);return{inner:{x:i.x-a*(e.x-t.x),y:i.y-a*(e.y-t.y)},outer:{x:i.x+h*(e.x-t.x),y:i.y+h*(e.y-t.y)}}},s.calculateOrderOfMagnitude=function(t){return Math.floor(Math.log(t)/Math.LN10)}),C=(s.calculateScaleRange=function(t,i,e,s,n){var o=2,a=Math.floor(i/(1.5*e)),h=o>=a,l=g(t),r=m(t);l===r&&(l+=.5,r>=.5&&!s?r-=.5:l+=.5);for(var c=Math.abs(l-r),u=y(c),d=Math.ceil(l/(1*Math.pow(10,u)))*Math.pow(10,u),p=s?0:Math.floor(r/(1*Math.pow(10,u)))*Math.pow(10,u),f=d-p,v=Math.pow(10,u),S=Math.round(f/v);(S>a||a>2*S)&&!h;)if(S>a)v*=2,S=Math.round(f/v),S%1!==0&&(h=!0);else if(n&&u>=0){if(v/2%1!==0)break;v/=2,S=Math.round(f/v)}else v/=2,S=Math.round(f/v);return h&&(S=o,v=f/S),{steps:S,stepValue:v,min:p,max:p+S*v}},s.template=function(t,i){function e(t,i){var e=/\W/.test(t)?new Function("obj","var p=[],print=function(){p.push.apply(p,arguments);};with(obj){p.push('"+t.replace(/[\r\t\n]/g," ").split("<%").join(" ").replace(/((^|%>)[^\t]*)'/g,"$1\r").replace(/\t=(.*?)%>/g,"',$1,'").split(" ").join("');").split("%>").join("p.push('").split("\r").join("\\'")+"');}return p.join('');"):s[t]=s[t];return i?e(i):e}if(t instanceof Function)return t(i);var s={};return e(t,i)}),w=(s.generateLabels=function(t,i,e,s){var o=new Array(i);return labelTemplateString&&n(o,function(i,n){o[n]=C(t,{value:e+s*(n+1)})}),o},s.easingEffects={linear:function(t){return t},easeInQuad:function(t){return t*t},easeOutQuad:function(t){return-1*t*(t-2)},easeInOutQuad:function(t){return(t/=.5)<1?.5*t*t:-0.5*(--t*(t-2)-1)},easeInCubic:function(t){return t*t*t},easeOutCubic:function(t){return 1*((t=t/1-1)*t*t+1)},easeInOutCubic:function(t){return(t/=.5)<1?.5*t*t*t:.5*((t-=2)*t*t+2)},easeInQuart:function(t){return t*t*t*t},easeOutQuart:function(t){return-1*((t=t/1-1)*t*t*t-1)},easeInOutQuart:function(t){return(t/=.5)<1?.5*t*t*t*t:-0.5*((t-=2)*t*t*t-2)},easeInQuint:function(t){return 1*(t/=1)*t*t*t*t},easeOutQuint:function(t){return 1*((t=t/1-1)*t*t*t*t+1)},easeInOutQuint:function(t){return(t/=.5)<1?.5*t*t*t*t*t:.5*((t-=2)*t*t*t*t+2)},easeInSine:function(t){return-1*Math.cos(t/1*(Math.PI/2))+1},easeOutSine:function(t){return 1*Math.sin(t/1*(Math.PI/2))},easeInOutSine:function(t){return-0.5*(Math.cos(Math.PI*t/1)-1)},easeInExpo:function(t){return 0===t?1:1*Math.pow(2,10*(t/1-1))},easeOutExpo:function(t){return 1===t?1:1*(-Math.pow(2,-10*t/1)+1)},easeInOutExpo:function(t){return 0===t?0:1===t?1:(t/=.5)<1?.5*Math.pow(2,10*(t-1)):.5*(-Math.pow(2,-10*--t)+2)},easeInCirc:function(t){return t>=1?t:-1*(Math.sqrt(1-(t/=1)*t)-1)},easeOutCirc:function(t){return 1*Math.sqrt(1-(t=t/1-1)*t)},easeInOutCirc:function(t){return(t/=.5)<1?-0.5*(Math.sqrt(1-t*t)-1):.5*(Math.sqrt(1-(t-=2)*t)+1)},easeInElastic:function(t){var i=1.70158,e=0,s=1;return 0===t?0:1==(t/=1)?1:(e||(e=.3),st?-.5*s*Math.pow(2,10*(t-=1))*Math.sin(2*(1*t-i)*Math.PI/e):s*Math.pow(2,-10*(t-=1))*Math.sin(2*(1*t-i)*Math.PI/e)*.5+1)},easeInBack:function(t){var i=1.70158;return 1*(t/=1)*t*((i+1)*t-i)},easeOutBack:function(t){var i=1.70158;return 1*((t=t/1-1)*t*((i+1)*t+i)+1)},easeInOutBack:function(t){var i=1.70158;return(t/=.5)<1?.5*t*t*(((i*=1.525)+1)*t-i):.5*((t-=2)*t*(((i*=1.525)+1)*t+i)+2)},easeInBounce:function(t){return 1-w.easeOutBounce(1-t)},easeOutBounce:function(t){return(t/=1)<1/2.75?7.5625*t*t:2/2.75>t?1*(7.5625*(t-=1.5/2.75)*t+.75):2.5/2.75>t?1*(7.5625*(t-=2.25/2.75)*t+.9375):1*(7.5625*(t-=2.625/2.75)*t+.984375)},easeInOutBounce:function(t){return.5>t?.5*w.easeInBounce(2*t):.5*w.easeOutBounce(2*t-1)+.5}}),b=s.requestAnimFrame=function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(t){return window.setTimeout(t,1e3/60)}}(),P=s.cancelAnimFrame=function(){return window.cancelAnimationFrame||window.webkitCancelAnimationFrame||window.mozCancelAnimationFrame||window.oCancelAnimationFrame||window.msCancelAnimationFrame||function(t){return window.clearTimeout(t,1e3/60)}}(),L=(s.animationLoop=function(t,i,e,s,n,o){var a=0,h=w[e]||w.linear,l=function(){a++;var e=a/i,r=h(e);t.call(o,r,e,a),s.call(o,r,e),i>a?o.animationFrame=b(l):n.apply(o)};b(l)},s.getRelativePosition=function(t){var i,e,s=t.originalEvent||t,n=t.currentTarget||t.srcElement,o=n.getBoundingClientRect();return s.touches?(i=s.touches[0].clientX-o.left,e=s.touches[0].clientY-o.top):(i=s.clientX-o.left,e=s.clientY-o.top),{x:i,y:e}},s.addEvent=function(t,i,e){t.addEventListener?t.addEventListener(i,e):t.attachEvent?t.attachEvent("on"+i,e):t["on"+i]=e}),k=s.removeEvent=function(t,i,e){t.removeEventListener?t.removeEventListener(i,e,!1):t.detachEvent?t.detachEvent("on"+i,e):t["on"+i]=c},F=(s.bindEvents=function(t,i,e){t.events||(t.events={}),n(i,function(i){t.events[i]=function(){e.apply(t,arguments)},L(t.chart.canvas,i,t.events[i])})},s.unbindEvents=function(t,i){n(i,function(i,e){k(t.chart.canvas,e,i)})}),R=s.getMaximumWidth=function(t){var i=t.parentNode;return i.clientWidth},T=s.getMaximumHeight=function(t){var i=t.parentNode;return i.clientHeight},A=(s.getMaximumSize=s.getMaximumWidth,s.retinaScale=function(t){var i=t.ctx,e=t.canvas.width,s=t.canvas.height;window.devicePixelRatio&&(i.canvas.style.width=e+"px",i.canvas.style.height=s+"px",i.canvas.height=s*window.devicePixelRatio,i.canvas.width=e*window.devicePixelRatio,i.scale(window.devicePixelRatio,window.devicePixelRatio))}),M=s.clear=function(t){t.ctx.clearRect(0,0,t.width,t.height)},W=s.fontString=function(t,i,e){return i+" "+t+"px "+e},z=s.longestText=function(t,i,e){t.font=i;var s=0;return n(e,function(i){var e=t.measureText(i).width;s=e>s?e:s}),s},B=s.drawRoundedRectangle=function(t,i,e,s,n,o){t.beginPath(),t.moveTo(i+o,e),t.lineTo(i+s-o,e),t.quadraticCurveTo(i+s,e,i+s,e+o),t.lineTo(i+s,e+n-o),t.quadraticCurveTo(i+s,e+n,i+s-o,e+n),t.lineTo(i+o,e+n),t.quadraticCurveTo(i,e+n,i,e+n-o),t.lineTo(i,e+o),t.quadraticCurveTo(i,e,i+o,e),t.closePath()};e.instances={},e.Type=function(t,i,s){this.options=i,this.chart=s,this.id=u(),e.instances[this.id]=this,i.responsive&&this.resize(),this.initialize.call(this,t)},a(e.Type.prototype,{initialize:function(){return this},clear:function(){return M(this.chart),this},stop:function(){return P(this.animationFrame),this},resize:function(t){this.stop();var i=this.chart.canvas,e=R(this.chart.canvas),s=this.options.maintainAspectRatio?e/this.chart.aspectRatio:T(this.chart.canvas);return i.width=this.chart.width=e,i.height=this.chart.height=s,A(this.chart),"function"==typeof t&&t.apply(this,Array.prototype.slice.call(arguments,1)),this},reflow:c,render:function(t){return t&&this.reflow(),this.options.animation&&!t?s.animationLoop(this.draw,this.options.animationSteps,this.options.animationEasing,this.options.onAnimationProgress,this.options.onAnimationComplete,this):(this.draw(),this.options.onAnimationComplete.call(this)),this},generateLegend:function(){return C(this.options.legendTemplate,this)},destroy:function(){this.clear(),F(this,this.events);var t=this.chart.canvas;t.width=this.chart.width,t.height=this.chart.height,t.style.removeProperty?(t.style.removeProperty("width"),t.style.removeProperty("height")):(t.style.removeAttribute("width"),t.style.removeAttribute("height")),delete e.instances[this.id]},showTooltip:function(t,i){"undefined"==typeof this.activeElements&&(this.activeElements=[]);var o=function(t){var i=!1;return t.length!==this.activeElements.length?i=!0:(n(t,function(t,e){t!==this.activeElements[e]&&(i=!0)},this),i)}.call(this,t);if(o||i){if(this.activeElements=t,this.draw(),this.options.customTooltips&&this.options.customTooltips(!1),t.length>0)if(this.datasets&&this.datasets.length>1){for(var a,h,r=this.datasets.length-1;r>=0&&(a=this.datasets[r].points||this.datasets[r].bars||this.datasets[r].segments,h=l(a,t[0]),-1===h);r--);var c=[],u=[],d=function(){var t,i,e,n,o,a=[],l=[],r=[];return s.each(this.datasets,function(i){t=i.points||i.bars||i.segments,t[h]&&t[h].hasValue()&&a.push(t[h])}),s.each(a,function(t){l.push(t.x),r.push(t.y),c.push(s.template(this.options.multiTooltipTemplate,t)),u.push({fill:t._saved.fillColor||t.fillColor,stroke:t._saved.strokeColor||t.strokeColor})},this),o=m(r),e=g(r),n=m(l),i=g(l),{x:n>this.chart.width/2?n:i,y:(o+e)/2}}.call(this,h);new e.MultiTooltip({x:d.x,y:d.y,xPadding:this.options.tooltipXPadding,yPadding:this.options.tooltipYPadding,xOffset:this.options.tooltipXOffset,fillColor:this.options.tooltipFillColor,textColor:this.options.tooltipFontColor,fontFamily:this.options.tooltipFontFamily,fontStyle:this.options.tooltipFontStyle,fontSize:this.options.tooltipFontSize,titleTextColor:this.options.tooltipTitleFontColor,titleFontFamily:this.options.tooltipTitleFontFamily,titleFontStyle:this.options.tooltipTitleFontStyle,titleFontSize:this.options.tooltipTitleFontSize,cornerRadius:this.options.tooltipCornerRadius,labels:c,legendColors:u,legendColorBackground:this.options.multiTooltipKeyBackground,title:t[0].label,chart:this.chart,ctx:this.chart.ctx,custom:this.options.customTooltips}).draw()}else n(t,function(t){var i=t.tooltipPosition();new e.Tooltip({x:Math.round(i.x),y:Math.round(i.y),xPadding:this.options.tooltipXPadding,yPadding:this.options.tooltipYPadding,fillColor:this.options.tooltipFillColor,textColor:this.options.tooltipFontColor,fontFamily:this.options.tooltipFontFamily,fontStyle:this.options.tooltipFontStyle,fontSize:this.options.tooltipFontSize,caretHeight:this.options.tooltipCaretSize,cornerRadius:this.options.tooltipCornerRadius,text:C(this.options.tooltipTemplate,t),chart:this.chart,custom:this.options.customTooltips}).draw()},this);return this}},toBase64Image:function(){return this.chart.canvas.toDataURL.apply(this.chart.canvas,arguments)}}),e.Type.extend=function(t){var i=this,s=function(){return i.apply(this,arguments)};if(s.prototype=o(i.prototype),a(s.prototype,t),s.extend=e.Type.extend,t.name||i.prototype.name){var n=t.name||i.prototype.name,l=e.defaults[i.prototype.name]?o(e.defaults[i.prototype.name]):{};e.defaults[n]=a(l,t.defaults),e.types[n]=s,e.prototype[n]=function(t,i){var o=h(e.defaults.global,e.defaults[n],i||{});return new s(t,o,this)}}else d("Name not provided for this chart, so it hasn't been registered");return i},e.Element=function(t){a(this,t),this.initialize.apply(this,arguments),this.save()},a(e.Element.prototype,{initialize:function(){},restore:function(t){return t?n(t,function(t){this[t]=this._saved[t]},this):a(this,this._saved),this},save:function(){return this._saved=o(this),delete this._saved._saved,this},update:function(t){return n(t,function(t,i){this._saved[i]=this[i],this[i]=t},this),this},transition:function(t,i){return n(t,function(t,e){this[e]=(t-this._saved[e])*i+this._saved[e]},this),this},tooltipPosition:function(){return{x:this.x,y:this.y}},hasValue:function(){return f(this.value)}}),e.Element.extend=r,e.Point=e.Element.extend({display:!0,inRange:function(t,i){var e=this.hitDetectionRadius+this.radius;return Math.pow(t-this.x,2)+Math.pow(i-this.y,2)=this.startAngle&&e.angle<=this.endAngle,o=e.distance>=this.innerRadius&&e.distance<=this.outerRadius;return n&&o},tooltipPosition:function(){var t=this.startAngle+(this.endAngle-this.startAngle)/2,i=(this.outerRadius-this.innerRadius)/2+this.innerRadius;return{x:this.x+Math.cos(t)*i,y:this.y+Math.sin(t)*i}},draw:function(t){var i=this.ctx;i.beginPath(),i.arc(this.x,this.y,this.outerRadius,this.startAngle,this.endAngle),i.arc(this.x,this.y,this.innerRadius,this.endAngle,this.startAngle,!0),i.closePath(),i.strokeStyle=this.strokeColor,i.lineWidth=this.strokeWidth,i.fillStyle=this.fillColor,i.fill(),i.lineJoin="bevel",this.showStroke&&i.stroke()}}),e.Rectangle=e.Element.extend({draw:function(){var t=this.ctx,i=this.width/2,e=this.x-i,s=this.x+i,n=this.base-(this.base-this.y),o=this.strokeWidth/2;this.showStroke&&(e+=o,s-=o,n+=o),t.beginPath(),t.fillStyle=this.fillColor,t.strokeStyle=this.strokeColor,t.lineWidth=this.strokeWidth,t.moveTo(e,this.base),t.lineTo(e,n),t.lineTo(s,n),t.lineTo(s,this.base),t.fill(),this.showStroke&&t.stroke()},height:function(){return this.base-this.y},inRange:function(t,i){return t>=this.x-this.width/2&&t<=this.x+this.width/2&&i>=this.y&&i<=this.base}}),e.Tooltip=e.Element.extend({draw:function(){var t=this.chart.ctx;t.font=W(this.fontSize,this.fontStyle,this.fontFamily),this.xAlign="center",this.yAlign="above";var i=this.caretPadding=2,e=t.measureText(this.text).width+2*this.xPadding,s=this.fontSize+2*this.yPadding,n=s+this.caretHeight+i;this.x+e/2>this.chart.width?this.xAlign="left":this.x-e/2<0&&(this.xAlign="right"),this.y-n<0&&(this.yAlign="below");var o=this.x-e/2,a=this.y-n;if(t.fillStyle=this.fillColor,this.custom)this.custom(this);else{switch(this.yAlign){case"above":t.beginPath(),t.moveTo(this.x,this.y-i),t.lineTo(this.x+this.caretHeight,this.y-(i+this.caretHeight)),t.lineTo(this.x-this.caretHeight,this.y-(i+this.caretHeight)),t.closePath(),t.fill();break;case"below":a=this.y+i+this.caretHeight,t.beginPath(),t.moveTo(this.x,this.y+i),t.lineTo(this.x+this.caretHeight,this.y+i+this.caretHeight),t.lineTo(this.x-this.caretHeight,this.y+i+this.caretHeight),t.closePath(),t.fill()}switch(this.xAlign){case"left":o=this.x-e+(this.cornerRadius+this.caretHeight);break;case"right":o=this.x-(this.cornerRadius+this.caretHeight)}B(t,o,a,e,s,this.cornerRadius),t.fill(),t.fillStyle=this.textColor,t.textAlign="center",t.textBaseline="middle",t.fillText(this.text,o+e/2,a+s/2)}}}),e.MultiTooltip=e.Element.extend({initialize:function(){this.font=W(this.fontSize,this.fontStyle,this.fontFamily),this.titleFont=W(this.titleFontSize,this.titleFontStyle,this.titleFontFamily),this.height=this.labels.length*this.fontSize+(this.labels.length-1)*(this.fontSize/2)+2*this.yPadding+1.5*this.titleFontSize,this.ctx.font=this.titleFont;var t=this.ctx.measureText(this.title).width,i=z(this.ctx,this.font,this.labels)+this.fontSize+3,e=g([i,t]);this.width=e+2*this.xPadding;var s=this.height/2;this.y-s<0?this.y=s:this.y+s>this.chart.height&&(this.y=this.chart.height-s),this.x>this.chart.width/2?this.x-=this.xOffset+this.width:this.x+=this.xOffset},getLineHeight:function(t){var i=this.y-this.height/2+this.yPadding,e=t-1;return 0===t?i+this.titleFontSize/2:i+(1.5*this.fontSize*e+this.fontSize/2)+1.5*this.titleFontSize},draw:function(){if(this.custom)this.custom(this);else{B(this.ctx,this.x,this.y-this.height/2,this.width,this.height,this.cornerRadius);var t=this.ctx;t.fillStyle=this.fillColor,t.fill(),t.closePath(),t.textAlign="left",t.textBaseline="middle",t.fillStyle=this.titleTextColor,t.font=this.titleFont,t.fillText(this.title,this.x+this.xPadding,this.getLineHeight(0)),t.font=this.font,s.each(this.labels,function(i,e){t.fillStyle=this.textColor,t.fillText(i,this.x+this.xPadding+this.fontSize+3,this.getLineHeight(e+1)),t.fillStyle=this.legendColorBackground,t.fillRect(this.x+this.xPadding,this.getLineHeight(e+1)-this.fontSize/2,this.fontSize,this.fontSize),t.fillStyle=this.legendColors[e].fill,t.fillRect(this.x+this.xPadding,this.getLineHeight(e+1)-this.fontSize/2,this.fontSize,this.fontSize)},this)}}}),e.Scale=e.Element.extend({initialize:function(){this.fit()},buildYLabels:function(){this.yLabels=[];for(var t=v(this.stepValue),i=0;i<=this.steps;i++)this.yLabels.push(C(this.templateString,{value:(this.min+i*this.stepValue).toFixed(t)}));this.yLabelWidth=this.display&&this.showLabels?z(this.ctx,this.font,this.yLabels):0},addXLabel:function(t){this.xLabels.push(t),this.valuesCount++,this.fit()},removeXLabel:function(){this.xLabels.shift(),this.valuesCount--,this.fit()},fit:function(){this.startPoint=this.display?this.fontSize:0,this.endPoint=this.display?this.height-1.5*this.fontSize-5:this.height,this.startPoint+=this.padding,this.endPoint-=this.padding;var t,i=this.endPoint-this.startPoint;for(this.calculateYRange(i),this.buildYLabels(),this.calculateXLabelRotation();i>this.endPoint-this.startPoint;)i=this.endPoint-this.startPoint,t=this.yLabelWidth,this.calculateYRange(i),this.buildYLabels(),tthis.yLabelWidth+10?e/2:this.yLabelWidth+10,this.xLabelRotation=0,this.display){var n,o=z(this.ctx,this.font,this.xLabels);this.xLabelWidth=o;for(var a=Math.floor(this.calculateX(1)-this.calculateX(0))-6;this.xLabelWidth>a&&0===this.xLabelRotation||this.xLabelWidth>a&&this.xLabelRotation<=90&&this.xLabelRotation>0;)n=Math.cos(S(this.xLabelRotation)),t=n*e,i=n*s,t+this.fontSize/2>this.yLabelWidth+8&&(this.xScalePaddingLeft=t+this.fontSize/2),this.xScalePaddingRight=this.fontSize/2,this.xLabelRotation++,this.xLabelWidth=n*o;this.xLabelRotation>0&&(this.endPoint-=Math.sin(S(this.xLabelRotation))*o+3)}else this.xLabelWidth=0,this.xScalePaddingRight=this.padding,this.xScalePaddingLeft=this.padding},calculateYRange:c,drawingArea:function(){return this.startPoint-this.endPoint},calculateY:function(t){var i=this.drawingArea()/(this.min-this.max);return this.endPoint-i*(t-this.min)},calculateX:function(t){var i=(this.xLabelRotation>0,this.width-(this.xScalePaddingLeft+this.xScalePaddingRight)),e=i/Math.max(this.valuesCount-(this.offsetGridLines?0:1),1),s=e*t+this.xScalePaddingLeft;return this.offsetGridLines&&(s+=e/2),Math.round(s)},update:function(t){s.extend(this,t),this.fit()},draw:function(){var t=this.ctx,i=(this.endPoint-this.startPoint)/this.steps,e=Math.round(this.xScalePaddingLeft);this.display&&(t.fillStyle=this.textColor,t.font=this.font,n(this.yLabels,function(n,o){var a=this.endPoint-i*o,h=Math.round(a),l=this.showHorizontalLines;t.textAlign="right",t.textBaseline="middle",this.showLabels&&t.fillText(n,e-10,a),0!==o||l||(l=!0),l&&t.beginPath(),o>0?(t.lineWidth=this.gridLineWidth,t.strokeStyle=this.gridLineColor):(t.lineWidth=this.lineWidth,t.strokeStyle=this.lineColor),h+=s.aliasPixel(t.lineWidth),l&&(t.moveTo(e,h),t.lineTo(this.width,h),t.stroke(),t.closePath()),t.lineWidth=this.lineWidth,t.strokeStyle=this.lineColor,t.beginPath(),t.moveTo(e-5,h),t.lineTo(e,h),t.stroke(),t.closePath()},this),n(this.xLabels,function(i,e){var s=this.calculateX(e)+x(this.lineWidth),n=this.calculateX(e-(this.offsetGridLines?.5:0))+x(this.lineWidth),o=this.xLabelRotation>0,a=this.showVerticalLines;0!==e||a||(a=!0),a&&t.beginPath(),e>0?(t.lineWidth=this.gridLineWidth,t.strokeStyle=this.gridLineColor):(t.lineWidth=this.lineWidth,t.strokeStyle=this.lineColor),a&&(t.moveTo(n,this.endPoint),t.lineTo(n,this.startPoint-3),t.stroke(),t.closePath()),t.lineWidth=this.lineWidth,t.strokeStyle=this.lineColor,t.beginPath(),t.moveTo(n,this.endPoint),t.lineTo(n,this.endPoint+5),t.stroke(),t.closePath(),t.save(),t.translate(s,o?this.endPoint+12:this.endPoint+8),t.rotate(-1*S(this.xLabelRotation)),t.font=this.font,t.textAlign=o?"right":"center",t.textBaseline=o?"middle":"top",t.fillText(i,0,0),t.restore()},this))}}),e.RadialScale=e.Element.extend({initialize:function(){this.size=m([this.height,this.width]),this.drawingArea=this.display?this.size/2-(this.fontSize/2+this.backdropPaddingY):this.size/2},calculateCenterOffset:function(t){var i=this.drawingArea/(this.max-this.min);return(t-this.min)*i},update:function(){this.lineArc?this.drawingArea=this.display?this.size/2-(this.fontSize/2+this.backdropPaddingY):this.size/2:this.setScaleSize(),this.buildYLabels()},buildYLabels:function(){this.yLabels=[];for(var t=v(this.stepValue),i=0;i<=this.steps;i++)this.yLabels.push(C(this.templateString,{value:(this.min+i*this.stepValue).toFixed(t)}))},getCircumference:function(){return 2*Math.PI/this.valuesCount},setScaleSize:function(){var t,i,e,s,n,o,a,h,l,r,c,u,d=m([this.height/2-this.pointLabelFontSize-5,this.width/2]),p=this.width,g=0;for(this.ctx.font=W(this.pointLabelFontSize,this.pointLabelFontStyle,this.pointLabelFontFamily),i=0;ip&&(p=t.x+s,n=i),t.x-sp&&(p=t.x+e,n=i):i>this.valuesCount/2&&t.x-e0){var s,n=e*(this.drawingArea/this.steps),o=this.yCenter-n;if(this.lineWidth>0)if(t.strokeStyle=this.lineColor,t.lineWidth=this.lineWidth,this.lineArc)t.beginPath(),t.arc(this.xCenter,this.yCenter,n,0,2*Math.PI),t.closePath(),t.stroke();else{t.beginPath();for(var a=0;a=0;i--){if(this.angleLineWidth>0){var e=this.getPointPosition(i,this.calculateCenterOffset(this.max));t.beginPath(),t.moveTo(this.xCenter,this.yCenter),t.lineTo(e.x,e.y),t.stroke(),t.closePath()}var s=this.getPointPosition(i,this.calculateCenterOffset(this.max)+5);t.font=W(this.pointLabelFontSize,this.pointLabelFontStyle,this.pointLabelFontFamily),t.fillStyle=this.pointLabelFontColor;var o=this.labels.length,a=this.labels.length/2,h=a/2,l=h>i||i>o-h,r=i===h||i===o-h;t.textAlign=0===i?"center":i===a?"center":a>i?"left":"right",t.textBaseline=r?"middle":l?"bottom":"top",t.fillText(this.labels[i],s.x,s.y)}}}}}),s.addEvent(window,"resize",function(){var t;return function(){clearTimeout(t),t=setTimeout(function(){n(e.instances,function(t){t.options.responsive&&t.resize(t.render,!0)})},50)}}()),p?define(function(){return e}):"object"==typeof module&&module.exports&&(module.exports=e),t.Chart=e,e.noConflict=function(){return t.Chart=i,e}}).call(this),function(){"use strict";var t=this,i=t.Chart,e=i.helpers,s={scaleBeginAtZero:!0,scaleShowGridLines:!0,scaleGridLineColor:"rgba(0,0,0,.05)",scaleGridLineWidth:1,scaleShowHorizontalLines:!0,scaleShowVerticalLines:!0,barShowStroke:!0,barStrokeWidth:2,barValueSpacing:5,barDatasetSpacing:1,legendTemplate:'
    <% for (var i=0; i
  • <%if(datasets[i].label){%><%=datasets[i].label%><%}%>
  • <%}%>
'};i.Type.extend({name:"Bar",defaults:s,initialize:function(t){var s=this.options;this.ScaleClass=i.Scale.extend({offsetGridLines:!0,calculateBarX:function(t,i,e){var n=this.calculateBaseWidth(),o=this.calculateX(e)-n/2,a=this.calculateBarWidth(t);return o+a*i+i*s.barDatasetSpacing+a/2},calculateBaseWidth:function(){return this.calculateX(1)-this.calculateX(0)-2*s.barValueSpacing},calculateBarWidth:function(t){var i=this.calculateBaseWidth()-(t-1)*s.barDatasetSpacing;return i/t}}),this.datasets=[],this.options.showTooltips&&e.bindEvents(this,this.options.tooltipEvents,function(t){var i="mouseout"!==t.type?this.getBarsAtEvent(t):[];this.eachBars(function(t){t.restore(["fillColor","strokeColor"])}),e.each(i,function(t){t.fillColor=t.highlightFill,t.strokeColor=t.highlightStroke}),this.showTooltip(i)}),this.BarClass=i.Rectangle.extend({strokeWidth:this.options.barStrokeWidth,showStroke:this.options.barShowStroke,ctx:this.chart.ctx}),e.each(t.datasets,function(i){var s={label:i.label||null,fillColor:i.fillColor,strokeColor:i.strokeColor,bars:[]};this.datasets.push(s),e.each(i.data,function(e,n){s.bars.push(new this.BarClass({value:e,label:t.labels[n],datasetLabel:i.label,strokeColor:i.strokeColor,fillColor:i.fillColor,highlightFill:i.highlightFill||i.fillColor,highlightStroke:i.highlightStroke||i.strokeColor}))},this)},this),this.buildScale(t.labels),this.BarClass.prototype.base=this.scale.endPoint,this.eachBars(function(t,i,s){e.extend(t,{width:this.scale.calculateBarWidth(this.datasets.length),x:this.scale.calculateBarX(this.datasets.length,s,i),y:this.scale.endPoint}),t.save()},this),this.render()},update:function(){this.scale.update(),e.each(this.activeElements,function(t){t.restore(["fillColor","strokeColor"])}),this.eachBars(function(t){t.save()}),this.render()},eachBars:function(t){e.each(this.datasets,function(i,s){e.each(i.bars,t,this,s)},this)},getBarsAtEvent:function(t){for(var i,s=[],n=e.getRelativePosition(t),o=function(t){s.push(t.bars[i])},a=0;a<% for (var i=0; i
  • <%if(segments[i].label){%><%=segments[i].label%><%}%>
  • <%}%>'};i.Type.extend({name:"Doughnut",defaults:s,initialize:function(t){this.segments=[],this.outerRadius=(e.min([this.chart.width,this.chart.height])-this.options.segmentStrokeWidth/2)/2,this.SegmentArc=i.Arc.extend({ctx:this.chart.ctx,x:this.chart.width/2,y:this.chart.height/2}),this.options.showTooltips&&e.bindEvents(this,this.options.tooltipEvents,function(t){var i="mouseout"!==t.type?this.getSegmentsAtEvent(t):[];e.each(this.segments,function(t){t.restore(["fillColor"])}),e.each(i,function(t){t.fillColor=t.highlightColor}),this.showTooltip(i)}),this.calculateTotal(t),e.each(t,function(t,i){this.addData(t,i,!0)},this),this.render()},getSegmentsAtEvent:function(t){var i=[],s=e.getRelativePosition(t);return e.each(this.segments,function(t){t.inRange(s.x,s.y)&&i.push(t)},this),i},addData:function(t,i,e){var s=i||this.segments.length;this.segments.splice(s,0,new this.SegmentArc({value:t.value,outerRadius:this.options.animateScale?0:this.outerRadius,innerRadius:this.options.animateScale?0:this.outerRadius/100*this.options.percentageInnerCutout,fillColor:t.color,highlightColor:t.highlight||t.color,showStroke:this.options.segmentShowStroke,strokeWidth:this.options.segmentStrokeWidth,strokeColor:this.options.segmentStrokeColor,startAngle:1.5*Math.PI,circumference:this.options.animateRotate?0:this.calculateCircumference(t.value),label:t.label})),e||(this.reflow(),this.update())},calculateCircumference:function(t){return 2*Math.PI*(Math.abs(t)/this.total)},calculateTotal:function(t){this.total=0,e.each(t,function(t){this.total+=Math.abs(t.value)},this)},update:function(){this.calculateTotal(this.segments),e.each(this.activeElements,function(t){t.restore(["fillColor"])}),e.each(this.segments,function(t){t.save()}),this.render()},removeData:function(t){var i=e.isNumber(t)?t:this.segments.length-1;this.segments.splice(i,1),this.reflow(),this.update()},reflow:function(){e.extend(this.SegmentArc.prototype,{x:this.chart.width/2,y:this.chart.height/2}),this.outerRadius=(e.min([this.chart.width,this.chart.height])-this.options.segmentStrokeWidth/2)/2,e.each(this.segments,function(t){t.update({outerRadius:this.outerRadius,innerRadius:this.outerRadius/100*this.options.percentageInnerCutout})},this)},draw:function(t){var i=t?t:1;this.clear(),e.each(this.segments,function(t,e){t.transition({circumference:this.calculateCircumference(t.value),outerRadius:this.outerRadius,innerRadius:this.outerRadius/100*this.options.percentageInnerCutout},i),t.endAngle=t.startAngle+t.circumference,t.draw(),0===e&&(t.startAngle=1.5*Math.PI),e<% for (var i=0; i
  • <%if(datasets[i].label){%><%=datasets[i].label%><%}%>
  • <%}%>'};i.Type.extend({name:"Line",defaults:s,initialize:function(t){this.PointClass=i.Point.extend({strokeWidth:this.options.pointDotStrokeWidth,radius:this.options.pointDotRadius,display:this.options.pointDot,hitDetectionRadius:this.options.pointHitDetectionRadius,ctx:this.chart.ctx,inRange:function(t){return Math.pow(t-this.x,2)0&&ithis.scale.endPoint?t.controlPoints.outer.y=this.scale.endPoint:t.controlPoints.outer.ythis.scale.endPoint?t.controlPoints.inner.y=this.scale.endPoint:t.controlPoints.inner.y0&&(s.lineTo(h[h.length-1].x,this.scale.endPoint),s.lineTo(h[0].x,this.scale.endPoint),s.fillStyle=t.fillColor,s.closePath(),s.fill()),e.each(h,function(t){t.draw()})},this)}})}.call(this),function(){"use strict";var t=this,i=t.Chart,e=i.helpers,s={scaleShowLabelBackdrop:!0,scaleBackdropColor:"rgba(255,255,255,0.75)",scaleBeginAtZero:!0,scaleBackdropPaddingY:2,scaleBackdropPaddingX:2,scaleShowLine:!0,segmentShowStroke:!0,segmentStrokeColor:"#fff",segmentStrokeWidth:2,animationSteps:100,animationEasing:"easeOutBounce",animateRotate:!0,animateScale:!1,legendTemplate:'
      <% for (var i=0; i
    • <%if(segments[i].label){%><%=segments[i].label%><%}%>
    • <%}%>
    '};i.Type.extend({name:"PolarArea",defaults:s,initialize:function(t){this.segments=[],this.SegmentArc=i.Arc.extend({showStroke:this.options.segmentShowStroke,strokeWidth:this.options.segmentStrokeWidth,strokeColor:this.options.segmentStrokeColor,ctx:this.chart.ctx,innerRadius:0,x:this.chart.width/2,y:this.chart.height/2}),this.scale=new i.RadialScale({display:this.options.showScale,fontStyle:this.options.scaleFontStyle,fontSize:this.options.scaleFontSize,fontFamily:this.options.scaleFontFamily,fontColor:this.options.scaleFontColor,showLabels:this.options.scaleShowLabels,showLabelBackdrop:this.options.scaleShowLabelBackdrop,backdropColor:this.options.scaleBackdropColor,backdropPaddingY:this.options.scaleBackdropPaddingY,backdropPaddingX:this.options.scaleBackdropPaddingX,lineWidth:this.options.scaleShowLine?this.options.scaleLineWidth:0,lineColor:this.options.scaleLineColor,lineArc:!0,width:this.chart.width,height:this.chart.height,xCenter:this.chart.width/2,yCenter:this.chart.height/2,ctx:this.chart.ctx,templateString:this.options.scaleLabel,valuesCount:t.length}),this.updateScaleRange(t),this.scale.update(),e.each(t,function(t,i){this.addData(t,i,!0)},this),this.options.showTooltips&&e.bindEvents(this,this.options.tooltipEvents,function(t){var i="mouseout"!==t.type?this.getSegmentsAtEvent(t):[];e.each(this.segments,function(t){t.restore(["fillColor"])}),e.each(i,function(t){t.fillColor=t.highlightColor}),this.showTooltip(i)}),this.render()},getSegmentsAtEvent:function(t){var i=[],s=e.getRelativePosition(t);return e.each(this.segments,function(t){t.inRange(s.x,s.y)&&i.push(t)},this),i},addData:function(t,i,e){var s=i||this.segments.length;this.segments.splice(s,0,new this.SegmentArc({fillColor:t.color,highlightColor:t.highlight||t.color,label:t.label,value:t.value,outerRadius:this.options.animateScale?0:this.scale.calculateCenterOffset(t.value),circumference:this.options.animateRotate?0:this.scale.getCircumference(),startAngle:1.5*Math.PI})),e||(this.reflow(),this.update())},removeData:function(t){var i=e.isNumber(t)?t:this.segments.length-1;this.segments.splice(i,1),this.reflow(),this.update()},calculateTotal:function(t){this.total=0,e.each(t,function(t){this.total+=t.value},this),this.scale.valuesCount=this.segments.length},updateScaleRange:function(t){var i=[];e.each(t,function(t){i.push(t.value)});var s=this.options.scaleOverride?{steps:this.options.scaleSteps,stepValue:this.options.scaleStepWidth,min:this.options.scaleStartValue,max:this.options.scaleStartValue+this.options.scaleSteps*this.options.scaleStepWidth}:e.calculateScaleRange(i,e.min([this.chart.width,this.chart.height])/2,this.options.scaleFontSize,this.options.scaleBeginAtZero,this.options.scaleIntegersOnly);e.extend(this.scale,s,{size:e.min([this.chart.width,this.chart.height]),xCenter:this.chart.width/2,yCenter:this.chart.height/2})},update:function(){this.calculateTotal(this.segments),e.each(this.segments,function(t){t.save()}),this.reflow(),this.render()},reflow:function(){e.extend(this.SegmentArc.prototype,{x:this.chart.width/2,y:this.chart.height/2}),this.updateScaleRange(this.segments),this.scale.update(),e.extend(this.scale,{xCenter:this.chart.width/2,yCenter:this.chart.height/2}),e.each(this.segments,function(t){t.update({outerRadius:this.scale.calculateCenterOffset(t.value)})},this)},draw:function(t){var i=t||1;this.clear(),e.each(this.segments,function(t,e){t.transition({circumference:this.scale.getCircumference(),outerRadius:this.scale.calculateCenterOffset(t.value)},i),t.endAngle=t.startAngle+t.circumference,0===e&&(t.startAngle=1.5*Math.PI),e<% for (var i=0; i
  • <%if(datasets[i].label){%><%=datasets[i].label%><%}%>
  • <%}%>'},initialize:function(t){this.PointClass=i.Point.extend({strokeWidth:this.options.pointDotStrokeWidth,radius:this.options.pointDotRadius,display:this.options.pointDot,hitDetectionRadius:this.options.pointHitDetectionRadius,ctx:this.chart.ctx}),this.datasets=[],this.buildScale(t),this.options.showTooltips&&e.bindEvents(this,this.options.tooltipEvents,function(t){var i="mouseout"!==t.type?this.getPointsAtEvent(t):[];this.eachPoints(function(t){t.restore(["fillColor","strokeColor"])}),e.each(i,function(t){t.fillColor=t.highlightFill,t.strokeColor=t.highlightStroke}),this.showTooltip(i)}),e.each(t.datasets,function(i){var s={label:i.label||null,fillColor:i.fillColor,strokeColor:i.strokeColor,pointColor:i.pointColor,pointStrokeColor:i.pointStrokeColor,points:[]};this.datasets.push(s),e.each(i.data,function(e,n){var o;this.scale.animation||(o=this.scale.getPointPosition(n,this.scale.calculateCenterOffset(e))),s.points.push(new this.PointClass({value:e,label:t.labels[n],datasetLabel:i.label,x:this.options.animation?this.scale.xCenter:o.x,y:this.options.animation?this.scale.yCenter:o.y,strokeColor:i.pointStrokeColor,fillColor:i.pointColor,highlightFill:i.pointHighlightFill||i.pointColor,highlightStroke:i.pointHighlightStroke||i.pointStrokeColor}))},this)},this),this.render()},eachPoints:function(t){e.each(this.datasets,function(i){e.each(i.points,t,this)},this)},getPointsAtEvent:function(t){var i=e.getRelativePosition(t),s=e.getAngleFromPoint({x:this.scale.xCenter,y:this.scale.yCenter},i),n=2*Math.PI/this.scale.valuesCount,o=Math.round((s.angle-1.5*Math.PI)/n),a=[];return(o>=this.scale.valuesCount||0>o)&&(o=0),s.distance<=this.scale.drawingArea&&e.each(this.datasets,function(t){a.push(t.points[o])}),a},buildScale:function(t){this.scale=new i.RadialScale({display:this.options.showScale,fontStyle:this.options.scaleFontStyle,fontSize:this.options.scaleFontSize,fontFamily:this.options.scaleFontFamily,fontColor:this.options.scaleFontColor,showLabels:this.options.scaleShowLabels,showLabelBackdrop:this.options.scaleShowLabelBackdrop,backdropColor:this.options.scaleBackdropColor,backdropPaddingY:this.options.scaleBackdropPaddingY,backdropPaddingX:this.options.scaleBackdropPaddingX,lineWidth:this.options.scaleShowLine?this.options.scaleLineWidth:0,lineColor:this.options.scaleLineColor,angleLineColor:this.options.angleLineColor,angleLineWidth:this.options.angleShowLineOut?this.options.angleLineWidth:0,pointLabelFontColor:this.options.pointLabelFontColor,pointLabelFontSize:this.options.pointLabelFontSize,pointLabelFontFamily:this.options.pointLabelFontFamily,pointLabelFontStyle:this.options.pointLabelFontStyle,height:this.chart.height,width:this.chart.width,xCenter:this.chart.width/2,yCenter:this.chart.height/2,ctx:this.chart.ctx,templateString:this.options.scaleLabel,labels:t.labels,valuesCount:t.datasets[0].data.length}),this.scale.setScaleSize(),this.updateScaleRange(t.datasets),this.scale.buildYLabels()},updateScaleRange:function(t){var i=function(){var i=[];return e.each(t,function(t){t.data?i=i.concat(t.data):e.each(t.points,function(t){i.push(t.value)})}),i}(),s=this.options.scaleOverride?{steps:this.options.scaleSteps,stepValue:this.options.scaleStepWidth,min:this.options.scaleStartValue,max:this.options.scaleStartValue+this.options.scaleSteps*this.options.scaleStepWidth}:e.calculateScaleRange(i,e.min([this.chart.width,this.chart.height])/2,this.options.scaleFontSize,this.options.scaleBeginAtZero,this.options.scaleIntegersOnly);e.extend(this.scale,s)},addData:function(t,i){this.scale.valuesCount++,e.each(t,function(t,e){var s=this.scale.getPointPosition(this.scale.valuesCount,this.scale.calculateCenterOffset(t));this.datasets[e].points.push(new this.PointClass({value:t,label:i,x:s.x,y:s.y,strokeColor:this.datasets[e].pointStrokeColor,fillColor:this.datasets[e].pointColor}))},this),this.scale.labels.push(i),this.reflow(),this.update()},removeData:function(){this.scale.valuesCount--,this.scale.labels.shift(),e.each(this.datasets,function(t){t.points.shift()},this),this.reflow(),this.update()},update:function(){this.eachPoints(function(t){t.save()}),this.reflow(),this.render()},reflow:function(){e.extend(this.scale,{width:this.chart.width,height:this.chart.height,size:e.min([this.chart.width,this.chart.height]),xCenter:this.chart.width/2,yCenter:this.chart.height/2}),this.updateScaleRange(this.datasets),this.scale.setScaleSize(),this.scale.buildYLabels()},draw:function(t){var i=t||1,s=this.chart.ctx;this.clear(),this.scale.draw(),e.each(this.datasets,function(t){e.each(t.points,function(t,e){t.hasValue()&&t.transition(this.scale.getPointPosition(e,this.scale.calculateCenterOffset(t.value)),i)},this),s.lineWidth=this.options.datasetStrokeWidth,s.strokeStyle=t.strokeColor,s.beginPath(),e.each(t.points,function(t,i){0===i?s.moveTo(t.x,t.y):s.lineTo(t.x,t.y)},this),s.closePath(),s.stroke(),s.fillStyle=t.fillColor,s.fill(),e.each(t.points,function(t){t.hasValue()&&t.draw()})},this)}})}.call(this); \ No newline at end of file diff --git a/BuildFeed/Scripts/_references.js b/BuildFeed/Scripts/_references.js index c55b41b..44ee799 100644 --- a/BuildFeed/Scripts/_references.js +++ b/BuildFeed/Scripts/_references.js @@ -1,13 +1,9 @@ /// /// -/// -/// -/// /// /// /// /// -/// /// /// /// diff --git a/BuildFeed/Scripts/bfs.js b/BuildFeed/Scripts/bfs.js index f4dfae8..de87dd7 100644 --- a/BuildFeed/Scripts/bfs.js +++ b/BuildFeed/Scripts/bfs.js @@ -1,44 +1,26 @@ -var bfsAjax; -var bfsTimeout; - -$(function() { - $("#page-navigation-search").click(function(event) { - event.preventDefault(); - $("#search-modal").modal("show"); - }); - $("#search-input").keyup(function() { - $(this).parent().find(".list-group").remove(); - - if (typeof bfsTimeout != "undefined") { - clearTimeout(bfsTimeout); - } - - if (typeof bfsAjax != "undefined" && bfsAjax.readyState != 4) { - bfsAjax.abort(); - } - - bfsTimeout = setTimeout(function(object) { - bfsAjax = $.ajax("/api/GetSearchResult/" + $("#search-input").val() + "/").done(function(data) { - var template = $.templates("#result-template"); - var content = $("
    "); - - var item = template.render(data); - content.append(item); - - $("#search-results").html(content); - - $("#search-results a.list-group-item").click(function() { - ga("send", "pageview", "/api/GetSearchResult/" + $("#search-input").val() + "/"); - }); - }); - }, 200); - }); - - $("#lang-switcher a").click(function(event) { - event.preventDefault(); - var lang = $(this).data("lang"); - document.cookie = "lang=" + lang + "; expires=Fri, 31 Dec 9999 23:59:59 GMT; path=/"; - - location.reload(true); - }); -}); \ No newline at end of file +var BuildFeed; +(function (BuildFeed) { + function DropdownClick(ev) { + ev.preventDefault(); + var link = this; + var menus = link.parentElement.getElementsByClassName("dropdown-menu"); + if (menus.length > 0) { + menus[0].classList.toggle("open"); + } + } + BuildFeed.DropdownClick = DropdownClick; + function BuildFeedSetup(ev) { + var ddParents = document.getElementsByClassName("dropdown-parent"); + for (var i = 0; i < ddParents.length; i++) { + for (var j = 0; j < ddParents[i].childNodes.length; j++) { + var el = ddParents[i].childNodes[j]; + if (el.nodeName === "A") { + el.addEventListener("click", DropdownClick); + } + } + } + } + BuildFeed.BuildFeedSetup = BuildFeedSetup; +})(BuildFeed || (BuildFeed = {})); +window.addEventListener("load", BuildFeed.BuildFeedSetup); +//# sourceMappingURL=bfs.js.map \ No newline at end of file diff --git a/BuildFeed/Scripts/bfs.js.map b/BuildFeed/Scripts/bfs.js.map new file mode 100644 index 0000000..06ef0af --- /dev/null +++ b/BuildFeed/Scripts/bfs.js.map @@ -0,0 +1 @@ +{"version":3,"file":"bfs.js","sourceRoot":"","sources":["bfs.ts"],"names":[],"mappings":"AAAA,IAAO,SAAS,CAgCf;AAhCD,WAAO,SAAS,EAChB,CAAC;IACE,uBAA8B,EAAc;QAEzC,EAAE,CAAC,cAAc,EAAE,CAAC;QAEpB,IAAI,IAAI,GAAG,IAAyB,CAAC;QACrC,IAAI,KAAK,GAAG,IAAI,CAAC,aAAa,CAAC,sBAAsB,CAAC,eAAe,CAAC,CAAC;QAEvE,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CACrB,CAAC;YACE,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACrC,CAAC;IACJ,CAAC;IAXe,uBAAa,gBAW5B,CAAA;IAED,wBAA+B,EAAS;QAErC,IAAM,SAAS,GAAG,QAAQ,CAAC,sBAAsB,CAAC,iBAAiB,CAAC,CAAC;QAErE,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,EACzC,CAAC;YACE,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,EACvD,CAAC;gBACE,IAAM,EAAE,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;gBAEtC,EAAE,CAAC,CAAC,EAAE,CAAC,QAAQ,KAAK,GAAG,CAAC,CACxB,CAAC;oBACE,EAAE,CAAC,gBAAgB,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;gBAC/C,CAAC;YACJ,CAAC;QACJ,CAAC;IACJ,CAAC;IAhBe,wBAAc,iBAgB7B,CAAA;AACJ,CAAC,EAhCM,SAAS,KAAT,SAAS,QAgCf;AAED,MAAM,CAAC,gBAAgB,CAAC,MAAM,EAAE,SAAS,CAAC,cAAc,CAAC,CAAC"} \ No newline at end of file diff --git a/BuildFeed/Scripts/bfs.min.js b/BuildFeed/Scripts/bfs.min.js new file mode 100644 index 0000000..482d317 --- /dev/null +++ b/BuildFeed/Scripts/bfs.min.js @@ -0,0 +1 @@ +var BuildFeed;(function(n){function t(n){n.preventDefault();var i=this,t=i.parentElement.getElementsByClassName("dropdown-menu");t.length>0&&t[0].classList.toggle("open")}function i(){for(var i,u,r=document.getElementsByClassName("dropdown-parent"),n=0;n 0) + { + menus[0].classList.toggle("open"); + } + } + + export function BuildFeedSetup(ev: Event) + { + const ddParents = document.getElementsByClassName("dropdown-parent"); + + for (let i = 0; i < ddParents.length; i++) + { + for (let j = 0; j < ddParents[i].childNodes.length; j++) + { + const el = ddParents[i].childNodes[j]; + + if (el.nodeName === "A") + { + el.addEventListener("click", DropdownClick); + } + } + } + } +} + +window.addEventListener("load", BuildFeed.BuildFeedSetup); \ No newline at end of file diff --git a/BuildFeed/Scripts/excanvas.compiled.js b/BuildFeed/Scripts/excanvas.compiled.js deleted file mode 100644 index a34ca1d..0000000 --- a/BuildFeed/Scripts/excanvas.compiled.js +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2006 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -document.createElement("canvas").getContext||(function(){var s=Math,j=s.round,F=s.sin,G=s.cos,V=s.abs,W=s.sqrt,k=10,v=k/2;function X(){return this.context_||(this.context_=new H(this))}var L=Array.prototype.slice;function Y(b,a){var c=L.call(arguments,2);return function(){return b.apply(a,c.concat(L.call(arguments)))}}var M={init:function(b){if(/MSIE/.test(navigator.userAgent)&&!window.opera){var a=b||document;a.createElement("canvas");a.attachEvent("onreadystatechange",Y(this.init_,this,a))}},init_:function(b){b.namespaces.g_vml_|| -b.namespaces.add("g_vml_","urn:schemas-microsoft-com:vml","#default#VML");b.namespaces.g_o_||b.namespaces.add("g_o_","urn:schemas-microsoft-com:office:office","#default#VML");if(!b.styleSheets.ex_canvas_){var a=b.createStyleSheet();a.owningElement.id="ex_canvas_";a.cssText="canvas{display:inline-block;overflow:hidden;text-align:left;width:300px;height:150px}g_vml_\\:*{behavior:url(#default#VML)}g_o_\\:*{behavior:url(#default#VML)}"}var c=b.getElementsByTagName("canvas"),d=0;for(;d','","");this.element_.insertAdjacentHTML("BeforeEnd",t.join(""))};i.stroke=function(b){var a=[],c=P(b?this.fillStyle:this.strokeStyle),d=c.color,f=c.alpha*this.globalAlpha;a.push("g.x)g.x=e.x;if(h.y==null||e.yg.y)g.y=e.y}}a.push(' ">');if(b)if(typeof this.fillStyle=="object"){var m=this.fillStyle,r=0,n={x:0,y:0},o=0,q=1;if(m.type_=="gradient"){var t=m.x1_/this.arcScaleX_,E=m.y1_/this.arcScaleY_,p=this.getCoords_(m.x0_/this.arcScaleX_,m.y0_/this.arcScaleY_), -z=this.getCoords_(t,E);r=Math.atan2(z.x-p.x,z.y-p.y)*180/Math.PI;if(r<0)r+=360;if(r<1.0E-6)r=0}else{var p=this.getCoords_(m.x0_,m.y0_),w=g.x-h.x,x=g.y-h.y;n={x:(p.x-h.x)/w,y:(p.y-h.y)/x};w/=this.arcScaleX_*k;x/=this.arcScaleY_*k;var R=s.max(w,x);o=2*m.r0_/R;q=2*m.r1_/R-o}var u=m.colors_;u.sort(function(ba,ca){return ba.offset-ca.offset});var J=u.length,da=u[0].color,ea=u[J-1].color,fa=u[0].alpha*this.globalAlpha,ga=u[J-1].alpha*this.globalAlpha,S=[],l=0;for(;l')}else a.push('');else{var K=this.lineScale_*this.lineWidth;if(K<1)f*=K;a.push("')}a.push("");this.element_.insertAdjacentHTML("beforeEnd",a.join(""))};i.fill=function(){this.stroke(true)};i.closePath=function(){this.currentPath_.push({type:"close"})};i.getCoords_=function(b,a){var c=this.m_;return{x:k*(b*c[0][0]+a*c[1][0]+c[2][0])-v,y:k*(b*c[0][1]+a*c[1][1]+c[2][1])-v}};i.save=function(){var b={};O(this,b);this.aStack_.push(b);this.mStack_.push(this.m_);this.m_=y(I(),this.m_)};i.restore=function(){O(this.aStack_.pop(), -this);this.m_=this.mStack_.pop()};function ha(b){var a=0;for(;a<3;a++){var c=0;for(;c<2;c++)if(!isFinite(b[a][c])||isNaN(b[a][c]))return false}return true}function A(b,a,c){if(!!ha(a)){b.m_=a;if(c)b.lineScale_=W(V(a[0][0]*a[1][1]-a[0][1]*a[1][0]))}}i.translate=function(b,a){A(this,y([[1,0,0],[0,1,0],[b,a,1]],this.m_),false)};i.rotate=function(b){var a=G(b),c=F(b);A(this,y([[a,c,0],[-c,a,0],[0,0,1]],this.m_),false)};i.scale=function(b,a){this.arcScaleX_*=b;this.arcScaleY_*=a;A(this,y([[b,0,0],[0,a, -0],[0,0,1]],this.m_),true)};i.transform=function(b,a,c,d,f,h){A(this,y([[b,a,0],[c,d,0],[f,h,1]],this.m_),true)};i.setTransform=function(b,a,c,d,f,h){A(this,[[b,a,0],[c,d,0],[f,h,1]],true)};i.clip=function(){};i.arcTo=function(){};i.createPattern=function(){return new U};function D(b){this.type_=b;this.r1_=this.y1_=this.x1_=this.r0_=this.y0_=this.x0_=0;this.colors_=[]}D.prototype.addColorStop=function(b,a){a=P(a);this.colors_.push({offset:b,color:a.color,alpha:a.alpha})};function U(){}G_vmlCanvasManager= -M;CanvasRenderingContext2D=H;CanvasGradient=D;CanvasPattern=U})(); diff --git a/BuildFeed/Scripts/excanvas.js b/BuildFeed/Scripts/excanvas.js deleted file mode 100644 index 367764b..0000000 --- a/BuildFeed/Scripts/excanvas.js +++ /dev/null @@ -1,924 +0,0 @@ -// Copyright 2006 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - - -// Known Issues: -// -// * Patterns are not implemented. -// * Radial gradient are not implemented. The VML version of these look very -// different from the canvas one. -// * Clipping paths are not implemented. -// * Coordsize. The width and height attribute have higher priority than the -// width and height style values which isn't correct. -// * Painting mode isn't implemented. -// * Canvas width/height should is using content-box by default. IE in -// Quirks mode will draw the canvas using border-box. Either change your -// doctype to HTML5 -// (http://www.whatwg.org/specs/web-apps/current-work/#the-doctype) -// or use Box Sizing Behavior from WebFX -// (http://webfx.eae.net/dhtml/boxsizing/boxsizing.html) -// * Non uniform scaling does not correctly scale strokes. -// * Optimize. There is always room for speed improvements. - -// Only add this code if we do not already have a canvas implementation -if (!document.createElement('canvas').getContext) { - -(function() { - - // alias some functions to make (compiled) code shorter - var m = Math; - var mr = m.round; - var ms = m.sin; - var mc = m.cos; - var abs = m.abs; - var sqrt = m.sqrt; - - // this is used for sub pixel precision - var Z = 10; - var Z2 = Z / 2; - - /** - * This funtion is assigned to the elements as element.getContext(). - * @this {HTMLElement} - * @return {CanvasRenderingContext2D_} - */ - function getContext() { - return this.context_ || - (this.context_ = new CanvasRenderingContext2D_(this)); - } - - var slice = Array.prototype.slice; - - /** - * Binds a function to an object. The returned function will always use the - * passed in {@code obj} as {@code this}. - * - * Example: - * - * g = bind(f, obj, a, b) - * g(c, d) // will do f.call(obj, a, b, c, d) - * - * @param {Function} f The function to bind the object to - * @param {Object} obj The object that should act as this when the function - * is called - * @param {*} var_args Rest arguments that will be used as the initial - * arguments when the function is called - * @return {Function} A new function that has bound this - */ - function bind(f, obj, var_args) { - var a = slice.call(arguments, 2); - return function() { - return f.apply(obj, a.concat(slice.call(arguments))); - }; - } - - var G_vmlCanvasManager_ = { - init: function(opt_doc) { - if (/MSIE/.test(navigator.userAgent) && !window.opera) { - var doc = opt_doc || document; - // Create a dummy element so that IE will allow canvas elements to be - // recognized. - doc.createElement('canvas'); - doc.attachEvent('onreadystatechange', bind(this.init_, this, doc)); - } - }, - - init_: function(doc) { - // create xmlns - if (!doc.namespaces['g_vml_']) { - doc.namespaces.add('g_vml_', 'urn:schemas-microsoft-com:vml', - '#default#VML'); - - } - if (!doc.namespaces['g_o_']) { - doc.namespaces.add('g_o_', 'urn:schemas-microsoft-com:office:office', - '#default#VML'); - } - - // Setup default CSS. Only add one style sheet per document - if (!doc.styleSheets['ex_canvas_']) { - var ss = doc.createStyleSheet(); - ss.owningElement.id = 'ex_canvas_'; - ss.cssText = 'canvas{display:inline-block;overflow:hidden;' + - // default size is 300x150 in Gecko and Opera - 'text-align:left;width:300px;height:150px}' + - 'g_vml_\\:*{behavior:url(#default#VML)}' + - 'g_o_\\:*{behavior:url(#default#VML)}'; - - } - - // find all canvas elements - var els = doc.getElementsByTagName('canvas'); - for (var i = 0; i < els.length; i++) { - this.initElement(els[i]); - } - }, - - /** - * Public initializes a canvas element so that it can be used as canvas - * element from now on. This is called automatically before the page is - * loaded but if you are creating elements using createElement you need to - * make sure this is called on the element. - * @param {HTMLElement} el The canvas element to initialize. - * @return {HTMLElement} the element that was created. - */ - initElement: function(el) { - if (!el.getContext) { - - el.getContext = getContext; - - // Remove fallback content. There is no way to hide text nodes so we - // just remove all childNodes. We could hide all elements and remove - // text nodes but who really cares about the fallback content. - el.innerHTML = ''; - - // do not use inline function because that will leak memory - el.attachEvent('onpropertychange', onPropertyChange); - el.attachEvent('onresize', onResize); - - var attrs = el.attributes; - if (attrs.width && attrs.width.specified) { - // TODO: use runtimeStyle and coordsize - // el.getContext().setWidth_(attrs.width.nodeValue); - el.style.width = attrs.width.nodeValue + 'px'; - } else { - el.width = el.clientWidth; - } - if (attrs.height && attrs.height.specified) { - // TODO: use runtimeStyle and coordsize - // el.getContext().setHeight_(attrs.height.nodeValue); - el.style.height = attrs.height.nodeValue + 'px'; - } else { - el.height = el.clientHeight; - } - //el.getContext().setCoordsize_() - } - return el; - } - }; - - function onPropertyChange(e) { - var el = e.srcElement; - - switch (e.propertyName) { - case 'width': - el.style.width = el.attributes.width.nodeValue + 'px'; - el.getContext().clearRect(); - break; - case 'height': - el.style.height = el.attributes.height.nodeValue + 'px'; - el.getContext().clearRect(); - break; - } - } - - function onResize(e) { - var el = e.srcElement; - if (el.firstChild) { - el.firstChild.style.width = el.clientWidth + 'px'; - el.firstChild.style.height = el.clientHeight + 'px'; - } - } - - G_vmlCanvasManager_.init(); - - // precompute "00" to "FF" - var dec2hex = []; - for (var i = 0; i < 16; i++) { - for (var j = 0; j < 16; j++) { - dec2hex[i * 16 + j] = i.toString(16) + j.toString(16); - } - } - - function createMatrixIdentity() { - return [ - [1, 0, 0], - [0, 1, 0], - [0, 0, 1] - ]; - } - - function matrixMultiply(m1, m2) { - var result = createMatrixIdentity(); - - for (var x = 0; x < 3; x++) { - for (var y = 0; y < 3; y++) { - var sum = 0; - - for (var z = 0; z < 3; z++) { - sum += m1[x][z] * m2[z][y]; - } - - result[x][y] = sum; - } - } - return result; - } - - function copyState(o1, o2) { - o2.fillStyle = o1.fillStyle; - o2.lineCap = o1.lineCap; - o2.lineJoin = o1.lineJoin; - o2.lineWidth = o1.lineWidth; - o2.miterLimit = o1.miterLimit; - o2.shadowBlur = o1.shadowBlur; - o2.shadowColor = o1.shadowColor; - o2.shadowOffsetX = o1.shadowOffsetX; - o2.shadowOffsetY = o1.shadowOffsetY; - o2.strokeStyle = o1.strokeStyle; - o2.globalAlpha = o1.globalAlpha; - o2.arcScaleX_ = o1.arcScaleX_; - o2.arcScaleY_ = o1.arcScaleY_; - o2.lineScale_ = o1.lineScale_; - } - - function processStyle(styleString) { - var str, alpha = 1; - - styleString = String(styleString); - if (styleString.substring(0, 3) == 'rgb') { - var start = styleString.indexOf('(', 3); - var end = styleString.indexOf(')', start + 1); - var guts = styleString.substring(start + 1, end).split(','); - - str = '#'; - for (var i = 0; i < 3; i++) { - str += dec2hex[Number(guts[i])]; - } - - if (guts.length == 4 && styleString.substr(3, 1) == 'a') { - alpha = guts[3]; - } - } else { - str = styleString; - } - - return {color: str, alpha: alpha}; - } - - function processLineCap(lineCap) { - switch (lineCap) { - case 'butt': - return 'flat'; - case 'round': - return 'round'; - case 'square': - default: - return 'square'; - } - } - - /** - * This class implements CanvasRenderingContext2D interface as described by - * the WHATWG. - * @param {HTMLElement} surfaceElement The element that the 2D context should - * be associated with - */ - function CanvasRenderingContext2D_(surfaceElement) { - this.m_ = createMatrixIdentity(); - - this.mStack_ = []; - this.aStack_ = []; - this.currentPath_ = []; - - // Canvas context properties - this.strokeStyle = '#000'; - this.fillStyle = '#000'; - - this.lineWidth = 1; - this.lineJoin = 'miter'; - this.lineCap = 'butt'; - this.miterLimit = Z * 1; - this.globalAlpha = 1; - this.canvas = surfaceElement; - - var el = surfaceElement.ownerDocument.createElement('div'); - el.style.width = surfaceElement.clientWidth + 'px'; - el.style.height = surfaceElement.clientHeight + 'px'; - el.style.overflow = 'hidden'; - el.style.position = 'absolute'; - surfaceElement.appendChild(el); - - this.element_ = el; - this.arcScaleX_ = 1; - this.arcScaleY_ = 1; - this.lineScale_ = 1; - } - - var contextPrototype = CanvasRenderingContext2D_.prototype; - contextPrototype.clearRect = function() { - this.element_.innerHTML = ''; - }; - - contextPrototype.beginPath = function() { - // TODO: Branch current matrix so that save/restore has no effect - // as per safari docs. - this.currentPath_ = []; - }; - - contextPrototype.moveTo = function(aX, aY) { - var p = this.getCoords_(aX, aY); - this.currentPath_.push({type: 'moveTo', x: p.x, y: p.y}); - this.currentX_ = p.x; - this.currentY_ = p.y; - }; - - contextPrototype.lineTo = function(aX, aY) { - var p = this.getCoords_(aX, aY); - this.currentPath_.push({type: 'lineTo', x: p.x, y: p.y}); - - this.currentX_ = p.x; - this.currentY_ = p.y; - }; - - contextPrototype.bezierCurveTo = function(aCP1x, aCP1y, - aCP2x, aCP2y, - aX, aY) { - var p = this.getCoords_(aX, aY); - var cp1 = this.getCoords_(aCP1x, aCP1y); - var cp2 = this.getCoords_(aCP2x, aCP2y); - bezierCurveTo(this, cp1, cp2, p); - }; - - // Helper function that takes the already fixed cordinates. - function bezierCurveTo(self, cp1, cp2, p) { - self.currentPath_.push({ - type: 'bezierCurveTo', - cp1x: cp1.x, - cp1y: cp1.y, - cp2x: cp2.x, - cp2y: cp2.y, - x: p.x, - y: p.y - }); - self.currentX_ = p.x; - self.currentY_ = p.y; - } - - contextPrototype.quadraticCurveTo = function(aCPx, aCPy, aX, aY) { - // the following is lifted almost directly from - // http://developer.mozilla.org/en/docs/Canvas_tutorial:Drawing_shapes - - var cp = this.getCoords_(aCPx, aCPy); - var p = this.getCoords_(aX, aY); - - var cp1 = { - x: this.currentX_ + 2.0 / 3.0 * (cp.x - this.currentX_), - y: this.currentY_ + 2.0 / 3.0 * (cp.y - this.currentY_) - }; - var cp2 = { - x: cp1.x + (p.x - this.currentX_) / 3.0, - y: cp1.y + (p.y - this.currentY_) / 3.0 - }; - - bezierCurveTo(this, cp1, cp2, p); - }; - - contextPrototype.arc = function(aX, aY, aRadius, - aStartAngle, aEndAngle, aClockwise) { - aRadius *= Z; - var arcType = aClockwise ? 'at' : 'wa'; - - var xStart = aX + mc(aStartAngle) * aRadius - Z2; - var yStart = aY + ms(aStartAngle) * aRadius - Z2; - - var xEnd = aX + mc(aEndAngle) * aRadius - Z2; - var yEnd = aY + ms(aEndAngle) * aRadius - Z2; - - // IE won't render arches drawn counter clockwise if xStart == xEnd. - if (xStart == xEnd && !aClockwise) { - xStart += 0.125; // Offset xStart by 1/80 of a pixel. Use something - // that can be represented in binary - } - - var p = this.getCoords_(aX, aY); - var pStart = this.getCoords_(xStart, yStart); - var pEnd = this.getCoords_(xEnd, yEnd); - - this.currentPath_.push({type: arcType, - x: p.x, - y: p.y, - radius: aRadius, - xStart: pStart.x, - yStart: pStart.y, - xEnd: pEnd.x, - yEnd: pEnd.y}); - - }; - - contextPrototype.rect = function(aX, aY, aWidth, aHeight) { - this.moveTo(aX, aY); - this.lineTo(aX + aWidth, aY); - this.lineTo(aX + aWidth, aY + aHeight); - this.lineTo(aX, aY + aHeight); - this.closePath(); - }; - - contextPrototype.strokeRect = function(aX, aY, aWidth, aHeight) { - var oldPath = this.currentPath_; - this.beginPath(); - - this.moveTo(aX, aY); - this.lineTo(aX + aWidth, aY); - this.lineTo(aX + aWidth, aY + aHeight); - this.lineTo(aX, aY + aHeight); - this.closePath(); - this.stroke(); - - this.currentPath_ = oldPath; - }; - - contextPrototype.fillRect = function(aX, aY, aWidth, aHeight) { - var oldPath = this.currentPath_; - this.beginPath(); - - this.moveTo(aX, aY); - this.lineTo(aX + aWidth, aY); - this.lineTo(aX + aWidth, aY + aHeight); - this.lineTo(aX, aY + aHeight); - this.closePath(); - this.fill(); - - this.currentPath_ = oldPath; - }; - - contextPrototype.createLinearGradient = function(aX0, aY0, aX1, aY1) { - var gradient = new CanvasGradient_('gradient'); - gradient.x0_ = aX0; - gradient.y0_ = aY0; - gradient.x1_ = aX1; - gradient.y1_ = aY1; - return gradient; - }; - - contextPrototype.createRadialGradient = function(aX0, aY0, aR0, - aX1, aY1, aR1) { - var gradient = new CanvasGradient_('gradientradial'); - gradient.x0_ = aX0; - gradient.y0_ = aY0; - gradient.r0_ = aR0; - gradient.x1_ = aX1; - gradient.y1_ = aY1; - gradient.r1_ = aR1; - return gradient; - }; - - contextPrototype.drawImage = function(image, var_args) { - var dx, dy, dw, dh, sx, sy, sw, sh; - - // to find the original width we overide the width and height - var oldRuntimeWidth = image.runtimeStyle.width; - var oldRuntimeHeight = image.runtimeStyle.height; - image.runtimeStyle.width = 'auto'; - image.runtimeStyle.height = 'auto'; - - // get the original size - var w = image.width; - var h = image.height; - - // and remove overides - image.runtimeStyle.width = oldRuntimeWidth; - image.runtimeStyle.height = oldRuntimeHeight; - - if (arguments.length == 3) { - dx = arguments[1]; - dy = arguments[2]; - sx = sy = 0; - sw = dw = w; - sh = dh = h; - } else if (arguments.length == 5) { - dx = arguments[1]; - dy = arguments[2]; - dw = arguments[3]; - dh = arguments[4]; - sx = sy = 0; - sw = w; - sh = h; - } else if (arguments.length == 9) { - sx = arguments[1]; - sy = arguments[2]; - sw = arguments[3]; - sh = arguments[4]; - dx = arguments[5]; - dy = arguments[6]; - dw = arguments[7]; - dh = arguments[8]; - } else { - throw Error('Invalid number of arguments'); - } - - var d = this.getCoords_(dx, dy); - - var w2 = sw / 2; - var h2 = sh / 2; - - var vmlStr = []; - - var W = 10; - var H = 10; - - // For some reason that I've now forgotten, using divs didn't work - vmlStr.push(' ' , - '', - ''); - - this.element_.insertAdjacentHTML('BeforeEnd', - vmlStr.join('')); - }; - - contextPrototype.stroke = function(aFill) { - var lineStr = []; - var lineOpen = false; - var a = processStyle(aFill ? this.fillStyle : this.strokeStyle); - var color = a.color; - var opacity = a.alpha * this.globalAlpha; - - var W = 10; - var H = 10; - - lineStr.push(''); - - if (!aFill) { - var lineWidth = this.lineScale_ * this.lineWidth; - - // VML cannot correctly render a line if the width is less than 1px. - // In that case, we dilute the color to make the line look thinner. - if (lineWidth < 1) { - opacity *= lineWidth; - } - - lineStr.push( - '' - ); - } else if (typeof this.fillStyle == 'object') { - var fillStyle = this.fillStyle; - var angle = 0; - var focus = {x: 0, y: 0}; - - // additional offset - var shift = 0; - // scale factor for offset - var expansion = 1; - - if (fillStyle.type_ == 'gradient') { - var x0 = fillStyle.x0_ / this.arcScaleX_; - var y0 = fillStyle.y0_ / this.arcScaleY_; - var x1 = fillStyle.x1_ / this.arcScaleX_; - var y1 = fillStyle.y1_ / this.arcScaleY_; - var p0 = this.getCoords_(x0, y0); - var p1 = this.getCoords_(x1, y1); - var dx = p1.x - p0.x; - var dy = p1.y - p0.y; - angle = Math.atan2(dx, dy) * 180 / Math.PI; - - // The angle should be a non-negative number. - if (angle < 0) { - angle += 360; - } - - // Very small angles produce an unexpected result because they are - // converted to a scientific notation string. - if (angle < 1e-6) { - angle = 0; - } - } else { - var p0 = this.getCoords_(fillStyle.x0_, fillStyle.y0_); - var width = max.x - min.x; - var height = max.y - min.y; - focus = { - x: (p0.x - min.x) / width, - y: (p0.y - min.y) / height - }; - - width /= this.arcScaleX_ * Z; - height /= this.arcScaleY_ * Z; - var dimension = m.max(width, height); - shift = 2 * fillStyle.r0_ / dimension; - expansion = 2 * fillStyle.r1_ / dimension - shift; - } - - // We need to sort the color stops in ascending order by offset, - // otherwise IE won't interpret it correctly. - var stops = fillStyle.colors_; - stops.sort(function(cs1, cs2) { - return cs1.offset - cs2.offset; - }); - - var length = stops.length; - var color1 = stops[0].color; - var color2 = stops[length - 1].color; - var opacity1 = stops[0].alpha * this.globalAlpha; - var opacity2 = stops[length - 1].alpha * this.globalAlpha; - - var colors = []; - for (var i = 0; i < length; i++) { - var stop = stops[i]; - colors.push(stop.offset * expansion + shift + ' ' + stop.color); - } - - // When colors attribute is used, the meanings of opacity and o:opacity2 - // are reversed. - lineStr.push(''); - } else { - lineStr.push(''); - } - - lineStr.push(''); - - this.element_.insertAdjacentHTML('beforeEnd', lineStr.join('')); - }; - - contextPrototype.fill = function() { - this.stroke(true); - } - - contextPrototype.closePath = function() { - this.currentPath_.push({type: 'close'}); - }; - - /** - * @private - */ - contextPrototype.getCoords_ = function(aX, aY) { - var m = this.m_; - return { - x: Z * (aX * m[0][0] + aY * m[1][0] + m[2][0]) - Z2, - y: Z * (aX * m[0][1] + aY * m[1][1] + m[2][1]) - Z2 - } - }; - - contextPrototype.save = function() { - var o = {}; - copyState(this, o); - this.aStack_.push(o); - this.mStack_.push(this.m_); - this.m_ = matrixMultiply(createMatrixIdentity(), this.m_); - }; - - contextPrototype.restore = function() { - copyState(this.aStack_.pop(), this); - this.m_ = this.mStack_.pop(); - }; - - function matrixIsFinite(m) { - for (var j = 0; j < 3; j++) { - for (var k = 0; k < 2; k++) { - if (!isFinite(m[j][k]) || isNaN(m[j][k])) { - return false; - } - } - } - return true; - } - - function setM(ctx, m, updateLineScale) { - if (!matrixIsFinite(m)) { - return; - } - ctx.m_ = m; - - if (updateLineScale) { - // Get the line scale. - // Determinant of this.m_ means how much the area is enlarged by the - // transformation. So its square root can be used as a scale factor - // for width. - var det = m[0][0] * m[1][1] - m[0][1] * m[1][0]; - ctx.lineScale_ = sqrt(abs(det)); - } - } - - contextPrototype.translate = function(aX, aY) { - var m1 = [ - [1, 0, 0], - [0, 1, 0], - [aX, aY, 1] - ]; - - setM(this, matrixMultiply(m1, this.m_), false); - }; - - contextPrototype.rotate = function(aRot) { - var c = mc(aRot); - var s = ms(aRot); - - var m1 = [ - [c, s, 0], - [-s, c, 0], - [0, 0, 1] - ]; - - setM(this, matrixMultiply(m1, this.m_), false); - }; - - contextPrototype.scale = function(aX, aY) { - this.arcScaleX_ *= aX; - this.arcScaleY_ *= aY; - var m1 = [ - [aX, 0, 0], - [0, aY, 0], - [0, 0, 1] - ]; - - setM(this, matrixMultiply(m1, this.m_), true); - }; - - contextPrototype.transform = function(m11, m12, m21, m22, dx, dy) { - var m1 = [ - [m11, m12, 0], - [m21, m22, 0], - [dx, dy, 1] - ]; - - setM(this, matrixMultiply(m1, this.m_), true); - }; - - contextPrototype.setTransform = function(m11, m12, m21, m22, dx, dy) { - var m = [ - [m11, m12, 0], - [m21, m22, 0], - [dx, dy, 1] - ]; - - setM(this, m, true); - }; - - /******** STUBS ********/ - contextPrototype.clip = function() { - // TODO: Implement - }; - - contextPrototype.arcTo = function() { - // TODO: Implement - }; - - contextPrototype.createPattern = function() { - return new CanvasPattern_; - }; - - // Gradient / Pattern Stubs - function CanvasGradient_(aType) { - this.type_ = aType; - this.x0_ = 0; - this.y0_ = 0; - this.r0_ = 0; - this.x1_ = 0; - this.y1_ = 0; - this.r1_ = 0; - this.colors_ = []; - } - - CanvasGradient_.prototype.addColorStop = function(aOffset, aColor) { - aColor = processStyle(aColor); - this.colors_.push({offset: aOffset, - color: aColor.color, - alpha: aColor.alpha}); - }; - - function CanvasPattern_() {} - - // set up externs - G_vmlCanvasManager = G_vmlCanvasManager_; - CanvasRenderingContext2D = CanvasRenderingContext2D_; - CanvasGradient = CanvasGradient_; - CanvasPattern = CanvasPattern_; - -})(); - -} // if diff --git a/BuildFeed/Scripts/jsrender.js b/BuildFeed/Scripts/jsrender.js deleted file mode 100644 index 4661fa7..0000000 --- a/BuildFeed/Scripts/jsrender.js +++ /dev/null @@ -1,1712 +0,0 @@ -/*! JsRender v1.0.0-beta: http://github.com/BorisMoore/jsrender and http://jsviews.com/jsviews -informal pre V1.0 commit counter: 60 */ -/* - * Optimized version of jQuery Templates, for rendering to string. - * Does not require jQuery, or HTML DOM - * Integrates with JsViews (http://jsviews.com/jsviews) - * - * Copyright 2014, Boris Moore - * Released under the MIT License. - */ - -(function(global, jQuery, undefined) { - // global is the this object, which is window when running in the usual browser environment. - "use strict"; - - if (jQuery && jQuery.render || global.jsviews) { return; } // JsRender is already loaded - - //========================== Top-level vars ========================== - - var versionNumber = "v1.0.0-beta", - - $, jsvStoreName, rTag, rTmplString, indexStr, // nodeJsModule, - -//TODO tmplFnsCache = {}, - delimOpenChar0 = "{", delimOpenChar1 = "{", delimCloseChar0 = "}", delimCloseChar1 = "}", linkChar = "^", - - rPath = /^(!*?)(?:null|true|false|\d[\d.]*|([\w$]+|\.|~([\w$]+)|#(view|([\w$]+))?)([\w$.^]*?)(?:[.[^]([\w$]+)\]?)?)$/g, - // none object helper view viewProperty pathTokens leafToken - - rParams = /(\()(?=\s*\()|(?:([([])\s*)?(?:(\^?)(!*?[#~]?[\w$.^]+)?\s*((\+\+|--)|\+|-|&&|\|\||===|!==|==|!=|<=|>=|[<>%*:?\/]|(=))\s*|(!*?[#~]?[\w$.^]+)([([])?)|(,\s*)|(\(?)\\?(?:(')|("))|(?:\s*(([)\]])(?=\s*\.|\s*\^|\s*$)|[)\]])([([]?))|(\s+)/g, - // lftPrn0 lftPrn bound path operator err eq path2 prn comma lftPrn2 apos quot rtPrn rtPrnDot prn2 space - // (left paren? followed by (path? followed by operator) or (path followed by left paren?)) or comma or apos or quot or right paren or space - - rNewLine = /[ \t]*(\r\n|\n|\r)/g, - rUnescapeQuotes = /\\(['"])/g, - rEscapeQuotes = /['"\\]/g, // Escape quotes and \ character - rBuildHash = /(?:\x08|^)(onerror:)?(?:(~?)(([\w$]+):)?([^\x08]+))\x08(,)?([^\x08]+)/gi, - rTestElseIf = /^if\s/, - rFirstElem = /<(\w+)[>\s]/, - rAttrEncode = /[\x00`><"'&]/g, // Includes > encoding since rConvertMarkers in JsViews does not skip > characters in attribute strings - rIsHtml = /[\x00`><\"'&]/, - rHasHandlers = /^on[A-Z]|^convert(Back)?$/, - rHtmlEncode = rAttrEncode, - autoTmplName = 0, - viewId = 0, - charEntities = { - "&": "&", - "<": "<", - ">": ">", - "\x00": "�", - "'": "'", - '"': """, - "`": "`" - }, - htmlStr = "html", - tmplAttr = "data-jsv-tmpl", - $render = {}, - jsvStores = { - template: { - compile: compileTmpl - }, - tag: { - compile: compileTag - }, - helper: {}, - converter: {} - }, - - // jsviews object ($.views if jQuery is loaded) - $views = { - jsviews: versionNumber, - settings: function(settings) { - $extend($viewsSettings, settings); - dbgMode($viewsSettings._dbgMode); - if ($viewsSettings.jsv) { - $viewsSettings.jsv(); - } - }, - sub: { - // subscription, e.g. JsViews integration - View: View, - Err: JsViewsError, - tmplFn: tmplFn, - cvt: convertArgs, - parse: parseParams, - extend: $extend, - syntaxErr: syntaxError, - onStore: {}, - _lnk: retVal, - _ths: tagHandlersFromProps - }, - map: dataMap, // If jsObservable loaded first, use that definition of dataMap - _cnvt: convertVal, - _tag: renderTag, - _err: error - }; - - function tagHandlersFromProps(tag, tagCtx) { - for (var prop in tagCtx.props) { - if (rHasHandlers.test(prop)) { - tag[prop] = tagCtx.props[prop]; // Copy over the onFoo props, convert and convertBack from tagCtx.props to tag (overrides values in tagDef). - // Note: unsupported scenario: if handlers are dynamically added ^onFoo=expression this will work, but dynamically removing will not work. - } - } - } - - function retVal(val) { - return val; - } - - function dbgBreak(val) { - debugger; // Insert breakpoint for debugging JsRender or JsViews. - // Consider https://github.com/BorisMoore/jsrender/issues/239: eval("debugger; //dbg"); // Insert breakpoint for debugging JsRender or JsViews. Using eval to prevent issue with minifiers (YUI Compressor) - return val; - } - - function dbgMode(debugMode) { - $viewsSettings._dbgMode = debugMode; - indexStr = debugMode ? "Unavailable (nested view): use #getIndex()" : ""; // If in debug mode set #index to a warning when in nested contexts - $tags("dbg", $helpers.dbg = $converters.dbg = debugMode ? dbgBreak : retVal); // Register {{dbg/}}, {{dbg:...}} and ~dbg() to insert break points for debugging - if in debug mode. - } - - function JsViewsError(message) { - // Error exception type for JsViews/JsRender - // Override of $.views.sub.Error is possible - this.name = ($.link ? "JsViews" : "JsRender") + " Error"; - this.message = message || this.name; - } - - function $extend(target, source) { - var name; - for (name in source) { - target[name] = source[name]; - } - return target; - } - - function $isFunction(ob) { - return typeof ob === "function"; - } - - (JsViewsError.prototype = new Error()).constructor = JsViewsError; - - //========================== Top-level functions ========================== - - //=================== - // jsviews.delimiters - //=================== - function $viewsDelimiters(openChars, closeChars, link) { - // Set the tag opening and closing delimiters and 'link' character. Default is "{{", "}}" and "^" - // openChars, closeChars: opening and closing strings, each with two characters - - if (!$sub.rTag || openChars) { - delimOpenChar0 = openChars ? openChars.charAt(0) : delimOpenChar0; // Escape the characters - since they could be regex special characters - delimOpenChar1 = openChars ? openChars.charAt(1) : delimOpenChar1; - delimCloseChar0 = closeChars ? closeChars.charAt(0) : delimCloseChar0; - delimCloseChar1 = closeChars ? closeChars.charAt(1) : delimCloseChar1; - linkChar = link || linkChar; - openChars = "\\" + delimOpenChar0 + "(\\" + linkChar + ")?\\" + delimOpenChar1; // Default is "{^{" - closeChars = "\\" + delimCloseChar0 + "\\" + delimCloseChar1; // Default is "}}" - // Build regex with new delimiters - // tag (followed by / space or }) or cvtr+colon or html or code - rTag = "(?:(?:(\\w+(?=[\\/\\s\\" + delimCloseChar0 + "]))|(?:(\\w+)?(:)|(>)|!--((?:[^-]|-(?!-))*)--|(\\*)))" - + "\\s*((?:[^\\" + delimCloseChar0 + "]|\\" + delimCloseChar0 + "(?!\\" + delimCloseChar1 + "))*?)"; - - // make rTag available to JsViews (or other components) for parsing binding expressions - $sub.rTag = rTag + ")"; - - rTag = new RegExp(openChars + rTag + "(\\/)?|(?:\\/(\\w+)))" + closeChars, "g"); - - // Default: bind tag converter colon html comment code params slash closeBlock - // /{(\^)?{(?:(?:(\w+(?=[\/\s}]))|(?:(\w+)?(:)|(>)|!--((?:[^-]|-(?!-))*)--|(\*)))\s*((?:[^}]|}(?!}))*?)(\/)?|(?:\/(\w+)))}}/g - - rTmplString = new RegExp("<.*>|([^\\\\]|^)[{}]|" + openChars + ".*" + closeChars); - // rTmplString looks for html tags or { or } char not preceded by \\, or JsRender tags {{xxx}}. Each of these strings are considered - // NOT to be jQuery selectors - } - return [delimOpenChar0, delimOpenChar1, delimCloseChar0, delimCloseChar1, linkChar]; - } - - //========= - // View.get - //========= - - function getView(inner, type) { //view.get(inner, type) - if (!type) { - // view.get(type) - type = inner; - inner = undefined; - } - - var views, i, l, found, - view = this, - root = !type || type === "root"; - // If type is undefined, returns root view (view under top view). - - if (inner) { - // Go through views - this one, and all nested ones, depth-first - and return first one with given type. - found = view.type === type ? view : undefined; - if (!found) { - views = view.views; - if (view._.useKey) { - for (i in views) { - if (found = views[i].get(inner, type)) { - break; - } - } - } else { - for (i = 0, l = views.length; !found && i < l; i++) { - found = views[i].get(inner, type); - } - } - } - } else if (root) { - // Find root view. (view whose parent is top view) - while (view.parent.parent) { - found = view = view.parent; - } - } else { - while (view && !found) { - // Go through views - this one, and all parent ones - and return first one with given type. - found = view.type === type ? view : undefined; - view = view.parent; - } - } - return found; - } - - function getNestedIndex() { - var view = this.get("item"); - return view ? view.index : undefined; - } - - getNestedIndex.depends = function() { - return [this.get("item"), "index"]; - }; - - function getIndex() { - return this.index; - } - - getIndex.depends = function() { - return ["index"]; - }; - - //========== - // View.hlp - //========== - - function getHelper(helper) { - // Helper method called as view.hlp(key) from compiled template, for helper functions or template parameters ~foo - var wrapped, - view = this, - ctx = view.linkCtx, - res = (view.ctx || {})[helper]; - - if (res === undefined && ctx && ctx.ctx) { - res = ctx.ctx[helper]; - } - if (res === undefined) { - res = $helpers[helper]; - } - - if (res) { - if ($isFunction(res) && !res._wrp) { - wrapped = function() { - // If it is of type function, and not already wrapped, we will wrap it, so if called with no this pointer it will be called with the - // view as 'this' context. If the helper ~foo() was in a data-link expression, the view will have a 'temporary' linkCtx property too. - // Note that helper functions on deeper paths will have specific this pointers, from the preceding path. - // For example, ~util.foo() will have the ~util object as 'this' pointer - return res.apply((!this || this === global) ? view : this, arguments); - }; - wrapped._wrp = true; - $extend(wrapped, res); // Attach same expandos (if any) to the wrapped function - } - } - return wrapped || res; - } - - //============== - // jsviews._cnvt - //============== - - function convertVal(converter, view, tagCtx, onError) { - // self is template object or linkCtx object - var tag, value, - // if tagCtx is an integer, then it is the key for the compiled function to return the boundTag tagCtx - boundTag = +tagCtx === tagCtx && view.tmpl.bnds[tagCtx-1], - linkCtx = view.linkCtx; // For data-link="{cvt:...}"... - - onError = onError !== undefined && {props: {}, args: [onError]}; - - tagCtx = onError || (boundTag ? boundTag(view.data, view, $views) : tagCtx); - - value = tagCtx.args[0]; - if (converter || boundTag) { - tag = linkCtx && linkCtx.tag; - if (!tag) { - tag = { - _: { - inline: !linkCtx, - bnd: boundTag - }, - tagName: ":", - cvt: converter, - flow: true, - tagCtx: tagCtx, - _is: "tag" - }; - if (linkCtx) { - linkCtx.tag = tag; - tag.linkCtx = linkCtx; - tagCtx.ctx = extendCtx(tagCtx.ctx, linkCtx.view.ctx); - } - $sub._lnk(tag); - } - tag._er = onError && value; - tagHandlersFromProps(tag, tagCtx); - - tagCtx.view = view; - - tag.ctx = tagCtx.ctx || {}; - delete tagCtx.ctx; - // Provide this tag on view, for addBindingMarkers on bound tags to add the tag to view._.bnds, associated with the tag id, - view._.tag = tag; - - value = convertArgs(tag, tag.convert || converter !== "true" && converter)[0]; // If there is a convertBack but no convert, converter will be "true" - - // Call onRender (used by JsViews if present, to add binding annotations around rendered content) - value = boundTag && view._.onRender - ? view._.onRender(value, view, boundTag) - : value; - view._.tag = undefined; - } - return value != undefined ? value : ""; - } - - function convertArgs(tag, converter) { - var tagCtx = tag.tagCtx, - view = tagCtx.view, - args = tagCtx.args; - - converter = converter && ("" + converter === converter - ? (view.getRsc("converters", converter) || error("Unknown converter: '" + converter + "'")) - : converter); - - args = !args.length && !tagCtx.index // On the opening tag with no args, bind to the current data context - ? [view.data] - : converter - ? args.slice() // If there is a converter, use a copy of the tagCtx.args array for rendering, and replace the args[0] in - // the copied array with the converted value. But we do not modify the value of tag.tagCtx.args[0] (the original args array) - : args; // If no converter, render with the original tagCtx.args - - if (converter) { - if (converter.depends) { - tag.depends = $sub.getDeps(tag.depends, tag, converter.depends, converter); - } - args[0] = converter.apply(tag, args); - } - return args; - } - - //============= - // jsviews._tag - //============= - - function getResource(resourceType, itemName) { - var res, store, - view = this; - while ((res === undefined) && view) { - store = view.tmpl[resourceType]; - res = store && store[itemName]; - view = view.parent; - } - return res || $views[resourceType][itemName]; - } - - function renderTag(tagName, parentView, tmpl, tagCtxs, isUpdate, onError) { - // Called from within compiled template function, to render a template tag - // Returns the rendered tag - - var tag, tags, attr, parentTag, i, l, itemRet, tagCtx, tagCtxCtx, content, tagDef, - callInit, mapDef, thisMap, args, props, initialTmpl, - ret = "", - linkCtx = parentView.linkCtx || 0, - ctx = parentView.ctx, - parentTmpl = tmpl || parentView.tmpl, - // if tagCtx is an integer, then it is the key for the compiled function to return the boundTag tagCtxs - boundTag = +tagCtxs === tagCtxs && parentTmpl.bnds[tagCtxs-1]; - - if (tagName._is === "tag") { - tag = tagName; - tagName = tag.tagName; - tagCtxs = tag.tagCtxs; - } - tag = tag || linkCtx.tag; - - onError = onError !== undefined && (ret += onError, [{props: {}, args: []}]); - - tagCtxs = onError || (boundTag ? boundTag(parentView.data, parentView, $views) : tagCtxs); - - l = tagCtxs.length; - for (i = 0; i < l; i++) { - if (!i && (!tmpl || !tag)) { - tagDef = parentView.getRsc("tags", tagName) || error("Unknown tag: {{" + tagName + "}}"); - } - tagCtx = tagCtxs[i]; - if (!linkCtx.tag || tag._er) { - // We are initializing tag, so for block tags, tagCtx.tmpl is an integer > 0 - content = tagCtx.tmpl; - content = tagCtx.content = content && parentTmpl.tmpls[content - 1]; - - $extend(tagCtx, { - tmpl: (tag ? tag : tagDef).template || content, // Set the tmpl property to the content of the block tag - render: renderContent, - index: i, - view: parentView, - ctx: extendCtx(tagCtx.ctx, ctx) // Extend parentView.ctx - - // Possible future feature: - //var updatedValueOfArg0 = this.tagCtx.get(0); - //var updatedValueOfPropFoo = this.tagCtx.get("foo"); - //var updatedValueOfCtxPropFoo = this.tagCtx.get("~foo"); - //_fns: {}, - //get: function(key) { - // return (this._fns[key] = this._fns[key] || new Function("data,view,j,u", - // "return " + $.views.sub.parse(this.params[+key === key ? "args" : (key.charAt(0) === "~" ? (key = key.slice(1), "ctx") : "props")][key]) + ";") - // )(this.view.data, this.view, $views); - //}, - }); - } - if (tmpl = tagCtx.props.tmpl) { - // If the tmpl property is overridden, set the value (when initializing, or, in case of binding: ^tmpl=..., when updating) - tmpl = "" + tmpl === tmpl // if a string - ? parentView.getRsc("templates", tmpl) || $templates(tmpl) - : tmpl; - - tagCtx.tmpl = tmpl; - } - - if (!tag) { - // This will only be hit for initial tagCtx (not for {{else}}) - if the tag instance does not exist yet - // Instantiate tag if it does not yet exist - if (tagDef._ctr) { - // If the tag has not already been instantiated, we will create a new instance. - // ~tag will access the tag, even within the rendering of the template content of this tag. - // From child/descendant tags, can access using ~tag.parent, or ~parentTags.tagName - tag = new tagDef._ctr(); - callInit = !!tag.init; - } else { - // This is a simple tag declared as a function, or with init set to false. We won't instantiate a specific tag constructor - just a standard instance object. - $sub._lnk(tag = { - // tag instance object if no init constructor - render: tagDef.render - }); - } - tag._ = { - inline: !linkCtx - }; - if (linkCtx) { - linkCtx.tag = tag; - tag.linkCtx = linkCtx; - } - if (tag._.bnd = boundTag || linkCtx.fn) { - // Bound if {^{tag...}} or data-link="{tag...}" - tag._.arrVws = {}; - } else if (tag.dataBoundOnly) { - error("{^{" + tagName + "}} tag must be data-bound"); - } - tag.tagName = tagName; - tag.parent = parentTag = ctx && ctx.tag; - tag._is = "tag"; - tag._def = tagDef; - tag.tagCtxs = tagCtxs; - - //TODO better perf for childTags() - keep child tag.tags array, (and remove child, when disposed) - // tag.tags = []; - // Provide this tag on view, for addBindingMarkers on bound tags to add the tag to view._.bnds, associated with the tag id - } - tagCtx.tag = tag; - if (tag.dataMap && tag.tagCtxs) { - tagCtx.map = tag.tagCtxs[i].map; // Copy over the compiled map instance from the previous tagCtxs to the refreshed ones - } - if (!tag.flow) { - tagCtxCtx = tagCtx.ctx = tagCtx.ctx || {}; - - // tags hash: tag.ctx.tags, merged with parentView.ctx.tags, - tags = tag.parents = tagCtxCtx.parentTags = ctx && extendCtx(tagCtxCtx.parentTags, ctx.parentTags) || {}; - if (parentTag) { - tags[parentTag.tagName] = parentTag; - //TODO better perf for childTags: parentTag.tags.push(tag); - } - tags[tag.tagName] = tagCtxCtx.tag = tag; - } - } - parentView._.tag = tag; - if (!(tag._er = onError)) { - tagHandlersFromProps(tag, tagCtxs[0]); - tag.rendering = {}; // Provide object for state during render calls to tag and elses. (Used by {{if}} and {{for}}...) - for (i = 0; i < l; i++) { - tagCtx = tag.tagCtx = tag.tagCtxs[i]; - props = tagCtx.props; - args = convertArgs(tag, tag.convert); - - if (mapDef = props.dataMap || tag.dataMap) { - if (args.length || props.dataMap) { - thisMap = tagCtx.map; - if (!thisMap || thisMap.src !== args[0] || isUpdate) { - if (thisMap && thisMap.src) { - thisMap.unmap(); // only called if observable map - not when only used in JsRender, e.g. by {{props}} - } - thisMap = tagCtx.map = mapDef.map(args[0], props); - } - args = [thisMap.tgt]; - } - } - tag.ctx = tagCtx.ctx; - - if (!i && callInit) { - initialTmpl = tag.template; - tag.init(tagCtx, linkCtx, tag.ctx); - callInit = undefined; - if (tag.template !== initialTmpl) { - tag._.tmpl = tag.template; // This will override the tag.template and also tagCtx.props.tmpl for all tagCtxs - } - if (linkCtx) { - // Set attr on linkCtx to ensure outputting to the correct target attribute. - // Setting either linkCtx.attr or this.attr in the init() allows per-instance choice of target attrib. - linkCtx.attr = tag.attr = linkCtx.attr || tag.attr; - } - } - - itemRet = undefined; - if (tag.render) { - itemRet = tag.render.apply(tag, args); - } - args = args.length ? args : [parentView]; // no arguments - get data context from view. - itemRet = itemRet !== undefined - ? itemRet // Return result of render function unless it is undefined, in which case return rendered template - : tagCtx.render(args[0], true) || (isUpdate ? undefined : ""); - // No return value from render, and no template/content tagCtx.render(...), so return undefined - ret = ret ? ret + (itemRet || "") : itemRet; // If no rendered content, this will be undefined - } - - delete tag.rendering; - } - tag.tagCtx = tag.tagCtxs[0]; - tag.ctx = tag.tagCtx.ctx; - - if (tag._.inline && (attr = tag.attr) && attr !== htmlStr) { - // inline tag with attr set to "text" will insert HTML-encoded content - as if it was element-based innerText - ret = attr === "text" - ? $converters.html(ret) - : ""; - } - return boundTag && parentView._.onRender - // Call onRender (used by JsViews if present, to add binding annotations around rendered content) - ? parentView._.onRender(ret, parentView, boundTag) - : ret; - } - - //================= - // View constructor - //================= - - function View(context, type, parentView, data, template, key, contentTmpl, onRender) { - // Constructor for view object in view hierarchy. (Augmented by JsViews if JsViews is loaded) - var views, parentView_, tag, - self = this, - isArray = type === "array", - self_ = { - key: 0, - useKey: isArray ? 0 : 1, - id: "" + viewId++, - onRender: onRender, - bnds: {} - }; - - self.data = data; - self.tmpl = template, - self.content = contentTmpl; - self.views = isArray ? [] : {}; - self.parent = parentView; - self.type = type || "top"; - // If the data is an array, this is an 'array view' with a views array for each child 'item view' - // If the data is not an array, this is an 'item view' with a views 'hash' object for any child nested views - // ._.useKey is non zero if is not an 'array view' (owning a data array). Use this as next key for adding to child views hash - self._ = self_; - self.linked = !!onRender; - if (parentView) { - views = parentView.views; - parentView_ = parentView._; - if (parentView_.useKey) { - // Parent is an 'item view'. Add this view to its views object - // self._key = is the key in the parent view hash - views[self_.key = "_" + parentView_.useKey++] = self; - self.index = indexStr; - self.getIndex = getNestedIndex; - tag = parentView_.tag; - self_.bnd = isArray && (!tag || !!tag._.bnd && tag); // For array views that are data bound for collection change events, set the - // view._.bnd property to true for top-level link() or data-link="{for}", or to the tag instance for a data-bound tag, e.g. {^{for ...}} - } else { - // Parent is an 'array view'. Add this view to its views array - views.splice( - // self._.key = self.index - the index in the parent view array - self_.key = self.index = key, - 0, self); - } - // If no context was passed in, use parent context - // If context was passed in, it should have been merged already with parent context - self.ctx = context || parentView.ctx; - } else { - self.ctx = context; - } - } - - View.prototype = { - get: getView, - getIndex: getIndex, - getRsc: getResource, - hlp: getHelper, - _is: "view" - }; - - //============= - // Registration - //============= - - function compileChildResources(parentTmpl) { - var storeName, resources, resourceName, resource, settings, compile, onStore; - for (storeName in jsvStores) { - settings = jsvStores[storeName]; - if ((compile = settings.compile) && (resources = parentTmpl[storeName + "s"])) { - for (resourceName in resources) { - // compile child resource declarations (templates, tags, tags["for"] or helpers) - resource = resources[resourceName] = compile(resourceName, resources[resourceName], parentTmpl); - if (resource && (onStore = $sub.onStore[storeName])) { - // e.g. JsViews integration - onStore(resourceName, resource, compile); - } - } - } - } - } - - function compileTag(name, tagDef, parentTmpl) { - var init, tmpl; - if ($isFunction(tagDef)) { - // Simple tag declared as function. No presenter instantation. - tagDef = { - depends: tagDef.depends, - render: tagDef - }; - } else { - if (tagDef.baseTag) { - tagDef.flow = !!tagDef.flow; // default to false even if baseTag has flow=true - tagDef = $extend($extend({}, tagDef.baseTag), tagDef); - } - // Tag declared as object, used as the prototype for tag instantiation (control/presenter) - if ((tmpl = tagDef.template) !== undefined) { - tagDef.template = "" + tmpl === tmpl ? ($templates[tmpl] || $templates(tmpl)) : tmpl; - } - if (tagDef.init !== false) { - // Set int: false on tagDef if you want to provide just a render method, or render and template, but no constuctor or prototype. - // so equivalent to setting tag to render function, except you can also provide a template. - init = tagDef._ctr = function() {}; - (init.prototype = tagDef).constructor = init; - } - } - if (parentTmpl) { - tagDef._parentTmpl = parentTmpl; - } - return tagDef; - } - - function compileTmpl(name, tmpl, parentTmpl, options) { - // tmpl is either a template object, a selector for a template script block, the name of a compiled template, or a template object - - //==== nested functions ==== - function tmplOrMarkupFromStr(value) { - // If value is of type string - treat as selector, or name of compiled template - // Return the template object, if already compiled, or the markup string - - if (("" + value === value) || value.nodeType > 0) { - try { - elem = value.nodeType > 0 - ? value - : !rTmplString.test(value) - // If value is a string and does not contain HTML or tag content, then test as selector - && jQuery && jQuery(global.document).find(value)[0]; // TODO address case where DOM is not available - // If selector is valid and returns at least one element, get first element - // If invalid, jQuery will throw. We will stay with the original string. - } catch (e) {} - - if (elem) { - // Generally this is a script element. - // However we allow it to be any element, so you can for example take the content of a div, - // use it as a template, and replace it by the same content rendered against data. - // e.g. for linking the content of a div to a container, and using the initial content as template: - // $.link("#content", model, {tmpl: "#content"}); - - value = $templates[name = name || elem.getAttribute(tmplAttr)]; - if (!value) { - // Not already compiled and cached, so compile and cache the name - // Create a name for compiled template if none provided - name = name || "_" + autoTmplName++; - elem.setAttribute(tmplAttr, name); - // Use tmpl as options - value = $templates[name] = compileTmpl(name, elem.innerHTML, parentTmpl, options); - } - elem = undefined; - } - return value; - } - // If value is not a string, return undefined - } - - var tmplOrMarkup, elem; - - //==== Compile the template ==== - tmpl = tmpl || ""; - tmplOrMarkup = tmplOrMarkupFromStr(tmpl); - - // If options, then this was already compiled from a (script) element template declaration. - // If not, then if tmpl is a template object, use it for options - options = options || (tmpl.markup ? tmpl : {}); - options.tmplName = name; - if (parentTmpl) { - options._parentTmpl = parentTmpl; - } - // If tmpl is not a markup string or a selector string, then it must be a template object - // In that case, get it from the markup property of the object - if (!tmplOrMarkup && tmpl.markup && (tmplOrMarkup = tmplOrMarkupFromStr(tmpl.markup))) { - if (tmplOrMarkup.fn && (tmplOrMarkup.debug !== tmpl.debug || tmplOrMarkup.allowCode !== tmpl.allowCode)) { - // if the string references a compiled template object, but the debug or allowCode props are different, need to recompile - tmplOrMarkup = tmplOrMarkup.markup; - } - } - if (tmplOrMarkup !== undefined) { - if (name && !parentTmpl) { - $render[name] = function() { - return tmpl.render.apply(tmpl, arguments); - }; - } - if (tmplOrMarkup.fn || tmpl.fn) { - // tmpl is already compiled, so use it, or if different name is provided, clone it - if (tmplOrMarkup.fn) { - if (name && name !== tmplOrMarkup.tmplName) { - tmpl = extendCtx(options, tmplOrMarkup); - } else { - tmpl = tmplOrMarkup; - } - } - } else { - // tmplOrMarkup is a markup string, not a compiled template - // Create template object - tmpl = TmplObject(tmplOrMarkup, options); - // Compile to AST and then to compiled function - tmplFn(tmplOrMarkup.replace(rEscapeQuotes, "\\$&"), tmpl); - } - compileChildResources(options); - return tmpl; - } - } - - function dataMap(mapDef) { - function newMap(source, options) { - this.tgt = mapDef.getTgt(source, options); - } - - if ($isFunction(mapDef)) { - // Simple map declared as function - mapDef = { - getTgt: mapDef - }; - } - - if (mapDef.baseMap) { - mapDef = $extend($extend({}, mapDef.baseMap), mapDef); - } - - mapDef.map = function(source, options) { - return new newMap(source, options); - }; - return mapDef; - } - - //==== /end of function compile ==== - - function TmplObject(markup, options) { - // Template object constructor - var htmlTag, - wrapMap = $viewsSettings.wrapMap || {}, - tmpl = $extend( - { - markup: markup, - tmpls: [], - links: {}, // Compiled functions for link expressions - tags: {}, // Compiled functions for bound tag expressions - bnds: [], - _is: "template", - render: fastRender - }, - options - ); - - if (!options.htmlTag) { - // Set tmpl.tag to the top-level HTML tag used in the template, if any... - htmlTag = rFirstElem.exec(markup); - tmpl.htmlTag = htmlTag ? htmlTag[1].toLowerCase() : ""; - } - htmlTag = wrapMap[tmpl.htmlTag]; - if (htmlTag && htmlTag !== wrapMap.div) { - // When using JsViews, we trim templates which are inserted into HTML contexts where text nodes are not rendered (i.e. not 'Phrasing Content'). - // Currently not trimmed for
  • tag. (Not worth adding perf cost) - tmpl.markup = $.trim(tmpl.markup); - } - - return tmpl; - } - - function registerStore(storeName, storeSettings) { - - function theStore(name, item, parentTmpl) { - // The store is also the function used to add items to the store. e.g. $.templates, or $.views.tags - - // For store of name 'thing', Call as: - // $.views.things(items[, parentTmpl]), - // or $.views.things(name, item[, parentTmpl]) - - var onStore, compile, itemName, thisStore; - - if (name && typeof name === "object" && !name.nodeType && !name.markup && !name.getTgt) { - // Call to $.views.things(items[, parentTmpl]), - - // Adding items to the store - // If name is a hash, then item is parentTmpl. Iterate over hash and call store for key. - for (itemName in name) { - theStore(itemName, name[itemName], item); - } - return $views; - } - // Adding a single unnamed item to the store - if (item === undefined) { - item = name; - name = undefined; - } - if (name && "" + name !== name) { // name must be a string - parentTmpl = item; - item = name; - name = undefined; - } - thisStore = parentTmpl ? parentTmpl[storeNames] = parentTmpl[storeNames] || {} : theStore; - compile = storeSettings.compile; - if (item === null) { - // If item is null, delete this entry - name && delete thisStore[name]; - } else { - item = compile ? (item = compile(name, item, parentTmpl)) : item; - name && (thisStore[name] = item); - } - if (compile && item) { - item._is = storeName; // Only do this for compiled objects (tags, templates...) - } - if (item && (onStore = $sub.onStore[storeName])) { - // e.g. JsViews integration - onStore(name, item, compile); - } - return item; - } - - var storeNames = storeName + "s"; - - $views[storeNames] = theStore; - jsvStores[storeName] = storeSettings; - } - - //============== - // renderContent - //============== - - function $fastRender(data, context, noIteration) { - var tmplElem = this.jquery && (this[0] || error('Unknown template: "' + this.selector + '"')), - tmpl = tmplElem.getAttribute(tmplAttr); - - return fastRender.call(tmpl ? $templates[tmpl] : $templates(tmplElem), data, context, noIteration); - } - - function tryFn(tmpl, data, view) { - if ($viewsSettings._dbgMode) { - try { - return tmpl.fn(data, view, $views); - } - catch (e) { - return error(e, view); - } - } - return tmpl.fn(data, view, $views); - } - - function fastRender(data, context, noIteration, parentView, key, onRender) { - var self = this; - if (!parentView && self.fn._nvw && !$.isArray(data)) { - return tryFn(self, data, {tmpl: self}); - } - return renderContent.call(self, data, context, noIteration, parentView, key, onRender); - } - - function renderContent(data, context, noIteration, parentView, key, onRender) { - // Render template against data as a tree of subviews (nested rendered template instances), or as a string (top-level template). - // If the data is the parent view, treat as noIteration, re-render with the same data context. - var i, l, dataItem, newView, childView, itemResult, swapContent, tagCtx, contentTmpl, tag_, outerOnRender, tmplName, tmpl, noViews, - self = this, - result = ""; - - if (!!context === context) { - noIteration = context; // passing boolean as second param - noIteration - context = undefined; - } - - if (key === true) { - swapContent = true; - key = 0; - } - - if (self.tag) { - // This is a call from renderTag or tagCtx.render(...) - tagCtx = self; - self = self.tag; - tag_ = self._; - tmplName = self.tagName; - tmpl = tag_.tmpl || tagCtx.tmpl; - noViews = self.attr && self.attr !== htmlStr, - context = extendCtx(context, self.ctx); - contentTmpl = tagCtx.content; // The wrapped content - to be added to views, below - if (tagCtx.props.link === false) { - // link=false setting on block tag - // We will override inherited value of link by the explicit setting link=false taken from props - // The child views of an unlinked view are also unlinked. So setting child back to true will not have any effect. - context = context || {}; - context.link = false; - } - parentView = parentView || tagCtx.view; - data = arguments.length ? data : parentView; - } else { - tmpl = self; - } - - if (tmpl) { - if (!parentView && data && data._is === "view") { - parentView = data; // When passing in a view to render or link (and not passing in a parent view) use the passed in view as parentView - } - if (parentView) { - contentTmpl = contentTmpl || parentView.content; // The wrapped content - to be added as #content property on views, below - onRender = onRender || parentView._.onRender; - if (data === parentView) { - // Inherit the data from the parent view. - // This may be the contents of an {{if}} block - data = parentView.data; - } - context = extendCtx(context, parentView.ctx); - } - if (!parentView || parentView.type === "top") { - (context = context || {}).root = data; // Provide ~root as shortcut to top-level data. - } - - // Set additional context on views created here, (as modified context inherited from the parent, and to be inherited by child views) - // Note: If no jQuery, $extend does not support chained copies - so limit extend() to two parameters - - if (!tmpl.fn) { - tmpl = $templates[tmpl] || $templates(tmpl); - } - - if (tmpl) { - onRender = (context && context.link) !== false && !noViews && onRender; - // If link===false, do not call onRender, so no data-linking marker nodes - outerOnRender = onRender; - if (onRender === true) { - // Used by view.refresh(). Don't create a new wrapper view. - outerOnRender = undefined; - onRender = parentView._.onRender; - } - context = tmpl.helpers - ? extendCtx(tmpl.helpers, context) - : context; - if ($.isArray(data) && !noIteration) { - // Create a view for the array, whose child views correspond to each data item. (Note: if key and parentView are passed in - // along with parent view, treat as insert -e.g. from view.addViews - so parentView is already the view item for array) - newView = swapContent - ? parentView : - (key !== undefined && parentView) || new View(context, "array", parentView, data, tmpl, key, contentTmpl, onRender); - for (i = 0, l = data.length; i < l; i++) { - // Create a view for each data item. - dataItem = data[i]; - childView = new View(context, "item", newView, dataItem, tmpl, (key || 0) + i, contentTmpl, onRender); - itemResult = tryFn(tmpl, dataItem, childView); - result += newView._.onRender ? newView._.onRender(itemResult, childView) : itemResult; - } - } else { - // Create a view for singleton data object. The type of the view will be the tag name, e.g. "if" or "myTag" except for - // "item", "array" and "data" views. A "data" view is from programmatic render(object) against a 'singleton'. - if (parentView || !tmpl.fn._nvw) { - newView = swapContent ? parentView : new View(context, tmplName || "data", parentView, data, tmpl, key, contentTmpl, onRender); - if (tag_ && !self.flow) { - newView.tag = self; - } - } - result += tryFn(tmpl, data, newView); - } - return outerOnRender ? outerOnRender(result, newView) : result; - } - } - return ""; - } - - //=========================== - // Build and compile template - //=========================== - - // Generate a reusable function that will serve to render a template against data - // (Compile AST then build template function) - - function error(e, view, fallback) { - var message = $viewsSettings.onError(e, view, fallback); - if ("" + e === e) { // if e is a string, not an Exception, then throw new Exception - throw new $sub.Err(message); - } - return !view.linkCtx && view.linked ? $converters.html(message) : message; - } - - function syntaxError(message) { - error("Syntax error\n" + message); - } - - function tmplFn(markup, tmpl, isLinkExpr, convertBack) { - // Compile markup to AST (abtract syntax tree) then build the template function code from the AST nodes - // Used for compiling templates, and also by JsViews to build functions for data link expressions - - //==== nested functions ==== - function pushprecedingContent(shift) { - shift -= loc; - if (shift) { - content.push(markup.substr(loc, shift).replace(rNewLine, "\\n")); - } - } - - function blockTagCheck(tagName) { - tagName && syntaxError('Unmatched or missing tag: "{{/' + tagName + '}}" in template:\n' + markup); - } - - function parseTag(all, bind, tagName, converter, colon, html, comment, codeTag, params, slash, closeBlock, index) { - - // bind tag converter colon html comment code params slash closeBlock - // /{(\^)?{(?:(?:(\w+(?=[\/\s}]))|(?:(\w+)?(:)|(>)|!--((?:[^-]|-(?!-))*)--|(\*)))\s*((?:[^}]|}(?!}))*?)(\/)?|(?:\/(\w+)))}}/g - // Build abstract syntax tree (AST): [tagName, converter, params, content, hash, bindings, contentMarkup] - if (html) { - colon = ":"; - converter = htmlStr; - } - slash = slash || isLinkExpr; - - var pathBindings = (bind || isLinkExpr) && [[]], - props = "", - args = "", - ctxProps = "", - paramsArgs = "", - paramsProps = "", - paramsCtxProps = "", - onError = "", - useTrigger = "", - // Block tag if not self-closing and not {{:}} or {{>}} (special case) and not a data-link expression - block = !slash && !colon && !comment; - - //==== nested helper function ==== - tagName = tagName || (params = params || "#data", colon); // {{:}} is equivalent to {{:#data}} - pushprecedingContent(index); - loc = index + all.length; // location marker - parsed up to here - if (codeTag) { - if (allowCode) { - content.push(["*", "\n" + params.replace(rUnescapeQuotes, "$1") + "\n"]); - } - } else if (tagName) { - if (tagName === "else") { - if (rTestElseIf.test(params)) { - syntaxError('for "{{else if expr}}" use "{{else expr}}"'); - } - pathBindings = current[7]; - current[8] = markup.substring(current[8], index); // contentMarkup for block tag - current = stack.pop(); - content = current[2]; - block = true; - } - if (params) { - // remove newlines from the params string, to avoid compiled code errors for unterminated strings - parseParams(params.replace(rNewLine, " "), pathBindings, tmpl) - .replace(rBuildHash, function(all, onerror, isCtx, key, keyToken, keyValue, arg, param) { - if (arg) { - args += keyValue + ","; - paramsArgs += "'" + param + "',"; - } else if (isCtx) { - ctxProps += key + keyValue + ","; - paramsCtxProps += key + "'" + param + "',"; - } else if (onerror) { - onError += keyValue; - } else { - if (keyToken === "trigger") { - useTrigger += keyValue; - } - props += key + keyValue + ","; - paramsProps += key + "'" + param + "',"; - hasHandlers = hasHandlers || rHasHandlers.test(keyToken); - } - return ""; - }).slice(0, -1); - - if (pathBindings && pathBindings[0]) { - pathBindings.pop(); // Remove the bindings that was prepared for next arg. (There is always an extra one ready). - } - } - - newNode = [ - tagName, - converter || !!convertBack || hasHandlers || "", - block && [], - parsedParam(paramsArgs, paramsProps, paramsCtxProps), - parsedParam(args, props, ctxProps), - onError, - useTrigger, - pathBindings || 0 - ]; - content.push(newNode); - if (block) { - stack.push(current); - current = newNode; - current[8] = loc; // Store current location of open tag, to be able to add contentMarkup when we reach closing tag - } - } else if (closeBlock) { - blockTagCheck(closeBlock !== current[0] && current[0] !== "else" && closeBlock); - current[8] = markup.substring(current[8], index); // contentMarkup for block tag - current = stack.pop(); - } - blockTagCheck(!current && closeBlock); - content = current[2]; - } - //==== /end of nested functions ==== - - var result, newNode, hasHandlers, - allowCode = tmpl && tmpl.allowCode, - astTop = [], - loc = 0, - stack = [], - content = astTop, - current = [,,astTop]; - -//TODO result = tmplFnsCache[markup]; // Only cache if template is not named and markup length < ..., -//and there are no bindings or subtemplates?? Consider standard optimization for data-link="a.b.c" -// if (result) { -// tmpl.fn = result; -// } else { - -// result = markup; - if (isLinkExpr) { - markup = delimOpenChar0 + markup + delimCloseChar1; - } - - blockTagCheck(stack[0] && stack[0][2].pop()[0]); - // Build the AST (abstract syntax tree) under astTop - markup.replace(rTag, parseTag); - - pushprecedingContent(markup.length); - - if (loc = astTop[astTop.length - 1]) { - blockTagCheck("" + loc !== loc && (+loc[8] === loc[8]) && loc[0]); - } -// result = tmplFnsCache[markup] = buildCode(astTop, tmpl); -// } - - if (isLinkExpr) { - result = buildCode(astTop, markup, isLinkExpr); - setPaths(result, astTop[0][7]); // With data-link expressions, pathBindings array is astTop[0][7] - } else { - result = buildCode(astTop, tmpl); - } - if (result._nvw) { - result._nvw = !/[~#]/.test(markup); - } - return result; - } - - function setPaths(fn, paths) { - fn.deps = []; - for (var key in paths) { - if (key !== "_jsvto" && paths[key].length) { - fn.deps = fn.deps.concat(paths[key]); - } - } - fn.paths = paths; - } - - function parsedParam(args, props, ctx) { - return [args.slice(0, -1), props.slice(0, -1), ctx.slice(0, -1)]; - } - - function paramStructure(parts, type) { - return '\n\t' + (type ? type + ':{' : '') + 'args:[' + parts[0] + ']' + (parts[1] || !type ? ',\n\tprops:{' + parts[1] + '}' : "") + (parts[2] ? ',\n\tctx:{' + parts[2] + '}' : ""); - } - - function parseParams(params, pathBindings, tmpl) { - - function parseTokens(all, lftPrn0, lftPrn, bound, path, operator, err, eq, path2, prn, comma, lftPrn2, apos, quot, rtPrn, rtPrnDot, prn2, space, index, full) { - //rParams = /(\()(?=\s*\()|(?:([([])\s*)?(?:(\^?)(!*?[#~]?[\w$.^]+)?\s*((\+\+|--)|\+|-|&&|\|\||===|!==|==|!=|<=|>=|[<>%*:?\/]|(=))\s*|(!*?[#~]?[\w$.^]+)([([])?)|(,\s*)|(\(?)\\?(?:(')|("))|(?:\s*(([)\]])(?=\s*\.|\s*\^)|[)\]])([([]?))|(\s+)/g, - // lftPrn0 lftPrn bound path operator err eq path2 prn comma lftPrn2 apos quot rtPrn rtPrnDot prn2 space - // (left paren? followed by (path? followed by operator) or (path followed by paren?)) or comma or apos or quot or right paren or space - operator = operator || ""; - lftPrn = lftPrn || lftPrn0 || lftPrn2; - path = path || path2; - prn = prn || prn2 || ""; - - var expr, isFn, exprFn, - fullLength = full.length - 1; - - function parsePath(allPath, not, object, helper, view, viewProperty, pathTokens, leafToken) { - // rPath = /^(?:null|true|false|\d[\d.]*|(!*?)([\w$]+|\.|~([\w$]+)|#(view|([\w$]+))?)([\w$.^]*?)(?:[.[^]([\w$]+)\]?)?)$/g, - // none object helper view viewProperty pathTokens leafToken - if (object) { - if (bindings) { - if (named === "linkTo") { - bindto = pathBindings._jsvto = pathBindings._jsvto || []; - bindto.push(path); - } - if (!named || boundName) { - bindings.push(path.slice(not.length)); // Add path binding for paths on props and args - } - } - if (object !== ".") { - var ret = (helper - ? 'view.hlp("' + helper + '")' - : view - ? "view" - : "data") - + (leafToken - ? (viewProperty - ? "." + viewProperty - : helper - ? "" - : (view ? "" : "." + object) - ) + (pathTokens || "") - : (leafToken = helper ? "" : view ? viewProperty || "" : object, "")); - - ret = ret + (leafToken ? "." + leafToken : ""); - - return not + (ret.slice(0, 9) === "view.data" - ? ret.slice(5) // convert #view.data... to data... - : ret); - } - } - return allPath; - } - - if (err && !aposed && !quoted) { - syntaxError(params); - } else { - if (bindings && rtPrnDot && !aposed && !quoted) { - // This is a binding to a path in which an object is returned by a helper/data function/expression, e.g. foo()^x.y or (a?b:c)^x.y - // We create a compiled function to get the object instance (which will be called when the dependent data of the subexpression changes, to return the new object, and trigger re-binding of the subsequent path) - if (!named || boundName || bindto) { - expr = pathStart[parenDepth]; - if (fullLength > index - expr) { // We need to compile a subexpression - expr = full.slice(expr, index + 1); - rtPrnDot = delimOpenChar1 + ":" + expr // The parameter or function subexpression - + " onerror=''" // set onerror='' in order to wrap generated code with a try catch - returning '' as object instance if there is an error/missing parent - + delimCloseChar0; - exprFn = tmplLinks[rtPrnDot]; - if (!exprFn) { - tmplLinks[rtPrnDot] = true; // Flag that this exprFn (for rtPrnDot) is being compiled - tmplLinks[rtPrnDot] = exprFn = tmplFn(rtPrnDot, tmpl || bindings, true); // Compile the expression (or use cached copy already in tmpl.links) - exprFn.paths.push({_jsvOb: exprFn}); //list.push({_jsvOb: rtPrnDot}); - } - if (exprFn !== true) { // If not reentrant call during compilation - (bindto || bindings).push({_jsvOb: exprFn}); // Insert special object for in path bindings, to be used for binding the compiled sub expression () - } - } - } - } - return (aposed - // within single-quoted string - ? (aposed = !apos, (aposed ? all : '"')) - : quoted - // within double-quoted string - ? (quoted = !quot, (quoted ? all : '"')) - : - ( - (lftPrn - ? (parenDepth++, pathStart[parenDepth] = index++, lftPrn) - : "") - + (space - ? (parenDepth - ? "" - // New arg or prop - so insert backspace \b (\x08) as separator for named params, used subsequently by rBuildHash, and prepare new bindings array - : (paramIndex = full.slice(paramIndex, index), named - ? (named = boundName = bindto = false, "\b") - : "\b,") + paramIndex + (paramIndex = index + all.length, bindings && pathBindings.push(bindings = []), "\b") - ) - : eq - // named param. Remove bindings for arg and create instead bindings array for prop - ? (parenDepth && syntaxError(params), bindings && pathBindings.pop(), named = path, boundName = bound, paramIndex = index + all.length, bound && (bindings = pathBindings[named] = []), path + ':') - : path - // path - ? (path.split("^").join(".").replace(rPath, parsePath) - + (prn - ? (fnCall[++parenDepth] = true, path.charAt(0) !== "." && (pathStart[parenDepth] = index), isFn ? "" : prn) - : operator) - ) - : operator - ? operator - : rtPrn - // function - ? ((fnCall[parenDepth--] = false, rtPrn) - + (prn - ? (fnCall[++parenDepth] = true, prn) - : "") - ) - : comma - ? (fnCall[parenDepth] || syntaxError(params), ",") // We don't allow top-level literal arrays or objects - : lftPrn0 - ? "" - : (aposed = apos, quoted = quot, '"') - )) - ); - } - } - var named, bindto, boundName, - quoted, // boolean for string content in double quotes - aposed, // or in single quotes - bindings = pathBindings && pathBindings[0], // bindings array for the first arg - paramIndex = 0, // list, - tmplLinks = tmpl ? tmpl.links : bindings && (bindings.links = bindings.links || {}), - fnCall = {}, - pathStart = {0: -1}, - parenDepth = 0; - //pushBindings(); - return (params + (tmpl ? " " : "")) - .replace(/\)\^/g, ").") // Treat "...foo()^bar..." as equivalent to "...foo().bar..." - //since preceding computed observables in the path will always be updated if their dependencies change - .replace(rParams, parseTokens); - } - - function buildCode(ast, tmpl, isLinkExpr) { - // Build the template function code from the AST nodes, and set as property on the passed-in template object - // Used for compiling templates, and also by JsViews to build functions for data link expressions - var i, node, tagName, converter, tagCtx, hasTag, hasEncoder, getsVal, hasCnvt, needView, useCnvt, tmplBindings, pathBindings, params, boundOnErrStart, boundOnErrEnd, - tagRender, nestedTmpls, tmplName, nestedTmpl, tagAndElses, content, markup, nextIsElse, oldCode, isElse, isGetVal, tagCtxFn, onError, tagStart, trigger, - tmplBindingKey = 0, - code = "", - tmplOptions = {}, - l = ast.length; - - if ("" + tmpl === tmpl) { - tmplName = isLinkExpr ? 'data-link="' + tmpl.replace(rNewLine, " ").slice(1, -1) + '"' : tmpl; - tmpl = 0; - } else { - tmplName = tmpl.tmplName || "unnamed"; - if (tmpl.allowCode) { - tmplOptions.allowCode = true; - } - if (tmpl.debug) { - tmplOptions.debug = true; - } - tmplBindings = tmpl.bnds; - nestedTmpls = tmpl.tmpls; - } - for (i = 0; i < l; i++) { - // AST nodes: [tagName, converter, content, params, code, onError, pathBindings, contentMarkup, link] - node = ast[i]; - - // Add newline for each callout to t() c() etc. and each markup string - if ("" + node === node) { - // a markup string to be inserted - code += '\n+"' + node + '"'; - } else { - // a compiled tag expression to be inserted - tagName = node[0]; - if (tagName === "*") { - // Code tag: {{* }} - code += ";\n" + node[1] + "\nret=ret"; - } else { - converter = node[1]; - content = node[2]; - tagCtx = paramStructure(node[3], 'params') + '},' + paramStructure(params = node[4]); - onError = node[5]; - trigger = node[6]; - markup = node[8]; - if (!(isElse = tagName === "else")) { - tmplBindingKey = 0; - if (tmplBindings && (pathBindings = node[7])) { // Array of paths, or false if not data-bound - tmplBindingKey = tmplBindings.push(pathBindings); - } - } - if (isGetVal = tagName === ":") { - if (converter) { - tagName = converter === htmlStr ? ">" : converter + tagName; - } - } else { - if (content) { - // Create template object for nested template - nestedTmpl = TmplObject(markup, tmplOptions); - nestedTmpl.tmplName = tmplName + "/" + tagName; - // Compile to AST and then to compiled function - buildCode(content, nestedTmpl); - nestedTmpls.push(nestedTmpl); - } - - if (!isElse) { - // This is not an else tag. - tagAndElses = tagName; - // Switch to a new code string for this bound tag (and its elses, if it has any) - for returning the tagCtxs array - oldCode = code; - code = ""; - } - nextIsElse = ast[i + 1]; - nextIsElse = nextIsElse && nextIsElse[0] === "else"; - } - tagStart = onError ? ";\ntry{\nret+=" : "\n+"; - boundOnErrStart = ""; - boundOnErrEnd= ""; - - if (isGetVal && (pathBindings || trigger || converter && converter !== htmlStr)) { - // For convertVal we need a compiled function to return the new tagCtx(s) - tagCtxFn = "return {" + tagCtx + "};"; - tagRender = 'c("' + converter + '",view,'; - tagCtxFn = new Function("data,view,j,u", " // " + tmplName + " " + tmplBindingKey + " " + tagName - + "\n" + tagCtxFn); - tagCtxFn._er = onError; - - boundOnErrStart = tagRender + tmplBindingKey + ","; - boundOnErrEnd = ")"; - - tagCtxFn._tag = tagName; - if (isLinkExpr) { - return tagCtxFn; - } - setPaths(tagCtxFn, pathBindings); - useCnvt = true; - } - code += (isGetVal - ? (isLinkExpr ? (onError ? "\ntry{\n" : "") + "return " : tagStart) + (useCnvt // Call _cnvt if there is a converter: {{cnvt: ... }} or {^{cnvt: ... }} - ? (useCnvt = undefined, needView = hasCnvt = true, tagRender + (pathBindings - ? ((tmplBindings[tmplBindingKey - 1] = tagCtxFn), tmplBindingKey) // Store the compiled tagCtxFn in tmpl.bnds, and pass the key to convertVal() - : "{" + tagCtx + "}") + ")") - : tagName === ">" - ? (hasEncoder = true, "h(" + params[0] + ')') - : (getsVal = true, "((v=" + params[0] + ')!=null?v:"")') // Strict equality just for data-link="title{:expr}" so expr=null will remove title attribute - ) - : (needView = hasTag = true, "\n{view:view,tmpl:" // Add this tagCtx to the compiled code for the tagCtxs to be passed to renderTag() - + (content ? nestedTmpls.length : "0") + "," // For block tags, pass in the key (nestedTmpls.length) to the nested content template - + tagCtx + "},")); - - if (tagAndElses && !nextIsElse) { - // This is a data-link expression or an inline bound tag without any elses, or the last {{else}} of an inline bound tag - // We complete the code for returning the tagCtxs array - code = "[" + code.slice(0, -1) + "]"; - tagRender = 't("' + tagAndElses + '",view,this,'; - if (isLinkExpr || pathBindings) { - // This is a bound tag (data-link expression or inline bound tag {^{tag ...}}) so we store a compiled tagCtxs function in tmp.bnds - code = new Function("data,view,j,u", " // " + tmplName + " " + tmplBindingKey + " " + tagAndElses + "\nreturn " + code + ";"); - code._er = onError; - code._tag = tagName; - if (pathBindings) { - setPaths(tmplBindings[tmplBindingKey - 1] = code, pathBindings); - } - if (isLinkExpr) { - return code; // For a data-link expression we return the compiled tagCtxs function - } - boundOnErrStart = tagRender + tmplBindingKey + ",undefined,"; - boundOnErrEnd = ")"; - } - - // This is the last {{else}} for an inline tag. - // For a bound tag, pass the tagCtxs fn lookup key to renderTag. - // For an unbound tag, include the code directly for evaluating tagCtxs array - code = oldCode + tagStart + tagRender + (tmplBindingKey || code) + ")"; - pathBindings = 0; - tagAndElses = 0; - } - if (onError) { - needView = true; - code += ';\n}catch(e){ret' + (isLinkExpr ? "urn " : "+=") + boundOnErrStart + 'j._err(e,view,' + onError + ')' + boundOnErrEnd + ';}\n' + (isLinkExpr ? "" : 'ret=ret'); - } - } - } - } - // Include only the var references that are needed in the code - code = "// " + tmplName - - + "\nvar v" - + (hasTag ? ",t=j._tag" : "") // has tag - + (hasCnvt ? ",c=j._cnvt" : "") // converter - + (hasEncoder ? ",h=j.converters.html" : "") // html converter - + (isLinkExpr ? ";\n" : ',ret=""\n') - + (tmplOptions.debug ? "debugger;" : "") - + code - + (isLinkExpr ? "\n" : ";\nreturn ret;"); - try { - code = new Function("data,view,j,u", code); - } catch (e) { - syntaxError("Compiled template code:\n\n" + code + '\n: "' + e.message + '"'); - } - if (tmpl) { - tmpl.fn = code; - } - if (!needView) { - code._nvw = true; - } - return code; - } - - //========== - // Utilities - //========== - - // Merge objects, in particular contexts which inherit from parent contexts - function extendCtx(context, parentContext) { - // Return copy of parentContext, unless context is defined and is different, in which case return a new merged context - // If neither context nor parentContext are defined, return undefined - return context && context !== parentContext - ? (parentContext - ? $extend($extend({}, parentContext), context) - : context) - : parentContext && $extend({}, parentContext); - } - - // Get character entity for HTML and Attribute encoding - function getCharEntity(ch) { - return charEntities[ch] || (charEntities[ch] = "&#" + ch.charCodeAt(0) + ";"); - } - - //========================== Initialize ========================== - - for (jsvStoreName in jsvStores) { - registerStore(jsvStoreName, jsvStores[jsvStoreName]); - } - - var $templates = $views.templates, - $converters = $views.converters, - $helpers = $views.helpers, - $tags = $views.tags, - $sub = $views.sub, - $viewsSettings = $views.settings; - - if (jQuery) { - //////////////////////////////////////////////////////////////////////////////////////////////// - // jQuery is loaded, so make $ the jQuery object - $ = jQuery; - $.fn.render = $fastRender; - if ($.observable) { - $extend($sub, $.views.sub); // jquery.observable.js was loaded before jsrender.js - $views.map = $.views.map; - } - } else { - //////////////////////////////////////////////////////////////////////////////////////////////// - // jQuery is not loaded. - - $ = global.jsviews = {}; - - $.isArray = Array && Array.isArray || function(obj) { - return Object.prototype.toString.call(obj) === "[object Array]"; - }; - - // //========================== Future Node.js support ========================== - // if ((nodeJsModule = global.module) && nodeJsModule.exports) { - // nodeJsModule.exports = $; - // } - } - - $.render = $render; - $.views = $views; - $.templates = $templates = $views.templates; - - $viewsSettings({ - debugMode: dbgMode, - delimiters: $viewsDelimiters, - onError: function(e, view, fallback) { - // Can override using $.views.settings({onError: function(...) {...}}); - if (view) { - // For render errors, e is an exception thrown in compiled template, and view is the current view. For other errors, e is an error string. - e = fallback === undefined - ? "{Error: " + e + "}" - : $isFunction(fallback) - ? fallback(e, view) : fallback; - } - return e == undefined ? "" : e; - }, - _dbgMode: true - }); - - //========================== Register tags ========================== - - $tags({ - "else": function() {}, // Does nothing but ensures {{else}} tags are recognized as valid - "if": { - render: function(val) { - // This function is called once for {{if}} and once for each {{else}}. - // We will use the tag.rendering object for carrying rendering state across the calls. - // If not done (a previous block has not been rendered), look at expression for this block and render the block if expression is truthy - // Otherwise return "" - var self = this, - ret = (self.rendering.done || !val && (arguments.length || !self.tagCtx.index)) - ? "" - : (self.rendering.done = true, self.selected = self.tagCtx.index, - // Test is satisfied, so render content on current context. We call tagCtx.render() rather than return undefined - // (which would also render the tmpl/content on the current context but would iterate if it is an array) - self.tagCtx.render(self.tagCtx.view, true)); // no arg, so renders against parentView.data - return ret; - }, - onUpdate: function(ev, eventArgs, tagCtxs) { - var tci, prevArg, different; - for (tci = 0; (prevArg = this.tagCtxs[tci]) && prevArg.args.length; tci++) { - prevArg = prevArg.args[0]; - different = !prevArg !== !tagCtxs[tci].args[0]; - if ((!this.convert && !!prevArg) || different) { - return different; - // If there is no converter, and newArg and prevArg are both truthy, return false to cancel update. (Even if values on later elses are different, we still don't want to update, since rendered output would be unchanged) - // If newArg and prevArg are different, return true, to update - // If newArg and prevArg are both falsey, move to the next {{else ...}} - } - } - // Boolean value of all args are unchanged (falsey), so return false to cancel update - return false; - }, - flow: true - }, - "for": { - render: function(val) { - // This function is called once for {{for}} and once for each {{else}}. - // We will use the tag.rendering object for carrying rendering state across the calls. - var finalElse, - self = this, - tagCtx = self.tagCtx, - result = "", - done = 0; - - if (!self.rendering.done) { - if (finalElse = !arguments.length) { - val = tagCtx.view.data; // For the final else, defaults to current data without iteration. - } - if (val !== undefined) { - result += tagCtx.render(val, finalElse); // Iterates except on final else, if data is an array. (Use {{include}} to compose templates without array iteration) - done += $.isArray(val) ? val.length : 1; - } - if (self.rendering.done = done) { - self.selected = tagCtx.index; - } - // If nothing was rendered we will look at the next {{else}}. Otherwise, we are done. - } - return result; - }, - flow: true - }, - include: { - flow: true - }, - "*": { - // {{* code... }} - Ignored if template.allowCode is false. Otherwise include code in compiled template - render: retVal, - flow: true - } - }); - - function getTargetProps(source) { - // this pointer is theMap - which has tagCtx.props too - // arguments: tagCtx.args. - var key, prop, - props = []; - - if (typeof source === "object") { - for (key in source) { - prop = source[key]; - if (!prop || !prop.toJSON || prop.toJSON()) { - if (!$isFunction(prop)) { - props.push({ key: key, prop: prop }); - } - } - } - } - return props; - } - - $tags("props", { - baseTag: $tags["for"], - dataMap: dataMap(getTargetProps) - }); - - //========================== Register converters ========================== - - function htmlEncode(text) { - // HTML encode: Replace < > & ' and " by corresponding entities. - return text != null ? rIsHtml.test(text) && ("" + text).replace(rHtmlEncode, getCharEntity) || text : ""; - } - - $converters({ - html: htmlEncode, - attr: htmlEncode, // Includes > encoding since rConvertMarkers in JsViews does not skip > characters in attribute strings - url: function(text) { - // URL encoding helper. - return text != undefined ? encodeURI("" + text) : text === null ? text : ""; // null returns null, e.g. to remove attribute. undefined returns "" - } - }); - - //========================== Define default delimiters ========================== - $viewsDelimiters(); - -})(this, this.jQuery); diff --git a/BuildFeed/Scripts/jsrender.min.js b/BuildFeed/Scripts/jsrender.min.js deleted file mode 100644 index ea2ffb7..0000000 --- a/BuildFeed/Scripts/jsrender.min.js +++ /dev/null @@ -1,6 +0,0 @@ -/*! JsRender v1.0.0-beta: http://github.com/BorisMoore/jsrender and http://jsviews.com/jsviews -informal pre V1.0 commit counter: 60 */ -(function(n,t,i){"use strict";function et(n,t){for(var i in t.props)wt.test(i)&&(n[i]=t.props[i])}function ot(n){return n}function ir(n){return n}function dt(n){s._dbgMode=n;pt=n?"Unavailable (nested view): use #getIndex()":"";it("dbg",ci.dbg=tt.dbg=n?ir:ot)}function st(n){this.name=(u.link?"JsViews":"JsRender")+" Error";this.message=n||this.name}function f(n,t){for(var i in t)n[i]=t[i];return n}function d(n){return typeof n=="function"}function gt(n,t,i){return(!o.rTag||n)&&(p=n?n.charAt(0):p,w=n?n.charAt(1):w,h=t?t.charAt(0):h,v=t?t.charAt(1):v,nt=i||nt,n="\\"+p+"(\\"+nt+")?\\"+w,t="\\"+h+"\\"+v,y="(?:(?:(\\w+(?=[\\/\\s\\"+h+"]))|(?:(\\w+)?(:)|(>)|!--((?:[^-]|-(?!-))*)--|(\\*)))\\s*((?:[^\\"+h+"]|\\"+h+"(?!\\"+v+"))*?)",o.rTag=y+")",y=new RegExp(n+y+"(\\/)?|(?:\\/(\\w+)))"+t,"g"),yt=new RegExp("<.*>|([^\\\\]|^)[{}]|"+n+".*"+t)),[p,w,h,v,nt]}function rr(n,t){t||(t=n,n=i);var e,f,o,u,r=this,s=!t||t==="root";if(n){if(u=r.type===t?r:i,!u)if(e=r.views,r._.useKey){for(f in e)if(u=e[f].get(n,t))break}else for(f=0,o=e.length;!u&&f0){try{h=u.nodeType>0?u:!yt.test(u)&&t&&t(n.document).find(u)[0]}catch(s){}return h&&(u=e[r=r||h.getAttribute(ft)],u||(r=r||"_"+nr++,h.setAttribute(ft,r),u=e[r]=ii(r,h.innerHTML,f,o)),h=i),u}}var s,h;return u=u||"",s=c(u),o=o||(u.markup?u:{}),o.tmplName=r,f&&(o._parentTmpl=f),!s&&u.markup&&(s=c(u.markup))&&s.fn&&(s.debug!==u.debug||s.allowCode!==u.allowCode)&&(s=s.markup),s!==i?(r&&!f&&(kt[r]=function(){return u.render.apply(u,arguments)}),s.fn||u.fn?s.fn&&(u=r&&r!==s.tmplName?a(o,s):s):(u=ui(s,o),lt(s.replace(pi,"\\$&"),u)),sr(o),u):void 0}function ri(n){function t(t,i){this.tgt=n.getTgt(t,i)}return d(n)&&(n={getTgt:n}),n.baseMap&&(n=f(f({},n.baseMap),n)),n.map=function(n,i){return new t(n,i)},n}function ui(n,t){var i,e=s.wrapMap||{},r=f({markup:n,tmpls:[],links:{},tags:{},bnds:[],_is:"template",render:fi},t);return t.htmlTag||(i=ki.exec(n),r.htmlTag=i?i[1].toLowerCase():""),i=e[r.htmlTag],i&&i!==e.div&&(r.markup=u.trim(r.markup)),r}function cr(n,t){function u(e,s,h){var v,c,l,a;if(e&&typeof e=="object"&&!e.nodeType&&!e.markup&&!e.getTgt){for(l in e)u(l,e[l],s);return r}return s===i&&(s=e,e=i),e&&""+e!==e&&(h=s,s=e,e=i),a=h?h[f]=h[f]||{}:u,c=t.compile,s===null?e&&delete a[e]:(s=c?s=c(e,s,h):s,e&&(a[e]=s)),c&&s&&(s._is=n),s&&(v=o.onStore[n])&&v(e,s,c),s}var f=n+"s";r[f]=u;k[n]=t}function lr(n,t,i){var r=this.jquery&&(this[0]||c('Unknown template: "'+this.selector+'"')),u=r.getAttribute(ft);return fi.call(u?e[u]:e(r),n,t,i)}function ct(n,t,i){if(s._dbgMode)try{return n.fn(t,i,r)}catch(u){return c(u,i)}return n.fn(t,i,r)}function fi(n,t,i,r,f,e){var o=this;return!r&&o.fn._nvw&&!u.isArray(n)?ct(o,n,{tmpl:o}):ei.call(o,n,t,i,r,f,e)}function ei(n,t,r,f,o,s){var y,ut,d,l,nt,tt,it,p,v,rt,w,ft,h,et,c=this,k="";if(!!t===t&&(r=t,t=i),o===!0&&(it=!0,o=0),c.tag?(p=c,c=c.tag,rt=c._,ft=c.tagName,h=rt.tmpl||p.tmpl,et=c.attr&&c.attr!==b,t=a(t,c.ctx),v=p.content,p.props.link===!1&&(t=t||{},t.link=!1),f=f||p.view,n=arguments.length?n:f):h=c,h&&(!f&&n&&n._is==="view"&&(f=n),f&&(v=v||f.content,s=s||f._.onRender,n===f&&(n=f.data),t=a(t,f.ctx)),f&&f.type!=="top"||((t=t||{}).root=n),h.fn||(h=e[h]||e(h)),h)){if(s=(t&&t.link)!==!1&&!et&&s,w=s,s===!0&&(w=i,s=f._.onRender),t=h.helpers?a(h.helpers,t):t,u.isArray(n)&&!r)for(l=it?f:o!==i&&f||new g(t,"array",f,n,h,o,v,s),y=0,ut=n.length;ypt-kt&&(kt=wt.slice(kt,pt+1),at=w+":"+kt+" onerror=''"+h,bt=y[at],bt||(y[at]=!0,y[at]=bt=lt(at,i||r,!0),bt.paths.push({_jsvOb:bt})),bt!==!0&&(s||r).push({_jsvOb:bt}))),o?(o=!st,o?b:'"'):e?(e=!ht,e?b:'"'):(d?(u++,p[u]=pt++,d):"")+(yt?u?"":(c=wt.slice(c,pt),f?(f=a=s=!1,"\b"):"\b,")+c+(c=pt+b.length,r&&t.push(r=[]),"\b"):rt?(u&&l(n),r&&t.pop(),f=nt,a=g,c=pt+b.length,g&&(r=t[f]=[]),nt+":"):nt?nt.split("^").join(".").replace(ai,ni)+(ft?(v[++u]=!0,nt.charAt(0)!=="."&&(p[u]=pt),dt?"":ft):tt):tt?tt:ct?(v[u--]=!1,ct)+(ft?(v[++u]=!0,ft):""):et?(v[u]||l(n),","):k?"":(o=st,e=ht,'"'));l(n)}var f,s,a,e,o,r=t&&t[0],c=0,y=i?i.links:r&&(r.links=r.links||{}),v={},p={0:-1},u=0;return(n+(i?" ":"")).replace(/\)\^/g,").").replace(vi,b)}function vt(n,t,r){var p,f,e,c,g,yt,pt,ni,wt,nt,ot,w,s,st,tt,it,v,ht,y,rt,k,ft,bt,d,kt,dt,ct,h,a,lt,gt,o=0,u="",et={},ti=n.length;for(""+t===t?(y=r?'data-link="'+t.replace(ut," ").slice(1,-1)+'"':t,t=0):(y=t.tmplName||"unnamed",t.allowCode&&(et.allowCode=!0),t.debug&&(et.debug=!0),w=t.bnds,ht=t.tmpls),p=0;p":c+e):(ft&&(rt=ui(bt,et),rt.tmplName=y+"/"+e,vt(ft,rt),ht.push(rt)),dt||(k=e,kt=u,u=""),d=n[p+1],d=d&&d[0]==="else"),lt=a?";\ntry{\nret+=":"\n+",tt="",it="",ct&&(s||gt||c&&c!==b)){if(h="return {"+g+"};",v='c("'+c+'",view,',h=new Function("data,view,j,u"," // "+y+" "+o+" "+e+"\n"+h),h._er=a,tt=v+o+",",it=")",h._tag=e,r)return h;at(h,s);ot=!0}if(u+=ct?(r?(a?"\ntry{\n":"")+"return ":lt)+(ot?(ot=i,nt=wt=!0,v+(s?(w[o-1]=h,o):"{"+g+"}")+")"):e===">"?(pt=!0,"h("+st[0]+")"):(ni=!0,"((v="+st[0]+')!=null?v:"")')):(nt=yt=!0,"\n{view:view,tmpl:"+(ft?ht.length:"0")+","+g+"},"),k&&!d){if(u="["+u.slice(0,-1)+"]",v='t("'+k+'",view,this,',r||s){if(u=new Function("data,view,j,u"," // "+y+" "+o+" "+k+"\nreturn "+u+";"),u._er=a,u._tag=e,s&&at(w[o-1]=u,s),r)return u;tt=v+o+",undefined,";it=")"}u=kt+lt+v+(o||u)+")";s=0;k=0}a&&(nt=!0,u+=";\n}catch(e){ret"+(r?"urn ":"+=")+tt+"j._err(e,view,"+a+")"+it+";}\n"+(r?"":"ret=ret"))}u="// "+y+"\nvar v"+(yt?",t=j._tag":"")+(wt?",c=j._cnvt":"")+(pt?",h=j.converters.html":"")+(r?";\n":',ret=""\n')+(et.debug?"debugger;":"")+u+(r?"\n":";\nreturn ret;");try{u=new Function("data,view,j,u",u)}catch(ii){l("Compiled template code:\n\n"+u+'\n: "'+ii.message+'"')}return t&&(t.fn=u),nt||(u._nvw=!0),u}function a(n,t){return n&&n!==t?t?f(f({},t),n):n:t&&f({},t)}function ar(n){return bt[n]||(bt[n]="&#"+n.charCodeAt(0)+";")}function vr(n){var i,t,r=[];if(typeof n=="object")for(i in n)t=n[i],t&&t.toJSON&&!t.toJSON()||d(t)||r.push({key:i,prop:t});return r}function li(n){return n!=null?di.test(n)&&(""+n).replace(gi,ar)||n:""}if((!t||!t.render)&&!n.jsviews){var u,rt,y,yt,pt,p="{",w="{",h="}",v="}",nt="^",ai=/^(!*?)(?:null|true|false|\d[\d.]*|([\w$]+|\.|~([\w$]+)|#(view|([\w$]+))?)([\w$.^]*?)(?:[.[^]([\w$]+)\]?)?)$/g,vi=/(\()(?=\s*\()|(?:([([])\s*)?(?:(\^?)(!*?[#~]?[\w$.^]+)?\s*((\+\+|--)|\+|-|&&|\|\||===|!==|==|!=|<=|>=|[<>%*:?\/]|(=))\s*|(!*?[#~]?[\w$.^]+)([([])?)|(,\s*)|(\(?)\\?(?:(')|("))|(?:\s*(([)\]])(?=\s*\.|\s*\^|\s*$)|[)\]])([([]?))|(\s+)/g,ut=/[ \t]*(\r\n|\n|\r)/g,yi=/\\(['"])/g,pi=/['"\\]/g,wi=/(?:\x08|^)(onerror:)?(?:(~?)(([\w$]+):)?([^\x08]+))\x08(,)?([^\x08]+)/gi,bi=/^if\s/,ki=/<(\w+)[>\s]/,di=/[\x00`><\"'&]/,wt=/^on[A-Z]|^convert(Back)?$/,gi=/[\x00`><"'&]/g,nr=0,tr=0,bt={"&":"&","<":"<",">":">","\x00":"�","'":"'",'"':""","`":"`"},b="html",ft="data-jsv-tmpl",kt={},k={template:{compile:ii},tag:{compile:hr},helper:{},converter:{}},r={jsviews:"v1.0.0-beta",settings:function(n){f(s,n);dt(s._dbgMode);s.jsv&&s.jsv()},sub:{View:g,Err:st,tmplFn:lt,cvt:ht,parse:hi,extend:f,syntaxErr:l,onStore:{},_lnk:ot,_ths:et},map:ri,_cnvt:fr,_tag:or,_err:c};(st.prototype=new Error).constructor=st;ni.depends=function(){return[this.get("item"),"index"]};ti.depends=function(){return["index"]};g.prototype={get:rr,getIndex:ti,getRsc:er,hlp:ur,_is:"view"};for(rt in k)cr(rt,k[rt]);var e=r.templates,tt=r.converters,ci=r.helpers,it=r.tags,o=r.sub,s=r.settings;t?(u=t,u.fn.render=lr,u.observable&&(f(o,u.views.sub),r.map=u.views.map)):(u=n.jsviews={},u.isArray=Array&&Array.isArray||function(n){return Object.prototype.toString.call(n)==="[object Array]"});u.render=kt;u.views=r;u.templates=e=r.templates;s({debugMode:dt,delimiters:gt,onError:function(n,t,r){return t&&(n=r===i?"{Error: "+n+"}":d(r)?r(n,t):r),n==i?"":n},_dbgMode:!0});it({"else":function(){},"if":{render:function(n){var t=this;return t.rendering.done||!n&&(arguments.length||!t.tagCtx.index)?"":(t.rendering.done=!0,t.selected=t.tagCtx.index,t.tagCtx.render(t.tagCtx.view,!0))},onUpdate:function(n,t,i){for(var r,f,u=0;(r=this.tagCtxs[u])&&r.args.length;u++)if(r=r.args[0],f=!r!=!i[u].args[0],!this.convert&&!!r||f)return f;return!1},flow:!0},"for":{render:function(n){var f,t=this,r=t.tagCtx,e="",o=0;return t.rendering.done||((f=!arguments.length)&&(n=r.view.data),n!==i&&(e+=r.render(n,f),o+=u.isArray(n)?n.length:1),(t.rendering.done=o)&&(t.selected=r.index)),e},flow:!0},include:{flow:!0},"*":{render:ot,flow:!0}});it("props",{baseTag:it["for"],dataMap:ri(vr)});tt({html:li,attr:li,url:function(n){return n!=i?encodeURI(""+n):n===null?n:""}});gt()}})(this,this.jQuery); -/* -//# sourceMappingURL=jsrender.min.js.map -*/ \ No newline at end of file diff --git a/BuildFeed/Scripts/jsrender.min.js.map b/BuildFeed/Scripts/jsrender.min.js.map deleted file mode 100644 index 4c7c9e8..0000000 --- a/BuildFeed/Scripts/jsrender.min.js.map +++ /dev/null @@ -1,8 +0,0 @@ -{ -"version":3, -"file":"jsrender.min.js", -"lineCount":3, -"mappings":";;CAWC,QAAQ,CAACA,CAAM,CAAEC,CAAM,CAAEC,CAAjB,CAA4B,CAEpC,Y,CAoFAC,SAASA,EAAoB,CAACC,CAAG,CAAEC,CAAN,CAAc,CAC1C,IAAK,IAAIC,EAAK,GAAGD,CAAME,MAAvB,CACKC,EAAYC,KAAK,CAACH,CAAD,C,GACpBF,CAAI,CAAAE,CAAA,CAAM,CAAED,CAAME,MAAO,CAAAD,CAAA,EAHe,CAS3CI,SAASA,EAAM,CAACC,CAAD,CAAM,CACpB,OAAOA,CADa,CAIrBC,SAASA,EAAQ,CAACD,CAAD,CAAM,CAGtB,OAAOA,CAHe,CAMvBE,SAASA,EAAO,CAACC,CAAD,CAAY,CAC3BC,CAAcC,SAAU,CAAEF,CAAS,CACnCG,EAAS,CAAEH,CAAU,CAAE,4CAA6C,CAAE,EAAE,CACxEI,EAAK,CAAC,KAAK,CAAEC,EAAQC,IAAK,CAAEC,EAAWD,IAAK,CAAEN,CAAU,CAAEF,EAAS,CAAEF,EAAhE,CAHsB,CAM5BY,SAASA,EAAY,CAACC,CAAD,CAAU,CAG9B,IAAIC,KAAM,CAAE,CAACC,CAACC,KAAM,CAAE,SAAU,CAAE,UAAtB,CAAkC,CAAE,QAAQ,CACxD,IAAIH,QAAS,CAAEA,CAAQ,EAAG,IAAIC,KAJA,CAO/BG,SAASA,CAAO,CAACC,CAAM,CAAEC,CAAT,CAAiB,CAEhC,IAAK,IAAAL,EAAK,GAAGK,CAAb,CACCD,CAAO,CAAAJ,CAAA,CAAM,CAAEK,CAAO,CAAAL,CAAA,CACvB,CACA,OAAOI,CALyB,CAQjCE,SAASA,CAAW,CAACC,CAAD,CAAK,CACxB,OAAO,OAAOA,CAAG,EAAI,UADG,CAWzBC,SAASA,EAAgB,CAACC,CAAS,CAAEC,CAAU,CAAER,CAAxB,CAA8B,CA6BtD,OAzBI,CAACS,CAAIC,KAAM,EAAGH,E,GACjBI,CAAe,CAAEJ,CAAU,CAAEA,CAASK,OAAO,CAAC,CAAD,CAAI,CAAED,CAAc,CACjEE,CAAe,CAAEN,CAAU,CAAEA,CAASK,OAAO,CAAC,CAAD,CAAI,CAAEC,CAAc,CACjEC,CAAgB,CAAEN,CAAW,CAAEA,CAAUI,OAAO,CAAC,CAAD,CAAI,CAAEE,CAAe,CACrEC,CAAgB,CAAEP,CAAW,CAAEA,CAAUI,OAAO,CAAC,CAAD,CAAI,CAAEG,CAAe,CACrEC,EAAS,CAAEhB,CAAK,EAAGgB,EAAQ,CAC3BT,CAAU,CAAE,IAAK,CAAEI,CAAe,CAAE,KAAM,CAAEK,EAAS,CAAE,MAAO,CAAEH,CAAc,CAC9EL,CAAW,CAAE,IAAK,CAAEM,CAAgB,CAAE,IAAK,CAAEC,CAAe,CAG5DL,CAAK,CAAE,yBAA0B,CAAEI,CAAgB,CAAE,mEACnC,CAAEA,CAAgB,CAAE,MAAO,CAAEA,CAAgB,CAAE,OAAQ,CAAEC,CAAgB,CAAE,OAAO,CAGpGN,CAAIC,KAAM,CAAEA,CAAK,CAAE,GAAG,CAEtBA,CAAK,CAAE,IAAIO,MAAM,CAACV,CAAU,CAAEG,CAAK,CAAE,uBAAwB,CAAEF,CAAU,CAAE,GAA1D,CAA8D,CAK/EU,EAAY,CAAE,IAAID,MAAM,CAAC,uBAAwB,CAAEV,CAAU,CAAE,IAAK,CAAEC,CAA9C,EAAyD,CAI3E,CAACG,CAAc,CAAEE,CAAc,CAAEC,CAAe,CAAEC,CAAe,CAAEC,EAAnE,CA7B+C,CAoCvDG,SAASA,EAAO,CAACC,CAAK,CAAEC,CAAR,CAAc,CACxBA,C,GAEJA,CAAK,CAAED,CAAK,CACZA,CAAM,CAAE5C,EAAS,CAGlB,IAAI8C,EAAOC,EAAGC,EAAGC,EAChBC,EAAO,KACPC,EAAO,CAACN,CAAK,EAAGA,CAAK,GAAI,MAAM,CAGhC,GAAID,EAAO,CAGV,GADAK,CAAM,CAAEC,CAAIL,KAAM,GAAIA,CAAK,CAAEK,CAAK,CAAElD,CAAS,CACzC,CAACiD,EAEJ,GADAH,CAAM,CAAEI,CAAIJ,MAAM,CACdI,CAAIE,EAAEC,QAAS,CAClB,IAAKN,EAAE,GAAGD,CAAV,CACC,GAAIG,CAAM,CAAEH,CAAM,CAAAC,CAAA,CAAEO,IAAI,CAACV,CAAK,CAAEC,CAAR,EACvB,KAHgB,CAMjB,KACD,IAAKE,CAAE,CAAE,C,CAAGC,CAAE,CAAEF,CAAKS,OAAO,CAAE,CAACN,CAAM,EAAGF,CAAE,CAAEC,CAAC,CAAED,CAAC,EAAhD,CACCE,CAAM,CAAEH,CAAM,CAAAC,CAAA,CAAEO,IAAI,CAACV,CAAK,CAAEC,CAAR,CAbb,CAiBT,KAAK,GAAIM,QAEHD,CAAIM,OAAOA,QACjBP,CAAM,CAAEC,CAAK,CAAEA,CAAIM,OACpB,CACC,WACMN,CAAK,EAAG,CAACD,EAEfA,CAAM,CAAEC,CAAIL,KAAM,GAAIA,CAAK,CAAEK,CAAK,CAAElD,CAAS,CAC7CkD,CAAK,CAAEA,CAAIM,OAEb,CACA,OAAOP,CAzCsB,CA4C9BQ,SAASA,EAAc,CAAA,CAAG,CACzB,IAAIP,EAAO,IAAII,IAAI,CAAC,MAAD,CAAQ,CAC3B,OAAOJ,CAAK,CAAEA,CAAIQ,MAAO,CAAE1D,CAFF,CAS1B2D,SAASA,EAAQ,CAAA,CAAG,CACnB,OAAO,IAAID,MADQ,CAYpBE,SAASA,EAAS,CAACC,CAAD,CAAS,CAE1B,IAAIC,EACHZ,EAAO,KACPa,EAAMb,CAAIc,SACVC,EAAM,CAACf,CAAIa,IAAK,EAAG,CAAA,CAAb,CAAiB,CAAAF,CAAA,CAAO,CAsB/B,OApBII,CAAI,GAAIjE,CAAU,EAAG+D,CAAI,EAAGA,CAAGA,I,GAClCE,CAAI,CAAEF,CAAGA,IAAK,CAAAF,CAAA,EAAO,CAElBI,CAAI,GAAIjE,C,GACXiE,CAAI,CAAEhD,EAAS,CAAA4C,CAAA,EAAO,CAGnBI,C,EACCrC,CAAW,CAACqC,CAAD,CAAM,EAAG,CAACA,CAAGC,K,GAC3BJ,CAAQ,CAAEA,QAAQ,CAAA,CAAG,CAKpB,OAAOG,CAAGE,MAAM,CAAE,CAAC,IAAK,EAAG,IAAK,GAAIrE,CAAQ,CAAEoD,CAAK,CAAE,IAAI,CAAEkB,SAA3C,CALI,CAMpB,CACDN,CAAOI,KAAM,CAAE,CAAA,CAAI,CACnBzC,CAAO,CAACqC,CAAO,CAAEG,CAAV,EAAc,CAGhBH,CAAQ,EAAGG,CA3BQ,CAkC3BI,SAASA,EAAU,CAACC,CAAS,CAAEpB,CAAI,CAAE/C,CAAM,CAAEoE,CAA1B,CAAmC,CAErD,IAAIrE,EAAKsE,EAERC,EAAW,CAACtE,CAAO,GAAIA,CAAO,EAAG+C,CAAIwB,KAAKC,KAAM,CAAAxE,CAAM,CAAC,CAAP,EAChD6D,EAAUd,CAAIc,QAAQ,CA8CvB,OA5CAO,CAAQ,CAAEA,CAAQ,GAAIvE,CAAU,EAAG,CAAC,KAAK,CAAE,CAAA,CAAE,CAAE,IAAI,CAAE,CAACuE,CAAD,CAAlB,CAA4B,CAE/DpE,CAAO,CAAEoE,CAAQ,EAAG,CAACE,CAAS,CAAEA,CAAQ,CAACvB,CAAI0B,KAAK,CAAE1B,CAAI,CAAE2B,CAAlB,CAA0B,CAAE1E,CAAhD,CAAuD,CAE3EqE,CAAM,CAAErE,CAAM2E,KAAM,CAAA,CAAA,CAAE,EAClBR,CAAU,EAAGG,E,GAChBvE,CAAI,CAAE8D,CAAQ,EAAGA,CAAO9D,IAAI,CACvBA,C,GACJA,CAAI,CAAE,CACL,CAAC,CAAE,CACF,MAAM,CAAE,CAAC8D,CAAO,CAChB,GAAG,CAAES,CAFH,CAGF,CACD,OAAO,CAAE,GAAG,CACZ,GAAG,CAAEH,CAAS,CACd,IAAI,CAAE,CAAA,CAAI,CACV,MAAM,CAAEnE,CAAM,CACd,GAAG,CAAE,KATA,CAUL,CACG6D,C,GACHA,CAAO9D,IAAK,CAAEA,CAAG,CACjBA,CAAG8D,QAAS,CAAEA,CAAO,CACrB7D,CAAM4D,IAAK,CAAEgB,CAAS,CAAC5E,CAAM4D,IAAI,CAAEC,CAAOd,KAAKa,IAAzB,EAA8B,CAErD9B,CAAI+C,KAAK,CAAC9E,CAAD,EAAK,CAEfA,CAAG+E,IAAK,CAAEV,CAAQ,EAAGC,CAAK,CAC1BvE,EAAoB,CAACC,CAAG,CAAEC,CAAN,CAAa,CAEjCA,CAAM+C,KAAM,CAAEA,CAAI,CAElBhD,CAAG6D,IAAK,CAAE5D,CAAM4D,IAAK,EAAG,CAAA,CAAE,CAC1B,OAAO5D,CAAM4D,IAAI,CAEjBb,CAAIE,EAAElD,IAAK,CAAEA,CAAG,CAEhBsE,CAAM,CAAEU,EAAW,CAAChF,CAAG,CAAEA,CAAGiF,QAAS,EAAGb,CAAU,GAAI,MAAO,EAAGA,CAA7C,CAAwD,CAAA,CAAA,CAAE,CAG7EE,CAAM,CAAEC,CAAS,EAAGvB,CAAIE,EAAEgC,SACzB,CAAElC,CAAIE,EAAEgC,SAAS,CAACZ,CAAK,CAAEtB,CAAI,CAAEuB,CAAd,CACjB,CAAED,CAAK,CACRtB,CAAIE,EAAElD,IAAK,CAAEF,EAAS,CAEhBwE,CAAM,EAAGxE,CAAU,CAAEwE,CAAM,CAAE,EAnDiB,CAsDtDU,SAASA,EAAW,CAAChF,CAAG,CAAEoE,CAAN,CAAiB,CACpC,IAAInE,EAASD,CAAGC,QACf+C,EAAO/C,CAAM+C,MACb4B,EAAO3E,CAAM2E,KAAK,CAmBnB,OAjBAR,CAAU,CAAEA,CAAU,EAAG,CAAC,EAAG,CAAEA,CAAU,GAAIA,CAC5C,CAAGpB,CAAImC,OAAO,CAAC,YAAY,CAAEf,CAAf,CAA0B,EAAGgB,CAAK,CAAC,sBAAuB,CAAEhB,CAAU,CAAE,GAAtC,CAChD,CAAEA,CAFsB,CAEZ,CAEbQ,CAAK,CAAE,CAACA,CAAIvB,OAAQ,EAAG,CAACpD,CAAMuD,MAC7B,CAAE,CAACR,CAAI0B,KAAL,CACF,CAAEN,CACD,CAAEQ,CAAIS,MAAM,CAAA,CAEZ,CAAET,CAAI,CAEJR,C,GACCA,CAASkB,Q,GACZtF,CAAGsF,QAAS,CAAEvD,CAAIwD,QAAQ,CAACvF,CAAGsF,QAAQ,CAAEtF,CAAG,CAAEoE,CAASkB,QAAQ,CAAElB,CAAtC,EAAgD,CAE3EQ,CAAK,CAAA,CAAA,CAAG,CAAER,CAASH,MAAM,CAACjE,CAAG,CAAE4E,CAAN,EAAW,CAE9BA,CAtB6B,CA6BrCY,SAASA,EAAW,CAACC,CAAY,CAAEC,CAAf,CAAyB,CAG5C,IAFA,IAAI3B,EAAK4B,EACR3C,EAAO,IACR,CAAQe,CAAI,GAAIjE,CAAW,EAAGkD,CAA9B,CAAA,CACC2C,CAAM,CAAE3C,CAAIwB,KAAM,CAAAiB,CAAA,CAAa,CAC/B1B,CAAI,CAAE4B,CAAM,EAAGA,CAAM,CAAAD,CAAA,CAAS,CAC9B1C,CAAK,CAAEA,CAAIM,OACZ,CACA,OAAOS,CAAI,EAAGY,CAAO,CAAAc,CAAA,CAAc,CAAAC,CAAA,CARS,CAW7CE,SAASA,EAAS,CAACC,CAAO,CAAEC,CAAU,CAAEtB,CAAI,CAAEuB,CAAO,CAAEC,CAAQ,CAAE3B,CAA/C,CAAwD,CAIzE,IAAIrE,EAAKiG,GAAMC,GAAMC,GAAWtD,EAAGC,GAAGsD,GAASnG,EAAQoG,GAAWC,GAASC,GAC1EC,GAAUC,GAAQC,EAAS9B,EAAMzE,GAAOwG,GACxCC,EAAM,GACN9C,EAAUgC,CAAUhC,QAAS,EAAG,EAChCD,GAAMiC,CAAUjC,KAChBgD,GAAarC,CAAK,EAAGsB,CAAUtB,MAE/BD,GAAW,CAACwB,CAAQ,GAAIA,CAAQ,EAAGc,EAAUpC,KAAM,CAAAsB,CAAO,CAAC,CAAR,CAAU,CAc9D,IAZIF,CAAOiB,IAAK,GAAI,K,GACnB9G,CAAI,CAAE6F,CAAO,CACbA,CAAQ,CAAE7F,CAAG6F,QAAQ,CACrBE,CAAQ,CAAE/F,CAAG+F,SAAQ,CAEtB/F,CAAI,CAAEA,CAAI,EAAG8D,CAAO9D,IAAI,CAExBqE,CAAQ,CAAEA,CAAQ,GAAIvE,CAAU,EAAG,CAAC8G,CAAI,EAAGvC,C,CAAS,CAAC,CAAC,KAAK,CAAE,CAAA,CAAE,CAAE,IAAI,CAAE,CAAA,CAAlB,CAAD,CAAjB,CAAyC,CAE5E0B,CAAQ,CAAE1B,CAAQ,EAAG,CAACE,EAAS,CAAEA,EAAQ,CAACuB,CAAUpB,KAAK,CAAEoB,CAAU,CAAEnB,CAA9B,CAAsC,CAAEoB,CAA5D,CAAoE,CAEzFjD,EAAE,CAAEiD,CAAO1C,OAAO,CACbR,CAAE,CAAE,CAAC,CAAEA,CAAE,CAAEC,EAAC,CAAED,CAAC,EAApB,CACMA,CAAE,EAAK2B,CAAK,EAAIxE,C,GACpBuG,EAAO,CAAET,CAAUX,OAAO,CAAC,MAAM,CAAEU,CAAT,CAAkB,EAAGT,CAAK,CAAC,iBAAkB,CAAES,CAAQ,CAAE,IAA/B,EAAoC,CAEzF5F,CAAO,CAAE8F,CAAQ,CAAAlD,CAAA,CAAE,EACf,CAACiB,CAAO9D,IAAK,EAAGA,CAAG+E,K,GAEtBuB,EAAQ,CAAErG,CAAMuE,KAAK,CACrB8B,EAAQ,CAAErG,CAAMqG,QAAS,CAAEA,EAAQ,EAAGO,EAAUE,MAAO,CAAAT,EAAQ,CAAE,CAAV,CAAY,CAEnE/E,CAAO,CAACtB,CAAM,CAAE,CACf,IAAI,CAAE,CAACD,CAAI,CAAEA,CAAI,CAAEuG,EAAb,CAAoBS,SAAU,EAAGV,EAAO,CAC9C,MAAM,CAAEW,EAAa,CACrB,KAAK,CAAEpE,CAAC,CACR,IAAI,CAAEiD,CAAU,CAChB,GAAG,CAAEjB,CAAS,CAAC5E,CAAM4D,IAAI,CAAEA,EAAb,CALC,CAAT,EAiBL,EAECW,CAAK,CAAEvE,CAAME,MAAMqE,M,GAEtBA,CAAK,CAAE,EAAG,CAAEA,CAAK,GAAIA,CACpB,CAAEsB,CAAUX,OAAO,CAAC,WAAW,CAAEX,CAAd,CAAoB,EAAG0C,CAAU,CAAC1C,CAAD,CACpD,CAAEA,CAAI,CAEPvE,CAAMuE,KAAM,CAAEA,EAAI,CAGdxE,C,GAGAuG,EAAMY,KAAV,EAICnH,CAAI,CAAE,IAAIuG,EAAMY,KAAO,CACvBX,EAAS,CAAE,CAAC,CAACxG,CAAGoH,MALjB,CAQCrF,CAAI+C,KAAK,CAAC9E,CAAI,CAAE,CAEf,MAAM,CAAEuG,EAAMc,OAFC,CAAP,C,CAKVrH,CAAGkD,EAAG,CAAE,CACP,MAAM,CAAE,CAACY,CADF,CAEP,CACGA,C,GACHA,CAAO9D,IAAK,CAAEA,CAAG,CACjBA,CAAG8D,QAAS,CAAEA,EAAO,EAElB9D,CAAGkD,EAAEoE,IAAK,CAAE/C,EAAS,EAAGT,CAAOyD,IAAnC,CAECvH,CAAGkD,EAAEsE,OAAQ,CAAE,CAAA,CAFhB,CAGWxH,CAAGyH,c,EACbrC,CAAK,CAAC,KAAM,CAAES,CAAQ,CAAE,2BAAnB,C,CAEN7F,CAAG6F,QAAS,CAAEA,CAAO,CACrB7F,CAAGsD,OAAQ,CAAE6C,EAAU,CAAEtC,EAAI,EAAGA,EAAG7D,IAAI,CACvCA,CAAG8G,IAAK,CAAE,KAAK,CACf9G,CAAG0H,KAAM,CAAEnB,EAAM,CACjBvG,CAAG+F,QAAS,CAAEA,EAAO,CAMtB9F,CAAMD,IAAK,CAAEA,CAAG,CACZA,CAAG2H,QAAS,EAAG3H,CAAG+F,Q,GACrB9F,CAAM2H,IAAK,CAAE5H,CAAG+F,QAAS,CAAAlD,CAAA,CAAE+E,KAAI,CAE3B5H,CAAG6H,K,GACPxB,EAAU,CAAEpG,CAAM4D,IAAK,CAAE5D,CAAM4D,IAAK,EAAG,CAAA,CAAE,CAGzCoC,EAAK,CAAEjG,CAAG8H,QAAS,CAAEzB,EAAS0B,WAAY,CAAElE,EAAI,EAAGgB,CAAS,CAACwB,EAAS0B,WAAW,CAAElE,EAAGkE,WAA1B,CAAuC,EAAG,CAAA,CAAE,CACpG5B,E,GACHF,EAAK,CAAAE,EAASN,QAAT,CAAmB,CAAEM,GAAS,CAGpCF,EAAK,CAAAjG,CAAG6F,QAAH,CAAa,CAAEQ,EAASrG,IAAK,CAAEA,EAEtC,CAEA,GADA8F,CAAU5C,EAAElD,IAAK,CAAEA,CAAG,CAClB,CAAC,CAACA,CAAG+E,IAAK,CAAEV,CAAX,EAAqB,CAGzB,IAFAtE,EAAoB,CAACC,CAAG,CAAE+F,CAAQ,CAAA,CAAA,CAAd,CAAiB,CACrC/F,CAAGgI,UAAW,CAAE,CAAA,CAAE,CACbnF,CAAE,CAAE,CAAC,CAAEA,CAAE,CAAEC,EAAC,CAAED,CAAC,EAApB,CACC5C,CAAO,CAAED,CAAGC,OAAQ,CAAED,CAAG+F,QAAS,CAAAlD,CAAA,CAAE,CACpC1C,EAAM,CAAEF,CAAME,MAAM,CACpByE,CAAK,CAAEI,EAAW,CAAChF,CAAG,CAAEA,CAAGiF,QAAT,CAAkB,EAEhCwB,EAAO,CAAEtG,EAAKwH,QAAS,EAAG3H,CAAG2H,S,GAC5B/C,CAAIvB,OAAQ,EAAGlD,EAAKwH,S,GACvBjB,CAAQ,CAAEzG,CAAM2H,IAAI,EAChB,CAAClB,CAAQ,EAAGA,CAAOuB,IAAK,GAAIrD,CAAK,CAAA,CAAA,CAAG,EAAGoB,E,GACtCU,CAAQ,EAAGA,CAAOuB,I,EACrBvB,CAAOwB,MAAM,CAAA,CAAE,CAEhBxB,CAAQ,CAAEzG,CAAM2H,IAAK,CAAEnB,EAAMmB,IAAI,CAAChD,CAAK,CAAA,CAAA,CAAE,CAAEzE,EAAV,EAAgB,CAElDyE,CAAK,CAAE,CAAC8B,CAAOyB,IAAR,EAAa,CAGtBnI,CAAG6D,IAAK,CAAE5D,CAAM4D,IAAI,CAEhB,CAAChB,CAAE,EAAG2D,E,GACTG,EAAY,CAAE3G,CAAGgH,SAAS,CAC1BhH,CAAGoH,KAAK,CAACnH,CAAM,CAAE6D,CAAO,CAAE9D,CAAG6D,IAArB,CAA0B,CAClC2C,EAAS,CAAE1G,CAAS,CAChBE,CAAGgH,SAAU,GAAIL,E,GACpB3G,CAAGkD,EAAEsB,KAAM,CAAExE,CAAGgH,UAAS,CAEtBlD,C,GAGHA,CAAOoC,KAAM,CAAElG,CAAGkG,KAAM,CAAEpC,CAAOoC,KAAM,EAAGlG,CAAGkG,OAAK,CAIpDE,EAAQ,CAAEtG,CAAS,CACfE,CAAGqH,O,GACNjB,EAAQ,CAAEpG,CAAGqH,OAAOpD,MAAM,CAACjE,CAAG,CAAE4E,CAAN,EAAW,CAEtCA,CAAK,CAAEA,CAAIvB,OAAQ,CAAEuB,CAAK,CAAE,CAACkB,CAAD,CAAY,CACxCM,EAAQ,CAAEA,EAAQ,GAAItG,CACrB,CAAEsG,EACF,CAAEnG,CAAMoH,OAAO,CAACzC,CAAK,CAAA,CAAA,CAAE,CAAE,CAAA,CAAV,CAAgB,EAAG,CAACoB,CAAS,CAAElG,CAAU,CAAE,EAAxB,CAA2B,CAE9D8G,CAAI,CAAEA,CAAI,CAAEA,CAAI,CAAE,CAACR,EAAQ,EAAG,EAAZ,CAAgB,CAAEA,EACrC,CAEA,OAAOpG,CAAGgI,UAhDe,CA2D1B,OATAhI,CAAGC,OAAQ,CAAED,CAAG+F,QAAS,CAAA,CAAA,CAAE,CAC3B/F,CAAG6D,IAAK,CAAE7D,CAAGC,OAAO4D,IAAI,CAEpB7D,CAAGkD,EAAEkF,OAAQ,EAAG,CAAClC,EAAK,CAAElG,CAAGkG,KAAX,CAAkB,EAAGA,EAAK,GAAImC,C,GAEjDzB,CAAI,CAAEV,EAAK,GAAI,MACd,CAAEjF,EAAWqH,KAAK,CAAC1B,CAAD,CAClB,CAAE,GAAE,CAECrC,EAAS,EAAGuB,CAAU5C,EAAEgC,SAE9B,CAAEY,CAAU5C,EAAEgC,SAAS,CAAC0B,CAAG,CAAEd,CAAU,CAAEvB,EAAlB,CACvB,CAAEqC,CArLsE,CA4L1E2B,SAASA,CAAI,CAACC,CAAO,CAAE7F,CAAI,CAAEmD,CAAU,CAAEpB,CAAI,CAAEsC,CAAQ,CAAEyB,CAAG,CAAEC,CAAW,CAAExD,CAA9D,CAAwE,CAEpF,IAAItC,EAAO+F,EAAa3I,EACvB4I,EAAO,KACPC,EAAUlG,CAAK,GAAI,QACnBmG,EAAQ,CACP,GAAG,CAAE,CAAC,CACN,MAAM,CAAED,CAAQ,CAAE,CAAE,CAAE,CAAC,CACvB,EAAE,CAAE,EAAG,CAAEE,EAAM,EAAE,CACjB,QAAQ,CAAE7D,CAAQ,CAClB,IAAI,CAAE,CAAA,CALC,CAMP,CAEF0D,CAAIlE,KAAM,CAAEA,CAAI,CAChBkE,CAAIpE,KAAM,CAAEwC,C,CACZ4B,CAAItC,QAAS,CAAEoC,C,CACfE,CAAIhG,MAAO,CAAEiG,CAAQ,CAAE,CAAA,CAAG,CAAE,CAAA,CAAE,CAC9BD,CAAItF,OAAQ,CAAEwC,CAAU,CACxB8C,CAAIjG,KAAM,CAAEA,CAAK,EAAG,KAAK,CAIzBiG,CAAI1F,EAAG,CAAE4F,CAAK,CACdF,CAAII,OAAQ,CAAE,CAAC,CAAC9D,CAAQ,CACpBY,CAAJ,EACClD,CAAM,CAAEkD,CAAUlD,MAAM,CACxB+F,CAAY,CAAE7C,CAAU5C,EAAE,CACtByF,CAAWxF,OAAf,EAGCP,CAAM,CAAAkG,CAAKL,IAAK,CAAE,GAAI,CAAEE,CAAWxF,OAAO,EAApC,CAAwC,CAAEyF,CAAI,CACpDA,CAAIpF,MAAO,CAAE3C,EAAQ,CACrB+H,CAAInF,SAAU,CAAEF,EAAc,CAC9BvD,CAAI,CAAE2I,CAAW3I,IAAI,CACrB8I,CAAKxB,IAAK,CAAEuB,CAAQ,EAAG,CAAC,CAAC7I,CAAI,EAAG,CAAC,CAACA,CAAGkD,EAAEoE,IAAK,EAAGtH,CAAxB,EAPxB,CAWC4C,CAAKqG,OAAO,CAEXH,CAAKL,IAAK,CAAEG,CAAIpF,MAAO,CAAEiF,CAAG,CAC7B,CAAC,CAAEG,CAHS,C,CAObA,CAAI/E,IAAK,CAAE2E,CAAQ,EAAG1C,CAAUjC,KArBjC,CAuBC+E,CAAI/E,IAAK,CAAE2E,CA/CwE,CA+DrFU,SAASA,EAAqB,CAACrC,CAAD,CAAa,CAC1C,IAAIsC,EAAWC,EAAWC,EAAcC,EAAUC,EAAUC,EAASC,CAAO,CAC5E,IAAKN,EAAU,GAAGO,CAAlB,CAEC,GADAH,CAAS,CAAEG,CAAU,CAAAP,CAAA,CAAU,CAC3B,CAACK,CAAQ,CAAED,CAAQC,QAAnB,CAA6B,EAAG,CAACJ,CAAU,CAAEvC,CAAW,CAAAsC,CAAU,CAAE,GAAZ,CAAxB,EACnC,IAAKE,EAAa,GAAGD,CAArB,CAECE,CAAS,CAAEF,CAAU,CAAAC,CAAA,CAAc,CAAEG,CAAO,CAACH,CAAY,CAAED,CAAU,CAAAC,CAAA,CAAa,CAAExC,CAAxC,CAAmD,CAC3FyC,CAAS,EAAG,CAACG,CAAQ,CAAE1H,CAAI0H,QAAS,CAAAN,CAAA,CAAxB,C,EAEfM,CAAO,CAACJ,CAAY,CAAEC,CAAQ,CAAEE,CAAzB,CAV+B,CAiB3CG,SAASA,EAAU,CAACvI,CAAI,CAAEmF,CAAM,CAAEM,CAAf,CAA2B,CAC7C,IAAIO,EAAM5C,CAAI,CA0Bd,OAzBI9C,CAAW,CAAC6E,CAAD,CAAf,CAECA,CAAO,CAAE,CACR,OAAO,CAAEA,CAAMjB,QAAQ,CACvB,MAAM,CAAEiB,CAFA,CAFV,EAOKA,CAAMqD,Q,GACTrD,CAAMsB,KAAM,CAAE,CAAC,CAACtB,CAAMsB,KAAK,CAC3BtB,CAAO,CAAEhF,CAAO,CAACA,CAAO,CAAC,CAAA,CAAE,CAAEgF,CAAMqD,QAAX,CAAoB,CAAErD,CAA9B,EAAqC,CAGlD,CAAC/B,CAAK,CAAE+B,CAAMS,SAAd,CAAyB,GAAIlH,C,GAChCyG,CAAMS,SAAU,CAAE,EAAG,CAAExC,CAAK,GAAIA,CAAK,CAAG0C,CAAW,CAAA1C,CAAA,CAAM,EAAG0C,CAAU,CAAC1C,CAAD,CAAQ,CAAEA,EAAI,CAEjF+B,CAAMa,KAAM,GAAI,CAAA,C,GAGnBA,CAAK,CAAEb,CAAMY,KAAM,CAAE0C,QAAQ,CAAA,CAAG,EAAE,CAClC,CAACzC,CAAI0C,UAAW,CAAEvD,CAAlB,CAAyBwD,YAAa,CAAE3C,G,CAGtCP,C,GACHN,CAAMyD,YAAa,CAAEnD,EAAU,CAEzBN,CA3BsC,CA8B9C0D,SAASA,EAAW,CAAC7I,CAAI,CAAEoD,CAAI,CAAEqC,CAAU,CAAEqD,CAAzB,CAAkC,CAIrDC,SAASA,CAAmB,CAAC7F,CAAD,CAAQ,CAInC,GAAK,EAAG,CAAEA,CAAM,GAAIA,CAAO,EAAGA,CAAK8F,SAAU,CAAE,EAAG,CACjD,GAAI,CACHC,CAAK,CAAE/F,CAAK8F,SAAU,CAAE,CACxB,CAAE9F,CACF,CAAE,CAAC9B,EAAWnC,KAAK,CAACiE,CAAD,CAElB,EAAGzE,CAAO,EAAGA,CAAM,CAACD,CAAM0K,SAAP,CAAiBC,KAAK,CAACjG,CAAD,CAAQ,CAAA,CAAA,CAL/C,OAQKkG,IAoBT,OAlBIH,C,GAOH/F,CAAM,CAAE4C,CAAW,CAAA9F,CAAK,CAAEA,CAAK,EAAGiJ,CAAII,aAAa,CAACC,EAAD,CAAhC,CAA2C,CACzDpG,C,GAGJlD,CAAK,CAAEA,CAAK,EAAG,GAAI,CAAEuJ,EAAY,EAAE,CACnCN,CAAIO,aAAa,CAACF,EAAQ,CAAEtJ,CAAX,CAAgB,CAEjCkD,CAAM,CAAE4C,CAAW,CAAA9F,CAAA,CAAM,CAAE6I,EAAW,CAAC7I,CAAI,CAAEiJ,CAAIQ,UAAU,CAAEhE,CAAU,CAAEqD,CAAnC,EAA2C,CAElFG,CAAK,CAAEvK,EAAS,CAEVwE,CA7B0C,CAJf,CAsCpC,IAAIwG,EAAcT,CAAI,CAqBtB,OAlBA7F,CAAK,CAAEA,CAAK,EAAG,EAAE,CACjBsG,CAAa,CAAEX,CAAmB,CAAC3F,CAAD,CAAM,CAIxC0F,CAAQ,CAAEA,CAAQ,EAAG,CAAC1F,CAAIuG,OAAQ,CAAEvG,CAAK,CAAE,CAAA,CAAtB,CAAyB,CAC9C0F,CAAOc,SAAU,CAAE5J,CAAI,CACnByF,C,GACHqD,CAAOF,YAAa,CAAEnD,EAAU,CAI7B,CAACiE,CAAa,EAAGtG,CAAIuG,OAAQ,EAAG,CAACD,CAAa,CAAEX,CAAmB,CAAC3F,CAAIuG,OAAL,CAAnC,C,EAC/BD,CAAYvD,GAAI,EAAG,CAACuD,CAAYG,MAAO,GAAIzG,CAAIyG,MAAO,EAAGH,CAAYI,UAAW,GAAI1G,CAAI0G,UAArE,C,GAEtBJ,CAAa,CAAEA,CAAYC,QAAO,CAGhCD,CAAa,GAAIhL,CAAjB,EACCsB,CAAK,EAAG,CAACyF,C,GACZsE,EAAQ,CAAA/J,CAAA,CAAM,CAAE,QAAQ,CAAA,CAAG,CAC1B,OAAOoD,CAAI6C,OAAOpD,MAAM,CAACO,CAAI,CAAEN,SAAP,CADE,EAE1B,CAEE4G,CAAYvD,GAAI,EAAG/C,CAAI+C,GAA3B,CAEKuD,CAAYvD,G,GAEd/C,CAAK,CADFpD,CAAK,EAAGA,CAAK,GAAI0J,CAAYE,SAAjC,CACQnG,CAAS,CAACqF,CAAO,CAAEY,CAAV,CADjB,CAGQA,EANV,EAYCtG,CAAK,CAAE4G,EAAU,CAACN,CAAY,CAAEZ,CAAf,CAAuB,CAExCmB,EAAM,CAACP,CAAYQ,QAAQ,CAACC,EAAa,CAAE,MAAhB,CAAuB,CAAE/G,CAA9C,E,CAEP0E,EAAqB,CAACgB,CAAD,CAAS,CACvB1F,EAvBJ,CAuBH,KAAA,CAtFoD,CA0FtDmD,SAASA,EAAO,CAAClB,CAAD,CAAS,CACxB+E,SAASA,CAAM,CAAC/J,CAAM,CAAEyI,CAAT,CAAkB,CAChC,IAAI/B,IAAK,CAAE1B,CAAMgF,OAAO,CAAChK,CAAM,CAAEyI,CAAT,CADQ,CAkBjC,OAdIxI,CAAW,CAAC+E,CAAD,C,GAEdA,CAAO,CAAE,CACR,MAAM,CAAEA,CADA,EAER,CAGEA,CAAMiF,Q,GACTjF,CAAO,CAAElF,CAAO,CAACA,CAAO,CAAC,CAAA,CAAE,CAAEkF,CAAMiF,QAAX,CAAoB,CAAEjF,CAA9B,EAAqC,CAGtDA,CAAMmB,IAAK,CAAE+D,QAAQ,CAAClK,CAAM,CAAEyI,CAAT,CAAkB,CACtC,OAAO,IAAIsB,CAAM,CAAC/J,CAAM,CAAEyI,CAAT,CADqB,CAEtC,CACMzD,CAnBiB,CAwBzB2E,SAASA,EAAU,CAACL,CAAM,CAAEb,CAAT,CAAkB,CAEpC,IAAI0B,EACHC,EAAUlL,CAAckL,QAAS,EAAG,CAAA,EACpCrH,EAAOjD,CAAO,CACb,CACC,MAAM,CAAEwJ,CAAM,CACd,KAAK,CAAE,CAAA,CAAE,CACT,KAAK,CAAE,CAAA,CAAE,CACT,IAAI,CAAE,CAAA,CAAE,CACR,IAAI,CAAE,CAAA,CAAE,CACR,GAAG,CAAE,UAAU,CACf,MAAM,CAAEe,EAPT,CAQC,CACD5B,CAVa,CAWb,CAcF,OAZKA,CAAO0B,Q,GAEXA,CAAQ,CAAEG,EAAUC,KAAK,CAACjB,CAAD,CAAQ,CACjCvG,CAAIoH,QAAS,CAAEA,CAAQ,CAAEA,CAAQ,CAAA,CAAA,CAAEK,YAAY,CAAA,CAAG,CAAE,GAAE,CAEvDL,CAAQ,CAAEC,CAAQ,CAAArH,CAAIoH,QAAJ,CAAa,CAC3BA,CAAQ,EAAGA,CAAQ,GAAIC,CAAOK,I,GAGjC1H,CAAIuG,OAAQ,CAAE1J,CAAC8K,KAAK,CAAC3H,CAAIuG,OAAL,EAAa,CAG3BvG,CA7B6B,CAgCrC4H,SAASA,EAAa,CAACjD,CAAS,CAAEkD,CAAZ,CAA2B,CAEhDC,SAASA,CAAQ,CAAClL,CAAI,CAAEmL,CAAI,CAAE1F,CAAb,CAAyB,CAOzC,IAAI4C,EAASD,EAAS9D,EAAU8G,CAAS,CAEzC,GAAIpL,CAAK,EAAG,OAAOA,CAAK,EAAI,QAAS,EAAG,CAACA,CAAIgJ,SAAU,EAAG,CAAChJ,CAAI2J,OAAQ,EAAG,CAAC3J,CAAIqK,QAAS,CAKvF,IAAK/F,EAAS,GAAGtE,CAAjB,CACCkL,CAAQ,CAAC5G,CAAQ,CAAEtE,CAAK,CAAAsE,CAAA,CAAS,CAAE6G,CAA3B,CACT,CACA,OAAO5H,CARgF,CAoCxF,OAzBI4H,CAAK,GAAIzM,C,GACZyM,CAAK,CAAEnL,CAAI,CACXA,CAAK,CAAEtB,EAAS,CAEbsB,CAAK,EAAG,EAAG,CAAEA,CAAK,GAAIA,C,GACzByF,CAAW,CAAE0F,CAAI,CACjBA,CAAK,CAAEnL,CAAI,CACXA,CAAK,CAAEtB,EAAS,CAEjB0M,CAAU,CAAE3F,CAAW,CAAEA,CAAW,CAAA4F,CAAA,CAAY,CAAE5F,CAAW,CAAA4F,CAAA,CAAY,EAAG,CAAA,CAAG,CAAEH,CAAQ,CACzF9C,CAAQ,CAAE6C,CAAa7C,QAAQ,CAC3B+C,CAAK,GAAI,IAAb,CAECnL,CAAK,EAAG,OAAOoL,CAAU,CAAApL,CAAA,CAF1B,EAICmL,CAAK,CAAE/C,CAAQ,CAAG+C,CAAK,CAAE/C,CAAO,CAACpI,CAAI,CAAEmL,CAAI,CAAE1F,CAAb,CAA0B,CAAE0F,CAAI,CAChEnL,CAAK,EAAG,CAACoL,CAAU,CAAApL,CAAA,CAAM,CAAEmL,CAAnB,E,CAEL/C,CAAQ,EAAG+C,C,GACdA,CAAIzF,IAAK,CAAEqC,EAAS,CAEjBoD,CAAK,EAAG,CAAC9C,CAAQ,CAAE1H,CAAI0H,QAAS,CAAAN,CAAA,CAAxB,C,EAEXM,CAAO,CAACrI,CAAI,CAAEmL,CAAI,CAAE/C,CAAb,CAAqB,CAEtB+C,CA7CkC,CAgD1C,IAAIE,EAAatD,CAAU,CAAE,GAAG,CAEhCxE,CAAO,CAAA8H,CAAA,CAAY,CAAEH,CAAQ,CAC7B5C,CAAU,CAAAP,CAAA,CAAW,CAAEkD,CArDyB,CA4DjDK,SAASA,EAAW,CAAChI,CAAI,CAAE8D,CAAO,CAAEmE,CAAhB,CAA6B,CAChD,IAAIC,EAAW,IAAIC,OAAQ,EAAG,CAAC,IAAK,CAAA,CAAA,CAAG,EAAGzH,CAAK,CAAC,qBAAsB,CAAE,IAAI0H,SAAU,CAAE,GAAzC,CAAjB,EAC7BtI,EAAOoI,CAAQnC,aAAa,CAACC,EAAD,CAAU,CAEvC,OAAOoB,EAAUiB,KAAK,CAACvI,CAAK,CAAE0C,CAAW,CAAA1C,CAAA,CAAM,CAAE0C,CAAU,CAAC0F,CAAD,CAAU,CAAElI,CAAI,CAAE8D,CAAO,CAAEmE,CAAhE,CAJ0B,CAOjDK,SAASA,EAAK,CAACxI,CAAI,CAAEE,CAAI,CAAE1B,CAAb,CAAmB,CAChC,GAAIrC,CAAcC,UACjB,GAAI,CACH,OAAO4D,CAAI+C,GAAG,CAAC7C,CAAI,CAAE1B,CAAI,CAAE2B,CAAb,CADX,OAGG6F,EAAG,CACT,OAAOpF,CAAK,CAACoF,CAAC,CAAExH,CAAJ,CADH,CAIX,OAAOwB,CAAI+C,GAAG,CAAC7C,CAAI,CAAE1B,CAAI,CAAE2B,CAAb,CATkB,CAYjCmH,SAASA,EAAU,CAACpH,CAAI,CAAE8D,CAAO,CAAEmE,CAAW,CAAE7G,CAAU,CAAE2C,CAAG,CAAEvD,CAA9C,CAAwD,CAC1E,IAAI0D,EAAO,IAAI,CAIf,MAHI,CAAC9C,CAAW,EAAG8C,CAAIrB,GAAG0F,KAAM,EAAG,CAAC5L,CAACwH,QAAQ,CAACnE,CAAD,CAAzC,CACIsI,EAAK,CAACpE,CAAI,CAAElE,CAAI,CAAE,CAAC,IAAI,CAAEkE,CAAP,CAAb,CADT,CAGG3B,EAAa8F,KAAK,CAACnE,CAAI,CAAElE,CAAI,CAAE8D,CAAO,CAAEmE,CAAW,CAAE7G,CAAU,CAAE2C,CAAG,CAAEvD,CAApD,CALiD,CAQ3E+B,SAASA,EAAa,CAACvC,CAAI,CAAE8D,CAAO,CAAEmE,CAAW,CAAE7G,CAAU,CAAE2C,CAAG,CAAEvD,CAA9C,CAAwD,CAG7E,IAAIrC,EAAGC,GAAGoK,EAAUC,EAASC,GAAWC,GAAYC,GAAarN,EAAQyI,EAAa6E,GAAMC,EAAexC,GAAUxG,EAAMiJ,GAC1H7E,EAAO,KACP8E,EAAS,EAAE,CAmCZ,GAjCI,CAAC,CAAClF,CAAQ,GAAIA,C,GACjBmE,CAAY,CAAEnE,CAAO,CACrBA,CAAQ,CAAE1I,EAAS,CAGhB2I,CAAI,GAAI,CAAA,C,GACX6E,EAAY,CAAE,CAAA,CAAI,CAClB7E,CAAI,CAAE,EAAC,CAGJG,CAAI5I,IAAR,EAECC,CAAO,CAAE2I,CAAI,CACbA,CAAK,CAAEA,CAAI5I,IAAI,CACfuN,EAAK,CAAE3E,CAAI1F,EAAE,CACb8H,EAAS,CAAEpC,CAAI/C,QAAQ,CACvBrB,CAAK,CAAE+I,EAAI/I,KAAM,EAAGvE,CAAMuE,KAAK,CAC/BiJ,EAAQ,CAAE7E,CAAI1C,KAAM,EAAG0C,CAAI1C,KAAM,GAAImC,C,CACrCG,CAAQ,CAAE3D,CAAS,CAAC2D,CAAO,CAAEI,CAAI/E,IAAd,C,CACnB6E,CAAY,CAAEzI,CAAMqG,QAAQ,CACxBrG,CAAME,MAAMmB,KAAM,GAAI,CAAA,C,GAIzBkH,CAAQ,CAAEA,CAAQ,EAAG,CAAA,CAAE,CACvBA,CAAOlH,KAAM,CAAE,CAAA,EAAK,CAErBwE,CAAW,CAAEA,CAAW,EAAG7F,CAAM+C,KAAK,CACtC0B,CAAK,CAAER,SAASb,OAAQ,CAAEqB,CAAK,CAAEoB,EAlBlC,CAoBCtB,CAAK,CAAEoE,C,CAGJpE,C,GACC,CAACsB,CAAW,EAAGpB,CAAK,EAAGA,CAAIoC,IAAK,GAAI,M,GACvChB,CAAW,CAAEpB,EAAI,CAEdoB,C,GACH4C,CAAY,CAAEA,CAAY,EAAG5C,CAAUQ,QAAQ,CAC/CpB,CAAS,CAAEA,CAAS,EAAGY,CAAU5C,EAAEgC,SAAS,CACxCR,CAAK,GAAIoB,C,GAGZpB,CAAK,CAAEoB,CAAUpB,MAAK,CAEvB8D,CAAQ,CAAE3D,CAAS,CAAC2D,CAAO,CAAE1C,CAAUjC,IAApB,EAAyB,CAExCiC,CAAW,EAAGA,CAAUnD,KAAM,GAAI,K,GACtC,CAAC6F,CAAQ,CAAEA,CAAQ,EAAG,CAAA,CAAtB,CAAyBvF,KAAM,CAAEyB,EAAI,CAMjCF,CAAI+C,G,GACR/C,CAAK,CAAE0C,CAAW,CAAA1C,CAAA,CAAM,EAAG0C,CAAU,CAAC1C,CAAD,EAAM,CAGxCA,GAAM,CAYT,GAXAU,CAAS,CAAE,CAACsD,CAAQ,EAAGA,CAAOlH,KAAnB,CAA0B,GAAI,CAAA,CAAM,EAAG,CAACmM,EAAQ,EAAGvI,CAAQ,CAEtEsI,CAAc,CAAEtI,CAAQ,CACpBA,CAAS,GAAI,CAAA,C,GAEhBsI,CAAc,CAAE1N,CAAS,CACzBoF,CAAS,CAAEY,CAAU5C,EAAEgC,UAAS,CAEjCsD,CAAQ,CAAEhE,CAAImJ,QACb,CAAE9I,CAAS,CAACL,CAAImJ,QAAQ,CAAEnF,CAAf,CACX,CAAEA,CAAO,CACNnH,CAACwH,QAAQ,CAACnE,CAAD,CAAO,EAAG,CAACiI,EAMvB,IAHAQ,CAAQ,CAAEG,EACT,CAAExH,CAAW,CACZ2C,CAAI,GAAI3I,CAAU,EAAGgG,CAAY,EAAG,IAAIyC,CAAI,CAACC,CAAO,CAAE,OAAO,CAAE1C,CAAU,CAAEpB,CAAI,CAAEF,CAAI,CAAEiE,CAAG,CAAEC,CAAW,CAAExD,CAA7D,CAAsE,CAC/GrC,CAAE,CAAE,C,CAAGC,EAAE,CAAE4B,CAAIrB,OAAO,CAAER,CAAE,CAAEC,EAAC,CAAED,CAAC,EAArC,CAECqK,CAAS,CAAExI,CAAK,CAAA7B,CAAA,CAAE,CAClBuK,EAAU,CAAE,IAAI7E,CAAI,CAACC,CAAO,CAAE,MAAM,CAAE2E,CAAO,CAAED,CAAQ,CAAE1I,CAAI,CAAE,CAACiE,CAAI,EAAG,CAAR,CAAW,CAAE5F,CAAC,CAAE6F,CAAW,CAAExD,CAAxE,CAAiF,CACrGmI,EAAW,CAAEL,EAAK,CAACxI,CAAI,CAAE0I,CAAQ,CAAEE,EAAjB,CAA2B,CAC7CM,CAAO,EAAGP,CAAOjK,EAAEgC,SAAU,CAAEiI,CAAOjK,EAAEgC,SAAS,CAACmI,EAAU,CAAED,EAAb,CAAwB,CAAEC,EAC5E,CACC,KAGGvH,CAAW,EAAG,CAACtB,CAAI+C,GAAG0F,M,GACzBE,CAAQ,CAAEG,EAAY,CAAExH,CAAW,CAAE,IAAIyC,CAAI,CAACC,CAAO,CAAEwC,EAAS,EAAG,MAAM,CAAElF,CAAU,CAAEpB,CAAI,CAAEF,CAAI,CAAEiE,CAAG,CAAEC,CAAW,CAAExD,CAAxE,CAAiF,CAC1HqI,EAAK,EAAG,CAAC3E,CAAIf,K,GAChBsF,CAAOnN,IAAK,CAAE4I,GAAI,CAGpB8E,CAAO,EAAGV,EAAK,CAACxI,CAAI,CAAEE,CAAI,CAAEyI,CAAb,CAChB,CACA,OAAOK,CAAc,CAAEA,CAAa,CAACE,CAAM,CAAEP,CAAT,CAAkB,CAAEO,CApC/C,CAuCX,MAAO,EAxGsE,CAkH9EtI,SAASA,CAAK,CAACoF,CAAC,CAAExH,CAAI,CAAE4K,CAAV,CAAoB,CACjC,IAAIzM,EAAUR,CAAc0D,QAAQ,CAACmG,CAAC,CAAExH,CAAI,CAAE4K,CAAV,CAAmB,CACvD,GAAI,EAAG,CAAEpD,CAAE,GAAIA,EACd,MAAM,IAAIzI,CAAI8L,IAAI,CAAC1M,CAAD,CAAS,CAE5B,MAAO,CAAC6B,CAAIc,QAAS,EAAGd,CAAIgG,OAAQ,CAAE/H,EAAWqH,KAAK,CAACnH,CAAD,CAAU,CAAEA,CALjC,CAQlC2M,SAASA,CAAW,CAAC3M,CAAD,CAAU,CAC7BiE,CAAK,CAAC,gBAAiB,CAAEjE,CAApB,CADwB,CAI9BkK,SAASA,EAAM,CAACN,CAAM,CAAEvG,CAAI,CAAEuJ,CAAU,CAAEC,CAA3B,CAAwC,CAKtDC,SAASA,CAAoB,CAACC,CAAD,CAAQ,CACpCA,CAAM,EAAGC,CAAG,CACRD,C,EACH5H,CAAO8H,KAAK,CAACrD,CAAMsD,OAAO,CAACF,CAAG,CAAED,CAAN,CAAY5C,QAAQ,CAACgD,EAAQ,CAAE,KAAX,CAAlC,CAHuB,CAOrCC,SAASA,CAAa,CAAC1I,CAAD,CAAU,CAC/BA,CAAQ,EAAGiI,CAAW,CAAC,gCAAiC,CAAEjI,CAAQ,CAAE,oBAAqB,CAAEkF,CAArE,CADS,CAIhCyD,SAASA,CAAQ,CAACC,CAAG,CAAEC,CAAI,CAAE7I,CAAO,CAAEzB,CAAS,CAAEuK,CAAK,CAAErG,CAAI,CAAEsG,EAAO,CAAEC,EAAO,CAAEC,EAAM,CAAEC,EAAK,CAAEC,EAAU,CAAExL,EAA1F,CAAiG,CAK7G8E,C,GACHqG,CAAM,CAAE,GAAG,CACXvK,CAAU,CAAEiE,EAAO,CAEpB0G,EAAM,CAAEA,EAAM,EAAGhB,CAAU,CAE3B,IAAIkB,GAAe,CAACP,CAAK,EAAGX,CAAT,CAAqB,EAAG,CAAC,CAAA,CAAD,EAC1C5N,GAAQ,GACRyE,GAAO,GACPsK,GAAW,GACXC,GAAa,GACbC,GAAc,GACdC,GAAiB,GACjBhL,GAAU,GACViL,GAAa,GAEbC,GAAQ,CAACR,EAAM,EAAG,CAACJ,CAAM,EAAG,CAACC,EAAO,CAGrC/I,CAAQ,CAAEA,CAAQ,EAAG,CAACiJ,EAAO,CAAEA,EAAO,EAAG,O,CAASH,CAA7B,CAAmC,CACxDV,CAAoB,CAACzK,EAAD,CAAO,CAC3B2K,CAAI,CAAE3K,EAAM,CAAEiL,CAAGpL,OAAO,CACpBwL,EAAJ,CACK3D,C,EACH5E,CAAO8H,KAAK,CAAC,CAAC,GAAG,CAAE,IAAK,CAAEU,EAAMxD,QAAQ,CAACkE,EAAe,CAAE,IAAlB,CAAwB,CAAE,IAArD,CAAD,CAFd,CAIW3J,CAAJ,EACFA,CAAQ,GAAI,M,GACX4J,EAAWpP,KAAK,CAACyO,EAAD,C,EACnBhB,CAAW,CAAC,4CAAD,CAA8C,CAE1DmB,EAAa,CAAES,CAAQ,CAAA,CAAA,CAAE,CACzBA,CAAQ,CAAA,CAAA,CAAG,CAAE3E,CAAM4E,UAAU,CAACD,CAAQ,CAAA,CAAA,CAAE,CAAElM,EAAb,CAAmB,CAChDkM,CAAQ,CAAEE,CAAKC,IAAI,CAAA,CAAE,CACrBvJ,CAAQ,CAAEoJ,CAAQ,CAAA,CAAA,CAAE,CACpBH,EAAM,CAAE,CAAA,EAAI,CAETT,E,GAEHgB,EAAW,CAAChB,EAAMxD,QAAQ,CAACgD,EAAQ,CAAE,GAAX,CAAe,CAAEW,EAAY,CAAEzK,CAA9C,CACV8G,QAAQ,CAACyE,EAAU,CAAE,QAAQ,CAACtB,CAAG,CAAEuB,CAAO,CAAEC,CAAK,CAAExH,CAAG,CAAEyH,CAAQ,CAAEC,CAAQ,CAAEC,CAAG,CAAEC,CAApD,CAA2D,CAiBvF,OAhBID,CAAJ,EACCxL,EAAK,EAAGuL,CAAS,CAAE,GAAG,CACtBhB,EAAW,EAAG,GAAI,CAAEkB,CAAM,CAAE,KAF7B,CAGWJ,CAAJ,EACNf,EAAS,EAAGzG,CAAI,CAAE0H,CAAS,CAAE,GAAG,CAChCd,EAAe,EAAG5G,CAAI,CAAE,GAAI,CAAE4H,CAAM,CAAE,KAFhC,CAGIL,CAAJ,CACN3L,EAAQ,EAAG8L,CADL,EAGFD,CAAS,GAAI,S,GAChBZ,EAAW,EAAGa,EAAQ,CAEvBhQ,EAAM,EAAGsI,CAAI,CAAE0H,CAAS,CAAE,GAAG,CAC7Bf,EAAY,EAAG3G,CAAI,CAAE,GAAI,CAAE4H,CAAM,CAAE,IAAI,CACvCC,CAAY,CAAEA,CAAY,EAAGlQ,EAAYC,KAAK,CAAC6P,CAAD,E,CAExC,EAjBgF,CAAhF,CAkBN7K,MAAM,CAAC,CAAC,CAAE,EAAJ,CAAO,CAEZ4J,EAAa,EAAGA,EAAa,CAAA,CAAA,C,EAChCA,EAAYY,IAAI,CAAA,EAAE,CAIpBU,CAAQ,CAAE,CACR1K,CAAO,CACPzB,CAAU,EAAG,CAAC,CAAC4J,CAAY,EAAGsC,CAAY,EAAG,EAAE,CAC/Cf,EAAM,EAAG,CAAA,CAAE,CACXiB,EAAW,CAACrB,EAAU,CAAEC,EAAW,CAAEC,EAA1B,CAAyC,CACpDmB,EAAW,CAAC5L,EAAI,CAAEzE,EAAK,CAAE+O,EAAd,CAAuB,CAClC7K,EAAO,CACPiL,EAAU,CACVL,EAAa,EAAG,CARR,CASR,CACF3I,CAAO8H,KAAK,CAACmC,CAAD,CAAS,CACjBhB,E,GACHK,CAAKxB,KAAK,CAACsB,CAAD,CAAS,CACnBA,CAAQ,CAAEa,CAAO,CACjBb,CAAQ,CAAA,CAAA,CAAG,CAAEvB,GArDR,CAuDIa,E,GACVT,CAAa,CAACS,EAAW,GAAIU,CAAQ,CAAA,CAAA,CAAG,EAAGA,CAAQ,CAAA,CAAA,CAAG,GAAI,MAAO,EAAGV,EAAvD,CAAkE,CAC/EU,CAAQ,CAAA,CAAA,CAAG,CAAE3E,CAAM4E,UAAU,CAACD,CAAQ,CAAA,CAAA,CAAE,CAAElM,EAAb,CAAmB,CAChDkM,CAAQ,CAAEE,CAAKC,IAAI,CAAA,E,CAEpBtB,CAAa,CAAC,CAACmB,CAAQ,EAAGV,EAAb,CAAwB,CACrC1I,CAAQ,CAAEoJ,CAAQ,CAAA,CAAA,CA5F+F,CAgGlH,IAAIhC,EAAQ6C,EAASD,EACpBpF,EAAY1G,CAAK,EAAGA,CAAI0G,WACxBuF,EAAS,CAAA,EACTtC,EAAM,EACNyB,EAAQ,CAAA,EACRtJ,EAAUmK,EACVf,EAAU,AAAC,CAAA,AAAC,CAAA,CAACe,CAAH,CAAU,CAkCrB,OAzBI1C,C,GACHhD,CAAO,CAAE9I,CAAe,CAAE8I,CAAO,CAAE1I,EAAe,CAGnDkM,CAAa,CAACqB,CAAM,CAAA,CAAA,CAAG,EAAGA,CAAM,CAAA,CAAA,CAAG,CAAA,CAAA,CAAEC,IAAI,CAAA,CAAG,CAAA,CAAA,CAA/B,CAAkC,CAE/C9E,CAAMO,QAAQ,CAACtJ,CAAI,CAAEwM,CAAP,CAAgB,CAE9BP,CAAoB,CAAClD,CAAM1H,OAAP,CAAe,EAE/B8K,CAAI,CAAEsC,CAAO,CAAAA,CAAMpN,OAAQ,CAAE,CAAhB,E,EAChBkL,CAAa,CAAC,EAAG,CAAEJ,CAAI,GAAIA,CAAI,EAAI,CAACA,CAAI,CAAA,CAAA,CAAG,GAAIA,CAAI,CAAA,CAAA,CAAI,EAAGA,CAAI,CAAA,CAAA,CAAjD,CAAoD,CAK9DJ,CAAJ,EACCL,CAAO,CAAEgD,EAAS,CAACD,CAAM,CAAE1F,CAAM,CAAEgD,CAAjB,CAA4B,CAC9C4C,EAAQ,CAACjD,CAAM,CAAE+C,CAAO,CAAA,CAAA,CAAG,CAAA,CAAA,CAAnB,EAFT,CAIC/C,CAAO,CAAEgD,EAAS,CAACD,CAAM,CAAEjM,CAAT,C,CAEfkJ,CAAMT,K,GACTS,CAAMT,KAAM,CAAE,CAAO,MAAA5M,KAAK,CAAC0K,CAAD,EAAQ,CAE5B2C,CAxJ+C,CA2JvDiD,SAASA,EAAQ,CAACpJ,CAAE,CAAEqJ,CAAL,CAAY,CAC5BrJ,CAAEsJ,KAAM,CAAE,CAAA,CAAE,CACZ,IAAK,IAAIpI,EAAI,GAAGmI,CAAhB,CACKnI,CAAI,GAAI,QAAS,EAAGmI,CAAM,CAAAnI,CAAA,CAAIpF,O,GACjCkE,CAAEsJ,KAAM,CAAEtJ,CAAEsJ,KAAKC,OAAO,CAACF,CAAM,CAAAnI,CAAA,CAAP,EAE1B,CACAlB,CAAEqJ,MAAO,CAAEA,CAPiB,CAU7BJ,SAASA,EAAW,CAAC5L,CAAI,CAAEzE,CAAK,CAAE0D,CAAd,CAAmB,CACtC,MAAO,CAACe,CAAIS,MAAM,CAAC,CAAC,CAAE,EAAJ,CAAO,CAAElF,CAAKkF,MAAM,CAAC,CAAC,CAAE,EAAJ,CAAO,CAAExB,CAAGwB,MAAM,CAAC,CAAC,CAAE,EAAJ,CAAjD,CAD+B,CAIvC0L,SAASA,EAAc,CAACC,CAAK,CAAErO,CAAR,CAAc,CACpC,MAAO,MAAO,CAAE,CAACA,CAAK,CAAEA,CAAK,CAAE,IAAK,CAAE,EAAtB,CAA0B,CAAE,QAAS,CAAEqO,CAAM,CAAA,CAAA,CAAG,CAAE,GAAI,CAAE,CAACA,CAAM,CAAA,CAAA,CAAG,EAAG,CAACrO,CAAK,CAAE,cAAe,CAAEqO,CAAM,CAAA,CAAA,CAAG,CAAE,GAAI,CAAE,EAAvD,CAA2D,CAAE,CAACA,CAAM,CAAA,CAAA,CAAG,CAAE,YAAa,CAAEA,CAAM,CAAA,CAAA,CAAG,CAAE,GAAI,CAAE,EAA5C,CADjG,CAIrClB,SAASA,EAAW,CAAChB,CAAM,CAAEG,CAAY,CAAEzK,CAAvB,CAA6B,CAEhDyM,SAASA,CAAW,CAACxC,CAAG,CAAEyC,CAAO,CAAEC,CAAM,CAAEC,CAAK,CAAEC,EAAI,CAAEC,EAAQ,CAAEC,EAAG,CAAEC,EAAE,CAAEC,EAAK,CAAEC,EAAG,CAAEC,EAAK,CAAEC,EAAO,CAAEC,EAAI,CAAEC,EAAI,CAAEC,EAAK,CAAEC,EAAQ,CAAEC,EAAI,CAAEC,EAAK,CAAE1O,EAAK,CAAE2O,EAApI,CAA0I,CAY7JC,SAASA,EAAS,CAACC,CAAO,CAAEC,CAAG,CAAEC,CAAM,CAAE5O,CAAM,CAAEX,CAAI,CAAEwP,CAAY,CAAEC,CAAU,CAAEC,CAA/D,CAA0E,CAG3F,GAAIH,C,GACCI,C,GACCC,CAAM,GAAI,Q,GACbC,CAAO,CAAE5D,CAAY6D,OAAQ,CAAE7D,CAAY6D,OAAQ,EAAG,CAAA,CAAE,CACxDD,CAAMzE,KAAK,CAACiD,EAAD,EAAM,EAEd,CAACuB,CAAM,EAAGG,E,EACbJ,CAAQvE,KAAK,CAACiD,EAAIhM,MAAM,CAACiN,CAAGjP,OAAJ,CAAX,EAAwB,CAGnCkP,CAAO,GAAI,KAAK,CACnB,IAAI3L,EAAM,CAACjD,CACT,CAAE,YAAa,CAAEA,CAAO,CAAE,IAC1B,CAAEX,CACD,CAAE,MACF,CAAE,MAJK,CAKT,CAAE,CAAC0P,CACF,CAAE,CAACF,CACF,CAAE,GAAI,CAAEA,CACR,CAAE7O,CACD,CAAE,EACF,CAAGX,CAAK,CAAE,EAAG,CAAE,GAAI,CAAEuP,CAJrB,CAKC,CAAE,CAACE,CAAW,EAAG,EAAf,CACL,CAAE,CAACC,CAAU,CAAE/O,CAAO,CAAE,EAAG,CAAEX,CAAK,CAAEwP,CAAa,EAAG,EAAG,CAAED,C,CAAQ,EAA/D,CAPD,CAOoE,CAIvE,OAFA3L,CAAI,CAAEA,CAAI,CAAE,CAAC8L,CAAU,CAAE,GAAI,CAAEA,CAAU,CAAE,EAA/B,CAAkC,CAEvCJ,CAAI,CAAE,CAAC1L,CAAGvB,MAAM,CAAC,CAAC,CAAE,CAAJ,CAAO,GAAI,WACjC,CAAEuB,CAAGvB,MAAM,CAAC,CAAD,CACX,CAAEuB,CAFU,CAjBM,CAsBrB,OAAOyL,CAnCoF,CAR5Ff,EAAS,CAAEA,EAAS,EAAG,EAAE,CACzBH,CAAO,CAAEA,CAAO,EAAGD,CAAQ,EAAGU,EAAO,CACrCP,EAAK,CAAEA,EAAK,EAAGI,EAAK,CACpBC,EAAI,CAAEA,EAAI,EAAGO,EAAK,EAAG,EAAE,CAEvB,IAAIe,GAAMC,GAAMC,GACfC,GAAahB,EAAI9O,OAAQ,CAAE,CAAC,CAwC7B,GAAI,CAAAkO,EAAI,EAAI6B,CAAO,EAAIC,EAyBtB,OAtBIV,CAAS,EAAGX,EAAS,EAAG,CAACoB,CAAO,EAAG,CAACC,C,GAGnC,CAACT,CAAM,EAAGG,CAAU,EAAGF,E,GAC1BG,EAAK,CAAEM,CAAU,CAAAC,CAAA,CAAW,CACxBJ,EAAW,CAAE3P,EAAM,CAAEwP,E,GACxBA,EAAK,CAAEb,EAAI9M,MAAM,CAAC2N,EAAI,CAAExP,EAAM,CAAE,CAAf,CAAiB,CAClCwO,EAAS,CAAE7P,CAAe,CAAE,GAAI,CAAE6Q,EACjC,CAAE,aACF,CAAE5Q,CAAe,CAClB8Q,EAAO,CAAEM,CAAU,CAAAxB,EAAA,CAAS,CACvBkB,E,GACJM,CAAU,CAAAxB,EAAA,CAAU,CAAE,CAAA,CAAI,CAC1BwB,CAAU,CAAAxB,EAAA,CAAU,CAAEkB,EAAO,CAAE7H,EAAM,CAAC2G,EAAQ,CAAExN,CAAK,EAAGmO,CAAQ,CAAE,CAAA,CAA7B,CAAkC,CACvEO,EAAMtC,MAAMxC,KAAK,CAAC,CAAC,MAAM,CAAE8E,EAAT,CAAD,EAAkB,CAEhCA,EAAO,GAAI,CAAA,C,EACd,CAACL,CAAO,EAAGF,CAAX,CAAoBvE,KAAK,CAAC,CAAC,MAAM,CAAE8E,EAAT,CAAD,GAAkB,CAKvCE,CAEP,CAAE,CAACA,CAAO,CAAE,CAACvB,E,CAAOuB,CAAO,CAAE3E,CAAI,CAAE,GAAjC,CACF,CAAE4E,CAED,CAAE,CAACA,CAAO,CAAE,CAACvB,E,CAAOuB,CAAO,CAAE5E,CAAI,CAAE,GAAjC,CACF,CAEA,CAAC0C,CACC,CAAE,CAACoC,CAAU,E,CAAID,CAAU,CAAAC,CAAA,CAAY,CAAE/P,EAAK,E,CAAI2N,CAAhD,CACF,CAAE,EAFJ,CAGA,CAAE,CAACe,EACF,CAAGqB,CACF,CAAE,EAEF,CAAE,CAACE,CAAW,CAAEtB,EAAI9M,MAAM,CAACoO,CAAU,CAAEjQ,EAAb,C,CAAqBoP,CAC9C,CAAE,CAACA,CAAM,CAAEG,CAAU,CAAEF,CAAO,CAAE,CAAA,C,CAAO,IAArC,CACF,CAAE,KAFD,CAEQ,CAAEY,CAAW,CAAE,CAACA,CAAW,CAAEjQ,EAAM,CAAEiL,CAAGpL,O,CAASsP,CAAS,EAAG1D,CAAYb,KAAK,CAACuE,CAAS,CAAE,CAAA,CAAZ,C,CAAiB,IAAhF,CAE1B,CAAEnB,EAED,CAAE,CAAC+B,CAAW,EAAGzF,CAAW,CAACgB,CAAD,C,CAAU6D,CAAS,EAAG1D,CAAYY,IAAI,CAAA,C,CAAI+C,CAAM,CAAEvB,E,CAAM0B,CAAU,CAAE3B,C,CAAOqC,CAAW,CAAEjQ,EAAM,CAAEiL,CAAGpL,O,CAAS+N,CAAM,EAAG,CAACuB,CAAS,CAAE1D,CAAa,CAAA2D,CAAA,CAAO,CAAE,CAAA,CAAlC,C,CAAuCvB,EAAK,CAAE,GAA7L,CACF,CAAEA,EAED,CAAGA,EAAIqC,MAAM,CAAC,GAAD,CAAKC,KAAK,CAAC,GAAD,CAAKrI,QAAQ,CAACsI,EAAK,CAAExB,EAAR,CACnC,CAAE,CAACV,EACF,CAAE,CAACmC,CAAO,CAAA,EAAEN,CAAF,CAAc,CAAE,CAAA,C,CAAMlC,EAAInP,OAAO,CAAC,CAAD,CAAI,GAAI,GAAI,EAAG,CAACoR,CAAU,CAAAC,CAAA,CAAY,CAAE/P,EAAzB,C,CAAiCyP,EAAK,CAAE,EAAG,CAAEvB,EAArG,CACF,CAAEJ,EAFD,CAIH,CAAEA,EACD,CAAEA,EACF,CAAES,EAED,CAAG,CAAC8B,CAAO,CAAAN,CAAU,EAAV,CAAc,CAAE,CAAA,C,CAAOxB,EAA/B,CACF,CAAE,CAACL,EACF,CAAE,CAACmC,CAAO,CAAA,EAAEN,CAAF,CAAc,CAAE,CAAA,C,CAAM7B,EAA9B,CACF,CAAE,EAFD,CAIH,CAAEC,EACD,CAAE,CAACkC,CAAO,CAAAN,CAAA,CAAY,EAAGzF,CAAW,CAACgB,CAAD,C,CAAU,GAA5C,CACF,CAAEoC,CACD,CAAE,EACF,CAAE,CAACkC,CAAO,CAAEvB,E,CAAMwB,CAAO,CAAEvB,E,CAAM,GAA/B,CA/BP,CAkCL,CArEChE,CAAW,CAACgB,CAAD,CAnDiJ,CA0H9J,IAAI8D,EAAOC,EAAQE,EAClBM,EACAD,EACAT,EAAW1D,CAAa,EAAGA,CAAa,CAAA,CAAA,EACxCwE,EAAa,EACbD,EAAYhP,CAAK,CAAEA,CAAIsP,MAAO,CAAEnB,CAAS,EAAG,CAACA,CAAQmB,MAAO,CAAEnB,CAAQmB,MAAO,EAAG,CAAA,CAApC,EAC5CD,EAAS,CAAA,EACTP,EAAY,CAAC,CAAC,CAAE,EAAJ,EACZC,EAAa,CAAC,CAEf,MAAO,CAACzE,CAAO,CAAE,CAACtK,CAAK,CAAE,GAAI,CAAE,EAAd,CAAV,CACN8G,QAAQ,CAAQ,OAAA,CAAE,IAAV,CAERA,QAAQ,CAACyI,EAAO,CAAE9C,CAAV,CAzIuC,CA4IjDP,SAASA,EAAS,CAACsD,CAAG,CAAExP,CAAI,CAAEuJ,CAAZ,CAAwB,CAGzC,IAAIlL,EAAGoR,EAAMpO,EAASzB,EAAWnE,EAAQiU,GAAQC,GAAYC,GAASC,GAASC,GAAUC,GAASC,EAAcvF,EAAcH,GAAQ2F,GAAiBC,GACtJC,EAAWC,GAAa5J,EAAU6J,GAAYC,EAAaxO,GAASyE,GAAQgK,EAAYC,GAASC,GAAQC,GAAUC,EAAU9Q,EAAS+Q,GAAUC,GAChJC,EAAiB,EACjBC,EAAO,GACPC,GAAc,CAAA,EACd1S,GAAIkR,CAAG3Q,OAAO,CAgBf,IAdI,EAAG,CAAEmB,CAAK,GAAIA,CAAlB,EACCwG,CAAS,CAAE+C,CAAW,CAAE,aAAc,CAAEvJ,CAAI8G,QAAQ,CAACgD,EAAQ,CAAE,GAAX,CAAejJ,MAAM,CAAC,CAAC,CAAE,EAAJ,CAAQ,CAAE,GAAI,CAAEb,CAAI,CAC7FA,CAAK,CAAE,EAFR,EAICwG,CAAS,CAAExG,CAAIwG,SAAU,EAAG,SAAS,CACjCxG,CAAI0G,U,GACPsK,EAAWtK,UAAW,CAAE,CAAA,EAAI,CAEzB1G,CAAIyG,M,GACPuK,EAAWvK,MAAO,CAAE,CAAA,EAAI,CAEzBuJ,CAAa,CAAEhQ,CAAIC,KAAK,CACxBmQ,EAAY,CAAEpQ,CAAIuC,O,CAEdlE,CAAE,CAAE,CAAC,CAAEA,CAAE,CAAEC,EAAC,CAAED,CAAC,EAApB,CAKC,GAHAoR,CAAK,CAAED,CAAI,CAAAnR,CAAA,CAAE,CAGT,EAAG,CAAEoR,CAAK,GAAIA,EAEjBsB,CAAK,EAAG,MAAO,CAAEtB,CAAK,CAAE,GAAG,CAC1B,KAGD,GADApO,CAAQ,CAAEoO,CAAK,CAAA,CAAA,CAAE,CACbpO,CAAQ,GAAI,IAEf0P,CAAK,EAAG,KAAM,CAAEtB,CAAK,CAAA,CAAA,CAAG,CAAE,WAAW,CACpC,IAAK,CAyCN,GAxCA7P,CAAU,CAAE6P,CAAK,CAAA,CAAA,CAAE,CACnB3N,EAAQ,CAAE2N,CAAK,CAAA,CAAA,CAAE,CACjBhU,CAAO,CAAE8Q,EAAc,CAACkD,CAAK,CAAA,CAAA,CAAE,CAAE,QAAV,CAAoB,CAAE,IAAK,CAAElD,EAAc,CAACjC,EAAO,CAAEmF,CAAK,CAAA,CAAA,CAAf,CAAkB,CACpF5P,CAAQ,CAAE4P,CAAK,CAAA,CAAA,CAAE,CACjBoB,EAAQ,CAAEpB,CAAK,CAAA,CAAA,CAAE,CACjBlJ,EAAO,CAAEkJ,CAAK,CAAA,CAAA,CAAE,EACVgB,EAAO,CAAEpP,CAAQ,GAAI,O,GAC1ByP,CAAe,CAAE,CAAC,CACdd,CAAa,EAAG,CAACvF,CAAa,CAAEgF,CAAK,CAAA,CAAA,CAArB,C,GACnBqB,CAAe,CAAEd,CAAYpG,KAAK,CAACa,CAAD,GAAc,EAG9CiG,EAAS,CAAErP,CAAQ,GAAI,IAA3B,CACKzB,C,GACHyB,CAAQ,CAAEzB,CAAU,GAAIiE,CAAQ,CAAE,GAAI,CAAEjE,CAAU,CAAEyB,EAFtD,EAKKS,E,GAEHuO,EAAW,CAAEzJ,EAAU,CAACL,EAAM,CAAEyK,EAAT,CAAqB,CAC5CX,EAAU7J,SAAU,CAAEA,CAAS,CAAE,GAAI,CAAEnF,CAAO,CAE9C6K,EAAS,CAACpK,EAAO,CAAEuO,EAAV,CAAqB,CAC9BD,EAAWxG,KAAK,CAACyG,EAAD,EAAY,CAGxBI,E,GAEJH,CAAY,CAAEjP,CAAO,CAErBmP,EAAQ,CAAEO,CAAI,CACdA,CAAK,CAAE,GAAE,CAEVR,CAAW,CAAEf,CAAI,CAAAnR,CAAE,CAAE,CAAJ,CAAM,CACvBkS,CAAW,CAAEA,CAAW,EAAGA,CAAW,CAAA,CAAA,CAAG,GAAI,O,CAE9CK,EAAS,CAAE/Q,CAAQ,CAAE,gBAAiB,CAAE,KAAK,CAC7CoQ,EAAgB,CAAE,EAAE,CACpBC,EAAa,CAAE,EAAE,CAEbQ,EAAS,EAAG,CAACjG,CAAa,EAAGoG,EAAQ,EAAGjR,CAAU,EAAGA,CAAU,GAAIiE,CAAvD,EAAiE,CAYhF,GAVA8M,CAAS,CAAE,UAAW,CAAElV,CAAO,CAAE,IAAI,CACrC0U,CAAU,CAAE,KAAM,CAAEvQ,CAAU,CAAE,SAAS,CACzC+Q,CAAS,CAAE,IAAIM,QAAQ,CAAC,eAAe,CAAE,MAAO,CAAEzK,CAAS,CAAE,GAAI,CAAEsK,CAAe,CAAE,GAAI,CAAEzP,CACrF,CAAE,IAAK,CAAEsP,CADS,CACA,CACvBA,CAAQpQ,IAAK,CAAEV,CAAO,CAEtBoQ,EAAgB,CAAEE,CAAU,CAAEW,CAAe,CAAE,GAAG,CAClDZ,EAAc,CAAE,GAAG,CAEnBS,CAAQO,KAAM,CAAE7P,CAAO,CACnBkI,EACH,OAAOoH,CACR,CACAxE,EAAQ,CAACwE,CAAQ,CAAElG,CAAX,CAAwB,CAChCsF,EAAQ,CAAE,CAAA,CAhBsE,CA+BjF,GAbAgB,CAAK,EAAIL,EACR,CAAE,CAACnH,CAAW,CAAE,CAAC1J,CAAQ,CAAE,UAAW,CAAE,EAAxB,CAA4B,CAAE,SAAU,CAAE+Q,EAAxD,CAAkE,CAAE,CAACb,EACtE,CAAE,CAACA,EAAQ,CAAEzU,C,CAAWwU,EAAS,CAAED,EAAQ,CAAE,CAAA,C,CAAMM,CAAU,CAAE,CAAC1F,CAC/D,CAAE,CAAEuF,CAAa,CAAAc,CAAe,CAAE,CAAjB,CAAoB,CAAEH,C,CAAWG,CAAhD,CACF,CAAE,GAAI,CAAErV,CAAO,CAAE,GAF6C,CAExC,CAAE,GAFvB,CAGF,CAAE4F,CAAQ,GAAI,GACb,CAAE,CAACsO,EAAW,CAAE,CAAA,C,CAAM,IAAK,CAAErF,EAAO,CAAA,CAAA,CAAG,CAAE,GAAvC,CACF,CAAE,CAACsF,EAAQ,CAAE,CAAA,C,CAAM,MAAO,CAAEtF,EAAO,CAAA,CAAA,CAAG,CAAE,eAAtC,CANkE,CAQtE,CAAE,CAACwF,EAAS,CAAEJ,EAAO,CAAE,CAAA,C,CAAM,oBAC5B,CAAE,CAAC5N,EAAQ,CAAEsO,EAAWvR,OAAQ,CAAE,GAAhC,CAAqC,CAAE,GACzC,CAAEpD,CAAO,CAAE,IAFV,CAEgB,CAEf6U,CAAY,EAAG,CAACC,EAAY,CAK/B,GAFAQ,CAAK,CAAE,GAAI,CAAEA,CAAIlQ,MAAM,CAAC,CAAC,CAAE,EAAJ,CAAQ,CAAE,GAAG,CACpCsP,CAAU,CAAE,KAAM,CAAEG,CAAY,CAAE,cAAc,CAC5C/G,CAAW,EAAGkB,EAAc,CAQ/B,GANAsG,CAAK,CAAE,IAAIE,QAAQ,CAAC,eAAe,CAAE,MAAO,CAAEzK,CAAS,CAAE,GAAI,CAAEsK,CAAe,CAAE,GAAI,CAAER,CAAY,CAAE,WAAY,CAAES,CAAK,CAAE,GAAtG,CAA0G,CAC7HA,CAAIxQ,IAAK,CAAEV,CAAO,CAClBkR,CAAIG,KAAM,CAAE7P,CAAO,CACfoJ,C,EACH0B,EAAQ,CAAC6D,CAAa,CAAAc,CAAe,CAAE,CAAjB,CAAoB,CAAEC,CAAI,CAAEtG,CAA1C,CAAuD,CAE5DlB,EACH,OAAOwH,CACR,CACAd,EAAgB,CAAEE,CAAU,CAAEW,CAAe,CAAE,aAAa,CAC5DZ,EAAc,CAAE,GAZe,CAkBhCa,CAAK,CAAEP,EAAQ,CAAEI,EAAS,CAAET,CAAU,CAAE,CAACW,CAAe,EAAGC,CAAnB,CAAyB,CAAE,GAAG,CACtEtG,CAAa,CAAE,CAAC,CAChB6F,CAAY,CAAE,CAzBiB,CA2B5BzQ,C,GACHiQ,EAAS,CAAE,CAAA,CAAI,CACfiB,CAAK,EAAG,kBAAmB,CAAE,CAACxH,CAAW,CAAE,MAAO,CAAE,IAAvB,CAA6B,CAAE0G,EAAgB,CAAE,gBAAiB,CAAEpQ,CAAQ,CAAE,GAAI,CAAEqQ,EAAc,CAAE,MAAO,CAAE,CAAC3G,CAAW,CAAE,EAAG,CAAE,SAAnB,EArGrI,CA2GTwH,CAAK,CAAE,KAAM,CAAEvK,CAEd,CAAE,SACF,CAAE,CAACkJ,EAAO,CAAE,WAAY,CAAE,EAAxB,CACF,CAAE,CAACG,EAAQ,CAAE,YAAa,CAAE,EAA1B,CACF,CAAE,CAACF,EAAW,CAAE,sBAAuB,CAAE,EAAvC,CACF,CAAE,CAACpG,CAAW,CAAE,KAAM,CAAE,WAAtB,CACF,CAAE,CAACyH,EAAWvK,MAAO,CAAE,WAAY,CAAE,EAAnC,CACF,CAAEsK,CACF,CAAE,CAACxH,CAAW,CAAE,IAAK,CAAE,gBAArB,CAAsC,CACzC,GAAI,CACHwH,CAAK,CAAE,IAAIE,QAAQ,CAAC,eAAe,CAAEF,CAAlB,CADhB,OAEK/K,GAAG,CACXsD,CAAW,CAAC,6BAA8B,CAAEyH,CAAK,CAAE,OAAQ,CAAE/K,EAACrJ,QAAS,CAAE,GAA9D,CADA,CASZ,OANIqD,C,GACHA,CAAI+C,GAAI,CAAEgO,EAAI,CAEVjB,E,GACJiB,CAAItI,KAAM,CAAE,CAAA,EAAI,CAEVsI,CAtKkC,CA8K1C1Q,SAASA,CAAS,CAAC2D,CAAO,CAAEmN,CAAV,CAAyB,CAG1C,OAAOnN,CAAQ,EAAGA,CAAQ,GAAImN,CAC7B,CAAGA,CACF,CAAEpU,CAAO,CAACA,CAAO,CAAC,CAAA,CAAE,CAAEoU,CAAL,CAAmB,CAAEnN,CAA7B,CACT,CAAEA,CACH,CAAEmN,CAAc,EAAGpU,CAAO,CAAC,CAAA,CAAE,CAAEoU,CAAL,CAPe,CAW3CC,SAASA,EAAa,CAACC,CAAD,CAAK,CAC1B,OAAOC,EAAa,CAAAD,CAAA,CAAI,EAAG,CAACC,EAAa,CAAAD,CAAA,CAAI,CAAE,IAAK,CAAEA,CAAEE,WAAW,CAAC,CAAD,CAAI,CAAE,GAA9C,CADD,CAwI3BC,SAASA,EAAc,CAACvU,CAAD,CAAS,CAG/B,IAAIgH,EAAKvI,EACRC,EAAQ,CAAA,CAAE,CAEX,GAAI,OAAOsB,CAAO,EAAI,SACrB,IAAKgH,EAAI,GAAGhH,CAAZ,CACCvB,CAAK,CAAEuB,CAAO,CAAAgH,CAAA,CAAI,CACbvI,CAAK,EAAIA,CAAI+V,OAAQ,EAAG,CAAA/V,CAAI+V,OAAO,CAAA,C,EAClCvU,CAAW,CAACxB,CAAD,C,EACfC,CAAKiO,KAAK,CAAC,CAAE,GAAG,CAAE3F,CAAG,CAAE,IAAI,CAAEvI,CAAlB,CAAD,CAId,CACA,OAAOC,CAhBwB,CA0BhC+V,SAASA,EAAU,CAACC,CAAD,CAAO,CAEzB,OAAOA,CAAK,EAAG,IAAK,CAAEC,EAAO/V,KAAK,CAAC8V,CAAD,CAAO,EAAG,CAAC,EAAG,CAAEA,CAAN,CAAW7K,QAAQ,CAAC+K,EAAW,CAAET,EAAd,CAA6B,EAAGO,CAAK,CAAE,EAF7E,CA/oD1B,IAAI,CAAAtW,CAAO,EAAG,CAAAA,CAAMwH,QAAQ,EAAG,CAAAzH,CAAM0W,SAAU,CAI/C,IAECjV,EAAGkV,GAAcvU,EAAMQ,GAAa3B,GAGpCoB,EAAiB,IAAKE,EAAiB,IAAKC,EAAkB,IAAKC,EAAkB,IAAKC,GAAW,IAErGsR,GAAsH,+GAGtHG,GAAmP,0OAInPzF,GAAgC,sBAChCkB,GAA6B,YAC7BjE,GAAyB,UACzBwE,GAAsF,0EACtFN,GAAqB,QACrB1D,GAA0B,cAE1BqK,GAAyB,gBACzBhW,GAA0C,4BAC1CiW,GAH6B,gBAI7B1L,GAAe,EACf5B,GAAS,EACT+M,GAAe,CACd,GAAG,CAAE,OAAO,CACZ,GAAG,CAAE,MAAM,CACX,GAAG,CAAE,MAAM,CACX,MAAM,CAAE,MAAM,CACd,GAAG,CAAE,OAAO,CACZ,GAAG,CAAE,OAAO,CACZ,GAAG,CAAE,OAPS,EASfzN,EAAU,OACVqC,GAAW,gBACXS,GAAU,CAAA,EACVzB,EAAY,CACX,QAAQ,CAAE,CACT,OAAO,CAAEO,EADA,CAET,CACD,GAAG,CAAE,CACJ,OAAO,CAAEN,EADL,CAEJ,CACD,MAAM,CAAE,CAAA,CAAE,CACV,SAAS,CAAE,CAAA,CARA,EAYZhF,EAAS,CACR,OAAO,CAnDW,aAmDI,CACtB,QAAQ,CAAE4E,QAAQ,CAACA,CAAD,CAAW,CAC5BhI,CAAO,CAACZ,CAAc,CAAE4I,CAAjB,CAA0B,CACjC9I,EAAO,CAACE,CAAcC,SAAf,CAAyB,CAC5BD,CAAc6V,I,EACjB7V,CAAc6V,IAAI,CAAA,CAJS,CAM5B,CACD,GAAG,CAAE,CAEJ,IAAI,CAAEjO,CAAI,CACV,GAAG,CAAErH,EAAY,CACjB,MAAM,CAAEmK,EAAM,CACd,GAAG,CAAErG,EAAW,CAChB,KAAK,CAAE8K,EAAW,CAClB,MAAM,CAAEvO,CAAO,CACf,SAAS,CAAEuM,CAAW,CACtB,OAAO,CAAE,CAAA,CAAE,CACX,IAAI,CAAExN,EAAM,CACZ,IAAI,CAAEP,EAXF,CAYJ,CACD,GAAG,CAAE4H,EAAO,CACZ,KAAK,CAAExD,EAAU,CACjB,IAAI,CAAEyB,EAAS,CACf,IAAI,CAAER,CAzBE,CA0BR,CA8CF,CAAClE,EAAY4I,UAAW,CAAE,IAAI2M,KAA9B,CAAsC1M,YAAa,CAAE7I,EAAY,CA4FjEqC,EAAc+B,QAAS,CAAEoR,QAAQ,CAAA,CAAG,CACnC,MAAO,CAAC,IAAItT,IAAI,CAAC,MAAD,CAAQ,CAAE,OAAnB,CAD4B,CAEnC,CAMDK,EAAQ6B,QAAS,CAAEqR,QAAQ,CAAA,CAAG,CAC7B,MAAO,CAAC,OAAD,CADsB,CAE7B,CAqXDpO,CAAIuB,UAAW,CAAE,CAChB,GAAG,CAAErH,EAAO,CACZ,QAAQ,CAAEgB,EAAQ,CAClB,MAAM,CAAE+B,EAAW,CACnB,GAAG,CAAE9B,EAAS,CACd,GAAG,CAAE,MALW,CAMhB,CAo5BD,IAAK6S,GAAa,GAAG7M,CAArB,CACC0C,EAAa,CAACmK,EAAY,CAAE7M,CAAU,CAAA6M,EAAA,CAAzB,CACd,CAEA,IAAIrP,EAAavC,CAAMiS,WACtB3V,GAAc0D,CAAMkS,YACpB9V,GAAW4D,CAAMgJ,SACjB7M,GAAQ6D,CAAMsB,MACdlE,EAAO4C,CAAMmS,KACbnW,EAAiBgE,CAAM4E,SAAS,CAE7B1J,CAAJ,EAGCwB,CAAE,CAAExB,CAAM,CACVwB,CAACkG,GAAGF,OAAQ,CAAEqF,EAAW,CACrBrL,CAAC0V,W,GACJxV,CAAO,CAACQ,CAAI,CAAEV,CAACuB,MAAMkU,IAAd,CAAmB,CAC1BnS,CAAMiD,IAAK,CAAEvG,CAACuB,MAAMgF,MAPtB,EAaCvG,CAAE,CAAEzB,CAAM0W,QAAS,CAAE,CAAA,CAAE,CAEvBjV,CAACwH,QAAS,CAAEmO,KAAM,EAAGA,KAAKnO,QAAS,EAAGoO,QAAQ,CAACC,CAAD,CAAM,CACnD,OAAOC,MAAMrN,UAAUsN,SAASrK,KAAK,CAACmK,CAAD,CAAM,GAAI,gBADI,E,CAUrD7V,CAACgG,OAAQ,CAAE8D,EAAO,CAClB9J,CAACuB,MAAO,CAAE+B,CAAM,CAChBtD,CAACuV,UAAW,CAAE1P,CAAW,CAAEvC,CAAMiS,UAAU,CAE3CjW,CAAc,CAAC,CACd,SAAS,CAAEF,EAAO,CAClB,UAAU,CAAEmB,EAAgB,CAC5B,OAAO,CAAEyC,QAAQ,CAACmG,CAAC,CAAExH,CAAI,CAAE4K,CAAV,CAAoB,CASpC,OAPI5K,C,GAEHwH,CAAE,CAAEoD,CAAS,GAAI9N,CAChB,CAAE,UAAW,CAAE0K,CAAE,CAAE,GACnB,CAAE9I,CAAW,CAACkM,CAAD,CACZ,CAAEA,CAAQ,CAACpD,CAAC,CAAExH,CAAJ,CAAU,CAAE4K,EAAQ,CAE1BpD,CAAE,EAAG1K,CAAU,CAAE,EAAG,CAAE0K,CATO,CAUpC,CACD,QAAQ,CAAE,CAAA,CAdI,CAAD,CAeZ,CAIF1J,EAAK,CAAC,CACL,MAAM,CAAEuW,QAAQ,CAAA,CAAG,EAAE,CACrB,IAAI,CAAE,CACL,MAAM,CAAEhQ,QAAQ,CAAC9G,CAAD,CAAM,CAKrB,IAAIqI,EAAO,IAMmC,CAC9C,OANQA,CAAIZ,UAAUsP,KAAM,EAAG,CAAC/W,CAAI,EAAG,CAAC2D,SAASb,OAAQ,EAAG,CAACuF,CAAI3I,OAAOuD,MAAjC,CACrC,CAAE,EACF,CAAE,CAACoF,CAAIZ,UAAUsP,KAAM,CAAE,CAAA,C,CAAM1O,CAAI2O,SAAU,CAAE3O,CAAI3I,OAAOuD,M,CAGzDoF,CAAI3I,OAAOoH,OAAO,CAACuB,CAAI3I,OAAO+C,KAAK,CAAE,CAAA,CAAnB,CAHjB,CARiB,CAarB,CACD,QAAQ,CAAEwU,QAAQ,CAACC,CAAE,CAAEC,CAAS,CAAE3R,CAAhB,CAAyB,CAE1C,IADA,IAAS4R,EAASC,EACbC,EAAM,CAAC,CAAE,CAACF,CAAQ,CAAE,IAAI5R,QAAS,CAAA8R,CAAA,CAAxB,CAA8B,EAAGF,CAAO/S,KAAKvB,OAAO,CAAEwU,CAAG,EAAvE,CAGC,GAFAF,CAAQ,CAAEA,CAAO/S,KAAM,CAAA,CAAA,CAAE,CACzBgT,CAAU,CAAE,CAACD,CAAQ,EAAI,CAAC5R,CAAQ,CAAA8R,CAAA,CAAIjT,KAAM,CAAA,CAAA,CAAE,CACzC,CAAC,IAAIK,QAAS,EAAG,CAAC,CAAC0S,CAAS,EAAGC,EACnC,OAAOA,CAKT,CAEA,MAAO,CAAA,CAbmC,CAc1C,CACD,IAAI,CAAE,CAAA,CA9BD,CA+BL,CACD,KAAK,CAAE,CACN,MAAM,CAAEvQ,QAAQ,CAAC9G,CAAD,CAAM,CAGrB,IAAIuX,EACHlP,EAAO,KACP3I,EAAS2I,CAAI3I,QACbyN,EAAS,GACT4J,EAAO,CAAC,CAeT,OAbK1O,CAAIZ,UAAUsP,K,IACdQ,CAAU,CAAE,CAAC5T,SAASb,Q,GACzB9C,CAAI,CAAEN,CAAM+C,KAAK0B,MAAK,CAEnBnE,CAAI,GAAIT,C,GACX4N,CAAO,EAAGzN,CAAMoH,OAAO,CAAC9G,CAAG,CAAEuX,CAAN,CAAgB,CACvCR,CAAK,EAAGjW,CAACwH,QAAQ,CAACtI,CAAD,CAAM,CAAEA,CAAG8C,OAAQ,CAAE,EAAC,EAEpCuF,CAAIZ,UAAUsP,KAAM,CAAEA,E,GACzB1O,CAAI2O,SAAU,CAAEtX,CAAMuD,QAAM,CAIvBkK,CAtBc,CAuBrB,CACD,IAAI,CAAE,CAAA,CAzBA,CA0BN,CACD,OAAO,CAAE,CACR,IAAI,CAAE,CAAA,CADE,CAER,CACD,GAAG,CAAE,CAEJ,MAAM,CAAEpN,EAAM,CACd,IAAI,CAAE,CAAA,CAHF,CAhEA,CAAD,CAqEH,CAqBFQ,EAAK,CAAC,OAAO,CAAE,CACd,OAAO,CAAEA,EAAM,CAAA,KAAA,CAAM,CACrB,OAAO,CAAE6G,EAAO,CAACqO,EAAD,CAFF,CAAV,CAGH,CASF/U,EAAW,CAAC,CACX,IAAI,CAAEiV,EAAU,CAChB,IAAI,CAAEA,EAAU,CAChB,GAAG,CAAE6B,QAAQ,CAAC5B,CAAD,CAAO,CAEnB,OAAOA,CAAK,EAAGrW,CAAU,CAAEkY,SAAS,CAAC,EAAG,CAAE7B,CAAN,CAAY,CAAEA,CAAK,GAAI,IAAK,CAAEA,CAAK,CAAE,EAFtD,CAHT,CAAD,CAOT,CAGFvU,EAAgB,CAAA,CA9pD+B,CAJX,EAoqDnC,CAAC,IAAI,CAAE,IAAI/B,OAAX,CAAmB", -"sources":["jsrender.js"], -"names":["global","jQuery","undefined","tagHandlersFromProps","tag","tagCtx","prop","props","rHasHandlers","test","retVal","val","dbgBreak","dbgMode","debugMode","$viewsSettings","_dbgMode","indexStr","$tags","$helpers","dbg","$converters","JsViewsError","message","name","$","link","$extend","target","source","$isFunction","ob","$viewsDelimiters","openChars","closeChars","$sub","rTag","delimOpenChar0","charAt","delimOpenChar1","delimCloseChar0","delimCloseChar1","linkChar","RegExp","rTmplString","getView","inner","type","views","i","l","found","view","root","_","useKey","get","length","parent","getNestedIndex","index","getIndex","getHelper","helper","wrapped","ctx","linkCtx","res","_wrp","apply","arguments","convertVal","converter","onError","value","boundTag","tmpl","bnds","data","$views","args","extendCtx","_lnk","_er","convertArgs","convert","onRender","getRsc","error","slice","depends","getDeps","getResource","resourceType","itemName","store","renderTag","tagName","parentView","tagCtxs","isUpdate","tags","attr","parentTag","itemRet","tagCtxCtx","content","tagDef","callInit","mapDef","thisMap","initialTmpl","ret","parentTmpl","_is","tmpls","template","renderContent","$templates","_ctr","init","render","bnd","fn","arrVws","dataBoundOnly","_def","dataMap","map","flow","parents","parentTags","rendering","src","unmap","tgt","inline","htmlStr","html","View","context","key","contentTmpl","parentView_","self","isArray","self_","viewId","linked","splice","compileChildResources","storeName","resources","resourceName","resource","settings","compile","onStore","jsvStores","compileTag","baseTag","tagDef._ctr","prototype","constructor","_parentTmpl","compileTmpl","options","tmplOrMarkupFromStr","nodeType","elem","document","find","e","getAttribute","tmplAttr","autoTmplName","setAttribute","innerHTML","tmplOrMarkup","markup","tmplName","debug","allowCode","$render","TmplObject","tmplFn","replace","rEscapeQuotes","newMap","getTgt","baseMap","mapDef.map","htmlTag","wrapMap","fastRender","rFirstElem","exec","toLowerCase","div","trim","registerStore","storeSettings","theStore","item","thisStore","storeNames","$fastRender","noIteration","tmplElem","jquery","selector","call","tryFn","_nvw","dataItem","newView","childView","itemResult","swapContent","tag_","outerOnRender","noViews","result","helpers","fallback","Err","syntaxError","isLinkExpr","convertBack","pushprecedingContent","shift","loc","push","substr","rNewLine","blockTagCheck","parseTag","all","bind","colon","comment","codeTag","params","slash","closeBlock","pathBindings","ctxProps","paramsArgs","paramsProps","paramsCtxProps","useTrigger","block","rUnescapeQuotes","rTestElseIf","current","substring","stack","pop","parseParams","rBuildHash","onerror","isCtx","keyToken","keyValue","arg","param","hasHandlers","newNode","parsedParam","astTop","buildCode","setPaths","paths","deps","concat","paramStructure","parts","parseTokens","lftPrn0","lftPrn","bound","path","operator","err","eq","path2","prn","comma","lftPrn2","apos","quot","rtPrn","rtPrnDot","prn2","space","full","parsePath","allPath","not","object","viewProperty","pathTokens","leafToken","bindings","named","bindto","_jsvto","boundName","expr","isFn","exprFn","fullLength","aposed","quoted","pathStart","parenDepth","tmplLinks","paramIndex","split","join","rPath","fnCall","links","rParams","ast","node","hasTag","hasEncoder","getsVal","hasCnvt","needView","useCnvt","tmplBindings","boundOnErrStart","boundOnErrEnd","tagRender","nestedTmpls","nestedTmpl","tagAndElses","nextIsElse","oldCode","isElse","isGetVal","tagCtxFn","tagStart","trigger","tmplBindingKey","code","tmplOptions","Function","_tag","parentContext","getCharEntity","ch","charEntities","charCodeAt","getTargetProps","toJSON","htmlEncode","text","rIsHtml","rHtmlEncode","jsviews","jsvStoreName","jsv","Error","getNestedIndex.depends","getIndex.depends","templates","converters","sub","observable","Array","$.isArray","obj","Object","toString","else","done","selected","onUpdate","ev","eventArgs","prevArg","different","tci","finalElse","url","encodeURI"] -} diff --git a/BuildFeed/Views/Web.config b/BuildFeed/Views/Web.config index f45a8e8..2ab13a6 100644 --- a/BuildFeed/Views/Web.config +++ b/BuildFeed/Views/Web.config @@ -15,7 +15,6 @@ - diff --git a/BuildFeed/Views/front/index.cshtml b/BuildFeed/Views/front/index.cshtml index 797eac0..5359c06 100644 --- a/BuildFeed/Views/front/index.cshtml +++ b/BuildFeed/Views/front/index.cshtml @@ -1,4 +1,6 @@ -@using BuildFeed.Local +@using BuildFeed.Code +@using BuildFeed.Controllers +@using BuildFeed.Local @using BuildFeed.Models.ViewModel.Front @using Humanizer @model IEnumerable @@ -18,22 +20,15 @@ }

    @Front.HomepageH1

    -

    @Front.Share

    -

    @Front.Listing

    -
    +
    @foreach (FrontBuildGroup group in Model) { -
    +

    - - @group.Key.ToString() + + @group.Key.ToString() +

    @if (group.LastBuild.HasValue) { @@ -43,12 +38,10 @@ if (maxDate.AddDays(28) > DateTime.Now) { @maxDate.Humanize() -
    } else { @maxDate.ToLongDateWithoutDay() -
    } }

    @@ -59,4 +52,4 @@
    }
    -@PaginationHelpers.PaginationBlock((int) ViewBag.PageNumber, (int) ViewBag.PageCount, "Index", ViewContext.RouteData.Values) \ No newline at end of file +@PaginationHelpers.PaginationBlock((int) ViewBag.PageNumber, (int) ViewBag.PageCount, nameof(FrontController.Index), ViewContext.RouteData.Values) \ No newline at end of file diff --git a/BuildFeed/Views/front/viewBuild.cshtml b/BuildFeed/Views/front/viewBuild.cshtml index 3a0e41f..d94d485 100644 --- a/BuildFeed/Views/front/viewBuild.cshtml +++ b/BuildFeed/Views/front/viewBuild.cshtml @@ -1,4 +1,5 @@ -@model BuildFeed.Models.BuildModel +@using BuildFeed.Code +@model BuildFeed.Models.BuildModel @{ ViewBag.Title = Model.FullBuildString + " | BuildFeed"; @@ -150,7 +151,7 @@ source = Model.SourceType })" class="more-link">   - @string.Format(BuildFeed.Local.Front.MoreFromSource, DisplayHelpers.GetDisplayTextForEnum(Model.SourceType)) + @string.Format(BuildFeed.Local.Front.MoreFromSource, MvcExtensions.GetDisplayTextForEnum(Model.SourceType))
    diff --git a/BuildFeed/Views/front/viewGroup.cshtml b/BuildFeed/Views/front/viewGroup.cshtml index 9469759..1b49a0b 100644 --- a/BuildFeed/Views/front/viewGroup.cshtml +++ b/BuildFeed/Views/front/viewGroup.cshtml @@ -1,4 +1,5 @@ @model Tuple> +@using BuildFeed.Code @using Humanizer; @{ ViewBag.Title = $"{Model.Item1} | {BuildFeed.Local.Common.SiteName}"; diff --git a/BuildFeed/Views/front/viewLab.cshtml b/BuildFeed/Views/front/viewLab.cshtml index 44b647d..39ec465 100644 --- a/BuildFeed/Views/front/viewLab.cshtml +++ b/BuildFeed/Views/front/viewLab.cshtml @@ -1,4 +1,5 @@ @model IEnumerable +@using BuildFeed.Code @using Humanizer; @{ ViewBag.Title = string.Format("{0}{1} | {2}", string.Format(BuildFeed.Local.Front.BuildsFrom, ViewBag.ItemId), ViewBag.PageNumber == 1 ? "" : string.Format(BuildFeed.Local.Common.PageTitleSegment, ViewBag.PageNumber), BuildFeed.Local.Common.SiteName); diff --git a/BuildFeed/Views/front/viewSource.cshtml b/BuildFeed/Views/front/viewSource.cshtml index 207087f..089475c 100644 --- a/BuildFeed/Views/front/viewSource.cshtml +++ b/BuildFeed/Views/front/viewSource.cshtml @@ -1,4 +1,5 @@ @model IEnumerable +@using BuildFeed.Code @using Humanizer; @{ ViewBag.Title = string.Format("{0}{1} | {2}", ViewBag.ItemId, ViewBag.PageNumber == 1 ? "" : string.Format(BuildFeed.Local.Common.PageTitleSegment, ViewBag.PageNumber), @BuildFeed.Local.Common.SiteName); diff --git a/BuildFeed/Views/front/viewVersion.cshtml b/BuildFeed/Views/front/viewVersion.cshtml index a940bf4..8c5d8c0 100644 --- a/BuildFeed/Views/front/viewVersion.cshtml +++ b/BuildFeed/Views/front/viewVersion.cshtml @@ -1,4 +1,5 @@ @model IEnumerable +@using BuildFeed.Code @using Humanizer; @{ ViewBag.Title = string.Format("{0} {1}{2} | {3}", BuildFeed.Local.Common.ProductName, ViewBag.ItemId, ViewBag.PageNumber == 1 ? "" : string.Format(BuildFeed.Local.Common.PageTitleSegment, ViewBag.PageNumber), BuildFeed.Local.Common.SiteName); diff --git a/BuildFeed/Views/front/viewYear.cshtml b/BuildFeed/Views/front/viewYear.cshtml index 37d1eed..811fc10 100644 --- a/BuildFeed/Views/front/viewYear.cshtml +++ b/BuildFeed/Views/front/viewYear.cshtml @@ -1,4 +1,5 @@ -@using BuildFeed.Local +@using BuildFeed.Code +@using BuildFeed.Local @using BuildFeed.Models @using Humanizer @model IEnumerable diff --git a/BuildFeed/Views/shared/DisplayTemplates/Enumeration.cshtml b/BuildFeed/Views/shared/DisplayTemplates/Enumeration.cshtml index e6cf9d2..565a627 100644 --- a/BuildFeed/Views/shared/DisplayTemplates/Enumeration.cshtml +++ b/BuildFeed/Views/shared/DisplayTemplates/Enumeration.cshtml @@ -1,5 +1,6 @@ @using System.ComponentModel.DataAnnotations +@using BuildFeed.Code @model Enum -@DisplayHelpers.GetDisplayTextForEnum(ViewData.Model) \ No newline at end of file +@MvcExtensions.GetDisplayTextForEnum(ViewData.Model) \ No newline at end of file diff --git a/BuildFeed/Views/shared/_default.cshtml b/BuildFeed/Views/shared/_default.cshtml index 7dabd87..d47019e 100644 --- a/BuildFeed/Views/shared/_default.cshtml +++ b/BuildFeed/Views/shared/_default.cshtml @@ -1,4 +1,7 @@ -@using System.Globalization; +@using System.Globalization +@using BuildFeed.Code.Options +@using BuildFeed.Controllers +@using BuildFeed.Local @{ bool isRtl = CultureInfo.CurrentUICulture.TextInfo.IsRightToLeft; } @@ -6,155 +9,140 @@ - + - - + + - + - + + @if (isRtl) { } @ViewBag.Title @RenderSection("head", false) - - + + -
    -
    -
    - @RenderBody() -
    -
    -
    - +
  • + + + + + -