My goal is to tidy up the UI for users who are editing or creating nodes - basically make the editing pages more user friendly. I hope to submit this code to the 'useful theme snippets' section of the handbook. I think it would be of use to theme developers who are concerned about making user contributions to their site as painless as possible.
(I am using drupal 4.6.3 and modifying friendselectic theme (phptemplate) by editing the template.php and style.css files (so far). The modules involved in my set up are: Flexinode, tinyMCE, Organic Groups, Subscriptions, Filter (HTML filter) and Event.)
The problem I'm having is that I want to theme the page-layout of input boxes and their attendant help info via style.css. Each form_element block on an edit page is assigned the class 'form-item' but there is no other 'hook' that would allow for CSS to disintinguish between, say, the 'Title' element and the 'start date' element. What I'm trying to do with the following code (appended into template.php), is generate individual, html id tags for each 'form-item' wrapper. Seasoned programmers will no doubt think that it's pretty simple, in which case I'd be very greatful for your input :)
The code so far basically works on most input fields, but currently tinyMCE textareas produce some strange and unhelpful behaviour which I can't even begin to fathom! As a non-programmer it has taken me many long hours to get this far, and I'm amazed that it actually works to this extent! However, now I'm stuck. I would really appreciate any suggestions and help to get this up and running and available for all drupal themers.
The story so far ...
- phase 1
- The function theme_form_elements is intercepted by phptemplate_form_element function in the standard way
- the code for phptemplate_form_element function was simply ripped from the API manual, and jiggled around a bit so that $title is followed inline by the $description text and then the actual input field (called $value) is displayed on the next line. I think this is a more logical and intuitive sequence. Others may find it helpful.
- I had to make a local copy of the function form_clean_id so that phptemplate_form_element would run - there might well be a better way of doing this.
- next step was to get the id tag into the first line of the phptemplate_form_element function (
$output = '<div class="form-item"\n";). Pretty straight forward. As I actually want to pass a variable to this tag, I left the string concatenation format in place, but used a non-variable string ('idname') for a dry run. - so far so good - this all seems to work fine.
code after phase 1:
/* ------------------------------------------------------*/
/* re-organise presentation of form elements / form-item */
/* ------------------------------------------------------*/
/* first we need this function locally? */
function form_clean_id($id = NULL) {
$id = str_replace('][', '-', $id);
return $id;
}
/* Catch the theme_form_element function, and redirect through the template api */
function phptemplate_form_element($title, $value, $description = NULL, $id = NULL, $required = FALSE, $error = FALSE) {
/* run the modufied version of the theme_form_element function */
$output = '<div class="form-item" id="' . 'idname' . '">\n' ;
$required = $required ? '<span class="form-required">*</span>' : '';
if ($title) {
if ($id) {
$output .= ' <label for="'. form_clean_id($id) .'">'. $title .':</label>'. $required ."\n";
}
else {
$output .= ' <label>'. $title .':</label>'. $required ."\n";
}
}
if ($description) {
$output .= ' <span class="description">('. $description .")</span><br />\n";
}
$output .= " $value\n";
$output .= "</div>\n";
return $output;
}
/* --------------------------------------*/
- phase 2 : inserting the $idname into the form-item html tag required a little more creativity, and is giving me problems:
- because every html
<input>field must have a unique identifier in itsname=""attribute, it made sense to use this for our $idname. - in phptemplate_form_element replacing
'idname'with a variable, eg$valueworks but is html messy... - so I wrote this function (which I'm rather proud of) to find, extract and return only the
name=attribute in $value:
function form_item_get_idname($value) { $nameregexp = '/name=\"(.*?)\"/i'; preg_match ($nameregexp, $value, $matches); $idname = $matches[1]; return $idname; }and this is called from phptemplate_form_element by inserting into the first line in place of
'idname'thus$output = '<div class="form-item" id="'. form_item_get_idname($value) .'">'."\n" ; - b ut ther's something wrong now.
so here is the whole guddle of code after phase 2:
/* ------------------------------------------------------*/
/* re-organise presentation of form elements / form-item */
/* ------------------------------------------------------*/
/* first we need this function locally? */
function form_clean_id($id = NULL) {
$id = str_replace('][', '-', $id);
return $id;
}
/* then we need to get our $idname */
function form_item_get_idname($value) {
$nameregexp = '/name=\"(.*?)\"/i';
preg_match ($nameregexp, $value, $matches);
$idname = $matches[1];
return $idname;
}
/* Catch the theme_form_element function, and redirect through the template api */
function phptemplate_form_element($title, $value, $description = NULL, $id = NULL, $required = FALSE, $error = FALSE) {
$output = '<div class="form-item" id="'. form_item_get_idname($value) .'">'."\n" ;
// $output = '<div class="form-item" id="'. 'idname' .'">'."\n";
$required = $required ? '<span class="form-required">*</span>' : '';
if ($title) {
if ($id) {
$output .= ' <label for="'. form_clean_id($id) .'">'. $title .':</label>'. $required ."\n";
}
else {
$output .= ' <label>'. $title .':</label>'. $required ."\n";
}
}
if ($description) {
$output .= ' <span class="description">('. $description .")</span><br />\n";
}
$output .= " $value\n";
$output .= "</div>\n";
return $output;
}
Note that I've left in the phase 1 line, escaped with // so if you copy the code to run it, you can toggle between 'stable' and 'buggy' versions.
- phase 3 : trouble at mill
- phase 2 actually works ( I can barely believe it) for most form elements, giving them a CSSable id tag based on their input box name! For example
id="edit[Title]"andid="edit[flexinode_59]"for an instance of a custom flexinode field. Such possibilities! I hope the[]brackets don't upset CSS! - but, there's a problem with textareas:
- with tinyMCE 'off' by default, some of the $title + $description html is duplicated inside the textarea (let's call this $junk!).
- when I 'enable rich-text', tinyMCE appears as expected, though the $junk is still there it can be easily deleted, and doesn't reappear after the page has been submitted.
- with tinyMCE set 'on' as default. The $title:description is sucked into the iframe! it disappears from it's rightful place, and it's html code can't be seen when i use the browser's view source (I guess this is because of the iframe). The 'disable rich-text' button is also sucked in and rendered functionless.
- in brief - I haven't the foggiest what's going on.
Thank you for reading this far. My apologies if the level of detail is OTT. If you have any suggestions whatsoever, please do take a moment to let me know. I've reached an impass and any help would be most appreciated.
thanks in advance
JohnG
Comments
formapi
i think the form api that just hit core will help here a lot. have a look.
API ?
moshe, sounds great!
While we're waiting for 4.7.x can you see what's wrong with my code? Is it something to do with arrays?
I'm trying to learn how to create solutions rather than just wait for the next release of drupal - otherwise I'll never get a site finished!
I just want to theme node-edit pages to help people who contribute to my website, and if I can, contribute to the theming handbook.
Please elaborate on why you think the immanent API can help me? I don't even know what an API is! I can't tell if the API will implement the 'css hooks' I'm trying to do.
updated and working! try this out:
added a filter to format the idname, removing [] that seem to upset the tinyMCE javascript ... The open square bracket [ is replace with underscore _ (initially I used a hyphen - but this upset the toggle tinyMCE function) and other $sensitive characters are simply removed.
So as far as I can tell it seems to be fully functional with this patch. If anyone would like to try it out, I've included the whole code below for you to cut&paste into your template.php or equivalent. Please do let me know if you experience any problems - as I've said I'm no coder and this kind of hacking is very slow for me so don't expect instant feedback!
Please do let me know what you think!
final ? working code: