📜 ⬆️ ⬇️

MODx - own ajax calendar of events / news without Ditto

They gave me the other day a puzzle: make a calendar of events on ModX Evolution.
I sincerely love this engine, for its unprecedented flexibility and personal clarity to me.

The task seemed simple, but as it was met, I met with a couple of difficult moments.
So, who wants to make a calendar on your site with a pop-up list of events - I ask for a habrokat!



To complete the task we need:

')
First, create a TV parameter for event documents. Go to the modx admin panel in Elements-> Element Management-> Parameters (TV) -> New Parameter (TV)
: event_date
: event_date
: Date
: , , .

Now, when you enter the event, this parameter will appear below, when you click, there will be a window for choosing a date, on which we will display this event in the calendar.

Next, we need to write a snippet that will produce an array of events for jQueryUI.datepicker. In general, this plugin is not intended for
output events, and to select dates. Perhaps using it for another function is not the right decision, but there are several reasons why I use it like this:

Firstly, I already have jQueryUI on the site, so why connect something else?
Secondly, the datepicker is perfectly customizable, it is possible to specify the range of the displayed dates, hang up the event to select the date, change the month, and so on.
All this will allow you to create a nice calendar of events with ajax requests without inventing your own bicycle.
Something like this I thought.

In fact, it turned out that this approach carries a couple of inconveniences, but about them later.

Snippet eventsCalendar. Work on the server side.

So, we write snippet. For some time now, I already can’t bring out “hello world!” Without writing a class, so sorry in advance.

 <?php class eventsCalendar { var $id; //  -  var $dateFormat = '%d %b %Y %H:%M'; //  ,  strftime() var $dateTV = 'event_date'; //  TV  modx   var $tplEvent = 'tplEvent'; //     var $tplMain = 'tplCalendar'; //      var $conv = 0; //      cp1251  utf8.   -  . /*   */ function error($err) { $arr = array( 'no_id' => '   id    ', 'no_action' => '     ajax .', 'no_result' => '    .' ); return $arr[$err]; } /*  ,    ,    */ function getEvents($id = '', $month = '', $year = '') { global $modx; if (empty($id)) {return $this->error('no_id');} if (empty($month)) {$month = date('m');} if (empty($year)) {$year = date('Y');} if (strlen($month) == 1) {$month = '0'.$month;} /*    ,    id   */ $tmp = $modx->getDocumentChildrenTVars($id, array('id',$this->dateTV)); /*         */ if (empty($tmp)) {return $this->error('no_result');} else { foreach ($tmp as $v) { $d = strftime('%Y-%m', strtotime($v[0]['value'])); if ($d == $year.'-'.$month) {$ids[] = $v[1]['value'];} $dates_arr[$v[1]['value']] = $v[0]['value']; } } /*      $ids,     ,      ,      .     */ $arr = $modx->getDocuments($ids, 1, 0, "id,pagetitle,introtext", "", 'pub_date ASC, id', 'ASC'); /*      -    ,     */ if (empty($arr)) {return json_encode(array());} /*    -   ,      */ /*         */ $tpl = $modx->getChunk($this->tplEvent); $i = 1; foreach ($arr as $v) { /*        */ $did = $v['id']; $url = $modx->makeUrl($did); $date = strftime($this->dateFormat, strtotime($dates_arr[$did])); $date2 = strftime('%Y-%m-%d', strtotime($dates_arr[$did])); $desc = $v['introtext']; $title = $v['pagetitle']; /*    ,       */ if (isset($date3) && $date3 != $date2) {$i = 1;} $date3 = $date2; /*        modx */ $placeholders = array('[+ec.date+]','[+ec.title+]','[+ec.url+]','[+ec.desc+]','[+ec.num+]'); $values = array($date, $title, $url, $desc, $i); $text = str_replace($placeholders, $values, $tpl); /*    ,     cp1251. */ if ($this->conv != 0) {$dates[$date2] .= iconv('cp1251', 'utf-8', $text);} else {$dates[$date2] .= $text;} $i++; } /* .. jqueryui.datepicker   '','css class',' ' -       */ foreach($dates as $k => $v) { $dates2[] = array($k, '', $v); } /*     json */ return json_encode($dates2); } /*      ,   */ function output($tpl) { global $modx; $tpl = $modx->getChunk($tpl); echo $tpl; } } /*  ,  ,     modx */ $Cal = new eventsCalendar; $Cal->id = $id; //  ! /*       -   */ if (!empty($dateTV)) {$Cal->dateTV = $dateTV;} if (!empty($dateFormat)) {$Cal->dateFormat = $dateFormat;} if (!empty($tplEvent)) {$Cal->tplEvent = $tplEvent;} if (!empty($tplMain)) {$Cal->tplMain = $tplMain;} if (!empty($conv)) {$Cal->conv = $conv;} /*     ajax -       */ if ($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') { $action = $_POST['action']; if (!empty($action)) { switch($action) { case 'getEvents': echo $Cal->getEvents($Cal->id, $_POST['month'], $_POST['year']); break; } } else { echo $Cal->error('no_action'); } die(); } /*    -     */ else { $Cal->output($Cal->tplMain); } ?> 


Next, go to the modx admin in the snippets, create a new one, call it eventsCalendar and copy the above.
We created a new snippet and call it anywhere on the page like this:
[!eventsCalendar?
&id=`13`
&dateTV=`event_date`
&dateFormat=`%d %b %Y %H:%M`
&tplMain=`tplCalendar`
&tplEvent=`tplEvent`
!]

See the parameters at the end of the topic.

Only while it will not display anything, because we have not written templates.


Chunky. Work on the client side.

Let's start with the small one - the template of one tplEvent event.
 <div class='event'> <span class='num'><b>[+ec.num+].</b></span> <span class='date'>[+ec.date+]</span> <span class='link'><a href='[+ec.url+]' target='_blank'>[+ec.title+]</a></span> <br /> <span class='notice'>[+ec.desc+]</span> </div> <br /> 


Next, a bigger template.
I’ll skip all the artwork, as there’s quite a lot of scribbling there, but here I’ll only provide the main thing, the rest is an attachment.

You need to connect the library (follow the path).
 <script type='text/javascript' src='[(site_url)]inc/js/jquery-1.4.4.min.js'></script> <script type='text/javascript' src='[(site_url)]inc/js/jquery-ui-1.8.6.custom.min.js'></script> <script type='text/javascript' src='[(site_url)]inc/js/jquery.ui.datepicker-ru.js'></script> <!--  datepicker --> <script type='text/javascript' src='[(site_url)]inc/js/jquery.qtip.js'></script> 


Now, the main magic.
 <script type='text/javascript'> $(document).ready(function() { class_enabled = 'enabled'; //   ,     class_disabled = 'disabled'; //   element = '#Calendar'; //  DOM     url = '/[~[*id*]~]'; //     ajax,   -  dates = getEvents(); //     ajax Calendar(dates); //         Qtip(); //  qTip,    }); //     . function Calendar(dates) { $(element).datepicker({ language: 'ru', inline: true, dateFormat: 'dd.mm.yy', //    -     .  ,  1   qTip, //       DOM . onChangeMonthYear: function(year, month) { dates = getEvents(year, month); window.setTimeout( function() { Qtip() }, 1000 ); }, //     -     ,   . //  3: /,    ,    title  td. beforeShowDay: function(d) { var date = $.datepicker.formatDate('yy-mm-dd', d); for (i = 0, c = dates.length; i < c; i++) { if (date == dates[i][0]) { return [true, class_enabled, dates[i][2]]; } } return [false, class_disabled]; }, //      .   -   . onSelect: function() {return false;} }); } //     ajax   . //    -  , , ,     -   . //      ,     ,     . function getEvents(year, month) { $.ajaxSetup({async: false}); $.post(url, {action: 'getEvents', month: month, year: year}, function(data) { if (data == 'null') {data = '[]';} dates = jQuery.parseJSON(data); response = dates; } ) return response; } //    qTip. //       .    title . function Qtip() { $(element + ' .' + class_enabled).qtip({ prerender: true, show: {when: {event: 'mouseover'}, effect: {length: 0}, solo: true}, hide: {when: {event: 'unfocus'}, effect: {length: 0}}, position: { corner: { target: 'center', tooltip: 'topLeft' } }, style: {height: 100,width: 300} }); } </script> 

 <div id='Calendar'></div> -- ,     

I still use some things to darken the calendar when the month changes and display the loading indicator.
Nothing complicated, you can see here .

How it works?

When you first open the page, we just get the tplCalendar template. After it is loaded, the function of requesting an array of dates starts.
As soon as an array arrives, a calendar is launched, which, when the date is drawn, assigns it a style and text for the tooltip.
Then qTip runs and generates a tooltip.

When changing the month, a new array of dates is requested and the pop-ups are restarted (since the DOM has changed).

At the same time, we can send events by clicking on the date (for example, go to the page with news on this date). To change the month (I have
the loading indicator comes out + the calendar itself is dimmed). The appearance of the popup window is completely customizable, both in style and in content.

Now about the shortcomings. There are several of them.

The drawbacks could have been circumvented by writing my calendar, to php for this particular task, but I decided that the merits of datepicker outweigh the disadvantages of using it to output events.

Application.

Download archive with snippet and templates
View in work (Revolution version)

Snippet parameters eventsCalendar:
& id
: ,
: [int]
: ID - .

& dateFormat
: '%d %b %Y %H:%M'
: strftime()
: .

& dateTV
: event_date
: tv
: TV modx .

& tplEvent
: tplEvent
: modx
: .

& tplMain
: tplCalendar
:
: .

& conv
: 0
: [int]
: cp1251 utf8.


Snippet placeCollers eventsCalendar:
[+ ec.num +]
. , . ,
TV . , .

[+ ec.date +]
.
[+ ec.url +]
.
[+ ec.title +]
, pagetitle modx.
[+ ec.desc +]
, introtext modx.


References to the necessary sites.


UPD.
Send bugreports to bezumkin@yandex.ru, or leave them in this thread.

UPD.2
The second version of the calendar is ready , WITHOUT the datepicker and its associated drawbacks!

Source: https://habr.com/ru/post/111155/


All Articles