Example 2: Simple text input
Introduction
This topic describes the different steps to implement a simple gICAPI-based web component.
In this example, we will implement a simple text editor based on a
textarea HTML element.
The dialog code implements a couple of triggers to show how the WEBCOMPONENT
field interacts with the program.
The HTML file is described in detail, and complete code example with program and form file is available at the end of this topic.
HTML code description
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html" charset="utf-8" />
<meta name='viewport' content='initial-scale=1.0, maximum-scale=1.0' />
The "viewport" meta is provided to adjust the viewport size for mobile devices.
<style>
html,body {
  height:100%;
  padding:0;
  margin:0;
  border:0;
  overflow:hidden;
}
textarea#field1 {
  font-weight: bold;
}
textarea {
  display: block;
  font-family: fixed;
  font-size: 10px;
  padding:0;
  margin:0;
  width: 99%;
}
</style></head><textarea> element and references the
external JavaScript file in a <script> element:<body>
<textarea id="field1"></textarea>
<script type="text/javascript" src="js/wc_simple.js"></script>
</body></html>The wc_simple.js file
The JavaScript code implementing the gICAPI web component starts with some global variables. These variables will hold information that must be persistent during the web component life:
var has_focus;
var field1 = {};
The global function onICHostReady() will be called by the front-end, when the
web component interface is ready. The version passed as parameter allows you to check that your
component code is compatible with the current gICAPI framework, and to define and assign the
gICAPI.on* callback methods (these will be defined in the body of the
onICHostReady() function:
var onICHostReady = function(version) {
    if ( version != "1.0" ) {
        alert('Invalid API version');
    }
    ... see below for gICAPI interface functions ...
}
At this point, the gICAPI interface is ready and the gICAPI object can be
used.
field1 variable is initialized to reference the
textarea element:    field1 = document.getElementById("field1");textarea element gets the
focus, to ask for a focus change with a gICAPI.setFocus()
call:    field1.addEventListener('focus', (event) => {
        if (has_focus === false) {
            gICAPI.SetFocus();
        }
    });The gICAPI.onData() function must be implemented to detect web component value
changes done in the program, and to acknowledge SetData() calls:
    gICAPI.onData = function(content) {
        field1.value = content;
    };
onFocus() function is used to detect that the web component has got or lost
the focus. If the focus is gained, we need to explicitly set the focus to the expected web component
element:    gICAPI.onFocus = function(polarity) {
        has_focus = polarity;
        if (has_focus) {
            field1.focus();
        }
    }The only way to detect that the focus was gained by the web compoment field, is when
onFocus(true) is called.
gICAPI.onFlushData() function, to provide
textarea content, when the front-end needs to send the field value to the runtime
system:    gICAPI.onFlushData = function() {
        gICAPI.SetData( field1.value );
    };gICAPI.onStateChanged()
function:    gICAPI.onStateChanged = function(ps) {
        var params = JSON.parse(ps);
        if ( params.active ) {
            field1.disabled = false;
        } else {
            field1.disabled = true;
        }
    };Complete source code
File webcomp.per:
LAYOUT (TEXT="Simple web component")
GRID
{
Id:                       [id               ]
[wc                                         ]
[                                           ]
[                                           ]
[                                           ]
[                                           ]
[tx                                         ]
[                                           ]
[                                           ]
[                                           ]
}
END
END
ATTRIBUTES
EDIT id = FORMONLY.id;
WEBCOMPONENT wc = FORMONLY.wc,
  COMPONENTTYPE = "wc_simple",
  SCROLLBARS = NONE,
  STRETCH = BOTH;
TEXTEDIT tx = FORMONLY.info;
END
            File webcomp.4gl:
MAIN
    DEFINE rec
        RECORD
            id INTEGER,
            wc STRING,
            info STRING
        END RECORD
    OPTIONS INPUT WRAP, FIELD ORDER FORM
    OPEN FORM f1 FROM "webcomp"
    DISPLAY FORM f1
    LET rec.id = 123
    LET rec.wc = "Hello, world!"
    INPUT BY NAME rec.* ATTRIBUTES(UNBUFFERED, WITHOUT DEFAULTS)
        BEFORE FIELD wc
           LET rec.info = "BEFORE FIELD wc=\n", rec.wc
        ON CHANGE wc
           LET rec.info = "ON CHANGE wc =\n", rec.wc
        AFTER FIELD wc
           LET rec.info = "AFTER FIELD wc =\n", rec.wc
        ON ACTION show_value
           LET rec.info = "ON ACTION show wc=\n", rec.wc
        ON ACTION set_value
           LET rec.wc = "A new value ", CURRENT HOUR TO FRACTION
        ON ACTION disable
           CALL DIALOG.setFieldActive("wc", FALSE)
        ON ACTION enable
           CALL DIALOG.setFieldActive("wc", TRUE)
    END INPUT
END MAIN
            File wc_simple.html:
<!DOCTYPE html>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html" charset="utf-8" />
<meta name='viewport' content='initial-scale=1.0, maximum-scale=1.0' />
<style>
html,body {
  height:100%;
  padding:0;
  margin:0;
  border:0;
  overflow:hidden;
}
textarea#field1 {
  font-weight: bold;
}
textarea {
  display: block;
  font-family: fixed;
  font-size: 10px;
  padding:0;
  margin:0;
  height: 99%;
  width: 99%;
}
</style>
</head>
<body>
<textarea id="field1"></textarea>
<script type="text/javascript" src="js/wc_simple.js"></script>
</body>
</html>
File wc_simple.js:
var has_focus = false;
var field1 = {};
var onICHostReady = function(version) {
    if ( version != "1.0" ) {
        alert('Invalid API version');
    }
    field1 = document.getElementById("field1");
    field1.addEventListener('focus', (event) => {
        if (has_focus === false) {
            gICAPI.SetFocus();
        }
    });
    gICAPI.onData = function(content) {
        field1.value = content;
    };
    gICAPI.onFocus = function(polarity) {
        has_focus = polarity;
        if (has_focus === true) {
            field1.focus();
        }
    };
    gICAPI.onFlushData = function() {
        gICAPI.SetData( field1.value );
    };
    gICAPI.onStateChanged = function(ps) {
        var params = JSON.parse(ps);
        if ( params.active ) {
            field1.disabled = false;
        } else {
            field1.disabled = true;
        }
    };
}