sexy slideshow with prototype and script.aculo.us

this here is a little slideshow made in prototype javascript and scriptaculous

NatashaVojnovic-Rafael-JesusIsMyHomeboy-DavidLaChapelle-iD2003Sept-zobSJParkerSexInSubwayVOGUE_ALICIA_DOG_DPRVOGUE_AGUILERA_CARW020051104474662908920

  • Facebook profile can tell you if a person is extroverted, but not if they’re neurotic: http://ow.ly/IhQB
  • What is
    “first instance of a nonhuman mammal changing its voice to advertise her peak of fertility”?
  • Dmbryonic Stem Cell Research Begins With $21 Million from Obama: http://ow.ly/HWoT via @ScienceInsider
  • IMice genetically derived
    from two mothers are smaller and live 30% longer than normally bred mice. http://ow.ly/HUu2

©pictures by David LaChapelle

the only thing which needs to be there is the script of course and those little divs:

<div id="cover"></div>
<div id="slideshowWrapper"> </div>

the content of the slideshow is everything in a div:

<div class="article-content">
      <img title="rel. url" alt="" />
      <img title="rel. url" alt="" />
      ....
<ul>
	<li>quote</li>
	<li>quote1</li>
	<li>quote2</li>
...</ul>
.....</div>

the pictures inside #article-content are taken right away if they have a title with the relative url to the picture. the quotes are from a list like this:

...
images: $$('div.article-content img[title]'),
text:   $$('div.article-content ul li'),
container: $('slideshowWrapper'),
...

/*
@author: Nils M. Petersohn
*/
 
$$('div.article-content').each(function(el){el.hide();});	
 
if (Object.isUndefined(Cygl)) { var Cygl = { } }
 
Cygl.Slideshow = Class.create({
 
    initialize: function() {
        this.options = Object.extend({
            images: $$('div.article-content img[title]'),
            text:   $$('div.article-content ul li'),
            container: $('slideshowWrapper'),
            completeLoops: 3,
            duration: 4,
            showTime: 8
        }, arguments[0] || { });
 
        var that = this;
        this.start = true;
        this.faster = false;
        this.delay = 0;
        this.delayText = 0;
        this.orginalSize = this.options.container.getStyle('width').replace("px","");
 
        this.options.images.each(function(el){el.hide();});
        this.options.text.each(function(el){el.hide()});
 
        var cont = this.options.container;
        var z = this.options.images.length;
 
        this.options.text.each(function(el){
            internalContainer = new Element('div', { 'class': 'quoteContainer','style':'z-index:1000;display:none'})
            internalContainer.insert(new Element('span', { 'class': 'quote'  }).update(el.innerHTML));//
            cont.insert(internalContainer);
        });
        this.options.images.each(function(el){
            internalContainer = new Element('div', { 'class': 'imageContainer','style':'z-index:' + z-- })
            internalContainer.insert(new Element('img', { 'class': 'sildeshowImage', src: "/"+el.title }));
            cont.insert(internalContainer);
        });	
 
        this.loop();
 
    },
 
    loop: function(){
 
        var cont = this.options.container;
        var that = this;
        var switcher = false;
 
        var images = $$('div.imageContainer');
        var quotes = $$('div.quoteContainer');
        var j=1;
        $R(1 ,this.options.completeLoops * images.length ).each(function(i){
 
            images.each(function(el){ 
 
                if(el.getStyle('z-Index') != 1)  that.moveEl(el,switcher);
                if(j % that.options.images.length == 0)  switcher = !switcher;
 
                j++;
 
            });
 
            images.reverse();
 
            quotes.each(function(el){
                that.moveElText(el,switcher);
            });
 
        });
 
    },
 
    moveEl: function(el,direction){
 
        new Effect.Morph(el,{style: {width: ((!direction)?'0':this.orginalSize)+'px' }, delay:this.delay, duration:this.options.duration});
 
        this.delay = this.delay + this.options.duration + this.options.showTime;
 
        var that = this;
        if(this.start){
            $$('div.quoteContainer').each(function(el){
                that.moveElText(el,direction);
            });
            this.start = false;
        }
 
    },
 
    moveElText: function(el,direction){
 
        new Effect.Appear(el, { delay:this.delayText, duration:this.options.duration , queue: 'end' } );
        new Effect.Fade(el,  { delay:this.delayText + this.options.showTime / 2 , duration:this.options.duration, queue: 'end' });
        this.delayText = this.delayText + this.options.duration  ;
 
    }
});
 
Event.observe(window, 'load', function() {
  $$('div.article-content').each(function(el){el.show();});
  new Cygl.Slideshow() ;
  new Effect.Fade('cover', {duration:4});
});
#slideshowWrapper, .sildeshowImage, .imageContainer, .quoteContainer,#cover {
	height:500px;
	width:700px;
       -webkit-border-top-left-radius:10px;
	-webkit-border-top-right-radius:10px;
	-webkit-border-bottom-left-radius:10px;
	-webkit-border-bottom-right-radius:10px;
	-moz-border-radius: 10px;
	border-spacing: 0px;
}
.imageContainer{
	position:absolute;
	overflow:hidden;
}
#cover{
	height:503px;
	width:703px;
	position:absolute;
	z-index:2000;
	background:#ECE3BA;
}
#slideshowWrapper{
	border: 1px inset #ECE3BA;
	overflow:hidden;
 
}
#container img.sildeshowImage{
	margin:0px;
}
.quoteContainer{
	position:absolute;
	overflow:hidden;
}
.quote{
	-webkit-border-top-left-radius:10px;
	-webkit-border-top-right-radius:10px;
	-webkit-border-bottom-left-radius:10px;
	-webkit-border-bottom-right-radius:10px;
	-moz-border-radius: 10px;
	font-family:"Palatino Linotype", "Book Antiqua", Palatino, serif;
	background-color:#333 ;
	color:white;
	font-weight:lighter;
	margin:20px;
	padding:10px;
	width:660px;
	font-size:50px;
	line-height:60px;
	-moz-opacity:0.4;
	filter:alpha(opacity=40);
	opacity: 0.4;
	position:absolute;
}
 
#debug{
	width:700px;
	height:200px;
}

reading a reflexive association in a recursive way for grails and groovy

Imagine you have a Menu with multiple items, those items have multiple items and so on. The Menu Items also depend on a Role a User has in the Application Context like ‘ROLE_ADMIN’, ‘ROLE_COOK’, ‘ROLE_SOME’ …
I think the best practice is to save the menu items as a reflexive association in a database table like this:

class MenuItem {
 
    Long id;
    String label;
    Boolean topLevel;
    Integer position;
 
    static hasMany = [roles:Role, childs:MenuItem]
    static belongsTo = [parent:MenuItem]
 
    static mapping = {
        topLevel type:'true_false'
        childs sort:'position'
    }
    static constraints = {
    }
 
    String toString() {
        "[MenuItem id: ${id}, label: ${label}, pos: ${position}]"
    }
 
}

so lets initialize some dummy menu Items:

def file =new MenuItem(label:'file', position:1,topLevel:true,parent:null, roles:[[somerole,cookrole,adminrole]).save();
def view =new MenuItem(label:'view', position:2,topLevel:true,parent:null, roles:[cookrole,adminrole]).save();
def help =new MenuItem(label:'help', position:2,topLevel:true,parent:null, roles:[someroleadminrole]).save();
def logout =new MenuItem(label:'logout', position:2,topLevel:true,parent:null, roles:[somerole,cookrole,adminrole]).save();

those 4 toplevel MenuItems have different roles assiciated with them, for example the view menu can only be accessed by a user wich has the cookrole or the adminrole. the roles have also the property of a level as a number which is zero for an admin user and one for a role which has less rights than the admin. the algorithm then extracts the hightest role from a user instance.
so lets insert some submenus to the database table:

new MenuItem(label:'save File', position:1,topLevel:false,parent:file, roles:[[somerole,cookrole,adminrole]).save();
new MenuItem(label:'save All Files', position:2,topLevel:false,parent:file, roles:[[somerole,cookrole,adminrole]).save();
def serivces = new MenuItem(label:'services', position:3,topLevel:false,parent:file, roles:[[somerole,cookrole,adminrole]).save();
new MenuItem(label:'capture Image', position:1,topLevel:false,parent:serivces, roles:[[somerole,cookrole,adminrole]).save();
new MenuItem(label:'send As Email', position:2,topLevel:false,parent:serivces, roles:[[somerole,adminrole]).save();

notice that the last menu item (send As Email) is not accessible for the cookrole
We now have a three dimensional menu like this:

  • file
    • save File
    • save All Files
    • services
      • capture Image
      • send As Email
  • view
  • help
  • logout

here is the code to render this menu structure in a controller and send it to the view:

class MainController {
 
    def authenticateService
    def testUser = null
    def menuItems = [:]
 
    void populateMenuItems(map,hightestRole){
 
        //fill the first time with topLevel Items
        if(menuItems.isEmpty()){
            map.each({
                    if(it.roles.contains(hightestRole))
                        menuItems[it] = [:]
            })
        }
 
        menuItems.each({ mi ->
 
                MenuItem.findAllByParent(mi.key).each({ subMi ->
 
                        if(subMi.roles.contains(hightestRole)){
                            mi.value[subMi] = [:]
 
                            findMore( mi.value[subMi],subMi)
                        }
                })
 
        })
    }
 
    void findMore(mapEntry,mi){
 
        def moreItems = MenuItem.findAllByParent(mi)
 
        if(!moreItems.isEmpty()){
 
            moreItems.each({
                    mapEntry[it] = [:]
                    findMore(mapEntry[it],it) //recursive call
            })
 
        }
    }
 
    def index = {
 
        def hightestRole = null
        def principal = (testUser != null)? testUser : authenticateService.principal();
        def itRole
 
        principal.getAuthorities().each({
 
                itRole = Role.findByAuthority(it.authority)
 
                if(hightestRole == null || ( hightestRole != null && itRole.level < hightestRole.level))
                    hightestRole = itRole
 
        })
 
        populateMenuItems( MenuItem.findAllByTopLevel( true, [sort: 'position', order: 'asc'] ), hightestRole )
 
        return [
                    highestRole:hightestRole,
                    menuItems:menuItems,
                    user: principal
                ]
    }
}

the function populateMenuItems calls the function findMore which calls itself recursively as long as a submenu for some item exists.

here are some integation tests for this:

def miSaveFile = MenuItem.findByLabel('save File')
def miSendAsEmail = MenuItem.findByLabel('send As Email')
 
def user = User.get(2)
assertEquals "bestcook", user.username
 
controller.testUser = user;
def model =  controller.index()
 
assertEquals "bestcook", model["bestcook"]?.username
assertEquals Role.findByAuthority("ROLE_COOK"),model["highestRole"]
assertFalse SearchNestedHash.search(model, miSendAsEmail)
assertTrue SearchNestedHash.search(model, miSaveFile)

the SearchNestedHash class is explained in my previous article.

recursive search on a nested (multidimensional) collection for groovy

you can search for any object in a nested list containing hash’s and lists recursively, check out the tests for examples:

here are the tests:

class SearchNestedHashTests extends GrailsUnitTestCase {
    protected void setUp() {
        super.setUp()
    }
    protected void tearDown() {
        super.tearDown()
    }
    void testHashMap(){
 
            def map = [
                            'x' , 'y', 's'
                         ]
 
            assertTrue SearchNestedHash.search(map,'x')
 
            def a = 'a'
            def b = false
            def c = 1
 
            map= [
                        [[a,b] : c] : 'y'
                   ]
 
            assertTrue SearchNestedHash.search(map,a)
            assertTrue SearchNestedHash.search(map,b)
            assertTrue SearchNestedHash.search(map,c)
            assertTrue SearchNestedHash.search(map,false)
 
            map = [
                           'y' : 'null'
                       ]
 
            assertFalse SearchNestedHash.search(map,'x')
 
            map = [
                           'x':'null'
                       ]
 
            assertTrue SearchNestedHash.search(map,'x')
 
            map = [
                        ['n' : 'y'] : 'x'
                    ]
 
            assertFalse SearchNestedHash.search(map,'t')
            assertFalse SearchNestedHash.search(map,null)
            assertTrue SearchNestedHash.search(map,'x')
 
            map= [
                        ['n' : 'x'] : 'y'
                    ]
 
            assertTrue SearchNestedHash.search(map,'x')
 
            map = [
                        ['x' : 'n'] : 'y'
                    ]
 
            assertTrue SearchNestedHash.search(map,'x')
 
            map= [
                        [['x':'z'] : 'n'] : 'y'
                    ]
 
            assertTrue SearchNestedHash.search(map,'x')
 
            map= [
                        [['c':'x'] : 'n'] : null
                    ]
 
            assertTrue SearchNestedHash.search(map,'x')
 
            def x = ['a':'b']
 
            map= [
                        [['y': x ] : null] : 'y'
                    ]
 
            assertTrue SearchNestedHash.search(map,x)
 
            map= [
                        [['y': ['a':'b'] ] : null] : 'y'
                    ]
 
            assertTrue SearchNestedHash.search(map,x)
 
            map= [
                        [['s':'x'] : null] : 'y'
                    ]
 
            assertTrue SearchNestedHash.search(map,'x')
 
            def crazyMap = [
                        [['c':'v'] : [['c':[['c':[[[[['xxsxx':'v'] : [['c':[['c':[[[          'X'            :'v']:'v']:'v']]:'v']]:'v']]:'v']:'v']:'v']]:'v']]:'v']] : 'y'
                    ]
 
            assertFalse SearchNestedHash.search(crazyMap,'q')
            assertFalse SearchNestedHash.search(crazyMap,'x')//only the capital X is inside
            assertTrue  SearchNestedHash.search(crazyMap,'X')//only the capital X is inside
            assertTrue  SearchNestedHash.search(crazyMap,['xxsxx':'v'])
 
     }
}

here is the Class:

class SearchNestedHash {
    static def found = false;
 
    static synchronized search(collection,targetObj){
        found = false;
        return searchRec(collection,targetObj)
    }
 
    static synchronized searchRec(collection, targetObj){
 
        if(collection instanceof List && collection.contains(targetObj))
            return true
 
        collection.each({
 
                if(
                    (
                        collection instanceof Map
                        &&
                        (
                            it.key == targetObj ||
                            it.value == targetObj ||
                            it.key    instanceof List && it.key    .contains(targetObj) ||
                            it.value instanceof List && it.value .contains(targetObj)
                        )
                    )
                        ||
                    (
                        it instanceof List && it == targetObj
                    )
 
                ){found = true;return}
            })
 
        if(!found){
 
            collection.each({
 
                    if(it.key instanceof Map)
                    searchRec(it.key,targetObj)
 
                    if(it.value instanceof Map)
                    searchRec(it.value,targetObj)
 
                    if(it instanceof List)
                    searchRec(it,targetObj)
 
                })
 
        }
        return found
    }
 
}