/** * Construct a sanitiser from a given HTMLEditorConfig * * Note that we build data structures from the current state of HTMLEditorConfig - later changes to * the passed instance won't cause this instance to update it's whitelist * * @param HTMLEditorConfig $config */ public function __construct(HTMLEditorConfig $config) { $valid = $config->getOption('valid_elements'); if ($valid) { $this->addValidElements($valid); } $valid = $config->getOption('extended_valid_elements'); if ($valid) { $this->addValidElements($valid); } }
public function testSanitisation() { $tests = array(array('p,strong', '<p>Leave Alone</p><div>Strip parent<strong>But keep children</strong> in order</div>', '<p>Leave Alone</p>Strip parent<strong>But keep children</strong> in order', 'Non-whitelisted elements are stripped, but children are kept'), array('p,strong', '<div>A <strong>B <div>Nested elements are still filtered</div> C</strong> D</div>', 'A <strong>B Nested elements are still filtered C</strong> D', 'Non-whitelisted elements are stripped even when children of non-whitelisted elements'), array('p', '<p>Keep</p><script>Strip <strong>including children</strong></script>', '<p>Keep</p>', 'Non-whitelisted script elements are totally stripped, including any children'), array('p[id]', '<p id="keep" bad="strip">Test</p>', '<p id="keep">Test</p>', 'Non-whitelisted attributes are stripped'), array('p[default1=default1|default2=default2|force1:force1|force2:force2]', '<p default1="specific1" force1="specific1">Test</p>', '<p default1="specific1" force1="force1" default2="default2" force2="force2">Test</p>', 'Default attributes are set when not present in input, forced attributes are always set')); $config = HTMLEditorConfig::get('htmleditorsanitisertest'); foreach ($tests as $test) { list($validElements, $input, $output, $desc) = $test; $config->setOptions(array('valid_elements' => $validElements)); $sanitiser = new HtmlEditorSanitiser($config); $htmlValue = Injector::inst()->create('HTMLValue', $input); $sanitiser->sanitise($htmlValue); $this->assertEquals($output, $htmlValue->getContent(), $desc); } }
public function testRequireJSIncludesAllConfigs() { $a = HTMLEditorConfig::get('configA'); $c = HTMLEditorConfig::get('configB'); $aAttributes = $a->getAttributes(); $cAttributes = $c->getAttributes(); $this->assertNotEmpty($aAttributes['data-config']); $this->assertNotEmpty($cAttributes['data-config']); }
public function saveInto(DataObjectInterface $record) { if ($record->hasField($this->name) && $record->escapeTypeForField($this->name) != 'xml') { throw new Exception('HTMLEditorField->saveInto(): This field should save into a HTMLText or HTMLVarchar field.'); } // Sanitise if requested $htmlValue = Injector::inst()->create('HTMLValue', $this->Value()); if ($this->config()->sanitise_server_side) { $santiser = Injector::inst()->create('HTMLEditorSanitiser', HTMLEditorConfig::get_active()); $santiser->sanitise($htmlValue); } // optionally manipulate the HTML after a TinyMCE edit and prior to a save $this->extend('processHTML', $htmlValue); // Store into record $record->{$this->name} = $htmlValue->getContent(); }
/** * Returns the wrapped config * * @return HtmlEditorConfig */ function getConfig() { return HTMLEditorConfig::get($this->configIdentifier); }
/** * @uses LeftAndMainExtension->init() * @uses LeftAndMainExtension->accessedCMS() * @uses CMSMenu */ protected function init() { parent::init(); Config::inst()->update('SSViewer', 'rewrite_hash_links', false); Config::inst()->update('ContentNegotiator', 'enabled', false); // set language $member = Member::currentUser(); if (!empty($member->Locale)) { i18n::set_locale($member->Locale); } if (!empty($member->DateFormat)) { i18n::config()->date_format = $member->DateFormat; } if (!empty($member->TimeFormat)) { i18n::config()->time_format = $member->TimeFormat; } // can't be done in cms/_config.php as locale is not set yet CMSMenu::add_link('Help', _t('LeftAndMain.HELP', 'Help', 'Menu title'), $this->config()->help_link, -2, array('target' => '_blank')); // Allow customisation of the access check by a extension // Also all the canView() check to execute Controller::redirect() if (!$this->canView() && !$this->getResponse()->isFinished()) { // When access /admin/, we should try a redirect to another part of the admin rather than be locked out $menu = $this->MainMenu(); foreach ($menu as $candidate) { if ($candidate->Link && $candidate->Link != $this->Link() && $candidate->MenuItem->controller && singleton($candidate->MenuItem->controller)->canView()) { $this->redirect($candidate->Link); return; } } if (Member::currentUser()) { Session::set("BackURL", null); } // if no alternate menu items have matched, return a permission error $messageSet = array('default' => _t('LeftAndMain.PERMDEFAULT', "You must be logged in to access the administration area; please enter your credentials below."), 'alreadyLoggedIn' => _t('LeftAndMain.PERMALREADY', "I'm sorry, but you can't access that part of the CMS. If you want to log in as someone else, do" . " so below."), 'logInAgain' => _t('LeftAndMain.PERMAGAIN', "You have been logged out of the CMS. If you would like to log in again, enter a username and" . " password below.")); Security::permissionFailure($this, $messageSet); return; } // Don't continue if there's already been a redirection request. if ($this->redirectedTo()) { return; } // Audit logging hook if (empty($_REQUEST['executeForm']) && !$this->getRequest()->isAjax()) { $this->extend('accessedCMS'); } // Set the members html editor config if (Member::currentUser()) { HTMLEditorConfig::set_active_identifier(Member::currentUser()->getHtmlEditorConfigForCMS()); } // Set default values in the config if missing. These things can't be defined in the config // file because insufficient information exists when that is being processed $htmlEditorConfig = HTMLEditorConfig::get_active(); $htmlEditorConfig->setOption('language', i18n::get_tinymce_lang()); Requirements::customScript("\n\t\t\twindow.ss = window.ss || {};\n\t\t\twindow.ss.config = " . $this->getCombinedClientConfig() . ";\n\t\t"); Requirements::javascript(FRAMEWORK_ADMIN_DIR . '/client/dist/js/bundle-lib.js', ['provides' => [THIRDPARTY_DIR . '/jquery/jquery.js', THIRDPARTY_DIR . '/jquery-ui/jquery-ui.js', THIRDPARTY_DIR . '/jquery-entwine/dist/jquery.entwine-dist.js', THIRDPARTY_DIR . '/jquery-cookie/jquery.cookie.js', THIRDPARTY_DIR . '/jquery-query/jquery.query.js', THIRDPARTY_DIR . '/jquery-form/jquery.form.js', THIRDPARTY_DIR . '/jquery-ondemand/jquery.ondemand.js', THIRDPARTY_DIR . '/jquery-changetracker/lib/jquery.changetracker.js', THIRDPARTY_DIR . '/jstree/jquery.jstree.js', FRAMEWORK_ADMIN_DIR . '/thirdparty/jquery-notice/jquery.notice.js', FRAMEWORK_ADMIN_DIR . '/thirdparty/jsizes/lib/jquery.sizes.js', FRAMEWORK_ADMIN_DIR . '/thirdparty/jlayout/lib/jlayout.border.js', FRAMEWORK_ADMIN_DIR . '/thirdparty/jlayout/lib/jquery.jlayout.js', FRAMEWORK_ADMIN_DIR . '/thirdparty/chosen/chosen/chosen.jquery.js', FRAMEWORK_ADMIN_DIR . '/thirdparty/jquery-hoverIntent/jquery.hoverIntent.js', FRAMEWORK_DIR . '/client/dist/js/TreeDropdownField.js', FRAMEWORK_DIR . '/client/dist/js/DateField.js', FRAMEWORK_DIR . '/client/dist/js/HtmlEditorField.js', FRAMEWORK_DIR . '/client/dist/js/TabSet.js', FRAMEWORK_DIR . '/client/dist/js/GridField.js', FRAMEWORK_DIR . '/client/dist/js/i18n.js', FRAMEWORK_ADMIN_DIR . '/client/dist/js/sspath.js', FRAMEWORK_ADMIN_DIR . '/client/dist/js/ssui.core.js']]); Requirements::javascript(FRAMEWORK_ADMIN_DIR . '/client/dist/js/bundle-legacy.js', ['provides' => [FRAMEWORK_ADMIN_DIR . '/client/dist/js/LeftAndMain.Layout.js', FRAMEWORK_ADMIN_DIR . '/client/dist/js/LeftAndMain.js', FRAMEWORK_ADMIN_DIR . '/client/dist/js/LeftAndMain.ActionTabSet.js', FRAMEWORK_ADMIN_DIR . '/client/dist/js/LeftAndMain.Panel.js', FRAMEWORK_ADMIN_DIR . '/client/dist/js/LeftAndMain.Tree.js', FRAMEWORK_ADMIN_DIR . '/client/dist/js/LeftAndMain.Content.js', FRAMEWORK_ADMIN_DIR . '/client/dist/js/LeftAndMain.EditForm.js', FRAMEWORK_ADMIN_DIR . '/client/dist/js/LeftAndMain.Menu.js', FRAMEWORK_ADMIN_DIR . '/client/dist/js/LeftAndMain.Preview.js', FRAMEWORK_ADMIN_DIR . '/client/dist/js/LeftAndMain.BatchActions.js', FRAMEWORK_ADMIN_DIR . '/client/dist/js/LeftAndMain.FieldHelp.js', FRAMEWORK_ADMIN_DIR . '/client/dist/js/LeftAndMain.FieldDescriptionToggle.js', FRAMEWORK_ADMIN_DIR . '/client/dist/js/LeftAndMain.TreeDropdownField.js', FRAMEWORK_ADMIN_DIR . '/client/dist/js/AddToCampaignForm.js']]); Requirements::add_i18n_javascript(FRAMEWORK_DIR . '/client/lang', false, true); Requirements::add_i18n_javascript(FRAMEWORK_ADMIN_DIR . '/client/lang', false, true); if ($this->config()->session_keepalive_ping) { Requirements::javascript(FRAMEWORK_ADMIN_DIR . '/client/dist/js/LeftAndMain.Ping.js'); } if (Director::isDev()) { // TODO Confuses jQuery.ondemand through document.write() Requirements::javascript(THIRDPARTY_DIR . '/jquery-entwine/src/jquery.entwine.inspector.js'); Requirements::javascript(FRAMEWORK_ADMIN_DIR . '/client/dist/js/leaktools.js'); } Requirements::javascript(FRAMEWORK_ADMIN_DIR . '/client/dist/js/bundle-framework.js'); Requirements::css(FRAMEWORK_ADMIN_DIR . '/thirdparty/jquery-notice/jquery.notice.css'); Requirements::css(THIRDPARTY_DIR . '/jquery-ui-themes/smoothness/jquery-ui.css'); Requirements::css(THIRDPARTY_DIR . '/jstree/themes/apple/style.css'); Requirements::css(FRAMEWORK_DIR . '/client/dist/styles/TreeDropdownField.css'); Requirements::css(FRAMEWORK_ADMIN_DIR . '/client/dist/styles/bundle.css'); Requirements::css(FRAMEWORK_DIR . '/client/dist/styles/GridField.css'); // Custom requirements $extraJs = $this->stat('extra_requirements_javascript'); if ($extraJs) { foreach ($extraJs as $file => $config) { if (is_numeric($file)) { $file = $config; } Requirements::javascript($file); } } $extraCss = $this->stat('extra_requirements_css'); if ($extraCss) { foreach ($extraCss as $file => $config) { if (is_numeric($file)) { $file = $config; $config = array(); } Requirements::css($file, isset($config['media']) ? $config['media'] : null); } } $extraThemedCss = $this->stat('extra_requirements_themedCss'); if ($extraThemedCss) { foreach ($extraThemedCss as $file => $config) { if (is_numeric($file)) { $file = $config; $config = array(); } Requirements::themedCSS($file, isset($config['media']) ? $config['media'] : null); } } $dummy = null; $this->extend('init', $dummy); // Assign default cms theme and replace user-specified themes SSViewer::set_themes($this->config()->admin_themes); //set the reading mode for the admin to stage Versioned::set_stage(Versioned::DRAFT); }
/** * Return this field's HTMLEditorConfig * * @return HTMLEditorConfig */ function getEditorConfig() { return HTMLEditorConfig::get($this->getEditorConfigID()); }
<?php // Default CMS HTMLEditorConfig HTMLEditorConfig::get('cms')->setOptions(array('friendly_name' => 'Default CMS', 'priority' => '50', 'body_class' => 'typography', 'contextmenu' => "sslink ssmedia inserttable | cell row column deletetable", 'use_native_selects' => false, 'valid_elements' => "@[id|class|style|title],a[id|rel|rev|dir|tabindex|accesskey|type|name|href|target|title" . "|class],-strong/-b[class],-em/-i[class],-strike[class],-u[class],#p[id|dir|class|align|style],-ol[class]," . "-ul[class],-li[class],br,img[id|dir|longdesc|usemap|class|src|border|alt=|title|width|height|align|data*]," . "-sub[class],-sup[class],-blockquote[dir|class],-cite[dir|class|id|title]," . "-table[cellspacing|cellpadding|width|height|class|align|summary|dir|id|style]," . "-tr[id|dir|class|rowspan|width|height|align|valign|bgcolor|background|bordercolor|style]," . "tbody[id|class|style],thead[id|class|style],tfoot[id|class|style]," . "#td[id|dir|class|colspan|rowspan|width|height|align|valign|scope|style]," . "-th[id|dir|class|colspan|rowspan|width|height|align|valign|scope|style],caption[id|dir|class]," . "-div[id|dir|class|align|style],-span[class|align|style],-pre[class|align],address[class|align]," . "-h1[id|dir|class|align|style],-h2[id|dir|class|align|style],-h3[id|dir|class|align|style]," . "-h4[id|dir|class|align|style],-h5[id|dir|class|align|style],-h6[id|dir|class|align|style],hr[class]," . "dd[id|class|title|dir],dl[id|class|title|dir],dt[id|class|title|dir]", 'extended_valid_elements' => "img[class|src|alt|title|hspace|vspace|width|height|align|onmouseover|onmouseout|name" . "|usemap|data*],iframe[src|name|width|height|align|frameborder|marginwidth|marginheight|scrolling]," . "object[width|height|data|type],param[name|value],map[class|name|id],area[shape|coords|href|target|alt]")); HTMLEditorConfig::get('cms')->enablePlugins(array('contextmenu' => null, 'image' => null, 'ssbuttons' => FRAMEWORK_DIR . '/client/dist/js/TinyMCE_SSPlugin.js')); CMSMenu::remove_menu_class('CMSProfileController');
/** * Set the currently active configuration object. Note that the existing active * config will not be renamed to the new identifier. * * @param string $identifier The identifier for the config set */ public static function set_active_identifier($identifier) { self::$current = $identifier; }