ICEfaces
  1. ICEfaces
  2. ICE-7293

Add ability to avoid having ice:inputRichText JS loaded on every page when not using it.

    Details

    • Type: Improvement Improvement
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 2.0.2
    • Fix Version/s: 2.1-Beta2, 3.0
    • Component/s: Bridge, ICE-Components
    • Labels:
      None
    • Environment:
      ICEfaces 2, ice:inputRichText component
    • Assignee Priority:
      P1
    • Affects:
      Documentation (User Guide, Ref. Guide, etc.), Compatibility/Configuration

      Description

      The inputRichText component JavaScript must be loaded into the <head> region of the page (CKeditor.js). Due to technical limitations with JSF partial-page updates not being able to update the HEAD region we preload the CKeditor.js into the head on every full page GET so that it is there should the ice:inputRichText component be added to the page later via a partial-page update.

      However, this preloading is not efficient as it causes the CKeditor.js to be loaded and evaluated each time a page is loaded, even if the component is not being used. This JIRA is to add a mechanism (config. param?) that would allow the application to opt. out of the inputRichText JS preload if that component is not being used.

        Issue Links

          Activity

          Hide
          Ken Fyten added a comment -

          Could we just have the ice:inputRichText component adopt the mandatoryResource feature, so it could be controlled the same way as the ace: components?

          Show
          Ken Fyten added a comment - Could we just have the ice:inputRichText component adopt the mandatoryResource feature, so it could be controlled the same way as the ace: components?
          Hide
          Mircea Toma added a comment -

          CKEditor is written in such a way as to load additional features/plugins lazily, when needed. These new code is loaded in by using relative URLs. ResourceRegistry resource serving infrastructure was written with relative referencing in mind, but unfortunately mixing it with mandatoryResource is not possible because the JSF implementation can choose to represent the resource request URLs non-hierarchically. In this case the relative paths do not work anymore.

          Show
          Mircea Toma added a comment - CKEditor is written in such a way as to load additional features/plugins lazily, when needed. These new code is loaded in by using relative URLs. ResourceRegistry resource serving infrastructure was written with relative referencing in mind, but unfortunately mixing it with mandatoryResource is not possible because the JSF implementation can choose to represent the resource request URLs non-hierarchically. In this case the relative paths do not work anymore.
          Hide
          Mircea Toma added a comment -

          Another solution to this issue would be to load all of the CKeditor resources as one file so that to avoid relative referencing. That proved impossible since there are also CSS and images that need to be included.

          Show
          Mircea Toma added a comment - Another solution to this issue would be to load all of the CKeditor resources as one file so that to avoid relative referencing. That proved impossible since there are also CSS and images that need to be included.
          Hide
          Mircea Toma added a comment -

          It looks like there is a CKEditor API that allows the URL re-mapping: http://docs.cksource.com/CKEditor_3.x/Developers_Guide/Editor_Core_URLs_Manipulation

          By using the CKEditor API we can use the JSF API to register all CKEditor resources, thus finding out their request URLs and create a mapping from the relative paths to the absolute request paths of all resources. Once this mapping created we just need to load it into the browser whenever CKeditor is used.

          Show
          Mircea Toma added a comment - It looks like there is a CKEditor API that allows the URL re-mapping: http://docs.cksource.com/CKEditor_3.x/Developers_Guide/Editor_Core_URLs_Manipulation By using the CKEditor API we can use the JSF API to register all CKEditor resources, thus finding out their request URLs and create a mapping from the relative paths to the absolute request paths of all resources. Once this mapping created we just need to load it into the browser whenever CKeditor is used.
          Hide
          Mircea Toma added a comment -

          The approach described above works well for most of the resources. Unfortunately there are some CSS files that reference images, being CSS the relative paths are not re-mapped like the paths used in JS files. So it seems that the complete solution would be to use the mapping to rewrite the image paths included in the CSS files, on the server at startup time.

          Show
          Mircea Toma added a comment - The approach described above works well for most of the resources. Unfortunately there are some CSS files that reference images, being CSS the relative paths are not re-mapped like the paths used in JS files. So it seems that the complete solution would be to use the mapping to rewrite the image paths included in the CSS files, on the server at startup time.
          Hide
          Mircea Toma added a comment -

          Changed InputRichTextSetup to register its resources through the JSF API. Created mapping between resource local paths and requests paths, mapping that is use by CKeditor when loading in new functionality. Re-created the CSS resources with the image references remapped to the resource request paths. Loaded these new CSS resources into the classpath at runtime so that they are found by JSF. Patched CKEditor in a couple of places where the JS code builds resource paths dynamically without calling CKEDITOR.getUrl function to translate them.

          Show
          Mircea Toma added a comment - Changed InputRichTextSetup to register its resources through the JSF API. Created mapping between resource local paths and requests paths, mapping that is use by CKeditor when loading in new functionality. Re-created the CSS resources with the image references remapped to the resource request paths. Loaded these new CSS resources into the classpath at runtime so that they are found by JSF. Patched CKEditor in a couple of places where the JS code builds resource paths dynamically without calling CKEDITOR.getUrl function to translate them.
          Hide
          Ken Fyten added a comment -

          ice:inputRichText demo in compat/component-showcase is not functional in Chrome, IE7.

          Fails with JS error:

          Failed to load resource: the server responded with a status of 404 (Not Found)
          http://localhost:8080/component-showcase/lang/en.js?t=B1GG4Z6Failed to load resource: the server responded with a status of 404 (Not Found)
          ckeditor.js.jsf:47Uncaught TypeError: Cannot read property 'options' of undefined

          Show
          Ken Fyten added a comment - ice:inputRichText demo in compat/component-showcase is not functional in Chrome, IE7. Fails with JS error: Failed to load resource: the server responded with a status of 404 (Not Found) http://localhost:8080/component-showcase/lang/en.js?t=B1GG4Z6Failed to load resource: the server responded with a status of 404 (Not Found) ckeditor.js.jsf:47Uncaught TypeError: Cannot read property 'options' of undefined
          Hide
          Ken Fyten added a comment -

          Also noticing that this invalid resource request is now appearing in ace/comp-suite sample:

          <link href="RES_NOT_FOUND" rel="stylesheet" type="text/css" />

          Show
          Ken Fyten added a comment - Also noticing that this invalid resource request is now appearing in ace/comp-suite sample: <link href="RES_NOT_FOUND" rel="stylesheet" type="text/css" />
          Hide
          Mircea Toma added a comment -

          I cannot reproduce the JS error in Chrome or FF. Was the browser cache cleared before testing?

          Show
          Mircea Toma added a comment - I cannot reproduce the JS error in Chrome or FF. Was the browser cache cleared before testing?
          Hide
          Mircea Toma added a comment -

          I cannot reproduce the RES_NOT_FOUND problem either.

          Show
          Mircea Toma added a comment - I cannot reproduce the RES_NOT_FOUND problem either.
          Hide
          Mircea Toma added a comment -

          Updated component-showcase configuration to have InputRichText resources loaded eagerly, on first page load.

          Show
          Mircea Toma added a comment - Updated component-showcase configuration to have InputRichText resources loaded eagerly, on first page load.
          Hide
          Mircea Toma added a comment - - edited

          Modified InputRichTextSetup to save the temporary files into the servlet spec defined directory ( http://java.sun.com/developer/technicalArticles/Servlets/servletapi/ ). This approach will work even in deployments that do not have the "java.io.tmpdir" directory created.

          Show
          Mircea Toma added a comment - - edited Modified InputRichTextSetup to save the temporary files into the servlet spec defined directory ( http://java.sun.com/developer/technicalArticles/Servlets/servletapi/ ). This approach will work even in deployments that do not have the "java.io.tmpdir" directory created.
          Hide
          Deryk Sinotte added a comment -

          Running the Compat Component Showcase portlets with MyFaces, I get this error:

          Caused by: java.lang.UnsupportedOperationException
          at java.util.Collections$UnmodifiableList.add(Collections.java:1159)
          at com.icesoft.faces.component.inputrichtext.InputRichTextSetup.processEvent(InputRichTextSetup.java:46)
          at javax.faces.event.SystemEvent.processListener(SystemEvent.java:43)

          It's not a portlet thing though as you can do the same thing with the non-portlet version of the showcase by going to the Rich Text example and trying to reload the page. The culprit is from the changes in http://jira.icefaces.org/browse/ICE-7293:

          List componentResources = root.getComponentResources(context, "head");
          //make sure the script is always loaded first
          if (componentResources.isEmpty())

          { root.addComponentResource(context, mappingsWriter, "head"); }

          else

          { //Not allowed to add stuff directly to this list as its unmodifiable and MyFaces is strict componentResources.add(0, mappingsWriter); }

          According to the JavaDoc:

          "Return an unmodifiable List of UIComponents for the provided target agrument."

          If it's critical that are our script is first, we may need to get the list of them, remove them, and add them again.

          Show
          Deryk Sinotte added a comment - Running the Compat Component Showcase portlets with MyFaces, I get this error: Caused by: java.lang.UnsupportedOperationException at java.util.Collections$UnmodifiableList.add(Collections.java:1159) at com.icesoft.faces.component.inputrichtext.InputRichTextSetup.processEvent(InputRichTextSetup.java:46) at javax.faces.event.SystemEvent.processListener(SystemEvent.java:43) It's not a portlet thing though as you can do the same thing with the non-portlet version of the showcase by going to the Rich Text example and trying to reload the page. The culprit is from the changes in http://jira.icefaces.org/browse/ICE-7293: List componentResources = root.getComponentResources(context, "head"); //make sure the script is always loaded first if (componentResources.isEmpty()) { root.addComponentResource(context, mappingsWriter, "head"); } else { //Not allowed to add stuff directly to this list as its unmodifiable and MyFaces is strict componentResources.add(0, mappingsWriter); } According to the JavaDoc: "Return an unmodifiable List of UIComponents for the provided target agrument." If it's critical that are our script is first, we may need to get the list of them, remove them, and add them again.
          Hide
          Ken Fyten added a comment -

          The new technique is also not deploying and running well on Jboss7.

          Following error seen in log:

          12:44:28,140 SEVERE [javax.enterprise.resource.webcontainer.jsf.context] (http--127.0.0.1-8080-1) JSF1073: javax.faces.event.AbortProcessingException caught during processing of RENDER_RESPONSE 6 : UIComponent-ClientId=, Message=java.io.IOException: Cannot access InputRichText resources icefaces-compat.jar when exploded into the classpath.
          12:44:28,140 SEVERE [javax.enterprise.resource.webcontainer.jsf.context] (http--127.0.0.1-8080-1) java.io.IOException: Cannot access InputRichText resources icefaces-compat.jar when exploded into the classpath.: javax.faces.event.AbortProcessingException: java.io.IOException: Cannot access InputRichText resources icefaces-compat.jar when exploded into the classpath.
          at com.icesoft.faces.component.inputrichtext.InputRichTextSetup.processEvent(InputRichTextSetup.java:50) [icefaces-compat.jar:]
          at javax.faces.event.SystemEvent.processListener(SystemEvent.java:106) [jboss-jsf-api_2.0_spec-1.0.0.Final.jar:1.0.0.Final]
          at com.sun.faces.application.ApplicationImpl.processListeners(ApplicationImpl.java:2102) [jsf-impl-2.0.4-b09-jbossorg-4.jar:2.0.4-b09-jbossorg-4]
          at com.sun.faces.application.ApplicationImpl.invokeListenersFor(ApplicationImpl.java:2078) [jsf-impl-2.0.4-b09-jbossorg-4.jar:2.0.4-b09-jbossorg-4]
          at com.sun.faces.application.ApplicationImpl.publishEvent(ApplicationImpl.java:301) [jsf-impl-2.0.4-b09-jbossorg-4.jar:2.0.4-b09-jbossorg-4]
          at com.sun.faces.application.ApplicationImpl.publishEvent(ApplicationImpl.java:245) [jsf-impl-2.0.4-b09-jbossorg-4.jar:2.0.4-b09-jbossorg-4]
          at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:108) [jsf-impl-2.0.4-b09-jbossorg-4.jar:2.0.4-b09-jbossorg-4]
          at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101) [jsf-impl-2.0.4-b09-jbossorg-4.jar:2.0.4-b09-jbossorg-4]
          at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:139) [jsf-impl-2.0.4-b09-jbossorg-4.jar:2.0.4-b09-jbossorg-4]
          at javax.faces.webapp.FacesServlet.service(FacesServlet.java:313) [jboss-jsf-api_2.0_spec-1.0.0.Final.jar:1.0.0.Final]
          at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:329) [jbossweb-7.0.0.CR4.jar:7.0.0.Final]
          at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.0.CR4.jar:7.0.0.Final]
          at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:275) [jbossweb-7.0.0.CR4.jar:7.0.0.Final]
          at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161) [jbossweb-7.0.0.CR4.jar:7.0.0.Final]
          at org.jboss.as.web.NamingValve.invoke(NamingValve.java:57) [jboss-as-web-7.0.0.Final.jar:7.0.0.Final]
          at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:154) [jbossweb-7.0.0.CR4.jar:7.0.0.Final]
          at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) [jbossweb-7.0.0.CR4.jar:7.0.0.Final]
          at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) [jbossweb-7.0.0.CR4.jar:7.0.0.Final]
          at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:362) [jbossweb-7.0.0.CR4.jar:7.0.0.Final]
          at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877) [jbossweb-7.0.0.CR4.jar:7.0.0.Final]
          at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:667) [jbossweb-7.0.0.CR4.jar:7.0.0.Final]
          at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:951) [jbossweb-7.0.0.CR4.jar:7.0.0.Final]
          at java.lang.Thread.run(Thread.java:619) [:1.6.0_21]
          Caused by: java.io.IOException: Cannot access InputRichText resources icefaces-compat.jar when exploded into the classpath.
          at com.icesoft.faces.component.inputrichtext.InputRichTextSetup.loadResources(InputRichTextSetup.java:92) [icefaces-compat.jar:]
          at com.icesoft.faces.component.inputrichtext.InputRichTextSetup.processEvent(InputRichTextSetup.java:36) [icefaces-compat.jar:]
          ... 22 more

          Show
          Ken Fyten added a comment - The new technique is also not deploying and running well on Jboss7. Following error seen in log: 12:44:28,140 SEVERE [javax.enterprise.resource.webcontainer.jsf.context] (http--127.0.0.1-8080-1) JSF1073: javax.faces.event.AbortProcessingException caught during processing of RENDER_RESPONSE 6 : UIComponent-ClientId=, Message=java.io.IOException: Cannot access InputRichText resources icefaces-compat.jar when exploded into the classpath. 12:44:28,140 SEVERE [javax.enterprise.resource.webcontainer.jsf.context] (http--127.0.0.1-8080-1) java.io.IOException: Cannot access InputRichText resources icefaces-compat.jar when exploded into the classpath.: javax.faces.event.AbortProcessingException: java.io.IOException: Cannot access InputRichText resources icefaces-compat.jar when exploded into the classpath. at com.icesoft.faces.component.inputrichtext.InputRichTextSetup.processEvent(InputRichTextSetup.java:50) [icefaces-compat.jar:] at javax.faces.event.SystemEvent.processListener(SystemEvent.java:106) [jboss-jsf-api_2.0_spec-1.0.0.Final.jar:1.0.0.Final] at com.sun.faces.application.ApplicationImpl.processListeners(ApplicationImpl.java:2102) [jsf-impl-2.0.4-b09-jbossorg-4.jar:2.0.4-b09-jbossorg-4] at com.sun.faces.application.ApplicationImpl.invokeListenersFor(ApplicationImpl.java:2078) [jsf-impl-2.0.4-b09-jbossorg-4.jar:2.0.4-b09-jbossorg-4] at com.sun.faces.application.ApplicationImpl.publishEvent(ApplicationImpl.java:301) [jsf-impl-2.0.4-b09-jbossorg-4.jar:2.0.4-b09-jbossorg-4] at com.sun.faces.application.ApplicationImpl.publishEvent(ApplicationImpl.java:245) [jsf-impl-2.0.4-b09-jbossorg-4.jar:2.0.4-b09-jbossorg-4] at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:108) [jsf-impl-2.0.4-b09-jbossorg-4.jar:2.0.4-b09-jbossorg-4] at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101) [jsf-impl-2.0.4-b09-jbossorg-4.jar:2.0.4-b09-jbossorg-4] at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:139) [jsf-impl-2.0.4-b09-jbossorg-4.jar:2.0.4-b09-jbossorg-4] at javax.faces.webapp.FacesServlet.service(FacesServlet.java:313) [jboss-jsf-api_2.0_spec-1.0.0.Final.jar:1.0.0.Final] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:329) [jbossweb-7.0.0.CR4.jar:7.0.0.Final] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.0.CR4.jar:7.0.0.Final] at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:275) [jbossweb-7.0.0.CR4.jar:7.0.0.Final] at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161) [jbossweb-7.0.0.CR4.jar:7.0.0.Final] at org.jboss.as.web.NamingValve.invoke(NamingValve.java:57) [jboss-as-web-7.0.0.Final.jar:7.0.0.Final] at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:154) [jbossweb-7.0.0.CR4.jar:7.0.0.Final] at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) [jbossweb-7.0.0.CR4.jar:7.0.0.Final] at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) [jbossweb-7.0.0.CR4.jar:7.0.0.Final] at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:362) [jbossweb-7.0.0.CR4.jar:7.0.0.Final] at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877) [jbossweb-7.0.0.CR4.jar:7.0.0.Final] at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:667) [jbossweb-7.0.0.CR4.jar:7.0.0.Final] at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:951) [jbossweb-7.0.0.CR4.jar:7.0.0.Final] at java.lang.Thread.run(Thread.java:619) [:1.6.0_21] Caused by: java.io.IOException: Cannot access InputRichText resources icefaces-compat.jar when exploded into the classpath. at com.icesoft.faces.component.inputrichtext.InputRichTextSetup.loadResources(InputRichTextSetup.java:92) [icefaces-compat.jar:] at com.icesoft.faces.component.inputrichtext.InputRichTextSetup.processEvent(InputRichTextSetup.java:36) [icefaces-compat.jar:] ... 22 more
          Hide
          Mircea Toma added a comment -

          Tying to collect the list of CKEditor resources by looking into the JAR or directory that contains them is not possible in JBoss. The URL returned when the JAR/directory is located has the "vfs:" protocol which means that we would need to use the VFS Jboss library to get access to the file. But that will force us onto being dependant on the VFS library which is not really acceptable.

          Show
          Mircea Toma added a comment - Tying to collect the list of CKEditor resources by looking into the JAR or directory that contains them is not possible in JBoss. The URL returned when the JAR/directory is located has the "vfs:" protocol which means that we would need to use the VFS Jboss library to get access to the file. But that will force us onto being dependant on the VFS library which is not really acceptable.
          Hide
          Mircea Toma added a comment -

          Modified the build to generate a file that contains the list of CKEditor resources. This file is loaded then as a resource at startup time by InputRichTextSetup class. This approach avoids the scanning of the JAR file (containing the CKeditor resources) at startup which proved to be problematic in JBoss.

          Show
          Mircea Toma added a comment - Modified the build to generate a file that contains the list of CKEditor resources. This file is loaded then as a resource at startup time by InputRichTextSetup class. This approach avoids the scanning of the JAR file (containing the CKeditor resources) at startup which proved to be problematic in JBoss.
          Hide
          Mircea Toma added a comment -

          It looks like JBoss's classloader cannot load new JARs while the application is running. Normally this feature (URLClassLoader.addURL) is used to load the modified CSS resources into the classpath so that JSF can find when they need to be served up.

          Show
          Mircea Toma added a comment - It looks like JBoss's classloader cannot load new JARs while the application is running. Normally this feature (URLClassLoader.addURL) is used to load the modified CSS resources into the classpath so that JSF can find when they need to be served up.
          Hide
          Mircea Toma added a comment - - edited

          Implemented new approach where the CSS resources are loaded into memory, image paths are re-written but instead of serving these resources from the file system they are served by a custom ResourceHandler registered with JSF (InputRichTextResourceHandler). Also modified the loading of the mapping between local paths to request paths registered with CKEditor. Now it is loaded as an external resource, not as inline JS which should improve loading performance through caching.

          Show
          Mircea Toma added a comment - - edited Implemented new approach where the CSS resources are loaded into memory, image paths are re-written but instead of serving these resources from the file system they are served by a custom ResourceHandler registered with JSF (InputRichTextResourceHandler). Also modified the loading of the mapping between local paths to request paths registered with CKEditor. Now it is loaded as an external resource, not as inline JS which should improve loading performance through caching.

            People

            • Assignee:
              Mircea Toma
              Reporter:
              Ken Fyten
            • Votes:
              1 Vote for this issue
              Watchers:
              0 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: