I'm not sure what the procedure is for suggesting additional field modules, but I needed a module that offers a way to select a value from a pre-configured list, so I worked one up.
I created the module to be as flexible as possible -- you can opt to view the options as a select list, radio boxes or checkboxes, either with multiple or single values. You can also opt how to display mutiple values in the view (single line separated with commas, each on a new line, or as a bulleted list). I also added in the functions needed to add the options field to views.
I used the same way of defining the list of options as flexinode's field_select uses (a text area where you can input a list of values separated with '|'). I am thinking this field could be adapted to handle imports from flexinode field_select, field_multiselect, and field_checkbox fields.
This obviously still needs testing, but just in case anyone is interested, I have attached my module.
| Comment | File | Size | Author |
|---|---|---|---|
| #20 | options.css.txt | 363 bytes | karens |
| #19 | text.module_1.patch | 2.87 KB | karens |
| #18 | number.module_0.patch | 2.91 KB | karens |
| #17 | options_1.module | 16.79 KB | karens |
| #2 | options_0.module | 14.59 KB | karens |
Comments
Comment #1
karens commentedHere is the install file that goes with it.
Comment #2
karens commentedThis was originally set up like the flexinode select field, i.e. it used a numeric key based on the sort order of the options in the textarea. This has a major weakness -- you can't add new options to the beginning or middle of the list once you begin using the field, since the key will change every time the option list changes.
Therefore, I completely re-wrote the field so you can set a key for each field. That way you can come back later and add new options to the list without goofing up data you already have saved.
I also made a number of other changes:
1) I added in validation for the option list to make sure it includes only alphanumeric data for option keys (the labels can contain spaces or any other value)
2) I added in additional validation when the list is changed to make sure an option that has been removed from the list is not currently being used in the database.
3) I created a way for the admin to decide how the data will appear in the form, i.e. in a label and div, in a definition list, in a table, plain, etc. using a selection option and a theme for each. I created these options in a way that I could scrape this whole part of the code out and put it into the content module to make these options available to all fields.
I'd be very interested in having other feedback on this module. I think it is far enough along now that I am going to try it with some live data.
Comment #3
karens commentedFor #3, I meant to say how the data will appear in the node view. The existing field modules just send back the data in a div, with no label. I wanted to give the admin some control over that so he/she could format it differently. Even with the views module (which is really great) to handle things like lists and tables of cck nodes, we still need to configure a way to format the display of the node itself.
Comment #4
jonbob commentedIt feels to me that this is probably not really best as a new field type, but rather a new widget type for the existing text and number fields. Any issues with this approach?
Comment #5
karens commentedI considered that when I started this, but couldn't see any way to shoehorn it into those modules. The whole process of creating, validating, and updating an options list is completely different than creating a text field where the user enters their own content, so it seems to me that this is a distinct module.
Or are you saying there would be another type of module for widgets, that would be called by the text and number modules? I can't quite visualize what you mean.
Comment #6
karens commentedAnother place where this type needs special treatment is in the views module. I set the view up so that it would pull the option value out of the database, but display the label that goes with it. This is again completely different from the way that text and number fields are handled in the view.
I think my other analogy is that a date field is a number, but it clearly is so different from other numbers that it needs its own field type.
Comment #7
coupet commentedTested and works perfectly. This is a great contrib to CCK and highly recommended!
The options module allow you to easily include data that is not taxonomy related into CCK.
Please note: I suggest using Taxonomy to include vocabulary and terms in CCK.
Comment #8
jvandyk commentedKarenS, thanks for your work on this module. However, I believe that there is a fundamental misunderstanding here.
CCK uses two concepts, fields and widgets.
A field has to do with the essential type of the data. A widget has to do with how that data is displayed. They are independent. A textbox widget is a completely different concept from a text field.
What you have written is not a field, but a collection of widgets. This is exactly what we need. I want to be able to display my number field as a textbox, a select box, a series of radio buttons, whatever...these are all widgets or ways of displaying a field type.
To answer your question above, yes, a module can contain only widgets. The widget callback will pick up the new widgets and make them available. In fact, one of the first things I did with your module was to modify the _widget_info() hook in your module, which is where your module declares which field types your widget(s) support.
Before:
After:
This allows your widget to be applied to a basic text field.
So in summary, you are writing configurable widgets, which we definitely need. However, I agree completely with JonBob -- these widgets need to be applied to the basic field types; creating new field types based on widget choice is what flexinode did and what we wanted to get away from in CCK. The CCK process of creating a content type is
1. Create a new content type.
2. Decide which field types (think of them as data types) the content type will have.
3. Now configure the user interface for those data types. Will your users be choosing their integer using a selectbox widget? A radio button widget? Typing it into a textbox widget?
It is very important to think of steps 2 and 3 separately.
If there are issues with validation or views, these need to be resolved in the basic field types rather than with a new module. In other words, it appears that you are doing core CCK development!
Comment #9
karens commentedI totally agree with the concept, just still having trouble seeing exactly how the code will work. I guess I need an example since the modules that already exist don't operate that way. I will play around with it a bit. What other changes would I make to make it operate the way you envision?
Comment #10
seandunaway commentedwill this make it into cck's code?
Comment #11
coupet commentedIn content.module, widgets can be added thru function :
function _content_widget_types()
adding the revised options module to cck subdirectory might do it!
example for 4.6
ecommerce product.module and generic.module
generic module is adding functionality to product module
generic module is added to subdirectory of ecommerce
Comment #12
karens commentedI was waiting a bit to be sure there were no more database changes coming, but am back working on this module. I think I can see how to make it work as a widget, except I need a "widget_view" hook to be called from the content module when viewing the data. (I assume that would not be hard to add.) My plan is to store the option list with the widget instance, which will allow me to do all the validation, etc. that is already in there. With the addition of a view hook, I can also take care of swapping the label back in for the field key when the node is viewed.
The only remaining issue is that the text field automatically has filtering options on it, which don't make sense when the options widget is used. Shouldn't those criteria be moved to the widget instead of the field? That way they will appear when you use a text field or text area widget where the user supplies the input, but will not appear when the data is constrained to a pre-defined list.
Comment #13
karens commentedTo clarify my thinking further...if content module called widget_view before calling field_view, I can have widget_view swap in a label (or labels if it is multi-select) into the $node object before field_view gets $node, then field_view can format the output as it does now.
Comment #14
karens commentedI'm explaining my thought process as I go here in case anyone wants to jump in to tell me I'm headed in the wrong direction before I get too far down that path.
In working with this, I realize that the option list has to be linked to the field, not the widget, otherwise every time you want to change the widget (i.e. from a select list to a checkbox) you have to re-define the option list, which I'm sure is not what anyone wants to do.
That leads to some problems because the widget only has access to a limited amount of information and only has one or two places where it can take action, as things are currently defined. The widget will need to know what the available options are, if they are not defined by the widget, in order to create the user input form. Plus there will need to be plugins for text and number to give them the necessary functionality to create and validate an option list.
This is all doable, just not what I originally did, so I am backtracking and trying this again.
If anyone has any thoughts about how this widget should work as I work along here, jump in anytime!
Comment #15
RayZ commentedfield or widget?
I think either is valid depending on your application. Here's the way I (currently) see it.
Widget - If the data is fundamentally a text type, for example, and you simply want to use a select or radio button set to allow easy entry of what will be a limited set of text values, then it's a widget. And yes, each widget (select or radio button) must contain the list of options.
Field - If, however, the data is fundamentally an enumerated type, then the list of options must be tied to the field and it should probably be stored as an index into the set of options. Obviously, it would make sense to have a select and/or radio button widget to go with such a type, and the widget would need to get the list of options from the field type as you mentioned.
I would expect the latter to be the more common case. If you are using a select menu or radio buttons with a text field, I would question whether your data is really fundamentally a text data type.
Not having looked at the code at all, it also seems to me that validation should be tied to the field type, or maybe more specifically to a field instance, rather than to the widget. Is this not the case?
Just some thoughts.
Comment #16
coupet commentedgoal is to create a widget module (options) that add to the basic widget for 'text_shortext' included in module text.module
-- the widget will provide the following: opt to view the options as a select list, radio boxes or checkboxes, either with multiple or single values.
The undocumentated part is how to make the widgets available to cck
Comment #17
karens commentedOK, I've got at least the beginnings of something here. Thanks RayZ, your comments helped me clarify what I was struggling with. And thanks to others who offered ideas. Here's how I ended up.
The options widget is configured to work with both the text and number fields. If you use it in a text field, you configure a list of options that has text keys which are stored as text. If you use it in a number field, you configure a list of options that have numeric keys, and your selections are stored as numbers in the number field. In addition to being able to input a list of values and labels, I also added an alternative for the number field where you can have it create an option list automatically as a series of numbers from min to max, incremented by increment (you supply the min, max, and increment).
My widget needed to communicate with the field module in several places, so I altered the text and number modules slightly to call the options module, if it is enabled. If the options module is not enabled, nothing will happen. The options module then handles the creation and validation of the options list, alters the view to replace the option with its label, etc. I tried to keep the changes to text and number to a minimum so they aren't weighted down with extra code if someone just wants plain text fields.
I felt it was important to store the options list in the field rather than the widget for several reasons. First, that way you can define a long list of options one time and use it in several different content types (like the list of countries that needs to be used in several types that someone has already requested). Second, if the options list disappears every time you change the widget, I think non-programmers will be completely baffled and are likely to consider it a bug in the way the module (and cck) works. My thinking is that it is really important do things in a way that non-programmers will find intuitive, since that's who this is designed for. Lastly, you might create a list as a select list and later decide to present the same options as a radio list instead without wanting to re-create the options list. If someone really needs a field that has different options, I think it makes more sense for them to create a different field.
To keep the option list from disappearing if someone changes the widget to a text field and then tries to change it back (perhaps accidentally, not realizing what they are doing), I am storing the options list as a hidden field if the text widget is used, and revealing it if the options widget is used, so the value isn't lost if you change the widget. The hooks I put into text and number make that possible.
The validation is not yet thoroughly tested, and I'm sure there are other bugs, and I'm also sure others will have different ideas about how it should work, but anyway, here is what I came up with.
I'm attaching the module to this post, and will supply the patches for text and number right after this.
Comment #18
karens commentedHere is the patch for number.
Comment #19
karens commentedAnd here is the patch for text.
Comment #20
karens commentedActually there is also a css file to go with this (not critical, just formats some of the options in a way that I like better.) Here is it.
Comment #21
coupet commentedlooking forward to implement the options widget, but with active development of text and number modules, I am unsure about patching them.
maybe number and text modules need to patch themselves to ease integration with other modules.
Comment #22
webchickComment #23
karens commentedI agree that a more global way of including widget info would be better. One thought is to create a widget_override function for each field function that needs intervention (maybe using a pattern like widgetname_override_fieldfunctionname.) Then have the field or content modules check whether any widget functions exist with that pattern, and pass them the $form or $output or $node or whatever else is needed so they can do their thing. I initially was going to say only check for the currently-used widget, but that won't be sufficient to do things like maintain the option list if the widget is changed, so I think it needs to be invoked always and the widget can just do nothing if it is not the currently selected widget and it has nothing to change.
In the case of formatting a view, obviously the widget needs to jump in before the field info is themed and returned. In the case of a form, the widget needs to be able to add (and maybe alter) form elements after the field case created the ones it needs. In the case of validation, the widget needs to have a chance to validate the input, either before or after the field has done so, and in the case of update or save, the widget needs to be able to jump in and alter the input value before it is stored to the database. I think those are the times the widget needs access to what the field is doing.
Because some of these things need to take place during the time the field function has control, I think the patch has to go in the field module rather than in the content module, so it won't be quite as neat as it would be if the content module could just invode the widget function after the field function.
If I get a chance I will try to figure out what the patch could look like, but probably won't get to this until next week.
Comment #24
karens commentedHere's a thought that might make this work with a minimum of changes in a way that should be globally usable by other widgets and fields.
So far I only see two functions that aren't already working fine -- the hook_field_settings function and the hook_field function. Only the field's version of those functions gets invoked, and nothing the widget needs to do in those processes gets done because the widget never gets called.
We could take care of this process by altering content.module when it invokes those two fields so that it checks to see if there is a similarly-named function in the widget as well as the field, and if so, invoke it, too. For instance, there is a function in the text field called text_field and there is a function in the options widget called options_field (I already set the options module up to use the those naming conventions). I then just need content.module to invoke options_field either before or after it invokes text_field, depending on the operation.
1) When creating an input form, call the field first, then the widget (that will allow the options widget to add a list of options to a select element, for instance).
2) When validating data, the order called probably doesn't matter.
3) When saving data, invoke the widget to make final changes necessary just before saving the data, then go ahead and invoke the field to save the data (just have to be sure it doesn't do anything to overwrite anything the widget may have added).
4) When viewing the data, invoke the field first, but have the field return the data it creates as an array or object with a label and a value for each field rather than as formatted output, then invoke the widget to allow it to change the label and value as necessary, then have the content module theme and format the individual fields, and the node as a whole. Think of it like the new form api handles the $form array -- just pass a $view array around to all the modules that need to do something with it, then sort it and process it at the end.
That's my 2 cents, anyway.
Comment #25
jonbob commentedI'm looking at this code carefully, and hopefully will start committing parts today. Thanks for all of your work, Karen.
I think it's absolutely vital that we keep a clean separation between the tasks a widget performs and the tasks a field performs. I'm going to write something up to define this clearly, so we have something to look at when making these decisions.
The plan here is to commit these new features piecewise. Please don't assume that because part doesn't get in right away that it won't be added later. I'm going to start with the more clear-cut issues and try forking separate feature requests off into their own threads as possible.
Comment #26
jonbob commentedA rudimentary version is now committed. Users may provide a list of allowed values for the field, which is just checked and throws an error if a normal text field widget is used. The alternate widgets use these allowed values for their option lists. Labels for the options will be a widget setting rather than a field setting; this has to wait until the admin interface is refactored to put widget and field settings on separate pages (so it's a two-step process).
Comment #27
jonbob commentedSorting is now available.
Marking this fixed; will open issues for the remaining missing pieces.
Comment #28
jonbob commentedOops, wrong thread.
Comment #29
yched commentedLooks fixed to me - optionwidgets is now bundled with cck.
Comment #30
(not verified) commented