F(x) is an application programmability framework for
securely building extendable web-application
using simple spreadsheet semantics

Why F(x)

Building extendable web applications, where developers and/or users have the option to securely extend the capabilities of the application at runtime can be challenging. While frameworks such as AngularJS and React are ideal for building web and in some cases native applications, providing users with the capabilities to extend those applications at runtime (with capabilities such as interoperable stand-alone applications, plug-ins, modules, applets, or widgets ‘programmed’ by third parties or end users) often introduces substantial security risks that need to be managed and mitigated.

Over the last two decades, we’ve had to implement and deploy several solutions where we needed to allow users (of various expertise) to extend our applications. The form and model for such extensions can take many shapes. In almost all cases, we ended up using some variation of an XML or JSON block (often with some type of a progamming UI) to describe the plugin (a plugin being: (a) some in-place user-interface component, (b) some logic/workflow/decision component, and (c) an ability to access and/or modify the core application data. For security reasons, we had to substantially limit what we allow the user to do – specially on the logic/workflow and data access components. For a class of trusted users, we would allow them to include some logic (programmable) elements (such as Javascript or AngularJS expressions) but that introduced substantial security concerns and operational complexities that we needed to mitigate.

What we needed is a programmable “language” that can be used to build embeddedable components (plugins/widgets) that is sufficiently flexible to allow for logic/workflow/branching, UI integration, and access to the application data, and do it all in a highly sandboxed, secure, and controlled way.

F(x) is an application framework to enable such capabilities.

How F(x) works – by example

F(x) uses standard spreadsheet functional syntax to allow for extending Web applications.

To start, let’s look at the building blocks for a simple stand-alone widget on a page built using F(x).  This widget shows two input fields and displays the SUM in span:

Item 1: <input type='text' fxaddr='A1' /><br />
Item 2: <input type='text' fxaddr='B1' /><br />
Subtotal: <span fxaddr='C1' fxfunc='=SUM(A1, B2)'></span><br />

In this example, you see that we gave  a unique Id to the two input fields using the fxaddr attribute. Then we set the span C1 to be a standard spreadsheet expression using the fxfunc attribute to sum the values from the A1 and B1 fields. In a sense, this is a mini-spreadsheet widget.

F(x) keeps track of the values for A1 and B1; should either change, the value for C1 gets reevaluated automatically.

Now let’s extend the capabilities slightly.  Lets say we need to display a Subtotal, which is the sum of the two fields, and a Total, which is the Subtotal multiplied by a fixed tax rate:

Item 1: <input type='text' fxaddr='A1' /><br />
Item 2: <input type='text' fxaddr='B1' /><br />
Subtotal: <span fxaddr='C1' fxname='Subtotal' fxfunc='=SUM(A1, B2)'></span><br />
<input type="hidden" fxaddr='D1' fxname='TaxRate' value='1.05' /><br />
Total: <span fxaddr='E1' fxname='Total' fxfunc='=Subtotal*TaxRate'></span>

The first thing to notice in this example is that we named the C1 field using the fxname attribute. As is the case with a spreadsheet, this field is now reference-able using either C1 or Subtotal. We also added a hidden attribute D1 to contain a fixed value for the tax rate. lastly, we added a formula for evaluating the E1 (Total) field using a standard spreadsheet expression to multiply the Subtotal – itself a derived field – by the TaxRate.

In this case as well, F(x) keeps track of the dependencies between A1, B1, C1 (Subtotal), D1, and E1 (Total). As is the case with the spreadsheet evaluator, F(x) evaluates the expressions for a dependent field in the correct order whenever any of the values changes.

Now let’s say you need this widget to only accept positive values for A1 and B1.

Subtotal: <span fxaddr='C1' fxname='Subtotal' fxfunc='=SUM(A1, B2)' fxshow='=AND(A1>0,B1>0)'></span><br />
Total: <span fxaddr='E1' fxname='Total' fxfunc='=IF(AND(A1>0,B1>1),Subtotal*TaxRate, "Bad values"></span>

In this example, we replace the two spans for Subtotal and Total.  Subtotal is only visible if A1 > 0 and B1 > 0.  The expression for total is a little more involved.  if A1>0 and B1>0 then display the Subtotal*TaxRate, otherwise display the error message.

In this example, we examined the fxaddr, fxname, fxfunc and fxshow attribute that can be added to any HTML element. there are additional attributes that the framework provides – as described below.

Integrating F(x)

The are different integration options for using F(x) in your applications. At the simplest level, you can integrate the capabilities described above by simply embedding the appropriate js files as described in the “Step-by-step integration” below.

However, a more interesting scenario is to provide customers with the ability to build widgets on the fly into your application – think Google Forms, Survey Money, or historically VBA. For that, see the “Advanced Integration” section below.

Step-by-step Integration

In order to run the example above, create a simple html file and edit it as follows:

1. Include the F(x) libraries
<script src="/lib/fx/script/jsep.js"></script>
<script src="/lib/fx/script/fx.js"></script>
<script src="/lib/fx/script/fx.ui.js"></script>
<link rel type="text/css" href="/lib/fx/styles/fx.css">

2. Include the function libraries needed
<script src="/lib/fx/script/funcs/fx.funcs.addin.js"></script>
<script src="/lib/fx/script/funcs/fx.funcs.compat.js"></script>
<script src="/lib/fx/script/funcs/fx.funcs.cube.js"></script>
<script src="/lib/fx/script/funcs/fx.funcs.db.js"></script>
<script src="/lib/fx/script/funcs/fx.funcs.debug.js"></script>
<script src="/lib/fx/script/funcs/fx.funcs.dt.js"></script>
<script src="/lib/fx/script/funcs/fx.funcs.engr.js"></script>
<script src="/lib/fx/script/funcs/fx.funcs.financial.js"></script>
<script src="/lib/fx/script/funcs/fx.funcs.info.js"></script>
<script src="/lib/fx/script/funcs/fx.funcs.logical.js"></script>
<script src="/lib/fx/script/funcs/fx.funcs.lookup.js"></script>
<script src="/lib/fx/script/funcs/fx.funcs.math.js"></script>
<script src="/lib/fx/script/funcs/fx.funcs.stats.js"></script>
<script src="/lib/fx/script/funcs/fx.funcs.text.js"></script>
<script src="/lib/fx/script/funcs/fx.funcs.web.js"></script>

3. Initialize F(x) framework

<script language='javascript>
$(document).ready(function() { fxui.init(); });
</script>

4. Add attributes for any controls
<input type='text' fxaddr='A1' /><br />
<input type='text' fxaddr='B1' /><br />
Subtotal: <span fxaddr='C1' fxname='Subtotal' fxfunc='=SUM(A1, B2)'></span><br />

Advanced Integration Models

A more extensible model is to enable (advanced) users to design widgets (plugins) on the fly. To enable dynamic creation of widgets, follow these steps:

1. Design and build a Widget builder

The widget builder enables the user to layout the set of controls for a given interface, and enables the user to optionally define the calculated value and display conditions for each control using standard spreadsheet syntax. The definition would then be serialized into the database in some data format (e.g. JSON).

A reference implementation can be found here [tbd]. In the reference implementation, the layout is serialized into this format:


"controls": [
{
"type": "section",
"address": "S1",
"title": "Basic Information",
"children": [
{
"address": "C1",
"name": "controlName",
"title": "Control label",
"help": "",
"type": "text"
},
{
"id": "C2",
"name": "controlName2",
"title": "Control Label 2",
"type": "span",
"formula": "=expression",
"show": "=formula"
}
]

2. Build a rendered that translates your JSON layout into HTML

TBD

3. Build custom integration functions and register them with F(x)

Formulas and Extensibility below.

Attributes


fxaddr

Every HTML element that choses to be addressable by F(x) must have an fxaddr attribute – this is the only required attribute.  While fxaddr can have any identifier value, it is best if it follows the standard spreadsheet AlphaNum syntax (e.g. A1, or C23.  Fields following this convention will be addressable via ranges.

fxname

As is the case with spreadsheets, fields may be give a name – e.g. Total, Subtotal, Income, etc.  This is an optional field.  Formula can reference fields either via an fxname or fxaddr

fxfunc

qwer qwer q

fxshow

qwer qwer q

fxtype

qwer qwer q

fxformat

qwer qwer q

fxedit

qwer qwer q

fxsecure

qwer qwer q

fxsecure

qwer qwer q

Cells, Addresses, and Ranges

In order to mimic as much as possible both the syntax and semantics of spreadsheets, F(x) enable the developer to define two attributes for any HTML element: axaddr and axname.

axaddr refers to the address of the field, and it must be unique within the page.  Also, ideally, addresses should follow the syntax of typical spreadsheet of an alpha followed by a numeric.  Doing so enables the user to reference a group of addressable elements using the standard range syntax. That is, if you define 4 elements named A1, A2, A3, A4, you can reference all 4 elements as follows SUM(A1:A4).

On the other hand, axname can be any identifier value, and does not have to be unique; thus if you have 4 fields and all 4 have are name HoursWorked, you can then reference all four elements using the named range – SUM(HoursWorked).

Evaluator

TBD

Supported HTML elements

TBD

Formulas and Extensibility

TBD

User Interface

TBD

Download

TBD

Debugging/Tracing

TBD

The Axle Addin allows a user to export a standard Excel sheet as a formatted stand-alone HTML with the full interactive capabilities of a spreadsheet.

The Axle Chrome extension allows a user to add spreadsheet semantics to any exiting open page.

Getting Started

Download…