Settings Page
| Project: | Christmas Snow |
| Version: | 5.x-1.1 |
| Component: | User interface |
| Category: | feature request |
| Priority: | normal |
| Assigned: | Unassigned |
| Status: | reviewed & tested by the community |
Jump to:
I think it would be nifty (and quite easy) to implement a settings page for this module.
All you'd have to do is create a menu item (in the $may_cache section of your hook_menu implementation) with path admin/settings/christmas-snow, callback drupal_get_form and 'callback arguments' of a form creation function (which assembles variables for the JS vars like flakeTypes, flakesMax etc, then passes the form through system_settings_form before returning it). The variables could then be inserted into JS in the same way that the JS path already is.
Actually I'd go one step further and say you're adding the path variable slightly wrong ... instead of drupal_set_html_head and a SCRIPT tag, you should be using drupal_add_js again, with data='var imagePath =' and type=inline.
In fact you should really be declaring an if($may_cache) case already, since at the moment the code in hook_menu is sometimes getting called twice. (All hook_menus may be called once or twice in pageload, always once with $may_cache=false and sometimes once with $may_cache=true - when the cache is being (re)built).
In fact what the hell, I'll rewrite your module for you, it's Christmas:
<?php
/*
* Drupal Module: Christmas Snow
* Adds Christmas Snow to your site
*
* @author: introfini <www.josefernandes.pt>
*/
function christmas_snow_help($section) {
switch ($section) {
case 'admin/modules#description':
return t('Add Christmas Snow to your site.');
case 'admin/settings/christmas_snow':
return t('Add Christmas Snow to your site.');
}
}
function christmas_snow_menu($may_cache) {
$items = array();
if ($may_cache) {
$items[] = array(
'path' => 'admin/settings/christmas-snow',
'title' => t('Christmas Snow'),
'callback' => 'drupal_get_form',
'callback arguments' => 'christmas_snow_settings',
'access' => user_access('administer site configuration'),
);
}
else {
$path = drupal_get_path('module', 'christmas_snow');
$variables = 'var usePNG = true;
var imagePath = "'. $GLOBALS['base_url'] .'/'. $path .'/image/snow/"; // relative path to snow images
var flakeTypes = '. variable_get('cs_flakeTypes', 6) .';
var flakesMax = '. variable_get('cs_flakesMax', '128') .';
var flakesMaxActive = '. variable_get('cs_flakesMaxActive', '64') .';
var vMax = '. variable_get('cs_vMax', '2.5') .';
var flakeWidth = '. variable_get('cs_flakeWidth', '5') .';
var flakeHeight = '. variable_get('cs_flakeHeight', '5') .';
var flakeBottom = null; // Integer for fixed bottom, 0 or null for "full-screen" snow effect
var snowCollect = '. variable_get('cs_snowCollect', 'true') .';
var showStatus = true;';
drupal_add_js($variables, 'inline');
$js = drupal_add_js($path . '/script/snowstorm.js');
}
return $items;
}
function christmas_snow_settings() {
$form = array();
$form['cs_flakeTypes'] = array(
'#type' => 'textfield',
'#description' => t('Sets the range of flake images to use (eg. a value of 5 will use images wanging from 0.png to 4.png)'),
'#title' => t('Flake Types'),
'#required' => true,
'#default_value' => variable_get('cs_flakeTypes', '6'),
);
$form['cs_flakesMax'] = array(
'#type' => 'textfield',
'#description' => t('Sets the maximum number of snowflakes that can exist on the screen at any given time.'),
'#title' => t('Max Flakes'),
'#required' => true,
'#default_value' => variable_get('cs_flakesMax', '128'),
);
$form['cs_flakesMaxActive'] = array(
'#type' => 'textfield',
'#description' => t('Sets the limit of "falling" snowflakes (ie. moving, thus considered to be "active".)'),
'#title' => t('Max Active Flakes'),
'#required' => true,
'#default_value' => variable_get('cs_flakesMaxActive', '64'),
);
$form['cs_vMax'] = array(
'#type' => 'textfield',
'#description' => t('Defines the maximum X and Y velocities for the storm. A range up to this value is selected at random.'),
'#title' => t('Maximum Velocity'),
'#required' => true,
'#default_value' => variable_get('cs_vMax', '2.5'),
);
$form['cs_flakeWidth'] = array(
'#type' => 'textfield',
'#description' => t('The width (in pixels) of each snowflake image.'),
'#title' => t('Flake Width'),
'#required' => true,
'#default_value' => variable_get('cs_flakeWidth', '5'),
);
$form['cs_flakeHeight'] = array(
'#type' => 'textfield',
'#description' => t('Height (pixels) of each snowflake image.'),
'#title' => t('Flake Height'),
'#required' => true,
'#default_value' => variable_get('cs_flakeHeight', '5'),
);
$form['cs_snowCollect'] = array(
'#type' => 'select',
'#options' => array('true' => 'Yes', 'false' => 'No'),
'#description' => t('Enables snow to pile up (slowly) at bottom of window. Can be very CPU/resource-intensive over time.'),
'#title' => t('Collect Snow?'),
'#required' => true,
'#default_value' => variable_get('cs_snowCollect', 'true'),
);
return system_settings_form($form); // Adds submit / reset buttons and automatically saves all fields as variables.
}
?>Then tell people to comment out the whole "User-configurable variables" chunk of code (which is why I've left the 'usePNG' and 'showStatus' variables in there even though they're not configurable - it's easier to say "comment out the whole block").
Closing notes:
- I'd think about maybe adding some validation (in a christmas_snow_settings_validate function) to ensure that all those settings remain numbers - anything other than a number will produce a JS error since I left the quote marks out and didn't use drupal_to_js().
- An alternate method, which wouldn't involve seven variable_get calls on each page load, would be to use a christmas_snow_settings_submit function to write a .js file and only include it in the _menu function. Or even re-writing the snowstorm.js file using a regexp replace to find '// User-configurable variables [.]* --- End of user section ---'. I don't know how much more efficient that would be, though - you'd run the risk of JS cacheing and, moreover, increase the HTTP request load. So it's kind of swings and roundabouts.
Well, that is what I think, anyway.

#1
Oh, FWIW, with the 'write a .js file' method you'd need to create a christmas_snow.install file which created the .js file with the default values in, in case the site administrator never bothers to visit the settings page...
#2
Thanks for the very timely additions here. Works very well indeed and a nice early Christmas Pressie :-)
One issue I have found is that the snow appears in any popups on the site (eg image_assist) and very useful addition would be to limit to certain pages only. Any pointers welcome.
#3
You'd probably want to do it like Block visibility ... have a radio button with 'Show on all except' / 'Show only on', and a textarea to store a list of paths. Then surround the JS injection code with an IF statement that validates the current path ($_GET['q']) against the list in your textarea variable.
This chunk of code from block_list() looks useful for matching a path against a line-break separated list of paths (including * wildcard):
<?php$path = drupal_get_path_alias($_GET['q']);
$regexp = '/^('. preg_replace(array('/(\r\n?|\n)/', '/\\\\\*/', '/(^|\|)\\\\<front\\\\>($|\|)/'), array('|', '.*', '\1'. preg_quote(variable_get('site_frontpage', 'node'), '/') .'\2'), preg_quote($block->pages, '/')) .')$/';
// Compare with the internal and path alias (if any).
$page_match = preg_match($regexp, $path);
if ($path != $_GET['q']) {
$page_match = $page_match || preg_match($regexp, $_GET['q']);
}
// When $block->visibility has a value of 0, the block is displayed on
// all pages except those listed in $block->pages. When set to 1, it
// is displayed only on those pages listed in $block->pages.
$page_match = !($block->visibility xor $page_match);
?>
... though obviously you'd change $block->visibility to variable_get('cs_visibility', 0), and $block->pages to variable_get('cs_pages', ''), or whatever.
Hmm ... since these variables are always going to be called at more or less the same time, I wonder if it would be more efficient to discard the system_settings_page function and manually set the CS variables as a single array (eg "$array['flakeHeight'] = $form_values['flakeHeight']; variable_set('christmas_snow', $array)", then just "$variables = variable_get('christmas_snow', array()); print $variables['flakeHeight']" etc) ...
#4
thx. Darn - would have been a great addition - sadly many javascript IE errors trying to grab none.gif from wrong site locations has caused too many 'page cannot be found' errors (hundreds a minute) which subsequently creates many log entries, causing multiple select calls to mysql which my host got the humbug over as it pretty much hogged the shared server. So be careful of this PNG transparent issue in IE that so many have had to find workarounds for. Of course could also likely be a clash with my Sky theme.
#5
This is pretty cool. Thanks for the JavaScript code. I am working on adding it in. I can see some places were we can reduce the load some already in the code. It has been a tough few weeks at the office but now things are starting to slow down some I am going to get it added in the next few weeks.
Thanks
Robert