Self contained system for color transition

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Richard A. DeVenezia

    Self contained system for color transition

    I hope this is the end of my present 'discovery' phase. I've learned alot
    about JavaScript in a short time and my head hurts. The following is what
    came out of all my questions and all the excellent answers (thanks!). It
    will be the basis of a slightly more complicated function for rendering a
    two-level navigation bar ( Don't have time to get into design of a
    multi-styletype renderer for n-level hierarchies. )

    This is a single function that will perform color transitioning.
    If Foo is an unavailable identifier, change it to whatever you want, nothing
    else needs to be changed (except the invocation of it)

    ----
    function Foo (argument) {
    // Simpleton singleton
    var callee = arguments.calle e

    if (callee.singlet on != undefined)
    return callee.singleto n

    if (this == window)
    return new callee ( argument )

    callee.singleto n = this

    var myName = callee.toString ().replace (/\n/g, ' ').match(
    /function\s(.*?) (\s|\()/ ) [1]
    //alert ('my name is ' + myName)

    installClassMet hods ()

    doBunchOfStuff( )
    return

    function doBunchOfStuff () {
    var id = '_' + Math.random(0). toString().subs tring(2)
    document.write ('<TABLE ID="' + id + '"><TR><TD></TD></TR></TABLE>')
    var table = document.getEle mentById (id)
    table.deleteRow (0)
    var row = table.insertRow (table.rows.len gth)
    var cell = row.insertCell ( row.cells.lengt h )

    cell.innerHTML = '<B>Provided</B> by <I>convenienc e</I> of innerHTML'

    cell.style.bord erStyle = 'solid'
    cell.style.bord erColor = 'Black'
    cell.style.bord erWidth = '1px'

    cell.onmouseove r = function ( E ) { callee.over (this) }
    cell.onmouseout = function ( E ) { callee.out (this) }
    }

    //--------------------------------------------------------------
    function installClassMet hods () {
    //------------------------------------------------------------
    callee.over = function (td) {
    td.style.backgr oundColor = 'black'
    }
    callee.out = function (td) {
    td.transition = new callee.transiti on (td)
    td.transition.d oStart()
    }
    callee.transiti on = function (td) {
    this.td = td
    this.step = 0
    this.interval = 10
    }
    callee.transiti on.prototype.do Start = function () {
    thisObj = this
    thisObj.doStep( )
    this.timerId = setInterval ( function () { thisObj.doStep( ) },
    this.interval )
    }
    callee.transiti on.prototype.do Step = function () {
    this.step += 4
    if (this.step > 255) this.step = 255
    this.td.style.b ackgroundColor =
    'rgb('+this.ste p+','+this.step +','+this.step+ ')'
    if (this.step == 255) {
    clearTimeout (this.timerId)
    this.td.transit ion = null
    }
    }
    }
    } // end of Foo

    Foo('Hi')

    -----
    Richard A. DeVenezia



  • Richard Cornford

    #2
    Re: Self contained system for color transition

    "Richard A. DeVenezia" <radevenz@ix.ne tcom.com> wrote in message
    news:bjkmbc$jpe um$1@ID-168040.news.uni-berlin.de...
    <snip>[color=blue]
    > function Foo (argument) {
    > // Simpleton singleton
    > var callee = arguments.calle e
    >
    > if (callee.singlet on != undefined)
    > return callee.singleto n
    >
    > if (this == window)
    > return new callee ( argument )
    >
    > callee.singleto n = this
    >
    > var myName = callee.toString ().replace (/\n/g, ' ').
    > match( /function\s(.*?) (\s|\()/ ) [1]
    > //alert ('my name is ' + myName)
    >
    > installClassMet hods ()
    >
    > doBunchOfStuff( )[/color]

    As - doBunchOfStuff - is and inner function of this function and is only
    called once does it need to be an inner function at all?
    [color=blue]
    > return
    >
    > function doBunchOfStuff () {
    > var id = '_' + Math.random(0). toString().subs tring(2)
    > document.write ('<TABLE ID="' + id +[/color]
    '"><TR><TD></TD></TR></TABLE>')[color=blue]
    > var table = document.getEle mentById (id)[/color]

    document.getEle mentById - may be widely implemented but it is not
    universal. It is safer to test for the existence of this type of
    function before using them to avoid error reports and allow for
    controlled fall-back and clean degradation.
    [color=blue]
    > table.deleteRow (0)[/color]

    deleteRow - may be HTML DOM specified and widely implemented but it is
    not universal (even in browsers that are otherwise quite good DOM
    implementations ). You should test that method exists before using it to
    avoid error reports and allow for controlled fall-back and clean
    degradation. One fall-back option might be the DOM core - removeChild -
    function called on the implied TBODY element.
    [color=blue]
    > var row = table.insertRow (table.rows.len gth)
    > var cell = row.insertCell ( row.cells.lengt h )[/color]

    Similarly insertRow and insertCell.
    [color=blue]
    > cell.innerHTML = '<B>Provided</B> by <I>convenienc e</I> of[/color]
    innerHTML'

    The test for innerHTML support is - if(typeof cell.innerHTML ==
    'string') - though it may be implemented as read only (eg. Web Browser
    2.0 on Palm OS as I recall (I don't have its docs to hand)). DOM node
    insertion methods are more widely supported and, if implemented, will do
    the job, so they could be the primary method with a fall-back to
    innerHTML or the other way around.
    [color=blue]
    > cell.style.bord erStyle = 'solid'
    > cell.style.bord erColor = 'Black'
    > cell.style.bord erWidth = '1px'
    >
    > cell.onmouseove r = function ( E ) { callee.over (this) }
    > cell.onmouseout = function ( E ) { callee.out (this) }[/color]

    IE browsers are unable to garbage collect DOM elements and JavaScript
    objects that form circular references with one another. Forming such
    circular references produces a memory leak that persists until the
    browser is shut down. Assigning these inner functions to properties of
    the TD means that the TD has a reference to the functions, the functions
    hold a reference to the closures that assigning the functions produces
    and that closure has a reference to the TD held in the - cell -
    property. A circular reference. At this point in the code this problem
    can be averted by actively clearing the references to the DOM nodes from
    the cell, row and table local variables (eg. cell = null; etc. at the
    end of the function).
    [color=blue]
    > }
    >
    > //--------------------------------------------------------------
    > function installClassMet hods () {
    > //------------------------------------------------------------
    > callee.over = function (td) {
    > td.style.backgr oundColor = 'black'
    > }
    > callee.out = function (td) {
    > td.transition = new callee.transiti on (td)
    > td.transition.d oStart()
    > }
    > callee.transiti on = function (td) {
    > this.td = td[/color]
    <snip>

    That is another circular reference. The - new callee.transiti on(td) -
    object is assigned as an expando property on the TD so the TD refers to
    it, and the object holds a reference to the TD which it is a property
    of. This circular reference is harder to break and would require the
    expando property to be cleared. I notice that you are doing that later
    on so this may not be a real problem (unless the page is unloaded before
    the end of the sequence), but I don't see the need for the expando at
    all. What would be wrong with:-

    callee.out = fuction(td){
    new callee.transiti n(td).doStart() ;
    };

    - and drop the - this.td.transit ion = null - line from the doStep
    function.

    However, the event handling functions do not need to be inner functions
    that call the public static functions of the constructor. You could just
    assign the equivalent functions directly to the event handlers:-

    cell.onmouseove r = function(E){
    this.style.back groundColor = 'black'
    };
    cell.onmouseout = function(E){
    new callee.transiti on(this).doStar t()
    };

    - Obviously the references to the TD have changed from a passed
    reference to the use of he - this - keyword (and I have removed the
    expando) but otherwise the functions do the same task.

    Also, although - new callee.transtio n(this) - will work I don't think
    that you need the transition constructor to be a property of the -
    callee - constructor at all. If - transition - was an inner function
    declaration:-

    function Transition(td){
    this.td = td;
    this.step = 0;
    this.interval = 10;
    }

    (or function expression - var Transition = function(td){ ...} -)

    It would be possible to assign functions to its prototype (eg):-

    Transition.prot otype.doStart = function (){
    thisObj = this;
    thisObj.doStep( );
    this.timerId =
    setInterval ( function () { thisObj.doStep( ) },this.interval );
    };

    - and use it as a constructor - new Transition(this ); - wherever its
    identifier was within the scope, ie. from within the "Foo" constructor
    and any of its inner functions (such as the one assigned to
    cell.onmouseout (the function that actually constructs the Transition
    objects)).

    Given your desire to keep the code independent of the identifier used
    for the constructor, my pattern for this object would be:-

    var Foo = (function(){
    var singleton = null;
    function Transition(){
    . . .
    }
    Transition.prot otype.doStart = function (){
    . . .
    };
    Transition.prot otype.doStep = function (){
    . . .
    };
    return (function(argum ent){ //this is the singleton's constructor.
    if (singleton)retu rn singleton;
    if (this == window){
    return new arguments.calle e( argument );
    }
    singleton = this
    . . .
    cell.onmouseove r = function(E){
    this.style.back groundColor = 'black'
    };
    cell.onmouseout = function(E){
    new Transition(this ).doStart()
    };
    . . .
    cell = null;
    . . .
    });
    })(); //inline function expression execution
    //assigning the singleton constructor to
    //any identifier required.

    - and now "Foo" has no public static properties at all.

    Richard.


    Comment

    • Richard A. DeVenezia

      #3
      Re: Self contained system for color transition

      "Richard Cornford" <richard@litote s.demon.co.uk> wrote in message
      news:bjm2pr$qnj $1@hercules.bti nternet.com...[color=blue]
      > "Richard A. DeVenezia" <radevenz@ix.ne tcom.com> wrote in message
      > news:bjkmbc$jpe um$1@ID-168040.news.uni-berlin.de...[/color]
      [color=blue]
      > Given your desire to keep the code independent of the identifier used
      > for the constructor, my pattern for this object would be:-
      >
      > var Foo = (function(){
      > var singleton = null;
      > function Transition(){
      > . . .
      > }
      > Transition.prot otype.doStart = function (){
      > . . .
      > };
      > Transition.prot otype.doStep = function (){
      > . . .
      > };
      > return (function(argum ent){ //this is the singleton's constructor.
      > if (singleton)retu rn singleton;
      > if (this == window){
      > return new arguments.calle e( argument );
      > }
      > singleton = this
      > . . .
      > cell.onmouseove r = function(E){
      > this.style.back groundColor = 'black'
      > };
      > cell.onmouseout = function(E){
      > new Transition(this ).doStart()
      > };
      > . . .
      > cell = null;
      > . . .
      > });
      > })(); //inline function expression execution
      > //assigning the singleton constructor to
      > //any identifier required.[/color]

      Thanks for the pattern. I think I've seen it before, but this is more
      digestable than those times.

      Would it matter if the prototype assignment came after the return ? I'm
      thinking it's yes, although the Transition function probably could be after
      (since its declared as a function and not a var assigned to an anonymous
      function)
      [color=blue][color=green]
      > >
      > > doBunchOfStuff( )[/color]
      >
      > As - doBunchOfStuff - is and inner function of this function and is only
      > called once does it need to be an inner function at all?
      >[/color]

      Well, it's about 470 lines of code that examines, parses and reports errors
      regarding FooData that is passed in.
      The nesting is gone (I used to rely of inheriting some vars from the parent
      functions, but now I have ~10 top-level function vars.
      They maintain counts and states needed at various multiple points.
      The parsing looks like
      bunch of lines
      loop1
      bunch of lines
      loop2
      bunch of lines
      end2
      end1
      where ever I had bunch of lines in a loop, I moved them out to a function
      which is then called from inside a now 'tight loop'
      [color=blue][color=green]
      > >
      > > per pretty widely implemented functions and clean degradation
      > >[/color][/color]

      Most browsers I get are ie. I'm willing to leave a few souls in the dark,
      but will test pages versus latest ie,moz & opera.
      [color=blue]
      > DOM node
      > insertion methods are more widely supported and, if implemented, will do
      > the job, so they could be the primary method with a fall-back to
      > innerHTML or the other way around.
      >[/color]

      DOM... but I have such little hair left to pull out.
      I think before I travel down the 'code that generates correctly nearly
      universally on the client side' road, I would investigate server side
      generation.
      [color=blue]
      > property. A circular reference. At this point in the code this problem
      > can be averted by actively clearing the references to the DOM nodes from
      > the cell, row and table local variables (eg. cell = null; etc. at the
      > end of the function).[/color]

      Excellent advice... thanks.
      [color=blue]
      >
      > all. What would be wrong with:-
      >
      > callee.out = fuction(td){
      > new callee.transiti n(td).doStart() ;
      > };
      >
      > - and drop the - this.td.transit ion = null - line from the doStep
      > function.
      >
      > However, the event handling functions do not need to be inner functions
      > that call the public static functions of the constructor. You could just
      > assign the equivalent functions directly to the event handlers:-
      >
      > cell.onmouseove r = function(E){
      > this.style.back groundColor = 'black'
      > };
      > cell.onmouseout = function(E){
      > new callee.transiti on(this).doStar t()
      > };[/color]

      I would love to not need to attached transition to the element, however in
      the 'bigger' version, I have to stop an elements transition if the mouse
      moves over the element again. I've got to store the timerId somewhere so
      that I can stop prematurely.
      [color=blue]
      >
      > Also, although - new callee.transtio n(this) - will work I don't think
      > that you need the transition constructor to be a property of the -
      > callee - constructor at all. If - transition - was an inner function
      > declaration:-
      >
      > function Transition(td){
      > this.td = td;
      > this.step = 0;
      > this.interval = 10;
      > }
      >[/color]

      Good point, however I find out that Mozilla doesn't do timered stuff with
      functions, just strings (grrrr). So if I want mozilla to transition I would
      need at least on Foo constructor function property for dispatching the event
      handling.
      [color=blue]
      >
      > Richard.
      >[/color]



      --
      Richard A. DeVenezia


      Comment

      • Richard Cornford

        #4
        Re: Self contained system for color transition

        "Richard A. DeVenezia" <radevenz@ix.ne tcom.com> wrote in message
        news:bjmrfi$l6a to$1@ID-168040.news.uni-berlin.de...[color=blue]
        > "Richard Cornford" <richard@litote s.demon.co.uk> wrote in message
        > news:bjm2pr$qnj $1@hercules.bti nternet.com...[/color]
        <snip>[color=blue]
        >Would it matter if the prototype assignment came after the
        >return ? I'm thinking it's yes, although the Transition function
        >probably could be after (since its declared as a function and
        >not a var assigned to an anonymous function)[/color]

        Yes it matters, function expressions (as distinct from function
        declarations) are evaluated in source doe order so if they follow the
        return statement then they will never be evaluated. See the ECMA
        specification for the difference between function declarations and
        expressions, and the section on the creation of the "variable" object in
        the execution context.
        [color=blue][color=green][color=darkred]
        >>> doBunchOfStuff( )[/color]
        >>
        >>As - doBunchOfStuff - is and inner function of this function and
        >>is only called once does it need to be an inner function at all?[/color]
        >
        >Well, it's about 470 lines of code that examines, parses and
        >reports errors regarding FooData that is passed in.[/color]

        OK, familiarise yourself with the distinction between function
        expressions and declarations (and the creation of the "variable"
        object), as you may find that you are needlessly repeatedly creating a
        very large function object each time the singleton constructor is called
        (as - doBunchOfStuff - is an inner function declaration in your original
        code).

        <snip>[color=blue]
        >Most browsers I get are ie.[/color]

        How can you tell?
        [color=blue]
        >I'm willing to leave a few souls in
        >the dark, but will test pages versus latest ie,moz & opera.[/color]

        It seems perverse to put so much effort into the OO style and patterns
        of your code and then apply such low standards to the browser scripts
        you create with it.

        One of the probable outcomes of your script erroring is that JavaScript
        execution for the page will be terminated. That would mean that the
        failure of a script that represents an optional visual effect is
        impacting on any other scripts on the page when none of those scripts
        may have any real dependency on your script or on the absence of the
        objects/functions that are causing your script to error.

        I think that it is in broad accordance with an OO approach that
        JavaScript Objects designed for use within a browser should encapsulate
        the consequences of their failure as well as the details of their
        operation.

        <snip>[color=blue]
        >DOM... but I have such little hair left to pull out.[/color]

        It isn't that difficult.
        [color=blue]
        >I think before I travel down the 'code that generates
        >correctly nearly universally on the client side' road, I
        >would investigate server side generation.[/color]

        They aren't mutually exclusive. "universal" JavaScript is impossible (as
        some browsers have JavaScript disabled/unavailable) but client side can
        ease the server load, provide optional extras and enhancements and
        having server scripts to fall back to in the event of client-side
        failure can produce the ultimate in cross-browser and reliable code.

        <snip>[color=blue]
        >I would love to not need to attached transition to the element,
        >however in the 'bigger' version, I have to stop an elements
        >transition if the mouse moves over the element again. I've got
        >to store the timerId somewhere so that I can stop prematurely.[/color]

        It is the circular object references that cause the IE memory leak but
        the value returned from setTimeout/Interval is just a value (only
        meaningful to clearTimeout/Interval). You could assign that value to the
        TD's expando if that is the only value that needs to be associated with
        the TD itself.

        <snip>[color=blue]
        >... , however I find out that Mozilla doesn't do timered
        >stuff with functions, just strings (grrrr). So if I want mozilla to
        >transition I would need at least on Foo constructor function
        >property for dispatching the event handling.[/color]

        Well you now know that Mozilla is fine with the function reference
        argument but you could still look into my toString based fallback
        method. That does require a global reference to be available (possibly
        as a property of "Foo") but it only needs to be created in the event
        that the fallback is needed (it could be assigned within the toString
        method and thus not used if function references are recognised).

        Richard.


        Comment

        Working...