Commit | Line | Data |
---|---|---|
7266e09b CW |
1 | <?php |
2 | /* | |
3 | +--------------------------------------------------------------------+ | |
4 | | CiviCRM version 4.6 | | |
5 | +--------------------------------------------------------------------+ | |
6 | | Copyright CiviCRM LLC (c) 2004-2015 | | |
7 | +--------------------------------------------------------------------+ | |
8 | | This file is a part of CiviCRM. | | |
9 | | | | |
10 | | CiviCRM is free software; you can copy, modify, and distribute it | | |
11 | | under the terms of the GNU Affero General Public License | | |
12 | | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. | | |
13 | | | | |
14 | | CiviCRM is distributed in the hope that it will be useful, but | | |
15 | | WITHOUT ANY WARRANTY; without even the implied warranty of | | |
16 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | | |
17 | | See the GNU Affero General Public License for more details. | | |
18 | | | | |
19 | | You should have received a copy of the GNU Affero General Public | | |
20 | | License and the CiviCRM Licensing Exception along | | |
21 | | with this program; if not, contact CiviCRM LLC | | |
22 | | at info[AT]civicrm[DOT]org. If you have questions about the | | |
23 | | GNU Affero General Public License or the licensing of CiviCRM, | | |
24 | | see the CiviCRM license FAQ at http://civicrm.org/licensing | | |
25 | +--------------------------------------------------------------------+ | |
26 | */ | |
27 | ||
28 | /** | |
29 | * | |
30 | * @package CRM | |
31 | * @copyright CiviCRM LLC (c) 2004-2015 | |
32 | * $Id$ | |
33 | * | |
34 | */ | |
35 | ||
36 | /** | |
37 | * Page for configuring CKEditor options | |
38 | * | |
39 | * Note that while this is implemented as a CRM_Core_Page, it is actually a form. | |
40 | * Because the form needs to be submitted and refreshed via javascrit, it seemed like | |
41 | * Quickform and CRM_Core_Form/Controller might get in the way. | |
42 | */ | |
43 | class CRM_Admin_Page_CKEditorConfig extends CRM_Core_Page { | |
44 | ||
45 | const CONFIG_FILENAME = 'crm-ckeditor-config.js'; | |
46 | ||
47 | /** | |
48 | * Default settings if config file has not been initialized | |
49 | * | |
50 | * @var array | |
51 | */ | |
52 | public $defaultSettings = array( | |
53 | 'skin' => 'moono', | |
54 | 'extraPlugins' => '', | |
55 | ); | |
56 | ||
57 | /** | |
58 | * @return string | |
59 | */ | |
60 | public function run() { | |
61 | // If the form was submitted, take appropriate action. | |
62 | if (!empty($_POST['revert'])) { | |
63 | self::deleteConfigFile(); | |
64 | } | |
65 | elseif (!empty($_POST['config'])) { | |
66 | $this->save($_POST); | |
67 | } | |
68 | ||
69 | CRM_Core_Resources::singleton() | |
70 | ->addScriptFile('civicrm', 'bower_components/ckeditor/samples/toolbarconfigurator/js/fulltoolbareditor.js', 1) | |
71 | ->addScriptFile('civicrm', 'bower_components/ckeditor/samples/toolbarconfigurator/js/abstracttoolbarmodifier.js', 2) | |
72 | ->addScriptFile('civicrm', 'bower_components/ckeditor/samples/toolbarconfigurator/js/toolbarmodifier.js', 3) | |
73 | ->addScriptFile('civicrm', 'js/wysiwyg/admin.ckeditor-configurator.js', 10) | |
74 | ->addStyleFile('civicrm', 'bower_components/ckeditor/samples/toolbarconfigurator/css/fontello.css') | |
75 | ->addStyleFile('civicrm', 'bower_components/ckeditor/samples/css/samples.css') | |
76 | ->addVars('ckConfig', array( | |
77 | 'plugins' => array_values($this->getCKPlugins()), | |
78 | )); | |
79 | ||
80 | $this->assign('skins', $this->getCKSkins()); | |
81 | $this->assign('skin', $this->getConfigSetting('skin')); | |
82 | $this->assign('extraPlugins', $this->getConfigSetting('extraPlugins')); | |
83 | $this->assign('configUrl', self::getConfigUrl()); | |
84 | $this->assign('revertConfirm', htmlspecialchars(ts('Are you sure you want to revert all changes?', array('escape' => 'js')))); | |
85 | ||
86 | CRM_Utils_System::appendBreadCrumb(array(array( | |
87 | 'url' => CRM_Utils_System::url('civicrm/admin/setting/preferences/display', 'reset=1'), | |
88 | 'title' => ts('Display Preferences'), | |
89 | ))); | |
90 | ||
91 | return parent::run(); | |
92 | } | |
93 | ||
94 | /** | |
95 | * Generate the config js file based on posted data. | |
96 | * | |
97 | * @param array $params | |
98 | */ | |
99 | public function save($params) { | |
100 | $config = "/**\n" | |
101 | . " * CKEditor config file auto-generated by CiviCRM.\n" | |
102 | . " *\n" | |
103 | . " * Note: This file will be overwritten if settings are modified at:\n" | |
104 | . " * @link " . CRM_Utils_System::url(CRM_Utils_System::currentPath(), NULL, TRUE, NULL, FALSE) . "\n" | |
105 | . " */\n\n" | |
106 | // Standardize line-endings | |
107 | . preg_replace('~\R~u', "\n", $params['config']); | |
108 | ||
109 | // Use defaultSettings as a whitelist so we don't just insert any old junk into the file | |
110 | foreach ($this->defaultSettings as $key => $default) { | |
111 | if (isset($params[$key]) && strlen($params[$key])) { | |
112 | $pos = strrpos($config, '};'); | |
113 | $setting = "\n\tconfig.$key = '{$params[$key]}';\n"; | |
114 | $config = substr_replace($config, $setting, $pos, 0); | |
115 | } | |
116 | } | |
117 | self::saveConfigFile($config); | |
118 | if (!empty($params['save'])) { | |
119 | CRM_Core_Session::setStatus(ts("You may need to clear your browser's cache to see the changes in CiviCRM."), ts('CKEditor Saved'), 'success'); | |
120 | } | |
121 | } | |
122 | ||
123 | /** | |
124 | * @return array | |
125 | */ | |
126 | private function getCKPlugins() { | |
127 | $plugins = array(); | |
128 | global $civicrm_root; | |
129 | $pluginDir = CRM_Utils_file::addTrailingSlash($civicrm_root, '/') . 'bower_components/ckeditor/plugins'; | |
130 | ||
131 | foreach (glob($pluginDir . '/*', GLOB_ONLYDIR) as $dir) { | |
132 | $dir = rtrim(str_replace('\\', '/', $dir), '/'); | |
133 | $name = substr($dir, strrpos($dir, '/') + 1); | |
134 | $dir = CRM_Utils_file::addTrailingSlash($dir, '/'); | |
135 | if (is_file($dir . 'plugin.js')) { | |
136 | $plugins[$name] = array( | |
137 | 'id' => $name, | |
138 | 'text' => ucfirst($name), | |
139 | 'icon' => NULL, | |
140 | ); | |
141 | if (is_dir($dir . "icons")) { | |
142 | if (is_file($dir . "icons/$name.png")) { | |
143 | $plugins[$name]['icon'] = "bower_components/ckeditor/plugins/$name/icons/$name.png"; | |
144 | } | |
145 | elseif (glob($dir . "icons/*.png")) { | |
146 | $icon = CRM_Utils_Array::first(glob($dir . "icons/*.png")); | |
147 | $icon = rtrim(str_replace('\\', '/', $icon), '/'); | |
148 | $plugins[$name]['icon'] = "bower_components/ckeditor/plugins/$name/icons/" . substr($icon, strrpos($icon, '/') + 1); | |
149 | } | |
150 | } | |
151 | } | |
152 | } | |
153 | ||
154 | return $plugins; | |
155 | } | |
156 | ||
157 | /** | |
158 | * @return array | |
159 | */ | |
160 | private function getCKSkins() { | |
161 | $skins = array(); | |
162 | global $civicrm_root; | |
163 | $skinDir = CRM_Utils_file::addTrailingSlash($civicrm_root, '/') . 'bower_components/ckeditor/skins'; | |
164 | foreach (glob($skinDir . '/*', GLOB_ONLYDIR) as $dir) { | |
165 | $dir = rtrim(str_replace('\\', '/', $dir), '/'); | |
166 | $skins[] = substr($dir, strrpos($dir, '/') + 1); | |
167 | } | |
168 | return $skins; | |
169 | } | |
170 | ||
171 | /** | |
172 | * @param $setting | |
173 | * @return string | |
174 | */ | |
175 | private function getConfigSetting($setting) { | |
176 | $value = CRM_Utils_Array::value($setting, $this->defaultSettings, ''); | |
177 | $file = self::getConfigFile(); | |
178 | if ($file) { | |
179 | $contents = file_get_contents($file); | |
180 | $matches = array(); | |
181 | preg_match("/\sconfig\.$setting\s?=\s?'([^']*)'/", $contents, $matches); | |
182 | if ($matches) { | |
183 | $value = $matches[1]; | |
184 | } | |
185 | } | |
186 | return $value; | |
187 | } | |
188 | ||
189 | /** | |
190 | * @return null|string | |
191 | */ | |
192 | public static function getConfigUrl() { | |
193 | if (self::getConfigFile()) { | |
194 | // FIXME: Basing file path off imageUploadURL sucks, but it's all we got | |
195 | $url = CRM_Utils_file::addTrailingSlash(CRM_Core_Config::singleton()->imageUploadURL, '/'); | |
196 | $url = str_replace('/persist/contribute/', '/persist/', $url); | |
197 | return $url . SELF::CONFIG_FILENAME; | |
198 | } | |
199 | return NULL; | |
200 | } | |
201 | ||
202 | /** | |
203 | * @param bool $checkIfFileExists | |
204 | * If false, this fn will return fileName even if it doesn't exist | |
205 | * | |
206 | * @return null|string | |
207 | */ | |
208 | public static function getConfigFile($checkIfFileExists = TRUE) { | |
209 | // FIXME: Basing file path off imageUploadDir sucks, but it's all we got | |
210 | $dir = CRM_Core_Config::singleton()->imageUploadDir; | |
211 | $dir = CRM_Utils_file::addTrailingSlash(str_replace('\\', '/', $dir), '/'); | |
212 | $dir = str_replace('/persist/contribute/', '/persist/', $dir); | |
213 | $fileName = $dir . SELF::CONFIG_FILENAME; | |
214 | return !$checkIfFileExists || is_file($fileName) ? $fileName : NULL; | |
215 | } | |
216 | ||
217 | /** | |
218 | * @param string $contents | |
219 | */ | |
220 | public static function saveConfigFile($contents) { | |
221 | $file = self::getConfigFile(FALSE); | |
222 | file_put_contents($file, $contents); | |
223 | } | |
224 | ||
225 | /** | |
226 | * Delete SELF::CONFIG_FILENAME | |
227 | */ | |
228 | public static function deleteConfigFile() { | |
229 | $file = self::getConfigFile(); | |
230 | if ($file) { | |
231 | unlink($file); | |
232 | } | |
233 | } | |
234 | ||
235 | } |