From 8e16ebb8d2316aee04764dd1e13dedb623ce8095 Mon Sep 17 00:00:00 2001 From: Sam Mousa Date: Tue, 9 Jul 2013 13:24:23 +0200 Subject: [PATCH] Cherrypick from 2.1 SettingsWidget --- .../SettingsWidget/SettingsWidget.php | 325 ++++++++++++++++++ .../SettingsWidget/assets/settingswidget.css | 19 + .../SettingsWidget/assets/settingswidget.js | 42 +++ application/helpers/PluginSettingsHelper.php | 24 +- application/views/plugins/configure.php | 26 +- plugins/Example/Example.php | 54 ++- themes/default/css/style.css | 3 + themes/default/images/poweredby.png | Bin 0 -> 3872 bytes 8 files changed, 464 insertions(+), 29 deletions(-) create mode 100644 application/extensions/SettingsWidget/SettingsWidget.php create mode 100644 application/extensions/SettingsWidget/assets/settingswidget.css create mode 100644 application/extensions/SettingsWidget/assets/settingswidget.js create mode 100644 themes/default/css/style.css create mode 100644 themes/default/images/poweredby.png diff --git a/application/extensions/SettingsWidget/SettingsWidget.php b/application/extensions/SettingsWidget/SettingsWidget.php new file mode 100644 index 00000000000..8e372b7225e --- /dev/null +++ b/application/extensions/SettingsWidget/SettingsWidget.php @@ -0,0 +1,325 @@ +action, $this->method, $this->formHtmlOptions); + } + + public function endForm() + { + echo CHtml::endForm(); + } + public function init() { + parent::init(); + + // Register assets. + Yii::app()->getClientScript()->registerPackage('jquery'); + Yii::app()->getClientScript()->registerCssFile(App()->getAssetManager()->publish(dirname(__FILE__) . '/assets/settingswidget.css')); + Yii::app()->getClientScript()->registerScriptFile(App()->getAssetManager()->publish(dirname(__FILE__) . '/assets/settingswidget.js')); + + // Add default form class. + $this->formHtmlOptions['class'] = isset($this->formHtmlOptions['class']) ? $this->formHtmlOptions['class'] . " settingswidget" : 'settingswidget'; + + + // Start form + $this->beginForm(); + + } + + protected function renderButton($label, $htmlOptions) + { + if (is_string($htmlOptions)) + { + $label = $htmlOptions; + $htmlOptions = array(); + } + echo CHtml::submitButton($label, $htmlOptions); + } + + protected function renderButtons() + { + foreach ($this->buttons as $label => $htmlOptions) + { + $this->renderButton($label, $htmlOptions); + } + } + + protected function renderSetting($name, $metaData, $form = null, $return = false) + { + $defaults = array( + 'class' => array(), + 'type' => 'string', + 'labelOptions' => array( + 'class' => 'control-label' + ) + ); + $metaData = array_merge($defaults, $metaData); + + if (is_string($metaData['class'])) + { + $metaData['class'] = array($metaData['class']); + } + if (isset($metaData['type'])) + { + $function = "render{$metaData['type']}"; + + // Handle localization. + if (isset($metaData['localized']) && $metaData['localized'] == true) + { + $name = "{$name}[{$metaData['language']}]"; + if (isset($metaData['current']) && is_array($metaData['current']) && isset($metaData['current'][$metaData['language']])) + { + $metaData['current'] = $metaData['current'][$metaData['language']]; + } + else + { + unset($metaData['current']); + } + } + + + $result = $this->$function($name, $metaData, $form); + + if ($return) + { + return $result; + } + else + { + echo $result; + } + } + } + + protected function renderSettings() + { + //echo '
'; var_dump($this->settings); echo ('
'); return; + foreach($this->settings as $name => $metaData) + { + $this->renderSetting($name, $metaData); + } + } + + + + public function run() { + parent::run(); + + // Render settings + $this->renderSettings(); + // Render buttons + $this->renderButtons(); + // End form + $this->endForm(); + } + + + + + /*********************************************************************** + * Settings renderers. + **********************************************************************/ + + + + public function renderBoolean($name, array $metaData, $form = null) + { + $out = ''; + $id = $name; + $value = isset($metaData['current']) ? $metaData['current'] : ''; + if (isset($metaData['label'])) + { + $out .= CHtml::label($metaData['label'], $id); + } + $out .= CHtml::radioButtonList($id, $value, array( + 0 => 'False', + 1 => 'True' + ), array('id' => $id, 'form' => $form, 'container'=>'div', 'separator' => '')); + + + return $out; + } + + public function renderFloat($name, array $metaData, $form = null) + { + $out = ''; + $id = $name; + $value = isset($metaData['current']) ? $metaData['current'] : ''; + if (isset($metaData['label'])) + { + $out .= CHtml::label($metaData['label'], $id, $metaData['labelOptions']); + } + $out .= CHtml::textField($id, $value, array( + 'id' => $id, + 'form' => $form, + 'pattern' => '\d+(\.\d+)?' + )); + + return $out; + } + + public function renderHtml($name, array $metaData, $form = null) + { + // Register CKEditor library for inclusion. + App()->getClientScript()->registerCoreScript('ckeditor'); + $out = ''; + $id = $name; + $value = isset($metaData['current']) ? $metaData['current'] : ''; + $metaData['class'][] = 'htmleditor'; + $readOnly = isset($metaData['readOnly']) ? $metaData['readOnly'] : false; + if (isset($metaData['label'])) + { + $out .= CHtml::label($metaData['label'], $id, $metaData['labelOptions']); + } + $out .= Chtml::tag('div', array('class' => implode(' ', $metaData['class'])), CHtml::textArea($id, $value, array('id' => $id, 'form' => $form, 'readonly' => $readOnly))); + return $out; + } + + public function renderInt($name, array $metaData, $form = null) + { + $out = ''; + $id = $name; + $value = isset($metaData['current']) ? $metaData['current'] : ''; + if (isset($metaData['label'])) + { + $out .= CHtml::label($metaData['label'], $id, $metaData['labelOptions']); + } + $out .= CHtml::textField($id, $value, array( + 'id' => $id, + 'form' => $form, + 'data-type' => 'int', + 'pattern' => '\d+' + )); + + return $out; + } + + public function renderLogo($name, array $metaData) + { + return CHtml::image($metaData['path']); + } + public function renderRelevance($name, array $metaData, $form = null) + { + $out = ''; + $metaData['class'][] = 'relevance'; + $id = $name; + + + if (isset($metaData['label'])) + { + $out .= CHtml::label($metaData['label'], $id, $metaData['labelOptions']); + } + $value = isset($metaData['current']) ? $metaData['current'] : ''; + + $out .= CHtml::textArea($name, $value, array('id' => $id, 'form' => $form, 'class' => implode(' ', $metaData['class']))); + + return $out; + } + + public function renderSelect($name, array $metaData, $form = null) + { + $out = ''; + $id = $name; + $value = isset($metaData['current']) ? $metaData['current'] : (isset($metaData['default']) ? $metaData['default'] : null); + if (isset($metaData['label'])) + { + $out .= CHtml::label($metaData['label'], $id, $metaData['labelOptions']); + } + $out .= CHtml::dropDownList($name, $value, $metaData['options'], array('form' => $form)); + + return $out; + } + + public function renderString($name, array $metaData, $form = null) + { + $out = ''; + $id = $name; + $value = isset($metaData['current']) ? $metaData['current'] : ''; + $readOnly = isset($metaData['readOnly']) ? $metaData['readOnly'] : false; + if (isset($metaData['label'])) + { + $out .= CHtml::label($metaData['label'], $id, $metaData['labelOptions']); + } + $out .= CHtml::textField($id, $value, array('id' => $id, 'form' => $form, 'class' => implode(' ', $metaData['class']), 'readonly' => $readOnly)); + + return $out; + } + + public function renderPassword($name, array $metaData, $form = null) + { + $out = ''; + $id = $name; + $value = isset($metaData['current']) ? $metaData['current'] : ''; + if (isset($metaData['label'])) + { + $out .= CHtml::label($metaData['label'], $id, $metaData['labelOptions']); + } + $out .= CHtml::passwordField($id, $value, array('id' => $id, 'form' => $form)); + + return $out; + } + + public function renderList($name, array $metaData, $form = null) + { + + if (isset($metaData['label'])) + { + $label = CHtml::label($metaData['label'], $id, $metaData['labelOptions']); + } + else + { + $label = ''; + } + + $headers = ''; + $cells = ''; + foreach ($metaData['items'] as $itemName => $itemMetaData) + { + $headers .= CHtml::tag('th', array(), $itemMetaData['label']); + unset($itemMetaData['label']); + $cells .= CHtml::tag('td', array(), $this->renderSetting($itemName . '[]', $itemMetaData, $form, true)); + } + $headers .= CHtml::tag('th'); + $cells .= CHtml::tag('td', array(), $this->widget('bootstrap.widgets.TbButtonGroup', array( + 'type' => 'link', + 'buttons' => array( + array('icon' => 'icon-minus', 'htmlOptions' => array('class' => 'remove')), + array('icon' => 'icon-plus', 'htmlOptions' => array('class' => 'add')), + ) + + ), true)); + echo CHtml::openTag('div', array('class' => 'settingslist')); + echo CHtml::openTag('table'); + // Create header row. + echo CHtml::openTag('thead'); + echo $headers; + echo CHtml::closeTag('thead'); + + // Create cells. + echo CHtml::openTag('tbody'); + echo CHtml::openTag('tr'); + echo $cells; + echo CHtml::closeTag('tr'); + echo CHtml::closeTag('tbody'); + echo CHtml::closeTag('table'); + echo CHtml::closeTag('div'); + } + } + +?> \ No newline at end of file diff --git a/application/extensions/SettingsWidget/assets/settingswidget.css b/application/extensions/SettingsWidget/assets/settingswidget.css new file mode 100644 index 00000000000..cc82f3121ff --- /dev/null +++ b/application/extensions/SettingsWidget/assets/settingswidget.css @@ -0,0 +1,19 @@ +div.row { + border: 2px solid red; +} + +/* + Special layout for list settings (inline). +*/ + +form.settingswidget .settingslist input[data-type=int]{ + width: 50px; +} + +form.settingswidget .settingslist table{ + width: 100%; +} +form.settingswidget .settingslist label{ + width: auto; + margin-right: 5px; +} \ No newline at end of file diff --git a/application/extensions/SettingsWidget/assets/settingswidget.js b/application/extensions/SettingsWidget/assets/settingswidget.js new file mode 100644 index 00000000000..0649b63dee1 --- /dev/null +++ b/application/extensions/SettingsWidget/assets/settingswidget.js @@ -0,0 +1,42 @@ +$(document).ready(function() { + var removeRow = function () + { + // Don't remove last row. + if ($(this).closest('tbody').children().length > 1) + { + $(this).closest('tr').fadeOut(400, function() { $(this).remove(); }); + } + + }; + + var addRow = function() + { + var baseRow = $(this).closest('tr'); + // Create new row, hidden and with empty inputs. + var newRow = baseRow.clone(true); + newRow.find('input').each(function() { $(this).val(''); }); + + // Check if the first element contains a number value and, if so, increase it by one. + var parts = baseRow.find('input:first').val().match(/([\d]+|[^\d]+)/g); + for (var i = parts.length - 1; i > 0; --i) + { + var num = parseInt(parts[i]); + var length = parts[i].length; + if (num === num) + { + parts[i] = (num + 1).toString(); + while (parts[i].length < length) + { + parts[i] = '0' + parts[i]; + } + } + } + newRow.find('input:first').val(parts.join('')); + baseRow.after(newRow); + newRow.fadeIn(); + + } + $('form.settingswidget .settingslist a.remove').bind('click', removeRow); + $('form.settingswidget .settingslist a.add').bind('click', addRow); + +}) diff --git a/application/helpers/PluginSettingsHelper.php b/application/helpers/PluginSettingsHelper.php index 3a5d5001532..e39191ef03e 100644 --- a/application/helpers/PluginSettingsHelper.php +++ b/application/helpers/PluginSettingsHelper.php @@ -215,7 +215,29 @@ public function renderPassword($name, array $metaData, $form = null) return $out; } - + + public function renderList($name, array $metaData, $form = null) + { + + if (isset($metaData['label'])) + { + $label = CHtml::label($metaData['label'], $id, $metaData['labelOptions']); + } + else + { + $label = ''; + } + + $out = ''; + foreach ($metaData['items'] as $itemName => $itemMetaData) + { + $out .= $this->renderSetting($itemName . '[0]', $itemMetaData, $form, true); + } + return $label . CHtml::tag('div', array('class' => 'list'), CHtml::tag('div', array( + 'class' => 'row', + 'data-index' => 0 + ), $out)); + } } diff --git a/application/views/plugins/configure.php b/application/views/plugins/configure.php index 3960da55680..b16409f4295 100644 --- a/application/views/plugins/configure.php +++ b/application/views/plugins/configure.php @@ -10,22 +10,18 @@ { echo CHtml::tag('h1', array(), sprintf(gT("Settings for plugin %s"), $plugin['name'])); } + $this->widget('ext.SettingsWidget.SettingsWidget', array( - Yii::import("application.helpers.PluginSettingsHelper"); - $PluginSettings = new PluginSettingsHelper(); - - echo CHtml::beginForm('', 'post', array('id' => "pluginsettings-{$plugin['name']}")); - echo CHtml::openTag('ol'); - foreach ($settings as $name => $setting) - { - echo CHtml::tag('li', array(), $PluginSettings->renderSetting($name, $setting, "pluginsettings-{$plugin['name']}", true)); - - } - echo CHtml::closeTag('ol'); - echo CHtml::submitButton(gT('Save plugin settings'), array('name'=>'ok')); - echo CHtml::submitButton(gT('Cancel'), array('name'=>'cancel')); - echo CHtml::endForm(); - + 'settings' => $settings, + 'formHtmlOptions' => array( + 'id' => "pluginsettings-{$plugin['name']}", + ), + 'method' => 'post', + 'buttons' => array( + gT('Save plugin settings'), + gT('Cancel') + ) + )); ?> diff --git a/plugins/Example/Example.php b/plugins/Example/Example.php index 57c12b33a48..15347ac525e 100644 --- a/plugins/Example/Example.php +++ b/plugins/Example/Example.php @@ -3,16 +3,26 @@ class Example extends PluginBase { protected $storage = 'DbStorage'; static protected $description = 'Example plugin'; - static protected $name = 'Example'; protected $settings = array( - 'logo' => array( - 'type' => 'logo', - 'path' => 'assets/logo.png' - ), - 'message' => array( + 'test' => array( 'type' => 'string', 'label' => 'Message' + ), + 'messages' => array( + 'type' => 'list', + 'label' => 'messages', + 'items' => array( + 'number' => array( + 'type' => 'int', + 'label' => 'Index' + ), + 'message' => array( + 'type' => 'string', + 'label' => 'Message' + ), + + ) ) ); @@ -24,6 +34,7 @@ public function __construct(PluginManager $manager, $id) { * Here you should handle subscribing to the events your plugin will handle */ $this->subscribe('afterPluginLoad', 'helloWorld'); + $this->subscribe('afterAdminMenuLoaded'); $this->subscribe('beforeSurveySettings'); $this->subscribe('newSurveySettings'); } @@ -32,34 +43,51 @@ public function __construct(PluginManager $manager, $id) { /* * Below are the actual methods that handle events */ - public function helloWorld() + + public function afterAdminMenuLoaded(PluginEvent $event) { - $this->pluginManager->getAPI()->setFlash($this->get('message', null, null, 'Example popup. Change this via plugin settings.')); + $menu = $event->get('menu', array()); + $menu['left'][]=array( + 'href' => "http://docs.limesurvey.org", + 'alt' => gT('LimeSurvey online manual'), + 'image' => 'showhelp.png' + ); + + $event->set('menu', $menu); } + + public function helloWorld(PluginEvent $event) + { + $count = (int) $this->get('count'); + if ($count === false) $count = 0; + $count++; + $this->pluginManager->getAPI()->setFlash($this->get('message') . $count); + $this->set('count', $count); + } + /** * This event is fired by the administration panel to gather extra settings * available for a survey. * The plugin should return setting meta data. + * @param PluginEvent $event */ - public function beforeSurveySettings() + public function beforeSurveySettings(PluginEvent $event) { - $event = $this->getEvent(); $event->set("surveysettings.{$this->id}", array( 'name' => get_class($this), 'settings' => array( 'message' => array( 'type' => 'string', - 'label' => 'Example survey specific setting (not used):', + 'label' => 'Message to show to users:', 'current' => $this->get('message', 'Survey', $event->get('survey')) ) ) )); } - public function newSurveySettings() + public function newSurveySettings(PluginEvent $event) { - $event = $this->getEvent(); foreach ($event->get('settings') as $name => $value) { diff --git a/themes/default/css/style.css b/themes/default/css/style.css new file mode 100644 index 00000000000..d533df463ea --- /dev/null +++ b/themes/default/css/style.css @@ -0,0 +1,3 @@ +div#poweredby{ + text-align: center; +} diff --git a/themes/default/images/poweredby.png b/themes/default/images/poweredby.png new file mode 100644 index 0000000000000000000000000000000000000000..9ac36ae8803a44d08adf7f129edb9997c80ff9d8 GIT binary patch literal 3872 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