Page tree
Skip to end of metadata
Go to start of metadata

This function creates a new base widget from scratch.  The implementation of the widget will require advanced JavaScript coding.

Parameter:

  • config object - JavaScript object containing configuration properties

Configuration Options:

  • name - the new base widget name; also referred to as the "field type"
  • newId - the default id prefix - used to assign id's when the element is first created; for example if the newId is "Map", new elements created will have id's of Map1, Map2, Map3, etc.
  • menuName - pull-down menu name for the widget
  • defaults - an object with name/value pairs for default property settings for this base widget; these values can overridden by the pui.toolbox.add() function
  • propertySetters - an object representing a set of functions that are triggered when a particular widget property is changed; the "field type" function can be used as the main function to construct the widget; each function will receive a configuration parameter with the following properties:
    • originalValue - original value before the property was changed
    • newValue - new value (before scripting evaluation)
    • value - new value (after scripting evaluation)
    • properties - object representing the current property names and values for the widget
    • dom - reference to the main DOM element for the widget
    • oldDom - reference to the old DOM element (this will only be different from dom if the change to the widget property required the dom element to be changed or recreated)
    • propertyName - the name of the widget property being changed
    • design - flag that specifies whether the widget property is being changed at design time or at run time 
    • designItem - reference to the design item object for this widget
    • resizer - reference to the resizer object for this widget
    • evalProperty - function that can be used to evaluate scripted properties
  • globalPropertySetter - a global function that is triggered every time any widget property is changed. globalPropertySetter is discarded when a widget is defined as a pui.BasicWidget–it uses either the options "constr" or render and getValue.
  • tag - the tag of the main DOM element; if omitted, "div" tag is assummed
  • inputType - if the "input" tag is specified, this option specifies the input type, such as "text", "checkbox", "radio", "password", etc.
  • resizable - if false is specified, the widget cannot be resized in the designer
  • canBelongToGrid - if false is specified, the widget cannot be dragged into a subfile grid
  • dependencies - Array of strings and/or objects with URLs pointing to JavaScript or CSS files. At run time, these will be loaded into your session (if not there already) only if your widget is used on the current format.  At design time, all dependencies are loaded when the Visual Designer is loaded or Genie is switched into Design Mode. (Note that this configuration option is available starting with Profound UI Version 5, Fix Pack 8.0)
    • Strings: when the string contains a URL the CSS or JavaScript file will always be loaded before a screen renders or Designer loads.
    • Objects: A script can be conditionally loaded, according to the return value of a custom function. Supply an object with a "script" property containing a string, the URL of a conditionally loaded JavaScript file. Also supply a function to a "condition" property. The condition function should return true for when the script should be loaded prior to rendering. If the function returns false, then the script does not load. The function accepts these parameters:
      • properties - an Object with the current properties and values of the widget.
      • boundData - an Object with fields and values loaded from the server-side program.
      • designer - a boolean value. True means the page is Visual Designer or Node Designer; false means the page is not in a Designer.
  • render - A function that makes the custom widget use bidirectional custom properties if "getValue" is also supplied. The widget becomes a subclass of pui.BasicWidget, and the "render" function gets assigned to that instance of pui.BasicWidget. Profound UI calls "render" on bidirectional widgets after setting all properties. Render should be used to draw content instead of using property-setters. If the "constr" option is set, then "render" is ignored. Within render(), the special word, "this", points to the instance of pui.BasicWidget. (The "render" option is available with Profound UI Version 6 Fix Pack 12.0 and later.)
  • getValue - A function that makes the custom widget use bidirectional custom properties if "render" is also supplied. The widget becomes a subclass of pui.BasicWidget, and the "getValue" function gets assigned to that instance of pui.BasicWidget. Profound UI calls "getValue" when building a screen response to send to the server-side program. Get value should fetch input values from custom elements and return a String. If the "constr" option is set, then "getValue" is ignored. Within render(), the special word, "this", points to the instance of pui.BasicWidget. (The "getValue" option is available with Profound UI Version 6 Fix Pack 12.0 and later.)
  • constr - A reference to a class constructor of a subclass of pui.BasicWidget, which handles rendering and routing data to the server-side program. (See the pui.BasicWidget section below) (The "constr" option is available with Profound UI Version 6 Fix Pack 12.0 and later.)

Example 1:

The following code creates a "google maps" base widget.

pui.widgets.add({
  name: "google maps",
  newId: "Map",
  menuName: "Google Maps Widget",

 // Scripts that are loaded only when this widget is first used.
  dependencies: ["/myproject/custom.css", "/myproject/custom.js",

    // A script that is loaded conditionally, only when the width property's value is 400px.
    {"script": "/myproject/custom2.js",
     "condition": function (properties, boundData, isDesigner){
        // The property is hard-coded in Designer or a Genie screen:
        if (typeof properties["width"] != "object") return properties["width"] == "400px";
        // The property is bound to an RPG field in a Rich Display File.
        else if (properties["width"] != null && typeof properties["width"]["fieldName"] == "string"){
          var value = boundData[ properties["width"]["fieldName"].toUpperCase() ];
          return value == "400px";
        }
        else if (isDesigner) return true; //Always load when in Visual Designer.
        return false;
      }
    }],

 // default properties for the widget
  defaults: {
    "width": "400px",
    "height": "300px",
    "z index": "25",
    "background color": "#FFFFFF"
  },

  // property setter functions
  propertySetters: {

    // this will fire when the field type property is set to "google maps"
    // all initialization code for the element goes here
    "field type": function(parms) {
      if (parms.design) {
        // all design mode content creation code goes here
        // add preview image
        var img = document.createElement("img");
        img.src = "/profoundui/proddata/images/GoogleMaps.jpg";
        img.style.position = "absolute";
        img.style.left = "0px";
        img.style.top = "0px";
        img.style.width = parms.dom.style.width;
        img.style.height = parms.dom.style.height;
        parms.dom.appendChild(img);
        parms.dom.style.overflow = "hidden";
      }
      else {
        // runtime content creation code goes here
        // clear
        parms.dom.innerHTML = "";
        // get url property - evalProperty will evaluate any js expressions that may have been used to build the property
        address = parms.evalProperty("google maps address");
        // populate the widget's dom element
        if (address == null || address == "") {
          parms.dom.innerHTML = "Google Maps Address property not specified.";
        }
        else {
          // here, we build an iframe element and put it into the dom
          var widthHeight = "";
          var width = parseInt(parms.properties["width"]);
          var height = parseInt(parms.properties["height"]);
          if (width > 0) widthHeight += " width=" + width;
          if (height > 0) widthHeight += " height=" + height;
          var url = "http://maps.google.com/maps?hl=enl&q=" + encodeURIComponent(address) + "&ie=UTF8&hq=&hnear=" + encodeURIComponent(address) + "&output=embed";
          var html = "<iframe src=\"" + url;
          html += '" frameborder="0" scrolling="no" marginheight="0" marginwidth="0"';
          html += '"' + widthHeight + '>';
          parms.dom.innerHTML = html;
        }
      }
    },

    // this will fire when the width property of the element changes
    "width": function(parms) {
      if (parms.design) {
        // adjust preview image width
        parms.dom.firstChild.style.width = parms.value;
      }
    },

    // this will fire when the height property of the element changes
    "height": function(parms) {
      if (parms.design) {
        // adjust preview image height
        parms.dom.firstChild.style.height = parms.value;
      }
    }

  }

});

Example 2:

The following code adds a widget that uses pui.BasicWidget without needing to define a class.

pui.widgets.add({
  name: "color picker",     //widget name - this is placed into the standard "field type" property
  newId: "ColorPicker",     //default id prefix - used to assign ID; e.g. ColorPicker2.
  menuName: "Color Picker", //Name shown in the Properties Window when the widget is selected.
  
  // Default properties for the widget
  defaults: {
    "width": "100px",
    "height": "22px",
    "color picker label": "Color:"
  },
  
  // Note: "this" in the "render" function refers to an instance of pui.BasicWidget that Profound UI automatically creates.
  render: function(){
    var value = this.evalProperty("color picker value");
    var labelText = this.evalProperty("color picker label");
    var disabled = this.evalProperty("disabled") == 'true';
    
    if (this.design){
      var bgcolor = disabled ? '#aaa' : '#eee';
      
      // Use a mock-up of the input so that dragging or selecting it will not popup the color picker.
      this.dom.innerHTML = labelText+' <div style="min-width:50px; min-height:16px; display:inline-block; background-color:'
      + bgcolor +'; border:outset 2px black;">'+value+'</div>';
    }
    else {
      if (this.label == null){
        this.label = document.createElement('label');
        var span = document.createElement('span');
        this.label.appendChild( span );
        this.dom.appendChild(this.label);
      }
      
      if (this.input == null){
        this.input = document.createElement('input');
        this.label.appendChild(this.input);
        this.input.addEventListener('change', this);
      }
      
      if (!pui.is_ie) this.input.type = 'color';
      this.input.value = value;
      this.input.style.width = '50px';
      this.input.disabled = disabled;
      this.label.children[0].innerHTML = labelText;
    }
  },
  
  // Note: "this" in the "getValue" function refers to an instance of pui.BasicWidget that Profound UI automatically creates.
  getValue: function (propname){
    if (propname == 'color picker value' && this.input) return this.input.value;
    return this.evalProperty(propname);
  }
});

Example 3:

The following code adds a widget defined in a subclass of pui.BasicWidget.

pui.widgets.add({
  name: "color picker",     //widget name - this is placed into the standard "field type" property
  newId: "ColorPicker",     //default id prefix - used to assign ID; e.g. ColorPicker2.
  menuName: "Color Picker", //Name shown in the Properties Window when the widget is selected.
  
  // Default properties for the widget
  defaults: {
    "width": "100px",
    "height": "22px",
    "color picker label": "Color:"
  },
  
  constr: puicustom.colorpicker
});

"puicustom.colorpicker" must be defined elsewhere as constructor of a class that inherits from pui.BasicWidget. The subclass must implement "render" and "getValue" at a minimum. See pui.BasicWidget.