Scripting:InfoBar Links

From STNE Wiki

Revision as of 04:19, 9 October 2011 by Miltiades (Talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Understanding InfoBar Links

The STNE engine allows for extensions accessible fro the 'InfoBar', an area at the top of the UI (user interface) primary pane. The intent it seems is to allow extensibility to the UI, and allow a certain level of customizations. These could include notes, coordinates, a list alliance members, etc. The InfoBar itself you have probably seen, it is the area where [You have a new message] appears.

To understand how to create an InfoBar application, one must first understand how it actually manages to get to the UI. This is done by CallBack methods. A callback is similar to system signal handlers in concept. When you tell the script to 'hook' a callback, it is added to a list of code to process every time that callback happens (with the exception that unlike a system signal, it can be pre filtered). A script can only hook a specific callback once, so if you need to have 3 individual methods happen for a particular callback event, you add them to a single function and call them all from there (In a normal driver or signal handler, you would not call the handler from a class, and this is good methodology to follow even with scripts) The following is an example of callback handling

Function RegisterHooks() {
  ScriptContext.EnableExtension();
  ScriptContext.RegisterEvent(EGuiEventType.InfoBarAfterCreate, AddressOf CB_InfoBarAfterCreate);
  ScriptContext.ActivateEvents();
}

Function CB_InfoBarAfterCreate(CBEvent As CGuiEventOnInfoBarAfterCreate) {
  // processing for event goes here, create the link, the output, etc.
  Var LinkItem As String = "my_infobar_app";
  Var Div As CHtmlDiv;
  InfoBarLink(CBEvent, LinkItem);
  Div = InfoBarDiv(CBEvent, LinkItem);
  Div.Style.Add('display', 'none'); 
  Div.Add("Hello, World!");
}

RegisterHooks();

RegisterHooks is a function called from the main body of the script, and the function itself handles adding the entry point onto the callback stack. Firstly, it sets up for being an extension via EnableExtensions. Next, it adds a handler to the callback stack, giving the code reference via AddressOf. Lastly, it lets the script engine know it's ready to handle events. Normally you will have any validation (checking data storage, initializing variables, etc) happening between EnableExtension and RegisterEvent. This function is called only at script initialization, which should be when you click on “Execute Script”, but experience tells me it gets called occasionally in other circumstances (the script seems to like to run from the main body after an STNE restart).

Once you have the callback hooked, you need the InfoBar link. For an InfoBar application to work, it needs two more components, other than the output. The first is a clickable link item, which usually contains the name of the script. The other is an area upon which to place your actual output. While the output can be appended from a different callback method, this is not the usual case. Firstly, set up the link:

Function InfoBarLink(CBEvent As CGuiEventOnInfoBarAfterCreate, LinkItem As String) {
  Var InfoBarAlignRight As Boolean = True;
  Var UrlCon As CHtmlControl;
  Var LinkText As String = "My InfoBar App";
  // Create the app bar link
  Var Url As CJsAction = CUrlBuilder.JsToggleElement(LinkItem);
  UrlCon = CControlBuilder.BracketLink(Url, LinkText);
  Var UrlSmall As New CHtmlSmall();
  UrlSmall.Add(UrlCon)
  CBEvent.CreateItem(InfoBarAlignRight).Add(UrlSmall.GuiControl);
}

This function simply sets up a toggle-able link on the InfoBar... It does not actually display anything, and clicking on it will do nothing, because no data is attached to it. The first line declares the function, and expects the passed parameter to be of type CGuiEventOnInfoBarAfterCreate, which is itself a child of the class CguiEvent. CguiEvent could be used instead, if this handler was to process multiple callbacks, but you loose accessibility to anything specific to the child (unless you cast it back to it's particular type). The declaration of InfoBarAlignRight is for clarity. If it was false, it would align on the left. LinkText is literally the text the link will have. JsToggleElement is how the UI adds the javascript code to toggle the output (a div tag) between visible and hidden. BracketLink adds [ and ] around the text. ChtmlSmall applies the <small> HTML tag to the link. The CreateItem is how the script adds the newly created link into the UI, on the infobar.

Now that we have the link, we need to add the output area for the link. This is done by creating a layered div tag. Why layered? So the output stays precisely where you want it, and it actually hides when necessary.

Function InfoBarDiv(CBEvent As CGuiEventOnInfoBarAfterCreate, LinkItem As String) As CHtmlDiv {
  Var BorderColor As String = "#16344E";
  Var OuterDiv As New CHtmlDiv();
  Var Div As New CHtmlDiv();
  
  CBEvent.Page.Body.Controls.Insert(0, OuterDiv.GuiControl);
  OuterDiv.Style.Add('position', 'absolute');
  OuterDiv.Width = '99%';
  OuterDiv.Style.Add('z-index', '255'); 
  
  OuterDiv.Add(Div);
  Div.Style.Add('position', 'absolute');
  Div.Style.Add('top', '0');
  Div.Style.Add('right', '0');
  Div.Style.Add('z-index', '255');
  Div.Style.Add('background-color', 'black');
  Div.Style.Add('border-style', 'solid');
  Div.Style.Add('border-color', BorderColor);
  Div.Style.Add('border-width', '1px');
  Div.ID = LinkItem; 
  Return Div;
}

Usually the InfoBar creation and the div creation are in the same function or method, but for purposes of example I have split them into two functions. The first part is the setup and assignment. LinkItem is the name of the inner div, and it is usually the similar to the link name. Keep in mind that if you create two scripts and name the Div the same, they will both appear and hide when either script link is toggled, so you want the inner div name to be unique. The middle of the function sets up the div attached to the control (the link). Since it was the last one added, it is the on the top of the stack, thus control at position 0. The width is 1% short of maximum, because some browsers (notably Opera) tends to cut the right border off if it is 100%. The Z-Index ensures it's appears above normal output. The last part of the function sets up the inner div, with a black background and the standard STNE blue border 1 pixel wide. The alignment for the output is top right, of the outer div, which is created just below the InfoBar. The output is adjusted to the smallest possible area that still displays the output. The following is the entire script:

#UseInterface Web, Gui;

Function InfoBarLink(CBEvent As CGuiEventOnInfoBarAfterCreate, LinkItem As String) {
  Var InfoBarAlignRight As Boolean = True;
  Var UrlCon As CHtmlControl;
  Var LinkText As String = "My InfoBar App";
  // Create the app bar link
  Var Url As CJsAction = CUrlBuilder.JsToggleElement(LinkItem);
  UrlCon = CControlBuilder.BracketLink(Url, LinkText);
  Var UrlSmall As New CHtmlSmall();
  UrlSmall.Add(UrlCon)
  CBEvent.CreateItem(InfoBarAlignRight).Add(UrlSmall.GuiControl);
}

Function InfoBarDiv(CBEvent As CGuiEventOnInfoBarAfterCreate, LinkItem As String) As CHtmlDiv {
  Var BorderColor As String = "#16344E";
  Var OuterDiv As New CHtmlDiv();
  Var Div As New CHtmlDiv();
  
  CBEvent.Page.Body.Controls.Insert(0, OuterDiv.GuiControl);
  OuterDiv.Style.Add('position', 'absolute');
  OuterDiv.Width = '99%';
  OuterDiv.Style.Add('z-index', '255'); 
  
  OuterDiv.Add(Div);
  Div.Style.Add('position', 'absolute');
  Div.Style.Add('top', '0');
  Div.Style.Add('right', '0');
  Div.Style.Add('z-index', '255');
  Div.Style.Add('background-color', 'black');
  Div.Style.Add('border-style', 'solid');
  Div.Style.Add('border-color', BorderColor);
  Div.Style.Add('border-width', '1px');
  Div.ID = LinkItem; 
  Return Div;
}


Function RegisterHooks() {
  ScriptContext.EnableExtension();
  ScriptContext.RegisterEvent(EGuiEventType.InfoBarAfterCreate, AddressOf CB_InfoBarAfterCreate);
  ScriptContext.ActivateEvents();
}

Function CB_InfoBarAfterCreate(CBEvent As CGuiEventOnInfoBarAfterCreate) {
  // processing for event goes here, create the link, the output, etc.
  Var LinkItem As String = "my_infobar_app";
  Var Div As CHtmlDiv;
  InfoBarLink(CBEvent, LinkItem);
  Div = InfoBarDiv(CBEvent, LinkItem);
  Div.Style.Add('display', 'none'); // See notes below
  Div.Add("Hello, World!");
}

RegisterHooks();

Normally, at the Div.Add in CB_ InfoBarAfterCreate, you would add your output table or div instead of a text string. Also, you would toggle the output with a URL Parameter, with something like this in CB_ InfoBarAfterCreate:

  Var ShowDiv As Boolean = False;
  // option processing here, usually returning the status of ShowDiv, like Showdiv = ProcessOptions()
  // … table/div output creation, like Div.Add(function());
  If (ShowDiv) {
    Div.Style.Add('display', 'block');
  } Else {
    Div.Style.Add('display', 'none');
  }

But URL/Form parameter passing and processing is for another tutorial --Miltiades (En-1:56599) 06:19, 9 October 2011 (CEST)

Personal tools