[reposted from rails-core] I''ve recently submitted two patches (#5122 and #5266) to the Rails trac. These patches are actually for Prototype. There appears to be very little discussion about Prototype on this list, but I wanted to share what I''ve been doing in the hopes of soliciting some feedback from you folks. If this isn''t the right place to discuss Prototype, mea culpa - where should I go? http://dev.rubyonrails.org/ticket/5122 #5122 addressed adding document.getElementsByAttribute, alongside the existing document.getElementsByClassName. We''ve found that while it''s useful to be able to use ''ByClassName, often we''ll step on our designers'' toes if we try to use the class for a programmatic function. Semantically I believe that the designer is right - the class attribute is for defining CSS attributes, and not really intended for functionality. Using document.getElementsByAttribute has changed how we approach our client side scripting. We''ve taken to using custom attributes to group input elements together to support domain specific functionality. For example, if we have a column of text elements that are intended to be totalled, I will set subtotal="true" inside those input elements. I can then assign an event handler to all of these elements with one statement: document.getElementsByAttribute(''subtotal'').each(function(obj) { obj.onchange = handle_calc; }); Seeing as any node can have multiple custom attributes defined, it is easy to attach an arbitrary number of semantically named attributes which can be iterated through as required. One huge advantage of this is that by DRYing up your event handling code, you encourage moving past defining individual event handlers on a per-node basis. Now, I have an init() function fire which assigns all event handling and behavioural code; when you inspect the source, all you see are intelligently named attributes. http://dev.rubyonrails.org/ticket/5266 The second half of this is #5266, a modification to the .pluck method in Prototype. Taken on its own, it might seem ho-hum, but when paired with document.getElementsByAttribute, you have the tools you need to create really potent domain specific solutions that don''t require any further inline event handling. My favourite example is for an application where you need to keep track of whether a change has been made on a page. Before you would have used a relatively ugly combination of inline event handlers and javascript variables. Instead, why not: 1. Attach changed="false" to every relevant node during the page render 2. Iterate through the document and assign the event handler for each node with the changed attribute defined to a generic function that sets { this.setAttribute(''changed'', ''true'') } 3. When updating, set all nodes to changed=''false''. 4. When leaving the page, iterate through the document using document.getElementsByAttribute(''changed'').pluck(''changed'') and verify that all nodes are changed = ''false'', or else take appropriate action. Many Rails coders will probably not feel the benefits of these changes right away, but anyone using Prototype to do heavy client side work will likely find this to be an awesome addition to their toolbox. Pete
document.getElementsByAttribute is a really cool idea! I currently use the CSS selector approach originally used in behaviour.js, but I like this approach much more. Thanks for sharing! On Friday, June 02, 2006, at 10:51 PM, Pete Forde wrote:>[reposted from rails-core] > >I''ve recently submitted two patches (#5122 and #5266) to the Rails trac. >These patches are actually for Prototype. There appears to be very little >discussion about Prototype on this list, but I wanted to share what I''ve >been doing in the hopes of soliciting some feedback from you folks. If this >isn''t the right place to discuss Prototype, mea culpa - where should I go? > >http://dev.rubyonrails.org/ticket/5122 >#5122 addressed adding document.getElementsByAttribute, alongside the >existing document.getElementsByClassName. We''ve found that while >it''s useful >to be able to use ''ByClassName, often we''ll step on our designers'' toes if >we try to use the class for a programmatic function. Semantically I believe >that the designer is right - the class attribute is for defining CSS >attributes, and not really intended for functionality. > >Using document.getElementsByAttribute has changed how we approach >our client >side scripting. We''ve taken to using custom attributes to group input >elements together to support domain specific functionality. For example, if >we have a column of text elements that are intended to be totalled, I will >set subtotal="true" inside those input elements. I can then assign an event >handler to all of these elements with one statement: > > document.getElementsByAttribute(''subtotal'').each(function(obj) { > obj.onchange = handle_calc; > }); > >Seeing as any node can have multiple custom attributes defined, it is easy >to attach an arbitrary number of semantically named attributes which can be >iterated through as required. One huge advantage of this is that by DRYing >up your event handling code, you encourage moving past defining individual >event handlers on a per-node basis. Now, I have an init() function fire >which assigns all event handling and behavioural code; when you inspect the >source, all you see are intelligently named attributes. > >http://dev.rubyonrails.org/ticket/5266 >The second half of this is #5266, a modification to the .pluck method in >Prototype. Taken on its own, it might seem ho-hum, but when paired with >document.getElementsByAttribute, you have the tools you need to create >really potent domain specific solutions that don''t require any further >inline event handling. > >My favourite example is for an application where you need to keep track of >whether a change has been made on a page. Before you would have used a >relatively ugly combination of inline event handlers and javascript >variables. Instead, why not: > >1. Attach changed="false" to every relevant node during the page render >2. Iterate through the document and assign the event handler for each node >with the changed attribute defined to a generic function that sets { >this.setAttribute(''changed'', ''true'') } >3. When updating, set all nodes to changed=''false''. >4. When leaving the page, iterate through the document using >document.getElementsByAttribute(''changed'').pluck(''changed'') and verify that >all nodes are changed = ''false'', or else take appropriate action. > >Many Rails coders will probably not feel the benefits of these >changes right >away, but anyone using Prototype to do heavy client side work will likely >find this to be an awesome addition to their toolbox. > >Pete > >_______________________________________________ >Rails-spinoffs mailing list >Rails-spinoffs-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org >http://lists.rubyonrails.org/mailman/listinfo/rails-spinoffsCheers! --Dave Teare http://1passwd.com - Password Manager + AutoFill for Mac OS X http://devlists.com - Email list management http://palmsphere.com - Apps for your hand-held -- Posted with http://DevLists.com. Sign up and save your mailbox.
Pete Forde wrote:> http://dev.rubyonrails.org/ticket/5122 > #5122 addressed adding document.getElementsByAttribute, alongside the > existing document.getElementsByClassName. We''ve found that while it''sI''m not arguing with the usefulness of this function but I am wondering why this should be used over selectors. I.E. You have: document.getElementsByAttribute(''subtotal'').each(function(obj) { obj.onchange = handle_calc; }); why not just do: $$(''[subtotal]'').each(function(obj) { obj.onchange = handle_calc; }); My concern is that what if later we want a function that will find all elements where attribute "changed" is equal to "true". Then we want to find all elements where the tag is "td" and the attribute "changed" is equal to "true". As you can see we can go on forever like this. As we keep adding methods to make element selection we end up with a bigger and bigger API that programmers have to learn to get the elements they need. Also prototype becomes large which is not good for a library that must be downloaded to every client. OR We can just use selectors. CSS selectors are very good as specifying elements in a document. Take a look at http://www.blooberry.com/indexdot/css/syntax/selectors/selectors.htm to see how capable they are. I don''t know if prototype support all the syntax that CSS selectors are capable of yet but it seems to me that is where the effort should be placed and not on adding to the API. Selectors are concise and people already know them from CSS (so nothing new to learn). The only advantage to special purpose selector functions is perhaps performance but I have found the selectors code quite efficient. Especially if you keep a few things in mind. See my post from the 31st for tips on how to keep performance good when using selectors. Just my two cents. I welcome disagreements. :) Eric
Hi Pete and Eric, Eric Anderson wrote:> We can just use selectors. CSS selectors are very good as specifying > elements in a document.That''s exactly what I thought, too. Using $$() is IMHO the way to go, and keeps us from adding more and more getElementsByWhatever() functions. Enhancing the generic $$() function to fully support (unit testable) CSS2 selectors while maintaining reasonable performance, would be the real challenge. cheers Ingmar
Hi Pete, Eric and Ingmar, I''ve spent quite some time making Brian Donovan''s attribute selectors for $$() IE6 compatible* and extending it with *=, ^= and $= selectors and the negation selector :not(X). These were the selectors I was really missing and thought could be the most useful. I purposely limited their number to keep the library lightweight. I added a bunch of tests and my patch here: http://dev.rubyonrails.org/ticket/5170 I''m already using this patch to great success in an application I''m currently working on. Your comments, suggestions, enhancement requests or bug reports are of course more then welcome. Hope this also answers some of your needs. Best regards, Tobie * There where various issues regarding IE6''s way of rendering getAttribute in case of empty attributes versus non-existing ones, and peculiarities in it''s handling of the href attribute. These, by the way, have been documented since by Glenn Jones: http://www.glennjones.net/Post/809/getAttributehrefbug.htm.> Hi Pete and Eric, > > Eric Anderson wrote: > > We can just use selectors. CSS selectors are very good as specifying > > elements in a document. > > That''s exactly what I thought, too. > > Using $$() is IMHO the way to go, and keeps us from adding more and > more > getElementsByWhatever() functions. > > Enhancing the generic $$() function to fully support (unit testable) > CSS2 selectors while maintaining reasonable performance, would be the > real challenge. > > cheers > Ingmar