Joining Plugin Stylesheets

Discussions and requests related to new CMSimple features, plugins, templates etc. and how to develop.
Please don't ask for support at this forums!
cmb
Posts: 12766
Joined: Tue Jun 21, 2011 11:04 am
Location: Mü-Sa, RLP, DE
Contact:

Joining Plugin Stylesheets

Post by cmb » Fri Jun 29, 2012 6:27 pm

Hello Community,

CMSimple includes a <link rel="stylesheet" ...> for each plugin stylesheet in the <head>. Unless the stylesheets are already cached in the browser, this results in several separate HTTP GET requests, which slows down the first access to a CMSimple powered website (might be a problem for overloaded servers as well as mobile networks). IMO joining all these stylesheets should be implemented and can easily be done by dynamically creating a cached stylesheet (say css/plugins.css) and linking only this one from the <head>.

Please note that there is a limit on stylesheets per page and on selectors per stylesheet in IE.

Christoph
Christoph M. Becker –Plugins for CMSimple_XH, but not for CMSimple 4+

Holger
Site Admin
Posts: 2880
Joined: Mon May 19, 2008 7:10 pm
Location: Hessen, Germany
Contact:

Re: Joining Plugin Stylesheets

Post by Holger » Sat Jun 30, 2012 11:10 am

Hi Christoph,

I was not aware about that limitations in IE.

So I think joining it's a good idea. And if you say "it can easily be done": +1 ;)

Holger

simpleSolutions.dk
Posts: 147
Joined: Thu Oct 06, 2011 7:00 am

Re: Joining Plugin Stylesheets

Post by simpleSolutions.dk » Sun Jul 01, 2012 10:33 pm

Hi Christoph

It will be a great optimization of CMSimple.

cmb
Posts: 12766
Joined: Tue Jun 21, 2011 11:04 am
Location: Mü-Sa, RLP, DE
Contact:

Re: Joining Plugin Stylesheets

Post by cmb » Mon Jul 02, 2012 2:44 pm

Hi Holger, hi Jerry,

I gave it try, and faced a problem: if the stylesheets contain relative URLs (e.g. for background-image), those won't work anymore in the combined stylesheet (as this has to be stored in another location). A simple solution would be to do a preg_replace() on url(...) changing the URL. But that won't work for directly entered URLs. Do you think this is a problem?

Otherwise the following patch against plugin/index.php of CMSimple_XH 1.5.3 should suffice (error handling and reporting has to be added, though). The combined file will be stored as css/plugins.css, so css/ has to be writable.

Code: Select all

Index: index.php
===================================================================
--- index.php    (revision 17)
+++ index.php    (working copy)
@@ -271,10 +271,12 @@
 
         // Add plugin css to the header of CMSimple/Template
         if (file_exists($pth['file']['plugin_stylesheet'])) {
-            $hjs .= tag('link rel="stylesheet" href="' . $pth['file']['plugin_stylesheet'] . '" type="text/css"') . "\n";
+            //$hjs .= tag('link rel="stylesheet" href="' . $pth['file']['plugin_stylesheet'] . '" type="text/css"') . "\n";
+        $Plugin_stylesheets[] = $plugin;
         }
     } // if($plugin)
 } // while (FALSE !== ($plugin = readdir($handle)))
+Plugin_stylesheet($Plugin_stylesheets);
 
 
 /**
@@ -900,4 +902,62 @@
     }
 }
 
-?>
\ No newline at end of file
+
+/**
+ * Includes a <link> to the combined plugin stylesheet in the <head>.
+ * If necessary, this stylesheet will be created/updated.
+ *
+ * @global string $hjs
+ * @param array $plugins  The list of plugins having a stylesheet.css.
+ * @return void
+ */
+// TODO: error checking and reporting
+function Plugin_stylesheet($plugins)
+{
+    global $hjs, $pth;
+
+    $ofn = $pth['folder']['base'] . 'css/plugins.css';
+    $expired = !file_exists($ofn);
+
+    // check for newly installed/uninstalled plugins
+    if (!$expired) {
+    $ofp = fopen($ofn, 'r');
+    fgets($ofp, 4096);
+    $oldPlugins = explode(',', fgets($ofp, 4096));
+    fclose($ofp);
+    $expired = $plugins == $oldPlugins;
+    }
+
+    // check for changes in the individual plugin stylesheets
+    if (!$expired) {
+    foreach ($plugins as $plugin) {
+        $fn = $pth['folder']['plugins'] . $plugin . '/css/stylesheet.css';
+        if (filemtime($fn) > filemtime($ofn)) {
+        $expired = true;
+        break;
+        }
+    }
+    }
+
+    // create combined plugin stylesheet
+    if ($expired) {
+    $o = array();
+    foreach ($plugins as $plugin) {
+        $fn = $pth['folder']['plugins'] . $plugin . '/css/stylesheet.css';
+        $css = file_get_contents($fn);
+        $css = preg_replace('/url\(\s*["\']?(?!\/|http[s]?:)(.*?)["\']?\s*\)/u',
+        "url('../plugins/$plugin/css/\$1')", $css);
+        $css = '/*' . str_repeat('*', 72 - strlen($fn)) . $fn . " */\n\n" . $css;
+        $o[] = $css;
+    }
+    $o = "/*\nAutomatically created by " . CMSIMPLE_XH_VERSION . ". DO NOT MODIFY!\n"
+        . implode(',', $plugins) . "\n*/\n\n" . implode("\n\n", $o);
+    $ofp = fopen($ofn, 'w');
+    fwrite($ofp, $o);
+    fclose($ofp);
+    }
+
+    $hjs .= tag('link rel="stylesheet" href="' . $ofn . '" type="text/css"') . "\n";
+}
+
+?>
Christoph
Christoph M. Becker –Plugins for CMSimple_XH, but not for CMSimple 4+

simpleSolutions.dk
Posts: 147
Joined: Thu Oct 06, 2011 7:00 am

Re: Joining Plugin Stylesheets

Post by simpleSolutions.dk » Mon Jul 02, 2012 3:53 pm

Hi Christoph

Relative urls aren't a big problem. It's only necessary to correct them to absolute urls once after installation of the new CMSimple version. It can be explained in documentation. The joined css is still a great idea. I try to find time to test your code.

cmb
Posts: 12766
Joined: Tue Jun 21, 2011 11:04 am
Location: Mü-Sa, RLP, DE
Contact:

Re: Joining Plugin Stylesheets

Post by cmb » Mon Jul 02, 2012 5:28 pm

Hi Jerry,
simpleSolutions.dk wrote:Relative urls aren't a big problem. It's only necessary to correct them to absolute urls once after installation of the new CMSimple version.
And everytime a new plugin gets installed. But I guess that URLs are rarely contained in plugin stylesheets.
simpleSolutions.dk wrote:I try to find time to test your code.
That would be nice. :)

Christoph
Christoph M. Becker –Plugins for CMSimple_XH, but not for CMSimple 4+

simpleSolutions.dk
Posts: 147
Joined: Thu Oct 06, 2011 7:00 am

Re: Joining Plugin Stylesheets

Post by simpleSolutions.dk » Mon Jul 02, 2012 6:26 pm

Hi Christoph
And everytime a new plugin gets installed. But I guess that URLs are rarely contained in plugin stylesheets.
According to a revised plugin manual has all new plugins absolute urls in stylesheets.

I have no idea if it will be possible to parse urls from config.php into styesheet when joining stylesheets, but it will make the stylesheets a bit more flexible. Something like background-imege: url(cf_plugin[x][y]); and cf_plugin[x][y] contains an url.
Last edited by simpleSolutions.dk on Tue Jul 03, 2012 2:46 pm, edited 1 time in total.

simpleSolutions.dk
Posts: 147
Joined: Thu Oct 06, 2011 7:00 am

Re: Joining Plugin Stylesheets

Post by simpleSolutions.dk » Tue Jul 03, 2012 1:37 pm

Hi Christoph

It works and what a wonderfull view only one stylesheet file for all plugins.

I use a background url only in ImageSlider plugin and it is an absolute url.
It is possible to replace urls in styelsheets with content from configuration file but after all I think it will confuse more then help.

cmb
Posts: 12766
Joined: Tue Jun 21, 2011 11:04 am
Location: Mü-Sa, RLP, DE
Contact:

Re: Joining Plugin Stylesheets

Post by cmb » Tue Jul 03, 2012 2:09 pm

Hi Jerry,
simpleSolutions.dk wrote:It works and what a wonderfull view only one stylesheet file for all plugins.
I'm glad you like it. :)

I forgot to mention a minor (?) issue: when inspecting the styling in the developer tools of a browser, the place of the definition doesn't point to the original file, so it might be harder to find and change the styles in the file. So if the combining of the plugin stylesheets will be implemented, it might be a good idea to allow to switch it off temporarily (another config option :?).
simpleSolutions.dk wrote:I have no idea if it will be possible to parse urls from config.php into styesheet when joining stylesheets, but it will make the stylesheets a bit more flexible. Something like background-imege: url(cf_plugin[x][y]); and cf_plugin[x][y] contains an url.
Parsing the stylesheets for config options and replacing them with the actual values should be no problem. But I'm not sure, if it's reasonable to do so. Consider your example: if the user edits the stylesheet, it might be simpler to insert the URL directly, instead of changing it in the plugin config. If a plugin wants to give the user the possibility to change this in the configuration, it could output the config option as inline style:

Code: Select all

$o .= '<div id="plugin_div" style="background-image: url(' . $plugin_cf['plugin']['option'] . ')">'; 
A user can still override this style in the stylesheet:

Code: Select all

#plugin_div {background-image: url(./path/to/image) !important}
What do others think about the config options in the stylesheet?

Christoph
Christoph M. Becker –Plugins for CMSimple_XH, but not for CMSimple 4+

simpleSolutions.dk
Posts: 147
Joined: Thu Oct 06, 2011 7:00 am

Re: Joining Plugin Stylesheets

Post by simpleSolutions.dk » Tue Jul 03, 2012 2:43 pm

Hi Christooph
What do others think about the config options in the stylesheet?
As I mentioned in mine last post parsing of config values in stylesheet will be confusing and is a bad idea for the same reasons you gave.
I forgot to mention a minor (?) issue: when inspecting the styling in the developer tools of a browser, the place of the definition doesn't point to the original file, so it might be harder to find and change the styles in the file.
You insert a path to each joined plugin so it is no problem to identify where styleshets can be found. It should be enough to identify the file.

Post Reply