Tapestry
  1. Tapestry
  2. TAPESTRY-2390

Components or mixins requiring external javascript files and rendered via AJAX do not work

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 5.0, 5.0.11, 5.0.12
    • Fix Version/s: 5.0.14
    • Component/s: JavaScript, tapestry-core
    • Labels:
      None
    • Environment:
      os x 10.4, firefox 2.0.0.13

      Description

      To witness the breakage, create a simple page template that includes a form within a block. In this form include any component (or mixin) that requires an external JS file (like datefield, palette, etc). Create a zone and tie an actionlink to it. In the page class inject the block, and in the actionlink handler, return the injected block. The net result is that clicking on the link will fetch the form from the server via AJAX and put it in the zone.

      Now try to use the control, and you'll see it doesn't work. The problem is that there is currently no infrastructure for handling external scripts added via PageRenderSupport in an AJAX context. After a good bit of digging I realized that the PageRenderSupport implementation (actually the DocumentLinker impl) used for AJAX simply NOOPS several important methods, and specifically addScriptLink().

      I see 2 ways to fix this.

      1) Preemptively include all scripts from all components in the page, even if they are not initially rendered (which is the case of a block). This may be the best way to go IF that at the point of the initial page rendering T5 can know every component that may ever be rendered on that page.

      2) Extend the DocumentLinker implementation and tapestry.js to coordinate on an additional key in the AJAX response. This key would hold an array of all needed external JS files, and tapestry.js would handle loading them. The good thing about this approach is that the JS is only ever loaded if needed.

      I'll attach patches that implement method 2, patching TapestryModule.java and tapestry.js. The js extension eval()s the script code after the external files have loaded. It does this using the onload handler of the dynamically created script element. Granted this is a tad hackish and would need a bit more testing and thought (like preventing external JS from being loaded more than once), but it's a start.

      1. ajax-external-js.java.patch
        3 kB
        Chris Lewis
      2. ajax-external-js.js.patch
        6 kB
        Chris Lewis

        Activity

        Hide
        Ted Steen added a comment -

        This is a problem, and my vote goes for method 2. Also I think we need to check if the script is already loaded.

        Show
        Ted Steen added a comment - This is a problem, and my vote goes for method 2. Also I think we need to check if the script is already loaded.
        Hide
        Chris Lewis added a comment -

        Support for ensuring that external scripts are only ever loaded once. Cross-platform emulation for document.scripts on browsers (like firefox) that don't support it. Coordinated execution of internal script code with external JS files, so that the required code from those files will be available to the internal script.

        Show
        Chris Lewis added a comment - Support for ensuring that external scripts are only ever loaded once. Cross-platform emulation for document.scripts on browsers (like firefox) that don't support it. Coordinated execution of internal script code with external JS files, so that the required code from those files will be available to the internal script.
        Hide
        Chris Lewis added a comment -

        That last comment was about the new patch I attached - sorry if it sounded cryptic. I've tested this on FF 2 and Safari 3, and I think it's pretty solid. The only iffy part is using the onload event of dynamically created script elements to coordinate the dependent execution, but it works consistently on those browsers as well.

        This brings to light another issue very much the same: css files. The same principles apply, but dealing with them should be simpler since you don't need to coordinate execution with them. If any page elements load unstyled, the browser will (should) automatically style them with the relevant sheet has downloaded. Perhaps a new ticket for that one is needed.

        Show
        Chris Lewis added a comment - That last comment was about the new patch I attached - sorry if it sounded cryptic. I've tested this on FF 2 and Safari 3, and I think it's pretty solid. The only iffy part is using the onload event of dynamically created script elements to coordinate the dependent execution, but it works consistently on those browsers as well. This brings to light another issue very much the same: css files. The same principles apply, but dealing with them should be simpler since you don't need to coordinate execution with them. If any page elements load unstyled, the browser will (should) automatically style them with the relevant sheet has downloaded. Perhaps a new ticket for that one is needed.
        Hide
        Chris Lewis added a comment -

        I think now I'll give this a rest until some feedback comes in. These are new patches with support for adding the style sheets in the same manner the scripts, without duplicating them. Checks for previously loaded style sheets rely on the document.styleSheets collection. Unlike document.scripts this is a w3c standard and so no emulation is done. If it turns out that there are major browsers lacking this collection, it can be modified - I've verified consistent behavior on firefox 2 and safari 3.

        Show
        Chris Lewis added a comment - I think now I'll give this a rest until some feedback comes in. These are new patches with support for adding the style sheets in the same manner the scripts, without duplicating them. Checks for previously loaded style sheets rely on the document.styleSheets collection. Unlike document.scripts this is a w3c standard and so no emulation is done. If it turns out that there are major browsers lacking this collection, it can be modified - I've verified consistent behavior on firefox 2 and safari 3.
        Hide
        Howard M. Lewis Ship added a comment -

        Still working on this. Had to go a long ways from the original patch in order for it to work in IE 7.

        Major differences between FF and IE in terms of knowing when a script has finished loading.

        Also, I'm currently struggling with the issue of determining whether a script has been loaded (so that we don't try to load it a second time, to unpredictable result). That requires the complete URL. FF provides the complete URL in the <script> element's src attribute. IE parrots back the relative URL.

        Show
        Howard M. Lewis Ship added a comment - Still working on this. Had to go a long ways from the original patch in order for it to work in IE 7. Major differences between FF and IE in terms of knowing when a script has finished loading. Also, I'm currently struggling with the issue of determining whether a script has been loaded (so that we don't try to load it a second time, to unpredictable result). That requires the complete URL. FF provides the complete URL in the <script> element's src attribute. IE parrots back the relative URL.
        Hide
        Howard M. Lewis Ship added a comment -

        Wow this is a lot of work; but I have it working well now in FF, IE 6 and 7, and Safari. I think other browsers are like FF and should work well.

        Show
        Howard M. Lewis Ship added a comment - Wow this is a lot of work; but I have it working well now in FF, IE 6 and 7, and Safari. I think other browsers are like FF and should work well.

          People

          • Assignee:
            Howard M. Lewis Ship
            Reporter:
            Chris Lewis
          • Votes:
            5 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development