Create your own (basic) DataEditor action
When you need to create an action with a simple form and render results based on this input, the easiest way to accomplish this is to create a custom class which inherits from the abstract class Smartsite.Manager.Actions.DataEditor.
Notice however, that this is a different implementation than creating a (custom) DataEditor action. In that case, the action you've created will (first) open a library containing the records for a specific table. After selecting a record and clicking the Edit button, then a new tab is opened which contains a DataEditor like implementation.
DataEditor
When directly inheriting from the abstract class Smartsite.Manager.Actions.DataEditor, you're creating an action which does use some of the same building blocks as a (custom) DataEditor action. You (also) need to load/create a DataEditor xml and you need to load/create an Instance document.
As example, the C# source code of a simplified version of the Google Pagespeed action is shown below.
C# | Copy Code |
---|---|
using Smartsite.Base; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Xml.Linq; using Smartsite.XForms; namespace Smartsite.Manager.Actions { internal class GooglePageSpeed : DataEditor { protected override XDocument LoadDataEditor(MgrContext context) { string form = FormParser.LoadForm("Smartsite.Manager.Source.Actions.GooglePageSpeed.DataEditor.xml"); XDocument dataEditor = XDocument.Parse(form); return dataEditor; } protected override XDocument LoadInstance(MgrContext context) { object obj; string url = ""; if (context.Action.Parameters.TryGetValue("url", out obj) && obj != null) url = (string)obj; XDocument document = new XDocument(); XElement root = new XElement(XNamespaces.MetaDocument + "data", new XElement(XNamespaces.MetaDocument + "entry", new XElement(XNamespaces.MetaDocument + "url", url), new XElement(XNamespaces.MetaDocument + "filterthirdparty", false), new XElement(XNamespaces.MetaDocument + "screenshot", true), new XElement(XNamespaces.MetaDocument + "strategy", new XElement(XNamespaces.MetaDocument + "key", "desktop")) )); document.Add(root); return document; } public override ActionResult ButtonClicked(MgrContext context, XFormsSubmission submission, ref XDocument instance) { if (!submission.Id.Equals("save")) return null; XElement entry = instance.Root.Element(XNamespaces.MetaDocument + "entry"); string url = (string)entry.Element(XNamespaces.MetaDocument + "url"); url += "&screenshot=" + (string)entry.Element(XNamespaces.MetaDocument + "screenshot"); url += "&strategy=" + (string)entry.Element(XNamespaces.MetaDocument + "strategy"); url += "&filter_third_party_resources=" + (string)entry.Element(XNamespaces.MetaDocument + "filterthirdparty"); url += "&locale=" + UserWorkspace.Current.UserProfile.Culture; Dictionary<string, object> parameters = new Dictionary<string, object>(); parameters.Add("url", url); return ActionResult.StartSubAction(typeof(GooglePageSpeedResult), parameters); } } } |
The LoadDataEditor() function loads the DataEditor xml from an embedded resource, see example below.
XML | Copy Code |
---|---|
<dataeditor xmlns="http://smartsite.nl/namespaces/dataeditor/2.0" xmlns:xf="http://www.w3.org/2002/xforms" xmlns:ev="http://www.w3.org/2001/xml-events"> <layout title="GOOGLE_PAGESPEED"> <tabs> <tab title=""> <field name="url" caption="URL"> <control type="textbox"> <properties> <property name="maxlength">500</property> <property name="required">true</property> <property name="alert">{text:URL_REQUIRED}</property> </properties> </control> </field> <field name="filterthirdparty" caption="PAGESPEED_FILTER_THIRDPARTY"> <control type="checkbox"> <properties> </properties> </control> </field> <field name="screenshot" caption="PAGESPEED_INCLUDE_SCREENSHOT"> <control type="checkbox"> <properties> </properties> </control> </field> <field name="strategy" caption="PAGESPEED_STRATEGY"> <control type="radiobuttonlist"> <itemset ref="is_strategy" /> <properties> </properties> </control> </field> </tab> </tabs> <buttons> <button code="save" css="icon_sys22 icon-sys22-execute" caption="EXECUTE" replace="instance" relevant="false"></button> <button code="close"></button> </buttons> <modellogic xmlns:xf="http://www.w3.org/2002/xforms"> <xf:bind nodeset="cms:entry/cms:screenshot" type="xf:boolean" /> <xf:bind nodeset="cms:entry/cms:filterthirdparty" type="xf:boolean" /> </modellogic> </layout> <itemsets> <itemset id="is_strategy" key="key" value="name"> <item key="desktop" value="{text:DESKTOP}" /> <item key="mobile" value="{text:MOBILE}" /> </itemset> </itemsets> </dataeditor> |
This xml specifies the UI (the html input form).
The LoadInstance() function creates and returns the Instance xml. Since we're not editing an existing record for a specific table, we're able to construct this instance from scratch.
When the action is started, the following input form will be displayed:
The ButtonClicked() function is called when the Execute button is clicked (which in fact is the save button, but with a different caption).
This function creates an url, based on the user input, and starts a subaction of type GooglePageSpeedResult, passing this url as parameter.
GooglePageSpeedResult
For completeness' sake, the C# source code for the GooglePageSpeedResult class (a simplified version of it) is included below.
C# | Copy Code |
---|---|
using Smartsite.Base; using Smartsite.Data; using Smartsite.Manager.Resources; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Text; using System.Threading.Tasks; using System.Web.Configuration; namespace Smartsite.Manager.Actions { internal class GooglePageSpeedResult : BaseAction { public override ActionResult Execute(MgrContext context) { if (context.Request.Form["action"] == "close") return ActionResult.CloseAction(); string url = null; object obj; string apiKey = WebConfigurationManager.AppSettings["google.pagespeed.apikey"]; if (String.IsNullOrWhiteSpace(apiKey)) apiKey = WebConfigurationManager.AppSettings["google.apikey"]; if (context.Action.Parameters.TryGetValue("url", out obj)) { url = "https://www.googleapis.com/pagespeedonline/v2/runPagespeed?url="; url += (string)obj; if (!String.IsNullOrWhiteSpace(apiKey)) url += "&key=" + apiKey; context.Action.State = url; } else { url = (string)context.Action.State; } if (url == null) throw new Exception("Url parameter not specified"); ButtonBar buttonBar = new ButtonBar(); buttonBar.Buttons.Add(new Button("close", Translations.GetString("CLOSE"), "icon_sys22 icon-sys22-cancel", true)); context.Response.Layout[ThreeColumnLayout.ButtonBar] = buttonBar.Render(); StringBuilder sb = new StringBuilder(); context.Response.IncludedCss.Add(new CssInclude(ManagerResource.CreateUrl("css/library.css"))); context.Response.InlineJavascripts.Add("$(function () { shell.PrepareInterceptor($(\"form\")); });"); HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); string result = null; try { using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) { using (StreamReader reader = new StreamReader(response.GetResponseStream())) { result = reader.ReadToEnd(); } } } catch (WebException we) { // code omitted } sb.AppendLine("<div class=\"selectable\">"); sb.AppendFormat("<h1>{0}</h1>", Translations.GetString("GOOGLE_PAGESPEED_RESULT")); if (String.IsNullOrWhiteSpace(apiKey)) { // show warning sb.AppendFormat("<div><span class=\"information-message\">{0}</span></div>", Translations.GetString("PAGESPEED_NO_API_KEY")); } Json json = new Json(result); Json pageStats = json.GetProperty("pageStats"); sb.AppendLine("<table class=\"librarytable\" style=\"width: 730px;\">"); sb.AppendFormat("<tr><th colspan=\"2\">{0}</th></tr>", json.GetTypedProperty("id")); sb.AppendFormat("<tr><td>{0}</td><td>{1}</td></tr>", Translations.GetString("TITLE"), json.GetTypedProperty("title")); sb.AppendFormat("<tr><td>{0}</td><td>{1}</td></tr>", "Score", json.GetProperty("ruleGroups").GetProperty("SPEED").GetTypedProperty("score")); // page stats sb.AppendFormat("<tr><td>{0}</td><td>{1}</td></tr>", Translations.GetString("PAGESPEED_TOTAL_RESOURCES"), pageStats.GetTypedProperty("numberResources")); sb.AppendFormat("<tr><td>{0}</td><td>{1}</td></tr>", Translations.GetString("PAGESPEED_JS_RESOURCES"), pageStats.GetTypedProperty("numberJsResources")); sb.AppendFormat("<tr><td>{0}</td><td>{1}</td></tr>", Translations.GetString("PAGESPEED_CSS_RESOURCES"), pageStats.GetTypedProperty("numberCssResources")); sb.AppendFormat("<tr><td>{0}</td><td>{1}</td></tr>", Translations.GetString("PAGESPEED_STATIC_RESOURCES"), pageStats.GetTypedProperty("numberStaticResources")); sb.AppendFormat("<tr><td>{0}</td><td>{1}</td></tr>", Translations.GetString("PAGESPEED_NUMBEROF_HOSTS"), pageStats.GetTypedProperty("numberHosts")); sb.AppendFormat("<tr><td>{0}</td><td>{1}</td></tr>", Translations.GetString("PAGESPEED_TOTAL_BYTES"), Helpers.BytesToString(Convert.ToInt64(pageStats.GetTypedProperty("totalRequestBytes")))); sb.AppendFormat("<tr><td>{0}</td><td>{1}</td></tr>", Translations.GetString("PAGESPEED_HTML_BYTES"), Helpers.BytesToString(Convert.ToInt64(pageStats.GetTypedProperty("htmlResponseBytes")))); sb.AppendFormat("<tr><td>{0}</td><td>{1}</td></tr>", Translations.GetString("PAGESPEED_JS_BYTES"), Helpers.BytesToString(Convert.ToInt64(pageStats.GetTypedProperty("javascriptResponseBytes")))); sb.AppendFormat("<tr><td>{0}</td><td>{1}</td></tr>", Translations.GetString("PAGESPEED_CSS_BYTES"), Helpers.BytesToString(Convert.ToInt64(pageStats.GetTypedProperty("cssResponseBytes")))); sb.AppendFormat("<tr><td>{0}</td><td>{1}</td></tr>", Translations.GetString("PAGESPEED_IMG_BYTES"), Helpers.BytesToString(Convert.ToInt64(pageStats.GetTypedProperty("imageResponseBytes")))); sb.AppendFormat("<tr><td>{0}</td><td>{1}</td></tr>", Translations.GetString("PAGESPEED_OTHER_BYTES"), Helpers.BytesToString(Convert.ToInt64(pageStats.GetTypedProperty("otherResponseBytes")))); sb.AppendLine("</table>"); // ruleResults skipped sb.AppendLine("</div>"); context.Response.Layout[ThreeColumnLayout.CenterColumn] = sb.ToString(); return ActionResult.ActionCompleted(); } } } |
The subaction result will look like this: