/// <summary> /// Attaches event listeners to elements that possess them. /// </summary> void Attach() { var evt = attributes.Event; if (evt == null) { return; } if (handler.Value == null) { throw new DOMTargetEventException(Element, Events.Error); } if (observer.Value == null) { throw new DOMTargetEventException(Element, Events.Error); } observer.Value.Register( evt, InterfaceEventListener.Create(InvokeHandleEvent), GetCapture()); }
/// <summary> /// Dynamically generate repeat items, reusing existing instances if available. /// </summary> /// <returns></returns> public void Update() { // refresh binding if (Binding != null) { Binding.Recalculate(); } // configure listener for instance alterations if (Binding != null && Binding.Context != null) { if (listener == null) { var target = Binding.Context.Instance.Element.Parent.Interface <EventTarget>(); // find existing listener listener = InterfaceEventListener.GetListener(target, Events.Insert, true, Update) ?? InterfaceEventListener.GetListener(target, Events.Delete, true, Update); // register listener if (listener == null) { listener = InterfaceEventListener.Create(Update); target.Register(Events.Insert, listener, true); target.Register(Events.Delete, listener, true); } } } // store current index item var indexPrev = Index; var indexItem = Element .Elements() .FirstOrDefault(i => i.AnnotationOrCreate <RepeatItemState>().Index == Index); // build new list of properly ordered nodes var items = Binding != null?Binding.ModelItems.Select(i => i.Xml).ToArray() : new XObject[0]; var nodes = Element.Elements().ToArray(); var sorts = new XElement[items.Length]; for (int index = 0; index < items.Length; index++) { // model item at current index var item = items[index]; // get existing item or create new var indx = Array.FindIndex(nodes, i => i.AnnotationOrCreate <RepeatItemState>().ModelObjectId == item.GetObjectId()); var node = indx >= 0 ? nodes[indx] : null; if (node == null) { node = new XElement( Constants.XForms_1_0 + "group", Template.GetNamespacePrefixAttributes(), Template.Nodes()); } // set node into output list sorts[index] = node; // configure item state var anno = node.AnnotationOrCreate <RepeatItemState>(); anno.ModelObjectId = item.GetObjectId(); anno.Index = index + 1; anno.Size = items.Length; } // new sequence is different from old sequence if (sorts.Length != nodes.Length || sorts.SequenceEqual(nodes) == false) { // replace all children Element.RemoveNodes(); Element.Add(sorts); // set of elements that were added var added = sorts .Except(nodes) .ToArray(); // model-construct-done sequence applied to new children foreach (var node in added) { foreach (var i in GetAllExtensions <IOnRefresh>(node)) { i.RefreshBinding(); } } // discard refresh events foreach (var node in added) { foreach (var i in GetAllExtensions <IOnRefresh>(node)) { i.DiscardEvents(); } } // final refresh foreach (var node in added) { foreach (var i in GetAllExtensions <IOnRefresh>(node)) { i.Refresh(); } } } // restore or reset index var length = Element.Elements().Count(); if (indexItem != null && indexItem.Parent != null) { Index = indexItem.AnnotationOrCreate <RepeatItemState>().Index; } else if (indexPrev > 0) { Index = indexPrev <= length ? indexPrev : length; } else if (length > 0) { Index = 1; } else { Index = 0; } }