Learn how to use jQuery at the Blog

Luigi Bormioli « visit

  • Added 9 months ago
  • 1652 Lines of Code shown
  • 2 Links of Interest
http://luigibormioli.com
This is my Source Code and I don't want to show it here
View Source Code only (as overlay)
// That code snippet belongs to Luigi Bormioli - http://luigibormioli.com

// Copyright (c) Luigi Bormioli (www.luigibormioli.com)
// Created by Superheroes (www.superhero.es) for BBDK (www.bbdk.com)

(function ($) {

  $.extend(com.luigibormioli,{products: {
    Guarantee: function () {

      var  self     = this,
          $open     = $('a#guarantee-open'),
          $view     = $('div#guarantee-view'),
          $mask     = $('div#guarantee-mask'),
          $content  = $('div#guarantee-content'),
          $close    = $('a#guarantee-close'),
           height   = $content.outerHeight(),
           position = height * -1;

      (function () {

        $mask.css({top: position});

        $open.bind('click',show);

      })();

      this.show = show;

      function show() {

        $open.unbind('click',show);

        $view.css({height: height});

        $mask.animate({top: 0},500,'easeInOutQuad',function () {

          $open.bind('click',hide);
  
          $close.bind('click',hide);
  
          $content.animate({opacity: 1},500,'easeInOutQuad');
  
        });
        
        return false;

      }

      function hide() {

        $open.unbind('click',hide);

        $close.unbind('click',hide);

        $content.animate({opacity: 0},500,'easeInOutQuad',function () {

          $mask.animate({top: position},500,'easeInOutQuad',function () {
  
            $view.css({height: 0});
    
            $open.bind('click',show);
    
          });
  
        });
        
        return false;

      }

    }
  }});

})(jQuery);



(function ($) {

  $.extend(com.luigibormioli.products,{
    CategoryList: function () {

      var $categories, $default, $window, active, categories, reset;

      (function () {

        $categories = $('ul#categories-list');

        // REFACTOR: PERFORMANCE
        $default = $categories.find('li.default');

        $window = $(window).one('CATEGORY_VIEW_OPEN',open);

        active = null;

        categories = {};

        reset = new com.luigibormioli.products.CategoryListReset;

        $categories
          .bind('CATEGORY_VIEW_OPEN',function (event,categoryIdentifier) {

              $window.trigger('VIEW_CONTROLLER_OPEN',[new com.luigibormioli.products.CategoryView(categoryIdentifier)]);

              return false;

            })
          .bind('mouseenter',function () {

              $categories.addClass('hover');

            })
          .bind('mouseleave',function () {

              $categories.removeClass('hover');

            })
          // REFACTOR: PERFORMANCE
          .find('li:not(li.default)')
          .each(function () {

              var category = new com.luigibormioli.products.CategoryListCategory($(this));

              categories[category._identifier] = category;

            });

      })();

      function close () {

        $window
          .unbind('COLLECTION_BROWSER_UNFILTER',close)
          .unbind('VIEW_CONTROLLER_ERROR',close)
          .one('CATEGORY_VIEW_OPEN',open);

        reset.disable();

        active.deselect();

        active = null;

        $default.addClass('selected');

      }

      function open (event,categoryIdentifier) {

        if (categories[categoryIdentifier]) {

          $window
            .one('COLLECTION_BROWSER_UNFILTER',close)
            .one('VIEW_CONTROLLER_ERROR',close);

          reset.enable();

          $default.removeClass('selected');

          active = categories[categoryIdentifier];

          active.select();

        }

      }

    },
    CategoryListCategory: function ($category) {

      var $link, identifier;

      (function () {

        $link = $category.find('a');

        identifier = $link.attr('rel');

        enable();

      })();

      this._identifier = identifier;

      this.deselect = deselect;

      this.select = select;

      function deselect () {

        enable();

        $category.removeClass('selected');

      }

      function disable () {

        $link.unbind('click',open);

      }

      function enable () {

        $link.bind('click',open);

      }

      function open () {

        $category.trigger('CATEGORY_VIEW_OPEN',[identifier]);

      }

      function select () {

        disable();

        $category.addClass('selected');

      }

    },
    CategoryListReset: function () {

      var $reset, $window;

      (function () {

        $reset = $('a#categories-reset');

        $window = $(window);

      })();

      this.disable = disable;

      this.enable = enable;

      function disable () {

        $reset
          .unbind('click',reset)
          .animate({opacity: 0},500,'easeInOutQuad',function () {

            $reset.css({visibility: 'hidden'});

          });

      }

      function enable () {

        $reset
          .stop()
          .one('click',reset)
          .css({visibility: 'visible'})
          .animate({opacity: 1},500,'easeInOutQuad');

      }

      function reset () {

        $window
          .trigger('COLLECTION_BROWSER_UNFILTER')
          .trigger('VIEW_CONTROLLER_CLOSE');

      }

    },
    ViewController: function () {

      var $body, $content, $view, $window, active, position;

      (function () {

        $body = $('html, body').attr('scrollTop',0);

        $content = $('div#view-content');

        $view = $('div#view');

        $window = $(window)
          .bind('VIEW_CONTROLLER_OPEN',open)
          .bind('VIEW_CONTROLLER_SUCCESS',function (event,scroll) {

              load(scroll);

            })
          .bind('VIEW_CONTROLLER_ERROR',function (event,message) {

              $content.html('<div id="view-description">' + message + '</div>');

              load();

            });

        active = null;

        position = $content.offset().top - 24;

        $.ajaxSetup({dataType: 'json',global: false,url: 'view.php',timeout: 5000});

      })();

      function close () {

        // DEBUG
        if ($.browser.msie) $content.css({visibility: 'hidden'});

        $view
          .queue([])
          .stop()
          .animate({opacity: 0},500,'easeInOutQuad')
          .animate({height: 0},1000,'easeInOutExpo',function () {

            $content
              .css({visibility: 'hidden'})
              .empty();

            $view.css({backgroundImage: 'url(/include/img/loading.gif)',overflow: 'hidden'});

          });

      }

      function load (scroll) {

        $view
          .animate({opacity: 0},500,'easeInOutQuad')
          .animate({height: $content.height()},1000,'easeInOutExpo',function () {

            if (scroll) $body.animate({scrollTop: position},1000,'easeInOutQuad');

            $content.css({visibility: 'visible'});

            $view
              .css({backgroundImage: 'none',overflow: 'visible'})
              .animate({opacity: 1},500,'easeInOutQuad');

            $window.trigger('VIEW_CONTROLLER_LOAD');

          });

      }

      function open (event,view) {

        $body.animate({scrollTop: 0},1000,'easeInOutQuad');

        if (active) $window.trigger('VIEW_CONTROLLER_CLOSE');

        active = view;

        $window.one('VIEW_CONTROLLER_CLOSE',close);

        $view
          .animate({height: 72},500,'easeInOutQuad')
          .animate({opacity: 1},500,'easeInOutQuad',request);

      }

      function request () {

        var cached = $.cache($.ajaxSettings.url + '?' + $.param($.ajaxSettings.data)),

          success = $.ajaxSettings.success;

        if (cached) success.apply(cached.scope,cached.arguments);

        else {

          $.ajaxSetup({success: function (response) {

                if (response) {

                  $.cache(this.url,{scope: this,arguments: arguments});

                  success.apply(this,arguments);

                }

                else $.ajaxSettings.error.call(this);

              }
            });

          $.ajax();

        }

      }

    },
    CollectionView: function (collectionIdentifier,itemIdentifier) {

      var $window;

      (function () {

        $window = $(window).one('VIEW_CONTROLLER_OPEN',function () {

            $window.trigger('COLLECTION_VIEW_OPEN',[collectionIdentifier]);

          });

        $.ajaxSetup({
          data: {collection: collectionIdentifier},
          success: function (response) {

            $('div#view-content').html(response.view);

            var $description = $('div#view-description'),

              $items = $('ul#view-items-list'),

              $reset = $('h2#view-reset a').bind('click',reset),

              $title = $('h1#view-title'),

              $subtitle = $title.find('span'),

              active = null,

              description = $description.html(),

              guarantee = new com.luigibormioli.products.Guarantee,

              items = {},

              loading = 0,

              scroller = new com.luigibormioli.products.CollectionViewItemScroller;

            $description.height($description.height());

            $window
              .one('VIEW_CONTROLLER_LOAD',open)
              .one('VIEW_CONTROLLER_CLOSE',close)
              .bind('COLLECTION_VIEW_SEEK',seek);

            $items
              .bind('COLLECTION_VIEW_ITEM_LOAD',load)
              .bind('COLLECTION_VIEW_SEEK',seek)
              .bind('COLLECTION_VIEW_FOCUS',focus)
              .find('li')
              .each(function () {

                  ++loading;

                  var item = new com.luigibormioli.products.CollectionViewItem($(this));

                  items[item._identifier] = item;

                });

            function close () {

              $window
                .unbind('VIEW_CONTROLLER_LOAD',open)
                .unbind('COLLECTION_VIEW_SEEK',seek);

              $items
                .unbind('COLLECTION_VIEW_ITEM_LOAD',load)
                .unbind('COLLECTION_VIEW_SEEK',seek)
                .unbind('COLLECTION_VIEW_FOCUS',focus);

              $reset.unbind('click',reset);

            }

            function focus (event,itemIdentifier) {

              if (itemIdentifier) {

                $subtitle
                  .html(items[itemIdentifier]._title)
                  .css({opacity: 1});

              }

              else {

                $subtitle
                  .html('')
                  .css({opacity: 0});

              }

              return false;

            }

            function load () {

              if (!--loading) {

                $items.unbind('COLLECTION_VIEW_ITEM_LOAD',load);

                $window.trigger('VIEW_CONTROLLER_SUCCESS',[true]);

              }

              return false;

            }

            function open () {

              $window.trigger('COLLECTION_VIEW_SEEK',[itemIdentifier]);

              return false;

            }

            function reset () {

              $window.trigger('COLLECTION_VIEW_SEEK');

            }

            function seek (event,itemIdentifier) {

              if (itemIdentifier) {

                if (active) {

                	if (itemIdentifier === active._identifier) return;

                  items[active._identifier] = active;

                  $subtitle.animate({opacity: 0},500,'easeInOutQuad');

                }

                active = items[itemIdentifier];

                delete items[itemIdentifier];

                active.disable();

                active.unfilter();

                $.each(items,function () {

                    this.disable();

                    this.filter();

                  });

                $description.animate({opacity: 0},500,'easeInOutQuad',function () {

                    $subtitle
                      .html(active._title)
                      .animate({opacity: 1},500,'easeInOutQuad');

                    $reset
                      .css({visibility: 'visible'})
                      .animate({opacity: 1},500,'easeInOutQuad');

                    $description
                      .html(active._description)
                      .animate({opacity: 1},500,'easeInOutQuad');

                  });

                scroller.seek(active._position);

              }

              else {

                if (active) {

                  items[active._identifier] = active;

                  active = null;

                  $subtitle.animate({opacity: 0},500,'easeInOutQuad',function () {

                      $subtitle.html('');

                    });

                  $reset.animate({opacity: 0},500,'easeInOutQuad',function () {

                      $reset.css({visibility: 'hidden'});

                    });

                  $description.animate({opacity: 0},500,'easeInOutQuad',function () {

                      $description
                        .html(description)
                        .animate({opacity: 1},500,'easeInOutQuad');

                    });


                }

                $.each(items,function () {

                    this.enable();

                    this.unfilter();

                  });

                scroller.seek();

              }

              return false;

            }

          },
          error: function () {

            $window.trigger('VIEW_CONTROLLER_ERROR',['An error occurred while loading a collection. Please try again.']);

          }
        });

      })();

    },
    CollectionViewItem: function ($item) {

      var $link, description, identifier, position, timer, title;

      (function () {

        // REFACTOR: PERFORMANCE
        $link = $item.children('a');

        description = $item.find('p').html();

        identifier = $link.attr('rel');

        position = $item.offset().left;

        timer = null;

        title = '&nbsp;/&nbsp;' + $item.find('h2').html();

        $(new Image)
          .one('load',function () {

              $item.trigger('COLLECTION_VIEW_ITEM_LOAD');

            })
          .attr('src',$link.find('img').attr('src'));

        enable();

      })();

      this._description = description;

      this._identifier = identifier;

      this._position = position;

      this._title = title;

      this.disable = disable;

      this.enable = enable;

      this.filter = filter;

      this.seek = seek;

      this.unfilter = unfilter;

      function blur () {

        $item.trigger('COLLECTION_VIEW_FOCUS');

      }

      function disable() {

        if ($.browser.msie) {

          stop();

          $item
            .unbind('mouseover',start)
            .unbind('mouseout',blur);

        }

        else {

          $item
            .unbind('mouseover',focus)
            .unbind('mouseout',blur);

        }

        $link
          .unbind('click',seek)
          .bind('click',reset);

      }

      function enable() {

        if ($.browser.msie) {

          $item
            .bind('mouseover',start)
            .bind('mouseout',blur);

        }

        else {

          $item
            .bind('mouseover',focus)
            .bind('mouseout',blur);

        }

        $link
          .unbind('click',reset)
          .bind('click',seek);

      }

      function filter () {

        $item.animate({opacity: .2},500,'easeInOutQuad');

      }

      function focus () {

        $item.trigger('COLLECTION_VIEW_FOCUS',[identifier]);

      }

      function reset () {

        $item.trigger('COLLECTION_VIEW_SEEK');

      }

      function seek () {

        $item.trigger('COLLECTION_VIEW_SEEK',[identifier]);

      }

      function start () {

        $item.bind('mouseout',stop);

        timer = setTimeout(focus,100);

      }

      function stop () {

        $item.unbind('mouseout',stop);

        clearTimeout(timer);

        timer = null;

      }

      function unfilter () {

        $item.animate({opacity: 1},500,'easeInOutQuad');

      }

    },
    CollectionViewItemScroller: function () {

      var $items, $scrollbar, $scroller, $window, active, currentPosition, itemsWidth, maximumDuration, maximumPosition, minimumPosition, positionOffset, positionRatio, targetPosition, timer;

      (function () {

        $items = $('ul#view-items-list');

        $scrollbar = $('div#collection-browser-scrollbar');

        $scroller = $('div#view-items').bind('mousemove',function (event) {

            targetPosition = (event.pageX * positionRatio) - positionOffset;

          });

        $window = $(window).bind('resize',function () {

            calculate();

            if (active) scroll(currentPosition,true);

          });

        active = true;

        currentPosition = $items.position().left;

        itemsWidth = $items.width();

        maximumDuration = 2000;

        maximumPosition = currentPosition;

        minimumPosition = null;

        positionOffset = currentPosition;

        positionRatio = null;

        targetPosition = null;

        timer = null;

        calculate();

        scroll(currentPosition);

      })();

      this.seek = seek;

      function calculate () {

        var scrollbarWidth = $scrollbar.width();

        minimumPosition = positionOffset;

        positionRatio = 0;

        if (itemsWidth > scrollbarWidth) {

          minimumPosition -= itemsWidth - scrollbarWidth;

          positionRatio = (itemsWidth - scrollbarWidth) / $window.width();

        }

      }

      function scroll (position,animate) {

        clearInterval(timer);

        timer = null;

        if (active) {

          if (position < minimumPosition) position = minimumPosition;

          else if (position > maximumPosition) position = maximumPosition;

        }

        if (animate) {

          var duration = (Math.abs(position - currentPosition) / maximumPosition) * maximumDuration;

          if (duration > maximumDuration) duration = maximumDuration;

          $items
            .stop()
            .animate({left: position},duration,'easeOutQuint',(active) ? start : null);

        }

        else {

          $items.css({left: position});

          start();

        }

        currentPosition = position;

        targetPosition = position * -1;

      }

      function seek (position) {

        if (position) {

          active = false;

          position = (positionOffset - position) + positionOffset;

        }

        else {

          active = true;

          position = currentPosition;

        }

        scroll(position,true);

      }

      function start () {

        timer = setInterval(function () {

            currentPosition -= (currentPosition - (targetPosition * -1)) / 10;

            $items
              .stop()
              .css({left: currentPosition});

          },1);

      }

    },
    CategoryView: function (categoryIdentifier) {

      var $window;

      (function () {

        $window = $(window)
          .one('VIEW_CONTROLLER_OPEN',function () {

              $window.trigger('CATEGORY_VIEW_OPEN',[categoryIdentifier]);

            })
          .trigger('COLLECTION_BROWSER_UNFILTER');

        $.ajaxSetup({
          data: {category: categoryIdentifier},
          success: function (response) {

            $('div#view-content').html(response.view);

            $window
              .trigger('COLLECTION_BROWSER_FILTER',[response.filter])
              .trigger('VIEW_CONTROLLER_SUCCESS');

          },
          error: function () {

            $window.trigger('VIEW_CONTROLLER_ERROR',['An error occurred while loading a category. Please try again.']);

          }
        });

      })();

    },
    CollectionBrowser: function () {

      var $window, active, collections, scrollbar;

      (function () {

        $window = $(window)
          .one('COLLECTION_VIEW_OPEN',open)
          .bind('COLLECTION_BROWSER_FILTER',function (event,results) {

              var position = null;

              $.each(collections,function (collectionIdentifier) {

                  $.each(this._items,function () {

                      if (!results[collectionIdentifier][this._identifier]) this.filter();

                      else if (!position) position = collections[collectionIdentifier]._position;

                    });

                });

              scrollbar.seek(position);

            })
          .bind('COLLECTION_BROWSER_UNFILTER',function () {

              $.each(collections,function () {

                  $.each(this._items,function () {

                      this.unfilter();

                    });

                });

              scrollbar.seek();

            });

        active = null;

        collections = {};

        scrollbar = new com.luigibormioli.products.CollectionBrowserScrollbar;

        $('div#collection-browser').bind('wheel',scrollbar.wheel);

        $('ul#collection-browser-list')
          .bind('COLLECTION_VIEW_OPEN',function (event,collectionIdentifier,itemIdentifier) {

              $window.trigger('VIEW_CONTROLLER_OPEN',[new com.luigibormioli.products.CollectionView(collectionIdentifier,itemIdentifier)]);

              return false;

            })
          .bind('COLLECTION_VIEW_SEEK',function (event,itemIdentifier) {

              $window.trigger('COLLECTION_VIEW_SEEK',[itemIdentifier]);

              return false;

            })
          .children('li')
          .each(function () {

              var collection = new com.luigibormioli.products.CollectionBrowserCollection($(this));

              collections[collection._identifier] = collection;

            });

      })();

      function close () {

        $window
          .unbind('VIEW_CONTROLLER_ERROR',close)
          .unbind('VIEW_CONTROLLER_CLOSE',close)
          .one('COLLECTION_VIEW_OPEN',open);

        active.deselect();

        active = null;

      }

      function open (event,collectionIdentifier) {

        if (collections[collectionIdentifier]) {

          $window
            .one('VIEW_CONTROLLER_ERROR',close)
            .one('VIEW_CONTROLLER_CLOSE',close);

          active = collections[collectionIdentifier];

          scrollbar.seek(active._position);

          active.select();

        }

      }

    },
    CollectionBrowserScrollbar: function () {

      var $collections, $handle, $scrollbar, collectionsOffset, collectionsWidth, handleHalfWidth, handlePosition, handleWidth, maximumDuration, maximumPosition, minimumPosition, positionRatio;

      (function () {

        $collections = $('ul#collection-browser-list');

        $handle = $('a#collection-browser-scrollbar-handle')
          .bind('dragstart',function () {

              $handle.addClass('hover');

            })
          .bind('drag',function (event) {

              var position = event.offsetX - collectionsOffset;

              scroll(position);

            })
          .bind('dragend',function () {

              $handle.removeClass('hover');

              return false;

            });

        $scrollbar = $('div#collection-browser-scrollbar')
          .bind('mousedown',function (event) {

            var position = event.pageX - handleHalfWidth - collectionsOffset;

            scroll(position,true);

          })
          .bind('wheel',wheel);

        collectionsOffset = $collections.position().left;

        collectionsWidth = $collections.width();

        handlePosition = $handle.position().left;

        handleWidth = $handle.width();

        handleHalfWidth = handleWidth / 2;

        maximumDuration = 1000;

        maximumPosition = null;

        minimumPosition = handlePosition;

        positionRatio = null;

        $(window).bind('resize',function () {

            var position = handlePosition / maximumPosition;

            calculate();

            position *= maximumPosition;

            scroll(position,true);

          });

        calculate();

      })();

      this.seek = seek;

      this.wheel = wheel;

      function calculate () {

        var scrollbarWidth = $scrollbar.width();

        maximumPosition = scrollbarWidth - handleWidth;

        if (handlePosition > maximumPosition) $handle.css({left: maximumPosition});

        positionRatio = ((collectionsWidth - scrollbarWidth) / maximumPosition) * -1;

      }

      function seek (position) {

        if (position) scroll(Math.abs((position - collectionsOffset) / positionRatio),true);

        else scroll(minimumPosition,true);

      }

      function scroll (position,animate) {

        if (position <= minimumPosition) {

          position = minimumPosition;

          $handle.css({cursor: 'e-resize'});

        }

        else if (position >= maximumPosition) {

          position = maximumPosition;

          $handle.css({cursor: 'w-resize'});

        }

        else $handle.css({cursor: 'ew-resize'});

        var collectionsPosition = (position * positionRatio) + collectionsOffset;

        if (animate) {

          $handle
            .queue([])
            .stop();


          $collections
            .queue([])
            .stop();

          var duration = (Math.abs(position - handlePosition) / maximumPosition) * maximumDuration;

          if (duration > maximumDuration) duration = maximumDuration;

          $handle.animate({left: position},duration,'easeOutQuint');

          $collections.animate({left: collectionsPosition},duration,'easeOutQuint');

        }

        else {

          $handle.css({left: position});

          $collections.css({left: collectionsPosition});

        }

        handlePosition = position;

      }

      function wheel (event,delta) {

        scroll(handlePosition + (((delta < 0) ? 1 : -1) * handleWidth),true);

        return false;

      }

    },
    CollectionBrowserCollection: function ($collection) {

      var $title, $subtitle, items, identifier, position;

      (function () {

        $title = $collection.find('h3 a');

        $subtitle = $collection.find('h4 a');

        items = {};

        identifier = $title.attr('rel');

        position = $collection.offset().left;

        $collection
          .find('ul')
          .bind('COLLECTION_VIEW_OPEN',function (event,itemIdentifier) {

              $collection.trigger('COLLECTION_VIEW_OPEN',[identifier,itemIdentifier]);

              return false;

            })
          .bind('COLLECTION_VIEW_SEEK',function (event,itemIdentifier) {

              $collection.trigger('COLLECTION_VIEW_SEEK',[itemIdentifier]);

              return false;

            })
          .find('li')
          .each(function () {

              var item = new com.luigibormioli.products.CollectionBrowserItem($(this));

              items[item._identifier] = item;

            });

        enable();

      })();

      this._items = items;

      this._identifier = identifier;

      this._position = position;

      this.deselect = deselect;

      this.select = select;

      function blur () {

        $.each(items,function () {

            this.hide();

          });

      }

      function deselect () {

        enable();

        $.each(items,function () {

            this.enable();

            this.hide();

          });

      }

      function disable () {

        $title
          .unbind('click',open)
          .unbind('mouseover',focus)
          .unbind('mouseout',blur)
          .bind('click',seek);

        $subtitle
          .unbind('click',open)
          .unbind('mouseover',focus)
          .unbind('mouseout',blur)
          .bind('click',seek);

      }

      function enable () {

        $title
          .unbind('click',seek)
          .bind('click',open)
          .bind('mouseover',focus)
          .bind('mouseout',blur);

        $subtitle
          .unbind('click',seek)
          .bind('click',open)
          .bind('mouseover',focus)
          .bind('mouseout',blur);

      }

      function focus () {

        $.each(items,function () {

            this.show();

          });

      }

      function open (event,itemIdentifier) {

        $collection.trigger('COLLECTION_VIEW_OPEN',[identifier,itemIdentifier]);

      }

      function seek (event,itemIdentifier) {

        $collection.trigger('COLLECTION_VIEW_SEEK',[itemIdentifier]);

      }

      function select () {

        disable();

        $.each(items,function () {

            this.disable();

            this.show();

          });

      }

    },
    CollectionBrowserItem: function ($item) {

      var $image, $link, identifier, filtered;

      (function () {

        $link = $item
          .find('a')
          .animate({opacity: 1},500,'easeInOutQuad');

        $image = $link.find('img');

        identifier = $link.attr('rel');

        filtered = false;

        var source = $image.attr('src');

        $(new Image)
          .one('load',function () {

              $link.animate({opacity: 0},500,'easeInOutQuad',function () {

                  $image.css({visibility: 'visible'});

                  $link
                    .css({background: 'transparent url(' + source + ') 0 -75px no-repeat'})
                    .animate({opacity: (filtered) ? .465 : 1},500,'easeInOutQuad');

                });

            })
          .attr('src',source);

        enable();

      })();

      this._identifier = identifier;

      this.disable = disable;

      this.enable = enable;

      this.filter = filter;

      this.hide = hide;

      this.show = show;

      this.unfilter = unfilter;

      function disable () {

        $link
          .unbind('mouseover',show)
          .unbind('focus',show)
          .unbind('mouseout',hide)
          .unbind('blur',hide)
          .unbind('click',open)
          .bind('click',seek);

      }

      function enable () {

        $link
          .unbind('click',seek)
          .bind('mouseover',show)
          .bind('focus',show)
          .bind('mouseout',hide)
          .bind('blur',hide)
          .bind('click',open);

      }

      function filter () {

        filtered = true;

        $link.animate({opacity: .465},500,'easeInOutQuad');

      }

      function hide () {

        if (filtered) $link.animate({opacity: .465},250,'easeInOutQuad');

        $image.animate({opacity: 1},250,'easeInOutQuad');

      }

      function open () {

        $item.trigger('COLLECTION_VIEW_OPEN',[identifier]);

      }

      function seek () {

        $item.trigger('COLLECTION_VIEW_SEEK',[identifier]);

      }

      function show () {

        if (filtered) $link
          .queue([])
          .stop()
          .animate({opacity: 1},250,'easeInOutQuad');

        $image
          .queue([])
          .stop()
          .animate({opacity: 0},250,'easeInOutQuad');

      }

      function unfilter () {

        filtered = false;

        $link.animate({opacity: 1},500,'easeInOutQuad');

      }

    },
    CollectionList: function () {

      var $window, active, collections;

      (function () {

        $window = $(window).one('COLLECTION_VIEW_OPEN',open);

        active = null;

        collections = {};

        $('ul#collection-list-list')
          .bind('COLLECTION_VIEW_OPEN',function (event,collectionIdentifier) {

              $window.trigger('VIEW_CONTROLLER_OPEN',[new com.luigibormioli.products.CollectionView(collectionIdentifier)]);

              return false;

            })
          .bind('COLLECTION_VIEW_SEEK',function () {

              $window.trigger('COLLECTION_VIEW_SEEK');

              return false;

            })
          .find('a')
          .each(function () {

              var collection = new com.luigibormioli.products.CollectionListCollection($(this));

              collections[collection._identifier] = collection;

            });

      })();

      function close () {

        $window
          .unbind('VIEW_CONTROLLER_ERROR',close)
          .unbind('VIEW_CONTROLLER_CLOSE',close)
          .one('COLLECTION_VIEW_OPEN',open);

        active.enable();

        active = null;

      }

      function open (event,collectionIdentifier) {

        if (collections[collectionIdentifier]) {

          $window
            .one('VIEW_CONTROLLER_ERROR',close)
            .one('VIEW_CONTROLLER_CLOSE',close);

          active = collections[collectionIdentifier];

          active.disable();

        }

      }

    },
    CollectionListCollection: function ($collection) {

      var identifier;

      (function () {

        identifier = $collection.attr('rel');

        enable();

      })();

      this._identifier = identifier;

      this.disable = disable;

      this.enable = enable;

      function disable () {

        $collection
          .unbind('click',open)
          .bind('click',seek);

      }

      function enable () {

        $collection
          .unbind('click',seek)
          .bind('click',open);

      }

      function open () {

        $collection.trigger('COLLECTION_VIEW_OPEN',[identifier]);

      }

      function seek () {

        $collection.trigger('COLLECTION_VIEW_SEEK');

      }

    }
  });

  $(function () {

    if (($.browser.msie && ($.browser.version < 6)) || ($.browser.safari && ($.browser.version < 500))) return false;

    new com.luigibormioli.products.CategoryList;

    new com.luigibormioli.products.ViewController;

    new com.luigibormioli.products.CollectionBrowser;

    new com.luigibormioli.products.CollectionList;

    var hash = location.hash.match(/^#\/(collection\/(\d+)(\/item\/(\d+))?|category\/(\d+))\/?$/);

    if (hash) {

      var view = (hash[2]) ?
        new com.luigibormioli.products.CollectionView(hash[2],(hash[4]) ? hash[4] : null) : (hash[5]) ?
          new com.luigibormioli.products.CategoryView(hash[5]) : null;

      if (view) $(window).trigger('VIEW_CONTROLLER_OPEN',[view]);

    }

  });

})(jQuery);