{"database": "24ways", "table": "articles", "is_view": false, "human_description_en": "where author_slug = \"drewmclellan\", topic = \"code\" and year = 2006", "rows": [[124, "Writing Responsible JavaScript", "Without a doubt, JavaScript has been making something of a comeback in the last year. If you\u2019re involved in client-side development in any way at all, chances are that you\u2019re finding yourself writing more JavaScript now than you have in a long time.\n\nIf you learned most of your JavaScript back when DHTML was all the rage and before DOM Scripting was in vogue, there have been some big shifts in the way scripts are written. Most of these are in the way event handlers are assigned and functions declared. Both of these changes are driven by the desire to write scripts that are responsible page citizens, both in not tying behaviour to content and in taking care not to conflict with other scripts. I thought it may be useful to look at some of these more responsible approaches to learn how to best write scripts that are independent of the page content and are safely portable between different applications.\n\nEvent Handling\n\nBack in the heady days of Web 1.0, if you wanted to have an object on the page react to something like a click, you would simply go ahead and attach an onclick attribute. This was easy and understandable, but much like the font tag or the style attribute, it has the downside of mixing behaviour or presentation in with our content. As we\u2019re learned with CSS, there are big benefits in keeping those layers separate. Hey, if it works for CSS, it should work for JavaScript too.\n\nJust like with CSS, instead of adding an attribute to our element within the document, the more responsible way to do that is to look for the item from your script (like CSS does with a selector) and then assign the behaviour to it. To give an example, take this oldskool onclick use case:\n\n<a id=\"anim-link\" href=\"#\" onclick=\"playAnimation()\">Play the animation</a>\n\nThis could be rewritten by removing the onclick attribute, and instead doing the following from within your JavaScript.\n\ndocument.getElementById('anim-link').onclick = playAnimation;\n\nIt\u2019s all in the timing\n\nOf course, it\u2019s never quite that easy. To be able to attach that onclick, the element you\u2019re targeting has to exist in the page, and the page has to have finished loading for the DOM to be available. This is where the onload event is handy, as it fires once everything has finished loading. Common practise is to have a function called something like init() (short for initialise) that sets up all these event handlers as soon as the page is ready.\n\nBack in the day we would have used the onload attibute on the <body> element to do this, but of course what we really want is:\n\nwindow.onload = init;\n\nAs an interesting side note, we\u2019re using init here rather than init() so that the function is assigned to the event. If we used the parentheses, the init function would have been run at that moment, and the result of running the function (rather than the function itself) would be assigned to the event. Subtle, but important.\n\nAs is becoming apparent, nothing is ever simple, and we can\u2019t just go around assigning our initialisation function to window.onload. What if we\u2019re using other scripts in the page that might also want to listen out for that event? Whichever script got there last would overwrite everything that came before it. To manage this, we need a script that checks for any existing event handlers, and adds the new handler to it. Most of the JavaScript libraries have their own systems for doing this. If you\u2019re not using a library, Simon Willison has a good stand-alone example\n\nfunction addLoadEvent(func) {\n\tvar oldonload = window.onload;\n\tif (typeof window.onload != 'function') {\n\t\twindow.onload = func;\n\t} else {\n\t\twindow.onload = function() {\n\t\t\tif (oldonload) {\n\t\t\t\toldonload();\n\t\t\t}\n\t\t\tfunc();\n\t\t}\n\t}\n}\n\nObviously this is just a toe in the events model\u2019s complex waters. Some good further reading is PPK\u2019s Introduction to Events.\n\nCarving out your own space\n\nAnother problem that rears its ugly head when combining multiple scripts on a single page is that of making sure that the scripts don\u2019t conflict. One big part of that is ensuring that no two scripts are trying to create functions or variables with the same names. Reusing a name in JavaScript just over-writes whatever was there before it.\n\nWhen you create a function in JavaScript, you\u2019ll be familiar with doing something like this.\n\nfunction foo() {\n\t... goodness ...\n}\n\nThis is actually just creating a variable called foo and assigning a function to it. It\u2019s essentially the same as the following.\n\nvar foo = function() {\n\t... goodness ...\n}\n\nThis name foo is by default created in what\u2019s known as the \u2018global namespace\u2019 \u2013 the general pool of variables within the page. You can quickly see that if two scripts use foo as a name, they will conflict because they\u2019re both creating those variables in the global namespace.\n\nA good solution to this problem is to add just one name into the global namespace, make that one item either a function or an object, and then add everything else you need inside that. This takes advantage of JavaScript\u2019s variable scoping to contain you mess and stop it interfering with anyone else.\n\nCreating An Object\n\nSay I was wanting to write a bunch of functions specifically for using on a site called \u2018Foo Online\u2019. I\u2019d want to create my own object with a name I think is likely to be unique to me.\n\nvar FOOONLINE = {};\n\nWe can then start assigning functions are variables to it like so:\n\nFOOONLINE.message = 'Merry Christmas!';\nFOOONLINE.showMessage = function() {\n\talert(this.message);\n};\n\nCalling FOOONLINE.showMessage() in this example would alert out our seasonal greeting. The exact same thing could also be expressed in the following way, using the object literal syntax.\n\nvar FOOONLINE = {\n\tmessage: 'Merry Christmas!',\n\tshowMessage: function() {\n\t\talert(this.message);\n\t}\n};\n\nCreating A Function to Create An Object\n\nWe can extend this idea bit further by using a function that we run in place to return an object. The end result is the same, but this time we can use closures to give us something like private methods and properties of our object.\n\nvar FOOONLINE = function(){\n\tvar message = 'Merry Christmas!';\n\treturn {\n\t\tshowMessage: function(){\n\t\t\talert(message);\n\t\t}\n\t}\n}();\n\nThere are two important things to note here. The first is the parentheses at the end of line 10. Just as we saw earlier, this runs the function in place and causes its result to be assigned. In this case the result of our function is the object that is returned at line 4.\n\nThe second important thing to note is the use of the var keyword on line 2. This ensures that the message variable is created inside the scope of the function and not in the global namespace. Because of the way closure works (which if you\u2019re not familiar with, just suspend your disbelief for a moment) that message variable is visible to everything inside the function but not outside. Trying to read FOOONLINE.message from the page would return undefined.\n\nThis is useful for simulating the concept of private class methods and properties that exist in other programming languages. I like to take the approach of making everything private unless I know it\u2019s going to be needed from outside, as it makes the interface into your code a lot clearer for someone else to read. \n\nAll Change, Please\n\nSo that was just a whistle-stop tour of a couple of the bigger changes that can help to make your scripts better page citizens. I hope it makes useful Sunday reading, but obviously this is only the tip of the iceberg when it comes to designing modular, reusable code.\n\nFor some, this is all familiar ground already. If that\u2019s the case, I encourage you to perhaps submit a comment with any useful resources you\u2019ve found that might help others get up to speed. Ultimately it\u2019s in all of our interests to make sure that all our JavaScript interoperates well \u2013 share your tips.", "2006", "Drew McLellan", "drewmclellan", "2006-12-10T00:00:00+00:00", "https://24ways.org/2006/writing-responsible-javascript/", "code"], [132, "Tasty Text Trimmer", "In most cases, when designing a user interface it\u2019s best to make a decision about how data is best displayed and stick with it. Failing to make a decision ultimately leads to too many user options, which in turn can be taxing on the poor old user. \n\nUnder some circumstances, however, it\u2019s good to give the user freedom in customising their workspace. One good example of this is the \u2018Article Length\u2019 tool in Apple\u2019s Safari RSS reader. Sliding a slider left of right dynamically changes the length of each article shown. It\u2019s that kind of awesomey magic stuff that\u2019s enough to keep you from sleeping. Let\u2019s build one.\n\nThe Setup\n\nLet\u2019s take a page that has lots of long text items, a bit like a news page or like Safari\u2019s RSS items view. If we were to attach a class name to each element we wanted to resize, that would give us something to hook onto from the JavaScript. \n\nExample 1: The basic page.\n\nAs you can see, I\u2019ve wrapped my items in a DIV and added a class name of chunk to them. It\u2019s these chunks that we\u2019ll be finding with the JavaScript. Speaking of which \u2026\n\nOur Core Functions\n\nThere are two main tasks that need performing in our script. The first is to find the chunks we\u2019re going to be resizing and store their original contents away somewhere safe. We\u2019ll need this so that if we trim the text down we\u2019ll know what it was if the user decides they want it back again. We\u2019ll call this loadChunks. \n\nvar loadChunks = function(){\n\tvar everything = document.getElementsByTagName('*');\n\tvar i, l;\n\tchunks\t= [];\n\tfor (i=0, l=everything.length; i<l; i++){\n\t\tif (everything[i].className.indexOf(chunkClass) > -1){\n\t\t\tchunks.push({\n\t\t\t\tref: everything[i],\n\t\t\t\toriginal: everything[i].innerHTML\n\t\t\t});\n\t\t}\n\t}\n};\n\nThe variable chunks is stored outside of this function so that we can access it from our next core function, which is doTrim.\n\nvar doTrim = function(interval) {\n\tif (!chunks) loadChunks();\n\tvar i, l;\n\tfor (i=0, l=chunks.length; i<l; i++){\n\t\tvar a = chunks[i].original.split(' ');\n\t\ta = a.slice(0, interval);\n\t\tchunks[i].ref.innerHTML\t= a.join(' ');\n\t}\n};\n\nThe first thing that needs to be done is to call loadChunks if the chunks variable isn\u2019t set. This should only happen the first time doTrim is called, as from that point the chunks will be loaded.\n\nThen all we do is loop through the chunks and trim them. The trimming itself (lines 6-8) is very simple. We split the text into an array of words (line 6), then select only a portion from the beginning of the array up until the number we want (line 7). Finally the words are glued back together (line 8).\n\nIn essense, that\u2019s it, but it leaves us needing to know how to get the number into this function in the first place, and how that number is generated by the user. Let\u2019s look at the latter case first.\n\nThe YUI Slider Widget\n\nThere are lots of JavaScript libraries available at the moment. A fair few of those are really good. I use the Yahoo! User Interface Library professionally, but have only recently played with their pre-build slider widget. Turns out, it\u2019s pretty good and perfect for this task. \n\nOnce you have the library files linked in (check the docs linked above) it\u2019s fairly straightforward to create yourself a slider.\n\nslider = YAHOO.widget.Slider.getHorizSlider(\"sliderbg\", \"sliderthumb\", 0, 100, 5); \nslider.setValue(50);\nslider.subscribe(\"change\", doTrim);\n\nAll that\u2019s needed then is some CSS to make the slider look like a slider, and of course a few bits of HTML. We\u2019ll see those later.\n\nSee It Working!\n\nRather than spell out all the nuts and bolts of implementing this fairly simple script, let\u2019s just look at in it action and then pick on some interesting bits I\u2019ve added.\n\nExample 2: Try the Tasty Text Trimmer.\n\nAt the top of the JavaScript file I\u2019ve added a small number of settings.\n\nvar chunkClass\t= 'chunk';\nvar minValue\t= 10;\nvar maxValue\t= 100;\nvar multiplier\t= 5;\n\nObvious candidates for configuration are the class name used to find the chunks, and also the some minimum and maximum values. The minValue is the fewest number of words we wish to display when the slider is all the way down. The maxValue is the length of the slider, in this case 100.\n\nMoving the slider makes a call to our doTrim function with the current value of the slider. For a slider 100 pixels long, this is going to be in the range of 0-100. That might be okay for some things, but for longer items of text you\u2019ll want to allow for displaying more than 100 words. I\u2019ve accounted for this by adding in a multiplier \u2013 in my code I\u2019m multiplying the value by 5, so a slider value of 50 shows 250 words. You\u2019ll probably want to tailor the multiplier to the type of content you\u2019re using.\n\nKeeping it Accessible \n\nThis effect isn\u2019t something we can really achieve without JavaScript, but even so we must make sure that this functionality has no adverse impact on the page when JavaScript isn\u2019t available. This is achieved by adding the slider markup to the page from within the insertSliderHTML function.\n\nvar insertSliderHTML = function(){\n\tvar s = '<a id=\"slider-less\" href=\"#less\"><img src=\"icon_min.gif\" width=\"10\" height=\"10\" alt=\"Less text\" class=\"first\" /></a>';\n\ts +=' <div id=\"sliderbg\"><div id=\"sliderthumb\"><img src=\"sliderthumbimg.gif\" /></div></div>';\n\ts +=' <a id=\"slider-more\" href=\"#more\"><img src=\"icon_max.gif\" width=\"10\" height=\"10\" alt=\"More text\" /></a>';\n\tdocument.getElementById('slider').innerHTML = s;\n}\n\nThe other important factor to consider is that a slider can be tricky to use unless you have good eyesight and pretty well controlled motor skills. Therefore we should provide a method of changing the value by the keyboard.\n\nI\u2019ve done this by making the icons at either end of the slider links so they can be tabbed to. Clicking on either icon fires the appropriate JavaScript function to show more or less of the text.\n\nIn Conclusion\n\nThe upshot of all this is that without JavaScript the page just shows all the text as it normally would. With JavaScript we have a slider for trimming the text excepts that can be controlled with the mouse or with a keyboard.\n\nIf you\u2019re like me and have just scrolled to the bottom to find the working demo, here it is again:\n\nTry the Tasty Text Trimmer\n\nTrimmer for Christmas? Don\u2019t say I never give you anything!", "2006", "Drew McLellan", "drewmclellan", "2006-12-01T00:00:00+00:00", "https://24ways.org/2006/tasty-text-trimmer/", "code"]], "truncated": false, "table_rows_count": 336, "filtered_table_rows_count": 2, "expanded_columns": [], "expandable_columns": [], "columns": ["rowid", "title", "contents", "year", "author", "author_slug", "published", "url", "topic"], "primary_keys": [], "units": {}, "query": {"sql": "select rowid, * from articles where \"author_slug\" = :p0 and \"topic\" = :p1 and \"year\" = :p2 order by rowid limit 101", "params": {"p0": "drewmclellan", "p1": "code", "p2": "2006"}}, "facet_results": {}, "suggested_facets": [], "next": null, "next_url": null, "query_ms": 14.058351516723633}