• Solutions
    • FERC XBRL Reporting
    • FDTA Financial Reporting
    • SEC Compliance
    • Windows Clipboard Management
    • Legato Scripting
  • Products
    • GoFiler Suite
    • XBRLworks
    • SEC Exhibit Explorer
    • SEC Extractor
    • Clipboard Scout
    • Legato
  • Education
    • Training
    • SEC and EDGAR Compliance
    • Legato Developers
  • Blog
  • Support
  • Skip to blog entries
  • Skip to archive page
  • Skip to right sidebar

Friday, January 24. 2020

LDC #165: A Quick Web Link Builder

While the Novaworks tools are principally used for EDGAR, sometimes there are non-EDGAR things to do. One of my activities is maintaining a website for a not-for-profit group supporting amateur radio. As part of my duties, the front page of the site has a section on recent non-club news which requires me to perform a little research and then add the links to the page. This script helps reduce the time to create the links.


Introduction


To add links, every day or two I walk through the news on various search sites, look at some related clubs in the US and UK and also look at stuff on YouTube. Once I find a story, I add the link:


1.  Copy the story title to the home page.

2.  Add a citation like “(ARRL 01/24/2020)” in small type next to the link.

3.  Copy the link URL and then use the Insert Hyperlink (which in GoFiler does not like non-SEC links, so a warning message is presented each time).

4.  Change the target to “_blank” (again, EDGAR does not allow target so it has to be added manually).

5.  Add a class to change the look of the link.


As can be seen, this is a lot of steps. So, what about a script to augment the functionality of GoFiler?


Here’s a dialog I can create:


Add Quick Web Link Dialog


Which adds the following code to the document at the current caret position:


The K7RA Solar Update (ARRL 01/24/2020)


or in HTML:


<a class="page" target="_blank" href="http://www.arrl.org/news/the-k7ra-solar-update-613">
The K7RA Solar Update</a> <font style="font-size: 8pt">(ARRL 01/24/2020)</font>


Note the class, which is hard coded.


The Script


Ideally the script can be executed as part of the application start up by adding it to the scripts folder or the user scripts extension folder (it must be renamed with the .ms extension).


Let’s look at the script:


                                                                /************************************************/

    string              a_class;
    string              a_text;
    string              a_url;
    string              a_cite;
    


                                                                /************************************************/
int setup() {

    string              fnScript;
    string              item[10];
    int                 rc;

    item["Code"] = "EXTENSION_QUICK_WEB_LINK";
    item["MenuText"] = "&Quick Web Link";
    item["Description"] = "<B>Quick Web Link</B>\r\rAdds a custom external web hypertext link.";
    item["Class"] = "DocumentExtension";

    rc = MenuFindFunctionID(item["Code"]);
    if (IsNotError(rc)) { return ERROR_NONE; }

    rc = MenuAddFunction(item);
    if (IsError(rc)) { return ERROR_NONE; }
    fnScript = GetScriptFilename();
    MenuSetHook(item["Code"], fnScript, "run");

    ArrayClear(item);
    item["KeyCode"] = "L_KEY_CONTROL";
    item["ChordAKey"] = "Q";
    item["FunctionCode"] = "EXTENSION_QUICK_WEB_LINK";
    item["Description"] = "Insert quick keb link";

    QuickKeyRegister("Page View", item);

    return ERROR_NONE;
    }

                                                                /************************************************/

int main() {

    string              s1;
    int                 rc;

    s1 = GetScriptParent();
    if (s1 == "LegatoIDE") {
      rc = MenuFindFunctionID("EXTENSION_QUICK_WEB_LINK");
      if (IsError(rc)) {
        setup();
        }
      else {
        MenuDeleteHook("EXTENSION_QUICK_WEB_LINK");
        s1 = GetScriptFilename();
        MenuSetHook("EXTENSION_QUICK_WEB_LINK", s1, "run");
        }
      MessageBox('i', "Hook running on IDE");
      }
    return ERROR_NONE;
    }

                                                                /************************************************/

int run(int f_id, string mode) {

    handle              hEO;
    string              code;
    string              s1;
    int                 c_x, c_y,
                        rc;

    if (mode != "preprocess") { return ERROR_NONE; }

    hEO = GetActiveEditObject();
    if (hEO == NULL_HANDLE) { return ERROR_CONTEXT; }

    rc = GetSelectMode(hEO);
    if (rc != EDO_NOT_SELECTED) {
      MessageBox('x', "Deselect to use this function");
      return ERROR_CANCEL;
      }
      
    c_y = GetCaretYPosition(hEO); c_x = GetCaretXPosition(hEO);

    rc = DialogBox("LinkQuery01Dlg", "lq_");
    if (IsError(rc)) { return rc; }

    a_class = "page";

    code = "<a " +
           "class=\"" + a_class + "\" " +
           "target=\"_blank\" "  +
           "href=\"" + a_url + "\"" +
           ">";
    code += ANSITextToXML(a_text);
    code += "</a>";
    code += " <font style=\"font-size: 8pt\">";
    code += ANSITextToXML(a_cite);
    code += "</font>";
    
    WriteSegment(hEO, code, c_x, c_y);

    return ERROR_NONE;
    }



                                                                /************************************************/

#beginresource

#define ASL_URL                                 201
#define ASL_URL_LOOKUP                          202
#define ASL_TEXT                                203
#define ASL_CITE                                204


LinkQuery01Dlg DIALOGEX 0, 0, 280, 118
STYLE DS_3DLOOK | WS_POPUP | WS_VISIBLE | WS_CAPTION
CAPTION "Add Quick Web Link"
FONT 8, "MS Shell Dlg"
{
 CONTROL "Link To:", -1, "static", SS_LEFT | WS_CHILD | WS_VISIBLE, 6, 4, 30, 8, 0
 CONTROL "", -1, "static", SS_ETCHEDFRAME | WS_CHILD | WS_VISIBLE, 36, 9, 236, 1, 0
 CONTROL "&URL:", -1, "static", SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP, 12, 18, 30, 8
 CONTROL "", ASL_URL, "edit", ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 45, 16, 170, 12
//CONTROL "Look Up", ASL_URL_LOOKUP, "button", BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 225, 16, 40, 12, 0
 CONTROL "Parameters:", -1, "static", SS_LEFT | WS_CHILD | WS_VISIBLE, 6, 37, 40, 8, 0
 CONTROL "", -1, "static", SS_ETCHEDFRAME | WS_CHILD | WS_VISIBLE, 46, 42, 226, 1, 0
 CONTROL "&Text:", -1, "static", SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP, 12, 53, 30, 8, 0
 CONTROL "", ASL_TEXT, "edit", ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 45, 51, 220, 12, 0
 CONTROL "&Cite:", -1, "static", SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP, 12, 69, 30, 8, 0
 CONTROL "", ASL_CITE, "edit", ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 45, 67, 220, 12, 0
 CONTROL "", -1, "static", SS_ETCHEDFRAME | WS_CHILD | WS_VISIBLE, 6, 90, 268, 1, 0
 CONTROL "OK", IDOK, "BUTTON", BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 168, 96, 50, 14
 CONTROL "Cancel", IDCANCEL, "BUTTON", BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 223, 96, 50, 14
}

#endresource

int lq_validate() {
    string              parts[];
    string              s1;
    int                 rc;

    a_url = EditGetText(ASL_URL, "URL", EGT_FLAG_REQUIRED);
    rc = GetLastError();
    if (IsError(rc)) { return rc; }
    parts = GetURIComponents(a_url);
    s1 = MakeLowerCase(parts["scheme"]);
    if ((s1 != "http:") && (s1 != "https:")) {
      MessageBox('x', "Need an HTTP or HTTPS scheme on link.");
      return ERROR_SOFT | ASL_URL;
      }

    a_text = EditGetText(ASL_TEXT, "Text", EGT_FLAG_REQUIRED);
    rc = GetLastError();
    if (IsError(rc)) { return rc; }

    a_cite = EditGetText(ASL_CITE, "Cite", EGT_FLAG_REQUIRED);
    rc = GetLastError();
    if (IsError(rc)) { return rc; }
    return ERROR_NONE;
    }

Let’s break this down:


The Globals


Four variables are global, all used for passing information out of the dialog: a_class, a_text, a_url and a_cite. Remember, the class variable is hard coded.


The Setup


When run as a menu script, or from the IDE, the setup function creates a custom menu function and adds a quick key. The quick key is added to the key chord combination for linking as Ctrl+L Q.


Just a reminder, when the application is initializing, it looks for in specific folders for menu scripts (*.ms) and runs the setup() function. It does not run the main() function.


The first function called is MenuAddFunction, only after checking that it has not already been added. This test is also performed during the main() function. The particulars are added to an array and then to the application’s function list. The next thing to do is add the hook using MenuSetHook. The hook causes our script (this script) to be added and then the run() function is called on execution of the specified menu item. This means the script cannot be run from the IDE as an untitled window (save the file before experimenting with this).


The extension is added to the Document ribbon:


Document Tools Ribbon Example 


Finally, a quick key is added. I like to quickly hit a key to start a function rather than hunting through the ribbons and menus. Note that it is only added to Page View.


The Main


This function is here only to support the debugging process to allow the script to be worked on in the IDE. If the function is already defined, it will delete the hook and re-hook to the IDE copy. This allows the script to be edited and then run repeatedly.


A couple of important notes: First, it only needs to be re-hooked once. So, testing the script simply involves saving the script (the hook reloads the file if the date, time or size changes). Second, the hook does not directly display errors. The hook just will not work! So preprocess the script for errors, use the trace function and other tricks like message boxes to see what is going on. Also, when working on tricky code, you can remove it from the script and make a jig so you can step through with the debugger.


Finally, note that main() does not run the linking function. It must be run from the application menu.


Run


This is the heart of the program. As one can see, not much is going on here. First, we only want to run on menu preprocess, so others are ignored. The next thing is to get the Edit Object for our window. Ideally, we should make sure we are running on an HTML file, but, the hook is on the Document | Tools menu, and that ribbon only shows up in Page View and Text View with HTML, so we can be pretty certain that users won’t be accessing this script from a non-HTML window.


The edit select mode is tested using GetSelectMode and the caret position retrieved using GetCaretYPosition and GetCaretXPosition functions. If the mode is not compatible, the script leaves after notifying the user.


Next the dialog is run. If “ok”, we fall into creating our code. This could be done with the SGML Object, but I decided to just hard code the string data.


Finally, the resulting code is inserted to the active edit window.


Dialog


I have discussed dialogs in a number of other previous blogs so I am not going to delve to deep here. In this case I coded only one function, validate the controls. All the dialog controls are required and the URL must be an “http” or “https” scheme.


If you look carefully, you’ll see a control commented called “Look Up”. This will be uncommented in a follow-up blog to fill in all the information by retrieving the web page and capturing menu data.


Conclusion


In many ways, this is a perfect example of extending the functionality of the application. This has been on the to do list for quite a while and I plan to start using this right away. I plan to later improve it with the addition of the lookup and a cite table that will fill the text and cite fields for certain common sites.


Here is the result:


Example Links


 


Scott Theis is the President of Novaworks and the principal developer of the Legato scripting language. He has extensive expertise with EDGAR, HTML, XBRL, and other programming languages.

Additional Resources

Novaworks’ Legato Resources

Legato Script Developers LinkedIn Group

Primer: An Introduction to Legato 

Posted by
The Novaworks Team
in Development at 17:16
Trackbacks
Trackback specific URI for this entry

No Trackbacks

Comments
Display comments as (Linear | Threaded)
No comments
The author does not allow comments to this entry

Quicksearch

Categories

  • XML Accounting
  • XML AICPA News
  • XML FASB News
  • XML GASB News
  • XML IASB News
  • XML Development
  • XML Events
  • XML FERC
  • XML eForms News
  • XML FERC Filing Help
  • XML Filing Technology
  • XML Information Technology
  • XML Investor Education
  • XML MSRB
  • XML EMMA News
  • XML FDTA
  • XML MSRB Filing Help
  • XML Novaworks News
  • XML GoFiler Online Updates
  • XML GoFiler Updates
  • XML XBRLworks Updates
  • XML SEC
  • XML Corporation Finance
  • XML DERA
  • XML EDGAR News
  • XML Investment Management
  • XML SEC Filing Help
  • XML XBRL
  • XML Data Quality Committee
  • XML GRIP Taxonomy
  • XML IFRS Taxonomy
  • XML US GAAP Taxonomy

Calendar

Back May '25 Forward
Mo Tu We Th Fr Sa Su
Sunday, May 18. 2025
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  

Feeds

  • XML
Sign Up Now
Get SEC news articles and blog posts delivered monthly to your inbox!
Based on the s9y Bulletproof template framework

Compliance

  • FERC
  • EDGAR
  • EMMA

Software

  • GoFiler Suite
  • SEC Exhibit Explorer
  • SEC Extractor
  • XBRLworks
  • Legato Scripting

Company

  • About Novaworks
  • News
  • Site Map
  • Support

Follow Us:

  • LinkedIn
  • YouTube
  • RSS
  • Newsletter
  • © 2024 Novaworks, LLC
  • Privacy
  • Terms of Use
  • Trademarks and Patents
  • Contact Us