There has been growing interest in overhauling WebHelpers. This page captures the task list for sprinting:
- Consolidate the 21 submodules into a much smaller number.
- Fix the bugs, inefficiencies, and unpythonic Rails'isms in the functions. Consider each function for API improvement or elimination.
- Replace the paginator with Christoph Haas' improved one.
- Convert the HTML-tag functions to use the html.py module so they all return literal objects.
- Don't remove or change the existing Rails-based helpers to retain backwards compatibility.
Please add feedback to this page if you think something should (not) be done, or if you have any better ideas.
HTML generators
WebHelpers is using a html.py generation system that returns literal objects which ensure they aren't further escaped. It also builds XHTML compliant tags that are still valid in HTML 4 strict in a fast, efficient manner. The WebHelpers quote function will be the default Mako escape.
Refactoring List
webhelpers.hinclude
Javascript/HTML trick to do client-side includes. Deprecate.
webhelpers.html
New module for Ian Bicking's HTML generator, which will be used by all HTML tag helpers. (DONE)
The new HTML tag generation library and literal and quote functions.
webhelpers.tags
New module for helpers that produce HTML tags. Helpers that produce a small "tree" of tags are welcome here too, but larger trees should be in webhelpers.? (name TBD).
link(label, name, **url_for_args) : a combination of link_to and url_for, using a named route. HTML-escape the label. Other url_for features (nameless routes, current URL, literal URL) will not be accessible from this method.
link_if(condition, label, name, **url_for_args) : call link() if condition is true, else just escape the label and return it.
link_unless(condition, label, name **url_for_args : same as link_if but opposite logical sense: call link if condition is false.
These functions, as well as link_to and possibly others, depend on url_for, which is not a part of WebHelpers. WH should put a dummy module global somewhere: url_for = None. The caller will have to set this value itself before using these helpers. Pylons will set it to a StackedObjectProxy, and update it with the url_for function provided by the Routes 2 middleware.
webhelpers.form (or webhelpers.tags.form or include in webhelpers.tags.
New module for form-related HTML helpers, including form_for.
webhelpers.?
New module for HTML-related helpers that produce more than just a tag. We haven't found a good name for this module yet.
We need a flash function, something like http://pylonshq.com/pasties/332
but without the Javascript assumptions. It should also probably be a <ul> with a particular class.
webhelpers.text
New module for helpers that format text and can be used in both HTML and non-HTML applications.
webhelpers.htmlgen
A text to HTML generator. Deprecate.
webhelpers.pagination
Retain, but deprecate existing paginator.
webhelpers.paginate
Add. Use Christoph Haas' much-improved paginate
(Mercurial repository and web interface). He has a (demo
).
TurboGears' @paginate decorator
may want to be use it. This brings up a few issues:
- paginate has no SQLObject support. A TG volunteer may provide us code for it someday.
- paginate does not have an option to reverse the sort order (for SQLAlchemy and SQLObject only, not regular lists). It looks like TG should preprocess its '-fieldname' option and construct the query and Pager based on it.
Rename to webhelpers.paginate?
The new paginate has an AJAX mode that depends on Javascripts being deleted from WebHelpers. How to handle this?
webhelpers.rails
Deprecate this and all submodules. Useful functions will be moved as described below. webhelpers top-level module will continue to "import *" highly useful functions.
Functions being relocated and updated
The following modules should have the functions indicated moved into a new module in the upper directory tree, ie, webhelpers.rails.asset_tag functions would be moved into webhelpers.asset.
webhelpers.rails.asset_tag
auto_discovery_link_tag: generate a <link> tag advertising an RSS or ATOM feed. Move/Update.
image_tag: generate an <img> tag. The width and height should be specified as integers, not "100x200". The original prepends "/images/" to the URL; don't do that because it's too magical. Call the function ``img`` or ``image``.
javascript_include_tag: generate a <link> tag to load a Javascript file. Rename to include_javascript>. The original prepends "/javascripts/" to the URL if it doesn't start with a slash, and appends ".css"; don't do this, it's too magical. Remove builtins option. Ideally, applications can just register which Javascripts they depend on, and then something at the end packs them all up and minimizes them. Move/Update. Rename to ``javascript_link`` unless that conflicts with something.
stylesheet_link_tag: generate a <link> tag to load a CSS stylesheet. The original prepends "/stylesheets/" to the URL if it doesn't start with a slash; don't do that because it's too magical. Move/Update. Rename to ``stylesheet_link``.
webhelpers.rails.date
distance_of_time_in_words: express the difference between two datetime objects in English words. Move to webhelpers.text.
ago_in_words: same but one end is now. Deprecate as too trivial?
Add a function that avoids weasel words like "about", and one that spells out the time in words. A fuzziness argument would also be useful.
webhelpers.rails.form_options
Move to webhelpers.html or webhelpers.html.form. Move/update.
options_for_select: generate HTML "<option>" set. Combine into select function.
options_for_select_from_objects: same but get the labels and values from specific attributes in a list of objects. Deprecate.
options_for_select_from_dicts: same but get the labels and values from specific keys in a list of dicts. Deprecate.
webhelpers.rails.form_tag
Existing functions
Consolidate all non-deprecated functions to webhelpers.html.form. (webhelpers.html is currently a module, so they'll have to go into webhelpers.form for now.)
form, start_form and end_form: generate HTML <form> and </form> tags. form and start start_form are identical. Move form; deprecate the others.
select: generate a dropdown <select> tag. Combine options_for_select into this. There's a discussion about whether to reverse the pairs from (label, value) to (value, label). This would allow dict.item() to work but would make it harder to sort by label. Since dict.items() are unordered and this is unacceptable in most use cases, we may as well prefer (label, value).
text_field: generate a text input tag. Rename to text.
hidden_field: generate a hidden input tag. Rename to hidden.
file_field: generate a file upload tag. If you use this, you also have to set the multipart option on the form. Rename to file.
password_field: generate a password input tag. Rename to password.
textarea: generate a <textarea> tag.
check_box: generate a checkbox input tag. Rename to checkbox.
radio_button: generate a radio button input tag. Rename to radiobutton. TODO: what about groups of buttons? Can this be a variation of a select function?
submit_button: generate a submit button. Rename to submit.
Missing: reset button. Create reset.
Chairos has contributed a ModelWebHelpers
enhancement. Consider incorporating this as f = form_for(record, use_keys=False); f.text("myfield"). The values would be taken from the corresponding record fields, and converted intelligently from Python to HTML. If use_keys is true, use dict syntax to access values, else use getattr. Possibly these model tags could use the same class as the other tags, though really these shouldn't have a positional arg for value and that may sabotage that.
webhelpers.rails.number
Deprecate. These are all badly written and/or duplicate builtin Python funcationality.
number_to_phone: convert an int to a North American phone number string. Deprecate.
number_to_currency: convert a float to a currency string. Deprecate.
number_to_percentage: convert a float to a rounded percent string. Deprecate as too trivial.
number_to_human_size: convert an int to a unit phrase; e.g., "N MB". This should really distinguish between MB and MiB. Move/update.
human_size: already deprecated.
number_with_delimeter: format an int using a thousands separator. Deprecate.
number_with_precision: format a float with a given number of decimal digits. Deprecate: Python's % operator does this: "%0.2f".
webhelpers.rails.secure_form_tag
Move all to webhelpers.secure. Move/update.
secure_form: generate a <form> tag with a hidden authentication token. Move/update.
Add secure button_to, which is just like the current button_to, but generates the form using secure_form. This would prevent XSRF attacks.
Pylons has a @authenticate_form action decorator to verify the submit data came from the form that was sent to the user.
webhelpers.rails.tags
Move all non-deprecated functions to webhelpers.tags.
camelize: convert a text word to camelCase. Move/update.
tag: generate an HTML tag. Deprecate.
content_tag: generate an opening and closing HTML tag with content in between. Deprecate.
cdata_section: wrap the text in a CDATA construct. Move/udpate.
escape_once: HTML-escape a string without double-escaping existing escapes. Deprecate.
webhelpers.rails.text
Move all non-deprecated functions to webhelpers.text or webhelpers.html.
cycle and reset_cycle: iterate a list repeatedly. Deprecate: unneded Rails'ism. See Pylons itertools module for alternatives. For alternating colored rows in an HTML table, use:
1
2 | % for i, r in enumerate(records):
<tr class="%{i % 2 and 'odd' or 'even'}">
|
counter and reset_counter: like range but the counter is implicit. Deprecate: range or xrange is more pythonic.
truncate: truncate a string if longer than a certain length, using a continuation marker. Move/update..
highlight: put a highlight span around some text. Move/update..
excerpt: extract a substring with N surrounding characters. Move/update.
word_wrap: already deprecated, use Python's textwrap.fill instead. Deprecate.
simple_format: convert text to HTML paragraphs. Deprecate in favor of one of the other text-to-HTML converters, or rename to webhelpers.html.? and perhaps add some features useful for blogs.
auto_link: convert all text URLs and email addresses to hyperlinks. Move/update.
strip_links: convert hyperlinks in text to just their labels (i.e., the body of the <a> tag). Move to webhelpers.html. Need another function to sanitize user input; i.e., stripping disallowed tags. Move/update.
textilize: filter text through webhelpers.textile, optionally converting the tags to XHTML. Move/update.
http://somethingaboutorange.com/mrl/projects/nose/
markdown: filter text through MarkDown, which is included in WebHelpers. Move/update.
webhelpers.rails.urls
url: lazy version of url_for. Deprecate.
link_to: generate a hyperlink based on a text URL. See use cases in old WebHelpers help
. Move/update.
button_to: same but generate a button rather than a link, with a little POST form. Use this for destructive actions, which should not be done by a link or GET. See examples in old WebHelpers help
. Move/update.
link_to_unless_current: generate a hyperlink unless the URL refers to the current page, else just return the label. Deprecate as too magical? Move to Routes url object?
link_to_unless and link_to_if: conditional versions of link_to. Move/update
current_page: true if the argument equals to the current page's URL. Move to Routes url object?
mail_to: generate a <a href="mailto:..." hyperlink. Move/update
js_obfuscate: obfuscate Javascript source code. Deprecate? Move to webhelpers.js.
Future plans after functions are moved.
webhelpers.text
New package for string functions that don't depend on HTML. (Also considered webhelpers.string.)
webhelpers.textile
A simpler text to HTML generator.
No changes planned. Ben is using this. Review source to see if updates are needed.
webhelpers.util
Ignore for now.
html_escape(s: convert to unicode and HTML escape; None to "". Move to webhelpers.html, along with a new url_escape function based on urllib2.quote. Note that the path part of a URL needs quote, and the query part needs quote_plus.
Partial: predecessor to functools.partial in Python 2.5. Deprecate.
SimpleXMLGenerator: small convenience subclass for Python's SAX XMLGenerator. Deprecate.
UnicodeMultiDictMixin. Deprecate.
If everything is deleted from this module, it would still be a worthwhile place for non-HTML functions. Mike Orr has several worth adding.
Javascript (Ignore for now)
We've decided to delete all Javascript libraries for now, including the existing Prototype and Scriptaculous. The libraries are moving too fast to support, and all contenders do too much browser sniffing (guessing the browser version to accommodate its quirks). The former discussion is in version 45
of this article.
The following Javascript helpers have been proposed, which do not depend on any of the bad libraries:
Organizing Javascript libraries in Pylons (historical)
We were planning to include YUI and JQuery, which are the most complete without being too big. (We're looking at you, ExtJS.)
Implementation of this has been cancelled but it remains here for reference.
webhelpers top level
javascript_path: absolute path to Javscripts directory. (Exposed to web.) Unsure if internal or public.
javascript_builtins: just of Javascript libraries included. Currently: "('prototype.js', 'scriptaculous.js')".
Delete attributes if non-public and not needed.
webhelpers.rails.javascript
Move all these to webhelpers.js. Convert to ElementTree as appropriate.
link_to_function: returns a link that'll trigger a JavaScript function using the onclick handler and return false after the fact.
button_to_function: same but display a button rather than a hyperlink?
escape_javascript: Escape carriage returns and single and double quotes for JavaScript segments.
javascript_tag: wrap a literal chunk of Javascript code in a <script> tag, doing the proper quoting.
webhelpers.rails.prototype
Move all to webhelpers.js.prototype. Convert to ElementTree where appropriate.
See the old documentation
for examples and arguments for these functions.
link_to_remote: the AJAX function.
Call a server action asynchronously from a webpage, usually to update an element in the page. Ben thinks this should be deprecated and replaced with something else because it has Javascript eval the result JSON, which is supposedly inefficient.
periodically_call_remote: same but repeat every N seconds.
form_remote_tag: create a form that submits to a remote action asynchronously.
submit_to_remote: generate a submit button that calls a remote action asynchronously.
update_element_function: return a JavaScript function (or expression) that'll update a DOM element.
evaluate_remote_response: return a Javascript function that evals a request response
remote_function: return the JavaScript needed for a remote function.
observe_field: observes the field with the DOM ID specified by field_id and makes an Ajax call when its contents have changed.
observe_form: same but operate on an entire form.
webhelpers.rails.scriptaculous
Move all to webhelpers.js.scriptaculous. Convert to ElementTree as appropriate.
visual_effect: add a variety of visual effects to an object on the webpage.
parallel_effects: apply multiple visual effects to the same object.
sortable_element: used in a table with a clickable column header for sorting?
draggable_element and drop_receiving_element: drag n drop.
Other parts of WebHelpers with Javascript support
secure_form_remote_tag: a secure form of form_remote_tag. (Does not exist yet.)
I'd like to see url_for in Pylons core since it really is essential function while the webhelpers is fully optional package (if I understand this correctly).
Choosing the "best" js library may be a futile attempt so may be it's better to somehow avoid this entirely.