tag:blogger.com,1999:blog-73022131577134603462024-03-27T19:52:57.504-04:00TACTIC TechBlogTACTIC is a dynamic, open-source, web-based platform used for building enterprise solutions maintained by <a href="http://southpawtech.com">Southpaw Technology Inc</a> and the open source <a href="http://community.southpawtech.com">Community</a>.Remko Noteboomhttp://www.blogger.com/profile/16584018990758100598noreply@blogger.comBlogger13125tag:blogger.com,1999:blog-7302213157713460346.post-44288768497142091962017-07-28T12:03:00.002-04:002017-07-28T12:03:37.177-04:00Basic Introduction to the TACTIC Workflow Engine<br />
The Workflow Engine is one of the key technology components of TACTIC. A workflow defines a set of connected process nodes. Each node represents some work that needs to be done within the entire workflow which constitutes a job.<br />
<br />
The workflow engine drives the entire work process forward. It is responsible<br />
for sending messages so that upstream and downstream process are notified of<br />
important events. For example, if a downstream process sets a task to complete, then all the next upstream processes will set the task to pending.<br />
<br />
In TACTIC, any sobject can have a pipeline defined. Fundamentally,t his means that any sobject can go through a series of processes, have tasks assigned to it and have files checked into it.<br />
<br />
<b>Pipeline or Workflow?</b><br />
<br />
Internally, TACTIC uses word pipeline, however, this word is not commonly<br />
recognized outside of the Visual Effects / Computer Graphics indusry. Workflow is commonly used in every other industry, so this is the terminology that we will use from now on.<br />
<br />
<b>Process Node Types</b><br />
<br />
<div>
<div>
By default, all nodes are manual nodes. These nodes represent processes</div>
<div>
where manual work must be done. In general, a task is created which is</div>
<div>
associated with this node. This task will have someone assigned to it</div>
<div>
and can have a specific start and end date.</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
When a task that belongs to a process changes its status, a message is</div>
<div>
sent to that processes. This allows the workflow engine to react to this</div>
<div>
change in status. For example, if a "complete" message is sent from the</div>
<div>
task to the process, then the process "send" a pending message to all of</div>
<div>
its output connections. This output notification is automatic.</div>
<div>
<br /></div>
<div>
If the output node is another manual node, then the process will notifiy any</div>
<div>
tasks associated with it and set them to pending. This task would now</div>
<div>
show up on a "pending" task list for users (who would set it to "In Progress" when working on the task)</div>
<div>
<br /></div>
<div>
If the output node is another node type, the behavior would be quite different.</div>
<div>
For example, if the output node was an "action" type, then the script code</div>
<div>
associated with that process would automatically get executed.</div>
<div>
<br /></div>
<div>
Action nodes are non-blocking. They will automatically execute their programmed task and without any manual involvement from a user, when they complete, they will send a "pending" message to the next process.</div>
<div>
<br />
Approval node is a specific type of node that is very similar to a<br />
<div>
manual node. There is always an assigned task that is associated with</div>
<div>
it however, usually, the task status options are more limited. Also,</div>
<br />
<div>
</div>
<br />
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: "Times New Roman"; font-size: medium; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;">
<div style="margin: 0px;">
many widgets recognize approval nodes and adjust accordingly.</div>
</div>
<br />
<b>Connecting Processes</b></div>
<div>
<br /></div>
<div>
These nodes can be connected together in any combination.</div>
<div>
<br /></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">manual1 -> auto1 -> auto2 -> manual2</span></div>
<div>
<br /></div>
<div>
In this example, after manual1 is set to "complete", "auto1" would automatically</div>
<div>
execute. On completion of "auto2" will automatically execute. Finally,</div>
<div>
when "auto2" completes, "manual2" will receive a "pending" signal which will</div>
<div>
set the task in this node to a status of "pending".</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
The nodes can also be connected in parallel:</div>
</div>
<div>
<br /></div>
<div>
<div>
<br /></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">manual1 -> auto1 -> manual2</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> -> auto2 -></span></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
In this case, both auto1 and auto2 would be executed simultaneously. Manual2</div>
<div>
would not receive the pending signal until both "auto1" and "auto2" are complete.</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
As can be seen from these examples, the workflow engine pushes process progress</div>
<div>
along the various steps defined in the definition of the workflow. Users</div>
<div>
do not need to remember to execute certain scripts in certain ways in certain</div>
<div>
order. This can all be hidden from the user and be executed exactly as they</div>
<div>
were designed to do.</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
There are a number of other nodes in built into TACTIC which enhance how the</div>
<div>
workflow engine behaves. It is even possible to write custom nodes types</div>
<div>
entirely in Python. These nodes can be loaded in as a TACTIC plugin</div>
<div>
and used just like a native node.</div>
<div>
<br /></div>
<div>
<br /></div>
</div>
Remko Noteboomhttp://www.blogger.com/profile/16584018990758100598noreply@blogger.comtag:blogger.com,1999:blog-7302213157713460346.post-86361572920130218602017-04-04T09:08:00.002-04:002017-04-05T15:07:14.798-04:00PHP and TACTIC Rest APITACTIC 4.6 just introduced a new generic REST API which implements most of the TACTIC API. This opens up the TACTIC API to almost all programming languages. There are still some advantages to using the client side libraries for Python and Javascript as there is some custom convenience and logic written in the client side libraries. However, for many important operations, the rest API is sufficient. This is especially useful when integrating TACTIC with such platforms as WordPress or Drupal or AngularJS.<br />
<br />
Since the TACTIC API functionality is very deep, the first REST implementation has been to only support POST requests. This provides the access to all of the arguments of the API methods without the inconvenient limitation of using a URL to provide all of the arguments to methods.<br />
<br />
The following example will made use of the PHP curl functionality wrapped up in a convenience function. It is assumed that you already have a login ticket. A login ticket is any non-expired entry in the "ticket" table in the "sthpw" database.<br />
<br />
The following function wraps up all the settings needed to access a TACTIC server:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">function executeREST($data) {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> $server = "http://tactic.server.com";</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> $login_ticket = "8f096a8359bbc355943f93545684b90e</span><span style="font-family: "courier new" , "courier" , monospace;">";</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> $project = "my_projects";</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> $url = $server."/".$project."/rest";</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> $data['login_ticket'] = $login_ticket;</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;"> $ch = curl_init();</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> curl_setopt($ch, CURLOPT_URL, $url);</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> curl_setopt($ch, CURLOPT_POSTFIELDS, $data);</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> curl_setopt($ch, CURLOPT_FAILONERROR, true);</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;"> $result = curl_exec($ch);</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> if (curl_error($ch)) {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> throw new Exception(curl_error($ch));</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> }</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> $result = json_decode( $result );</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> return $result;</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">}</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
With this function, we can access the api simply with a single line. We can start with a simple ping.<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">$data = [</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> 'method' => 'ping'</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">];</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">echo executeREST($data);</span><br />
<br />
This should print "OK", which means that the code has contacted the TACTIC server and was authenticated. The method<br />
<br />
Next, we can try a simple sobject with a search key:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">$data = [</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> 'method' => 'get_by_search_key',</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> 'search_key' => $search_key,</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">];</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">print executeREST($data);</span><br />
<div>
<br /></div>
<div>
And we can also use expressions:</div>
<div>
<br /></div>
<div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">$data = [</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> 'method' => 'eval',</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> 'kwargs' => json_encode( [</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> 'expression' => '@SOBJECT(workflow/asset)',</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> 'single' => true,</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> ] ),</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">];</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">$result = executeREST($data);</span></div>
</div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span></div>
<div>
Note the difference in the arguments between this method (eval) and the last (get_by_search_key). There are two ways for arguments to be passed through and both are valid for either function. You can use the arguments explicitly or you can wrap the arguments in a kwargs key. However, the kwargs key is assumed to be JSON encoded and allows for complex data structures to be passed through. The post interface does not allow for complex data structures, so these should be JSON encoded.</div>
<div>
<br /></div>
<div>
This opens up the TACTIC API to many languages, in particular PHP and Ruby which are used in server side processing of popular web platforms. All of these platforms have a very weak ability to handle complex data and really have no asset management capabilities. This API makes it easy to integrate a powerful back-end with these content delivery systems.</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<br />
<br />
<br />
<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<br />
<div>
<br /></div>
Remko Noteboomhttp://www.blogger.com/profile/16584018990758100598noreply@blogger.comtag:blogger.com,1999:blog-7302213157713460346.post-25015513518866131952017-03-31T12:20:00.000-04:002017-03-31T12:28:52.553-04:00TACTIC Javascript API Start-upUsing the TACTIC 4.6 API from javascript is very simple. You just have to reference<br />
a single javascript file. You can either reference a local copy of this file:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;"><script src="js/tactic.js"> </script></span><br />
<br />
Or you can reference it from TACTIC server itself:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;"><script src="http://<server>/context/spt_js/tactic.js"> </script></span><br />
<br />
Replace<span style="font-family: "courier new" , "courier" , monospace;"> <server></span> with your own server IP or domain name running TACTIC. This<br />
will import all the necessary javascript libraries and functions to interact with<br />
the TACTIC server.<br />
<br />
Next you will need to generate an API ticket. This key is a long unique alpha-numeric string of characters. This ticket is added to the API key, which has the form:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">http<s>://<server>/<site>/<project>/ticket/<ticket></span><br />
<br />
So, for example, you would set up the server with the following:<br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;"><script></span><br />
<span style="font-family: "courier new" , "courier" , monospace;">tactic = TACTIC.get();</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">var key = http://<server>/workflow/workflow/ticket/571be6bb09142c4c6b883e0c9f310f57");</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">tactic.set_key(key);</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"></script></span><br />
<br />
If you wish to build tickets dynamically, then this can be done from a custom login<br />
screen that captures a login and password. For there, you would execute the following:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">tactic = TACTIC.get();</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">tactic.set_server(server);</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">var ticket = tactic.get_ticket(name, password);</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">tactic.set_ticket(ticket);</span><br />
<br />
where "server" is the IP or domain name of your TACTIC Server and name and password<br />
are user entered fields. Once you have a ticket, this can be used until the ticket<br />
expires on the server.<br />
<br />
You are all ready to access any of TACTIC API functionality. To check if you can access the server, simple run the ping method:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">alert( tactic.ping() )</span><br />
<br />
If it returns "OK", you have successfully accessed the TACTIC server with proper credentials.<br />
<br />
At this point, you have the full API at your disposal. As an example, you could run a query for tasks completed assigned to Fred:<br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">tasks = tactic.query("sthpw/task", {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> filter: [['status','Complete'],['assigned','fred']],</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">} );</span><br />
<br />
<br />
If you wish to run this asynchronously, you would add an on_complete callback:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">tactic.query("sthpw/task", {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> filter: [['status','Complete'],['assigned','fred']],</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> on_complete: (tasks) => {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> console.log(tasks)</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> }</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">} );</span><br />
<br />
<br />
Or if you wish to use promises:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">tactic.p_query("sthpw/task", {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> filter: [['status','Complete'],['assigned','fred']],</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">} )</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">.then( (tasks) => {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> console.log(tasks)</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">} );</span><br />
<br />
<br />
Or we could use an expression to get the same result:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">var expression = "@SOBJECT(sthpw/task['status','Complete']['assigned','fred'])"</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">tactic.p_eval(expression)</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">.then( (tasks) => {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> console.log(tasks)</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">} );</span><br />
<br />
<br />
<br />
The javascript implementation is a fully featured TACTIC API. This is useful for<br />
many applications such as server side javascript such as NodeJS, Mobile apps that<br />
run on javascript. It can also be used in WordPress or Drupal applications on the<br />
browser.<br />
<div>
<br /></div>
<div>
<br /></div>
Remko Noteboomhttp://www.blogger.com/profile/16584018990758100598noreply@blogger.comtag:blogger.com,1999:blog-7302213157713460346.post-80223160146542992272017-03-16T22:41:00.001-04:002017-03-17T09:37:38.865-04:00Executing server side scripts from browser<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">TACTIC provides a number of mechanism to Python code on the server. We can start with a widget in the Custom Layout Editor with the HTML definition:</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><div></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> <input type=”button press_me” name=”Press Me”/></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></div></span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">In the behaviors:</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><behavior class=”press_me”></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> var script_path = “my_scripts/press_me”;</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> var kwargs = {};</span></div>
<span style="font-family: Courier New, Courier, monospace;">
</span>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> var server = TacticServerStub.get();</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> server.execute_python_script(path, kwargs);</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></behavior></span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">In the Script Editor, you can create a script with the folder “my_scripts” and title “press_me”.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">print “Button is pressed”</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This simple example prints “Button is pressed” to the console. Of course, this script can contain any Python code. In this example, the script is blocking. This is not usually desirable because blocking scripts cause the Javascript engine to wait until the full execution of the script. Except for very fast and small scripts, this will negatively influence the user experience. In order to run the script asynchronously, you could run the following call instead:</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">server.execute_python_script(path, kwargs, {</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> on_complete: function() {</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> spt.alert(“Script Complete”);</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> }</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">} )</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This works well for simple scripts that need to be executed on the server. It is often desirable to use full python classes to execute scripts on the server side. To execute a class on the server, you need to derive the class from the TACTIC Command class and override the execute function.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">from pyasm.command import Command</span></div>
<span style="font-family: Courier New, Courier, monospace;"><b style="font-weight: normal;"><br /></b>
</span><br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">class MyCmd(Command):</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> def exectute(self):</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> print “Running ....”</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> print “kwargs: “, self.kwargs</span></div>
<span style="font-family: Courier New, Courier, monospace;"><b style="font-weight: normal;"><br /></b>
</span><br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> my.info = {</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> test: 456</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> }</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Instead of “server.execute_python_script” in the behavior, you would have:</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">var cmd = “foo.MyCmd”</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">var kwargs = {</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> test: 123</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">}</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">var server = TacticServerStub.get()</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">var ret_val = server.execute_cmd(cmd, kwargs);</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The kwargs for the command will be the dictionary with key “test” and value “123”. The returned value is a dictionary that will contain any error information as well as an “info” dictionary that will contained any returned data from the command itself. In the example above, it would return the dictionary with the key “test” and value “456”.</span></div>
<br />
<span style="font-family: "arial"; font-size: 11pt; vertical-align: baseline; white-space: pre-wrap;">This method allows you to create interface elements and then run custom scripts on the server based on interaction with those interface elements. The HTML code is connected to the behaviors which run Javascript code. The javascript uses the TACTIC API to execute commands directly on the TACTIC Server and provides a clear mechanism to send information to the command as well as receive information from the command.</span>Remko Noteboomhttp://www.blogger.com/profile/16584018990758100598noreply@blogger.comtag:blogger.com,1999:blog-7302213157713460346.post-30809119497814968682016-10-07T21:52:00.001-04:002016-10-07T21:52:23.725-04:00Introduction to TACTIC Plugins<br />
TACTIC Plugins are a way of packaging up functionality and distributing them<br />
to other projects or other servers.<br />
<br />
The Plugin architecture is very flexible and almost any functionality, large<br />
or small can be packaged in as a plugin.<br />
<br />
A TACTIC Plugin can contain:<br />
<br />
<ol>
<li>data</li>
<li>configuration</li>
<li>python class</li>
<li>4mages and media</li>
<li>css and javascript libraries</li>
</ol>
<br />
<br />
At the core of a TACTIC Plugin is a manifest file. The manifest file tells TACTIC how to load and unload a plugin. It is an xml file and is placed at the root of the plugin folder. A simple example of on is as follows:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><manifest></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> <data></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> <code>spt.whatever</code></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> <title>XYZ</title></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> </data></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> <sobject search_type="custom/asset"/></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"></manifest></span><br />
<br />
It declares what data belongs to the plugin.<br />
<div>
<br /></div>
<div>
<div>
The above manifest will create a plugin that will export all entries from the "custom/asset" search</div>
<div>
type to a file called "custom_asset.spt". Files with ".spt" extension are TACTIC custom files that are used for importing and exporting data. The syntax used is exactly the same as Python (a python processor is used to read the data), however they are not self-contained and executable and thus not really considered ".py" files. However, if desired, any python code could be added and it should be processed correctly.</div>
<div>
<br /></div>
<div>
When loading the plugin, the "sobject" will read the corresponding ".spt" file and insert the new sobjects into the database. On unloading the plugin, the entire table will be removed. This because the line states that the entire table belongs to the plugin. This is useful for custom search types, but often it is desireble for the plugin to own a subset of table. The easiest way to do this is with an expression</div>
<div>
<br /></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><sobject search_type="custom/asset" expression="@SOBJECT(custom/asset['asset_type','image'])"/></span></div>
<div>
<br /></div>
<div>
This will export all the sobjects with the column asset_type equal to "image". This</div>
<div>
allows multiple plugins to share data in the same search type. Care must be taken so</div>
<div>
that a given sobject only belongs to a single plugin to avoid conflicts.</div>
<div>
<br /></div>
<div>
To control the output file the data is written to, the "path" attribute can be used.</div>
<div>
<br /></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><sobject search_type="custom/asset" path="config/asset.spt"/></span></div>
<div>
<br /></div>
<div>
This file created will be relative to the manifest file. This can be used to</div>
<div>
break up a single table into multiple files, if that is desired.</div>
<div>
<br /></div>
<div>
It is quite common not to wnat all the columns in the exported file. The</div>
<div>
"ignore_columns" attribute can be used to specify columns that are not exported.</div>
<div>
<br /></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><sobject search_type="custom/asset" igonre_columns="id,code,timestamp"/></span></div>
</div>
<div>
<br /></div>
<div>
<div>
The code and id are commonly not exported. The "id" column is usually auto</div>
<div>
generated, so their exact values are not important as long as they are not used</div>
<div>
to relate to other table. This prevents conflicts of ids loaded in from other</div>
<div>
plugins. If the code needs to be exported, it is important to ensure that this</div>
<div>
code will be unique enough to be loaded even if data is already filled in that table.</div>
<div>
<br /></div>
<div>
If the definition of a search_type needs to be exported, the "search_type" tag can</div>
<div>
be used:</div>
<div>
<br /></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><search_type code="custom/asset"/></span></div>
<div>
<br /></div>
<div>
This will save out the entire search_type definition into the ".spt" file. This makes</div>
<div>
it possible for a plugin to own the definition of a search_type allowing a plugin</div>
<div>
to define a data model.</div>
<div>
<br /></div>
<div>
With the combination of the <search_type> tag and the <sobject> tag, almost any</div>
<div>
configuration data can be stored in a plugin.</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
When a plugin is loaded, the plugins folder is also accessible from the web server.</div>
<div>
This means that images and other files can be put into a plugin and be visible by</div>
<div>
a client web broser.</div>
<div>
<br /></div>
<div>
For example:</div>
<div>
<br /></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><img src="/plugins/test_plugin/media/image.png"/></span></div>
</div>
<div>
<br /></div>
<div>
This would be visible by the following URL:</div>
<div>
<br /></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">http://<server>/plugins/test_plugin/media/image.png</span></div>
<div>
<br /></div>
<div>
This allows the plugin to package up different image files as well as javascript and css files.</div>
<div>
<br /></div>
<div>
This was just a small introduction to TACTIC plugins. The plugin architecture is flexible enough that almost any TACTIC functionality can be encapsulated in one.</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
Remko Noteboomhttp://www.blogger.com/profile/16584018990758100598noreply@blogger.comtag:blogger.com,1999:blog-7302213157713460346.post-33329089004951594392016-09-30T13:25:00.005-04:002016-09-30T13:26:15.814-04:00Dynamic updates when data changes.<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: "arial"; font-size: 14.6667px; white-space: pre-wrap;">Dynamic updates allow any part of the page to update itself based on change occurring on the server.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">To illustrate, begin with a simple element that display the number of assets in the system.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><div>${asset_count}</div></span></span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">In Python, the asset count would be retrieved as follows.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">asset_count = server.eval(“@COUNT(example/asset)”)</span></span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">When the view loads, it would process the asset count on the server side and then fill in the value in HTML. The problem comes when someone else who is using the system adds another asset after a view has been loaded. The data displayed is now out of date. Normally the entire page, or in TACTIC’s case, the widget needs to be reloaded to update the correct value. However, knowing when data has changed presents a challenge.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Dynamic update solves this problem by providing a mechanism to update some part of the content based on some specified updated criteria.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">For example, in the widget above, we will add an update through javascript:</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><div class=”test_update”>${asset_count)</div></span></span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">In python, we would write:</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">kwargs[‘expr’] = “@COUNT(example/asset)”</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">asset_count = server.eval(kwargs.get(“expr”))</span></span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">And in behaviors, we would add:</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><behavior class=”test_update” event=”load”></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> var expr = kwargs.expr;</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> spt.update.add( bvr.src_el, {</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> expression: expr</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> } );</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"></behavior></span></span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This will check the expression periodically to see if the value has changed on the server. It the value changes, such as a new asset was added, this would be detected and the value of the expression will replace what is inside the “test_update” element. This is very useful for keeping values up to date on a page without having to refresh.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">There is another argument called interval. Normally, a dynamic update will check every couple of seconds, however, most data this is much too often. It is possible to slow down the number of checks by setting the interval.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><behavior class=”test_update” event=”load”></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> var expr = kwargs.expr;</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> spt.update.add( bvr.src_el, {</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> expression: expr,</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> Interval: 10,</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> } );</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"></behavior></span></span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This will do a check on the server about every 50 seconds.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">If a widget is dependent on the values of a single SObject, then we can add search_key parameter instead and this will detect if any change to a particular SObject has been made.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><behavior class=”test_update” event=”load”></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> var search_key = bvr.kwargs.search_key;</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> spt.update.add( bvr.src_el, {</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> search_key: search_key,</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> expression: “@GET(.status), </span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> } );</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"></behavior></span></span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">With the addition of a search_key, TACTIC will check if any changes have been made to that SObject. If so, it will replace the “test_update” widget with the value returned from the corresponding expression.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">In order to have more control, it is possible to run some javascript.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><behavior class=”test_update” event=”load”></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> var search_key = bvr.kwargs.search_key;</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> spt.update.add( bvr.src_el, {</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> search_key: search_key,</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> cbjs_action: “spt.panel.refresh(bvr.src_el)”</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> } );</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"></behavior></span></span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This will update refresh the next parent refreshable widget when the corresponding SObject changes. With a javascript callback, it is possible to do a wide variety of actions.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Finally, it is possible to attach a dynamic behavior purely in Python.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">div = DivWdg()</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">div.add_update( {</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> “expression”: expr</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">} )</span></span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This allows a widget that is entirely written using a Python class to make use of dynamic updates.</span></div>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Dynamic updates provide a powerful and flexible means of update interface elements based on data changes on the server. With careful judgement about what needs to be updated and how often, data viewed on a page will never be out of date.</span></div>
Remko Noteboomhttp://www.blogger.com/profile/16584018990758100598noreply@blogger.comtag:blogger.com,1999:blog-7302213157713460346.post-42606929210213138932016-09-28T10:37:00.000-04:002016-09-28T10:39:10.983-04:00What is a TACTIC Widget?<b id="docs-internal-guid-08e72ac6-7132-45f4-d086-6e76859622ec" style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="color: black; font-family: "arial"; font-size: 14.6667px; vertical-align: baseline; white-space: pre-wrap;">Widgets are self-contained user interface elements. In TACTIC, they combine </span><span style="font-family: "arial"; font-size: 14.6667px; white-space: pre-wrap;">HTML layout and CSS styling with</span><span style="font-family: "arial"; font-size: 14.6667px; white-space: pre-wrap;"> server-side Python processing, client side Javascript behaviors, all encapsulated in a single entity called a widget.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Widgets are a fundamental building block to interfaces in TACTIC. Even the base HTML tags have been mapped to TACTIC Widgets, however, most users will create and combine higher level widgets using pure python </span><span style="font-family: "arial"; font-size: 14.6667px; white-space: pre-wrap;">classes or, more commonly, they can be created using the TACTIC Custom Layout Editor.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The custom layout editor enables the creation of widgets directly within the TACTIC interface. Very complex enterprise applications can be created using solely this editor without needing to resort to Python class (however, that is always an option, if desired)</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">There are 5 main components to a TACTIC Widget:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br />
<ol>
<li>Keyword Arguments</li>
<li>HTML</li>
<li>Styles</li>
<li>Behaviors</li>
<li>Python</li>
</ol>
</div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Each of these components make up the definition of single widget. They are form a single interface element. </span><span style="font-family: "arial"; font-size: 14.6667px; white-space: pre-wrap;">The simplest widget is a pure html element.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><div>Hello</div></span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">In order to style this element, CSS can be attached to this element. Because this is HTML, you can add CSS styles directly on the element itself:</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Courier New, Courier, monospace; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><div style=”color: #F00”>Hello</div></span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">A better method is to separate out the styling of the widget from the structure. Although, an “id” could be used to relate CSS to this element, it is generally not recommended. This is because “id” must be unique throughout the entire document. With widgets as reusable elements that can appear many times in a single interface, it is better to identify an element using “class”.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new" , "courier" , monospace; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><div class=”element1”></span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">And in the styles tab of the Custom Layout Editor, you would add:</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new" , "courier" , monospace; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.element1 {</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new" , "courier" , monospace; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> color: #F00;</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new" , "courier" , monospace; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">}</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">TACTIC Widgets also bind server side processing into the widget. The python component has a predefined kwargs variable that contains input arguments to the widget. Thus in the python tab, you could write:</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new" , "courier" , monospace; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">color = kwargs.get(“color”)</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">And you could use this variable in both the HTML tab and the styles tab. For example:</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new" , "courier" , monospace; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.example1 {</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new" , "courier" , monospace; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> color: ${color};</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new" , "courier" , monospace; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">}</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This becomes a configurable widget that can be embedded into another widget using the HTML as follows:</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new" , "courier" , monospace; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><div></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new" , "courier" , monospace; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> <h1>Reference to another widget</h1></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new" , "courier" , monospace; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> <element view=”content1” color=”#0B0”/></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new" , "courier" , monospace; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></div></span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The would embed the word “Hello” with blue text into this widget. </span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Finally, you can access the kwargs variable in javascript in the behaviors tab from the implicit bvr variable:</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new" , "courier" , monospace; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><behavior class=”.element1” event=”click”></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new" , "courier" , monospace; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> var color = bvr.kwargs.color;</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new" , "courier" , monospace; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> alert(color)</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new" , "courier" , monospace; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></behavior></span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Using these together, you can build up more complex reusable widgets.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">There are a number of significant advantages of using TACTIC for content delivery, despite the many web platforms out there and many that do a good job of delivering web content. For those more comfortable with these other platforms, there is a TACTIC javascript standalone API which can be imported into any web framework. </span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">TACTIC widgets have a very strong encapsulation between the client side code and the server side code. Data structures are seamless transferred and shared between the two. </span><span style="font-family: "arial"; font-size: 14.6667px; white-space: pre-wrap;">TACTIC widgets can be loaded asynchronously and do not rely on full page refresh to load content. This makes TACTIC apps feel smoother because they only update parts of the interface that need updating. TACTIC also has many built-in widgets that do common widgets that together provide a wide range of tools to handle many enterprise requirements, especially when creating data driven workflow solutions.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: "arial"; font-size: 14.6667px; white-space: pre-wrap;"><br /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: "arial"; font-size: 14.6667px; white-space: pre-wrap;"><br /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: "arial"; font-size: 14.6667px; white-space: pre-wrap;"><br /></span></div>
Remko Noteboomhttp://www.blogger.com/profile/16584018990758100598noreply@blogger.comtag:blogger.com,1999:blog-7302213157713460346.post-85523126833359348582016-09-26T12:34:00.000-04:002016-09-28T10:42:22.414-04:00Keyword arguments (kwargs) in Custom Views<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Custom views are a great way to create widgets in TACTIC. They combine HTML, CSS, server side Python and client Javascript all in a single self contained widget. All views in TACTIC have a predefined variable named “kwargs” which contain parameters that are passed to the widget from some external source. The kwargs variable is a simple dictionary of name / value pairs and represent keyword arguments for that widget. These kwargs can be used to write highly functional general purpose widgets that can be reused.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">In a TACTIC using the Custom Layout Editor, it can be assumed that there is always a kwargs variable which can be simply accessed in the Python section of the custom view.</span></div>
<b style="font-weight: normal;"><span style="font-family: "courier new" , "courier" , monospace; font-size: xx-small;"><br /></span></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">color = kwargs.get(“color”) or “”</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">search_type = kwargs.get(“search_type”) or “”</span></span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">These variables can be accessed in the HTML </span><span style="color: black; font-family: "arial"; font-size: 14.6667px; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">component using the following syntax:</span></div>
<b style="font-weight: normal;"><span style="font-family: "courier new" , "courier" , monospace; font-size: xx-small;"><br /></span></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><div class=”top_element” style=”color: ${color}”></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> <element view=”view1” search_type=”${search_type}”/></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"></div></span></span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Thus a variable take from the kwargs are passed from python to an HTML, first to set the color style and second, to pass the search_type to another view which will receive as a kwarg as well.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The variables defined in Python are also accessible in the styles section:</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">.top_element {</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> color: ${color};</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">}</span></span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The kwargs variable is also passed along to the behavior section:</span></div>
<b style="font-weight: normal;"><span style="font-family: "courier new" , "courier" , monospace; font-size: xx-small;"><br /></span></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><behavior class=”top_element” event=”click”></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> alert( bvr.kwargs.search_key );</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"></behavior></span></span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This makes the input variables through kwargs available to all parts of a TACTIC widget. One often used technique is to go fill in the kwargs variable with custom key / value pairs to simplify the communication of data between Python and Javascript</span></div>
<span style="font-size: x-small;"><b style="font-weight: normal;"><br /></b>
</span><br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">server = TacticServerStub.get()</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">count = server.eval(“@COUNT(workflow/asset)”)</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">kwargs.count = count</span></span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">And in Javascript</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><behavior class=”top_element” event=”click”></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> alert(bvr.kwargs.count)</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"></behavior></span></span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The kwargs value can be a complex data structure as well:</span></div>
<b style="font-weight: normal;"><span style="font-family: "courier new" , "courier" , monospace; font-size: xx-small;"><br /></span></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">codes = server.eval(“@GET(workflow/asset.code”)</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">kwargs.codes = codes</span></span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">And in Javascript</span></div>
<span style="font-size: x-small;"><b style="font-weight: normal;"><br /></b>
</span><br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">var codes = bvr.kwargs.codes;</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">for (var i = 0; i < codes.length; i++ ) {</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> alert(codes[i]);</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> }</span></span></div>
<br />
<br />
<span style="font-family: "arial"; font-size: 14.6667px; vertical-align: baseline; white-space: pre-wrap;">Put together, this provides a complete communication for transferring data for server side data to the client side, all encapsulated in a single widget.</span>Remko Noteboomhttp://www.blogger.com/profile/16584018990758100598noreply@blogger.comtag:blogger.com,1999:blog-7302213157713460346.post-7018795169415064922016-09-24T22:18:00.002-04:002016-09-28T10:42:28.761-04:00Delayed loading using load=”async and load=”sequence”<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Custom Layout views enable the display of content using a set of widgets. The custom <element> tag enables TACTIC views to reference other widgets. A complex page can be broken down into smaller reusable components.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><div></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> <element view=”content.view1” mode=”XYZ”/></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"></div></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><div></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> <element view=”content.view2” mode=”XYZ”/></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"></div></span></span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Here, a master view can reference two smaller views, each passing in the kwarg “mode” with the value “XYZ” to the referenced view. When a call is made to draw the overall view, TACTIC will build the entire view with all the reference view on the server and then serve up the entire content to the client. If “content.view1” or “content.view2” are either large or take up a lot of processing time, the user experience is compromised as they will have to wait for the entire view to be processed before seeing anything on the screen.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">To improve the user experience, it is possible to delay the processing of a referenced view. So for example:</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><div></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> <element view=”content.view1” mode=”XYZ”/></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"></div></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><div></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> <element view=”content.view2” mode=”XYZ” load=”async”/></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"></div></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><div></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> <element view=”content.view3” mode=”XYZ” load=”async”/></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"></div></span></span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The server will only process “content.view1” and send that to the client. Only fter the main view and “content.view” have be been drawn, will the client make asynchronous requests for both “content.view2” and “content.view3” simultaneously.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This has two advantages:</span></div>
<ol style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: decimal; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The user experience is improved because content will show up much more quickly as the server only has to process “content.view1”. The views “content.view2” and “content.view3” are processed after “content.view1” is visible.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: decimal; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The view in its entirety will load much more quickly because “content.view2” and “content.view3” will both be processed simultaneously by the server on two separate processes, making use of load balancing on the server</span></div>
</li>
</ol>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">However, making a lot of heavy simultaneous requests all at once on the server could stress the server. While desirable to process and receive the content as quickly as possible, it is not always necessary when the content is “below the fold” and falls below the cut-off at the bottom of the page, This problem can be solved with “sequence” loading.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><div></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> <element view=”content.view1” mode=”XYZ”/></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"></div></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><div></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> <element view=”content.view2” mode=”XYZ” load=”sequence”/></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"></div></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><div></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> <element view=”content.view3” mode=”XYZ” load=”sequence”/></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"></div></span></span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This will initially load only “content.view1” with the main view. Once these are loaded, TACTIC will send a request for “content.view2” and once that is loaded, it will send another request for “content.view3” in sequence. These views end up being loaded over time in sequence without the user really being aware that the content is missing until they scroll down.</span></div>
<br />
<span style="font-family: "arial"; font-size: 14.6667px; vertical-align: baseline; white-space: pre-wrap;">Having control of how and when a page loads content improves the user experience. Content immediately needed is loaded first and other content can be delayed. Mixing and matching async loading and sequence loading provides a flexible means of loading heavy content views.</span>Remko Noteboomhttp://www.blogger.com/profile/16584018990758100598noreply@blogger.comtag:blogger.com,1999:blog-7302213157713460346.post-42771408772977809152016-09-22T21:56:00.004-04:002016-09-22T22:42:25.224-04:00Using "tactic_load" and "tactic_popup" to dynamically load widgets<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<h2>
<span style="font-family: "arial"; font-size: 14.6667px; font-weight: 400; white-space: pre-wrap;">The TACTIC Custom Layout Editor is a key tool for building enterprise applications in TACTIC. When building dynamic enterprise applications, dynamically loaded view or a custom widget make for a much better end user experience. </span></h2>
</div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Dynamic loading can be done with the javascript api function:</span></div>
<b style="font-weight: normal;"><span style="font-family: "courier new" , "courier" , monospace;"><br /></span></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">spt.panel.load(element, class_name, kwargs);</span></span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">However, this function requires writing a full behavior with custom javascript code. Using Javascript is necessary if some logic is required to determine what to load, but often one just needs to load a know widget with known keyword arguments. This can be very easily achieved using custom html classes. For example, to a load a view “customers.list”, one could just use the “tactic_load” class:</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><div></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> <input type=”button tactic_load” view=”customers.list” target=”content” value=”View Customers” /></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> <div class=”content”/></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"></div></span></span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This will create a button with the label “View Customers”. When clicking, it will dynamically load the view “customers.list” into the “content” element. This is a very simple way to create a dynamically loaded applications. It is very useful for creating sidebars or menu items.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Sometimes arguments need to passed to this new view. This is easily done by adding extra attributes to the html element</span></div>
<b style="font-weight: normal;"><span style="font-family: "courier new" , "courier" , monospace;"><br /></span></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><input type=”button tactic_load” view=”customers.list” target=”content” search_type=”workflow/asset” value=”View Customers” /></span></span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This will add the “search_type” key with the value “workflow/asset” into the kwargs of the view “customer.list”. This is very useful for configuring the usage of a widget that is to be loaded. Even more powerful would be to make the value a variable that is determined in Python.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Similarly, the “tactic_popup” class will open up a popup with the corresponding widget. This is often used to open up edit or insert widgets or to display some additional information. </span></div>
<br />
<span style="font-family: "arial"; font-size: 14.6667px; vertical-align: baseline; white-space: pre-wrap;">The use of these built-in classes make for a very powerful application building tool. For a concrete example, this is how the <a href="http://portal.southpawtech.com/" target="_blank">TACTIC Portal</a> loads most of its content. Since these classes can open up any widget in TACTIC, one can create complex dynamic applications very quickly.</span>Remko Noteboomhttp://www.blogger.com/profile/16584018990758100598noreply@blogger.comtag:blogger.com,1999:blog-7302213157713460346.post-63709176873181144392015-03-06T18:42:00.001-05:002015-03-06T20:36:26.523-05:00Using a Search object in an TACTIC ExpressionAnother interesting feature added to 4.4 is the ability to add use a Search object as starting point for the expression language. At present this only makes sense for server side code, so this code needs to be used on the "Python" tab on custom widgets or in server side triggers. On server side code, TACTIC uses the Search object for all searches. It packages up all search functionality possible in a single object.<br />
<br />
The expression language is very convenient for doing relatively complex queries very simply. Previous, the expression language could use a list of sobjects as a starting point.<br />
<br />
For example:<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">expression = "@SUM(vfx/shot.cost)"</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">results = Search.eval( expression, sobjects=sobjects)</span><br />
<br />
The sobjects passed in will be used as a "starting" point for the expression and evaluate the expression relative to those starting sobjects. In this case, it will calculate the total sum of all the "cost" values for all the sobjects.<br />
<br />
SObjects are usually built by an Search object such as:<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">search = Search("vfx/shot")</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">search.add_filter("sequence_code", "XYZ")</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">sobjects = search.get_sobjects()</span><br />
<br />
Now if we wanted to use the resultant sobjects in an expression, we would have to do:<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">results = Search.eval(expression, sobjects=sobjects)</span><br />
<br />
This was inefficient because it would do a search on the database, build all the sobjects and then extract information from those sobjects to operate on. This made it impossible or inefficient to do further filters on the passed in list.<br />
<br />
Passing in a Search object delays the search until the expression language has had a change to add extra filters. So the above example would change to:<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">search = Search("vfx/shot")</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">search.add_filter("sequence_code", "XYZ")</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"><span style="font-size: x-small;">results = Search.eval(expression, search=search)</span></span><br />
<br />
If the expression contained filters, this would be much more efficient:<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">expression = "@SUM(vfx/shot['date_due','>','$TODAY']['date_due','<','$TOMORROW'])"</span><br />
<br />
These date filters would be applied at the same time as the sequence code filters.<br />
<br />
Since the search object is often accessible from a command or widget, this becomes a very convenient way to further operate on a search. This is especially useful when calculate aggregate data starting from some previously selected search criteria. More on that later.<br />
<br />
<br />
<br />
<br />
<br />Remko Noteboomhttp://www.blogger.com/profile/16584018990758100598noreply@blogger.comtag:blogger.com,1999:blog-7302213157713460346.post-67190228884835367592015-02-25T12:21:00.000-05:002016-09-28T10:41:01.863-04:00Just committed the ability to do "full text" searching in the TACTIC expression language in 4.4 alpha.<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">@SOBJECT(test/type['keywords','@@','fast red car'])</span><br />
<br />
This can be mixed with other search criteria:<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">@SOBJECT(test/type['keywords','@@','fast red car']['media_type','image'])</span><br />
<br />
This will make use of the underlying database's full text search. At present, the operator used is '@@' simply because it is used in PostgreSQL. This doesn't seem to be a standard operator, but will work in the meantime.<br />
<br />
Full text search had previously been implemented for PostgreSQL and SQLServer so these databases should work.Remko Noteboomhttp://www.blogger.com/profile/16584018990758100598noreply@blogger.comtag:blogger.com,1999:blog-7302213157713460346.post-62914698949407226912015-02-24T16:29:00.002-05:002016-09-28T13:07:16.137-04:00Welcome to the TACTIC TechBlog<br />
<br />
This will be a technical blog which will highlight and demonstrate techniques in TACTIC for building effective enterprise solutions.Remko Noteboomhttp://www.blogger.com/profile/16584018990758100598noreply@blogger.com