BxFroalaEditor.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. <?php defined('BX_DOL') or die('hack attempt');
  2. /**
  3. * Copyright (c) UNA, Inc - https://una.io
  4. * MIT License - https://opensource.org/licenses/MIT
  5. *
  6. * @defgroup Froala Froala editor integration
  7. * @ingroup UnaModules
  8. *
  9. * @{
  10. */
  11. /**
  12. * Froala editor representation.
  13. * @see BxDolEditor
  14. */
  15. class BxFroalaEditor extends BxDolEditor
  16. {
  17. protected $_sModule;
  18. /**
  19. * Common initialization params
  20. */
  21. protected static $CONF_COMMON = <<<EOS
  22. new FroalaEditor('{bx_var_selector}', {
  23. {bx_var_custom_init}
  24. {bx_var_custom_conf}
  25. key:'SDB17hD9B4F4B3eMRPYa1c1REe1BGQOQIc1CDBREJImD6F5F4I4E1B9B6C3F5C4==',
  26. attribution: false,
  27. embedlyKey: '{bx_var_embedly_key}',
  28. emoticonsUseImage: false,
  29. charCounterCount: false,
  30. toolbarSticky: false,
  31. quickInsertTags: [],
  32. pastePlain: true,
  33. entities: '',
  34. imageUpload: true,
  35. imageUploadURL: '{bx_var_image_upload_url}',
  36. videoUpload: false,
  37. language: '{bx_var_lang}',
  38. theme: '{bx_var_skin}',
  39. iconsTemplate: '{bx_var_icons_template}',
  40. events: {
  41. 'initialized': function () {
  42. var editor = this;
  43. \$('{bx_var_selector}').data('froala-instance', editor);
  44. \$(editor.el).atwho({
  45. searchKey: 'label',
  46. at: "@",
  47. limit: 20,
  48. displayTpl: '<li class="bx-mention-row" data-value="\${value}"><span>\${label}</span> <img class="bx-def-round-corners" src="\${thumb}" /></li>',
  49. insertTpl: '<a class="bx-mention" data-profile-id="\${value}" href="\${url}">\${label}</a>',
  50. callbacks: {
  51. remoteFilter: function(query, callback) {
  52. $.getJSON("{bx_url_root}searchExtended.php?action=get_authors", {term: query}, function(data) {
  53. callback(data);
  54. });
  55. }
  56. },
  57. });
  58. bx_editor_on_init('{bx_var_selector}');
  59. },
  60. 'keydown': function (e) {
  61. var editor = this;
  62. if (e.which == FroalaEditor.KEYCODE.ENTER || e.which == FroalaEditor.KEYCODE.SPACE)
  63. bx_editor_on_space_enter('{bx_var_selector}');
  64. if (e.which == FroalaEditor.KEYCODE.ENTER && \$(editor.el).atwho('isSelecting'))
  65. return false;
  66. },
  67. }
  68. });
  69. EOS;
  70. /**
  71. * Standard view initialization params
  72. */
  73. protected static $CONF_STANDARD = "";
  74. /**
  75. * Minimal view initialization params
  76. */
  77. protected static $CONF_MINI = "";
  78. /**
  79. * Full view initialization params
  80. */
  81. protected static $CONF_FULL = "";
  82. /**
  83. * Available editor languages
  84. */
  85. protected static $CONF_LANGS = array('ar' => 1, 'bs' => 1, 'cs' => 1, 'da' => 1, 'de' => 1, 'el' => 1, 'en_ca' => 1, 'en_gb' => 1, 'es' => 1, 'et' => 1, 'fa' => 1, 'fi' => 1, 'fr' => 1, 'he' => 1, 'hr' => 1, 'hu' => 1, 'id' => 1, 'it' => 1, 'ja' => 1, 'ko' => 1, 'ku' => 1, 'me' => 1, 'nb' => 1, 'nl' => 1, 'pl' => 1, 'pt_br' => 1, 'pt_pt' => 1, 'ro' => 1, 'ru' => 1, 'sk' => 1, 'sr' => 1, 'sv' => 1, 'th' => 1, 'tr' => 1, 'uk' => 1, 'vi' => 1, 'zh_cn' => 1, 'zh_tw' => 1);
  86. protected $_oTemplate;
  87. protected $_bJsCssAdded = false;
  88. public function __construct ($aObject, $oTemplate)
  89. {
  90. parent::__construct ($aObject);
  91. $this->_sModule = 'bx_froala';
  92. if ($oTemplate)
  93. $this->_oTemplate = $oTemplate;
  94. else
  95. $this->_oTemplate = BxDolTemplate::getInstance();
  96. $this->_aSkins = array(
  97. 'dark' => array('name' => 'dark', 'title' => '_bx_froala_txt_skin_dark'),
  98. 'gray' => array('name' => 'gray', 'title' => '_bx_froala_txt_skin_gray'),
  99. 'royal' => array('name' => 'royal', 'title' => '_bx_froala_txt_skin_royal')
  100. );
  101. }
  102. /**
  103. * Attach editor to HTML element, in most cases - textarea.
  104. * @param $sSelector - jQuery selector to attach editor to.
  105. * @param $iViewMode - editor view mode: BX_EDITOR_STANDARD, BX_EDITOR_MINI, BX_EDITOR_FULL
  106. * @param $bDynamicMode - is AJAX mode or not, the HTML with editor area is loaded dynamically.
  107. */
  108. public function attachEditor ($sSelector, $iViewMode = BX_EDITOR_STANDARD, $bDynamicMode = false)
  109. {
  110. // set visual mode
  111. switch ($iViewMode) {
  112. case BX_EDITOR_MINI:
  113. $sToolbarItems = $this->_getToolbarItems(getParam('bx_froala_option_toolbar_mini'));
  114. $sToolbarItemsXC = $this->_getToolbarItems(getParam('bx_froala_option_toolbar_mini_mobile'));
  115. $sCustomInit = self::$CONF_MINI;
  116. break;
  117. case BX_EDITOR_FULL:
  118. $sToolbarItems = $this->_getToolbarItems(getParam('bx_froala_option_toolbar_full'));
  119. $sToolbarItemsXC = $this->_getToolbarItems(getParam('bx_froala_option_toolbar_full_mobile'));
  120. $sCustomInit = self::$CONF_FULL;
  121. break;
  122. case BX_EDITOR_STANDARD:
  123. default:
  124. $sToolbarItems = $this->_getToolbarItems(getParam('bx_froala_option_toolbar_standard'));
  125. $sToolbarItemsXC = $this->_getToolbarItems(getParam('bx_froala_option_toolbar_standard_mobile'));
  126. $sCustomInit = self::$CONF_STANDARD;
  127. }
  128. $sCustomInit .= "\ntoolbarButtons: " . $sToolbarItems . ",";
  129. $sCustomInit .= "\ntoolbarButtonsXS: " . $sToolbarItemsXC . ",";
  130. // detect language
  131. $sLang = BxDolLanguages::getInstance()->detectLanguageFromArray (self::$CONF_LANGS, 'en', true);
  132. $sCss = 'editor.less';
  133. $aCss = BxDolTemplate::getInstance()->_lessCss(array(
  134. 'path' => $this->_oTemplate->getCssPath($sCss),
  135. 'url' => $this->_oTemplate->getCssUrl($sCss)
  136. ));
  137. $oModule = BxDolModule::getInstance($this->_sModule);
  138. // allow insert any tags for admins
  139. if(isAdmin())
  140. $this->_sConfCustom .= 'htmlRemoveTags: [],';
  141. // initialize editor
  142. $aMarkers = array(
  143. 'bx_var_custom_init' => $sCustomInit,
  144. 'bx_var_custom_conf' => $this->_sConfCustom,
  145. 'bx_var_plugins_path' => bx_js_string(BX_DOL_URL_PLUGINS_PUBLIC, BX_ESCAPE_STR_APOS),
  146. 'bx_var_css_path' => bx_js_string($aCss['url'], BX_ESCAPE_STR_APOS),
  147. 'bx_var_skin' => bx_js_string($this->_sSkin, BX_ESCAPE_STR_APOS),
  148. 'bx_var_lang' => bx_js_string($sLang, BX_ESCAPE_STR_APOS),
  149. 'bx_var_selector' => bx_js_string($sSelector, BX_ESCAPE_STR_APOS),
  150. 'bx_url_root' => bx_js_string(BX_DOL_URL_ROOT, BX_ESCAPE_STR_APOS),
  151. 'bx_var_embedly_key' => bx_js_string(getParam('sys_embedly_api_key'), BX_ESCAPE_STR_APOS),
  152. 'bx_var_image_upload_url' => $oModule ? BX_DOL_URL_ROOT . $oModule->_oConfig->getBaseUri() . 'upload' : '',
  153. 'bx_var_icons_template' => getParam('bx_froala_icons_template'),
  154. );
  155. $sInitEditor = $this->_replaceMarkers(self::$CONF_COMMON, $aMarkers);
  156. bx_alert($this->_sModule, 'init_editor', 0, false, array(
  157. 'conf_common' => self::$CONF_COMMON,
  158. 'markers' => $aMarkers,
  159. 'override_result' => &$sInitEditor
  160. ));
  161. if ($bDynamicMode) {
  162. list($aJs, $aCss) = $this->_getJsCss(true);
  163. $sCss = $this->_oTemplate->addCss($aCss, true);
  164. $sScript = $sCss . "<script>
  165. if ('undefined' == typeof(window.FroalaEditor)) {
  166. bx_get_scripts(" . json_encode($aJs) . ", function () {
  167. $sInitEditor
  168. });
  169. } else {
  170. setTimeout(function () {
  171. $sInitEditor
  172. }, 10); // wait while html is rendered in case of dynamic adding html
  173. }
  174. </script>";
  175. } else {
  176. $sScript = "
  177. <script>
  178. $(document).ready(function () {
  179. $sInitEditor
  180. });
  181. </script>";
  182. }
  183. return $this->_addJsCss($bDynamicMode) . $sScript;
  184. }
  185. protected function _getToolbarItems($s)
  186. {
  187. if ($this->_sButtonsCustom !== false)
  188. return $this->_sButtonsCustom && '{' == $this->_sButtonsCustom[0] ? $this->_sButtonsCustom : json_encode(explode(',', $this->_sButtonsCustom));
  189. return $s && '{' == $s[0] ? $s : json_encode(explode(',', $s));
  190. }
  191. /**
  192. * Add css/js files which are needed for editor display and functionality.
  193. */
  194. protected function _addJsCss($bDynamicMode = false, $sInitEditor = '')
  195. {
  196. if ($bDynamicMode)
  197. return '';
  198. if ($this->_bJsCssAdded)
  199. return '';
  200. list($aJs, $aCss) = $this->_getJsCss();
  201. $this->_oTemplate->addJs($aJs);
  202. $this->_oTemplate->addCss($aCss);
  203. $this->_bJsCssAdded = true;
  204. return '';
  205. }
  206. protected function _getPlugins($b3rdParty = false)
  207. {
  208. $a3rdParty = array('embedly', 'image_aviary', 'spell_checker');
  209. $a = explode(',', $this->_sPluginsCustom !== false ? $this->_sPluginsCustom : getParam('bx_froala_option_plugins'));
  210. return array_filter($a, function ($s) use ($a3rdParty, $b3rdParty) {
  211. return !($b3rdParty ^ in_array($s, $a3rdParty));
  212. });
  213. }
  214. protected function _getJsCss($bUseUrlsForJs = false)
  215. {
  216. $sLang = BxDolLanguages::getInstance()->detectLanguageFromArray (self::$CONF_LANGS, 'en', true);
  217. $sJsPrefix = $bUseUrlsForJs ? BX_DOL_URL_MODULES : BX_DIRECTORY_PATH_MODULES;
  218. $sJsSuffix = $bUseUrlsForJs ? '' : '|';
  219. $aJs = array(
  220. $sJsPrefix . 'boonex/froala/js/' . $sJsSuffix . 'editor.js',
  221. $sJsPrefix . 'boonex/froala/plugins/froala/js/' . $sJsSuffix . 'froala_editor.pkgd.min.js',
  222. );
  223. if ($sLang && 'en' != $sLang)
  224. $aJs[] = $sJsPrefix . 'boonex/froala/plugins/froala/js/languages/' . $sJsSuffix . $sLang . '.js';
  225. $aCss = array(
  226. BX_DIRECTORY_PATH_MODULES . 'boonex/froala/template/css/|editor.css',
  227. BX_DIRECTORY_PATH_MODULES . 'boonex/froala/plugins/froala/css/|froala_editor.pkgd.min.css',
  228. BX_DIRECTORY_PATH_MODULES . 'boonex/froala/plugins/froala/css/|froala_style.min.css',
  229. BX_DIRECTORY_PATH_MODULES . 'boonex/froala/plugins/froala/css/themes/|' . $this->_sSkin . '.min.css',
  230. );
  231. $aPlugins = $this->_getPlugins(true);
  232. foreach ($aPlugins as $sPlugin) {
  233. $aJs[] = $sJsPrefix . 'boonex/froala/plugins/froala/js/third_party/' . $sJsSuffix . $sPlugin . '.min.js';
  234. $aCss[] = BX_DIRECTORY_PATH_MODULES . 'boonex/froala/plugins/froala/css/third_party/|' . $sPlugin . '.min.css';
  235. }
  236. $aPlugins = $this->_getPlugins(false);
  237. foreach ($aPlugins as $sPlugin) {
  238. $aJs[] = $sJsPrefix . 'boonex/froala/plugins/froala/js/plugins/' . $sJsSuffix . $sPlugin . '.min.js';
  239. $aCss[] = BX_DIRECTORY_PATH_MODULES . 'boonex/froala/plugins/froala/css/plugins/|' . $sPlugin . '.min.css';
  240. }
  241. return array($aJs, $aCss);
  242. }
  243. }
  244. /** @} */