Opened 13 years ago

Closed 12 years ago

Last modified 10 years ago

#1622 closed New Feature (fixed)

CSS cache in JS

Reported by: designfu Owned by: Frederico Caldeira Knabben
Priority: Normal Milestone: FCKeditor 2.6
Component: Core : Styles Version: SVN (FCKeditor) - Retired
Keywords: Review+ Cc:


Instead of including CSS files with <link ...> tags, how about caching them in a global data structure? Then, instead of emitting tags, we can echo the <style> information in-place and save extraneous CSS requests. We plan to use this at to help optimize page loading time and minimize the number of requests we serve. Patch attached.

Attachments (8)

1622.patch (7.5 KB) - added by designfu 13 years ago.
Patch against FCKeditor/FCKpackager SVN
1622_packager.patch (1.5 KB) - added by Alfonso Martínez de Lizarrondo 12 years ago.
patch for the packager
1622_FCKeditor.patch (3.5 KB) - added by Alfonso Martínez de Lizarrondo 12 years ago.
Patch for the editor
1622_2.patch (26.8 KB) - added by Alfonso Martínez de Lizarrondo 12 years ago.
work in progress
1622_3.patch (25.4 KB) - added by Frederico Caldeira Knabben 12 years ago.
This implementation is completely different from the original proposal
1622_4.patch (25.6 KB) - added by Frederico Caldeira Knabben 12 years ago.
1622_5.patch (25.9 KB) - added by Frederico Caldeira Knabben 12 years ago.
1622_6.patch (26.0 KB) - added by Frederico Caldeira Knabben 12 years ago.

Download all attachments as: .zip

Change History (23)

Changed 13 years ago by designfu

Attachment: 1622.patch added

Patch against FCKeditor/FCKpackager SVN

comment:1 Changed 13 years ago by Frederico Caldeira Knabben

Keywords: HasPatch added

comment:2 Changed 12 years ago by Frederico Caldeira Knabben

I'm trying to apply this patch to the trunk with no luck. Not only Trac is not able to show the diff, but I'm not able to apply it with TortoiseSVN nor the patch command.

By reading the patch file, your solutions looks good, with a few minor changes, and some cleanup.

Can you please provide a new patch file? Be sure it is in Unified format (diff -u). To be sure the patch file is ok, just click on the attached file name. You should see a Trac diff page (like this).

Changed 12 years ago by Alfonso Martínez de Lizarrondo

Attachment: 1622_packager.patch added

patch for the packager

Changed 12 years ago by Alfonso Martínez de Lizarrondo

Attachment: 1622_FCKeditor.patch added

Patch for the editor

comment:3 Changed 12 years ago by Alfonso Martínez de Lizarrondo

I've recreated the patch in order to test it. There are some comments about it:

It doesn't apply any compression to the css files processed by the packager. It should remove all the comments, tabs and new lines as they aren't needed and they might end up being a big percentage of those files.

It doesn't seems that the css are being properly cached, in Firebug I can see still several calls to the files (in order to debug I've tried to add the "FCKCSSManager.AddCachedCSS(" commands located at the end of the compressed files to the fckcssmanager.js)

People should be warned that it does cache only the files that are added to the packager.xml (for example now it's compressing the silver skin instead of the default)

I guess that a future version could use CSSDom to cache any css file that it's being loaded, so it will be easier to use with custom styles.

comment:4 Changed 12 years ago by Alfonso Martínez de Lizarrondo

In order to compress the CSS that is processed by the packager I think that we could hook up this parser:

It should be a matter of checking that the licenses are compatible and this way we don't have to worry about that part.

comment:5 Changed 12 years ago by Alfonso Martínez de Lizarrondo

Owner: set to Alfonso Martínez de Lizarrondo
Status: newassigned

#198 has been marked as dup

Changed 12 years ago by Alfonso Martínez de Lizarrondo

Attachment: 1622_2.patch added

work in progress

comment:6 Changed 12 years ago by Alfonso Martínez de Lizarrondo

Keywords: Review? added; HasPatch removed

This new patch shows the current status. If you want to test how it behaves when the code is packaged then uncomment the four FCKCSSManager.AddCachedCSS lines at the end of the FCKCSSManager.js file.

The new patch does support a CSSDom parser, so it automatically can cache any file that will be later used again. This can be seen easily with the dialogs, before each time a dialog was opened there was 2 request for the same css file sent to the server, now it only does it once, just the first time that it loads the dialog frame. This is done without any requirement to package the css file.

In the body of the editor the benefits are visible if you switch to source mode and back to design, the css files aren't requested again.

Currently some files are still requested twice because they are used in two different frames and they are loaded before the main window does finish. Maybe another idea to improve loading time would be to delay the creation of the panels until the moment that they are really needed. I thought that it was already that way, as it could save some little time initializing those panels if they aren't gonna be used.

If the css files are packaged then the requests for them can be 0 if I have not forgotten anything.

The css parser does have the benefit from my point of view that it doesn't interfere with the browser with the loading order of elements, if we use a XmlHttpRequest it must be a blocking request, but the browser might choose to load the css in parallel, so we would be forcing a delay in the loading time. Maybe there's some file that we can choose to load by a XmlHttpRequest, but the benefit of the current patch is that it doesn't should have no drawback in any browser (only just a little processing time for the stylesheet, but that should be almost 0). We can study later the best approach for the files that are loaded twice.

Marking for review just to get comments, not really to check it in.

Changed 12 years ago by Frederico Caldeira Knabben

Attachment: 1622_3.patch added

This implementation is completely different from the original proposal

comment:7 Changed 12 years ago by Frederico Caldeira Knabben

I've just attached a new proposal for it. It has nothing to do with the original proposal. Actually, it doesn't even adds a dedicated object to handle it.

It doesn't include the dynamic CSS caching, which we could consider as another feature, not really part of it.

It reflects the initial idea I had of it when discussing it with Chris. It make it possible to place the CSS definitions inline in the configuration file, avoiding downloading them on separate calls.

This implementation though make the CSS related settings (EditorAreaCSS, ToolbarComboPreviewCSS, SkinEditorCSS, SkinDialogCSS) much more powerful, and now sharing the same features. It is possible to set them in the following way:

  • String pointing to a CSS file.
  • String pointing to several CSS files separated by comma.
  • Array of Strings pointing to CSS files.
  • String containing the raw css definition.
  • String containing the raw css definition, including a way to fix url() entries in the format "/absolute/path/for/urls/|<raw CSS>".

The fck_internal.css and fck_showtableborders_gecko.css files are already hardcoded in the fckeditor.html file, but are not enabled in the dev version (see FCK_InternalCSS in that file).

To test it, just uncomment the minified FCK_InternalCSS and FCK_ShowTableBordersCSS values in fckeditor.html and add the following at the very end of fckconfig.js:

// CSS minified by
FCKConfig.EditorAreaCSS = FCKConfig.BasePath + "css/" + "|body{background-color:#fff;padding:5px;margin:0}body,td{font-family:Arial, Verdana, sans-serif;font-size:12px}a[href]{color:-moz-hyperlinktext !important;text-decoration:-moz-anchor-decoration}.Bold{font-weight:700}.Title{font-weight:700;font-size:18px;color:#c30}.Code{border:#8b4513 1px solid;padding-right:5px;padding-left:5px;color:#006;font-family:\'Courier New\' , Monospace;background-color:#f93}" ;
FCKConfig.SkinEditorCSS = FCKConfig.SkinPath + "|body{padding:1px;margin:0;background-color:#fff}#xEditingArea{border:#696969 1px solid}.SourceField{padding:5px;margin:0;font-family:Monospace}.TB_ToolbarSet,.TB_Expand,.TB_Collapse{cursor:default;background-color:#efefde}.TB_ToolbarSet{border-top:#efefde 1px outset;border-bottom:#efefde 1px outset}.TB_Toolbar{height:24px;display:inline-table}.TB_Separator{width:1px;height:16px;margin:2px;background-color:#996}.TB_Start{background-image:url(images/toolbar.start.gif);margin:2px;width:3px;background-repeat:no-repeat;height:16px}.TB_End{display:none}.TB_ExpandImg{background-image:url(images/toolbar.expand.gif);background-repeat:no-repeat}.TB_CollapseImg{background-image:url(images/toolbar.collapse.gif);background-repeat:no-repeat}.TB_SideBorder{background-color:#696969}.TB_Expand,.TB_Collapse{padding:2px;border:#efefde 1px outset}.TB_Collapse{width:5px}.TB_Break{height:24px}.TB_Button_On,.TB_Button_Off,.TB_Button_On_Over,.TB_Button_Off_Over,.TB_Button_Disabled{border:#efefde 1px solid;height:22px}.TB_Button_On{border:#316ac5 1px solid;background-color:#c1d2ee}.TB_Button_On_Over,.TB_Button_Off_Over{border:#316ac5 1px solid;background-color:#dff1ff}.TB_Button_Padding{visibility:hidden;width:3px;height:22px}.TB_Button_Image{overflow:hidden;width:16px;height:16px;margin:3px;background-repeat:no-repeat}.TB_Button_Image img{position:relative}.TB_ConnectionLine{background-color:#fff;height:1px;margin-left:1px;margin-right:1px}.TB_Text{height:22px}.TB_Button_Off .TB_Text,.TB_Button_Off .TB_Button_Text{background-color:#efefde}.TB_Button_On_Over .TB_Text{background-color:#dff1ff}.MN_Menu{border:1px solid #8f8f73;padding:2px;background-color:#fff;cursor:default}.MN_Item_Padding{visibility:hidden;width:3px;height:20px}.MN_Icon{background-color:#e3e3c7;text-align:center;height:20px}.MN_Separator{height:3px}.MN_Separator_Line{border-top:#b9b99d 1px solid}.MN_Item .MN_Icon IMG,.TB_Button_Off{filter:alpha(opacity=70);opacity:0.70}.MN_Item_Over{color:#fff;background-color:#8f8f73}.MN_Item_Over .MN_Icon{background-color:#737357}.MN_Item_Disabled .MN_Label{color:#b7b7b7}.MN_Arrow,.MN_Label{padding-right:3px;padding-left:3px}.MN_ConnectionLine{background-color:#fff}.Menu .TB_Button_On,.Menu .TB_Button_On_Over{border:#8f8f73 1px solid;background-color:#fff}.FCK_Panel{border:#8f8f73 1px solid;padding:2px;background-color:#fff}.SC_Panel{overflow:auto;white-space:nowrap;cursor:default;border:1px solid #8f8f73;padding-left:2px;padding-right:2px}.SC_Panel,.SC_Panel TD,.FCK_Panel,.FCK_Panel TD,.MN_Menu,.MN_Menu .MN_Label,.TB_ToolbarSet TD{font-size:11px;font-family:\'Microsoft Sans Serif\' , Tahoma, Arial, Verdana, Sans-Serif}.SC_Item,.SC_ItemSelected{margin-top:2px;margin-bottom:2px;background-position:left center;text-overflow:ellipsis;overflow:hidden;background-repeat:no-repeat;border:#ddd 1px solid;padding:2px 3px 2px 11px}.SC_Item *,.SC_ItemSelected *{margin-top:0;margin-bottom:0}.SC_ItemSelected{border:#9a9afb 1px solid;background-image:url(images/toolbar.arrowright.gif)}.SC_Field{border:#b7b7a6 1px solid;cursor:default}.SC_FieldCaption{overflow:visible;padding-right:5px;padding-left:5px;opacity:0.75;filter:alpha(opacity=70);height:23px;background-color:#efefde}.SC_FieldLabel{white-space:nowrap;padding:2px;width:100%;cursor:default;background-color:#fff;text-overflow:ellipsis;overflow:hidden}.SC_FieldButton{background-position:center center;background-image:url(images/toolbar.buttonarrow.gif);border-left:#b7b7a6 1px solid;width:14px;background-repeat:no-repeat}.SC_FieldDisabled .SC_FieldButton,.SC_FieldDisabled .SC_FieldCaption,.MN_Item_Disabled IMG,.TB_Button_Disabled{opacity:0.30;filter:gray() alpha(opacity=30)}.SC_FieldOver,.SC_ItemOver{border:#316ac5 1px solid}.SC_FieldOver .SC_FieldButton{border-left:#316ac5 1px solid}.ColorBoxBorder{border:gray 1px solid;position:static}.ColorBox{font-size:1px;width:10px;position:static;height:10px}.ColorDeselected,.ColorSelected{cursor:default}.ColorDeselected{border:#fff 1px solid;padding:2px;float:left}.ColorSelected{border:#306 1px solid;padding:2px;float:left;background-color:#c4cdd6}" ;
FCKConfig.SkinDialogCSS = FCKConfig.SkinPath + "|html,body{background-color:transparent;margin:0;padding:0}body{padding:10px}body,td,input,select,textarea{font-size:11px;font-family:\'Microsoft Sans Serif\' , Arial, Helvetica, Verdana}body,.BackColor{background-color:#f1f1e3}.PopupBody{height:100%;width:100%;overflow:hidden;background-color:transparent;padding:0}#header{cursor:move}.PopupTitle{font-weight:700;font-size:14pt;color:#737357;background-color:#e3e3c7;padding:3px 10px}.PopupButtons{position:absolute;right:0;left:0;bottom:0;border-top:#d5d59d 1px solid;background-color:#e3e3c7;padding:7px 10px}.Button{border:#737357 1px solid;color:#3b3b1f;background-color:#c7c78f}#btnOk{width:100px}.DarkBackground{background-color:#eaead1}.LightBackground{background-color:#ffffbe}.PopupTitleBorder{border-bottom:#d5d59d 1px solid}.PopupTabArea{color:#737357;background-color:#e3e3c7}.PopupTabEmptyArea{padding-left:10px;border-bottom:#d5d59d 1px solid}.PopupTab,.PopupTabSelected{border-right:#d5d59d 1px solid;border-top:#d5d59d 1px solid;border-left:#d5d59d 1px solid;padding:3px 5px;color:#737357}.PopupTab{margin-top:1px;border-bottom:#d5d59d 1px solid;cursor:hand}.PopupTabSelected{font-weight:700;cursor:default;padding-top:4px;border-bottom:#f1f1e3 1px solid;background-color:#f1f1e3}.PopupSelectionBox{border:#f93 1px solid !important;background-color:#fffacd !important;cursor:hand}#tdBrowse{vertical-align:bottom}.contents{position:absolute;top:2px;left:16px;right:16px;bottom:20px;background-color:#f1f1e3;overflow:hidden;z-index:1}.tl,.tr,.tc,.bl,.br,.bc{position:absolute;background-image:url(images/sprites.png);background-repeat:no-repeat}* html .tl,* html .tr,* html .tc,* html .bl,* html .br,* html .bc{background-image:url(images/sprites.gif)}.ml,.mr{position:absolute;background-image:url(images/dialog.sides.png);background-repeat:repeat-y}.rtl .ml,.rtl .mr{position:absolute;background-image:url(images/dialog.sides.rtl.png);background-repeat:repeat-y}* html .rtl .ml,* html .rtl .mr,* html .ml,* html .mr{background-image:url(images/dialog.sides.gif)}.tl{top:0;left:0;width:16px;height:16px;background-position:-16px -16px}.rtl .tl{background-position:-16px -397px}.tr{top:0;right:0;width:16px;height:16px;background-position:-16px -76px}.rtl .tr{background-position:-16px -457px}.tc{top:0;right:16px;left:16px;height:16px;background-position:0 -136px;background-repeat:repeat-x}.ml{top:16px;left:0;width:16px;bottom:51px;background-position:0 0}.mr{top:16px;right:0;width:16px;bottom:51px;background-position:-16px 0}.bl{bottom:0;left:0;width:30px;height:51px;background-position:-16px -196px}.rtl .bl{background-position:-16px -517px}.br{bottom:0;right:0;width:30px;height:51px;background-position:-16px -263px}.rtl .br{background-position:-16px -584px}.bc{bottom:0;right:30px;left:30px;height:51px;background-position:0 -330px;background-repeat:repeat-x}* html .blocker{position:absolute;width:100%;height:100%;z-index:12;filter:progid}.cover{position:absolute;top:0;left:14px;right:14px;bottom:18px;z-index:11}#closeButton{position:absolute;right:0;top:0;margin-top:5px;margin-right:10px;width:20px;height:20px;cursor:pointer;background-image:url(images/sprites.png);background-repeat:no-repeat;background-position:-16px -651px}* html #closeButton{cursor:hand;background-image:url(images/sprites.gif)}.rtl #closeButton{right:auto;left:0;margin-left:10px}#closeButton:hover{background-position:-16px -687px}#throbberBlock{z-index:10}#throbberBlock div{float:left;width:8px;height:9px;margin-left:2px;margin-right:2px;font-size:1px}.throbber_1{background-color:#737357}.throbber_2{background-color:#8f8f73}.throbber_3{background-color:#abab8f}.throbber_4{background-color:#c7c7ab}.throbber_5{background-color:#e3e3c7}" ;

Also, I've tested several CSS compressors, with and finally used even if they state that it may break some "hacks".

Notes about other CSS minifiers:

comment:8 Changed 12 years ago by Frederico Caldeira Knabben

Owner: changed from Alfonso Martínez de Lizarrondo to Frederico Caldeira Knabben
Status: assignednew

I'm getting the ownership of this one just for proper review.

Changed 12 years ago by Frederico Caldeira Knabben

Attachment: 1622_4.patch added

comment:9 Changed 12 years ago by Frederico Caldeira Knabben

I've added a new patch following Alfonso's suggestions:

  • Added the URL fix path to the in-file CSS definition in fck_dialog_common.js.
  • Always using "this" inside the related functions in FCKTools.

comment:10 Changed 12 years ago by Alfonso Martínez de Lizarrondo

Keywords: Review- added; Review? removed

The fck_dialog_common.css file is missing the warning that its contents are compressed in another file.

You have removed the ability in FCKTools._AppendStyleSheet to return the created stylesheet, but that means that if someone wants to append a stylesheet and then do something else with that node he will have to write extra code. For example I've found a plugin were I added a stylesheet and then according to the state I enable or disable that stylesheet thanks to keeping a reference to the returned node.

The loop

			for ( var i = 0 ; i < cssFileOrArrayOrDef.length ; i++ )
				html += getLink( cssFileOrArrayOrDef, markTemp ) ;

should be

			for ( var i = 0 ; i < cssFileOrArrayOrDef.length ; i++ )
				html += getLink( cssFileOrArrayOrDef[i], markTemp ) ;

comment:11 Changed 12 years ago by Alfonso Martínez de Lizarrondo

Besides FCKTools._AppendStyleSheet, I would also like FCKTools.AppendStyleString to keep returning the created element. It's a little detail that helps with the development of external code and the plugins based approach for V3.

And as commented in IRC, instead of running the replacement of url() with the base path in FixCssUrls everytime, just do it the first time and then change the value stored for that css entry

Changed 12 years ago by Frederico Caldeira Knabben

Attachment: 1622_5.patch added

comment:12 Changed 12 years ago by Frederico Caldeira Knabben

Keywords: Review+ added; Review- removed

Added a new patch for it, including all Alfonso's suggestions.

The only thing it misses is the "fix url() once" idea. It's not that simple to implement it as strings are passed to functions "by value", so we can't do that automatically inside FCKTools._GetUrlFixedCss. The only possibility would be fixing all known values when starting the editor, but as there is no clear way to do that, I would avoid having it for now. The impact of it should be quite low though.

Changed 12 years ago by Frederico Caldeira Knabben

Attachment: 1622_6.patch added

comment:13 Changed 12 years ago by Frederico Caldeira Knabben

Actually, the "fix url() once" thing could be done at least for our internal stuff. I've updated the patch to do that in fckeditor.html.

comment:14 Changed 12 years ago by Alfonso Martínez de Lizarrondo

Everything looks nice now. Review+

comment:15 Changed 12 years ago by Frederico Caldeira Knabben

Milestone: FCKeditor 2.6
Resolution: fixed
Status: newclosed

Feature introduced with [1598].

Note: See TracTickets for help on using tickets.
© 2003 – 2019 CKSource – Frederico Knabben. All rights reserved. | Terms of use | Privacy policy