diff --git a/common/php/class-module.php b/common/php/class-module.php index 2ebdb0cb..dfd888eb 100644 --- a/common/php/class-module.php +++ b/common/php/class-module.php @@ -908,5 +908,274 @@ public function getPostStatusOptions() return $postStatuses; } + + /** + * Retrieve wordpress registered taxonomy + * + * Private taxonomy are excluded + * + * @since 3.7.0 + */ + public function get_all_taxonomies() + { + + //category and post tag are not included in public taxonomy + $category = get_taxonomies(['name' => 'category'], 'objects'); + $post_tag = get_taxonomies(['name' => 'post_tag'], 'objects'); + + $public = get_taxonomies(['_builtin' => false, 'public' => true], 'objects'); + + $taxonomies = array_merge($category, $post_tag, $public); + + return $taxonomies; + } + + /** + * + * @param string $param The parameter to look for in $_GET + * + * @return mixed null if the parameter is not set in $_GET, empty string if the parameter is empty in $_GET, + * or a sanitized version of the parameter from $_GET if set and not empty + */ + public function filter_get_param($param, $request_filter = false) + { + if (!$request_filter) { + $request_filter = $_GET; + } + + // Sure, this could be done in one line. But we're cooler than that: let's make it more readable! + if (! isset($request_filter[$param])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended + return null; + } elseif (empty($request_filter[$param])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended + return ''; + } + + return sanitize_key($request_filter[$param]); // phpcs:ignore WordPress.Security.NonceVerification.Recommended + } + + /** + * This function is an alternative to filter_get_param() that's stripping out date characters + * + * @param string $param The parameter to look for in $_GET + * + * @return mixed null if the parameter is not set in $_GET, empty string if the parameter is empty in $_GET, + * or a sanitized version of the parameter from $_GET if set and not empty + */ + public function filter_get_param_text($param, $request_filter = false) + { + if (!$request_filter) { + $request_filter = $_GET; + } + + // Sure, this could be done in one line. But we're cooler than that: let's make it more readable! + if (! isset($request_filter[$param])) { + return null; + } elseif ($request_filter[$param] == '0') { + return 0; + } elseif (empty($request_filter[$param])) { + return ''; + } + + return sanitize_text_field($request_filter[$param]); + } + + public function meta_query_operator_label($operator = false) { + $operators = [ + 'equals' => 'Equals (=)', + 'not_equals' => 'Does not equal (!=)', + 'greater_than' => 'Greater than (>)', + 'greater_than_or_equals' => 'Greater than or equals (>=)', + 'less_than' => 'Less than (<)', + 'less_than_or_equals' => 'Less than or equals (<=)', + 'like' => 'Like/Contains', + 'not_like' => 'Not Like', + 'not_exists' => 'Not Exists/Empty', + ]; + + if ($operator) { + $return = array_key_exists($operator, $operators) ? $operators[$operator] : $operator; + } else { + $return = $operators; + } + + return $return; + } + + public function meta_query_operator_symbol($operator = false) { + $operators = [ + 'equals' => '=', + 'not_equals' => '!=', + 'greater_than' => '>', + 'greater_than_or_equals' => '>=', + 'less_than' => '<', + 'less_than_or_equals' => '<=', + 'like' => 'LIKE', + 'not_like' => 'NOT LIKE', + 'not_exists' => 'NOT EXISTS', + ]; + + if ($operator) { + $return = array_key_exists($operator, $operators) ? $operators[$operator] : $operator; + } else { + $return = $operators; + } + + return $return; + } + + public function localize_post_data($localized_post_data, $post, $can_edit_post) { + global $publishpress; + + // add taxonomies + $taxonomies = get_object_taxonomies($post->post_type, 'object'); + foreach ($taxonomies as $taxonomy => $tax_object ) { + if (!empty($tax_object->public) + && !in_array($taxonomy, ['author', 'post_format', 'post_status', 'post_status_core_wp_pp', 'post_visibility_pp'])) { + $terms = get_the_terms($post->ID, $taxonomy); + //add post content to localized data + $localized_post_data['taxonomies'][$post->ID][$taxonomy] = [ + 'post_id' => $post->ID, + 'taxonomy' => $taxonomy, + 'taxonomy_label' => $tax_object->label, + 'taxonomy_placeholder' => sprintf(esc_attr__('Select %s', 'publishpress'), esc_html($tax_object->label)), + 'terms' => (!empty($terms) && !is_wp_error($terms)) ? $terms : [] + ]; + } + } + + $post_title = _draft_or_post_title($post->ID); + + //add post content to localized data + $localized_post_data['posts'][] = [ + 'post_id' => $post->ID, + 'post_title' => $post_title, + 'raw_title' => $post->post_title, + 'post_status' => $post->post_status, + 'status_label' => $this->get_post_status_friendly_name($post->post_status), + 'can_edit_post' => $can_edit_post ? 1 : 0, + 'date_markup' => $can_edit_post ? $this->get_date_markup($post) : get_the_time(get_option("date_format"), $post->ID) . " " . get_the_time(get_option("time_format"), $post->ID), + 'action_links' => $this->get_post_action_links($post, $can_edit_post), + 'author_markup' => $this->get_author_markup($post, $can_edit_post), + 'status_options' => $this->getUserAuthorizedPostStatusOptions($post->post_type), + 'post_content' => apply_filters('the_content', $post->post_content) + ]; + + return $localized_post_data; + } + + public function get_date_markup($post) { + $date_name = 'content_board_post_date'; + $date_markup = + sprintf( + '', + esc_attr($date_name), + esc_attr(date_i18n('F j, Y H:i', strtotime($post->post_date))), + esc_attr(pp_convert_date_format_to_jqueryui_datepicker('Y-m-d H:i:s')), + '' + ); + $date_markup .= sprintf( + '', + esc_attr($date_name), + esc_attr($date_name), + esc_attr(date_i18n('Y-m-d H:i:s', strtotime($post->post_date))) + ); + + return $date_markup; + } + + public function get_post_action_links($post, $can_edit_post) { + + $post_type_object = get_post_type_object($post->post_type); + + $item_actions = [ + 'edit' => '', + 'trash' => '', + 'view' => '', + 'previewpost' => '', + ]; + + if ($can_edit_post) { + $item_actions["edit"] = esc_url(get_edit_post_link($post->ID)); + } + + if (EMPTY_TRASH_DAYS > 0 && current_user_can($post_type_object->cap->delete_post, $post->ID)) { + $item_actions["trash"] = esc_url(get_delete_post_link($post->ID)); + } + + if (in_array($post->post_status, ["publish"])) { + $item_actions["view"] = esc_url(get_permalink($post->ID)); + } elseif ($can_edit_post) { + $item_actions["previewpost"] = esc_url( + apply_filters( + "preview_post_link", + add_query_arg("preview", "true", get_permalink($post->ID)), + $post + ) + ); + } + + return $item_actions; + } + + public function get_author_markup($post, $can_edit_post) { + + if ($can_edit_post) { + ob_start(); + $authorId = (int) $post->post_author; + if (function_exists('get_post_authors')) { + $authors = get_post_authors($post); + $multiple = 'multiple'; + } else { + $authors = [$authorId]; + $multiple = ''; + } + ?> + + post_author); + $author_name = is_object($post_author) ? $post_author->display_name : ''; + $author_name = apply_filters('the_author', $author_name); + + $author_name = apply_filters('publishpress_content_overview_author_column', $author_name, $post); + return $author_name; + } + } + } } diff --git a/modules/calendar/calendar.php b/modules/calendar/calendar.php index d643feef..fa7d31f0 100644 --- a/modules/calendar/calendar.php +++ b/modules/calendar/calendar.php @@ -28,6 +28,7 @@ * along with PublishPress. If not, see . */ +use PublishPress\Legacy\Util; use PublishPress\Notifications\Traits\Dependency_Injector; if (! class_exists('PP_Calendar')) { @@ -321,6 +322,7 @@ public function init() add_filter('pp_calendar_after_form_submission_sanitize_content', [$this, 'sanitize_text_input'], 10, 1); add_filter('pp_calendar_after_form_submission_sanitize_author', [$this, 'sanitize_author_input'], 10, 1); add_filter('pp_calendar_after_form_submission_validate_author', [$this, 'validateAuthorForPost'], 10, 1); + add_filter('admin_body_class', [$this, 'add_admin_body_class']); } // Clear li cache for a post when post cache is cleared @@ -330,6 +332,14 @@ public function init() $this->default_date_time_format = get_option('date_format') . ' ' . get_option('time_format'); } + public function add_admin_body_class($classes) { + global $pagenow; + if ('admin.php' === $pagenow && isset($_GET['page']) && $_GET['page'] === self::MENU_SLUG) { + $classes .= ' pp-content-calendar-page'; + } + return $classes; + } + /** * @param $original_template * @@ -747,6 +757,7 @@ public function enqueue_admin_scripts() 'publishpress_calendar_allow_multiple_authors', false ), + 'proActive' => Util::isPlannersProActive(), 'strings' => [ 'loading' => esc_js(__('Loading...', 'publishpress')), 'loadingItem' => esc_js(__('Loading item...', 'publishpress')), @@ -791,6 +802,19 @@ public function enqueue_admin_scripts() 'xWeeks' => esc_js(__('%d weeks', 'publishpress')), 'today' => esc_js(__('Today', 'publishpress')), 'noTerms' => esc_js(__('No terms', 'publishpress')), + 'post_date_label' => esc_html__('Post Date', 'publishpress'), + 'edit_label' => esc_html__('Edit', 'publishpress'), + 'delete_label' => esc_html__('Trash', 'publishpress'), + 'preview_label' => esc_html__('Preview', 'publishpress'), + 'view_label' => esc_html__('View', 'publishpress'), + 'prev_label' => esc_html__('Previous Post', 'publishpress'), + 'next_label' => esc_html__('Next Post', 'publishpress'), + 'post_status_label' => esc_html__('Post Status', 'publishpress'), + 'update_label' => esc_html__('Save Changes', 'publishpress'), + 'empty_term' => esc_html__('Taxonomy not set.', 'publishpress'), + 'post_author' => esc_html__('Author', 'publishpress'), + 'date_format' => pp_convert_date_format_to_jqueryui_datepicker(get_option('date_format')), + 'week_first_day' => esc_js(get_option('start_of_week')), ] ]; wp_localize_script('publishpress-async-calendar-js', 'publishpressCalendarParams', $params); @@ -1759,50 +1783,6 @@ class="date-time-pick" return ['selected_value' => $selected_value, 'filter_label' => $filter_label, 'html' => ob_get_clean()]; } - private function meta_query_operator_label($operator = false) { - $operators = [ - 'equals' => 'Equals (=)', - 'not_equals' => 'Does not equal (!=)', - 'greater_than' => 'Greater than (>)', - 'greater_than_or_equals' => 'Greater than or equals (>=)', - 'less_than' => 'Less than (<)', - 'less_than_or_equals' => 'Less than or equals (<=)', - 'like' => 'Like/Contains', - 'not_like' => 'Not Like', - 'not_exists' => 'Not Exists/Empty', - ]; - - if ($operator) { - $return = array_key_exists($operator, $operators) ? $operators[$operator] : $operator; - } else { - $return = $operators; - } - - return $return; - } - - private function meta_query_operator_symbol($operator = false) { - $operators = [ - 'equals' => '=', - 'not_equals' => '!=', - 'greater_than' => '>', - 'greater_than_or_equals' => '>=', - 'less_than' => '<', - 'less_than_or_equals' => '<=', - 'like' => 'LIKE', - 'not_like' => 'NOT LIKE', - 'not_exists' => 'NOT EXISTS', - ]; - - if ($operator) { - $return = array_key_exists($operator, $operators) ? $operators[$operator] : $operator; - } else { - $return = $operators; - } - - return $return; - } - /** * Return calendar filters * @return string @@ -1941,25 +1921,6 @@ public function update_content_calendar_form_action() { } } - /** - * Retrieve wordpress registered taxonomy - * - * Private taxonomy are excluded - */ - public function get_all_taxonomies() - { - - //category and post tag are not included in public taxonomy - $category = get_taxonomies(['name' => 'category'], 'objects'); - $post_tag = get_taxonomies(['name' => 'post_tag'], 'objects'); - - $public = get_taxonomies(['_builtin' => false, 'public' => true], 'objects'); - - $taxonomies = array_merge($category, $post_tag, $public); - - return $taxonomies; - } - /** * Get content calendar data that's required on the * content calendar page @@ -4379,16 +4340,29 @@ private function extractPostDataForTheCalendar($post) { $postTypeOptions = $this->get_post_status_options($post->post_status); $postTypeObject = $this->getPostTypeObject($post->post_type); + $canEdit = current_user_can($postTypeObject->cap->edit_post, $post->ID); - return [ + $data = [ 'label' => esc_html($post->post_title), 'id' => (int)$post->ID, 'timestamp' => esc_attr($post->post_date), 'icon' => esc_attr($postTypeOptions['icon']), 'color' => esc_attr($postTypeOptions['color']), 'showTime' => (bool)$this->showPostsPublishTime($post->post_status), - 'canEdit' => current_user_can($postTypeObject->cap->edit_post, $post->ID), + 'canEdit' => $canEdit, ]; + + if (Util::isPlannersProActive()) { + $modal_data = $this->localize_post_data([], $post, $canEdit); + + $data['calendar_post_data'] = !empty($modal_data['posts'][0]) ? $modal_data['posts'][0] : []; + $data['calendar_taxonomies_data'] = !empty($modal_data['taxonomies'][$post->ID]) ? $modal_data['taxonomies'][$post->ID] : []; + } else { + $data['calendar_post_data'] = []; + $data['calendar_taxonomies_data'] = []; + } + + return $data; } public function moveCalendarItemToNewDate() @@ -4989,55 +4963,6 @@ private function getCalendarData($beginningDate, $endingDate, $args = []) return $data; } - /** - * - * @param string $param The parameter to look for in $_GET - * - * @return mixed null if the parameter is not set in $_GET, empty string if the parameter is empty in $_GET, - * or a sanitized version of the parameter from $_GET if set and not empty - */ - public function filter_get_param($param, $request_filter = false) - { - if (!$request_filter) { - $request_filter = $_GET; - } - - // Sure, this could be done in one line. But we're cooler than that: let's make it more readable! - if (! isset($request_filter[$param])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended - return null; - } elseif (empty($request_filter[$param])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended - return ''; - } - - return sanitize_key($request_filter[$param]); // phpcs:ignore WordPress.Security.NonceVerification.Recommended - } - - /** - * This function is an alternative to filter_get_param() that's stripping out date characters - * - * @param string $param The parameter to look for in $_GET - * - * @return mixed null if the parameter is not set in $_GET, empty string if the parameter is empty in $_GET, - * or a sanitized version of the parameter from $_GET if set and not empty - */ - public function filter_get_param_text($param, $request_filter = false) - { - if (!$request_filter) { - $request_filter = $_GET; - } - - // Sure, this could be done in one line. But we're cooler than that: let's make it more readable! - if (! isset($request_filter[$param])) { - return null; - } elseif ($request_filter[$param] == '0') { - return 0; - } elseif (empty($request_filter[$param])) { - return ''; - } - - return sanitize_text_field($request_filter[$param]); - } - /** * Sanitize a $_GET or similar filter being used on the calendar * diff --git a/modules/calendar/lib/async-calendar/js/AsyncCalendar.jsx b/modules/calendar/lib/async-calendar/js/AsyncCalendar.jsx index 62007381..29c106fc 100644 --- a/modules/calendar/lib/async-calendar/js/AsyncCalendar.jsx +++ b/modules/calendar/lib/async-calendar/js/AsyncCalendar.jsx @@ -2,7 +2,7 @@ import NavigationBar from "./NavigationBar"; import WeekDays from "./WeekDays"; import MessageBar from "./MessageBar"; import DayCell from "./DayCell"; -import {calculateWeeksInMilliseconds, getBeginDateOfWeekByDate, getDateAsStringInWpFormat, getDateInstanceFromString} from "./Functions"; +import {calculateWeeksInMilliseconds, getBeginDateOfWeekByDate, getDateAsStringInWpFormat, getDateInstanceFromString, addCalendarPosts, openPostModal, adjustTextareaHeight, updateModalPost} from "./Functions"; import FilterBar from "./FilterBar"; import ItemFormPopup from "./ItemFormPopup"; @@ -59,6 +59,13 @@ export default function AsyncCalendar(props) { onFilterEventCallback(selectName, selectValue); } + const onModalNavClick = (event) => { + event.preventDefault(); + let openedItemId = event.currentTarget.getAttribute('data-post_id'); + + openPostModal(openedItemId); + }; + const onMeModeClick = (event) => { let new_value = ''; if (event.target.classList.contains('active-filter')) { @@ -126,6 +133,11 @@ export default function AsyncCalendar(props) { $(document).on('click', '.metadata-item-filter .filter-apply input[type=submit]', onFilterApplyClick); $(document).on('click', '.pp-content-calendar-manage .search-bar input[type=submit]', onSearchClick); $(document).on('click', '.pp-content-calendar-manage .me-mode-action', onMeModeClick); + $(document).on('click', '.pp-popup-modal-header .modal-nav-prev, .pp-popup-modal-header .modal-nav-next', onModalNavClick); + $(document).on('input', '.pp-content-calendar-general-modal-container .modal-post-title .title-area', adjustTextareaHeight); + $(document).on('click', '.pp-content-calendar-general-modal-container .modal-content-right .save-post-changes:not(.disabled)', function(e) { + updateModalPost(e, jQuery(this), handleRefreshOnClick); + }); } const removeEventListeners = () => { @@ -175,6 +187,7 @@ export default function AsyncCalendar(props) { fetch(dataUrl) .then(response => response.json()) .then((fetchedData) => { + publishpressCalendarParams.PostData = addCalendarPosts(publishpressCalendarParams.PostData, fetchedData); setItemsByDate(fetchedData); setIsLoading(false); setMessage(null); @@ -192,19 +205,23 @@ export default function AsyncCalendar(props) { if (!openedItemId) { return; } + + if (publishpressCalendarParams.proActive) { + openPostModal(openedItemId); + } else { + setIsLoading(true); + setMessage(props.strings.loadingItem); - setIsLoading(true); - setMessage(props.strings.loadingItem); + const dataUrl = props.ajaxUrl + '?action=' + 'publishpress_calendar_get_post_data' + '&nonce=' + props.nonce + '&id=' + openedItemId; + fetch(dataUrl) + .then(response => response.json()) + .then((data) => { + setIsLoading(false); + setMessage(null); - const dataUrl = props.ajaxUrl + '?action=' + 'publishpress_calendar_get_post_data' + '&nonce=' + props.nonce + '&id=' + openedItemId; - fetch(dataUrl) - .then(response => response.json()) - .then((data) => { - setIsLoading(false); - setMessage(null); - - setOpenedItemData(data); + setOpenedItemData(data); }); + } } const addOffsetInWeeksToFirstDateToDisplay = (offsetInWeeks) => { @@ -214,7 +231,7 @@ export default function AsyncCalendar(props) { const handleRefreshOnClick = (e) => { e.preventDefault(); - setRefreshCount(refreshCount + 1); + setRefreshCount(prevCount => prevCount + 1); }; const handleBackPageOnClick = (e) => { @@ -430,6 +447,10 @@ export default function AsyncCalendar(props) { setHoveredDate(null); setFormDate(null); setOpenedItemId(id); + + if (publishpressCalendarParams.proActive) { + openPostModal(id); + } } const onPopupItemActionClick = (action, id, result) => { diff --git a/modules/calendar/lib/async-calendar/js/Functions.jsx b/modules/calendar/lib/async-calendar/js/Functions.jsx index 73362ebb..0b7963ab 100644 --- a/modules/calendar/lib/async-calendar/js/Functions.jsx +++ b/modules/calendar/lib/async-calendar/js/Functions.jsx @@ -186,3 +186,387 @@ export function getDateInstanceFromString(dateString) { // The "-" char is replaced to make it compatible to Safari browser. Issue #1001. return new Date(String(dateString).replace(/-/g, "/")); } + +export function addCalendarPosts(posts, calendarPosts) { + + for (const date in calendarPosts) { + if (calendarPosts.hasOwnProperty(date)) { + calendarPosts[date].forEach(post => { + if (post.calendar_post_data && Object.keys(post.calendar_post_data).length > 0) { + const existingIndex = posts.findIndex(mergedPost => mergedPost.post_id === post.calendar_post_data.post_id); + const mergedPost = { + ...post.calendar_post_data, + taxonomies: { + ...post.calendar_taxonomies_data + } + }; + if (existingIndex > -1) { + // Update the existing post + posts[existingIndex] = mergedPost; + } else { + // Add the new post + posts.push(mergedPost); + } + } + }); + } + } + + return posts; +} + +export function updateModalPost(e, button, handleRefreshOnClick) { + e.preventDefault(); + var modal_form = button.closest('.modal-content-right'); + + button.addClass('disabled'); + + var post_id = button.attr('data-post_id'); + var post_title = modal_form.find('.title-area').val(); + var post_date = modal_form.find('.content_board_post_date_hidden').val(); + var post_author = modal_form.find('.pp-modal-form-author').val(); + var post_status = modal_form.find('.pp-modal-form-post-status').val(); + var post_taxonomies = {}; + modal_form.find('.pp-modal-form-post-taxonomy').each(function () { + var tax_html = jQuery(this); + post_taxonomies[tax_html.attr('data-taxonomy')] = tax_html.val(); + }); + var data = { + action: "publishpress_content_calendar_update_post", + post_id: post_id, + post_title: post_title, + post_date: post_date, + post_author: post_author, + post_status: post_status, + post_taxonomies: post_taxonomies, + nonce: publishpressCalendarParams.nonce + }; + + jQuery.post(ajaxurl, data, function (response) { + if (response.status == 'success') { + let PostData = publishpressCalendarParams.PostData; + + var target_post = jQuery('.publishpress-calendar .publishpress-calendar-item.post-' + post_id); + var post_index = PostData.findIndex(function(p) { + return Number(p.post_id) === Number(post_id); + }); + + // update card and post global data + var post = PostData[post_index]; + var taxonomies = post.taxonomies; + + post.post_title = post_title; + post.raw_title = post_title; + post.post_status = post_status; + post.author_markup = response.author_markup; + post.date_markup = response.date_markup; + + var response_taxonomies = response.taxonomy_terms; + for (var taxonomyKey in response_taxonomies) { + if (response_taxonomies.hasOwnProperty(taxonomyKey)) { + var taxonomyData = response_taxonomies[taxonomyKey]; + taxonomies[taxonomyKey].terms = taxonomyData; + } + } + post.taxonomies = taxonomies; + publishpressCalendarParams.PostData[post_index] = post; + + // update post title + target_post.find('.publishpress-calendar-item-title').html(post.post_title); + + //refresh calendar + if (typeof handleRefreshOnClick === 'function') { + handleRefreshOnClick(e); + } + } + + // enable button + button.removeClass('disabled'); + // show status message + ppcTimerStatus(response.status, response.content); + }); +} + +export function openPostModal(post_id) { + + let PostData = publishpressCalendarParams.PostData; + + var post_index = PostData.findIndex(function(p) { + return Number(p.post_id) === Number(post_id); + }); + + if (post_index === -1) { + console.error('Post with id ' + post_id + ' not found'); + console.log(PostData); + return; + } + + var post = PostData[post_index]; + + var post_status = post.post_status; + // post details + var previous_post = PostData[post_index - 1] || PostData[PostData.length - 1]; + var next_post = PostData[post_index + 1] || PostData[0]; + + var status_title = post.status_label; + var action_links = post.action_links; + + var post_taxonomies = post.taxonomies || null; + + var can_edit_post = Number(post.can_edit_post) > 0; + + // build header + var popup_header = '
'; + + if (previous_post.post_id != post.post_id) { + popup_header += '
'; + popup_header += ' ' + previous_post.post_title + ''; + popup_header += '
'; + } + + if (next_post.post_id != post.post_id) { + popup_header += '
'; + popup_header += '' + next_post.post_title + ' '; + popup_header += '
'; + } + + // add post edit link meta + if (action_links.edit !== '') { + popup_header += '
' + publishpressCalendarParams.strings.edit_label + '
'; + } + // add post trash meta + if (action_links.trash !== '') { + popup_header += '
' + publishpressCalendarParams.strings.delete_label + '
'; + } + // add post view/preview meta + if (action_links.previewpost !== '') { + popup_header += '
' + publishpressCalendarParams.strings.preview_label + '
'; + } else if (action_links.view !== '') { + popup_header += '
' + publishpressCalendarParams.strings.view_label + '
'; + } + + popup_header += '
'; + + // build content + var popup_content = '
'; + + popup_content = ''; + + popup_content += ''; + + popup_content += '
'; + + jQuery('#pp-content-calendar-general-modal-container').html(popup_content); + + var height = Math.round(window.innerHeight * 0.78); + + tb_show(popup_header, '#TB_inline?width=600&height=' + height + '&inlineId=pp-content-calendar-general-modal'); + var modal_height = jQuery('body.pp-content-calendar-page #TB_window').css('height'); + if (modal_height) { + // update inner content height for scroll bar + var inner_height = parseInt(modal_height, 10) - 55; + + jQuery('.pp-content-calendar-general-modal-container .modal-content-right .scrollable-content').css('height', inner_height - 60 + 'px'); + jQuery('.pp-content-calendar-general-modal-container .modal-content-left').css('height', inner_height + 'px'); + jQuery('body.pp-content-calendar-page #TB_ajaxContent').css('height', inner_height + 'px'); + + // adjust textarea height + var textarea = jQuery('.pp-content-calendar-general-modal-container .modal-post-title .title-area'); + if (textarea.length > 0) { + adjustTextareaHeight(false, textarea); + } + } + + // init date picker + init_date_time_picker(); + // init select2 + initFormSelect2(); + +} + +export function adjustTextareaHeight(event, textarea = false) { + if (!textarea) { + var textarea = jQuery('.pp-content-calendar-general-modal-container .modal-post-title .title-area'); + } + // Reset the height so that it can shrink on deleting content + textarea.css('height', 'auto'); + // Set the height to the scroll height of the content + textarea.css('height', textarea[0].scrollHeight + 'px'); +} + +export function initFormSelect2() { + jQuery('.pp-modal-form-author').pp_select2({ + allowClear: false, + ajax: { + url: ajaxurl, + dataType: 'json', + delay: 0, + data: function (params) { + return { + action: 'publishpress_calendar_search_authors', + nonce: publishpressCalendarParams.nonce, + q: params.term + }; + }, + processResults: function (data) { + return { + results: data + }; + }, + cache: false + } + }); + + jQuery('.pp-modal-form-post-taxonomy').pp_select2({ + allowClear: true, + ajax: { + url: ajaxurl, + dataType: 'json', + delay: 0, + data: function (params) { + return { + action: 'publishpress_calendar_search_terms', + taxonomy: jQuery(this).attr('data-taxonomy'), + nonce: publishpressCalendarParams.nonce, + q: params.term + }; + }, + processResults: function (data) { + return { + results: data + }; + }, + cache: false + } + }); + + jQuery('.pp-modal-form-post-status').pp_select2({ + allowClear: false + }); +} + + +export function init_date_time_picker() { + jQuery('.pp-content-calendar-general-modal-container .modal-content-right .date-time-pick').each(function () { + var self = jQuery(this); + var options = getOptions(self, { + alwaysSetTime: false, + controlType: 'select', + altFieldTimeOnly: false + }); + if (self.hasClass('future-date')) { + options.minDate = new Date(); + } + self.datetimepicker(options); + }); +} + +export function getOptions (self, custom_options) { + var default_options = { + dateFormat: publishpressCalendarParams.strings.date_format, + firstDay: publishpressCalendarParams.strings.week_first_day + }; + + var options = jQuery.extend({}, default_options, custom_options); + var altFieldName = self.attr('data-alt-field'); + + if ((!altFieldName) || typeof altFieldName == 'undefined' || altFieldName.length == 0) { + return options; + } + + return jQuery.extend({}, options, { + altField: 'input[name="'+ altFieldName +'"]', + altFormat: self.attr('data-alt-format'), + }); +} + +export function ppcTimerStatus(type = "success", message = '') { + setTimeout(function () { + var uniqueClass = "pp-floating-msg-" + Math.round(new Date().getTime() + Math.random() * 100); + var instances = jQuery(".pp-floating-status").length; + jQuery("#wpbody-content").after('' + message + ""); + jQuery("." + uniqueClass) + .css("bottom", instances * 45) + .fadeIn(1e3) + .delay(1e4) + .fadeOut(1e3, function () { + jQuery(this).remove(); + }); + }, 500); +} \ No newline at end of file diff --git a/modules/calendar/lib/async-calendar/js/Item.jsx b/modules/calendar/lib/async-calendar/js/Item.jsx index 768b51d4..be7f40ec 100644 --- a/modules/calendar/lib/async-calendar/js/Item.jsx +++ b/modules/calendar/lib/async-calendar/js/Item.jsx @@ -15,8 +15,8 @@ export default function Item(props) { return getHourStringOnFormat(timestampDate, props.timeFormat || DEFAULT_TIME_FORMAT); } - const getClassName = () => { - let className = 'publishpress-calendar-item'; + const getClassName = (itemID) => { + let className = 'publishpress-calendar-item post-' + itemID; if (props.isPopupOpened) { className += ' publishpress-calendar-item-opened-popup'; @@ -55,7 +55,7 @@ export default function Item(props) { return (
  • {iconElement}{timeElement} - + {props.isPopupOpened && -