public static Element[] CreateDateTimeField() { var label = new HTMLLabelElement { HtmlFor = "dateTimeInput", InnerHTML = "Server Date and Time:" }; var div = new HTMLDivElement { ClassName = "input-group" }; var spanPrefix = new HTMLSpanElement { ClassName = "input-group-addon glyphicon glyphicon-time" }; var spanSuffix = new HTMLSpanElement { ClassName = "input-group-btn" }; var button = new HTMLButtonElement { Type = ButtonType.Button, ClassName = "btn btn-primary", InnerHTML = "<span class=\"glyphicon glyphicon-refresh\"></span>", OnClick = Html5App.UpdateButton_Click }; var input = new HTMLInputElement { Id = "dateTimeInput", Type = InputType.Text, ClassName = "form-control", Placeholder = "Click update...", ReadOnly = true, Name = "datetime" }; spanSuffix.AppendChild(button); div.AppendChild(spanPrefix); div.AppendChild(input); div.AppendChild(spanSuffix); return(new Element[] { label, div }); }
//TODO refactor this monster private static Tuple <HTMLElement, DataGridColumnControllerResult <InternalT> > Create <InternalT, OperT, ViewT>( Func <InternalT, OperT> toOper, ITransformationMediator listener, FilterDef <OperT>[] availableFilters, IEnumerable <AggregatorDef <OperT> > rawAvailableAggregators, IEnumerable <GrouperDef <OperT> > rawAvailableGroupers, Func <IReadWriteValue <OperT>, IReadWriteValueView <HTMLElement, ViewT> > paramEditor, OperT initialFilterValue, OperT invalidFilterValue, IComparer <OperT> sortingImpl) { var availableAggregators = rawAvailableAggregators.ToList(); var availableGroupers = rawAvailableGroupers.ToList(); AssureUnique(availableFilters, x => x.Label); AssureUnique(availableAggregators, x => x.Label); AssureUnique(availableGroupers, x => x.Label); LocalValue <AggregatorDef <OperT> > aggregateFunc = null; LocalValue <GrouperDef <OperT> > groupingFunc = null; LocalValue <GroupOrAggregate?> groupOrAggregateChoice = null; FilterDef <OperT> currentFilterImplOrNull = null; var filterLabelToImpl = new Dictionary <string, FilterDef <OperT> >(); availableFilters.ForEach(x => filterLabelToImpl.Add(x.Label, x)); AggregatorDef <OperT> currentAggrImplOrNull = null; var aggregLabelToImpl = new Dictionary <string, AggregatorDef <OperT> >(); availableAggregators.ForEach(x => aggregLabelToImpl.Add(x.Label, x)); GrouperDef <OperT> currentGrouperImplOrNull = null; var grouperLabelToImpl = new Dictionary <string, GrouperDef <OperT> >(); availableGroupers.ForEach(x => grouperLabelToImpl.Add(x.Label, x)); var filterParam = new LocalValue <OperT>(initialFilterValue, invalidFilterValue); HTMLElement controllerElem = new HTMLSpanElement { ClassName = Magics.CssClassFilterMainContainer }; var actionContainer = new HTMLSpanElement { ClassName = Magics.CssClassFilterActionContainer }; controllerElem.AppendChild(actionContainer); var groupOrAggregateChoiceView = new RadioBasedSingleChoice(); Element GetLabelTh() { var filterTh = controllerElem.ParentElement; var filterTr = filterTh.ParentElement; var thead = filterTr.ParentElement; var iCol = filterTr.IndexOfChild(filterTh); var labelTr = thead.GetChildAtOrNull(0); var labelTh = labelTr.GetChildAtOrNull(iCol); return(labelTh); } void MarkAsGrouped(bool activated) { Logger.Debug(typeof(DataGridColumnController), "markAsGrouped({0})", activated); controllerElem.ParentElement.AddOrRemoveClass(activated, Magics.CssClassActive); GetLabelTh().AddOrRemoveClass(activated, Magics.CssClassWithGrouping); controllerElem.ParentElement.AddOrRemoveClass(activated, Magics.CssClassWithGrouping); } void MarkAsAggregated(bool activated) { Logger.Debug(typeof(DataGridColumnController), "markAsAggregated({0})", activated); controllerElem.ParentElement.AddOrRemoveClass(activated, Magics.CssClassActive); GetLabelTh().AddOrRemoveClass(activated, Magics.CssClassWithAggregation); controllerElem.ParentElement.AddOrRemoveClass(activated, Magics.CssClassWithAggregation); } void MarkAsFiltered(bool activated) { Logger.Debug(typeof(DataGridColumnController), "markAsFiltered({0})", activated); controllerElem.ParentElement.AddOrRemoveClass(activated, Magics.CssClassActive); GetLabelTh().AddOrRemoveClass(activated, Magics.CssClassWithFilter); controllerElem.ParentElement.AddOrRemoveClass(activated, Magics.CssClassWithFilter); } var removeFilter = new HTMLAnchorElement { Target = "#", Title = I18n.Translate("Remove filter"), Text = FontAwesomeSolid.IconFilter }; removeFilter.AddClasses(Magics.CssClassFilterRemove, IconFontType.FontAwesomeSolid.ToCssClassName()); actionContainer.AppendChild(removeFilter); var removeFilterActionView = new InputTypeButtonActionView(removeFilter); LocalActionBuilder.Build(removeFilterActionView, () => { currentFilterImplOrNull = null; MarkAsFiltered(false); listener.UserFilterChangedHandler(ChangeOrRemove.Removed); }); var removeGrouping = new HTMLAnchorElement { Target = "#", Title = I18n.Translate("Remove grouping"), Text = FontAwesomeSolid.IconListUl }; removeGrouping.AddClasses(Magics.CssClassGroupingRemove, IconFontType.FontAwesomeSolid.ToCssClassName()); actionContainer.AppendChild(removeGrouping); var removeGroupingActionView = new InputTypeButtonActionView(removeGrouping); LocalActionBuilder.Build(removeGroupingActionView, async() => { currentGrouperImplOrNull = null; MarkAsGrouped(false); await groupOrAggregateChoice.DoChange(null, false, null, false); listener.UserGroupingChangedHandler(ChangeOrRemove.Removed); }); var removeAggregation = new HTMLAnchorElement { ClassName = Magics.CssClassAggregationRemove, Target = "#", Title = I18n.Translate("Remove aggregation"), Text = "Σ" }; actionContainer.AppendChild(removeAggregation); var removeAggregationActionView = new InputTypeButtonActionView(removeAggregation); LocalActionBuilder.Build(removeAggregationActionView, async() => { currentAggrImplOrNull = null; await groupOrAggregateChoice.DoChange(null, false, null, false); MarkAsAggregated(false); listener.UserAggregationChangedHandler(ChangeOrRemove.Removed); }); Action <string> groupingChangedHandler = async labelOrNull => { Logger.Debug(typeof(DataGridColumnController), "Setting grouping programmatically to {0}", labelOrNull); if (labelOrNull == null) { currentGrouperImplOrNull = null; MarkAsGrouped(false); await groupOrAggregateChoice.DoChange(null, false, null, false); return; } GrouperDef <OperT> grouper; if (!grouperLabelToImpl.TryGetValue(labelOrNull, out grouper)) { Logger.Debug(typeof(DataGridColumnController), "No such grouping func when looking by label"); return; } await groupingFunc.DoChange(grouper, false, null, false); currentGrouperImplOrNull = grouper; MarkAsGrouped(true); }; Action <string> aggregationChangedHandler = async labelOrNull => { Logger.Debug(typeof(DataGridColumnController), "Setting aggregation programmatically to {0}", labelOrNull); if (labelOrNull == null) { currentAggrImplOrNull = null; MarkAsAggregated(false); await groupOrAggregateChoice.DoChange(null, false, null, false); listener.UserAggregationChangedHandler(ChangeOrRemove.Removed); return; } if (!aggregLabelToImpl.TryGetValue(labelOrNull, out var aggr)) { Logger.Debug(typeof(DataGridColumnController), "No such aggregation func when looking by label"); return; } await aggregateFunc.DoChange(aggr, false, null, false); currentAggrImplOrNull = aggr; MarkAsAggregated(true); }; listener.InitUserSide(groupingChangedHandler, aggregationChangedHandler); var filterOper = new LocalValue <FilterDef <OperT> >(availableFilters.FirstOrDefault()); var filterOperView = new DropDownSelectBox("") { PermittedValues = filterLabelToImpl.Select(x => Tuple.Create(x.Key, x.Key)) }; filterOperView.BindReadWriteAndInitialize(filterOper, x => x != null ? Tuple.Create(x.Label, x.Label) : Tuple.Create("", ""), x => !string.IsNullOrEmpty(x.Item1) ? filterLabelToImpl[x.Item1] : null); controllerElem.AppendChild(filterOperView.Widget); var val = paramEditor(filterParam); controllerElem.AppendChild(val.Widget); filterParam.Changed += (_, __, newValue, ___, isUserChange) => { if (!isUserChange) { return; } currentFilterImplOrNull = filterOper.Value; MarkAsFiltered(true); listener.UserFilterChangedHandler(ChangeOrRemove.Changed); }; filterOper.Changed += (_, __, newValue, ___, isUserChange) => { if (!isUserChange) { return; } currentFilterImplOrNull = newValue; MarkAsFiltered(true); listener.UserFilterChangedHandler(ChangeOrRemove.Changed); }; { groupOrAggregateChoice = new LocalValue <GroupOrAggregate?>(null); groupOrAggregateChoiceView.Widget.ClassList.Add(Magics.CssClassGroupOrAggregate); groupOrAggregateChoiceView.PermittedValues = EnumExtensions.GetEnumValues <GroupOrAggregate>().Select(x => Tuple.Create(((int)x).ToString(), x.GetUserFriendlyName())); groupOrAggregateChoiceView.BindReadWriteAndInitialize(groupOrAggregateChoice, x => !x.HasValue ? null : Tuple.Create(((int)x).ToString(), x.Value.GetUserFriendlyName()), x => (x == null || string.IsNullOrEmpty(x.Item1)) ? null : (GroupOrAggregate?)Convert.ToInt32(x.Item1)); groupingFunc = new LocalValue <GrouperDef <OperT> >(availableGroupers.FirstOrDefault()); var groupingFuncView = new DropDownSelectBox(I18n.Translate("group by:")); groupingFuncView.Widget.ClassList.Add(Magics.CssClassGroupingFunc); groupingFuncView.PermittedValues = grouperLabelToImpl.Select(x => Tuple.Create(x.Key, x.Key)); groupingFuncView.BindReadWriteAndInitialize(groupingFunc, x => x != null ? Tuple.Create(x.Label, x.Label) : Tuple.Create("", ""), x => !string.IsNullOrEmpty(x.Item1) ? grouperLabelToImpl[x.Item1] : null); aggregateFunc = new LocalValue <AggregatorDef <OperT> >(availableAggregators.FirstOrDefault()); var aggregateFuncView = new DropDownSelectBox(I18n.Translate("aggregate by:")); aggregateFuncView.Widget.ClassList.Add(Magics.CssClassAggregateFunc); aggregateFuncView.PermittedValues = aggregLabelToImpl.Select(x => Tuple.Create(x.Key, x.Key)); aggregateFuncView.BindReadWriteAndInitialize(aggregateFunc, x => x != null ? Tuple.Create(x.Label, x.Label) : Tuple.Create("", ""), x => !string.IsNullOrEmpty(x.Item1) ? aggregLabelToImpl[x.Item1] : null); groupingFunc.Changed += (_, __, newValue, errors, isUserChange) => { if (!isUserChange) { return; } currentGrouperImplOrNull = newValue; MarkAsGrouped(newValue != null); listener.UserGroupingChangedHandler(newValue != null ? ChangeOrRemove.Changed : ChangeOrRemove.Removed); }; aggregateFunc.Changed += (_, __, newValue, errors, isUserChange) => { if (!isUserChange) { return; } currentAggrImplOrNull = newValue; MarkAsAggregated(newValue != null); listener.UserAggregationChangedHandler(newValue != null ? ChangeOrRemove.Changed : ChangeOrRemove.Removed); }; groupOrAggregateChoice.Changed += (_, __, newValue, ___, isUserChange) => { Logger.Debug(typeof(DataGridColumnController), "groupOrAggregateChoice changed to {0} by {1}", newValue, isUserChange); //if (!isUserChange) { // return; //} if (!newValue.HasValue) { return; } switch (newValue.Value) { case GroupOrAggregate.Aggregate: currentAggrImplOrNull = aggregateFunc.Value; MarkAsAggregated(true); listener.UserAggregationChangedHandler(ChangeOrRemove.Changed); break; case GroupOrAggregate.Group: currentGrouperImplOrNull = groupingFunc.Value; MarkAsGrouped(true); listener.UserGroupingChangedHandler(ChangeOrRemove.Changed); break; default: throw new Exception("unsupported GroupOrAggregate"); } }; controllerElem.AppendChild(groupOrAggregateChoiceView.Widget); controllerElem.AppendChild(groupingFuncView.Widget); controllerElem.AppendChild(aggregateFuncView.Widget); } DocumentUtil.AddMouseClickListener(controllerElem, ev => { if (!ev.HasHtmlTarget()) { return; } //find out if clicked item is a descendant of th if (ev.HtmlTarget().IsDescendantOf(controllerElem.ParentElement)) { controllerElem.ParentElement.ClassList.Add(Magics.CssClassActive); return; } controllerElem.ParentElement?.ClassList.Remove(Magics.CssClassActive); }); return(Tuple.Create(controllerElem, new DataGridColumnControllerResult <InternalT> { FilterImpl = x => currentFilterImplOrNull == null || currentFilterImplOrNull.FilterFunc(filterParam.Value, toOper(x)), AggregationImpl = x => currentAggrImplOrNull?.AggregatorFunc(x.Select(toOper)), GroupingImpl = x => currentGrouperImplOrNull?.GroupingFunc(x.Select(toOper)), SortingImpl = new CompareImpl <InternalT>((x, y) => sortingImpl.Compare(toOper(x), toOper(y))), IsGroupingActive = () => currentGrouperImplOrNull != null })); }