David Janes' Code Weblog

December 28, 2010

Display only one jPicker at a time

code fragments,javascript,jquery · David Janes · 9:26 am ·

I’ve been playing with jQuery (in general) and jPicker (in particular) over the last few days. I’m using jPicker because it’s not only a color picker but it also supports alpha-levels.

One – major – issue I’ve had is that jPicker doesn’t make it very easy to display only one control at a time, making the screen a bit of a visual mess when multiple color fields are being used.

Here’s how I fixed this.

$(document).ready(function() {
    $('body').click(function(evt) {
        if ($('div.jPicker.Container:visible').length > 0) {
            if ($(evt.target).parents('span.jPicker').length > 0) {
                $('div.jPicker.Container').each(function() {
                    if ($(this).css('z-index') == '10') {
                        $(this).hide('fast');
                    }
                });
            } else if ($(evt.target).parents('div.jPicker.Container').length == 0) {
                $('div.jPicker.Container').hide('fast');
            }
        }
    });
});

Notes:

  • this will dismiss the current jPicker if you click outside of one
  • the first if makes sure there’s something to do first
  • the second and third ifs take care of the case where the user clicks on the control to popup a jPicker. This takes advantage of the fact that the current jPicker is shown at z-index = 20 (which makes me wonder if we could do a lot of this with just a CSS selector for z-index = 10)
  • the final if takes care of the case where we’ve clicked outside of all jPicker controls

November 29, 2010

Good-bye XML, SOAP & SOA

ideas,javascript,xml · David Janes · 7:17 am ·

In my callow youth, I remember being so excited about XML. Ah, how wrong I was. Two articles of interest:

The End Of The Road For Web Services

Web services as a strategy was fundamentally flawed in my view because it was so un-web. It took an idea that hardly worked on an Intranet – remote manipulation of tightly-specified objects – and tried to make it work on the Internet. It led to software applications that by default were complex, brittle and heavy. Although I know many brilliant software engineers who worked unexpected miracles with Web Services, implementation by the common corporate programmer was stodgy in every case I heard about. In the end Web Services became an intranet tool for most uses, rendering the “W” incorrect even if WS* will be with enterprise developers for years to come as a kind of architectural COBOL.

and

XML vs the Web

It’s “Yay”, because for important use cases JSON is dramatically better than XML. In particular, JSON shines as a programming language-independent representation of typical programming language data structures. This is an incredibly important use case and it would be hard to overstate how appallingly bad XML is for this. The fundamental problem is the mismatch between programming language data structures and the XML element/attribute data model of elements. This leaves the developer with three choices, all unappetising

[...]

So what’s the way forward? I think the Web community has spoken, and it’s clear that what it wants is HTML5, JavaScript and JSON. XML isn’t going away but I see it being less and less a Web technology; it won’t be something that you send over the wire on the public Web, but just one of many technologies that are used on the server to manage and generate what you do send over the wire.

In the short-term, I think the challenge is how to make HTML5 play more nicely with XML. In the longer term, I think the challenge is how to use our collective experience from building the XML stack to create technologies that work natively with HTML, JSON and JavaScript, and that bring to the broader Web developer community some of the good aspects of the modern XML development experience

Having in recent memory been involved in a SOA deathmarch project (still in the process of tumbling down to inevitable failure), and dealing daily with the issues of transferring data using XML, I can firmly say: good riddance.

What do we do now? We do JSON. Why do we do JSON? Because the JSON object model (and the implicit RESTful JSON API model) is almost an exact match for how programmers – especially those of languages such as Python, Ruby & JavaScript – think about data .

December 25, 2009

Make INPUT fields select dates using the YUI Calendar Control

code fragments,javascript,tips,yui · David Janes · 3:57 pm ·

Here’s a lengthy Javascript code segment that can be dropped into any of your existing forms that provide for a date selection range. It has the following functionality:

  • clicking a date field pops up a YUI Calendar control to change the date
  • the date field is made read only by this code
  • pressing ESC while a Calendar is displaying dismisses it
  • pressing DEL while a Calendar is displaying clears the input field
  • there is an Input field for the start date and an Input field for the end date
  • you cannot make the end date before the start date, and you cannot make the start date after the end date
  • that the dates are optional
  • dates are displayed in the standard ISO YYYY-MM-DD format

This code sample demonstrates:

  • the YUI Calendar control, including
    • setting the date in the control
    • getting the date from the control (after selection)
    • dynamically displaying and hiding the control
    • manipulating ISO dates into the format that YUI requires
    • setting min and max dates on the fly – specifically, this shows you how to manipulate YUI “config” parameters which the documentation implies are readonly (look for functions in source code named like configMinDate)
    • simple YUI animations (to show that a field value has been changed)
    • detecting keystrokes (DEL and ESC) using YUI
    • adding functionality using Javascript, after the DOM loads

    This assumes:

    • you have an Input field for the start date with DOM id="id_event_start"
    • you have an Input field for the end date with DOM id="id_event_end"
    • that the Form (or a parent element of the Form, up to Body) has DOM class="yui-skin-sam"

    Add the following Script inclusions to your HTML (note: not all of these are probably needed, and there’s more efficient ways to include YUI JS, especially for production deployments):

    <script type="text/javascript"
     src="http://yui.yahooapis.com/2.8.0r4/build/json/json-min.js"></script>
    <script type="text/javascript"
     src="http://yui.yahooapis.com/2.8.0r4/build/event/event-min.js"></script>
    <script type="text/javascript"
     src="http://yui.yahooapis.com/2.8.0r4/build/connection/connection-min.js"></script>
    <script type="text/javascript"
     src="http://yui.yahooapis.com/2.8.0r4/build/dom/dom-min.js"></script>
    <script type="text/javascript"
     src="http://yui.yahooapis.com/2.8.0r4/build/element/element-min.js"></script>
    <script type="text/javascript"
     src="http://yui.yahooapis.com/2.8.0r4/build/button/button-min.js"></script>
    <script type="text/javascript"
     src="http://yui.yahooapis.com/2.8.0r4/build/dragdrop/dragdrop-min.js"></script>
    <script type="text/javascript"
     src="http://yui.yahooapis.com/2.8.0r4/build/container/container-min.js"></script>
    <script type="text/javascript"
     src="http://yui.yahooapis.com/2.8.0r4/build/yuiloader/yuiloader-min.js"></script>
    <script type="text/javascript"
     src="http://yui.yahooapis.com/2.8.0r4/build/container/container_core-min.js"></script>
    <script type="text/javascript"
     src="http://yui.yahooapis.com/2.8.0r4/build/calendar/calendar-min.js"></script>
    <script type="text/javascript"
     src="http://yui.yahooapis.com/2.8.0r4/build/animation/animation-min.js"></script>
    

    Add the following CSS inclusions to your HTML:

    <link rel="stylesheet" type="text/css"
     href="http://yui.yahooapis.com/2.8.0r4/build/button/assets/skins/sam/button.css" />
    <link rel="stylesheet" type="text/css"
     href="http://yui.yahooapis.com/2.8.0r4/build/container/assets/skins/sam/container.css" />
    <link rel="stylesheet" type="text/css"
     href="http://yui.yahooapis.com/2.8.0r4/build/calendar/assets/skins/sam/calendar.css" />
    

    Add the following CSS to your HTML:

    <style type="text/css">
    
    #id_calendar {
     position: absolute;
     z-index: 15;
    }
    .yui-skin-sam .yui-panel .bd, .yui-skin-sam .yui-panel .ft {
     background-color:#FFFFFF;
    }
    </style>
    

    Add the following HTML fragment:

    <div id="id_calendar_wrapper">
     <div id="id_calendar"></div>
    </div>
    

    And finally, here’s the JS that makes it all work

    <script type="text/javascript">
    calendar_js = {
     c : null,
     start_e : null,
     end_e : null,
     current_e : 0,
     supress : 0,
    
     create : function() {
     calendar_js.start_e = YAHOO.util.Dom.get("id_event_start");
     calendar_js.end_e = YAHOO.util.Dom.get("id_event_end");
    
     YAHOO.util.Event.addListener(calendar_js.start_e, "click", calendar_js.onclick, this);
     YAHOO.util.Event.addListener(calendar_js.end_e, "click", calendar_js.onclick, this);
    
     YAHOO.util.Dom.get(calendar_js.start_e).readOnly = true;
     YAHOO.util.Dom.get(calendar_js.end_e).readOnly = true;
    
     (new YAHOO.util.KeyListener(document, { keys:27 }, { fn:calendar_js.onesc })).enable();
     (new YAHOO.util.KeyListener(document, { keys:8 }, { fn:calendar_js.ondel })).enable();
     },
    
     onesc : function() {
     calendar_js.current_e = null;
     if (calendar_js.c) {
     calendar_js.c.hide();
     }
    
     },
    
     ondel : function() {
     if (calendar_js.current_e) {
     calendar_js.current_e.value = "";
     calendar_js.current_e = null;
     }
     if (calendar_js.c) {
     calendar_js.c.hide();
     }
    
     },
    
     toydate : function(d) {
     if (!d) {
     return null;
     }
     if (d.value) {
     d = d.value;
     }
     if (d && d.length) {
     d = d.replace(/(\d\d\d\d)-(\d\d)-(\d\d)/, "$2/$3/$1");
     if (d.indexOf('/') == 2) {
     return d;
     }
     }
     return null;
     },
    
     onclick : function(evt, obj) {
     var e_e = YAHOO.util.Event.getTarget(evt);
    
     if (calendar_js.c == null) {
     calendar_js.c = new YAHOO.widget.Calendar(null, "id_calendar");
     calendar_js.c.render();
    
     calendar_js.c.selectEvent.subscribe(calendar_js.ondate, calendar_js.c, true);
     }
    
     var c_e = YAHOO.util.Dom.get("id_calendar");
     if (calendar_js.current_e == e_e) {
     calendar_js.current_e = null;
     calendar_js.c.hide();
     } else {
     YAHOO.util.Dom.setAttribute(c_e, "display", "block");
     calendar_js.current_e = e_e;
    
     var region = YAHOO.util.Region.getRegion(e_e);
    
     calendar_js.c.show();
    
     if (e_e.value.length) {
     var d = calendar_js.toydate(e_e);
     if (d) {
     calendar_js.supress = 1;
     calendar_js.c.select(d);
     }
     }
    
     if (e_e == calendar_js.start_e) {
     var d = calendar_js.toydate(calendar_js.end_e);
     if (d) {
     calendar_js.c.configMaxDate(null, [ d ], null);
     calendar_js.c.configMinDate(null, [ "01/01/1970" ], null);
     }
     } else {
     var d = calendar_js.toydate(calendar_js.start_e);
     if (d) {
     calendar_js.c.configMinDate(null, [ d ], null);
     calendar_js.c.configMaxDate(null, [ "01/01/2200" ], null);
     }
     }
    
     calendar_js.c.render();
     YAHOO.util.Dom.setXY(c_e, [ region.right + 2, region.top ]);
     }
     },
    
     ondate : function(type, args, obj) {
     if (calendar_js.supress) {
     calendar_js.supress = 0;
     return;
     }
    
     var date = this.toDate(args[0][0]);
    
     var year = "" + date.getFullYear();
     var month = "" + ( 1 + date.getMonth() );
     while (month.length < 2) {
     month = "0" + month;
     }
     var day = "" + date.getDate();
     while (day.length < 2) {
     day = "0" + day;
     }
    
     var animate = new YAHOO.util.ColorAnim(calendar_js.current_e,
     {backgroundColor: { from: '#ffff99', to: '#FFFFFF' } }
     );
     animate.duration = 0.75;
     animate.method = YAHOO.util.Easing.easeOut;
     animate.animate();
    
     calendar_js.current_e.value = year + "-" + month + "-" + day;
     calendar_js.c.hide();
     calendar_js.current_e = null;
     },
    
     end : 0
    };
    YAHOO.util.Event.onDOMReady(calendar_js.oninit);
    </script>
    

    Notes:

    • no apologies for verboseness – I write code so I can understand it in 24 months time
    • my original code is a lot more “tabby” – I flattened to a single space so they’d fit in the space constraints here
    • the code should be fairly self explanatory if you step through it – the hard stuff is probably YUI weirdness and you can probably just accept that “that’s just the way it is”

Powered by WordPress

Switch to our mobile site