. * * @category WYSIWYG * @package StatusNet * @author Evan Prodromou * @copyright 2010 StatusNet, Inc. * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 * @link http://status.net/ */ if (!defined('STATUSNET')) { // This check helps protect against security problems; // your code file can't be executed directly from the web. exit(1); } /** * Use TinyMCE library to allow rich text editing in the browser * * Converts the notice form in browser to a rich-text editor. * * @category WYSIWYG * @package StatusNet * @author Evan Prodromou * @copyright 2010 StatusNet, Inc. * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 * @link http://status.net/ */ class TinyMCEPlugin extends Plugin { var $html; function onEndShowScripts($action) { if (common_logged_in ()) { $action->script(common_path('plugins/TinyMCE/js/jquery.tinymce.js')); $action->inlineScript($this->_inlineScript()); } return true; } function onEndShowStyles($action) { $action->style('span#notice_data-text_container, span#notice_data-text_parent { float: left }'); return true; } function onPluginVersion(&$versions) { $versions[] = array('name' => 'TinyMCE', 'version' => STATUSNET_VERSION, 'author' => 'Evan Prodromou', 'homepage' => 'http://status.net/wiki/Plugin:TinyMCE', 'rawdescription' => _m('Use TinyMCE library to allow rich text editing in the browser')); return true; } /** * Sanitize HTML input and strip out potentially dangerous bits. * * @param string $raw HTML * @return string HTML */ private function sanitizeHtml($raw) { require_once INSTALLDIR . '/extlib/htmLawed/htmLawed.php'; $config = array('safe' => 1, 'deny_attribute' => 'id,style,on*'); return htmLawed($raw, $config); } /** * Strip HTML to plaintext string * * @param string $html HTML * @return string plaintext, single line */ private function stripHtml($html) { return str_replace("\n", " ", html_entity_decode(strip_tags($html))); } /** * Hook for new-notice form processing to take our HTML goodies; * won't affect API posting etc. * * @param NewNoticeAction $action * @param User $user * @param string $content * @param array $options * @return boolean hook return */ function onStartSaveNewNoticeWeb($action, $user, &$content, &$options) { if ($action->arg('richedit')) { $html = $this->sanitizeHtml($content); $options['rendered'] = $html; $content = $this->stripHtml($html); } return true; } /** * Hook for new-notice form processing to process file upload appending... * * @param NewNoticeAction $action * @param MediaFile $media * @param string $content * @param array $options * @return boolean hook return */ function onStartSaveNewNoticeAppendAttachment($action, $media, &$content, &$options) { if ($action->arg('richedit')) { // See if we've got a placeholder inline image; if so, fill it! $dom = new DOMDocument(); common_log(LOG_INFO, 'QQQQQQQQQQQQQQQQQQQQQQQQ'); if ($dom->loadHTML($options['rendered'])) { $imgs = $dom->getElementsByTagName('img'); foreach ($imgs as $img) { common_log(LOG_INFO, 'img: ' . var_export($img, true)); if (preg_match('/(^| )placeholder( |$)/', $img->getAttribute('class'))) { common_log(LOG_INFO, 'QQQQQQ: img src: ' . $media->fileRecord->url); $img->setAttribute('src', $media->fileRecord->url); $holderWidth = intval($img->getAttribute('width')); $holderHeight = intval($img->getAttribute('height')); $holderAspect = $holderWidth / $holderHeight; $path = File::path($media->filename); $imgInfo = getimagesize($path); common_log(LOG_INFO, 'QQQQQQ: ' . $path . ' : ' . var_export($imgInfo, true)); $origWidth = $imgInfo[0]; $origHeight = $imgInfo[1]; $origAspect = $origWidth / $origHeight; if ($origAspect >= 1.0) { // wide image if ($origWidth > $holderWidth) { $width = $holderWidth; $height = intval($holderWidth / $origAspect); } else { $width = $origWidth; $height = $origHeight; } } else { if ($origHeight > $holderHeight) { $height = $holderHeight; $width = ($holderWidth * $origAspect); } else { $width = $origWidth; $height = $origHeight; } } $img->setAttribute('width', $width); $img->setAttribute('height', $height); common_log(LOG_INFO, 'QQQQQ: ' . $width . ' ' . $height); } } $html = $dom->saveHTML(); common_log(LOG_INFO, 'QQQQQQ: out: ' . $html); $options['rendered'] = $html; } // The regular code will append the short URL to the plaintext content. // Carry on and let it through... } return true; } function _inlineScript() { $path = common_path('plugins/TinyMCE/js/tiny_mce.js'); // Note: the normal on-submit triggering to save data from // the HTML editor into the textarea doesn't play well with // our AJAX form submission. Manually moving it to trigger // on our send button click. $scr = <<'); $('#notice_action-submit').click(function() { if (typeof tinymce != "undefined") { tinymce.triggerSave(); } }); $('#'+SN.C.S.NoticeDataAttach).change(function() { /* S = '
'+$(this).val()+'
'; NDAS = $('#'+SN.C.S.NoticeDataAttachSelected); if (NDAS.length > 0) { NDAS.replaceWith(S); } */ //alert('yay'); var img = ''; var html = tinyMCE.activeEditor.getContent(); tinyMCE.activeEditor.setContent(html + img); }); }); END_OF_SCRIPT; return $scr; } }