philippfrenzel/yii2fullcalendar

View on GitHub
yii2fullcalendar.php

Summary

Maintainability
B
6 hrs
Test Coverage
<?php

 /**
 * This class is used to embed FullCalendar JQuery Plugin to my Yii2 Projects
 * @copyright Frenzel GmbH - www.frenzel.net
 * @link http://www.frenzel.net
 * @author Philipp Frenzel <philipp@frenzel.net>
 *
 */

namespace yii2fullcalendar;

use Yii;
use yii\web\View;
use yii\helpers\Html;
use yii\helpers\Json;
use yii\web\JsExpression;
use yii\base\Widget as elWidget;

class yii2fullcalendar extends elWidget
{

    /**
    * @var array options the HTML attributes (name-value pairs) for the field container tag.
    * The values will be HTML-encoded using [[Html::encode()]].
    * If a value is null, the corresponding attribute will not be rendered.
    */
    public $options = [
        'class' => 'fullcalendar'
    ];

    /**
     * @var bool $theme default is true and will render the jui theme for the calendar
     */
    public $theme = true;
  
    /**
    * @var the name of the theme how the calendar should be displayed. default bootstrap 3
       * Available Options
    * 
    */
    public $themeSystem = 'bootstrap3';

    /**
     * @var array clientOptions the HTML attributes for the widget container tag.
     */
    public $clientOptions = [
        'weekends' => true,
        'editable' => false,
        'aspectRatio' => 1.35
    ];

    /**
     * @var string defaultView will define which view renderer will initially be used for displaying calendar events
     */
    public $defaultView = 'month';

    /**
    * Holds an array of Event Objects
    * @var array events of yii2fullcalendar\models\Event
    * @todo add the event class and write docs
    **/
    public $events = [];

    /**
     * Add custom buttons to the calendar header
     * @var array customButtons
     */
    public $customButtons = [];

    /**
     * Define the look n feel for the calendar header, known placeholders are left, center, right
     * @var array header format
     */
    public $header = [
        'center'=>'title',
        'left'=>'prev,next today',
        'right'=>'month,agendaWeek'
    ];

    /**
     * Will hold an url to json formatted events!
     * replaced by $events pls refer to fullcalendar.io documentation
     * @var url to json service
     */
    public $ajaxEvents = NULL;

    /**
     * wheather the events will be "sticky" on pagination or not. Uncomment if you are loading events
     * separately from the initial options.
     * @var boolean
     */
    //public $stickyEvents = true;
    
    /**
    * public string/integer $contentHeight
    */
    public $contentHeight = NULL;

    /**
     * tell the calendar, if you like to render google calendar events within the view
     * @var boolean
     */
    public $googleCalendar = false;

    /**
     * the text that will be displayed on changing the pages
     * @var string
     */
    public $loading = 'Loading ...';

    /**
     * internal marker for the name of the plugin
     * @var string
     */
    private $_pluginName = 'fullCalendar';
    
     /**
     * The javascript function to us as en onLoading callback
     * @var string the javascript code that implements the onLoading function
     */
    public $onLoading = "";

    /**
     * The javascript function to us as en eventRender callback
     * @var string the javascript code that implements the eventRender function
     */
    public $eventRender = "";

    /**
     * The javascript function to us as en eventAfterRender callback
     * @var string the javascript code that implements the eventAfterRender function
     */
    public $eventAfterRender = "";

    /**
     * The javascript function to us as en eventAfterAllRender callback
     * @var string the javascript code that implements the eventAfterAllRender function
     */
    public $eventAfterAllRender = "";

     /**
     * The javascript function to us as en eventDrop callback
     * @var string the javascript code that implements the eventDrop function
     */

    public $eventDrop = "";
    
     /**
     * The javascript function to us as en eventResize callback
     * @var string the javascript code that implements the eventResize function
     */

    public $eventResize = "";

    /**
     * A js callback that triggered when the user clicks an event.
     * @var string the javascript code that implements the eventClick function
     */
    public $eventClick = "";

    /**
     * A js callback that triggered when the user clicks an day.
     * @var string the javascript code that implements the dayClick function
     */
    public $dayClick = "";

    /**
     * A js callback that will fire after a selection is made.
     * @var string the javascript code that implements the select function
     */
    public $select = "";

    /**
     * Initializes the widget.
     * If you override this method, make sure you call the parent implementation first.
     */
    public function init()
    {
        //checks for the element id
        if (!isset($this->options['id'])) {
            $this->options['id'] = $this->getId();
        }
        //checks for the class
        if (!isset($this->options['class'])) {
            $this->options['class'] = 'fullcalendar';
        }

        parent::init();
    }
    
    /**
     * Renders the widget.
     */
    public function run()
    {
        $this->options['data-plugin-name'] = $this->_pluginName;

        if (!isset($this->options['class'])) {
            $this->options['class'] = 'fullcalendar';
        }

        echo Html::beginTag('div', $this->options) . "\n";
            echo Html::beginTag('div',['class'=>'fc-loading','style' => 'display:none;']);
                echo Html::encode($this->loading);
            echo Html::endTag('div')."\n";
        echo Html::endTag('div')."\n";
        $this->registerPlugin();
    }

    /**
    * Registers the FullCalendar javascript assets and builds the requiered js  for the widget and the related events
    */
    protected function registerPlugin()
    {
        $id = $this->options['id'];
        $view = $this->getView();

        /** @var \yii\web\AssetBundle $assetClass */
        $assets = CoreAsset::register($view);

        //by default we load the jui theme, but if you like you can set the theme to false and nothing gets loaded....
        if($this->theme == true)
        {
            ThemeAsset::register($view);
        }
    
    if (array_key_exists('defaultView',$this->clientOptions) && ($this->clientOptions['defaultView'] == 'timelineDay' || $this->clientOptions['defaultView'] == 'timelineWeek' || $this->clientOptions['defaultView'] == 'timelineMonth' || $this->clientOptions['defaultView'] == 'agendaDay'))
        {
            SchedulerAsset::register($view);
        }    

        if (isset($this->options['lang']))
        {
            $assets->language = $this->options['lang'];
        }

        if ($this->googleCalendar)
        {
            $assets->googleCalendar = $this->googleCalendar;
        }

        $js = array();

        if($this->ajaxEvents != NULL){
            $this->clientOptions['events'] = $this->ajaxEvents;
        }
        
    if(!is_null($this->contentHeight) && !isset($this->clientOptions['contentHeight']))
        {
            $this->clientOptions['contentHeight'] = $this->contentHeight;
        }

        if(isset($this->customButtons) && !isset($this->clientOptions['customButtons']))
        {
            $this->clientOptions['customButtons'] = $this->customButtons;
        }

        if(is_array($this->header) && isset($this->clientOptions['header']))
        {
            $this->clientOptions['header'] = array_merge($this->header,$this->clientOptions['header']);
        } else {
            $this->clientOptions['header'] = $this->header;
        }

        if(isset($this->defaultView) && !isset($this->clientOptions['defaultView']))
        {
            $this->clientOptions['defaultView'] = $this->defaultView;
        }

        // clear existing calendar display before rendering new fullcalendar instance
        // this step is important when using the fullcalendar widget with pjax
        $js[] = "var loading_container = jQuery('#$id .fc-loading');"; // take backup of loading container
        $js[] = "jQuery('#$id').empty().append(loading_container);"; // remove/empty the calendar container and append loading container bakup

        $cleanOptions = $this->getClientOptions();
        $js[] = "jQuery('#$id').fullCalendar($cleanOptions);";

        /**
        * Loads events separately from the calendar creation. Uncomment if you need this functionality.
        *
        * lets check if we have an event for the calendar...
            * if(is_array($this->events))
            * {
            *    foreach($this->events AS $event)
            *    {
            *        $jsonEvent = Json::encode($event);
            *        $isSticky = $this->stickyEvents;
            *        $js[] = "jQuery('#$id').fullCalendar('renderEvent',$jsonEvent,$isSticky);";
            *    }
            * }
        */

        $view->registerJs(implode("\n", $js),View::POS_READY);
    }

    /**
     * @return array the options for the text field
     */
    protected function getClientOptions()
    {
        $id = $this->options['id'];
      
    if ($this->onLoading)
            $options['loading'] = new JsExpression($this->onLoading);
        else {
        $options['loading'] = new JsExpression("function(isLoading, view ) {
                jQuery('#{$id}').find('.fc-loading').toggle(isLoading);
        }");
    }
                                               
        //add new theme information for the calendar                                       
        $options['themeSystem'] = $this->themeSystem;
                                               
        if ($this->eventRender){
            $options['eventRender'] = new JsExpression($this->eventRender);
        }
        if ($this->eventAfterRender){
            $options['eventAfterRender'] = new JsExpression($this->eventAfterRender);
        }
        if ($this->eventAfterAllRender){
            $options['eventAfterAllRender'] = new JsExpression($this->eventAfterAllRender);
        }

        if ($this->eventDrop){
            $options['eventDrop'] = new JsExpression($this->eventDrop);
        }
        
        if ($this->eventResize){
            $options['eventResize'] = new JsExpression($this->eventResize);
        }        

        if ($this->select){
            $options['select'] = new JsExpression($this->select);
        }
                                               
        if ($this->eventClick){
            $options['eventClick'] = new JsExpression($this->eventClick);
        }
        if ($this->dayClick){
            $options['dayClick'] = new JsExpression($this->dayClick);
        }

        if (is_array($this->events) || is_string($this->events)){
            $options['events'] = $this->events;
    }

        $options = array_merge($options, $this->clientOptions);
        return Json::encode($options);
    }

}