The Custom Layout Editor allows you to have complete control over the look and feel of TACTIC using many of the standard web technologies (HTML, CSS and Javascript). With this tool, you can build your own TACTIC components (called widgets) that have the ability to interact with one another intelligently, making it easier for you to design your very own TACTIC interface.
TACTIC Custom Layout introduces a new html tag <element> which allows for TACTIC widgets to be embedded into HTML.
There are two formats for a TACTIC element: a short form and a long form:
short form:
<element view='forms/my_form'/>
long form:
<element> <display class='tactic.ui.panel.CustomLayoutWdg'> <view>forms/my_form</view> </display> </element>
This ability to reference other views and elements makes it easy to keep a top level view that draws from other views.
For display class names of other widgets, see section on Common Widgets.
You can create styles for each view in the Styles tab. However, most of the time it will be useful to reference a central stylesheet for a number of views.
In order to include a top level stylesheet, you can create an empty view with only styles defined and include these styles into other top level views, just as how you would reference a normal view.
For example, you can create a view called 'common/styles' and add this line to the HTML of a view where you want the styles to appear.
<element view='common/styles'/>
TACTIC's behavior system makes use of standard JavaScript behaviors with the added functionality of some built-in classes.
Here are two ways to add an alert behavior to a button class called 'my_button'.
<behavior class=”my_button” event='click_up'> alert('Hello World'); </behavior> <behavior class='my_button'>{ 'type': 'click_up', 'cbjs_action': "' alert('Hello World'); "' }</behavior>
Here are the types of events that the TACTIC behavior system has built-in support for:
click_up | click | wheel | double_click | drag | hover | move | change | blur | mouseover | mouseout | keyup | keydown | listen
You can set the behavior class to activate upon the firing of another event using the 'listen' type event.
<behavior class='my_button'>{ 'type': 'click_up', 'cbjs_action': "' spt.named_events.fire_event('my_event_trigger'); "' }</behavior> <behavior class='my_class'>{ 'type': 'listen', 'event_name': 'my_event_trigger', 'cbjs_action': "' alert('Hello World'); "' }</behavior>
When the behavior is applicable to a specific HTML element (eg. click, click_up, mouseover, etc.), you can get element for which the behavior originated from using the 'bvr.src_el' (Behavior Source Element) tag.
var table = bvr.src_el.getParent('.my_table'); var cells = table.getElements('.my_cells'); cells.setStyle('background', 'red');
TACTIC’s powerful framework comes with many API functions that make developing for TACTIC easier. Here are some common ones.
Show loading popup:
spt.app_busy.show('Saving data...')
Hide loading popup:
spt.app_busy.hide()
Load an element:
spt.panel.load(element_name, class_name, kwargs)
Load an element into a popup:
spt.panel.load_popup(element_name, class_name, kwargs)
Close a popup:
spt.popup.close(popup_element)
Images can be checked into TACTIC and used in interface design. In the Files tab, you can check in images using the Check-in wizard.
Once the file is checked in, you use the web path as the URL of the image.
The custom layout engine embeds the Mako, a powerful templating engine which allows you to embed Python scripts and logic within HTML. Here is a simple example for its usage.
<div> <% my_car = 'A ferrari' %> </div> <p>${my_car}</p>
Mako makes passing and accessing of data in TACTIC easy, especially combined with the support of XML by TACTIC widgets for passing arguments.
The 'kwargs.get' function can be used to get the value of an XML attribute of an element, whether it is an attribute already supported by the element or an arbitrary one. Here is an example of setting a value for an arbitrary attribute.
HTML code in top level view:
<element> <display class='tactic.ui.panel.CustomLayoutWdg'> <view>my_forms.photoshoot_form</view> <args>Hello</args> </display> </element>
HTML code in a view named 'my_forms.photoshoot_form':
<element> <display class='tactic.ui.input.TextInputWdg'> <default>${kwargs.get("args")}</default> </display> </element>
For the example above, the text field will be populated with the string 'Hello'.
Most of the time, it will be beneficial to use Mako to pass search keys from one view to another. That's covered in a bit more detail in the Creating Forms section of this document.
You can inject your custom widgets or TACTIC built-in widgets into your view through the user interface. You can do it through the gear menu:
All these injection options allow you to inject the widget you want directly where your cursor is in the code. All these injections have the name field in common. The name field allows you to name your widget in case you want to refer to it later in the code.
Selecting Inject Widget allows you to inject any widget you want. You need to define which widget to inject, you can select your widget through the dropdown or select classpath and write the class path of a built-in TACTIC widget. After selecting, a built-in widget, you may have to fill in additional arguments which are required to successfully run the widget.
Selecting Inject Text Input allows you to inject the text input field widget. You can specify many options like the width of the input field. The Inject Look Ahead Text Input is similar except there is a look ahead which comes with the input field.
Similarly, you can inject a table or a calendar where you are given other options to customize them respectively.
You can add the view you have created directly to the sidebar. To do this, click on the gear in the top menu and select “Add to Side Bar”. This will add this view to the sidebar under the Project Views. By default, It will get named according to the view name and “/” will be treated as a space. For example, “app/chart” will be named “App Chart”. You can always rename these views in the sidebar by right clicking on them and selecting “Edit Side Bar”. Now select the view you want to edit and change the Title field.
When you startup tactic and go to the main project URL (…/tactic/<project_name>), you are presented with the tactic homepage of the project. That tactic homepage URL can be changed to show one of your created views. To do this, open up your view in the custom layout editor, then from the gear menu select “Set as Project Url”. The current view you have open will be shown when you go the main project URL. You can come back to admin side of tactic by adding “/admin” to the URL (…/tactic/<project_name>/admin).
You can also turn your view into a custom URL. This means that your view will open when you go to a specific URL. To do this, open your view in the custom layout editor, then from the gear menu select “Add as Custom Url”. This will open up a dialog box where you can specify what URL should open up the view. The URL specified there is showing the URL which is appended to (…/tactic). You can specify which widget to run in the URL in the widget field. By default, it shows the widget code for the view that was open in the custom layout editor. You can check all your custom URLs by going to the gear menu and selecting “Show Custom URLs”. This will show all the existing custom URLs. This is where you can delete existing custom URLs.
Forms provide an interface for updating TACTIC data. The Custom Layout Editor makes the creation of forms easy with built-in widgets and functions.
TACTIC already has some predefined input widgets that can be used as input fields for forms, and they are referenced like any other widget.
TextInputWdg
SelectWdg
TextAreaWdg
CalendarInputWdg
ActionButtonWdg
<element name='my_text_input_field'> <display class='tactic.ui.input.TextInputWdg'> <default>Hello</default> <width>100px</width> </display> </element>
You can find more details on the exact XML attributes that are supported by each widget in the Common Widgets section.
Here are some useful functions for generating forms.
spt.api.get_input_values(div_container)
This gets the values of the all the input fields of a div as an array with the attributes being the names of the element names.
server.update(search_key, data)
This updates an sobject with data that is passed in as an array.
The search key is a key that uniquely identifies an sobject.
Here is an example of usage of both for updating a TACTIC task through a form.
In this example, the search key of an sobject is passed into the view through a list of keyword arguments, and it is kept as a hidden input for ease of access. The clicking of the save button activates the behavior for saving the form.
HTML: <div class='spt_form'> <input type="hidden" name="spt_search_key" value="${kwargs.get('search_key')}"/> <element name='spt_status'> <display class='SelectWdg'> <values>Assigned|Pending|Approved|Waiting</values> <search_key>${kwargs.get("search_key")}</search_key> </display> </element> <input type="button" class="spt_save_button" value="Save >>"/> </div> JavaScript: <behavior class="spt_save_button> { "type": "click", "cbjs_action": ''' //gets the parent of the behavior source element var top = bvr.src_el.getParent('.spt_form'); //gets all the input values var values = spt.api.get_input_values(top); var data = { //gets value of element named 'spt_status' //sets it as the value of the 'status' column for the task sobject status: values.spt_status; } search_key = values.spt_search_key; server.update(search_key, data) ''' }
You can customize your views to behave during a testing phase. To do this, you can add a condition in your code to check whether the code is being run in testing mode. You can use the following condition in the python section of the code:
if kwargs.get("is_test") in [True, 'true']:
This condition will be true if it is testing mode. You can now use this condition to setup your variables correctly. You can run the view in testing mode by clicking the test button in the top menu.
Handling None:
The default value for the empty string in Python is the word "None". This does not help very much when you want to obtain something like the search key of an sobject because if there is no search key, instead of getting an empty string, you get the string "None". And if you try to pass "None" into an element, an error will likely result.
The way to work around that is to add an "or" at the end of your kwargs.get function.
ie: kwargs.get("search_key") or ""
Embed Elements:
A shortcut for embedding elements into the HTML is by clicking on the gear menu.
Similarly, if you would like to inject another view into your current view, you can do so by right clicking on the view you want to inject.
Element Name as Column of sObject:
If you pass a search key into an element, it automatically takes the element name as the column if you do not specify one. In the example below, the text input will display the id of the sObject with the given search key.
<element name="id"> <display class="tactic.ui.input.TextInputWdg"> <search_key>${search_key}</search_key> <width>100px</width> </display> </element>