public override Task <string> BuildOutputAsync() { var b = new HtmlCodeBuilder(); b.Line("@using IntelliTect.Coalesce.Knockout.Helpers"); b.Line(); BuildOutput(b); return(Task.FromResult(b.ToString())); }
public static HtmlString ModalFor(MethodViewModel method, string elementId = null, bool includeWithBinding = true) { if (elementId == null) { elementId = $"method-{method.Name}"; } var b = new HtmlCodeBuilder(); b.Line($"<!-- Modal for method: {method.Name} -->"); var withBinding = includeWithBinding ? $"with: {method.JsVariable}" : null; using (b .TagBlock("div", new { @class = "modal fade", id = elementId, tabindex = -1, role = "dialog", data_bind = withBinding }) .TagBlock("div", "modal-dialog") .TagBlock("div", "modal-content") ) { using (b.TagBlock("div", "modal-header")) { b.Line("<button type='button' class='close' data-dismiss='modal' aria-label='Close'><span aria-hidden='true'>×</span></button>"); b.Line($"<h4 class='modal-title'>{method.Name.ToProperCase()}</h4>"); } using (b.TagBlock("div", "modal-body form-horizontal", "with: args")) { foreach (ParameterViewModel arg in method.ClientParameters) { using (b.TagBlock("div", "form-group")) { b.Line($"<label class='col-md-4 control-label'>{arg.Name.ToProperCase()}</label>"); using (b.TagBlock("div", "col-md-8")) { b.Line($"<input type='text' class='form-control' data-bind='value: {arg.JsVariable}'>"); } } } } using (b.TagBlock("div", "modal-footer")) { b.Line("<button type='button' class='btn btn-default' data-dismiss='modal'>Cancel</button>"); b.Line(@"<button type='button' class='btn btn-primary btn-ok'"); b.Indented(@"data-bind=""click: invokeWithArgs.bind(this, args, function(){jQuery($element).closest('.modal').modal('hide')}, null)"">"); b.Indented("OK"); b.Line("</button>"); } } return(new HtmlString(b.ToString())); }
protected void WriteListViewObjectButtons(HtmlCodeBuilder b) { // Dropdown for invoking instance methods. WriteInstanceMethodsDropdownButton(b); if (Model.SecurityInfo.IsEditAllowed()) { using (b.TagBlock("a", "btn btn-sm btn-default", "attr: { href: editUrl }")) { b.Line("<i class=\"fa fa-pencil\"></i>"); } } if (Model.SecurityInfo.IsDeleteAllowed()) { using (b.TagBlock("button", "btn btn-sm btn-danger", "click: deleteItemWithConfirmation")) { b.Line("<i class=\"fa fa-remove\"></i>"); } } }
protected void WriteInstanceMethodsDropdownButton(HtmlCodeBuilder b) { if (Model.ClientMethods.Any(f => !f.IsHidden(HiddenAttribute.Areas.List) && !f.IsStatic)) { b.Line("<!-- Action buttons -->"); using (b.TagBlock("div", new { @class = "btn-group", role = "group" })) { b.Line("<button type=\"button\" class=\"btn btn-sm btn-default dropdown-toggle\" data-toggle=\"dropdown\" aria-haspopup=\"true\" aria-expanded=\"false\">"); b.Indented("Actions <span class=\"caret\"></span>"); b.Line("</button>"); using (b.TagBlock("ul", "dropdown-menu")) { foreach (var method in Model.ClientMethods.Where(f => !f.IsHidden(HiddenAttribute.Areas.List) && !f.IsStatic)) { b.Line($"<li>{Display.MethodHelper(method)}</li>"); } } } } }
public override void BuildOutput(HtmlCodeBuilder b) { b.Line("@{ ViewBag.Fluid = true; }"); b.Line(); using (b.TagBlock("style")) { b.Lines( "td div a {", " display: block;", "}", "th.sortable-header {", " cursor: pointer;", "}", "th.sortable-header:hover {", " background-color: #e6e6e6", "}", ".table-view-header {", " padding: 10px 15px;", "}" ); } using (b.TagBlock("div", $"table-view obj-{Model.ClientTypeName.ToCamelCase()}")) { WriteAdminTableControls(b, "table", additionalButtons: () => { b.Line("@if (ViewBag.Editable)"); b.Line("{"); b.Indented($"<a href=\"~/{Model.ControllerName}/Table?@(ViewBag.Query)\" role=\"button\" class=\"btn btn-sm btn-default \"><i class=\"fa fa-lock\"></i> Make Read-only</a>"); b.Line("}"); if (Model.SecurityInfo.IsEditAllowed()) { b.Line("else"); b.Line("{"); b.Indented($"<a href=\"~/{Model.ControllerName}/[email protected]\" role=\"button\" class=\"btn btn-sm btn-default \"><i class=\"fa fa-pencil\"></i> Make Editable</a>"); b.Line("}"); } }); b.Line("<hr />"); using (b .TagBlock("div", "card table-view-body") .TagBlock("div", "card-body") .TagBlock("table", "table @(ViewBag.Editable ? \"editable\" : \"\" )") ) { using (b.TagBlock("thead").TagBlock("tr")) { // Data column headers foreach (var prop in Model.ClientProperties.Where(f => !f.IsHidden(HiddenAttribute.Areas.List)).OrderBy(f => f.EditorOrder)) { if (!prop.Type.IsCollection) { using (b.TagBlock("th", "sortable-header", dataBind: $"click: function(){{orderByToggle('{prop.Name}')}}")) { b.Line(prop.DisplayName); b.Line($"<i class=\"pull-right fa\" data-bind=\"css:{{'fa-caret-up': orderBy() == '{prop.Name}', 'fa-caret-down': orderByDescending() == '{prop.Name}'}}\"></i>"); } } else { b.Line($"<th>{prop.DisplayName}</th>"); } } // Buttons column header b.Line("<th style=\"width: 1%\">"); b.Line("</th>"); } using (b .TagBlock("tbody", dataBind: "foreach: items") .TagBlock("tr", dataBind: $"css: {{'btn-warning': errorMessage()}}, attr: {{id: {Model.PrimaryKey.Name.ToCamelCase()}}}") ) { var properties = Model.ClientProperties .Where(f => !f.IsHidden(HiddenAttribute.Areas.List)) .OrderBy(f => f.EditorOrder); b.Line("@if (@ViewBag.Editable)"); b.Line("{"); foreach (var prop in properties) { // Edit mode -- display property inputs b.Indented($"<td class=\"prop-{prop.JsonName}\">{Display.PropertyHelper(prop, !prop.IsReadOnly, null, true)}</td>"); } b.Line("}"); b.Line("else"); b.Line("{"); foreach (var prop in properties) { // Read-only mode -- display properties only b.Indented($"<td class=\"prop-{prop.JsonName}\">{Display.PropertyHelper(prop, false, null, true)}</td>"); } b.Line("}"); // Edit/Delete buttons, and instance method dropdown. using (b.TagBlock("td")) { b.Line("<!-- Editor buttons -->"); using (b.TagBlock("div", new { @class = "btn-group pull-right", role = "group", style = "display: inline-flex" })) { WriteListViewObjectButtons(b); } b.Line("<div class=\"form-control-static\" data-bind=\"text: errorMessage\"></div>"); } } } } b.Line(); WriteMethodsCard(b, Model.ClientMethods.Where(f => f.IsStatic)); b.Line(); foreach (var method in Model.ClientMethods.Where(f => f.IsStatic && f.ClientParameters.Any())) { b.Line(IntelliTect.Coalesce.Knockout.Helpers.Knockout.ModalFor(method).ToString()); } WriteListViewScript(b); }
public override void BuildOutput(HtmlCodeBuilder b) { string viewModelsNamespace = "ViewModels"; if (!string.IsNullOrWhiteSpace(AreaName)) { viewModelsNamespace = AreaName + "." + viewModelsNamespace; } if (!string.IsNullOrWhiteSpace(ModulePrefix)) { viewModelsNamespace = ModulePrefix + "." + viewModelsNamespace; } using (b.TagBlock("div", "card")) { using (b.TagBlock("div", "card-heading")) { using (b.TagBlock("div", "btn-group pull-right")) { b.Line("<button onclick=\"window.history.back()\" class=\"btn btn-xs btn-default\"><i class=\"fa fa-arrow-left\"></i> Back</button>"); b.Line("<button data-bind=\"click:function() { load(); }\" class=\"btn btn-xs btn-default\"><i class=\"fa fa-refresh\"></i> Refresh</button>"); } b.Line($"<h1 class=\"card-title clearfix\" style=\"display:inline-block;\">{Model.DisplayName}</h1>"); b.Line("<span class=\"label label-info\" data-bind=\"fadeVisible: isLoading()\">Loading...</span>"); } using (b.TagBlock("div", "card-body").TagBlock("div", "form-horizontal")) { using (b.TagBlock("div", "form-group btn-warning", dataBind: "if: errorMessage(), visible: errorMessage()", style: "display: none")) { b.Line("<label class=\"col-md-4 control-label\">Error</label>"); b.Line("<div class=\"col-md-8\">"); b.Indented("<div class=\"form-control-static\" data-bind=\"text: errorMessage\"></div>"); b.Line("</div>"); } foreach (var prop in Model.ClientProperties.Where(f => !f.IsHidden(HiddenAttribute.Areas.Edit)).OrderBy(f => f.EditorOrder)) { using (b.TagBlock("div", "form-group")) { b.Line($"<label class=\"col-md-4 control-label\">{prop.DisplayName}</label>"); if (prop.IsPOCO && prop.PureTypeOnContext) { b.Line(Display.PropertyHelperWithSurroundingDiv(prop, !prop.IsReadOnly, AreaName, 7)); b.Line($"<div class=\"col-md-1\" data-bind=\"with: {prop.JsVariableForBinding()}\">"); b.Indented("<a data-bind=\"attr: {href: editUrl}\" class=\"btn btn-default pull-right\"><i class=\"fa fa-ellipsis-h \"></i></a>"); b.Line("</div>"); } else { b.Line(Display.PropertyHelperWithSurroundingDiv(prop, !prop.IsReadOnly, AreaName, 8)); } } } } } b.Line(); WriteMethodsCard(b, Model.ClientMethods.Where(f => !f.IsStatic)); b.Line(); foreach (var method in Model.ClientMethods.Where(f => !f.IsStatic && f.ClientParameters.Any())) { b.Line(IntelliTect.Coalesce.Knockout.Helpers.Knockout.ModalFor(method).ToString()); } b.Line(); b.Line("@section Scripts"); b.Line("{"); b.Line("<script>"); b.Line($" var model = new {viewModelsNamespace}.{Model.ViewModelClassName}();"); b.Line(" model.includes = \"Editor\";"); b.Line(" model.saveCallbacks.push(function(obj){"); b.Line(" // If there is a new id, set the one for this page"); b.Line(" if (!Coalesce.Utilities.GetUrlParameter('id')){"); b.Line(" if (model.myId) {"); b.Line(" var newUrl = Coalesce.Utilities.SetUrlParameter(window.location.href, \"id\", model.myId);"); b.Line(" window.history.replaceState(null, window.document.title, newUrl);"); b.Line(" }"); b.Line(" }"); b.Line(" });"); b.Line(" @if (ViewBag.Id != null)"); b.Line(" {"); b.Line(" @:model.load(\'@ViewBag.Id\');"); b.Line(" }"); b.Line(" @foreach (var kvp in ViewBag.ParentIds)"); b.Line(" {"); b.Line(" @:model.@(((string)(@kvp.Key)))(@kvp.Value);"); b.Line(" }"); b.Line(); b.Line(" window.onbeforeunload = function(){"); b.Line(" if (model.isDirty()) model.save();"); b.Line(" }"); b.Line(" model.coalesceConfig.autoSaveEnabled(false);"); b.Line(" model.loadChildren(function() {"); b.Line(" ko.applyBindings(model);"); b.Line(" model.coalesceConfig.autoSaveEnabled(true);"); b.Line(" });"); b.Line("</script>"); b.Line("}"); }
public override void BuildOutput(HtmlCodeBuilder b) { b.Line("@{ ViewBag.Fluid = true; }"); b.Line(); using (b.TagBlock("style")) { b.Lines( ".card-view-header {", " padding: 10px 15px;", "}" ); } b.Line(); using (b.TagBlock("div", $"card-view obj-{Model.ClientTypeName.ToCamelCase()}")) { WriteAdminTableControls(b, "card"); b.Line(); b.EmptyTag("hr"); b.Line(); using (b.TagBlock("div", @class: "flex-card-container card-view-body", dataBind: "foreach: items, visible: isLoaded", style: "display: none")) { var titleProp = Model.ListTextProperty; // The card for each object. using (b.TagBlock("div", "flex-card")) { if (titleProp != null) { using (b.TagBlock("div", "card-heading").TagBlock("h3", "card-title")) { b.Line($"<span data-bind=\"text: {titleProp.JsVariableForBinding()}\"></span>"); } } using (b.TagBlock("div", "card-body flex")) { // List of all data properties on the object using (b.TagBlock("dl")) { var properties = Model.ClientProperties .Where(f => !f.IsHidden(HiddenAttribute.Areas.List)) .OrderBy(f => f.EditorOrder) .ToList(); foreach (var prop in properties) { b.Line($"<dt>{prop.DisplayName}</dt>"); b.Line("<dd>"); b.Indented($"{Display.PropertyHelper(prop, false)}"); b.Line("</dd>"); } } // Edit/Delete buttons, and instance method dropdown. b.Line(); using (b.TagBlock("div", style: "margin-top: auto")) { b.Line("<!-- Editor buttons -->"); using (b.TagBlock("div", new { @class = "pull-right", role = "group" })) { WriteListViewObjectButtons(b); } b.Line("<span class=\"form-control-static\" data-bind=\"text: errorMessage\"></span>"); } } } } } b.Line(); WriteMethodsCard(b, Model.ClientMethods.Where(f => f.IsStatic)); b.Line(); foreach (var method in Model.ClientMethods.Where(f => f.IsStatic && f.ClientParameters.Any())) { b.Line(IntelliTect.Coalesce.Knockout.Helpers.Knockout.ModalFor(method).ToString()); } WriteListViewScript(b); }
protected void WriteAdminTableControls(HtmlCodeBuilder b, string classPrefix, Action additionalButtons = null) { using (b.TagBlock("div", $"{classPrefix}-view-header")) { using (b .TagBlock("div", "clearfix") .TagBlock("h1", style: "display: inline-block") ) { b.Line($"{Model.DisplayName} List"); b.Line($"<span style=\"font-size: .5em; padding-left: 20px;\"><a href=\"~/{Model.ControllerName}/Docs\">API Docs</a></span>"); } using (b.TagBlock("div", "clearfix")) { using (b.TagBlock("div", style: "display: inline-block; font-size: 1.1em; margin-right: 10px;")) { b.Line("<i class=\"fa fa-arrow-circle-left\" data-bind=\"enabled: previousPageEnabled() && !isLoading(), click: previousPage\"></i>"); b.Line("Page"); b.Line("<input data-bind=\"value: page\" style=\"width: 35px\">"); b.Line("of"); b.Line("<span data-bind=\"text: pageCount\"></span>"); b.Line("<i class=\"fa fa-arrow-circle-right\" data-bind=\"enabled: nextPageEnabled() && !isLoading(), click: nextPage\"></i>"); } // Page size dropdown using (b.TagBlock("select", "form-control", dataBind: "value: pageSize", style: "width: 100px; display: inline-block;")) { foreach (var n in new[] { 1, 5, 10, 50, 100, 500, 1000 }) { b.Line($"<option value=\"{n}\">{n}</option>"); } } b.Line("<input class=\"form-control pull-right\" style=\"width: 250px; margin-left: 20px\" data-bind=\"textInput: search\" placeholder=\"Search\" />"); // Create / Refresh / CSV buttons using (b.TagBlock("div", "btn-group pull-right")) { if (Model.SecurityInfo.IsCreateAllowed()) { b.Line($"<a href=\"~/{Model.ControllerName}/CreateEdit?@(ViewBag.Query)\" role=\"button\" class=\"btn btn-sm btn-default \"><i class=\"fa fa-plus\"></i> Create</a>"); } b.Line("<button data-bind=\"click:load\" class=\"btn btn-sm btn-default \"><i class=\"fa fa-refresh\"></i> Refresh</button>"); additionalButtons?.Invoke(); b.Line("<a href=\"#\" role=\"button\" class=\"btn btn-sm btn-default \" data-bind=\"attr:{href: downloadAllCsvUrl}\"><i class=\"fa fa-download\"></i> CSV</a>"); if (Model.SecurityInfo.IsCreateAllowed() && Model.SecurityInfo.IsEditAllowed()) { b.Line("<button role=\"button\" class=\"btn btn-sm btn-default \" data-bind=\"click: csvUploadUi\"><i class=\"fa fa-upload\"></i> CSV</button>"); } } } } }
protected void WriteListViewScript(HtmlCodeBuilder b) { b.Line("@section Scripts"); b.Line("{"); using (b.Indented()) { using (b.TagBlock("script")) { b.Line($"@if (!ViewBag.Editable)"); b.Line($"{{"); b.Line($" @:Coalesce.GlobalConfiguration.viewModel.setupValidationAutomatically(false);"); b.Line($"}}"); b.Line($"var {Model.ListViewModelObjectName} = new ListViewModels.{Model.ListViewModelClassName}();"); b.Line(); b.Line($"// Set up parent info based on the URL."); b.Line($"@if (ViewBag.Query != null)"); b.Line($"{{"); b.Line($" @:{Model.ListViewModelObjectName}.queryString = \"@(ViewBag.Query)\";"); b.Line($"}}"); b.Line(); b.Line($"// Save and restore values from the URL:"); b.Line($"var urlVariables = ['page', 'pageSize', 'search', 'orderBy', 'orderByDescending'];"); b.Line($"$.each(urlVariables, function(){{"); b.Line($" var param = Coalesce.Utilities.GetUrlParameter(this);"); b.Line($" if (param) {{{Model.ListViewModelObjectName}[this](param);}}"); b.Line($"}})"); b.Line($"{Model.ListViewModelObjectName}.isLoading.subscribe(function(){{"); b.Line($" var newUrl = window.location.href;"); b.Line(); b.Line($" $.each(urlVariables, function(){{"); b.Line($" var param = {Model.ListViewModelObjectName}[this]();"); b.Line($" newUrl = Coalesce.Utilities.SetUrlParameter(newUrl, this, param);"); b.Line($" }})"); b.Line($" history.replaceState(null, document.title, newUrl);"); b.Line($"}});"); b.Line(); b.Line($"{Model.ListViewModelObjectName}.isSavingAutomatically = false;"); b.Line($"ko.applyBindings({Model.ListViewModelObjectName});"); b.Line($"{Model.ListViewModelObjectName}.isSavingAutomatically = true;"); b.Line(); b.Line($"{Model.ListViewModelObjectName}.includes = \"{Model.ListViewModelClassName}Gen\";"); b.Line($"{Model.ListViewModelObjectName}.load();"); } } b.Line("}"); }
protected void WriteMethodsCard(HtmlCodeBuilder b, IEnumerable <MethodViewModel> methods) { if (!methods.Any()) { return; } using (b.TagBlock("div", "card")) { using (b.TagBlock("div", "card-heading")) { b.Line("<h3 class=\"card-title\">Actions</h3>"); } using (b.TagBlock("div", "card-body").TagBlock("table", "table")) { using (b.TagBlock("thead").TagBlock("tr")) { b.Line("<th style=\"width: 20%;\">Action</th>"); b.Line("<th style=\"width: 50%;\">Result</th>"); b.Line("<th style=\"width: 20%;\">Successful</th>"); b.Line("<th style=\"width: 10%;\"></th>"); } using (b.TagBlock("tbody")) { foreach (MethodViewModel method in methods) { using (b.TagBlock("tr", dataBind: $"with: {method.JsVariable}")) { using (b.TagBlock("td")) { string clickBinding = method.ClientParameters.Any() ? $"click: function(){{ $('#method-{method.Name}').modal() }}" : $"click: function(){{ invoke() }}"; using (b.TagBlock("button", "btn btn-default btn-xs", dataBind: clickBinding)) { b.Line(method.DisplayName); } } using (b.TagBlock("td")) { if (method.ResultType.IsCollection) { b.Line("<ul data-bind=\"foreach: result\">"); b.Indented("<li data-bind=\"text: $data\"></li>"); b.Line("</ul>"); } else if (method.ResultType.HasClassViewModel) { using (b.TagBlock("dl", "dl-horizontal", dataBind: "with: result")) { foreach (var prop in method.ResultType.ClassViewModel.ClientProperties.Where(f => !f.IsHidden(HiddenAttribute.Areas.Edit))) { b.Line($"<dt>{prop.DisplayName}</dt>"); b.Line($"<dd data-bind=\"text: {prop.JsVariableForBinding()}\"></dd>"); } } } else { b.Line("<span data-bind=\"text: result\"></span>"); } } using (b.TagBlock("td")) { b.Line("<span data-bind=\"text: wasSuccessful\"></span>"); b.Line("<span data-bind=\"text: message\"></span>"); } using (b.TagBlock("td")) { b.Line("<span class=\"label label-info\" data-bind=\"fadeVisible: isLoading\">Loading</span>"); } } } } } } }