EllisLab text mark
Advanced Search
1 of 3
1
   
External Library for managing javascript and css files and code snippets
Posted: 04 January 2009 03:32 PM
Avatar
Joined: 2008-08-19
340 posts

EDIT: I’ve created a version 2 of this library here http://ellislab.com/forums/viewthread/181405/ - I’ve added a lot of features that were requested here, so if you liked this version, please check it out. Thanks!

I’ve created a library to manage javascript and css files and code snippets so that it’s very easy to set default files and include different files for individual pages.

You can download the package here http://www.darkhousemedia.com/snippets/ci/External_Library.zip

The usage is pretty simple (that’s the whole idea, right?).  First, you should autoload the External library so that you don’t have to add it to each controller’s constructor.

In a controller, you would use it like this:

class Home extends Controller {

    
function Home(){
        parent
::Controller();    
    
}
    
    
function index(){
        $this
->external->set(array(
            
'css' => 'css/form.css',
            
'js' => 'js/swfobject.js'
        
));

        
//or you can do this
        
$this->external->set_css('css/form.css');
        
$this->external->set_js('js/swfobject.js');
        
        
$this->load->view('home');
    
}

If you have multiple files, you can do this

class Home extends Controller {

    
function Home(){
        parent
::Controller();    
    
}
    
    
function index(){
        $this
->external->set(array(
            
'css' => array('css/master.css''css/form.css'),
            
'js' => array('js/jquery.js''js/swfobject.js')
        ));
        
$this->load->view('home');
    
}

But that’s not all, it also allows you to add javascript and css that may not necessarily reside in their own files.  And you can also add IE and IE6 specific items which uses conditional comments, like so

class Home extends Controller {

    
function Home(){
        parent
::Controller();    
    
}
    
    
function index(){
        $this
->external->set(array(
            
'css' => array(
                
'css/master.css',
                
'css/form.css',
                array(
'css/ie.css''ie'),
                array(
'css/ie6.css''ie6'),
                array(
'css/print.css''print'), //this would only be used if a user printed the page
                
array('.hide { display: none; }''custom'),
                array(
'#ie { background-color: #f00; }''ie_custom'),
                array(
'#ie6 { display: block; }''ie6_custom')
            ),
            
'js' => array(
                
'js/jquery.js',
                
'js/swfobject.js',
                array(
'js/ie.js''ie'),
                array(
'js/ie6.js''ie6'),
                array(
'alert("custom");''custom'),
                array(
'alert("You are using IE");''ie_custom'),
                array(
'alert("Stop using IE6");''ie6_custom')
            
)
        ));
        
$this->load->view('home');
    
}

Then all you need to do in your view is this

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
>
<
html >
    <
head>
        <
meta http-equiv="Content-type" content="text/html; charset=utf-8" />
        <
base href="<?=base_url()?>" />
        <
title>My Site</title>
        
<?php $this->external->run(); ?>
    
</head>
    <
body

Finally, it also uses a config file, so in the config folder you can add the file external.php with the following code

$config = array(
    
'all' => array(
        
'css' => array(
            
'css/reset.css'
            
'css/shortcuts.css'
            array(
'.png_bg {behavior: url(iepngfix.htc)}''ie6_custom')
        ),
        
'js' => array(
            
'js/functions.js',
            array(
'var base_url = "'.base_url().'";''custom'),
            array(
'js/ie_png_fix.js''ie6')    
        )
    ),
    
'default' => array('css' => 'css/master.css'),
    
'admin' => array('css' => 'css/admin/master.css')
); 

So as you can see I’ve set mine up with 3 keys in an array.  The ‘all’ key contains the javascript and css items that I want to load on every page of my site. 

The ‘admin’ key contains all the items it want to load if the user is in a uri that can be ‘admin/*/*/*...’.  This allows you to setup groups of items based on the uri.  In fact, you could control ALL of the javascript and css for your entire site from this one file if you wanted.  So, if you had something setup like ‘admin/login’ => array(...) and the user was trying to login to the admin, it would use all of the items in the ‘admin/login’ key, however it would NOT use any of the ones in the ‘admin’ key.  It finds the most specific key relating to the uri and then doesn’t look any further.

If it doesn’t find any items to use based on the uri, then it will use the ‘default’ key.  I set mine up so the homepage and any other page that isn’t in the admin area will use the ‘css/master.css’ file.

I hope this isn’t too confusing for anyone, I tried to make it as easy as possible to manage your external files and snippets.  I know I run into this a lot, so this library has certainly sped up my development time.

If anyone has any questions, feel free to ask.  Enjoy, and happy development!

 
Posted: 04 January 2009 03:34 PM   [ # 1 ]   [ Rating: 0 ]
Avatar
Joined: 2008-08-19
340 posts

I wanted to show the output in the previous post, but I ran out of characters, so here it is.  This library will produce something like this:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
>
<
html>
    <
head>
        <
meta http-equiv="Content-type" content="text/html; charset=utf-8" />
        <
base href="http://www.mysite.com/" />
        <
title>My Site</title>
        <
style type="text/css">
            @
import url("css/reset.css");
            @
import url("css/shortcuts.css");
            @
import url("css/master.css");
            @
import url("css/form.css");
        </
style>
        <!--
[if IE 6]><style type="text/css" media="screen">.png_bg {behaviorurl(iepngfix.htc)}</style><![endif]-->
        
[removed][removed]
        [removed][removed]
        
<!--[if IE 6]>[removed][removed]<![endif]-->
        
[removed]
            
// <![CDATA[
                
var base_url "http://www.mysite.com/";
            
// ]]>
        
[removed]
    
</head>
    <
body

Just so everyone can see the final product.

 
Posted: 04 January 2009 03:35 PM   [ # 2 ]   [ Rating: 0 ]
Avatar
Joined: 2008-08-19
340 posts

Hehe, ok well everyone that it says “removed” are javascript lines.  I forgot that I wouldn’t be able to show that in a forum post, but you can see where they go anyways.  This output was copied directly from a site I have running, I just changed the urls.

 
Posted: 04 January 2009 03:49 PM   [ # 3 ]   [ Rating: 0 ]
Joined: 2008-12-13
110 posts

Nice.

Thanks for sharing it with us. Going to give it a try today.

Maybe you should create a Wiki page for this and add your library there.

 
Posted: 04 January 2009 10:40 PM   [ # 4 ]   [ Rating: 0 ]
Avatar
Joined: 2009-01-03
22 posts

Awesome thanks alot.

Will definitely give this a shout come the time. Will let you know how it goes from a complete noob pov.

Cheers

a.g.r.c

 
Posted: 06 January 2009 03:00 PM   [ # 5 ]   [ Rating: 0 ]
Joined: 2009-01-06
6 posts

Hi,

Great lib only problem I’ve found is the use of short tags in the JS loading section.

I’ve had to edit the library to compensate for this but apart from that great.

Cheers
Adam

 
Posted: 06 January 2009 09:40 PM   [ # 6 ]   [ Rating: 0 ]
Avatar
Joined: 2008-08-19
340 posts

Hmm… can you give me an example, and what the fix was?  I’ll add it to the .zip

Thanks.

 
Posted: 07 January 2009 07:52 PM   [ # 7 ]   [ Rating: 0 ]
Joined: 2009-01-06
6 posts

Hi,

An example of where the short tags are used is -

if(count($this->ext['js']['file']) > 0):
            foreach(
$this->ext['js']['file'as $file):
            
?>
            [removed]<?
=$file ?>[removed]
            <?php
            
endforeach;
        endif; 

This doesn’t work if short tags are not enabled in the php.ini file. The line

[removed]<?=$file ?>[removed] 
needs to be changed to
[removed]<?php echo $file ?>[removed] 

.

Once all of those are altered then everything works with no problems. I’m using this library on my site now it’s helped so much as I use a fair amount of different CSS for the public pages and admin pages, loading it all at once was slower, now I can make the site load faster.

Cheers
Adam

 
Posted: 07 January 2009 09:10 PM   [ # 8 ]   [ Rating: 0 ]
Avatar
Joined: 2008-08-19
340 posts

Oohhh, gotcha.  I thought you meant javascript short tags, which is why I was confused because I had no clue what javascript short tags were.  I’ll change that.  I did it like that because CI has a setting to convert short tags so that you can still use them in your views, and originally this was a helper function.

Thanks for pointing that out.

Glad to hear it’s helping you out.  It’s definitely sped up my production.

 
Posted: 08 January 2009 12:02 AM   [ # 9 ]   [ Rating: 0 ]
Avatar
Joined: 2008-08-19
340 posts

I’ve edited the library file and got rid of all the php short tags.

http://www.darkhousemedia.com/snippets/ci/External_Library.zip

 
Posted: 09 January 2009 06:01 AM   [ # 10 ]   [ Rating: 0 ]
Joined: 2009-01-09
1 posts

Hi, I’m new to CI, but I am really interested to use it and I am happy to found quickly solutions like yours.
But I’ve got a question.
Your example throws out an error, that base_url() is not defined in config/external.php
If I uncomment this special line your script works well.
So I ask myself, why is base_url() undefined, because it’s autoloaded with the url_helper I think.
autoload.php contains these entries:

$autoload['libraries'= array('menu','external');
$autoload['helper'= array('url');
$autoload['config'= array('menu','external'); 

For me, this means the special url_helper function is not loaded at this point?!
Has this to do with the order of the variables above?
Maybe I missed something?

A second Question appears while working with that.

Am I right that I can’t set the order how the JS at example displayed?

I need something like

script src="soundmanager/script/soundmanager2.js" type="text/javascript" charset="utf-8">< /script>
script type="text/javascript" charset="utf-8" >
                
// <![CDATA[
                
                                    
var PP_CONFIG {
                                        autoStart
true,
                                      
flashVersion9,       // version of Flash to tell SoundManager to use - either 8 or 9. Flash 9 required for peak / spectrum data.
                                      
usePeakDatatrue,     // [Flash 9 only] whether or not to show peak data (left/right channel values) - nor noticable on CPU
                                      
useWaveformDatatrue// [Flash 9 only] show raw waveform data - WARNING: LIKELY VERY CPU-HEAVY
                                      
useEQDatatrue,      // [Flash 9 only] show EQ (frequency spectrum) data
                                      
useFavIcontrue,      // try to apply peakData to address bar (Firefox + Opera) - performance note: appears to make Firefox 3 do some temporary, heavy disk access/swapping/garbage collection at first(?)
                                      
useMovieStarfalse     // Flash 9.0r115+ only: Support for a subset of MPEG4 formats.
                                    
}
                
// ]]>
< /script>
script src="soundmanager/page-player.js" type="text/javascript" charset="utf-8">< /script

but first all external files are included and then the custom stuff.
So it would be better to write that in View files, right?
Thanks in advance
marcus

 
Posted: 09 January 2009 09:46 AM   [ # 11 ]   [ Rating: 0 ]
Avatar
Joined: 2008-08-19
340 posts

Yes, the base_url() function is a helper function.  The example I used was from a site I have running and I just stripped out most of the code.

Unfortunately you can’t control the order of files and custom code snippets, so your example won’t work, BUT, looking at the code in that custom section it doesn’t look like anything you’re generating at run time, so why can’t you just put that in a file?  The order of the files you CAN control.

 
Posted: 13 February 2009 05:31 PM   [ # 12 ]   [ Rating: 0 ]
Avatar
Joined: 2009-01-21
109 posts

I’ve written a similar library, called Carabiner. It’s a little different in methodology, though.

I really like how you can add CSS styles directly using your library.  That’s pretty slick! Great idea.

 Signature 

Do you use CSS or JavaScript? Carabiner makes your life easier.  I promise.

CI-Disqus makes playing with the Disqus API a snap.

 
Posted: 17 February 2009 03:10 PM   [ # 13 ]   [ Rating: 0 ]
Joined: 2008-05-11
20 posts

I wasn’t too thrilled about the lack of inheritance for subdirectories (e.g. ‘backend/category/edit’ will never inherit the css and js from ‘backend’) because it would force me to re-declare JS and CSS a million times throughout my config file, so I changed the library a bit:

Find:

for($i 0$i $total_segments$i++){
                $uri_key 
implode('/'$uri);
                if(isset(
$groups[$uri_key])){
                    $this
->set($groups[$uri_key]);
                    
$success true;
                    break;
                
}
                array_pop
($uri);
            

Replace:

for($i 1$i <= $total_segments$i++)
            
{
                $uri_key 
implode('/'array_slice($uri0$i));
                if(isset(
$groups[$uri_key]))
                
{
                    $this
->set($groups[$uri_key]);
                    
$success true;
                
}
            } 

Just in case anyone was wanting to do the same. It’s saved me a lot of repetitive includes already. smile

Summary for anyone who didn’t follow what I’m talking about:  The code change allows you to include, say, jquery.js and jquery.ui.js for “backend” which will then be inherited by every child page like “backend/settings/” or “backend/category/add/1/”…

Actually, I just realized I wouldn’t have been able to use this library at all (using the much easier “config” method… I don’t want to spread my JS/CSS all over the controllers), because my TinyMCE editor would need to be included on the Add/Edit pages for entries, and those URIs end with the Entry ID.  I’d then have to include the TinyMCE code under “all” and there was no way I would do that. hah.

Thanks for the nice library!

EDIT: I actually thought about controlling the depth to search by making the URI keys in the config use REGEX, or my own proprietary method, but I’m deciding now if it’s worth doing. smile

Say, ‘backend[:4]’ would look up to 4 directories deep. Or ‘backend[:all]’ would have no limit. Also, ‘backend/some/directory[:override]’ would override the “defaults” from ‘backend’ and they wouldn’t be included. And it would prevent the code from even looping through the parent directories.

Just a thought.  Maybe I’ll update this soon.

 
Posted: 18 February 2009 12:52 AM   [ # 14 ]   [ Rating: 0 ]
Avatar
Joined: 2008-08-19
340 posts

Ah, I see what you mean.  I guess it never really affected me because I use my config file for setting up the default css and js to use throughout the major sections, and then add the page specific items right in the controllers.  I originally made it break the loop once it found the most specific uri to include to make sure it didn’t load anything that was unnecessary, but I see now that was backwards thinking.  It should include all items with ‘backend’ and it’s up to the developer to setup the different uri’s properly.

Thanks for the code change, I’ll incorporate that in my library and maybe look at your other suggestions.  I think I might have an idea or 2 of my own, so maybe a v1.1 is necessary.

 
Posted: 20 February 2009 12:45 PM   [ # 15 ]   [ Rating: 0 ]
Avatar
Joined: 2009-02-19
4534 posts

This looks exactly what I need and will be quite useful.  Thank you.  Ive built custom stuff like this in my own frameworks before I started using CI.

 Signature 
 
1 of 3
1