/// <summary> /// Write as an asynchronous operation. /// </summary> /// <param name="scope">The scope.</param> /// <param name="block">The block.</param> /// <param name="token">The cancellation token that can be used by other objects or threads to receive notice of cancellation.</param> /// <returns>A Task representing the asynchronous operation.</returns> /// <exception cref="System.NotSupportedException">'where' should be a string expression but instead found '{oWhere.GetType().Name}'</exception> public override async Task WriteAsync(ScriptScopeContext scope, PageBlockFragment block, CancellationToken token) { var htmlAttrs = await block.Argument.GetJsExpressionAndEvaluateAsync(scope) as Dictionary <string, object>; var hasEach = false; IEnumerable each = null; var binding = "it"; var hasExplicitBinding = false; JsToken where = null; if (htmlAttrs != null) { if (htmlAttrs.TryGetValue("if", out var oIf)) { if (DefaultScripts.isFalsy(oIf)) { return; } htmlAttrs.Remove("if"); } if (htmlAttrs.TryGetValue(nameof(where), out var oWhere)) { if (oWhere is not string whereExpr) { throw new NotSupportedException($"'where' should be a string expression but instead found '{oWhere.GetType().Name}'"); } where = whereExpr.GetCachedJsExpression(scope); htmlAttrs.Remove(nameof(where)); } if (htmlAttrs.TryGetValue(nameof(each), out var oEach)) { hasEach = true; htmlAttrs.Remove(nameof(each)); } each = oEach as IEnumerable; if (htmlAttrs.TryGetValue("it", out var oIt) && oIt is string it) { binding = it; hasExplicitBinding = true; htmlAttrs.Remove("it"); } if (htmlAttrs.TryGetValue("class", out var oClass)) { var cls = scope.Context.HtmlMethods.htmlClassList(oClass); if (string.IsNullOrEmpty(cls)) { htmlAttrs.Remove("class"); } else { htmlAttrs["class"] = cls; } } } var attrString = scope.Context.HtmlMethods.htmlAttrsList(htmlAttrs); if (HtmlScripts.VoidElements.Contains(Tag)) //e.g. img, input, br, etc { await scope.OutputStream.WriteAsync($"<{Tag}{attrString}>{Suffix}", token).ConfigAwait(); } else { if (hasEach) { var hasElements = each != null && each.GetEnumerator().MoveNext(); if (hasElements) { await scope.OutputStream.WriteAsync($"<{Tag}{attrString}>{Suffix}", token).ConfigAwait(); var index = 0; var whereIndex = 0; foreach (var element in each) { // Add all properties into scope if called without explicit in argument var scopeArgs = !hasExplicitBinding && CanExportScopeArgs(element) ? element.ToObjectDictionary() : new Dictionary <string, object>(); scopeArgs[binding] = element; scopeArgs[nameof(index)] = AssertWithinMaxQuota(whereIndex++); var itemScope = scope.ScopeWithParams(scopeArgs); if (where != null) { var result = await where.EvaluateToBoolAsync(itemScope); if (!result) { continue; } } itemScope.ScopedParams[nameof(index)] = AssertWithinMaxQuota(index++); await WriteBodyAsync(itemScope, block, token).ConfigAwait(); } await scope.OutputStream.WriteAsync($"</{Tag}>{Suffix}", token).ConfigAwait(); } else { await WriteElseAsync(scope, block.ElseBlocks, token).ConfigAwait(); } } else { await scope.OutputStream.WriteAsync($"<{Tag}{attrString}>{Suffix}", token).ConfigAwait(); await WriteBodyAsync(scope, block, token).ConfigAwait(); await scope.OutputStream.WriteAsync($"</{Tag}>{Suffix}", token).ConfigAwait(); } } }
public override bool Test(object lhs, object rhs) => !DefaultScripts.isFalsy(lhs) && !DefaultScripts.isFalsy(rhs);
public override object Evaluate(object target) => DefaultScripts.isFalsy(target);
public override object Evaluate(object lhs, object rhs) => DefaultScripts.isFalsy(lhs) ? rhs : lhs;