ED php framework :: Tutorial #5
Create new or integrate a 3rd party widget
There is almost no difference whether you'd like to create a new or to integrate an existing widget. A widget may rely on images, stylesheets, locale files and most probably javascript classes. All you have to do is to gather together the needed resources under one directory.

We place all our advanced widgets under "protected/widgets". If you have read the previous chapter, explaining in details how the framework works, then you already know that in 90% of the cases we need 2 classes with the same name. A PHP class and a javascript class with the same name. Both need to extend TWebControl base class. Actually we need the javascript class only if there will be ajax communication with the widget or it has "postback value", which need to be filled every time a page action takes place like clicking a button.

Because nowadays jQuery is on the top of the hype, we will build a widget called TjQueryDatePicker, which encapsulates an existing widget. First, create a directory called "3rd_party_jquery" under "protected/widgets". Then, inside the new directory create the following sub-directories - "css", "js", "php" and "tpl". Now take all jQuery files, which are required and place them under "css" and "js" respectively. We won't do it here, but you'll find them in the attached file at the bottom of the page. Then it's time to define our widget as html.
3rd_party_jquery/tpl/
jquery_date_picker.tpl
<!-- jQuery date picker -->
 
<input type='text' id='{#name}' style='{#style}' />
 
<!-- // jQuery date picker -->
You can see many strings like {#xxx}, which will be replaced by the php class. Now it's time to add:
3rd_party_jquery/js/
jquery_date_picker.js.php
<?php
    Header("Content-Type:text/javascript");
?>
 
 
/**
 * TjQueryDatePicker
 */
var TjQueryDatePicker = TClass.extend(TWebControl, {
 
    /**
     * Constructor
     */
    initialize: function(name, args) {
        $C(TWebControl).initialize.call(this, name, args);
    },
 
 
 
    /**
     * Set value
     */
    setValue: function(aValue) {
        document.getElementById(this.getName()).value = aValue;
    },
 
 
    /**
     * Get value
     */
    getValue: function() {
        return document.getElementById(this.getName()).value;
    },
 
 
    /**
     * Get postback data
     */
    getPostbackData: function() {
        return document.getElementById(this.getName()).value;
    },
 
 
    /**
     * Finalize
     */
    finalize: function() {
        $("#" + this.getName()).datepicker();
    }
 
});
We will define only 2 methods: setValue and getValue. If we want to make it more advance we can add also setEnabled, setVisible, etc. Both methods just manipulate the input field, which we placed in the tpl file. The method "finalize" is called by the framework, here you have to place all the necessary logic to complete your widget. Logic like binding event handlers, building extra html, etc. And finally we will add the php class.
3rd_party_jquery/php/
TjQueryDatePicker.inc
<?php
 
    /**
     * <pre>
     *
     * TjQueryDatePicker is a simple wrapper around "jQuery date picker" js and css files
     *
     * <u>Settings through TWebControl (Optional):</u>
     *
     *     setProperty("Style", "width:100px");
     *
     * </pre>
     *
     * @package 3rd_party.widgets
     */
    class TjQueryDatePicker extends TWebControl {
 
        /**
         * Constructor
         */
        public function __construct() {
            parent::__construct();
    	  }
 
 
 
 
        /**
         * On init
         */
        protected function OnInit() {
            page()->includeScript($this->uri("js/jquery.v132.js"));
            page()->includeScript($this->uri("js/jquery-ui.v172.js"));
            page()->includeScript($this->uri("js/jquery_date_picker.js.php"));
 
            page()->includeStylesheet($this->uri("css/jquery-ui.css"));
            page()->includeStylesheet($this->uri("css/ui.theme.css"));
        }
 
 
        /**
         * Gets the html code for this web control
         * 
         * @return string The html code for this web control
         */
        protected function toHtml() {
            $widgetHTML = TContent::load($this->file("tpl/jquery_date_picker.tpl"));
            $widgetHTML->replace("{#name}", $this->getName());
            $widgetHTML->replace("{#style}", $this->getProperty("Style", ""));
 
            return $widgetHTML->toString();
        }
 
 
        /**
         * Post back data event
         */
        protected function OnPostBackData() {
            $this->setValue(request()->getParam($this->getName()), !AJAX_REQUEST ? TRUE : FALSE);
        }
 
 
        /**
         * Event method triggered for every control to 
         * register itself with the agent
         */
    	  protected function OnFinalize() {
            agent()->registerWidget($this->getName(), "TjQueryDatePicker");
    	  }
 
 
        /**
         * Event method triggered for every control to apply 
         * possible state changes
         */
    	  protected function OnPossibleStateChange() {
    	      if ($this->isValueChanged()) {
    	          agent()->call("page.{$this->fName}.setValue", $this->getValue());
    	      }
    	  }
    }
?>
 
TWebControl like TPage offers many methods for override, like: OnPostBackData, OnFinalize, OnPossibleStateChange, OnLoadState, OnSaveState, etc. Actually we deal only with the first 3 methods. With the first one we set the current widget state after action has been made. Usually we take the value from the request. Another possible source could be the "data model". It depends how the widget is designed. By overriding "OnFinalize" we register the javascript class with the javascript "page" variable. Apart of this we may call the widget's javascript methods. This event is invoked only once, when the page is constructed. "OnPossibleStateChange" is the last invoked event. Here we check if there are some properties that has been changed and usually we call JavaScript methods to update the state of our widget in the browser.

Now let's take a look at the "toHtml" method. Here we will load the template and replace all {#xxx}-like strings with suitable values. The most useful method here is:
$this->getProperty("Style", "")
The second argument "" is the default value in case "Style" is not set. You may consider the method "hasProperty" as well.

Well, that's it. This simple Widget API helps us to encapsulate any javascript-based widget on the web. This is useful, because every widget comes with it's own javascript and css structure and tweaks and putting them directly on a web page may create a lot of mess. But, with a small, simple wrapper they can fit the framework structure quite well.

DOWNLOAD CUSTOM WIDGETS