In our previous post, we had a great discussion on building the base classes that we can use to turn any javascript UI into a Yii widget. What we did not do was to see how we can use the base classes to create an actual example widget.

We are going to look at how we can turn one of those WYSIWYG editors into a Yii widget. They are very essential when you decide to create a blog website. You cannot do without a very good one.

There are many WYSIWYG editors out there but personally, there are two which I have come to love; NicEdit and Markitup. So in this post, we will see how we can turn the NicEdit into a Yii widget.

For those who are not familiar with NicEdit, it is a WYSIWYG editor for websites. Its goal is to be as simple and fast as possible for users of your application. NicEdit is extremely lightweight and can be easily integrated in any site with minimal impact while providing visitors an effective means to express themselves in rich text. NicEdit is a Lightweight, Cross Platform, Inline Content Editor to allow easy editing of web site content on the fly in the browser.

NicEdit falls into the category of UI which are used to collect user input. So the NicEdit widget we will create will extend the JsInputWidget.

I will call the widget NicEdit after it original name.

class NicEdit extends JsInputWidget {
    . /**
     *
     * @var boolean Whether an HTML label should be rendered 
     */
    public $renderLabel = true;
}

In the class we define a variable $renderLabel. Its value indicates if we should render a label for the widget.
The base class CWidget provides two methods we need to override to achieve our goal; the init and run method.
For our NicEdit implementation, we will only override the run method.

public function run() {
    list($name, $id) = $this->resolveNameID();

    if (isset($this->htmlOptions['id']))
        $id = $this->htmlOptions['id'];
    else
        $this->htmlOptions['id'] = $id;
    if (isset($this->htmlOptions['name']))
        $name = $this->htmlOptions['name'];
    else
        $this->htmlOptions['name'] = $name;

    if ($this->hasModel()) {
        if ($this->renderLabel) {
           echo CHtml::activeLabelEx($this->model, $this->attribute);
        }
       echo CHtml::activeTextArea($this->model,$this->attribute,
                                       $this->htmlOptions);
    }
    else {
        if ($this->renderLabel) {
            echo CHtml::label($name, $id);
        }
        echo CHtml::textArea($name, $this->value,$this->htmlOptions) . "\n";
    }
    $this->registerCorescript();
}

We first get the name and id to use for the widget by calling the resolveNameID(). If we specified an id or name in the htmlOptions property, they will take precedence over the id and name we have generated.
We then check if this widget has a model associated with it. If it is set, we call the activeTextArea CHtml otherwise we just call textArea. We then register our javascript code by calling the registerCorescript.

 private function registerCorescript(){
    $id = $this->htmlOptions['id'];
    $basedir = dirname(__FILE__) . '/widgetfiles';
    $baseUrl = Yii::app()->getAssetManager()->publish($basedir);
    if(!isset($this->options['iconsPath'])){
       $this->options['iconsPath'] = $baseUrl . '/images/nicEditorIcons.gif';
    }
    $options = CJavaScript::encode($this->options);
    $script = "
        bkLib.onDomLoaded(function() {
            new nicEditor($options).panelInstance('$id');
            jQuery('#$id').closest('form').submit(function(){
                    nicEditors.findEditor('$id').saveContent();
            });
        })
     ";
    $cs = Yii::app()->getClientScript();
    $cs->registerScript("nic_$id", $script);
 $cs->registerScriptFile($baseUrl . '/js/nicEdit.js');
}

The PHP options parameter is encoded into json object and passed to the nicEditor constructor together with the id of the textarea.
Let’s see how we can use the widget in our view file.

<div class="row">
  <?php
     $this->widget('NicEdit', array(
         'attribute'=>'profile',
          'model' => $model,
           'htmlOptions'=>array(
                   'style'=>'width:600px; height:120px;',
            ),
         'options'=>array(
           'buttonList'=>array( 'fontSize','fontFormat','fontFamily','bold',
                'italic','underline','strikeThrough','subscript',
               'superscript','left','center','right','justify','ol','ul','hr'
              )
            )
       ));
  ?>
 <?php echo $form->error($model,'profile'); ?>
</div>

I believe you can now go and find any javascript widget and turn it into a Yii widget you can add to your app. Have fun.

Resources

NicEdit