public static object CreateJsFromXElement <TElement, TAttribute, TObject>(IElementProvider <TElement, TAttribute, TObject> elementProvider, TElement xelement) { var index = new Dictionary <string, object>(); index["name"] = elementProvider.LocalName(xelement); if (elementProvider.Namespace(xelement) != null) { index["ns"] = elementProvider.Namespace(xelement); } var attrs = elementProvider.Attributes(xelement).Select(attr => new { name = elementProvider.LocalName(attr), value = elementProvider.Value(attr) }).ToArray(); if (attrs.Any()) { index["a"] = attrs; } var elements = elementProvider.Elements(xelement).Select(child => CreateJsFromXElement(elementProvider, child)).Where(child => child != null).ToArray(); if (elements.Any()) { index["e"] = elements; } var texts = elementProvider.Texts(xelement).ToArray(); if (texts.Any()) { index["t"] = new { value = texts.JoinToString(null) } } ; var raws = elementProvider.Raws(xelement).ToArray(); if (raws.Any()) { index["h"] = raws.JoinToString(null); } return(index); } }
public static IEnumerable <object> JsSync <TElement, TAttribute, TObject>(IElementProvider <TElement, TAttribute, TObject> elementProvider, TElement oldBody, TElement body, params object[] path) { if (oldBody == null) { oldBody = elementProvider.Element("body"); yield return(new { path, cmd = "clear-all" }); } var oldElements = elementProvider.Elements(oldBody).ToArray(); var newElements = elementProvider.Elements(body).ToArray(); var lastText = elementProvider.Texts(oldBody).JoinToString(null); var newText = elementProvider.Texts(body).JoinToString(null); var lastHtml = elementProvider.Raws(oldBody).JoinToString(null); var newHtml = elementProvider.Raws(body).JoinToString(null); if (oldElements.Length > 0 != newElements.Length > 0 && (lastText != "") != (newText != "") || lastHtml != "" && newHtml == "") { yield return(new { path, cmd = "clear" }); oldElements = Array <TElement> .Empty; lastText = ""; lastHtml = ""; } var left_i = 0; for (var i = 0; i < Math.Max(oldElements.Length, newElements.Length); ++i) { var oldChild = oldElements.ElementAtOrDefault(i); var newChild = newElements.ElementAtOrDefault(i); if (newChild == null) { yield return new { path = path.Concat(new[] { new { kind = "element", index = left_i } }).ToArray(), cmd = "remove" } } ; else if (oldChild == null || elementProvider.LocalName(oldChild) != elementProvider.LocalName(newChild) || elementProvider.Attribute_Get(oldChild, "data-id") != elementProvider.Attribute_Get(newChild, "data-id")) { if (oldChild != null) { yield return new { path = path.Concat(new[] { new { kind = "element", index = left_i } }).ToArray(), cmd = "remove" } } ; if (i == 0) { yield return new { path, cmd = "insert", value = CreateJsFromXElement(elementProvider, newChild) } } ; else { yield return new { path = path.Concat(new[] { new { kind = "element", index = i - 1 } }).ToArray(), cmd = "after", value = CreateJsFromXElement(elementProvider, newChild) } }; left_i++; } else { foreach (var res in JsSync(elementProvider, oldChild, newChild, path.Concat(new[] { new { kind = "element", index = i } }).ToArray())) { yield return(res); } left_i++; } } var attributes = elementProvider.Attributes(body).ToArray(); var attrs = elementProvider.Attributes(oldBody) .OuterJoin(attributes, lastAtr => elementProvider.LocalName(lastAtr), newAtr => elementProvider.LocalName(newAtr), (lastAttr, newAttr) => new { lastAttr, newAttr }) .Where(pair => elementProvider.Value(pair.lastAttr) != elementProvider.Value(pair.newAttr)) .Select(pair => { var attrName = pair.lastAttr._f(_ => elementProvider.LocalName(_)) ?? pair.newAttr._f(_ => elementProvider.LocalName(_)); return(new { name = attrName, value = elementProvider.Value(pair.newAttr) }); } ) .ToArray(); var t = newText != lastText ? new { value = newText } : null; var h = newHtml != lastHtml ? newHtml : null; if (attrs.Any() || t != null || h != null) { yield return(new { path, cmd = "set", value = new { a = attrs, t, h } }); } if (true) { var jsUpdate = attributes.FirstOrDefault(_attr => elementProvider.LocalName(_attr) == "js-update"); if (jsUpdate != null) { yield return new { path, cmd = "js-update", value = elementProvider.Value(jsUpdate) } } ; } }