CrazySquirrel/CSShare

View on GitHub
js/jquery.CSTiles-1.1.0.js

Summary

Maintainability
F
1 wk
Test Coverage
/**
 * CrazySquirrel
 * http://crazysquirrel.ru/
 *
 * @author Yastrebov Sergey
 * @version 1.0.0
 * @copyright 2015 CrazySquirrel
 */

;(function ( $ ) {
    "use strict";
    
    if(typeof $.CrazySquirrel === "undefined"){
        $.CrazySquirrel = {};
    }

    /**
     * Class of tiles viewer
     * 
     * @namespace CrazySquirrel
     * @class Tiles
     * @param {JQuery object} that [JQuery object]
     * @param {object} settings [object with tiles setings]
     */
    $.CrazySquirrel.Tiles = function(that, settings){
        /**
         * Pointer to this object
         * @type {object}
         */
        var base = this;
        base.that = that.get(0);
        
        /**
         * Search for more suitable parameters for the grid
         * @param  {array} optionSize  [array with size]
         * @param  {array} defaultSize [default sizes]
         * @return {array} size        [result sizes]
         */
        base.getsize = function(optionSize,defaultSize){
            var size = [];
            if(optionSize){
                if(Array.isArray(optionSize)){
                    if(optionSize.length === 0){
                        size =  defaultSize;
                    }else{
                        if(optionSize[0]*1 && optionSize[0]*1 > 0){
                            size[0] = optionSize[0]*1;
                        }else{
                            size[0] = defaultSize[0];
                        }
                        if(optionSize.length > 1){
                            if(optionSize[1]*1 && optionSize[1]*1 > 0){
                                size[1] = optionSize[1]*1;
                            }else{
                                size[1] = defaultSize[1];
                            }
                        }else{
                            size[1] = size[0];
                        }
                    }
                }else{
                    if(optionSize*1 && optionSize*1 > 0){
                        size = [optionSize*1,optionSize*1];
                    }else{
                        size = defaultSize;
                    }
                }
            }else{
                size =  defaultSize;
            }
            return size;
        };
        
        /**
         * Get data attributes which belong to tiles
         * @param  {JQuery object} that [tiles or tile]
         * @return {object} data [object with settings from data attributes]
         */
        base.getSettingsFromData = function(that){
            var i,j,k,x,y,z;
            var attrs = that.attributes;
            var data;
            if(typeof attrs !== "undefined"){
                for(i = 0; i < attrs.length; i++){
                    x = attrs[i].nodeName.toString();
                    y = attrs[i].nodeValue.toString();
                    y = y.split(",");
                    for(j=0;j<y.length;j++){
                        if(y[j] === "Y" || y[j] === "true"){y[j] = true;} else 
                        if(y[j] === "N" || y[j] === "false"){y[j] = false;} else 
                        if(!isNaN(parseFloat(y[j])) && isFinite(y[j])){y[j] = parseInt(y[j]);}
                    }
                    if(y.length === 1){
                        y = y[0];
                    }
                    
                    if(x.indexOf("data-cstiles") !== -1){
                        x = x.split("-");
                        for(j=1;j<x.length;j++){
                            z = x[j].split("_");
                            if(z.length>1){
                                for(k=1;k<z.length;k++){
                                    z[k] = z[k].slice(0,1).toUpperCase() + z[k].slice(1).toLowerCase();
                                }
                            }
                            z = z.join("");
                            x[j] = z;
                        }
                        switch(x[2]){
                            case "size":
                                if(typeof data === "undefined"){data={};}
                                data.size = base.getsize(y,["auto","auto"]);
                            break;
                            case "adaptivSize":
                                if(typeof data === "undefined"){data={};}
                                if(typeof data.adaptivSize === "undefined"){data.adaptivSize={};}
                                data.adaptivSize[z] = base.getsize(y,["auto","auto"]);
                            break;
                            case "adaptivMedia":
                                if(typeof data === "undefined"){data={};}
                                if(typeof data.adaptivMedia === "undefined"){data.adaptivMedia={};}
                                data.adaptivMedia[z] = y;
                            break;
                            default:
                                if(typeof data === "undefined"){data={};}
                                data[x[2]] = y;
                        }
                    }
                }
            }
            return data;
        };
        
        /**
         * Initial function
         */
        base.Init = function(){
            var i,j,x;
            
            var data = base.getSettingsFromData(base.that);
    
            base.settings = {};
            
            var id = (new Date()).getTime().toString()+(Math.round(Math.random()*1000)+"000").substr(0,3);
            $(base.that).data("cstiles-id",id);
            base.settings.id = id;
            
            for(i in $.CrazySquirrel.Tiles.defaultSettings){
                if($.CrazySquirrel.Tiles.defaultSettings.hasOwnProperty(i)){
                    switch(i){
                        case"size":
                            if(typeof settings !== "undefined" && typeof settings[i] !== "undefined"){
                                base.settings[i] = base.getsize(settings[i],$.CrazySquirrel.Tiles.defaultSettings[i]);
                            }else if(typeof data !== "undefined" && typeof data[i] !== "undefined"){
                                base.settings[i] = base.getsize(data[i],$.CrazySquirrel.Tiles.defaultSettings[i]);
                            }else{
                                base.settings[i] = $.CrazySquirrel.Tiles.defaultSettings[i];
                            }
                        break;
                        case"adaptivSize":
                            
                        break;
                        default:
                            if(typeof settings !== "undefined" && typeof settings[i] !== "undefined"){
                                base.settings[i] = settings[i];
                            }else if(typeof data !== "undefined" && typeof data[i] !== "undefined"){
                                base.settings[i] = data[i];
                            }else{
                                base.settings[i] = $.CrazySquirrel.Tiles.defaultSettings[i];
                            }
                        break;
                    }
                }
            }
            for(i in $.CrazySquirrel.Tiles.defaultSettings){
                if($.CrazySquirrel.Tiles.defaultSettings.hasOwnProperty(i)){
                    switch(i){
                        case"adaptivSize":
                            base.settings[i] = {};
                            if(typeof settings !== "undefined" && typeof settings[i] !== "undefined"){
                                for(j in settings[i]){
                                    if(
                                        settings[i].hasOwnProperty(j) &&
                                        base.settings.adaptivMedia.hasOwnProperty(j)
                                    ) {
                                        if($.CrazySquirrel.Tiles.defaultSettings[i].hasOwnProperty(j)){
                                            x =     $.CrazySquirrel.Tiles.defaultSettings[i][j];
                                        }else{
                                            x =     ["auto","auto"];
                                        }
                                        base.settings[i][j] = base.getsize(settings[i][j],x);
                                    }
                                }
                            }else if(typeof data !== "undefined" && typeof data[i] !== "undefined"){
                                for(j in data[i]){
                                    if(
                                        data[i].hasOwnProperty(j) &&
                                        base.settings.adaptivMedia.hasOwnProperty(j)
                                    ) {
                                        if($.CrazySquirrel.Tiles.defaultSettings[i].hasOwnProperty(j)){
                                            x =     $.CrazySquirrel.Tiles.defaultSettings[i][j];
                                        }else{
                                            x =     ["auto","auto"];
                                        }
                                        base.settings[i][j] = base.getsize(data[i][j],x);
                                    }
                                }
                            }else{
                                base.settings[i] = $.CrazySquirrel.Tiles.defaultSettings[i];
                            }
                        break;
                    }
                }
            }
            
            base.settings.tiles = {};
            
            $(base.that).find(".cstiles__item").each(
                function(){
                    var i;
                    
                    var id = (new Date()).getTime().toString()+(Math.round(Math.random()*1000)+"000").substr(0,3);
                    $(this).data("cstiles-id",id);
                    
                    base.settings.tiles[id] = {
                        adaptivSize: {},
                        adaptivOrder: {},
                        element : $(this).clone()
                    };
                    
                    var data = base.getSettingsFromData(this)||{};
                    var defaultdata = {
                        id:$(this).index(),    
                        order:$(this).index(),    
                        size:[1,1],        
                        margin:base.settings.margin,
                        adaptivSize:{},
                        adaptivOrder:{},    
                        autoClone:base.settings.autoClone,
                        autoMove:base.settings.autoMove,    
                        animate:base.settings.animate,    
                        shareTile:base.settings.shareTile,
                        shareTypes:base.settings.shareTypes,    
                        imagePosition:base.settings.imagePosition,
                        imageSrc:false
                    };
                    data = $.extend({}, defaultdata, data);
                    
                    if(typeof settings !== "undefined" && typeof settings.tiles !== "undefined"){
                        if(typeof settings.tiles[data.id] !== "undefined"){
                            for(i in settings.tiles[data.id]){
                                if(settings.tiles[data.id].hasOwnProperty(i)){
                                    switch(i){
                                        case "adaptivSize":
                                            if(typeof settings.tiles[data.id][i] !== "undefined"){
                                                for(j in settings.tiles[data.id][i]){
                                                    if(settings.tiles[data.id][i].hasOwnProperty(j)){
                                                        data[i][j] = base.getsize(settings.tiles[data.id][i][j],data[i][j]||data.size);
                                                    }    
                                                }
                                            }
                                        break;
                                        case "size":
                                            if(typeof settings.tiles[data.id][i] !== "undefined"){
                                                data[i] = base.getsize(settings.tiles[data.id][i],data[i]);
                                            }
                                        break;
                                        default:
                                            if(typeof settings.tiles[data.id][i] !== "undefined"){
                                                data[i] = settings.tiles[data.id][i];
                                            }
                                        break;
                                    }
                                }    
                            }    
                        }
                    }
                    
                    for(i in base.settings.adaptivMedia){
                        if(base.settings.adaptivMedia.hasOwnProperty(i)){
                            if(typeof data.adaptivSize[i] === "undefined"){
                                data.adaptivSize[i] = data.size;
                            }
                            if(typeof data.adaptivOrder[i] === "undefined"){
                                data.adaptivOrder[i] = data.order;
                            }
                        }        
                    }
                    
                    for(i in data){
                        if(data.hasOwnProperty(i)){
                            base.settings.tiles[id][i] = data[i];
                        }
                    }
                }
            );
        };
        
        /**
         * Search function is free space in the grid
         * @param  {array} size  [array with tile size]
         * @param  {array} grid  [array of array with free ceils of grid]
         * @param  {boolean} scale [flag to scale grid or not]
         * @return {object} result [object with new grid and position of tile]
         */
        base.findGridPlace = function(size,grid,scale){
            var x,y,z,i,j,f,g,a;
            z = 0;
            do{
                z++;
                f = false;
                if(grid.length-size[1]>0){
                    for(y=0;y<=grid.length-size[1];y++){
                        for(x=0;x<=grid[y].length-size[0];x++){
                            g = true;
                            for(i=y;i<y+size[1];i++){
                                for(j=x;j<x+size[0];j++){
                                    if(grid[i][j]){
                                        g = false;
                                        break;
                                    }
                                }    
                                if(!g){
                                    break;    
                                }
                            }
                            if(g){
                                f = true;
                                break;    
                            }    
                        }
                        if(f){
                            break;    
                        }
                    }
                }
                if(!f && scale){
                    a = [];
                    for(i=0;i<grid[0].length;i++){
                        a[i] = false;
                    }
                    grid.push(a);
                }
            }while(f === false && scale && z !== 1000);
            if(f){
                for(i=y;i<y+size[1];i++){
                    for(j=x;j<x+size[0];j++){
                        grid[i][j] = true;
                    }
                }
                return {
                    x:x,
                    y:y,
                    grid:grid    
                };
            }else{
                return false;    
            }
        };
        
        /**
         * Detect is the grid has free place
         * @param  {array}  grid [grid]
         * @return {Boolean} result [has or not]
         */
        base.isGridHasPlace = function(grid){
            var x,y,z;
            z = false;
            for(y=0;y<=grid.length;y++){
                for(x=0;x<=grid[y].length;x++){
                    if(grid[y][x]){
                        z = true;
                        break;    
                    }
                }
                if(z){
                    break;    
                }
            }
            return z;
        };
        
        /**
         * Cal padding value
         * @param  {array} padding [array with padding values]
         * @return {string} result [css padding]
         */
        base.preparePadding = function(padding){
            padding[0] = padding[0].toFixed(2)*1+0.01;
            padding[1] = padding[1].toFixed(2)*1+0.01;
            
            if(padding[0] === padding[1]){
                padding = padding[0]+"%";    
            }else{
                padding = padding[1]+"% "+padding[0]+"%";    
            }
            
            return padding;
        };
        
        /**
         * Cal margin value
         * @param  {array} margin [array with margin values]
         * @return {string} result [css margin]
         */
        base.prepareMargin = function(margin){
            if(margin[0] === margin[1]){
                margin = margin[0]+"% 0 0 "+margin[0]+"%";    
            }else{
                margin = margin[1]+"% 0 0 "+margin[0]+"%";
            }
            
            return margin;
        };
        
        /**
         * Create tile code
         * @param  {jQuery object} e [tile jquery object]
         * @param  {object} setting [object with tile settings]
         * @param  {array} grid [grid array]
         * @param  {boolian} gridscale [grid scale flag]
         * @param  {array} gridSize  [array with grid size]
         * @return {object} result [result object]
         */
        base.makeTile = function(e,setting,grid,gridscale,gridSize){
            var j,x,image,size,padding,height,finder,margin;
            e.html("<div class='cstiles__item-content-wrap' style='padding:"+setting.margin+"px;'><div class='cstiles__item-content'>"+e.html()+"</div></div>");
            image = e.find(".cstiles__item-image:first");
            if(image.size()>0||setting.imageSrc){
                e.find(".cstiles__item-content").css({
                    "background-image":"url("+(setting.imageSrc||image.attr("src"))+")",
                    "background-position":setting.imagePosition.join(" "),
                    "background-size":"cover"
                });    
                image.remove();
            }
    
            if(setting.size[0] === "auto"){setting.size[0] = 1;}
            if(setting.size[1] === "auto"){setting.size[1] = 1;}
            size = [Math.min(setting.size[0],gridSize[0]),Math.min(setting.size[1],gridSize[0])];
            
            padding = [(50/gridSize[0]*size[0]),(50/gridSize[0]*size[1])];
            height = padding[1]*2;
                
            padding = base.preparePadding(padding);
            
            if(typeof setting.animate !== "undefined"){
                for(j in setting.animate){
                    if(
                        setting.animate.hasOwnProperty(j) &&
                        setting.animate[j]
                    ){
                        e.addClass("is-animate-"+j);    
                    }
                }    
            }
    
            if(setting.shareTile){
                e.find(".cstiles__item-content").CSShare({
                    types:setting.shareTypes||[]    
                });
            }
            
            if(base.settings.autoMove && setting.autoMove){
                finder = base.findGridPlace(size,grid,gridscale);
                if(finder){
                    grid = finder.grid;
                    
                    margin = [(100/gridSize[0]*finder.x),(100/gridSize[0]*finder.y)];
                    
                    height += margin[1];
                    
                    margin = base.prepareMargin(margin);
    
                    e.css({
                        "padding":padding,
                        "margin":margin
                    });
                }
            }else{
                e.css({
                    "padding":padding    
                });
            }
            return {
                e:e,
                grid:grid,
                height:height    
            };    
        };
        
        /**
         * Function of build the grid
         */
        base.Build = function(){
            var i,j,k,h,g,x,y,z,e,image,media,gridSize,tiles,height,grid,size,padding,margin,_height,fainder,html,make;
            
            for(i in base.settings.adaptivMedia){
                if(base.settings.adaptivMedia.hasOwnProperty(i)){
                    if(window.matchMedia(base.settings.adaptivMedia[i]).matches){
                        media = i;
                    }
                }    
            }
            if(!base.lastmedia || base.lastmedia !== media){
                base.lastmedia = media;
                
                if(base.settings.autoMove){
                    $(base.that).addClass("is-auto-fix");    
                }else{
                    $(base.that).removeClass("is-auto-fix");
                }
                
                $(base.that).find(".cstiles__item").remove();
                if(media){
                    gridSize = base.settings.adaptivSize[media]||base.settings.size;
                }else{
                    gridSize = base.settings.size;
                }
                if(gridSize[0] === "auto"){
                    gridSize[0] = Math.ceil(base.width()/200);        
                }
                
                tiles = {};
                for(i in base.settings.tiles){
                    if(base.settings.tiles.hasOwnProperty(i)){
                        tiles[i] = $.extend(
                            {},
                            base.settings.tiles[i],
                            {
                                order:base.settings.tiles[i].adaptivOrder[media],
                                size:base.settings.tiles[i].adaptivSize[media]    
                            }
                        );
                    }
                }
                
                height = 0;
                grid = [[]];
                for(i=0;i<gridSize[0];i++){
                    grid[0][i] = false;
                }
                for(i in tiles){
                    if(tiles.hasOwnProperty(i)){
                        e = tiles[i].element.clone();
                        make = base.makeTile(e,tiles[i],grid,true,gridSize);
                        e = make.e;
                        grid = make.grid;
                        if(make.height>height){height = make.height;}
                        that.append(e);
                    }
                }
                if(base.settings.autoClone){
                    i=0;
                    k=0;
                    do{
                        z = base.isGridHasPlace(grid);
                        if(z){
                            for(x=gridSize[0];x>0;x--){
                                for(y=gridSize[0];y>0;y--){
                                    fainder = base.findGridPlace([x,y],grid,false);
                                    if(fainder){
                                        size = [x,y];
                                        padding = [(50/gridSize[0]*size[0]),(50/gridSize[0]*size[1])];
                                        margin = [(100/gridSize[0]*fainder.x),(100/gridSize[0]*fainder.y)];
                                        k++;
                                        e = false;
                                        h = 0;
                                        for(j in tiles){
                                            if(tiles.hasOwnProperty(j)){
                                                if(h===k){
                                                    e = tiles[j].element.clone();
                                                    break;
                                                }
                                                h++;
                                            }
                                        }
                                        if(!e){
                                            k=0;
                                            h = 0;
                                            for(j in tiles){
                                                if(tiles.hasOwnProperty(j)){
                                                    if(h===k){
                                                        e = tiles[j].element.clone();
                                                        break;
                                                    }
                                                    h++;
                                                }
                                            }
                                        }
                                        
                                        e = tiles[j].element.clone();
                                        make = base.makeTile(e,tiles[j],grid,false,gridSize);
                                        e = make.e;
                                        grid = make.grid;
                                        padding = base.preparePadding(padding);
                                        margin = base.prepareMargin(margin);
                                        e.css({
                                            "padding":padding,
                                            "margin":margin
                                        });
                                        
                                        that.append(e);
                                
                                        j++;
                                        if(j === tiles.length){
                                            j=0;    
                                        }
                                        break;    
                                    }
                                }
                                if(fainder){
                                    break;    
                                }
                            }
                        }
                        i++;
                    }while(z && i!== 1000);
                }
                if(base.settings.autoMove){
                    that.append("<div class='cstiles__item is-fixer' style='padding:"+height+"% 0 0 0;'></div>");
                }
            }
        };
        
        /**
         * Calling initial function
         */
        base.Init();
        
        /**
         * Calling build function
         */
        base.Build();

        /**
         * Attache resize event
         */
        $(window).resize(base.Build);
    };
    
    /**
     * Default tiles settings
     * @type {Object}
     */
    $.CrazySquirrel.Tiles.defaultSettings = {
        size: [4,"auto"],
        autoMove: true,
        autoClone: true,
        margin: 0,
        animate: {
            "zoom":true,
            "share":true
        },
        adaptivSize: {
            "big-desktop": [6,"auto"],
            "desktop": [4,"auto"],
            "tablet": [3,"auto"],
            "phone-landscape": [2,"auto"],
            "phone": [1,"auto"]
        },
        adaptivMedia: {
            "big-desktop":"screen and (min-width: 1279px)",
            "desktop":"screen and (max-width: 1279px)",
            "tablet":"screen and (max-width: 1023px)",
            "phone-landscape":"screen and (max-width: 767px)",
            "phone":"screen and (max-width: 479px)"
        },
        shareTile: true,
        shareTypes: ["twitter","facebook","vkontakte","print"],
        imagePosition: ["center","center"] 
    };
    
    /**
     * CSTiles plugin registration
     *
     * @namespace fn
     * @param {object} options [object with tile settings]
     */
    $.fn.CSTiles = function (options) {
        return this.each(function () {
            (new $.CrazySquirrel.Tiles($(this), options));
        });
    };

})( jQuery );