starikan
1/30/2014 - 6:32 AM

Editable form + CSSMenu Kartofan

Editable form + CSSMenu Kartofan

/*http://cssmenumaker.com/builder/954292*/

@import url(http://fonts.googleapis.com/css?family=Open+Sans:400,600,300);
@charset 'UTF-8';
/* Base Styles */

.cssmenu_container {
  position: absolute;
  top: 50%;
  left: 50%;
}

.cssmenu {
  transform: translate(-50%, -50%);
  -moz-transform: translate(-50%, -50%);
  -ms-transform: translate(-50%, -50%);
  -webkit-transform: translate(-50%, -50%);
  -o-transform: translate(-50%, -50%);    
}

.cssmenu,
.cssmenu ul,
.cssmenu li,
.cssmenu a {
  margin: 0;
  padding: 0;
  border: 0;
  list-style: none;
  font-weight: normal;
  text-decoration: none;
  line-height: 1;
  font-family: 'Open Sans', sans-serif;
  font-size: 14px;
  position: relative;
  z-index: 1500;
}
.cssmenu a {
  line-height: 1.3;
}
.cssmenu {
  width: 250px;
}
.cssmenu > ul > li > a {
  padding-right: 40px;
  font-size: 25px;
  font-weight: bold;
  display: block;
  background: #0b9054;
  color: #ffffff;
  border-bottom: 1px solid #04311d;
  text-transform: uppercase;
}
.cssmenu > ul > li > a > span {
  background: #0fbf70;
  padding: 10px;
  display: block;
  font-size: 13px;
  font-weight: 300;
}
.cssmenu > ul > li > a:hover {
  text-decoration: none;
}
.cssmenu > ul > li.active {
  border-bottom: none;
}
.cssmenu > ul > li.active > a {
  color: #fff;
}
.cssmenu > ul > li.active > a span {
  background: #0b9054;
}
.cssmenu span.cnt {
  position: absolute;
  top: 8px;
  right: 15px;
  padding: 0;
  margin: 0;
  background: none;
}
/* Sub menu */
.cssmenu ul ul {
  display: none;
}
.cssmenu ul ul li {
  border: 1px solid #e0e0e0;
  border-top: 0;
}
.cssmenu ul ul a {
  padding: 10px;
  display: block;
  color: #0f0809;
  font-size: 13px;
}
.cssmenu ul ul a:hover {
  color: #29991f;
}
.cssmenu ul ul li.odd {
  background: #f4f4f4;
}
.cssmenu ul ul li.even {
  background: #fff;
}
.eform {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  -moz-transform: translate(-50%, -50%);
  -ms-transform: translate(-50%, -50%);
  -webkit-transform: translate(-50%, -50%);
  -o-transform: translate(-50%, -50%);
    
  background: #0fbf70;
  width: 40%;
  height: 100%;
  min-height: 240px;
  max-height: 600px;
  min-width: 240px;
  max-width: 400px;
  z-index: 1400;
  padding: 0;
}

.eform-header {
  position: absolute;
  top: -40px;
  margin: 0;
  padding: 0;
  text-align: center;
  height: 40px;
  width: 100%;
  color: white;
  background: #0b9054;
  font-size: 30px;
}

.eform-content {
  position: absolute;
  padding: 10px;
  height: 100%;
  overflow-x:hidden;
  overflow-y:auto;
}

.eform-content input,
.eform-content select,
.eform-content textarea
 {
  width: 100%;
  padding: 6px;
  box-sizing: border-box;
  border: none;
  color: black;
  outline: none;
  -webkit-transition: all 0.15s linear;
  -moz-transition: all 0.15s linear;
  transition: all 0.15s linear;  
}

.eform-content input:focus,
.eform-content select:focus,
.eform-content textarea:focus
{
  background: #badbad;
}

.eform-content .button {
  border: none;
  text-align: center;
  background: #0b9054;
  display: block;
  padding: 10px;
  margin: 10px 0px;
  -webkit-transition: all 0.15s linear;
  -moz-transition: all 0.15s linear;
  transition: all 0.15s linear;
}

.eform-content .noCheck {
  background: #de3163 !important;
}



.bootstrap-tagsinput {
  background-color: #fff;
  display: inline-block;
  padding: 6px;
  vertical-align: middle;
  max-width: 100%;
  line-height: 22px;
  width: 100%;
}
.bootstrap-tagsinput input {
  border: none;
  box-shadow: none;
  outline: none;
  background-color: transparent;
  padding: 0;
  margin: 0;
  width: auto !important;
  max-width: inherit;
}
.bootstrap-tagsinput input:focus {
  border: none;
  box-shadow: none;
  background-color: #fff;
}
.bootstrap-tagsinput .tag {
  margin-right: 2px;
  color: white;
}
.bootstrap-tagsinput .tag [data-role="remove"] {
  margin-left: 8px;
  cursor: pointer;
}
.bootstrap-tagsinput .tag [data-role="remove"]:after {
  content: "x";
  padding: 0px 2px;
}
var EditableForm = function(arr, funcs, id, show){
    
    var parent = this;

    if (!id) {id = "eform"};
    if (!show) {show = true};
    if (!funcs) {funcs = {}};

    this.arr = arr;
    this.funcs = funcs;

    this.$form;
    this.$formContent;

    this.fields = [];

    this.data;
    this.check;
    this.checkForm = true;

    this._initForm = function(id){

        var $id = "#"+id;

        if (!$("div").is($id)){
            $("<div></div>").appendTo($("body")).attr("id", id);
        }

        this.$form = $("div"+$id);
        this.$form.empty().addClass("eform hide");

        $("<div></div>").appendTo(this.$form).addClass("eform-header");
        $("<div></div>").appendTo(this.$form).addClass("eform-content");

        this.$formContent = this.$form.find(".eform-content");

        if (show){ this.showForm() }

     }

    this.checkAllFields = function(){
        this.checkForm = true;
        this.$form.find("input, select").each(function(i, v){
            var $v = $(v);
            var check = $v.attr("check")
            if (check){
                var value = $v.val();
                var checkReg = new RegExp(check.substring(1, check.length-1));
                if (checkReg.test(value)){
                    $v.removeClass("noCheck");
                }
                else {
                    parent.checkForm = false;
                    $v.addClass("noCheck");
                }                
            }
        })

     }

    this._checkInputAttr = function(v){
        if (v.classList && $.isArray(v.classList)){ v.classList = v.classList.join(" ") }
        if (!v.check) { v.check = /.?/; }
        if (v.description){
            $("<label>"+v.description+"</label>").appendTo(this.$formContent).addClass(v.classList);
        }        
        if (!v.options){v.options = []}
        v.check = v.check ? new RegExp(v.check) : new RegExp(".?");
        v.tabindex = this.$formContent.find("input, select").length + 1;
        v.rows = v.rows ? v.rows : 1;

        return v;
     }

    // TODO: не ясно как это будет на мобильных работать
    this._checkVal = function(v, $item){
        $item.addClass(v.classList).bind("keyup change", function(){
            if (v.check){
                var value = $(this).val();
                if (v.check.test(value)){ $item.removeClass("noCheck") }
                else { $item.addClass("noCheck") }                
            }

        });
     }


    // ***** ADDING FIELDS ******

    this.addHeader = function(v){
        v = this._checkInputAttr(v);
        if (v.val){
            parent.$form.find(".eform-header").append(v.val).addClass(v.classList);
        }
     }

    this.addInput = function(v){
        v = this._checkInputAttr(v);

        var $input = $("<input/>").attr({
            "type": "text",
            "id": v.id,
            "placeholder": v.placeholder,
            "value": v.val,
            "tabindex": v.tabindex,
            "check": v.check,
        });
        $input.appendTo(this.$formContent);
        this._checkVal(v, $input);
        this.fields.push($input);
     }

    this.addDatalist = function(v){
        v = this._checkInputAttr(v);

        var $input = $("<input/>").attr({
            "type": "datalist",
            "id": v.id,
            "placeholder": v.placeholder,
            "value": v.val,
            "tabindex": v.tabindex,
            "check": v.check,
            "list": v.id+"_list"
        });
        // $input.addClass("form-control flat");
        $input.appendTo(this.$formContent);

        var $datalist = $("<datalist></datalist>").attr({
            "id": v.id+"_list"
        });
        if (!v.options.length){
            $.each(v.options, function(i, option){
                $datalist.append($("<option></option>").val(option))
            })
        };
        $datalist.appendTo(this.$formContent);

        this._checkVal(v, $input);
        this.fields.push($input);
     }

    this.addSelect = function(v){
        v = this._checkInputAttr(v);

        var $select = $("<select/>").attr({
            "type": "select",
            "id": v.id,
            "value": v.val,
            "tabindex": v.tabindex,
            "check": v.check,
        });
        // $select.addClass("form-control flat");
        $select.appendTo(this.$formContent);

        $.each(v.options, function(i, v){
            $("<option>"+v+"</option>").appendTo($select);
        });

        this._checkVal(v, $select);
        this.fields.push($select);
     }

    this.addTags = function(v){
        v = this._checkInputAttr(v);

        var $tags = $("<input/>").appendTo(this.$formContent).attr({
            "type": "tags",
            "id": v.id,
            "tabindex": v.tabindex,
            "check": v.check,
            "data-role": "tagsinput",
            "value": v.val,
        })

        $tags.tagsinput();

        this._checkVal(v, $tags);
        this.fields.push($tags);
     }

    this.addTextArea = function(v){
        v = this._checkInputAttr(v);

        var $input = $("<textarea/>").attr({
            "id": v.id,
            "value": v.val,
            "tabindex": v.tabindex,
            "check": v.check,
            "rows": v.rows,
        });
        $input.appendTo(this.$formContent);
        this._checkVal(v, $input);
        this.fields.push($input);
     }

    this.addRadio = function(v){

     }

    this.addCheckbox = function(v){
        v = this._checkInputAttr(v);

        var $input = $("<input/>").attr({
            "type": "checkbox",
            "id": v.id,
            "value": v.val,
            "tabindex": v.tabindex,
        });
        $input.appendTo(this.$formContent);
        this._checkVal(v, $input);
        this.fields.push($input);
     }

    this.addButton = function(v, f){
        v = this._checkInputAttr(v);

        var $button = $("<input/>").appendTo(this.$formContent).attr({
            "type": "button",
            "value": v.val,
            "id": v.id,
            "tabindex": v.tabindex,
        });
        $button.addClass("button");

        // TODO: add touch
        try {
            $button.bind(f.events, function(){f.callback(parent)});
        }
        catch(e){
            console.log(e);
        };

        // TODO: add touch
        try {
            $button.bind("click", function(){v.callback(parent)});
        }
        catch(e){
            console.log(e);
        };

        this._checkVal(v, $button);
     }


    // ******* MAKE FORM *******

    this.makeFromObj = function(arr, funcs){

        // v = {
        //     type: header|input|select|select2,
        //     val: "value",
        //     id: "id",
        //     placeholder: "placeholder",
        //     check: "regexp to checking the value",
        //     description: "description",
        //     options: [] for select options, tags
        //     callback: callback function,
        //     rows: lines count for textarea
        // }

        arr = arr ? arr : this.arr;
        funcs = funcs ? funcs : this.funcs;

        if (!$.isArray(arr)){ return }

        $.each(arr, function(i, v){
            var f = funcs[v.id]
            switch (v.type){
                case "header":
                    parent.addHeader(v, f);
                    break;
                case "input":
                    parent.addInput(v, f);
                    break;
                case "select":
                    parent.addSelect(v, f);
                    break;
                case "tags":
                    parent.addTags(v, f);
                    break;            
                case "button":
                    parent.addButton(v, f);
                    break; 
                case "datalist":
                    parent.addDatalist(v, f);
                    break;             
                case "checkbox":
                    parent.addCheckbox(v, f);
                    break;    
                case "textarea":
                    parent.addTextArea(v, f);
                    break;  
            }   
        })

        this.checkAllFields();

        this.focusFirstField();

     }

    this.fillForm = function(vals){

        if (!vals || $.isEmptyObject(vals)) {return}

        $.each(vals, function(id, val){
            $.each(parent.fields, function(j, field){
                if (field.attr("id") == id){

                    // Set vals
                    switch (field.attr("type")){

                        case "tags":
                            var tags = val.split(",");
                            $.each(tags, function(num, tag){
                                field.tagsinput('add', tag);
                            })      
                            break;

                        case "checkbox":
                            field.prop('checked', val);                                    
                            break;

                        default:
                            field.val(val);
                    }
                }
            })
        })            

        this.checkAllFields();
     }

    this.fillOptions = function(options){
        if (!options || $.isEmptyObject(options)) {return}
        
        $.each(options, function(id, val){
            $.each(parent.fields, function(j, field){
                if (field.attr("id") == id){

                    // Set options
                    if (options && !$.isEmptyObject(options) && $.isArray(options[id]) && options[id].length){

                        if (field.attr("type") == "datalist"){
                            $.each(options[id], function(o, option){
                                $("datalist#"+id+"_list").append($("<option></option>").val(option))
                            })
                        }

                        if (field.attr("type") == "select"){
                            console.log("Select options sdd: "+options[id]);
                        }
                        
                        if (field.attr("type") == "tags"){
                            // TODO: Add suggestions on tags
                            // http://timschlechter.github.io/bootstrap-tagsinput/examples/bootstrap3/
                        }
                    }
                }
            })
        })
     }

    // TODO
    this.focusFirstField = function(){
        // console.log(this.$form.find("input")[0]);
        // $this.$form.find("input")[0].focus();
     }

    this.showForm = function(){
        this.$form.removeClass("hide");
     }

    this.hideForm = function(){
        this.$form.addClass("hide");
     }

    this.getAllData = function(){

        var data = {};
        var check = {};

        this.checkAllFields();

        $.each(this.fields, function(i, v){
            var $v = $(v);

            switch (v.attr("type")){
                case "checkbox":
                    data[v.attr("id")] = $v.prop('checked')
                    break;
                default:
                    data[v.attr("id")] = $v.val();
            }

            check[v.attr("id")] = !$v.hasClass("noCheck");
        })

        this.data = data;
        this.check = check;

     }

    this._initForm(id);
    this.makeFromObj();
 }

var CSSMenu = function(arr, id, show){
    
    var parent = this;

    if (arr == undefined){ return }
    if (!id) {id = "nonamemenu"}
    if (show == undefined) {show = true}

    this.$container;
    this.$menu;

    this.arr = arr;

    // ************ MAIN FUCNTIONS ************

    this._initMenu = function(){
        var $id = "#"+id;

        if (!$("div").is($id)){
            $("<div></div>").appendTo($("body")).attr("id", id);
        }

        this.$container = $("div"+$id)
        this.$container.empty().addClass("hide cssmenu_container");

        $("<div><ul></ul></div>").appendTo(this.$container).addClass("cssmenu");

        this.$menu = $("div"+$id+" > div.cssmenu > ul");

        if (show){ this.showMenu() }

     }

    this.showMenu = function(){
        this.$container.removeClass("hide");
     }

    this.hideMenu = function(){
        this.$container.addClass("hide");
     }

    // ************ ADD FIELDS ************

    this.addHeader = function(text, classList){

     }

    this.addParagraf = function(text, classList, idList, callback, active){
        
        text = text ? text : "No title";
        classList = classList ? classList : [];
        idList = idList ? idList : [];
        active = active ? active : false;

        $("<li><a><span>"+text+"</span></a></li>").appendTo(this.$menu).addClass("paragraf");
        var $li = this.$menu.find(".paragraf:last-child");
        $.each(classList, function(i, v){
            $li.addClass(v);
        });
        $.each(idList, function(i, v){
            $li.attr("id", v);
        });       
        // TODO: touch
        if (callback){
            $li.bind("click", callback);
        }
        if (active){
            $li.addClass("openOnStart");
        }
     }

    this.addLine = function(text, classList, idList, callback){

        text = text ? text : "No title";
        classList = classList ? classList : [];
        idList = idList ? idList : [];

        var $main = this.$menu.find(".paragraf:last-child");
        $main.addClass("has-sub");

        var $ul = $main.find("ul");

        if (!$ul.length){
            $("<ul><li><a><span>"+text+"</span></a></li></ul>").appendTo($main);
        }
        else {
            $("<li><a><span>"+text+"</span></a></li>").appendTo($ul);
        }

        var $li = $main.find("li:last-child");
        $.each(classList, function(i, v){
            $li.addClass(v);
        });
        $.each(idList, function(i, v){
            $li.attr("id", v);
        });   

        // TODO: touch
        if (callback){
            $li.bind("click", function(){
                parent.hideMenu();
                callback();
            });
        }
        else {
            $li.bind("click", this.hideMenu);
        }
     }

    // ************ BULK ************

    this.makeFromObj = function(arr){

        arr = arr ? arr : this.arr;

        if (!$.isArray(arr)){ return }

        $.each(arr, function(i, v){
            switch (v.type){
                case "header":
                    parent.addHeader(v.text, v.classList);
                    break;
                case "paragraf":
                    parent.addParagraf(v.text, v.classList, v.idList, v.callback, v.active);
                    break;
                case "line":
                    parent.addLine(v.text, v.classList, v.idList, v.callback);
                    break;
            }
        });

        this.activateMenu();
        this.openOnStart();
     }

    this.groupedCollectionMenu = function(collection, callback, show, groupSelector, header){

        if (!collection) { return }
        var show = show == undefined ? true : show;
        groupSelector = groupSelector ? groupSelector : "group"

        var groups = $.pluck(collection, groupSelector);
        groups = unique(groups);
        groups.sort();

        var genArray = [{ type: "header", text: header }];

        $.each(groups, function(g, group){

            var dataInGroup = {};
            $.each(collection, function(i, v){
                if (!v.group && !group || v.group == group){
                    dataInGroup[i] = v;
                }
            })

            if (!$.isEmptyObject(dataInGroup)){
                
                if (!group) {group = "Others"};
                genArray.push({ type: "paragraf", text: group });
                
                $.each(dataInGroup, function(i, vi){
                    genArray.push({
                        type: "line", 
                        text: vi.title ? vi.title : "Noname",
                        callback: function(){
                            callback(i, vi);
                        },
                    })
                });
            }
        })

        this.arr = genArray;

        this._initMenu();
        this.makeFromObj(genArray); 

        show ? this.showMenu() : "";
     }

    this.groupedCollectionMenuExteranlJSON = function(collection, callback, show, header){

        var show = show == undefined ? true : show;

        var extData = opt.getOption("global", "externalFeeds");

        var menuObj = [{ type: "header", text: header }]; 

        $.each(extData, function(i, extJSON){

            $.getJSON(extJSON.url, function(data){
                var genArr = [ { type: "paragraf", text: extJSON.title } ];
                try {
                    data = JSON.parse(Base64.decode(data.content));
                }
                catch(e){}

                $.each(data[collection], function(j, data){
                    genArr.push({
                        type: "line", 
                        text: data.title ? data.title : "Noname",
                        callback: function(){ 
                            console.log(j, data)
                            callback(j, data) 
                        },
                    });
                });

                parent._initMenu();
                parent.makeFromObj(genArr);
                show ? parent.showMenu() : "";

            })
        });
     }

    // ************ ACTIVATE ************

    this.activateMenu = function(){

        // Add counts
        $('.cssmenu > ul > li ul').each(function(index, e){
            var count = $(e).find('li').length;
            var content = '<span class="cnt">' + count + '</span>';
            if (!$(e).closest('li').children('a').find("span.cnt").length){
                $(e).closest('li').children('a').append(content);
            }
        });

        $('.cssmenu ul ul li:odd').addClass('odd');
        $('.cssmenu ul ul li:even').addClass('even');

        // Removed click event because when call several times it`s conflict each other
        $('.cssmenu > ul > li > a').unbind("click");

        $('.cssmenu > ul > li > a').click(function() {
            $('.cssmenu li').removeClass('active');
            $(this).closest('li').addClass('active'); 
            var checkElement = $(this).next();
            if((checkElement.is('ul')) && (checkElement.is(':visible'))) {
                $(this).closest('li').removeClass('active');
                checkElement.slideUp('normal');
            }
            if((checkElement.is('ul')) && (!checkElement.is(':visible'))) {
                $('.cssmenu ul ul:visible').slideUp('normal');
                checkElement.slideDown('normal');
            }
            if($(this).closest('li').find('ul').children().length == 0) {
                return true;
            } else {
                return false;   
            }     
        });        
     }

    this.openOnStart = function(){
        $('.cssmenu > ul > li.openOnStart > a').trigger( "click" );
     }

    this._initMenu();
    this.makeFromObj();

 }