3 * StatusNet, the distributed open-source microblogging tool
5 * Design administration panel
9 * LICENCE: This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU Affero General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Affero General Public License for more details.
19 * You should have received a copy of the GNU Affero General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 * @author Evan Prodromou <evan@status.net>
25 * @author Zach Copley <zach@status.net>
26 * @author Sarven Capadisli <csarven@status.net>
27 * @copyright 2008-2009 StatusNet, Inc.
28 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
29 * @link http://status.net/
32 if (!defined('STATUSNET')) {
37 * Administer design settings
41 * @author Evan Prodromou <evan@status.net>
42 * @author Zach Copley <zach@status.net>
43 * @author Sarven Capadisli <csarven@status.net>
44 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
45 * @link http://status.net/
47 class DesignadminpanelAction extends AdminPanelAction
49 /* The default site design */
53 * Returns the page title
55 * @return string page title
59 // TRANS: Message used as title for design settings for the site.
64 * Instructions for using this form.
66 * @return string instructions
68 function getInstructions()
70 // TRANS: Instructions for design adminsitration panel.
71 return _('Design settings for this StatusNet site');
75 * Get the default design and show the design admin panel form
81 $this->design = Design::siteDesign();
82 $form = new DesignAdminPanelForm($this);
88 * Save settings from the form
92 function saveSettings()
94 if ($this->arg('save')) {
95 $this->saveDesignSettings();
96 } else if ($this->arg('defaults')) {
97 $this->restoreDefaults();
99 // TRANS: Client error displayed when the submitted form contains unexpected data.
100 $this->clientError(_('Unexpected form submission.'));
105 * Save the new design settings
109 function saveDesignSettings()
111 // Workaround for PHP returning empty $_POST and $_FILES when POST
112 // length > post_max_size in php.ini
116 && ($_SERVER['CONTENT_LENGTH'] > 0)
118 // TRANS: Client error displayed when the number of bytes in a POST request exceeds a limit.
119 // TRANS: %s is the number of bytes of the CONTENT_LENGTH.
120 $msg = _m('The server was unable to handle that much POST data (%s byte) due to its current configuration.',
121 'The server was unable to handle that much POST data (%s bytes) due to its current configuration.',
122 intval($_SERVER['CONTENT_LENGTH']));
123 $this->clientException(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
127 // check for file uploads
129 $bgimage = $this->saveBackgroundImage();
130 $customTheme = $this->saveCustomTheme();
132 $oldtheme = common_config('site', 'theme');
134 // This feels pretty hacky :D
135 $this->args['theme'] = $customTheme;
136 $themeChanged = true;
138 $themeChanged = ($this->trimmed('theme') != $oldtheme);
141 static $settings = array('theme', 'logo', 'ssllogo');
145 foreach ($settings as $setting) {
146 $values[$setting] = $this->trimmed($setting);
149 $this->validate($values);
151 $config = new Config();
153 $config->query('BEGIN');
156 // If the theme has changed, reset custom colors and let them pick
157 // up the new theme's defaults.
158 $colors = array('background', 'content', 'sidebar', 'text', 'link');
159 foreach ($colors as $colorKey) {
160 // Clear from global config so we see defaults on this page...
161 $GLOBALS['config']['design'][$colorKey . 'color'] = false;
163 // And remove old settings from DB...
164 $this->deleteSetting('design', $colorKey . 'color');
167 // Only save colors from the form if the theme has not changed.
169 // @fixme a future more ajaxy form should allow theme switch
170 // and color customization in one step.
172 $bgcolor = new WebColor($this->trimmed('design_background'));
173 $ccolor = new WebColor($this->trimmed('design_content'));
174 $sbcolor = new WebColor($this->trimmed('design_sidebar'));
175 $tcolor = new WebColor($this->trimmed('design_text'));
176 $lcolor = new WebColor($this->trimmed('design_links'));
178 Config::save('design', 'backgroundcolor', $bgcolor->intValue());
179 Config::save('design', 'contentcolor', $ccolor->intValue());
180 Config::save('design', 'sidebarcolor', $sbcolor->intValue());
181 Config::save('design', 'textcolor', $tcolor->intValue());
182 Config::save('design', 'linkcolor', $lcolor->intValue());
185 $onoff = $this->arg('design_background-image_onoff');
190 if ($onoff == 'on') {
196 $tile = $this->boolean('design_background-image_repeat');
198 // Hack to use Design's bit setter
199 $scratch = new Design();
200 $scratch->setDisposition($on, $off, $tile);
202 Config::save('design', 'disposition', $scratch->disposition);
204 foreach ($settings as $setting) {
205 Config::save('site', $setting, $values[$setting]);
208 if (isset($bgimage)) {
209 Config::save('design', 'backgroundimage', $bgimage);
212 if (common_config('custom_css', 'enabled')) {
213 $css = $this->arg('css');
214 if ($css != common_config('custom_css', 'css')) {
215 Config::save('custom_css', 'css', $css);
219 $config->query('COMMIT');
223 * Restore the default design
227 function restoreDefaults()
229 $this->deleteSetting('site', 'logo');
230 $this->deleteSetting('site', 'ssllogo');
231 $this->deleteSetting('site', 'theme');
234 'theme', 'backgroundimage', 'backgroundcolor', 'contentcolor',
235 'sidebarcolor', 'textcolor', 'linkcolor', 'disposition'
238 foreach ($settings as $setting) {
239 $this->deleteSetting('design', $setting);
242 // XXX: Should we restore the default dir settings, etc.? --Z
244 // XXX: I can't get it to show the new settings without forcing
245 // this terrible reload -- FIX ME!
246 common_redirect(common_local_url('designadminpanel'), 303);
250 * Save the background image if the user uploaded one
252 * @return string $filename the filename of the image
254 function saveBackgroundImage()
257 if (isset($_FILES['design_background-image_file']['error']) &&
258 $_FILES['design_background-image_file']['error'] ==
265 ImageFile::fromUpload('design_background-image_file');
266 } catch (Exception $e) {
267 $this->clientError('Unable to save background image.');
271 // Note: site design background image has a special filename
273 $filename = Design::filename('site-design-background',
274 image_type_to_extension($imagefile->type),
277 $filepath = Design::path($filename);
279 move_uploaded_file($imagefile->filepath, $filepath);
281 // delete any old backround img laying around
283 if (isset($this->design->backgroundimage)) {
284 @unlink(Design::path($design->backgroundimage));
292 * Save the custom theme if the user uploaded one.
294 * @return mixed custom theme name, if succesful, or null if no theme upload.
295 * @throws ClientException for invalid theme archives
296 * @throws ServerException if trouble saving the theme files
298 function saveCustomTheme()
300 if (common_config('theme_upload', 'enabled') &&
301 $_FILES['design_upload_theme']['error'] == UPLOAD_ERR_OK) {
303 $upload = ThemeUploader::fromUpload('design_upload_theme');
304 $basedir = common_config('local', 'dir');
305 if (empty($basedir)) {
306 $basedir = INSTALLDIR . '/local';
308 $name = 'custom'; // @todo allow multiples, custom naming?
309 $outdir = $basedir . '/theme/' . $name;
310 $upload->extract($outdir);
318 * Attempt to validate setting values
322 function validate(&$values)
324 if (!empty($values['logo']) &&
325 !Validate::uri($values['logo'], array('allowed_schemes' => array('http', 'https')))) {
326 // TRANS: Client error displayed when a logo URL does is not valid.
327 $this->clientError(_('Invalid logo URL.'));
330 if (!empty($values['ssllogo']) &&
331 !Validate::uri($values['ssllogo'], array('allowed_schemes' => array('https')))) {
332 // TRANS: Client error displayed when an SSL logo URL is invalid.
333 $this->clientError(_('Invalid SSL logo URL.'));
336 if (!in_array($values['theme'], Theme::listAvailable())) {
337 // TRANS: Client error displayed when a theme is submitted through the form that is not in the theme list.
338 // TRANS: %s is the chosen unavailable theme.
339 $this->clientError(sprintf(_('Theme not available: %s.'), $values['theme']));
344 * Add the Farbtastic stylesheet
348 function showStylesheets()
350 parent::showStylesheets();
351 $this->cssLink('js/farbtastic/farbtastic.css',null,'screen, projection, tv');
355 * Add the Farbtastic scripts
359 function showScripts()
361 parent::showScripts();
363 $this->script('farbtastic/farbtastic.js');
364 $this->script('userdesign.go.js');
366 $this->autofocus('design_background-image_file');
371 class DesignAdminPanelForm extends AdminForm
377 * @return int ID of the form
381 return 'form_design_admin_panel';
387 * @return string class of the form
391 return 'form_settings';
395 * HTTP method used to submit the form
397 * For image data we need to send multipart/form-data
398 * so we set that here too
400 * @return string the method to use for submitting
404 $this->enctype = 'multipart/form-data';
412 * @return string URL of the action
416 return common_local_url('designadminpanel');
420 * Data elements of the form
428 $this->showBackground();
430 $this->showAdvanced();
435 $this->out->elementStart('fieldset', array('id' => 'settings_design_logo'));
436 // TRANS: Fieldset legend for form to change logo.
437 $this->out->element('legend', null, _('Change logo'));
439 $this->out->elementStart('ul', 'form_data');
443 // TRANS: Field label for StatusNet site logo.
445 // TRANS: Title for field label for StatusNet site logo.
446 'Logo for the site (full URL).');
450 $this->input('ssllogo',
451 // TRANS: Field label for SSL StatusNet site logo.
453 // TRANS: Title for field label for SSL StatusNet site logo.
454 'Logo to show on SSL pages.');
457 $this->out->elementEnd('ul');
459 $this->out->elementEnd('fieldset');
465 $this->out->elementStart('fieldset', array('id' => 'settings_design_theme'));
466 // TRANS: Fieldset legend for form change StatusNet site's theme.
467 $this->out->element('legend', null, _('Change theme'));
469 $this->out->elementStart('ul', 'form_data');
471 $themes = Theme::listAvailable();
473 // XXX: listAvailable() can return an empty list if you
474 // screw up your settings, so just in case:
476 if (empty($themes)) {
477 $themes = array('default', 'default');
481 $themes = array_combine($themes, $themes);
484 // TRANS: Field label for dropdown to choose site theme.
485 $this->out->dropdown('theme', _('Site theme'),
486 // TRANS: Title for field label for dropdown to choose site theme.
487 $themes, _('Theme for the site.'),
488 false, $this->value('theme'));
491 if (common_config('theme_upload', 'enabled')) {
493 // TRANS: Field label for uploading a cutom theme.
494 $this->out->element('label', array('for' => 'design_upload_theme'), _('Custom theme'));
495 $this->out->element('input', array('id' => 'design_upload_theme',
496 'name' => 'design_upload_theme',
498 // TRANS: Form instructions for uploading a cutom StatusNet theme.
499 $this->out->element('p', 'form_guide', _('You can upload a custom StatusNet theme as a .ZIP archive.'));
503 $this->out->elementEnd('ul');
505 $this->out->elementEnd('fieldset');
508 function showBackground()
510 $design = $this->out->design;
512 $this->out->elementStart('fieldset', array('id' =>
513 'settings_design_background-image'));
514 // TRANS: Fieldset legend for theme background image.
515 $this->out->element('legend', null, _('Change background image'));
516 $this->out->elementStart('ul', 'form_data');
519 $this->out->element('input', array('name' => 'MAX_FILE_SIZE',
521 'id' => 'MAX_FILE_SIZE',
522 'value' => ImageFile::maxFileSizeInt()));
523 $this->out->element('label', array('for' => 'design_background-image_file'),
524 // TRANS: Field label for background image on theme designer page.
526 $this->out->element('input', array('name' => 'design_background-image_file',
528 'id' => 'design_background-image_file'));
529 $this->out->element('p', 'form_guide',
530 // TRANS: Form guide for background image upload form on theme designer page.
531 sprintf(_('You can upload a background image for the site. ' .
532 'The maximum file size is %1$s.'), ImageFile::maxFileSize()));
535 if (!empty($design->backgroundimage)) {
537 $this->out->elementStart('li', array('id' =>
538 'design_background-image_onoff'));
540 $this->out->element('img', array('src' =>
541 Design::url($design->backgroundimage)));
543 $attrs = array('name' => 'design_background-image_onoff',
545 'id' => 'design_background-image_on',
549 if ($design->disposition & BACKGROUND_ON) {
550 $attrs['checked'] = 'checked';
553 $this->out->element('input', $attrs);
555 $this->out->element('label', array('for' => 'design_background-image_on',
557 // TRANS: Used as radio button label to add a background image.
560 $attrs = array('name' => 'design_background-image_onoff',
562 'id' => 'design_background-image_off',
566 if ($design->disposition & BACKGROUND_OFF) {
567 $attrs['checked'] = 'checked';
570 $this->out->element('input', $attrs);
572 $this->out->element('label', array('for' => 'design_background-image_off',
574 // TRANS: Used as radio button label to not add a background image.
576 // TRANS: Form guide for turning background image on or off on theme designer page.
577 $this->out->element('p', 'form_guide', _('Turn background image on or off.'));
581 $this->out->checkbox('design_background-image_repeat',
582 // TRANS: Checkbox label to title background image on theme designer page.
583 _('Tile background image'),
584 ($design->disposition & BACKGROUND_TILE) ? true : false);
588 $this->out->elementEnd('ul');
589 $this->out->elementEnd('fieldset');
592 function showColors()
594 $design = $this->out->design;
596 $this->out->elementStart('fieldset', array('id' => 'settings_design_color'));
597 // TRANS: Fieldset legend for theme colors.
598 $this->out->element('legend', null, _('Change colors'));
600 $this->out->elementStart('ul', 'form_data');
603 // @fixme avoid loop unrolling in non-performance-critical contexts like this
605 $bgcolor = new WebColor($design->backgroundcolor);
608 // TRANS: Field label for background color selector.
609 $this->out->element('label', array('for' => 'swatch-1'), _('Background'));
610 $this->out->element('input', array('name' => 'design_background',
619 $ccolor = new WebColor($design->contentcolor);
622 // TRANS: Field label for content color selector.
623 $this->out->element('label', array('for' => 'swatch-2'), _('Content'));
624 $this->out->element('input', array('name' => 'design_content',
633 $sbcolor = new WebColor($design->sidebarcolor);
636 // TRANS: Field label for sidebar color selector.
637 $this->out->element('label', array('for' => 'swatch-3'), _('Sidebar'));
638 $this->out->element('input', array('name' => 'design_sidebar',
647 $tcolor = new WebColor($design->textcolor);
650 // TRANS: Field label for text color selector.
651 $this->out->element('label', array('for' => 'swatch-4'), _('Text'));
652 $this->out->element('input', array('name' => 'design_text',
661 $lcolor = new WebColor($design->linkcolor);
664 // TRANS: Field label for link color selector.
665 $this->out->element('label', array('for' => 'swatch-5'), _('Links'));
666 $this->out->element('input', array('name' => 'design_links',
675 } catch (WebColorException $e) {
676 // @fixme normalize them individually!
677 common_log(LOG_ERR, 'Bad color values in site design: ' .
681 $this->out->elementEnd('fieldset');
683 $this->out->elementEnd('ul');
686 function showAdvanced()
688 if (common_config('custom_css', 'enabled')) {
689 $this->out->elementStart('fieldset', array('id' => 'settings_design_advanced'));
690 // TRANS: Fieldset legend for advanced theme design settings.
691 $this->out->element('legend', null, _('Advanced'));
692 $this->out->elementStart('ul', 'form_data');
695 // TRANS: Field label for custom CSS.
696 $this->out->element('label', array('for' => 'css'), _('Custom CSS'));
697 $this->out->element('textarea', array('name' => 'css',
701 strval(common_config('custom_css', 'css')));
704 $this->out->elementEnd('fieldset');
705 $this->out->elementEnd('ul');
715 function formActions()
717 // TRANS: Button text for resetting theme settings.
718 $this->out->submit('defaults', _m('BUTTON','Use defaults'), 'submit form_action-default',
719 // TRANS: Title for button for resetting theme settings.
720 'defaults', _('Restore default designs.'));
722 $this->out->element('input', array('id' => 'settings_design_reset',
724 // TRANS: Button text for resetting theme settings.
726 'class' => 'submit form_action-primary',
727 // TRANS: Title for button for resetting theme settings.
728 'title' => _('Reset back to default.')));
730 $this->out->submit('save',
731 // TRANS: Button text for saving theme settings.
733 'submit form_action-secondary',
735 // TRANS: Title for button for saving theme settings.