addStyleSheet(VBO_ADMIN_URI . 'helpers/' . 'wp.css', ['version' => VIKBOOKING_SOFTWARE_VERSION], ['id' => 'vbo-wp-style']); } } /** * Includes a script URI. * * @param string $uri The script URI. * * @return void */ public function addScript($uri) { JHtml::fetch('script', $uri); } /** * Sets additional commands for any methods. Like raise an error if the recipient email address is empty. * Returns this object for chainability. */ public function setCommand($key, $value) { if (!empty($key)) { $this->commands[$key] = $value; } return $this; } public function sendMail($from_address, $from_name, $to, $reply_address, $subject, $hmess, $is_html = true, $encoding = 'base64', $attachment = null) { if (!is_array($to) && strpos($to, ',') !== false) { $all_recipients = explode(',', $to); foreach ($all_recipients as $k => $v) { if (empty($v)) { unset($all_recipients[$k]); } } if (count($all_recipients) > 0) { $to = $all_recipients; } } if (empty($to)) { //Prevent Joomla Exceptions that would stop the script execution if (isset($this->commands['print_errors'])) { VikError::raiseWarning('', 'The recipient email address is empty. Email message could not be sent. Please check your configuration.'); } return false; } if ($from_name == $from_address) { $mainframe = JFactory::getApplication(); $attempt_fromn = $mainframe->get('fromname', ''); if (!empty($attempt_fromn)) { $from_name = $attempt_fromn; } } /** * Conditional text rules may set extra recipients or attachments. * * @since 1.16.0 (J) - 1.6.0 (WP) */ $extra_admin_recipients = VikBooking::addAdminEmailRecipient(null); $bcc_addresses = VikBooking::addAdminEmailRecipient(null, $bcc = true); $extra_attachments = VikBooking::addEmailAttachment(null); if ($extra_admin_recipients) { // cast a possible string to array $to = (array) $to; // merge additional recipients $to = array_merge($to, $extra_admin_recipients); } if ($extra_attachments) { $attachment = $attachment ? (array) $attachment : []; $attachment = array_merge($attachment, $extra_attachments); } /** * We let the internal library process the email sending depending on the platform. * This will allow us to perform the required manipulation of the content, if needed. * * @since 1.15.2 (J) - 1.5.5 (WP) */ $mail_data = new VBOMailWrapper([ 'sender' => [$from_address, $from_name], 'recipient' => $to, 'bcc' => $bcc_addresses, 'reply' => $reply_address, 'subject' => $subject, 'content' => $hmess, 'attachments' => $attachment, ]); // unset queues for the next email sending operation VikBooking::addAdminEmailRecipient(null, false, $reset = true); VikBooking::addEmailAttachment(null, $reset = true); // dispatch the email sending command return VBOFactory::getPlatform()->getMailer()->send($mail_data); } /** * @param $arr_values array * @param $current_key string * @param $empty_value string (J3.x only) * @param $default * @param $input_name string * @param $record_id = '' string */ public function getDropDown($arr_values, $current_key, $empty_value, $default, $input_name, $record_id = '') { $dropdown = ''; $dropdown .= ''."\n"; return $dropdown; } public function loadSelect2() { //load JS + CSS $document = JFactory::getDocument(); $document->addStyleSheet(VBO_ADMIN_URI.'resources/select2.min.css'); $this->addScript(VBO_ADMIN_URI.'resources/select2.min.js'); } /** * Returns the HTML code to render a regular dropdown * menu styled through the jQuery plugin Select2. * * @param $arr_values array * @param $current_key string * @param $input_name string * @param $placeholder string used when the select has no selected option (it's empty) * @param $empty_name [string] the name of the option to set an empty value to the field () * @param $empty_val [string] the value of the option to set an empty value to the field () * @param $onchange [string] javascript code for the onchange attribute * @param $idattr [string] the identifier attribute of the select * * @return string */ public function getNiceSelect($arr_values, $current_key, $input_name, $placeholder, $empty_name = '', $empty_val = '', $onchange = 'document.adminForm.submit();', $idattr = '') { //load JS + CSS $this->loadSelect2(); //attribute $idattr = empty($idattr) ? rand(1, 999) : $idattr; //select $dropdown = ''."\n"; //js code $dropdown .= ''."\n"; return $dropdown; } /** * Adds the script declaration to render the Bootstrap JModal window. * The suffix can be passed to generate other JS functions. * Optionally pass JavaScript code for the 'show' and 'hide' events. * For compatibility with the Joomla framework, this method should be * echoed although it does not return anything on WordPress. * * @param $suffix string * @param $hide_js string * @param $show_js string * * @return void should still be echoed for compatibility with J. */ public function getJmodalScript($suffix = '', $hide_js = '', $show_js = '') { static $loaded = []; $doc = JFactory::getDocument(); if (!isset($loaded[$suffix])) { $doc->addScriptDeclaration( <<addStyleSheet(VBO_SITE_URI.'resources/jquery-ui.min.css'); JHtml::fetch('jquery.framework', true, true); $this->addScript(VBO_SITE_URI.'resources/jquery-ui.min.js'); $vbo_df = VikBooking::getDateFormat(); $juidf = $vbo_df == "%d/%m/%Y" ? 'dd/mm/yy' : ($vbo_df == "%m/%d/%Y" ? 'mm/dd/yy' : 'yy/mm/dd'); $is_rtl_lan = false; $is_rtl_str = 'false'; $day_names_min_len = 2; $now_lang = JFactory::getLanguage(); if (method_exists($now_lang, 'isRtl')) { $is_rtl_lan = $now_lang->isRtl(); $is_rtl_str = $is_rtl_lan ? 'true' : $is_rtl_str; if ($is_rtl_lan) { // for most RTL languages, 2 chars for the week-days would not make sense $day_names_min_len = 3; } } $ldecl = ' jQuery(function($){'."\n".' $.datepicker.regional["vikbooking"] = {'."\n".' closeText: "'.JText::translate('VBJQCALDONE').'",'."\n".' prevText: "'.JText::translate('VBJQCALPREV').'",'."\n".' nextText: "'.JText::translate('VBJQCALNEXT').'",'."\n".' currentText: "'.JText::translate('VBJQCALTODAY').'",'."\n".' monthNames: ["'.JText::translate('VBMONTHONE').'","'.JText::translate('VBMONTHTWO').'","'.JText::translate('VBMONTHTHREE').'","'.JText::translate('VBMONTHFOUR').'","'.JText::translate('VBMONTHFIVE').'","'.JText::translate('VBMONTHSIX').'","'.JText::translate('VBMONTHSEVEN').'","'.JText::translate('VBMONTHEIGHT').'","'.JText::translate('VBMONTHNINE').'","'.JText::translate('VBMONTHTEN').'","'.JText::translate('VBMONTHELEVEN').'","'.JText::translate('VBMONTHTWELVE').'"],'."\n".' monthNamesShort: ["'.$this->safeSubstr(JText::translate('VBMONTHONE')).'","'.$this->safeSubstr(JText::translate('VBMONTHTWO')).'","'.$this->safeSubstr(JText::translate('VBMONTHTHREE')).'","'.$this->safeSubstr(JText::translate('VBMONTHFOUR')).'","'.$this->safeSubstr(JText::translate('VBMONTHFIVE')).'","'.$this->safeSubstr(JText::translate('VBMONTHSIX')).'","'.$this->safeSubstr(JText::translate('VBMONTHSEVEN')).'","'.$this->safeSubstr(JText::translate('VBMONTHEIGHT')).'","'.$this->safeSubstr(JText::translate('VBMONTHNINE')).'","'.$this->safeSubstr(JText::translate('VBMONTHTEN')).'","'.$this->safeSubstr(JText::translate('VBMONTHELEVEN')).'","'.$this->safeSubstr(JText::translate('VBMONTHTWELVE')).'"],'."\n".' dayNames: ["'.JText::translate('VBWEEKDAYZERO').'", "'.JText::translate('VBWEEKDAYONE').'", "'.JText::translate('VBWEEKDAYTWO').'", "'.JText::translate('VBWEEKDAYTHREE').'", "'.JText::translate('VBWEEKDAYFOUR').'", "'.JText::translate('VBWEEKDAYFIVE').'", "'.JText::translate('VBWEEKDAYSIX').'"],'."\n".' dayNamesShort: ["'.$this->safeSubstr(JText::translate('VBWEEKDAYZERO')).'", "'.$this->safeSubstr(JText::translate('VBWEEKDAYONE')).'", "'.$this->safeSubstr(JText::translate('VBWEEKDAYTWO')).'", "'.$this->safeSubstr(JText::translate('VBWEEKDAYTHREE')).'", "'.$this->safeSubstr(JText::translate('VBWEEKDAYFOUR')).'", "'.$this->safeSubstr(JText::translate('VBWEEKDAYFIVE')).'", "'.$this->safeSubstr(JText::translate('VBWEEKDAYSIX')).'"],'."\n".' dayNamesMin: ["'.$this->safeSubstr(JText::translate('VBWEEKDAYZERO'), $day_names_min_len).'", "'.$this->safeSubstr(JText::translate('VBWEEKDAYONE'), $day_names_min_len).'", "'.$this->safeSubstr(JText::translate('VBWEEKDAYTWO'), $day_names_min_len).'", "'.$this->safeSubstr(JText::translate('VBWEEKDAYTHREE'), $day_names_min_len).'", "'.$this->safeSubstr(JText::translate('VBWEEKDAYFOUR'), $day_names_min_len).'", "'.$this->safeSubstr(JText::translate('VBWEEKDAYFIVE'), $day_names_min_len).'", "'.$this->safeSubstr(JText::translate('VBWEEKDAYSIX'), $day_names_min_len).'"],'."\n".' weekHeader: "'.JText::translate('VBJQCALWKHEADER').'",'."\n".' dateFormat: "'.$juidf.'",'."\n".' firstDay: '.VikBooking::getFirstWeekDay().','."\n".' isRTL: ' . $is_rtl_str . ','."\n".' showMonthAfterYear: false,'."\n".' yearSuffix: ""'."\n".' };'."\n".' $.datepicker.setDefaults($.datepicker.regional["vikbooking"]);'."\n".' });'; /** * Trigger event to allow third party plugins to overwrite the JS declaration for the datepicker. * * @since 1.16.0 (J) - 1.6.0 (WP) */ VBOFactory::getPlatform()->getDispatcher()->trigger('onBeforeDeclareDatepickerRegionalVikBooking', [$is_rtl_lan, $now_lang->getTag(), &$ldecl]); // add script declaration $document->addScriptDeclaration($ldecl); // cache loaded flag $datepicker_loaded = 1; } /** * Loads the CMS's native datepicker calendar. * * @since 1.10 */ public function getCalendar($val, $name, $id = null, $df = null, array $attributes = array()) { if ($df === null) { $df = VikBooking::getDateFormat(); } return parent::calendar($val, $name, $id, $df, $attributes); } /** * Returns a masked e-mail address. The e-mail are masked using * a technique to encode the bytes in hexadecimal representation. * The chunk of the masked e-mail will be also encoded to be HTML readable. * * @param string $email The e-mail to mask. * @param boolean $reverse True to reverse the e-mail address. * Only if the e-mail is not contained into an attribute. * * @return string The masked e-mail address. */ public function maskMail($email, $reverse = false) { if ($reverse) { // reverse the e-mail address $email = strrev($email); } // converts the e-mail address from bin to hex $email = bin2hex($email); // append ;&#x sequence after every chunk of the masked e-mail $email = chunk_split($email, 2, ";&#x"); // prepend &#x sequence before the address and trim the ending sequence $email = "&#x" . substr($email, 0, -3); return $email; } /** * Returns a safemail tag to avoid the bots spoof a plain address. * * @param string $email The e-mail address to mask. * @param boolean $mail_to True if the address should be wrapped * within a "mailto" link. * * @return string The HTML tag containing the masked address. * * @uses maskMail() */ public function safeMailTag($email, $mail_to = false) { // include the CSS declaration to reverse the text contained in the tags JFactory::getDocument()->addStyleDeclaration('safemail {direction: rtl;unicode-bidi: bidi-override;}'); // mask the reversed e-mail address $masked = $this->maskMail($email, true); // include the address into a custom tag $tag = "$masked"; if ($mail_to) { // mask the address for mailto command (do not use reverse) $mailto = $this->maskMail($email); // wrap the safemail tag within a mailto link $tag = "$tag"; } return $tag; } /** * Loads and echoes the script necessary to render the Fancybox * plugin for jQuery to open images or iframes within a modal box. * This resolves conflicts with some Bootstrap or Joomla (4) versions * that do not support the old-native CSS class .modal with "behavior.modal". * Mainly made to open pictures in a modal box, so the default "type" is set to "image". * By passing a custom $opts string, the "type" property could be set to "iframe", but * in this case it's better to use the other method of this class (Jmodal). * The base jQuery library should be already loaded when using this method. * * @param string $selector The jQuery selector to trigger Fancybox. * @param string $opts The options object for the Fancybox setup. * @param boolean $reloadfunc If true, an additional function is included in the script * to apply again Fancybox to newly added images to the DOM (via Ajax). * * @return void * * @uses addScript() */ public function prepareModalBox($selector = '.vbomodal', $opts = '', $reloadfunc = false) { if (empty($opts)) { $opts = '{ "helpers": { "overlay": { "locked": false } }, "width": "70%", "height": "75%", "autoScale": true, "transitionIn": "none", "transitionOut": "none", "padding": 0, "type": "image" }'; } $document = JFactory::getDocument(); $document->addStyleSheet(VBO_SITE_URI.'resources/jquery.fancybox.css'); $this->addScript(VBO_SITE_URI.'resources/jquery.fancybox.js'); $reloadjs = ' function reloadFancybox() { jQuery("'.$selector.'").fancybox('.$opts.'); } '; $js = ' '; echo $js; } /** * Method used to handle the reCAPTCHA events. * * @param string $event The reCAPTCHA event to trigger. * Here's the list of the accepted events: * - display Returns the HTML used to * display the reCAPTCHA input. * - check Validates the POST data to make sure * the reCAPTCHA input was checked. * @param array $options A configuration array. * * @return mixed The event response. * * @since 1.2.3 * @wponly the Joomla integration differs */ public function reCaptcha($event = 'display', array $options = array()) { $response = null; // an optional configuration array (just leave empty) $options = array(); // trigger reCAPTCHA display event to fill $response var do_action_ref_array('vik_recaptcha_' . $event, array(&$response, $options)); // display reCAPTCHA by echoing it (empty in case reCAPTCHA is not available) return $response; } /** * Checks if the com_user captcha is configured. * In case the parameter is set to global, the default one * will be retrieved. * * @param string $plugin The plugin name to check ('recaptcha' by default). * * @return boolean True if configured, otherwise false. * * @since 1.2.3 * @wponly the Joomla integration differs */ public function isCaptcha($plugin = 'recaptcha') { return apply_filters('vik_' . $plugin . '_on', false); } /** * Checks if the global captcha is configured. * * @param string $plugin The plugin name to check ('recaptcha' by default). * * @return boolean True if configured, otherwise false. * * @since 1.2.3 */ public function isGlobalCaptcha($plugin = 'recaptcha') { return $this->isCaptcha($plugin); } /** * Method used to obtain a WordPress media form field. * * @return string The media in HTML. * * @since 1.3.0 */ public function getMediaField($name, $value = null, array $data = array()) { // check if WordPress is installed if (VBOPlatformDetection::isWordPress()) { add_action('admin_enqueue_scripts', function() { wp_enqueue_media(); }); // import form field class JLoader::import('adapter.form.field'); // create XML field manifest $xml = ""; // instantiate field $field = JFormField::getInstance(simplexml_load_string($xml)); // overwrite name and value within data $data['name'] = $name; $data['value'] = $value; // inject display data within field instance foreach ($data as $k => $v) { $field->bind($v, $k); } // render field return $field->render(); } // fallback to Joomla // init media field $field = new JFormFieldMedia(null, $value); // setup an empty form as placeholder $field->setForm(new JForm('vikbooking.media')); // force field attributes $data['name'] = $name; $data['value'] = $value; if (empty($data['previewWidth'])) { // there is no preview width, set a defualt value // to make the image visible within the popover $data['previewWidth'] = 480; } // render the field return $field->render('joomla.form.field.media', $data); } /** * Displays a multi-state toggle switch element with unlimited buttons. * Custom values, contents, labels, attributes and JS events can be attached * to each button. VCM will use this same method. * * @param string $name the input name equal for all radio buttons. * @param string $value the current input field value to be pre-selected. * @param array $values list of radio buttons with each value. * @param array $labels list of contents for each button trigger. * @param array $attrs list of associative array attributes for each button. * @param array $wrap list of associative array attributes for the wrapper. * * @return string the necessary HTML to render the multi-state toggle switch. * * @since 1.15.0 (J) - 1.5.0 (WP) */ public function multiStateToggleSwitchField($name, $value, $values = array(), $labels = array(), $attrs = array(), $wrap = array()) { static $tooltip_js_declared = null; // whether tooltip for titles is needed $needs_tooltip = false; // HTML container $multi_state_switch = ''; if (!is_array($values) || !count($values)) { // values must be set or we don't know what buttons to display return $multi_state_switch; } // build default classes for the tri-state toggle switch (with 3 buttons) $def_tristate_cls = array( 'vik-multiswitch-radiobtn-on', 'vik-multiswitch-radiobtn-def', 'vik-multiswitch-radiobtn-off', ); // start wrapper $multi_state_switch .= "\n" . '
' . "\n"; foreach ($values as $btn_k => $btn_val) { // build default classes for button label $btn_classes = array('vik-multiswitch-radiobtn'); if (isset($def_tristate_cls[$btn_k])) { // push default class for a 3-state toggle switch array_push($btn_classes, $def_tristate_cls[$btn_k]); } // check if additional custom classes have been defined for this button if (isset($attrs[$btn_k]) && isset($attrs[$btn_k]['label_class']) && !empty($attrs[$btn_k]['label_class'])) { if (is_array($attrs[$btn_k]['label_class'])) { // list of additional classes for this button $btn_classes = array_merge($btn_classes, $attrs[$btn_k]['label_class']); } elseif (is_string($attrs[$btn_k]['label_class'])) { // multiple classes should be space-separated array_push($btn_classes, $attrs[$btn_k]['label_class']); } } // check title as first thing, even though this is passed along with the labels $label_title = ''; if (isset($labels[$btn_k]) && !is_scalar($labels[$btn_k]) && isset($labels[$btn_k]['title'])) { $needs_tooltip = true; $label_title = ' title="' . addslashes(htmlentities($labels[$btn_k]['title'])) . '"'; } // start button label $multi_state_switch .= "\t" . '' . "\n"; } // end wrapper $multi_state_switch .= '
' . "\n"; // check tooltip JS rendering if (!$tooltip_js_declared && $needs_tooltip) { // turn static flag on $tooltip_js_declared = 1; // add script declaration for JS rendering of tooltips $doc = JFactory::getDocument(); $doc->addScriptDeclaration( <<getVisualEditorFonts(); $font_shortfam = $this->getVisualEditorFonts(true); $js_font_names = json_encode($font_shortfam); // build inline CSS styles $css_font_decl = ''; foreach ($font_families as $k => $font_name) { $font_val = $font_shortfam[$k]; $css_font_decl .= '.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="' . $font_val . '"]::before,'; $css_font_decl .= '.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="' . $font_val . '"]::before {' . "\n"; $css_font_decl .= 'content: "' . $font_name . '";' . "\n"; $css_font_decl .= 'font-family: "' . $font_name . '";' . "\n"; $css_font_decl .= '}' . "\n"; } $css_font_decl .= ' .ql-picker.ql-specialtags .ql-picker-label { padding-right: 18px; } .ql-picker.ql-specialtags .ql-picker-label:before { content: "' . htmlspecialchars(JText::translate('VBO_CONDTEXT_TKN')) . '"; } '; /** * Cache the pre-configuration CSS onto a file to allow AJAX requests * to properly load the asset inline within the response. Before this * change the styles used to be added as an inline style declaration. * * @since 1.16.7 (J) - 1.6.7 (WP) */ $cached_preconfig_css_path = implode(DIRECTORY_SEPARATOR, [VBO_ADMIN_PATH, 'resources', 'quill', 'vik-quill-preconfig-cache.css']); $cached_preconfig_css_uri = VBO_ADMIN_URI . 'resources/quill/vik-quill-preconfig-cache.css'; $cached_preconfig_css_ok = is_file($cached_preconfig_css_path); if (!$cached_preconfig_css_ok) { // attempt to create the file $cached_preconfig_css_ok = JFile::write($cached_preconfig_css_path, $css_font_decl); } if ($cached_preconfig_css_ok) { // load cached script file $doc->addStyleSheet($cached_preconfig_css_uri); } else { // revert to append CSS style declaration to document $doc->addStyleDeclaration($css_font_decl); } // append theme CSS to document $doc->addStyleSheet(VBO_ADMIN_URI . 'resources/quill/quill.snow.css'); // append JS assets to document $this->addScript(VBO_ADMIN_URI . 'resources/quill/quill.js'); $this->addScript(VBO_ADMIN_URI . 'resources/quill/quill-image-resize.min.js'); $this->addScript(VBO_ADMIN_URI . 'resources/quill/vik-content-builder.js'); // icon for mail wrapper $mail_wrapper_icn = ''; // icon for mail preview $mail_preview_icn = ''; // icon for property logo (home icon) $mail_homelogo_icn = ''; // build script pre-configuration string $quill_preconfig_script = <<addScript($cached_preconfig_script_uri); } else { // revert to append JS script declaration to document $doc->addScriptDeclaration($quill_preconfig_script); } } /** * Renders a third-party visual editor (Quill). * * @param string $name the input name of the textarea field. * @param string $value the current value of the textarea field/editor. * @param array $attrs list of associative array attributes for the textarea. * @param array $opts associative array of options for the editor. * @param array $btns associative array of custom buttons for the editor (special tags). * * @return string the necessary HTML to render the visual editor. * * @since 1.15.0 (J) - 1.5.0 (WP) */ public function renderVisualEditor($name, $value, $attrs = array(), $opts = array(), $btns = array()) { if (empty($name)) { return null; } // build the AJAX endpoint for uploading files and to preview the message $upload_endpoint = VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=upload_media_file'); $ajax_preview_mess = VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=mail.preview_visual_editor'); $ajax_logo_url = VikBooking::ajaxUrl('index.php?option=com_vikbooking&task=mail.get_default_logo'); // the HTML to build $editor = "\n"; // static editor counter static $editor_counter = 0; // increase counter for this instance $editor_counter++; // build id attributes for text and visual editors $editor_id = 'vik-contentbuilder-editor-' . $editor_counter; if (!isset($attrs['id'])) { $attrs['id'] = 'vik-contentbuilder-tarea-' . $editor_counter; } // textarea attributes $ta_attributes = array(); foreach ($attrs as $aname => $aval) { if ($aname == 'name') { // skip reserved attribute name continue; } $ta_attributes[] = $aname . '="' . JHtml::fetch('esc_attr', $aval) . '"'; } // labels for modes and editor $text_html_lbl = JText::translate('VBO_MODE_TEXTHTML'); $visual_mode_lbl = JText::translate('VBO_MODE_VISUAL'); JText::script('VBO_CONT_WRAPPER'); JText::script('VBO_CONT_WRAPPER_HELP'); // allowed modes to display the visual editor $allowed_modes = array( 'text' => $text_html_lbl, 'visual' => $visual_mode_lbl, 'modal-visual' => $visual_mode_lbl, ); // define the default buttons to display for mode switching $modes = array( 'text' => $text_html_lbl, 'modal-visual' => $visual_mode_lbl, ); // overwrite modes to display if (isset($opts['modes']) && is_array($opts['modes']) && count($opts['modes'])) { // check if the given array is associative, hence inclusive of texts if (array_keys($opts['modes']) != range(0, (count($opts['modes']) - 1))) { // replace modes $modes = $opts['modes']; } else { // only the allowed keys must have been passed $new_modes = array(); foreach ($opts['modes'] as $mode_type) { if (!isset($allowed_modes[$mode_type])) { continue; } $new_modes[$mode_type] = $allowed_modes[$mode_type]; } $modes = count($new_modes) ? $new_modes : $modes; } } // overwrite default mode if (isset($opts['def_mode']) && isset($modes[$opts['def_mode']]) && count($modes) > 1) { $def_mode_val = $modes[$opts['def_mode']]; unset($modes[$opts['def_mode']]); // sort modes accordingly $modes = array_merge(array($opts['def_mode'] => $def_mode_val), $modes); // reset the array pointer reset($modes); } // set default mode $default_mode = key($modes); // build visual editor JS options $js_editor_opts = [ 'snippetsyntax' => true, 'modules' => [ 'toolbar' => [ 'container' => [ [ [ 'font' => $this->getVisualEditorFonts(true) ], ], [ [ 'header' => [1, 2, 3, 4, 5, 6, false] ] ], [ 'bold', 'italic', 'underline', 'strike', 'blockquote', ], [ ['align' => []], ['indent' => '-1'], ['indent' => '+1'], ], [ [ 'color' => [] ], [ 'background' => [] ], ], [ ['list' => 'ordered'], ['list' => 'bullet'], ], [ 'link', 'image', 'homelogo', ], [ 'mailwrapper', 'preview', ], ], ], 'imageResize' => [ 'displaySize' => true, ], ], 'theme' => 'snow', ]; // build the list of special tags to be added to the editor $special_tags_btns = array(); foreach ($btns as $tag_val) { $special_tags_btns[] = $tag_val; } if (count($special_tags_btns)) { // add custom buttons to the editor to manage special tags $js_editor_opts['modules']['toolbar']['container'][] = array( array('specialtags' => $special_tags_btns) ); // append CSS inline styles $editor .= '' . "\n"; } // attept to pretty print a JSON encoded string for the editor options $editor_opts_str = defined('JSON_PRETTY_PRINT') ? json_encode($js_editor_opts, JSON_PRETTY_PRINT) : json_encode($js_editor_opts); // safe default value for editor (HTML tags should not be converted to entities) $safe_value = preg_replace("/(<\/ ?textarea>)+/i", '', $value); // the HTML to render the visual editor $html_visual_editor = '
'; // build the actual HTML content $editor .= '
' . "\n"; if (count($modes) > 1) { // display buttons to switch mode only if more than one mode available $editor .= "\t" . '
' . "\n"; foreach ($modes as $key => $val) { if (!isset($allowed_modes[$key])) { continue; } $editor .= ''; } $editor .= "\t" . '
' . "\n"; } $editor .= "\t" . '
' . "\n"; $editor .= "\t\t" . '' . "\n"; if (isset($modes['visual'])) { $editor .= "\t\t" . '
' . "\n"; $editor .= "\t\t\t" . $html_visual_editor . "\n"; $editor .= "\t\t" . '
' . "\n"; } if (isset($modes['modal-visual'])) { $editor .= "\t\t" . '
' . "\n"; $editor .= "\t\t\t" . '' . "\n"; $editor .= "\t\t\t" . '
' . "\n"; $editor .= "\t\t\t\t" . '
×
' . "\n"; $editor .= "\t\t\t\t" . '
' . "\n"; $editor .= "\t\t\t\t\t" . (!isset($modes['visual']) ? $html_visual_editor : '') . "\n"; $editor .= "\t\t\t\t" . '
' . "\n"; $editor .= "\t\t\t" . '
' . "\n"; $editor .= "\t\t" . '
' . "\n"; } $editor .= "\t" . '
' . "\n"; $editor .= '
' . "\n"; $editor .= "\n"; // add JS script to HTML content $editor .= '' . "\n"; // return the necessary HTML string to be displayed return $editor; } /** * Loads the necessary assets to render context menus. * * @return void * * @since 1.16.0 (J) - 1.6.0 (WP) */ public function loadContextMenuAssets() { static $loaded = null; if ($loaded) { return; } // get appearance preference $app_pref = VikBooking::getAppearancePref(); $dark_mode = 'null'; if ($app_pref == 'light') { $dark_mode = 'false'; } elseif ($app_pref == 'dark') { $dark_mode = 'true'; } $this->addScript(VBO_ADMIN_URI . 'resources/contextmenu.js'); $doc = JFactory::getDocument(); $doc->addStyleSheet(VBO_ADMIN_URI . 'resources/contextmenu.css'); $doc->addScriptDeclaration( <<addStyleSheet(VBO_SITE_URI . 'resources/intlTelInput.css'); $document->addScript(VBO_SITE_URI . 'resources/intlTelInput.js'); } }