qa-wysiwyg-editor.php 8.09 KB
Newer Older
Gideon Greenspan committed
1 2 3 4 5 6 7
<?php

/*
	Question2Answer (c) Gideon Greenspan

	http://www.question2answer.org/

8

Gideon Greenspan committed
9 10 11 12 13 14 15 16 17
	File: qa-plugin/wysiwyg-editor/qa-wysiwyg-editor.php
	Version: See define()s at top of qa-include/qa-base.php
	Description: Editor module class for WYSIWYG editor plugin


	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.
18

Gideon Greenspan committed
19 20 21 22 23 24 25 26
	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	More about this license: http://www.question2answer.org/license.php
*/

Gideon Greenspan committed
27

28 29 30
class qa_wysiwyg_editor
{
	private $urltoroot;
31

32 33 34 35
	public function load_module($directory, $urltoroot)
	{
		$this->urltoroot = $urltoroot;
	}
36

37 38 39 40
	public function option_default($option)
	{
		if ($option == 'wysiwyg_editor_upload_max_size') {
			require_once QA_INCLUDE_DIR.'qa-app-upload.php';
41

42
			return min(qa_get_max_upload_size(), 1048576);
Gideon Greenspan committed
43
		}
44
	}
45

46 47 48
	public function admin_form(&$qa_content)
	{
		require_once QA_INCLUDE_DIR.'qa-app-upload.php';
49

50
		$saved = false;
51

52 53 54 55 56 57
		if (qa_clicked('wysiwyg_editor_save_button')) {
			qa_opt('wysiwyg_editor_upload_images', (int)qa_post_text('wysiwyg_editor_upload_images_field'));
			qa_opt('wysiwyg_editor_upload_all', (int)qa_post_text('wysiwyg_editor_upload_all_field'));
			qa_opt('wysiwyg_editor_upload_max_size', min(qa_get_max_upload_size(), 1048576*(float)qa_post_text('wysiwyg_editor_upload_max_size_field')));
			$saved = true;
		}
58

59 60 61 62
		qa_set_display_rules($qa_content, array(
			'wysiwyg_editor_upload_all_display' => 'wysiwyg_editor_upload_images_field',
			'wysiwyg_editor_upload_max_size_display' => 'wysiwyg_editor_upload_images_field',
		));
63

64 65
		return array(
			'ok' => $saved ? 'WYSIWYG editor settings saved' : null,
Gideon Greenspan committed
66

67 68 69 70 71 72
			'fields' => array(
				array(
					'label' => 'Allow images to be uploaded',
					'type' => 'checkbox',
					'value' => (int)qa_opt('wysiwyg_editor_upload_images'),
					'tags' => 'name="wysiwyg_editor_upload_images_field" id="wysiwyg_editor_upload_images_field"',
Gideon Greenspan committed
73
				),
74

75 76 77 78 79 80
				array(
					'id' => 'wysiwyg_editor_upload_all_display',
					'label' => 'Allow other content to be uploaded, e.g. Flash, PDF',
					'type' => 'checkbox',
					'value' => (int)qa_opt('wysiwyg_editor_upload_all'),
					'tags' => 'name="wysiwyg_editor_upload_all_field"',
Gideon Greenspan committed
81
				),
82

83 84 85 86 87 88 89 90 91
				array(
					'id' => 'wysiwyg_editor_upload_max_size_display',
					'label' => 'Maximum size of uploads:',
					'suffix' => 'MB (max '.$this->bytes_to_mega_html(qa_get_max_upload_size()).')',
					'type' => 'number',
					'value' => $this->bytes_to_mega_html(qa_opt('wysiwyg_editor_upload_max_size')),
					'tags' => 'name="wysiwyg_editor_upload_max_size_field"',
				),
			),
92

93 94 95 96 97 98 99 100
			'buttons' => array(
				array(
					'label' => 'Save Changes',
					'tags' => 'name="wysiwyg_editor_save_button"',
				),
			),
		);
	}
Gideon Greenspan committed
101

102 103 104 105 106 107 108 109 110
	public function calc_quality($content, $format)
	{
		if ($format == 'html')
			return 1.0;
		elseif ($format == '')
			return 0.8;
		else
			return 0;
	}
111

112 113 114 115
	public function get_field(&$qa_content, $content, $format, $fieldname, $rows)
	{
		$scriptsrc = $this->urltoroot.'ckeditor/ckeditor.js?'.QA_VERSION;
		$alreadyadded = false;
116

117 118 119 120
		if (isset($qa_content['script_src'])) {
			foreach ($qa_content['script_src'] as $testscriptsrc) {
				if ($testscriptsrc == $scriptsrc)
					$alreadyadded = true;
Gideon Greenspan committed
121
			}
122
		}
123

124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
		if (!$alreadyadded) {
			$uploadimages = qa_opt('wysiwyg_editor_upload_images');
			$uploadall = $uploadimages && qa_opt('wysiwyg_editor_upload_all');
			$imageUploadUrl = qa_js( qa_path('wysiwyg-editor-upload', array('qa_only_image' => true)) );
			$fileUploadUrl = qa_js( qa_path('wysiwyg-editor-upload') );

			$qa_content['script_src'][] = $scriptsrc;
			$qa_content['script_lines'][] = array(
				"var qa_wysiwyg_editor_config = {",
				// The toolbar arrangement, two rows of buttons
				"	toolbar: [",
				"		{ name: 'basic', items: [ 'Bold', 'Italic', 'Underline', 'Strike', 'Subscript', 'Superscript' ] },",
				"		{ name: 'color', items: [ 'TextColor', 'BGColor' ] },",
				"		{ name: 'align', items: [ 'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock' ] },",
				"		{ name: 'clipboard', items: [ 'Cut', 'Copy', 'Paste', 'PasteFromWord', '-', 'Undo', 'Redo' ] },",
				"		'/',",
				"		{ name: 'font', items: [ 'Font', 'FontSize', 'Format' ] },",
				"		{ name: 'paragraph', items: [ 'NumberedList', 'BulletedList', '-', 'Outdent', 'Indent', 'Blockquote' ] },",
				"		{ name: 'links', items: [ 'Link', 'Unlink' ] },",
				"		{ name: 'insert', items: [ 'Image', 'Table', 'HorizontalRule', 'SpecialChar' ] },",
				"		{ name: 'last', items: [ 'RemoveFormat', 'Maximize' ] }",
				"	],",

				// Set the most common block elements.
				"	format_tags: 'p;h1;h2;h3;pre',",
				"	entities: false,",
				// Make dialogs simpler.
				"	removeDialogTabs: 'image:advanced;link:advanced;table:advanced',",
				// Use native spell checking (note: Ctrl+right-click is required for native context menu).
				"	disableNativeSpellChecker: false,",
				// Set language (note: appropriate language file must be extracted from ckeditor/lang/languages.zip).
				"	defaultLanguage: " . qa_js(qa_opt('site_language')) . ",",

				// File uploads
				($uploadimages ? "	filebrowserImageUploadUrl: $imageUploadUrl," : ""),
				($uploadall ? "	filebrowserUploadUrl: $fileUploadUrl," : ""),

				// Prevent config file being loaded
				"	customConfig: ''",
				"};",
Gideon Greenspan committed
164 165
			);
		}
166

167 168 169
		if ($format == 'html') {
			$html = $content;
			$text = $this->html_to_text($content);
Gideon Greenspan committed
170
		}
171 172 173
		else {
			$text = $content;
			$html = qa_html($content, true);
Gideon Greenspan committed
174 175
		}

176 177 178 179 180 181 182
		return array(
			'tags' => 'name="'.$fieldname.'"',
			'value' => qa_html($text),
			'rows' => $rows,
			'html_prefix' => '<input name="'.$fieldname.'_ckeditor_ok" id="'.$fieldname.'_ckeditor_ok" type="hidden" value="0"><input name="'.$fieldname.'_ckeditor_data" id="'.$fieldname.'_ckeditor_data" type="hidden" value="'.qa_html($html).'">',
		);
	}
183

184 185 186 187 188 189 190 191
	public function load_script($fieldname)
	{
		return
			"if (qa_ckeditor_".$fieldname." = CKEDITOR.replace(".qa_js($fieldname).", qa_wysiwyg_editor_config)) { " .
				"qa_ckeditor_".$fieldname.".setData(document.getElementById(".qa_js($fieldname.'_ckeditor_data').").value); " .
				"document.getElementById(".qa_js($fieldname.'_ckeditor_ok').").value = 1; " .
			"}";
	}
192

193 194 195 196
	public function focus_script($fieldname)
	{
		return "if (qa_ckeditor_".$fieldname.") qa_ckeditor_".$fieldname.".focus();";
	}
197

198 199 200 201
	public function update_script($fieldname)
	{
		return "if (qa_ckeditor_".$fieldname.") qa_ckeditor_".$fieldname.".updateElement();";
	}
202

203 204 205 206 207
	public function read_post($fieldname)
	{
		if (qa_post_text($fieldname.'_ckeditor_ok')) {
			// CKEditor was loaded successfully
			$html = qa_post_text($fieldname);
208

209 210
			// remove <p>, <br>, etc... since those are OK in text
			$htmlformatting = preg_replace('/<\s*\/?\s*(br|p)\s*\/?\s*>/i', '', $html);
Gideon Greenspan committed
211

212 213 214 215 216 217 218 219 220 221 222
			if (preg_match('/<.+>/', $htmlformatting)) {
				// if still some other tags, it's worth keeping in HTML
				// qa_sanitize_html() is ESSENTIAL for security
				return array(
					'format' => 'html',
					'content' => qa_sanitize_html($html, false, true),
				);
			}
			else {
				// convert to text
				$viewer = qa_load_module('viewer', '');
Gideon Greenspan committed
223 224 225

				return array(
					'format' => '',
226
					'content' => $this->html_to_text($html),
Gideon Greenspan committed
227
				);
228
			}
Gideon Greenspan committed
229
		}
230 231 232 233 234 235 236 237
		else {
			// CKEditor was not loaded so treat it as plain text
			return array(
				'format' => '',
				'content' => qa_post_text($fieldname),
			);
		}
	}
238

Gideon Greenspan committed
239

240 241 242 243 244
	private function html_to_text($html)
	{
		$viewer = qa_load_module('viewer', '');
		return $viewer->get_text($html, 'html', array());
	}
245

246 247 248
	private function bytes_to_mega_html($bytes)
	{
		return qa_html(number_format($bytes/1048576, 1));
Gideon Greenspan committed
249
	}
250
}
251

Gideon Greenspan committed
252 253 254 255

/*
	Omit PHP closing tag to help avoid accidental output
*/