Commit ae0ad422 authored by Mingsong Hu's avatar Mingsong Hu

Use JSFrame instead of Drupal modal

parent f88537b4
......@@ -49,6 +49,18 @@ libraries.fullcalendar:
- fullcalendar_view/libraries.fullcalendar-theme
- fullcalendar_view/libraries.rrule
libraries.jsframe:
remote: https://github.com/riversun/JSFrame.js
version: '1.5.16'
license:
name: MIT
url: https://github.com/riversun/JSFrame.js/blob/master/LICENSE
gpl-compatible: true
cdn:
https://cdn.jsdelivr.net/npm/jsframe.js@1.5.16/lib/jsframe.min.js
js:
/libraries/JSFrame/1.5.16/jsframe.min.js: { minified: true }
# Feature libraries.
fullcalendar:
js:
......
......@@ -51,6 +51,11 @@ function fullcalendar_view_form_node_form_alter(&$form, FormStateInterface $form
function fullcalendar_view_library_info_alter(array &$libraries, $module) {
if ('fullcalendar_view' == $module) {
// Use CDN instead of all local missing libraries.
// JSFrame.js
$cdn_library = _fullcalendar_view_use_cdn_full_path($libraries, 'libraries.jsframe', 'js');
if ($cdn_library) {
$libraries['libraries.jsframe']['js'] = $cdn_library;
}
// RRule js.
$cdn_library = _fullcalendar_view_use_cdn_full_path($libraries, 'libraries.rrule', 'js');
if ($cdn_library) {
......
......@@ -4,84 +4,12 @@
*/
(function($, Drupal) {
Drupal.behaviors.fullcalendarView = {
attach: function(context, settings) {
var calendarObjs = [];
var initialLocaleCode = 'en';
var localeSelectorEl = document.getElementById('locale-selector');
// Date entry clicked.
var slotDate;
var calendarEl = document.getElementsByClassName("js-drupal-fullcalendar");
let calendarOptions = JSON.parse(drupalSettings.calendar_options);
// Bind the render event handler.
calendarOptions.eventRender = eventRender;
// Bind the resize event handler.
calendarOptions.eventResize = eventResize;
// Bind the day click handler.
calendarOptions.dateClick = dayClickCallback;
// Bind the event click handler.
calendarOptions.eventClick = eventClick;
// Bind the drop event handler.
calendarOptions.eventDrop = eventDrop;
// Define calendar elemetns.
if (calendarEl) {
for (let i = 0; i < calendarEl.length; i++) {
var calendar = new FullCalendar.Calendar(calendarEl[i], calendarOptions);
// Render the calendar.
calendar.render();
// Language dropdown box.
if (drupalSettings.languageSelector) {
// build the locale selector's options
calendar.getAvailableLocaleCodes().forEach(function(localeCode) {
var optionEl = document.createElement('option');
optionEl.value = localeCode;
optionEl.selected = localeCode == calendarOptions.locale;
optionEl.innerText = localeCode;
localeSelectorEl.appendChild(optionEl);
});
// when the selected option changes, dynamically change the calendar option
localeSelectorEl.addEventListener('change', function() {
if (this.value) {
calendar.setOption('locale', this.value);
}
});
}
else {
$(".locale-selector").hide();
}
// Put into the calendar array.
calendarObjs[i] = calendar;
}
// Double click event.
$(".js-drupal-fullcalendar").dblclick(function() {
// New event window can be open if following conditions match.
// * The new event content type are specified.
// * Allow to create a new event by double click.
// * User has the permission to create a new event.
// * The add form for the new event type is known.
if (
slotDate &&
drupalSettings.eventBundleType &&
drupalSettings.dblClickToCreate &&
drupalSettings.addForm !== ""
) {
// Open a new window to create a new event (content).
window.open(
drupalSettings.path.baseUrl +
drupalSettings.addForm +
"?start=" +
slotDate +
"&start_field=" +
drupalSettings.startField,
"_blank"
);
}
});
}
// Dialog index.
var dialogIndex = 0;
// Dialog objects.
var dialogs = [];
/**
* Event render handler
......@@ -174,30 +102,31 @@
function eventClick(info) {
slotDate = null;
info.jsEvent.preventDefault();
if (drupalSettings.linkToEntity) {
// if (drupalSettings.linkToEntity) {
// Open a time slot details in a dialog
if (drupalSettings.dialogWindow) {
let dataDialogOptionsDetails = {};
let thisEvent = info.event;
var modalLink = $('<a id="fullcalendar-view-dialog"></a>');
dataDialogOptionsDetails.draggable = true;
dataDialogOptionsDetails.autoResize = false;
dataDialogOptionsDetails.title = thisEvent.title.replace(/(<([^>]+)>)/ig,"");
if (thisEvent.url == '') {
return false;
}
modalLink.addClass('use-ajax');
modalLink.attr('href', thisEvent.url);
modalLink.attr('data-dialog-type', 'dialog');
modalLink.attr('data-dialog-options', JSON.stringify(dataDialogOptionsDetails));
modalLink.appendTo($('body'));
const jsFrame = new JSFrame({
parentElement:document.body,//Set the parent element to which the jsFrame is attached here
});
// Position offset.
let posOffset = dialogIndex * 20;
// Dialog options.
let dialogOptions = JSON.parse(drupalSettings.dialog_options);
dialogOptions.left += posOffset;
dialogOptions.top += posOffset;
dialogOptions.title = thisEvent.title.replace(/(<([^>]+)>)/ig,"");
dialogOptions.url = thisEvent.url;
//Create window
dialogs[dialogIndex] = jsFrame.create(dialogOptions);
Drupal.attachBehaviors();
modalLink.trigger('click').remove();
// The entry element object.
let $thisEntry = $(this);
if (typeof $thisEntry.qtip === "function") {
// Hide the pop tip.
$thisEntry.qtip("hide");
}
dialogs[dialogIndex].show();
dialogIndex++;
return false;
}
......@@ -213,7 +142,7 @@
return true;
}
}
}
// }
return false;
}
......@@ -289,7 +218,94 @@
}
}
Drupal.behaviors.fullcalendarView = {
attach: function(context, settings) {
/*if (typeof calendarObjs === 'undefined') {
return;
}
else {
if (calendarObjs.length > 0) {
for (let i = 0; i < calendarObjs.length; i++) {
calendarObjs[i].render();
}
return;
}
}*/
// Language select element.
var localeSelectorEl = document.getElementById('locale-selector');
// Date entry clicked.
var slotDate;
var calendarEl = document.getElementsByClassName("js-drupal-fullcalendar");
let calendarOptions = JSON.parse(drupalSettings.calendar_options);
// Bind the render event handler.
calendarOptions.eventRender = eventRender;
// Bind the resize event handler.
calendarOptions.eventResize = eventResize;
// Bind the day click handler.
calendarOptions.dateClick = dayClickCallback;
// Bind the event click handler.
calendarOptions.eventClick = eventClick;
// Bind the drop event handler.
calendarOptions.eventDrop = eventDrop;
// Define calendar elemetns.
if (calendarEl) {
for (let i = 0; i < calendarEl.length; i++) {
var calendar = new FullCalendar.Calendar(calendarEl[i], calendarOptions);
// Render the calendar.
calendar.render();
// Language dropdown box.
if (drupalSettings.languageSelector) {
// build the locale selector's options
calendar.getAvailableLocaleCodes().forEach(function(localeCode) {
var optionEl = document.createElement('option');
optionEl.value = localeCode;
optionEl.selected = localeCode == calendarOptions.locale;
optionEl.innerText = localeCode;
localeSelectorEl.appendChild(optionEl);
});
// when the selected option changes, dynamically change the calendar option
localeSelectorEl.addEventListener('change', function() {
if (this.value) {
calendar.setOption('locale', this.value);
}
});
}
else {
$(".locale-selector").hide();
}
// Put into the calendar array.
calendarObjs[i] = calendar;
}
// Double click event.
$(".js-drupal-fullcalendar").dblclick(function() {
// New event window can be open if following conditions match.
// * The new event content type are specified.
// * Allow to create a new event by double click.
// * User has the permission to create a new event.
// * The add form for the new event type is known.
if (
slotDate &&
drupalSettings.eventBundleType &&
drupalSettings.dblClickToCreate &&
drupalSettings.addForm !== ""
) {
// Open a new window to create a new event (content).
window.open(
drupalSettings.path.baseUrl +
drupalSettings.addForm +
"?start=" +
slotDate +
"&start_field=" +
drupalSettings.startField,
"_blank"
);
}
});
}
}
};
})(jQuery, Drupal);
......@@ -104,14 +104,14 @@ class FullcalendarViewPreprocess {
$start_field_option['settings']['timezone_override'] : date_default_timezone_get();
// Title field machine name.
$title_field = (empty($options['title']) || $options['title'] == 'title') ? 'title' : $options['title'];
// Calendar entries linked to entity.
/* // Calendar entries linked to entity.
$link_to_entity = FALSE;
if (isset($fields[$title_field]->options['settings']['link_to_entity'])) {
$link_to_entity = $fields[$title_field]->options['settings']['link_to_entity'];
}
elseif (isset($fields[$title_field]->options['settings']['link'])) {
$link_to_entity = $fields[$title_field]->options['settings']['link'];
}
} */
// Set the first day setting.
$first_day = isset($options['firstDay']) ? intval($options['firstDay']) : 0;
// Left side buttons.
......@@ -156,10 +156,18 @@ class FullcalendarViewPreprocess {
else {
$title = t('Invalid event title');
}
$link_url = strstr($title, 'href="');
if ($link_url) {
$link_url = substr($link_url, 6);
$link_url = strstr($link_url, '"', true);
}
else {
$link_url = '';
}
$entry = [
'title' => Xss::filterAdmin($title),
'id' => $entity_id,
'url' => $current_entity->toUrl()->toString(),
'url' => $link_url,
];
// Event duration.
if (!empty($duration_field) && !empty($fields[$duration_field])) {
......@@ -304,15 +312,31 @@ class FullcalendarViewPreprocess {
'eventLimit' => true, // Allow "more" link when too many events.
'eventOverlap' => $options['allowEventOverlap'] !== 0,
];
// Dialog options.
// Other modules can override following options by custom plugin.
// For reference of JSFrame options see:
// https://github.com/riversun/JSFrame.js/
$dialog_optoins = [
'left' => 40,
'top' => 60,
'width' => 640,
'height' => 480,
'movable' => true, //Enable to be moved by mouse
'resizable' => true, //Enable to be resized by mouse
];
// Load the fullcalendar js library.
$variables['#attached']['library'][] = 'fullcalendar_view/fullcalendar';
if ($options['dialogWindow']) {
// Load the JS library for dialog.
$variables['#attached']['library'][] = 'fullcalendar_view/libraries.jsframe';
}
// Pass data to js file.
$variables['#attached']['drupalSettings'] = [
'languageSelector' => $options['languageSelector'],
'updateConfirm' => $options['updateConfirm'],
'dialogWindow' => $options['dialogWindow'],
'linkToEntity' => $link_to_entity,
// 'linkToEntity' => $link_to_entity,
'eventBundleType' => $event_bundle_type,
'startField' => $start_field,
'endField' => $end_field,
......@@ -322,6 +346,7 @@ class FullcalendarViewPreprocess {
'token' => $token,
'openEntityInNewTab' => $options['openEntityInNewTab'],
'calendar_options' => json_encode($calendar_options),
'dialog_options' => json_encode($dialog_optoins),
];
}
}
......
......@@ -147,15 +147,6 @@ class FullCalendarDisplay extends StylePluginBase {
'#empty_value' => '',
'#default_value' => (!empty($this->options['end'])) ? $this->options['end'] : '',
];
// Field name of rrules.
$form['duration'] = [
'#title' => $this->t('Event duration field.'),
'#description' => $this->t('The field value should be a string in the format hh:mm:ss.sss, hh:mm:sss or hh:mm. For example, "05:00" signifies 5 hours.'),
'#type' => 'select',
'#options' => $field_names,
'#empty_value' => '',
'#default_value' => (!empty($this->options['duration'])) ? $this->options['duration'] : '',
];
// Field name of title.
$form['title'] = [
'#title' => $this->t('Title Field'),
......@@ -478,10 +469,28 @@ class FullCalendarDisplay extends StylePluginBase {
':doc-url' => 'https://github.com/jakubroztocil/rrule'
]),
'#type' => 'select',
'#empty_value' => '',
'#fieldset' => 'recurring',
'#options' => $field_names,
'#default_value' => (!empty($this->options['rrule'])) ? $this->options['rrule'] : '',
];
// Field name of rrules.
$form['duration'] = [
'#fieldset' => 'recurring',
'#title' => $this->t('Event duration field.'),
'#description' => $this->t('For specifying the end time of each recurring event instance. The field value should be a string in the format hh:mm:ss.sss, hh:mm:sss or hh:mm. For example, "05:00" signifies 5 hours.'),
'#type' => 'select',
'#empty_value' => '',
'#options' => $field_names,
'#empty_value' => '',
'#default_value' => (!empty($this->options['duration'])) ? $this->options['duration'] : '',
'#states' => [
// Only show this field when the 'rrule' is specified.
'invisible' => [
[':input[name="style_options[rrule]"]' => ['value' => '']],
],
],
];
// New event bundle type.
$form['bundle_type'] = [
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment