(function () {
    'use strict';'use strict';
var angular = window.angular;
// var constructorApp = angular.module('constructorApp', ['angularColorPicker', 'mgcrea.ngStrap.select'], function($httpProvider) {
//     $httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8';
// });

var constructorApp = angular.module('constructorApp', [
    'ngSanitize',
    'summernote',
    'angularColorPicker',
    'angularInfobar',
    'aModalWindow'
]);

constructorApp.config(['$provide', function($provide) {
    $provide.decorator('acpOptions', ['$delegate', function(acpOptions) { // $delegate is the acpOptions we are decorating
        // set the path to the bgGradient.png
        acpOptions.imgPath = 'constructor/img/bgGradient.png';
        acpOptions.imgPathLine = 'constructor/img/transparent-mini.png';

        acpOptions.startPosition.x = 'root';
        acpOptions.startPosition.y = 'root';
        acpOptions.topPanel = false;

        return acpOptions;
    }]);
}]);

constructorApp.value('paths', {
    json: [
        'constructor/json/options.json',
        'constructor/json/slide.options.json',
        'constructor/json/block.options.json',
        'constructor/json/groups.json'
    ],
    zipMagicSLideshow: '../trial/magicslideshow-trial/magicslideshow' // path to magicslideshow folder
});

constructorApp.controller('constructor', [
    'parseSlide',
    '$scope',
    '$window',
    '$http',
    'slideshowAPI',
    '$timeout',
    '$rootScope',
    'lib',
    'loader',
    '$compile',
    'convertFontSize',
    '$q',
    'acpManager',
    'activeTab',
    'orderBlocksApi',
    'globalMenuAPI',
    '$location',
    'editSlideF',
    'messages',
    'paths',
    'getHtmlSlideshow',
    'aModalWindowManager',
    'saveSlideshow',
    function(parseSlide, $scope, $window, $http, slideshowAPI, $timeout, $rootScope, lib, loader, $compile, convertFontSize, $q, acpManager, activeTab, orderBlocksApi, globalMenuAPI, $location, editSlideF, messages, paths, getHtmlSlideshow, aModalWindowManager, saveSlideshow) {

    $rootScope.dontsave = false;

    $rootScope.defaultContent = {
        // img = 'http://www.ipukr.com/wp-content/uploads/2014/07/1376578323_molodozheny-iz-odessy-priobreli-bilety-v-kosmos.jpg',
        // img = 'http://rewalls.com/large/201010/6476.jpg',
        img: 'https://sirv.sirv.com/website/screenshots/sirv-for-magento-830x291.png',
        // youtube = 'f1i6jTbisYM',
        youtube: '10BFj6aPjVU',
        vimeo: '104587370'
    };

    $rootScope.outlineIsShow = true;

    $rootScope.colorPickerOpened = false;

    $rootScope.newItemWindowIsOpened = false;

    $rootScope.zoomIcon = 'fit';

    $rootScope.idSlideshow = {};

    $rootScope.dataCss = [
        'top',
        'left',
        'width',
        'color',
        'height',
        'filter',
        'padding',
        'opacity',
        'position',
        'font-size',
        'background',
        'padding-top',
        'border',
        'border-color',
        'border-style',
        'border-width',
        'padding-left',
        'padding-right',
        'padding-bottom',
        'background-color'
    ];

    $rootScope.defCss = {
        'top': '10%',
        'left': '10%',
        'width': 'auto',
        'height': 'auto',
        'font-size': '20px',
        'color': 'rgb(0,0,0)',
        'background-color': 'none',
        'padding': '0px',
        'border-width': '0px',
        'border-style': 'none',
        'line-height': '100%',
        'z-index': '0',
        'opacity': 1,
        'font-family': 'Arial, Helvetica, sans-serif',
        'text-align': 'left',
        'border-color': 'none'
    };

    function copy_ (value) {
        var o;
        function check(v) {
            var tmp;

            if (angular.isElement(v)) {
                tmp = null;
            } else if (angular.isArray(v)) {
                tmp = arr(v);
            } else if (angular.isObject(v)) {
                tmp = obj(v);
            } else {
                tmp = v;
            }
            return tmp;
        }
        function arr(v) {
            var f, o2 = [];
            angular.forEach(v, function(v_, k_) {
                f = check(v_);
                if (null !== f) {
                    o2.push(f);
                }
            });
            return o2;
        }
        function obj(v) {
            var f, o2 = {};
            angular.forEach(v, function(v_, k_) {
                if (v.hasOwnProperty(k_) && !(/^$/.test(k_)) && 'scope' !== k_) {
                    f = check(v_);
                    if (null !== f) {
                        o2[k_] = f;
                    }
                }
            });
            return o2;
        }

        if (angular.isArray(value)) {
            o = arr(value);
        } else if (angular.isObject(value)) {
            o = obj(value);
        }
        return o;
    }

    $scope.allVisible = true; // for loading slides and render
    $rootScope.loader = false;
    // $rootScope.slideSize = null;
    $rootScope.slideSize = { width: 0, height: 0 };

    $rootScope.globalMenuIsOpen = false;

    $rootScope.getSlideshowJSON = function() {
        var ss, opt = [], id;

        function replaceContent (content) {
            content = content.replace(/'/g, '&#39');
            content = content.replace(/"/g, '&#34');
            return content;
        }

        opt = copy_($scope.slideshowOptions);
        opt = JSON.stringify($scope.slideshowOptions);

        ss = copy_($scope.slides);
        angular.forEach(ss, function(s) {
            s.activeBlock = null;
            angular.forEach(s.blocks, function(b) {
                b.content = replaceContent(b.content);
                b.newBlock = false;
                b.load = false;
            });
        });

        ss = JSON.stringify(ss);

        if ('id' in $rootScope.idSlideshow) {
            id = $rootScope.idSlideshow.id;
        } else {
            id = null;
        }

        return {
            slideshow: ss,
            options: opt,
            id: id
        };
    };

    $rootScope.oldSlideshow = '';

    $scope.globalMenuTimer = null;

    $scope.inIframe = messages.status;

    $scope.empty = true;
    $scope.zoomIcon = 'fit';
    $scope.zoomIconsDefault = [
        { value: 0.25, label: '25%'},
        { value: 0.5, label: '50%'},
        { value: 0.75, label: '75%'},
        { value: 1, label: '100%' },
        { value: 1.5, label: '150%' },
        { value: 2, label: '200%' },
        { value: 2.5, label: '250%' }
    ];
    $scope.zoomIcons = [
        { value: 0.25, label: '25%'},
        { value: 0.5, label: '50%'},
        { value: 0.75, label: '75%'},
        { value: 1, label: '100%' },
        { value: 1.5, label: '150%' },
        { value: 2, label: '200%' },
        { value: 2.5, label: '250%' }
    ];


    $scope.summernoteOptions = {
        disableDragAndDrop: true,
        lang: "en-US",
        forButton: false,
        // fontSizes: ['8', '9', '10', '11', '12', '14', '18', '24', '36']
        fontSizes: ['12', '14', '18', '24', '30', '36', '42', '48', '56', '64', '73', '82', '100', '150'],
        toolbar: [
            ['style', ['bold', 'italic', 'underline', 'clear']],
            ['fontsize', ['fontsize']],
            ['color', ['color']],
            ['para', ['ul', 'ol', 'paragraph']],
            ['height', ['height']],
            ['link', ['link']],
            ['fontname', ['fontname']]
         ]
    };

    $scope.buttonSummernoteOptions = {
        disableDragAndDrop: true,
        lang: "en-US",
        forButton: true,
        fontSizes: ['12', '14', '18', '24', '30', '36', '42', '48', '56', '64', '73', '82', '100', '150'],
        toolbar: [
            ['style', ['bold', 'italic', 'underline', 'clear']],
            ['fontsize', ['fontsize']],
            ['color', ['color']],
            ['fontname', ['fontname']]
         ]
    };

    $scope.defBlock = {
        wrapper: '',
        outline: '',
        title: '',
        node: '',
        imgName: null,
        index: null,
        type: '',
        url: '',
        imgId: null, // for cms(wordpress)
        base64: null,
        load: false,
        newBlock: true,
        isBackground: false,
        backgroundOldStyle: false,
        baseWidth: null,
        baseHeihgt: null,
        activeBlock: null,
        ta: { isActive: false },
        styles: {},
        options: [],
        size: { width: 0, height: 0 },
        customCss: {},
        href: '',
        link: false,
        saveProportions: true,
        video: {
            'videoType': '',
            'video-autoplay': false,
            'video-fullsize': false
        },
        content: '<p style="line-height:1;">Text... Text... Text... Text... Text... Text...</p>',
        correctStyles: {
            'font-size': 20,
            'font-family': 'Arial, Helvetica, sans-serif',
            'color': 'black',
            'background-color': 'transparent',
            'padding': 0,
            'border-width': 0,
            'border-style': 'none',
            'border-color': 'black',
            'border-radius': 0,
            'top': 0,
            'left': 0,
            'width': 0,
            'height': 0,
            'opacity': 100,
            'bs-x': 0,
            'bs-y': 0,
            'bs-blur': 0,
            'bs-size': 0,
            'bs-color': 'rgba(0,0,0,1)',
            'bs-inset': false,
            'ts-x': 0,
            'ts-y': 0,
            'ts-blur': 0,
            'ts-size': 0,
            'ts-color': 'rgba(0,0,0,1)',
            'ts-inset': false,
            'bg-color': 'none'
        }
    };

    $scope.slideshowSlides = [];

    // $scope.thumbnailsType = 'img';  // img or text

    $scope.defSlide = {
        node: null,
        blocks: [],
        rightSideSize: 0,
        index: null,
        focusClass: '',
        backgroundBlock: null,
        slideOptions: [],
        blockNumber: 0,
        styles: { 'background-color': 'transparent' },
        correctStyles: { 'bg-color': 'transparent' },

        // thumbnails: {
        //     textContent: '',
        //     img: {
        //         node: null,
        //         list: [angular.element('<img src="http://photoholic24.com/wp-content/uploads/2012/01/u234280.jpg">')[0]]
        //     },
        // },

        panel: {
            node: null,
            styles: {
                'top': '0%',
                'left': '0%',
                'width': '0%',
                'height': '0%'
            },
            show: false
        }
        // taToolbarName: 'ta-toolbar'
    };

    $scope.defaults = {
        slideshowOptions: [],
        slides: [],
        slideOptions: {},
        blockOptions: {}
    };

    $scope.slideshowOptions = [];
    $scope.slides = [];

    $scope.defSlideEditor = {
        editor: 0,
        editorStyles: {
            'top': '0px',
            'left': '0px',
            'width': '100%',
            'height': '100%'
        },
        cSlide: null,
        cBlock: null,
        flags: {
            slide: true,
            block: false,
            colorPicker: false
        },
        colorPickerType: '',
        type: 'text',
        url: '',
        title: ''
    };

    $scope.slideEditor = angular.copy($scope.defSlideEditor, {});

    $scope.borderType = [
        'none',
        'dotted',
        'dashed',
        'solid',
        'double',
        'groove',
        'ridge',
        'inset',
        'outset'
    ];

    // $scope._fontFamily = [
    //     { name: 'sans-serif',          value: 'sans-serif'                                       },
    //     { name: 'Arial',               value: 'Arial, Helvetica, sans-serif'                     },
    //     { name: 'Arial Black',         value: "Arial Black, Gadget, sans-serif"                  },
    //     { name: 'Comic Sans MS',       value: 'Comic Sans MS, cursive'                           },
    //     { name: 'Courier New',         value: 'Courier New, Courier, monospace'                  },
    //     { name: 'Georgia',             value: 'Georgia, serif'                                   },
    //     { name: 'Impact',              value: 'Impact, Charcoal, sans-serif'                     },
    //     { name: 'Lucida Console',      value: 'Lucida Console, Monaco, monospace'                },
    //     { name: 'Lucida Sans Unicode', value: 'Lucida Sans Unicode, Lucida Grande, sans-serif'   },
    //     { name: 'Palatino Linotype',   value: 'Palatino Linotype, Book Antiqua, Palatino, serif' },
    //     { name: 'Tahoma',              value: 'Tahoma, Geneva, sans-serif'                       },
    //     { name: 'Times New Roman',     value: 'Times New Roman, Times, serif'                    },
    //     { name: 'Trebuchet MS',        value: 'Trebuchet MS, Helvetica, sans-serif'              },
    //     { name: 'Verdana',             value: 'Verdana, Geneva, sans-serif'                      },
    //     { name: 'Symbol',              value: 'Symbol'                                           },
    //     { name: 'Webdings',            value: 'Webdings'                                         },
    //     { name: 'Wingdings',           value: 'Wingdings, "Zapf Dingbats"'                       },
    //     { name: 'MS Sans Serif',       value: 'MS Sans Serif, Geneva, sans-serif'                },
    //     { name: 'MS Serif',            value: 'MS Serif, New York, serif'                        }
    // ];

    $scope.proportionsIsSet = null;
    $scope.mainField = null;

    $scope.toolbarClick = function(e) {
        e.preventDefault();
        return false;
    };

    $scope.setAsBackground = function(isStore, currentBlock) {
        var slideIndex = currentBlock ? currentBlock.slide : $scope.slideEditor.cSlide,
            blockIndex = currentBlock ? currentBlock.block : $scope.slideEditor.cBlock,
            cs = $scope.slides[slideIndex],
            cb = cs.blocks[blockIndex],
            isBackground = cb.isBackground,

            setStyle = function(t, l, w, h) {
                cb.styles['top'] = t;
                cb.styles['left'] = l;
                cb.styles['width'] = w;
                cb.styles['height'] = h;
            };
        if (isStore) {
            isBackground = !isStore.isBackground;
            $scope.$apply(function() { cb.isBackground = isBackground; });
        }

        if (isBackground) {
            cb.backgroundOldStyle = {
                'top': cb.styles['top'],
                'left': cb.styles['left'],
                'width': cb.styles['width'],
                'height': cb.styles['height'],
                'z-index': cb.styles['z-index'],
                'box-shadow': cb.styles['box-shadow'],

                'border-width': cb.correctStyles['border-width'], // 0
                'border-style': cb.correctStyles['border-style'] // 'none'
            };

            angular.element(cb.node.parentNode).addClass('mss-centering-img');
            // angular.element(cb.node).addClass('mss-centering-img');
            angular.element(cb.node).removeAttr('data-mss-animation-block');

            setStyle('0%', '0%', '', '');
            if (cb.baseWidth / cb.baseHeight * lib.getOption($scope.slideshowOptions, 'base-width').value <= lib.getOption($scope.slideshowOptions, 'base-height').value) {
                angular.element(cb.node).addClass('mss-img-horizontal');
            } else {
                angular.element(cb.node).addClass('mss-img-vertical');
            }

            cb.correctStyles['border-width'] = 0;
            cb.correctStyles['border-style'] = 'none';
            $scope.setStyles('border-width', 'px', true);
            $scope.setStyles('border-style', '', true);

            cb.styles['box-shadow'] = 'none';

            orderBlocksApi.setFirstZIndex(cb, cs.blocks);

            cs.backgroundBlock = cb;
        } else {
            cs.backgroundBlock = null;

            angular.element(cb.node.parentNode).removeClass('mss-centering-img');
            // angular.element(cb.node).removeClass('mss-centering-img');
            angular.element(cb.node).removeClass('mss-img-horizontal');
            angular.element(cb.node).removeClass('mss-img-vertical');
            angular.element(cb.node).attr('data-mss-animation-block', '');

            setStyle(cb.backgroundOldStyle['top'], cb.backgroundOldStyle['left'], cb.backgroundOldStyle['width'], cb.backgroundOldStyle['height']);

            cb.correctStyles['border-width'] = cb.backgroundOldStyle['border-width'];
            cb.correctStyles['border-style'] = cb.backgroundOldStyle['border-style'];
            $scope.setStyles('border-width', 'px', true);
            $scope.setStyles('border-style', '', true);

            cb.styles['box-shadow'] = cb.backgroundOldStyle['box-shadow'];

            orderBlocksApi.setDesiredZIndex(cb.backgroundOldStyle['z-index'], cb, cs.blocks);

            cb.backgroundOldStyle = null;
        }

        $scope.$broadcast('checkButtonsEvent');

        if (!isStore && !currentBlock) {
            $scope.$broadcast('savingActionAddEvent', {
                event: {
                    type: 'setBeckground',
                    slideIndex: cs.index,
                    blockIndex: cb.index,
                    isBackground: cb.isBackground,
                    backgroundOldStyle: angular.copy(cb.backgroundOldStyle, {})
                }
            });
            $scope.$broadcast('slidePreviewUpdateEvent', {
                index: $scope.slideEditor.cSlide
            });
        }

        !currentBlock && $scope.$broadcast('auxiliaryPanelUpdateSizeEvent');
    };

    $scope.setUpProportionsToSlide = function() {
        var cs = $scope.slides[$scope.slideEditor.cSlide];
        var cb = cs.blocks[$scope.slideEditor.cBlock];
        var pis = $scope.slideEditor.cSlide + '' + $scope.slideEditor.cBlock;
        var w;
        var h;
        var oldSize;
        var oldProportions;

        if (null === $scope.slideEditor.cBlock || pis === $scope.proportionsIsSet) {
            return;
        }

        oldProportions = $scope.proportionsIsSet;

        if (!cb.size.width) {
            cb.size.width = cb.node.offsetWidth;
        }

        if (!cb.size.height) {
            cb.size.height = cb.node.offsetHeight;
        }

        $scope.proportionsIsSet = pis;

        oldSize = {
            'width': lib.getOption($scope.slideshowOptions, 'base-width').value,
            'height': lib.getOption($scope.slideshowOptions, 'base-height').value
        };

        $scope.$broadcast('edtorZoomEvent', {type: 'resize', param: {
            width: cb.baseWidth,
            height: cb.baseHeight,
            callback: function() {
                $timeout(function() {
                    angular.forEach(cs.blocks, function(b) {
                        var w_ = b.node.offsetWidth + 'px',
                            h_ = b.node.offsetHeight + 'px';

                        if ($scope.slideEditor.cBlock === b.index && cb.isBackground) {
                            angular.element(b.outline).css({
                                'top': ($rootScope.slideSize.height - parseInt(h_)) / 2 + 'px',
                                'left': ($rootScope.slideSize.width - parseInt(w_)) / 2 + 'px'
                            });
                        }
                        angular.element(b.outline).css({
                            'width': w_,
                            'height': h_
                        });
                    });
                }, 0);

                $scope.$broadcast('savingActionAddEvent', {
                    event: {
                        type: 'canvasResize',
                        slideIndex: cs.index,
                        blockIndex: cb.index,
                        oldSize: oldSize,
                        newSize: {
                            // width: cb.size.width,
                            // height: cb.size.height
                            width: $rootScope.slideSize.width,
                            height: $rootScope.slideSize.height
                        },
                        oldProportions: oldProportions,
                        newProportions: $scope.proportionsIsSet
                    }
                });
            }
        }});

        $scope.$$correctBlocksPosition();
        $scope.$broadcast('auxiliaryPanelUpdateSizeEvent');
        $scope.$broadcast('slidePreviewSlideSizeEvent', {
            index: $scope.slideEditor.cSlide,
            width: cb.size.width,
            height: cb.size.height,
        });
    };

    $scope.$$correctBlocksPosition = function() {
        var edrst = $scope.slideEditor.editorStyles,
            pf = function(v) { return parseFloat(v); },
            canvasTop = pf(edrst.top),
            canvasLeft = pf(edrst.left),
            canvasWidth = pf(edrst.width),
            canvasHeight = pf(edrst.height);

        angular.forEach($scope.slides, function(s, i) {
            angular.forEach(s.blocks, function(b, j) {
                var bt, bl, bw, bh;

                if (/%$/.test(b.styles.top)) {
                    if (pf(b.styles.top) > 100) {
                        bt = '90%';
                    }
                } else {
                    bt = pf(b.styles.top);
                }

                if (/%$/.test(b.styles.left)) {
                    if (pf(b.styles.left) > 100) {
                        bl = '90%';
                    }
                } else {
                    bl = pf(b.styles.left);
                }

                if (/%$/.test(b.styles.width)) {
                    bw = pf(b.styles.width);
                    bw = canvasWidth / 100 * bw;
                } else if ('auto' === b.styles.width) {
                    // bw = b.node.offsetWidth; // display: none
                    bw = b.size.width;
                } else {
                    bw = pf(b.styles.width);
                }

                if (/%$/.test(b.styles.height)) {
                    bh = pf(b.styles.height);
                    bh = canvasHeight / 100 * bh;
                } else if ('auto' === b.styles.height) {
                    if ('image' === b.type) {
                        bh = b.size.height / b.size.width * pf(b.styles.height);
                    } else {
                        // bh = b.node.offsetHeight;  // display: none
                        bh = b.size.height;
                    }
                } else {
                    bh = pf(b.styles.height);
                }

                if (!(/%$/.test(b.styles.left))) {
                    if (bl > canvasWidth + 15) {
                        bl = (canvasWidth - 15) + 'px';
                    } else if (bl + bw + 15 < 0) {
                        bl = (0 - (bl + bw - 15)) + 'px';
                    } else {
                        bl = b.styles.left;
                    }
                } else {
                    if (pf(b.styles.left) > 90) {
                        bl = '90%';
                    } else {
                        bl = b.styles.left;
                    }
                }

                if (!(/%$/.test(b.styles.top))) {
                    if (bt > canvasHeight + 15) {
                        bt = (canvasHeight - 15) + 'px';
                    } else if (bt + bh - 15 < 0) {
                        bt = (0 - (bt + bh - 15)) + 'px';
                    } else {
                        bt = b.styles.top;
                    }
                } else {
                    if (pf(b.styles.top) > 90) {
                        bt = '90%';
                    } else {
                        bt = b.styles.top;
                    }
                }

                b.styles.top = bt;
                b.styles.left = bl;
                if (s.fakeImg) {
                    s.fakeImgStyles.top = bt;
                    s.fakeImgStyles.left = bl;
                }

                $scope.changeField('top', i, j);
                $scope.changeField('left', i, j);
            });
            s.node.style.cssText = 'display: ""';
        });
    };

    var controlLineTimer = null;
    $scope.$on('controlLineEventResize', function(e) {
        $timeout.cancel(controlLineTimer);
        controlLineTimer = $timeout(function() {
            // $scope.$apply(function() {
                $scope.$broadcast('edtorZoomEvent', { type: 'control-line' });
            // });
        // }, 100);
        }, 100);
    });

    $scope.appendImgToSecretContainer = (function() {
        var allUrls = [],
            container = angular.element('<div>'),
            append = function(url) {
                var img = angular.element('img');
                img.attr('src', url);
                allUrls.push(url);
                container.append(img);
            };

        container.css({
            'position': 'absolute',
            'top': '-10000px',
            'left': '-10000px',
            'width': '10px',
            'height': '10px',
            'overflow': 'hidden'
        });
        container.appendTo(document.body);
        return function(url) {
            for (var i = 0; i < allUrls.length; i++) {
                if (url === allUrls[i]) { return; }
            }
            append(url);
        };
    })();

    $scope.$$loadAllImg = function(callback, arr) {
        var ss = arr || $scope.slides, slideIndex = 0, blockIndex = -1,
        getNextBlock = function() {
            if (slideIndex < ss.length) {
                if (blockIndex + 1 < ss[slideIndex].blocks.length) {
                    blockIndex += 1;
                    return ss[slideIndex].blocks[blockIndex];
                } else {
                    blockIndex = 0;
                    slideIndex += 1;
                    if (slideIndex < ss.length) {
                        return ss[slideIndex].blocks[blockIndex];
                    } else {
                        return null;
                    }
                }
            } else {
                return null;
            }
        },

        loadBlock = function(block, cb) {
            if (!block.load && 'image' === block.type) {
                loader.load(block.url, {
                    onload: function (e) {
                        block.load = true;
                        block.size = e.size;
                        block.styles.height = 'auto';
                        $scope.appendImgToSecretContainer(block.url);
                        cb();
                    },
                    error: function(e) {
                        block.load = true;
                        cb();
                    }
                });
            } else {
                cb();
            }
        },

        loadBlocks = function(cb) {
            var b = getNextBlock();
            if (b) {
                loadBlock(b, function() {
                    loadBlocks(cb);
                });
            } else {
                cb();
            }
        };

        loadBlocks(callback);
    };

    $scope.setMagicSlideshowOptions = function() {
        // $window.MagicSlideshow.options
        if ($window.MagicSlideshow) {
            angular.forEach($scope.defaults.slideshowOptions, function(o) {
                $window.MagicSlideshow.options[o.name] = o.value;
            });
        }
    };

    function getResources(resources, callback) {
        var results = [],

            get_ = function(res) {
                var deferred = $q.defer();
                $http.get(res, {})
                .success(function(data, status, headers, config) {
                    deferred.resolve(data);
                }).error(function(data) {
                    deferred.reject('Can not get ' + res);
                });
                return deferred.promise;
            },

            q = function() {
                var promise = get_(resources.shift());
                promise.then(function(data) {
                    results.push(data);
                    load();
                }, function(reason) {
                    results.push(null);
                    load();
                    throw reason;
                });
            },

            load = function() {
                if (resources.length > 0) {
                    q();
                } else {
                    callback(results);
                }
            };
        load();
    }

    $scope.openGlobalMenu = function() {
        if (!$scope.slides[$scope.slideEditor.cSlide].panel.show) {
            // $scope.$broadcast('activeBlockEvent', { index: null });
            // $scope.toggleBlocks(null);
            var el = $scope.slides[$scope.slideEditor.cSlide].blocks[$scope.slideEditor.cBlock];
            if (el) {
                angular.element(el.node)
                    .removeClass('ta-border-shadow');

                $scope.slides[$scope.slideEditor.cSlide].panel.show = true;
            }
        }

        globalMenuAPI.open();
    };
    $scope.closeGlobalMenu = function() {
        globalMenuAPI.close();
    };

    $scope.activateSlide = function(index, noSaveAction, deferred, callback) {
        var i, newSlide = (undefined === index),
            last = $scope.slideEditor.cSlide,
            sld, ocb;

        globalMenuAPI.close();

        if (null !== $scope.slideEditor.cSlide && $scope.slideEditor.cSlide < $scope.slides.length) {
            sld = $scope.slides[$scope.slideEditor.cSlide];
            sld.focusClass = '';
            sld.activeBlock = null;

            ocb = sld.blocks[$scope.slideEditor.cBlock];

            $scope.slideEditor.cBlock = null;
        }

        if (undefined === index) {
            index = $scope.slides.length;
            $scope.slides.push(angular.extend({}, $scope.defSlide));
            $scope.defSlide.blocks = [];
            $scope.slides[index].index = index;
            $scope.slides[index].node = document.createElement('div');
            $scope.slides[index].slideOptions = angular.copy($scope.defaults.slideOptions, []);
            $scope.slides[index].styles = angular.copy($scope.defSlide.styles, {});
            $scope.slides[index].correctStyles = angular.copy($scope.defSlide.correctStyles, {});
        } else {
            // (null !== last && $scope.slides.length < last) && angular.forEach($scope.slides[last].blocks, function(b) {
            //     if ('text' === b.type && b.ta.isActive) {
            //         b.ta.isActive = false;
            //         b.node.innerHTML = b.content;
            //     }
            // });
        }

        angular.element($scope.slides[index].node).addClass('mss-content');

        $scope.slides[index].focusClass = 'active';
        $scope.empty = false;
        $scope.slideEditor.cSlide = index;
        $timeout(function() {
            $scope.slideEditor.title = 'Slide ' + (index + 1) + '.';
            if (undefined === noSaveAction && newSlide) {
                $scope.$broadcast('savingActionAddEvent', {
                    event: {
                        type: 'newSlide',
                        index: index,
                        slide: $scope.slides[index],
                        lastActiveSlide: last
                    }
                });
            }

            // $scope.slideEditor.cSlide = index;
            $scope.slides[index].panel.show = false;
            $scope.toggleBlocks(null);

            deferred && deferred.resolve();
            callback && callback();
        }, 0);
    };

    $scope.removeSlide = function (index, activateSlide, noSaveAction, deferred) {
        var _slides = [];

        globalMenuAPI.close();

        if ($scope.slides.length > 0 && undefined !== index) {
            if (undefined === activateSlide) {
                if (index === $scope.slideEditor.cSlide || undefined === index) {
                    activateSlide = 0;
                } else {
                    if ($scope.slideEditor.cSlide > index) {
                        activateSlide = $scope.slideEditor.cSlide - 1;
                    } else {
                        activateSlide = $scope.slideEditor.cSlide;
                    }
                }
            }

            angular.forEach($scope.slides, function(s, i) {
                if (index !== i) {
                    _slides.push(s);
                    _slides[_slides.length - 1].index = _slides.length - 1;
                } else {
                    if (undefined === noSaveAction) {
                        noSaveAction = 0;
                    }
                    $scope.$broadcast('savingActionAddEvent', {
                        event: {
                            type: 'removeSlide',
                            activeIndex: $scope.slideEditor.cSlide,
                            index: i,
                            slide: s
                        }
                    });
                }
            });

            if ($scope.slides.length !== _slides.length) {
                $scope.slides = _slides;
            }

            if ($scope.slides.length > 0) {
                $scope.activateSlide(activateSlide, noSaveAction, deferred);
            } else {
                $scope.empty = true;
                $scope.slideEditor.cSlide = null;
                $scope.slideEditor.cBlock = null;
                // $scope.$broadcast('componentsEmptyEvent');
                deferred && deferred.resolve();
            }
        }
    };

    $scope.saveSlide = function(index) {
        var s = '',
            size, t,
            border, a,
            obj = {},
            slide = {},
            cs, spans,
            cloneSlide,
            correctSize = function(key, value, block) {
                if ('width' === key || 'height' === key || 'top' === key || 'left' === key) {
                    !size && (size = { width: $rootScope.slideSize.width, height: $rootScope.slideSize.height });

                    if ('width' === key || 'height' === key) {
                        if ('image' === block.type || ('text' === block.type || 'shape' === block.type || 'button' === block.type) && /px$/.test(value)) {
                            if ('width' === key) {
                                t = border.left + border.right;
                            } else {
                                t = border.top + border.bottom;
                            }

                            if ('auto' !== value && !(/%$/.test(value))) {
                                value = ((parseInt(value) - t) / size[key] * 100) + '%';
                            }
                        }
                    } else {
                        if (!(/%$/.test(value))) {
                            value = (parseInt(value) / size['top' === key ? 'height' : 'width'] * 100) + '%';
                        }
                    }
                }
                return value;
            };

        // if (undefined !== index) {
        //     $scope.slideEditor.cSlide = index;
        // }
        // cs = $scope.slides[$scope.slideEditor.cSlide];
        // cs = $scope.slides[index || $scope.slideEditor.cSlide];
        cs = $scope.slides[index];
        cloneSlide = cs.node.cloneNode(true);
        cloneSlide.innerHTML = '';


        angular.forEach(cs.blocks, function(b, i) {
            var cloneBlock = b.node.cloneNode(true);
            border = lib.getBorder(cloneBlock);

            angular.element(cloneBlock)
                .attr('data-rwd', true)
                .removeClass('ng-scope')
                .removeAttr('style')
                .removeAttr('ng-style')
                .removeAttr('ng-model')
                .removeAttr('text-angular')
                .removeAttr('name')
                .removeAttr('ng-if')
                .removeAttr('ng-src')
                .removeAttr('block-text')
                .removeAttr('index');


            if ('image' === b.type && b.link) {
                a = angular.element('<a>');
                a.attr('href', b.href);

                if (!b.isBackground) {
                    a.attr('data-mss-animation-block', '');
                    angular.element(cloneBlock).css({
                        'position': 'relative',
                        'max-width': '100%'
                    }).removeAttr('data-mss-animation-block');
                } else {
                    a.attr('data-mss-constr-bg', '');
                }


                a.append(cloneBlock);
                cloneBlock = a[0];
            }

            if ('text' === b.type || 'button' === b.type) {
                // angular.element(b.node).find('span').removeClass('ng-scope');
                spans = angular.element(cloneBlock).find('span');
                angular.forEach(spans, function(sp) {
                    sp = angular.element(sp);
                    sp.removeClass('ng-scope');
                    // .css('font-size', convertFontSize.convertToEm(sp.css('font-size')));
                });
                // convertFontSize.convertInvestedEm(cloneBlock);
                if ('text' === b.type) {
                    cloneBlock = angular.element('<div data-mss-animation-block data-rwd="true">' + b.content + '</div>')[0];
                }
                convertFontSize.convertInvestedEm(cloneBlock);
            }

            if ('button' === b.type) {
                angular.element(cloneBlock).attr('href', b.href);
            }

            angular.forEach(b.options, function(o, i2) {
                if (true === o.value || false === o.value) { o.value += ''; }
                if ($scope.defaults.blockOptions[i2].value !== o.value) {
                    angular.element(cloneBlock).attr('data-'+ o.name, o.value);
                } else {
                    angular.element(cloneBlock).removeAttr('data-'+ o.name);
                }
            });
            // b.focusClass = '';

            if ('text' !== b.type && 'button' !== b.type && 'shape' !== b.type && !b.isBackground) {
                if (/%$/.test(b.styles.width)) {
                    b.styles.width = ($rootScope.slideSize.width / 100 * parseInt(b.styles.width)) + 'px';
                }
                if (/%$/.test(b.styles.height)) {
                    b.styles.height = ($rootScope.slideSize.height / 100 * parseInt(b.styles.height)) + 'px';
                }

                angular.element(cloneBlock).attr('data-width', b.styles.width);
                if ('video' === b.type) {
                    angular.element(cloneBlock).attr('data-height', b.styles.height);
                }
            }

            if (!b.isBackground) {
                s = '';
                angular.forEach(b.styles, function(value, key) {
                    s += key + ':' + correctSize(key, value, b) + ';';
                });

                angular.element(cloneBlock).attr('style', s);
            }
            angular.element(cloneSlide).append(cloneBlock);
        });

        angular.forEach(cs.slideOptions, function(o, i) {
            // TODO
            // if ($scope.defaults.slideOptions[i].value !== o.value) {
                angular.element(cloneSlide).attr('data-'+ o.name, o.value);
            // } else {
                // angular.element(cloneSlide).removeAttr('data-'+ o.name);
            // }
        });

        angular.element(cloneSlide).removeAttr('ng-style');

        s = '';
        angular.forEach(cs.styles, function(value, key) {
            if ($scope.defSlide.styles[key] !== value) {
                s += (key + ':' + value + ';');
            }
        });

        // cs.focusClass = '';

        // angular.forEach(cs.blocks, function(b) {
        //     angular.element(cs.node).append(b.node);
        //     b.wrapper && angular.element(b.wrapper).remove();
        // });

        // angular.element(cs.panel.node).remove();
        // cs.panel.node = null;
        return cloneSlide;
    };

    $scope.tmpStyle = {
        timer: null,
        styles: null,
        correctStyles: null,
        panelStyles: null,
        size: null,
        fakeImg: null,
        content: null,
        saveProportions: null,
        customCss: null
    };

    $scope.$on('blockTextReCalcEvent', function() {
        // data.value
        var s = $scope.slides[$scope.slideEditor.cSlide],
            b = s.blocks[$scope.slideEditor.cBlock], e;

        $timeout.cancel($scope.tmpStyle.timer);
        $scope.tmpStyle.timer = $timeout(function() {
            $scope.tmpStyle.timer = null;
            e = {
                type: 'setStyles',
                slideIndex: $scope.slideEditor.cSlide,
                blockIndex: $scope.slideEditor.cBlock,
                oldPanelStyles: $scope.tmpStyle.panelStyles,
                newPanelStyles: angular.copy(s.panel.styles, {}),
                oldContent: $scope.tmpStyle.content,
                newContent: b.content,
                oldSize: $scope.tmpStyle.size,
                newSize: angular.copy(s.size, {})
            };

            if (null !== $scope.tmpStyle.saveProportions) {
                e.oldSaveProportions = $scope.tmpStyle.saveProportions;
                e.newSaveProportions = b.saveProportions;
            }

            $scope.$broadcast('savingActionAddEvent', { event: e });
            $scope.tmpStyle.content = null;
            $scope.tmpStyle.panelStyles = null;
            $scope.tmpStyle.size = null;
            $scope.tmpStyle.saveProportions = null;
        }, 450);
        $scope.setStyles('', '', true);
    });

    $scope.setStyles = function(style, units, notSave) {
        var s, p, v, e;
        s = $scope.slides[$scope.slideEditor.cSlide].blocks[$scope.slideEditor.cBlock];
        if (undefined === s) { return; }
        p = $scope.slides[$scope.slideEditor.cSlide].panel;
        v = s.correctStyles[style];

        if ('opacity' === style) {
            v = v / 100;
            units = 0;
        }

        if (!$scope.tmpStyle.styles && !notSave) {
            $scope.tmpStyle.styles = angular.copy(s.styles, {});
            $scope.tmpStyle.correctStyles = angular.copy(s.correctStyles, {});
            $scope.tmpStyle.panelStyles = angular.copy(p.styles, {});
            $scope.tmpStyle.size = angular.copy(s.size, {});
            $scope.tmpStyle.correctStyles[style] = parseInt($scope.tmpStyle.styles[style]);
        }

        if ('' !== style) {
            s.styles[style] = v + units;
        }

        $timeout(function() {
            if ('top' === style || 'left' === style) {
                p.styles.top = s.styles.top;
                p.styles.left = s.styles.left;
            }

            p.styles.width = (s.node.offsetWidth || 0) + 'px';
            p.styles.height = (s.node.offsetHeight || 0) + 'px';
            s.size = {
                width: s.node.offsetWidth,
                height: s.node.offsetHeight
            };
            if (!notSave) {
                $timeout.cancel($scope.tmpStyle.timer);
                $scope.tmpStyle.timer = $timeout(function() {
                    $scope.tmpStyle.timer = null;

                    e = {
                        type: 'setStyles',
                        slideIndex: $scope.slideEditor.cSlide,
                        blockIndex: $scope.slideEditor.cBlock,
                        oldStyles: $scope.tmpStyle.styles,
                        newStyles: angular.copy(s.styles, {}),
                        oldCorrectStyles: $scope.tmpStyle.correctStyles,
                        newCorrectStyles: angular.copy(s.correctStyles, {}),
                        oldPanelStyles: $scope.tmpStyle.panelStyles,
                        newPanelStyles: angular.copy(p.styles, {}),
                        oldSize: $scope.tmpStyle.size,
                        newSize: angular.copy(s.size, {})
                    };

                    if (null !== $scope.tmpStyle.saveProportions) {
                        e.oldSaveProportions = $scope.tmpStyle.saveProportions;
                        e.newSaveProportions = s.saveProportions;
                    }

                    $scope.$broadcast('savingActionAddEvent', { event: e });
                    $scope.tmpStyle.styles = null;
                    $scope.tmpStyle.correctStyles = null;
                    $scope.tmpStyle.panelStyles = null;
                    $scope.tmpStyle.saveProportions = null;
                }, 450);
            }
        }, 0);
    };

    $scope.$on('buttonCheckboxEvent', function(e, data) {
        $scope.$apply(function() {
            $scope.slides[$scope.slideEditor.cSlide].blocks[$scope.slideEditor.cBlock].styles['text-align'] = data.target;
        });
    });

    $scope.changeField = function(style, slide, block) {
        var s = $scope.slides[!isNaN(slide) ? slide : $scope.slideEditor.cSlide].blocks[!isNaN(block) ? block : $scope.slideEditor.cBlock],
            p = $scope.slides[!isNaN(slide) ? slide : $scope.slideEditor.cSlide].panel,
            e;

        $timeout(function() {
            if ('top' === style || 'left' === style) {
                p.styles[style] = s.styles[style];
                if (s.fakeImg) {
                    s.fakeImgStyles[style] = s.styles[style];
                }
            }

            if (undefined === slide || slide === $scope.slideEditor.cSlide && block === $scope.slideEditor.cBlock) {
                if (s.saveProportions && 'text' !== s.type) {
                    if ($scope.$$phase) {
                        lib.getProportionsSize(s, style);
                    } else {
                        $scope.$apply(function() {
                            lib.getProportionsSize(s, style);
                        });
                    }
                }

                p.styles.width = (s.node.offsetWidth || 0) + 'px';
                p.styles.height = (s.node.offsetHeight || 0) + 'px';
                if ('text' === s.type) {
                    s.size = {
                        width: s.node.offsetWidth,
                        height: s.node.offsetHeight
                    };
                }

                if (s.fakeImg) {
                    s.fakeImgStyles.width = p.styles.width;
                    s.fakeImgStyles.height = p.styles.height;
                }
            }

            if (undefined === slide) {
                $timeout.cancel($scope.tmpStyle.timer);
                $scope.tmpStyle.timer = $timeout(function() {
                    if ('auto' === s.styles[style] || (/(%|px)$/.test(s.styles[style]))) {
                        $scope.tmpStyle.timer = null;
                        e = {
                            type: 'setStyles',
                            slideIndex: $scope.slideEditor.cSlide,
                            blockIndex: $scope.slideEditor.cBlock,
                            oldStyles: $scope.tmpStyle.styles,
                            newStyles: angular.copy(s.styles, {}),
                            oldPanelStyles: $scope.tmpStyle.panelStyles,
                            newPanelStyles: angular.copy(p.styles, {}),
                            oldSize: $scope.tmpStyle.size,
                            newSize: angular.copy(s.size, {})
                        };
                        if (s.fakeImg) {
                            e.oldFakeImg = $scope.tmpStyle.fakeImg;
                            e.newFakeImg = angular.copy(s.fakeImgStyles, {});
                        }

                        if (null !== $scope.tmpStyle.saveProportions) {
                            e.oldSaveProportions = $scope.tmpStyle.saveProportions;
                            e.newSaveProportions = s.saveProportions;
                        }

                        $scope.$broadcast('savingActionAddEvent', { event: e });
                        $scope.tmpStyle.styles = null;
                        $scope.tmpStyle.fakeImg = null;
                        $scope.tmpStyle.panelStyles = null;
                        $scope.tmpStyle.size = null;
                        $scope.tmpStyle.saveProportions = null;
                    }
                }, 450);
            }
        }, 0);
    };

    $scope.$on('blockOptionsEvent', function(e, args) {
        var opt;
        if ('slideshow' === args.type) {
            opt = $scope.slideshowOptions;
        } else if ('slide' === args.type) {
            opt = $scope.slides[$scope.slideEditor.cSlide].slideOptions;
        } else {
            opt = $scope.slides[$scope.slideEditor.cSlide].blocks[$scope.slideEditor.cBlock].options;
        }
        angular.forEach(opt, function(v) {
            if (args.name === v.name) {
                v.value = args.value;
            }
        });
    });

    $scope.$on('keepColorEvent', function(ev, data) {
        var s = $scope.slides[$scope.slideEditor.cSlide],
            b = s.blocks[$scope.slideEditor.cBlock], e;

        if (!$rootScope.colorPickerOpened) { return; }

        if (lib.checkArr(['box-shadow', 'text-shadow', 'background-color'], data.style)) {
            if (!$scope.tmpStyle.styles) {
                $scope.tmpStyle.styles = angular.copy(b.styles, {});
                $scope.tmpStyle.correctStyles = angular.copy(b.correctStyles, {});
                $scope.tmpStyle.size = angular.copy(b.size, {});
            }

            if ('background-color' === data.style) {
                $scope.setBGColor();
            } else {
                $scope.setShadow(data.style);
            }
        } else {
            if (!$scope.tmpStyle.styles) {
                $scope.tmpStyle.styles = angular.copy(b.styles, {});
                $scope.tmpStyle.styles[data.style] = data.oldValue;
                $scope.tmpStyle.size = angular.copy(b.size, {});
            }
        }

        $timeout.cancel($scope.tmpStyle.timer);
        $scope.tmpStyle.timer = $timeout(function() {
            $scope.tmpStyle.timer = null;

            e = {
                type: 'setStyles',
                slideIndex: $scope.slideEditor.cSlide,
                blockIndex: $scope.slideEditor.cBlock,
                oldStyles: $scope.tmpStyle.styles,
                newStyles: angular.copy(b.styles, {})
            };

            if (null !== $scope.tmpStyle.saveProportions) {
                e.oldSaveProportions = $scope.tmpStyle.saveProportions;
                e.newSaveProportions = b.saveProportions;
            }

            $scope.$broadcast('savingActionAddEvent', { event: e });
            $scope.tmpStyle.styles = null;
            $scope.tmpStyle.correctStyles = null;
            $scope.tmpStyle.saveProportions = null;
            $scope.tmpStyle.size = null;
        }, 450);
    });

    $scope.selectSlide = function(e) {
        var click = true,
            target = e.target, editorScope,
            cs = $scope.slides[$scope.slideEditor.cSlide],
            check = function(node) {
                if (node === cs.panel.node) {
                    click = false;
                }

                if (click) {
                    angular.forEach(cs.blocks, function(b) {
                        if (node === b.wrapper) {
                            click = false;
                        }
                    });
                }
            };

        if (1 === e.which) {
            // TODO video - acpManager.close();
            acpManager.close();
            globalMenuAPI.close();
            e.stopPropagation();
            if ('BUTTON' !== e.target.tagName && click) {
                if ($scope.slides.length > 0 && null !== $scope.slideEditor.cSlide && null !== $scope.slideEditor.cBlock) {
                    while(click && target !== $window.document.body) {
                        check(target);
                        target = target.parentNode;
                    }
                    if (click) {
                        e.preventDefault();

                        $scope.$broadcast('slidePreviewUpdateEvent', {
                            index: $scope.slideEditor.cSlide
                        });

                        $scope.toggleBlocks(null);
                        $scope.$broadcast('activeBlockEvent', {
                            index: null
                        });
                    }
                }
            }
        }
    };

    $scope.preserveProportions = function() {
        if ($scope.slides[$scope.slideEditor.cSlide].blocks[$scope.slideEditor.cBlock].saveProportions) {
            $scope.tmpStyle.saveProportions = false;
            $scope.restoreProportions();
        } else {
            $scope.tmpStyle.saveProportions = true;
        }
    };

    $scope.restoreProportions = function() {
        $scope.$broadcast('auxiliaryPanelRestoreProportionsEvent');
    };

    $scope.createFakeImg = function() {
        var fakeImgStyles, fakeImg = angular.element(new Image());
        fakeImg.attr('src', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNgYAAAAAMAASsJTYQAAAAASUVORK5CYII=');

        fakeImgStyles = {
            'top': '10%',
            'left': '10%',
            'width': '100%',
            'height': '100%',
            'position': 'absolute',
            'z-index': 100
        };
        fakeImg.bind('click', function(e) {
            e.preventDefault();
        });

        fakeImg.addClass('video-border');

        return {
            img: fakeImg,
            style: fakeImgStyles
        };
    };

    $scope.setShadow = function(style, notSave) {
        var cs = $scope.slides[$scope.slideEditor.cSlide],
            cb = cs.blocks[$scope.slideEditor.cBlock],
            crst = cb.correctStyles, color, inset, t, e;

        !style && (style = 'box-shadow');

        t = 'box-shadow' === style ? 'b' : 't';

        color = crst[t + 's-color'];
        inset = crst[t + 's-inset'] ? 'inset' : '';


        if (!$scope.tmpStyle.styles && !notSave) {
            $scope.tmpStyle.styles = angular.copy(cb.styles, {});
            $scope.tmpStyle.correctStyles = angular.copy(cb.correctStyles, {});
            $scope.tmpStyle.size = angular.copy(cb.size, {});
            $scope.tmpStyle.correctStyles[style] = parseInt($scope.tmpStyle.styles[style]);
        }

        if ('box-shadow' === style) {
            cb.styles['box-shadow'] = crst['bs-x'] + 'px ' + crst['bs-y'] + 'px ' + crst['bs-blur'] + 'px ' + crst['bs-size'] + 'px ' + color + ' ' + inset;
        } else {
            cb.styles['text-shadow'] = crst['ts-x'] + 'px ' + crst['ts-y'] + 'px ' + crst['ts-blur'] + 'px ' + color + ' ' + inset;
        }

        $timeout(function() {
            if (!notSave) {
                $timeout.cancel($scope.tmpStyle.timer);
                $scope.tmpStyle.timer = $timeout(function() {
                    $scope.tmpStyle.timer = null;

                    e = {
                        type: 'setStyles',
                        slideIndex: $scope.slideEditor.cSlide,
                        blockIndex: $scope.slideEditor.cBlock,
                        oldStyles: $scope.tmpStyle.styles,
                        newStyles: angular.copy(cb.styles, {}),
                        oldCorrectStyles: $scope.tmpStyle.correctStyles,
                        newCorrectStyles: angular.copy(cb.correctStyles, {}),
                        oldSize: $scope.tmpStyle.size,
                        newSize: angular.copy(cb.size, {})
                    };

                    if (null !== $scope.tmpStyle.saveProportions) {
                        e.oldSaveProportions = $scope.tmpStyle.saveProportions;
                        e.newSaveProportions = s.saveProportions;
                    }

                    $scope.$broadcast('savingActionAddEvent', { event: e });
                    $scope.tmpStyle.styles = null;
                    $scope.tmpStyle.correctStyles = null;
                    $scope.tmpStyle.saveProportions = null;
                    $scope.tmpStyle.size = null;
                }, 450);
            }
        }, 0);
    };

    $scope.setBGColor = function(slideBG, notSave) {
        var cs = $scope.slides[$scope.slideEditor.cSlide],
            cb, receiving, crst, color, value, e;

        if (!cs.blocks) { return; }

        cb = cs.blocks[$scope.slideEditor.cBlock];
        receiving = slideBG ? cs : cb;
        crst = receiving.correctStyles;
        color = crst['bg-color'];

        if (!$scope.tmpStyle.styles && !slideBG) {
            $scope.tmpStyle.styles = angular.copy(cb.styles, {});
            $scope.tmpStyle.correctStyles = angular.copy(cb.correctStyles, {});
            $scope.tmpStyle.size = angular.copy(cb.size, {});
        }

        value = color;

        receiving.styles['background-color'] = value;

        $timeout(function() {
            if (!notSave && !slideBG) {
                $timeout.cancel($scope.tmpStyle.timer);
                $scope.tmpStyle.timer = $timeout(function() {
                    $scope.tmpStyle.timer = null;

                    e = {
                        type: 'setStyles',
                        slideIndex: $scope.slideEditor.cSlide,
                        blockIndex: $scope.slideEditor.cBlock,
                        oldStyles: $scope.tmpStyle.styles,
                        newStyles: angular.copy(cb.styles, {}),
                        oldCorrectStyles: $scope.tmpStyle.correctStyles,
                        newCorrectStyles: angular.copy(cb.correctStyles, {}),
                        oldSize: $scope.tmpStyle.size,
                        newSize: angular.copy(cb.size, {})
                    };

                    if (null !== $scope.tmpStyle.saveProportions) {
                        e.oldSaveProportions = $scope.tmpStyle.saveProportions;
                        e.newSaveProportions = s.saveProportions;
                    }

                    $scope.$broadcast('savingActionAddEvent', { event: e });
                    $scope.tmpStyle.styles = null;
                    $scope.tmpStyle.correctStyles = null;
                    $scope.tmpStyle.saveProportions = null;
                    $scope.tmpStyle.size = null;
                }, 450);
            }
        }, 0);
    };

    $scope.$on('controlPanelBlocksEvent', function(e, data) {
        var lbi = $scope.slideEditor.cBlock;
        if ('remove' === data.type) {
            if (null === $scope.slideEditor.cBlock || undefined === $scope.slideEditor.cBlock) {
                return;
            }

            $scope.$broadcast('editSlideEvent', {
                type: 'remove'
            });

            $scope.slideEditor.cBlock = null;
            if ($scope.slides[$scope.slideEditor.cSlide].backgroundBlock) {
                $scope.slides[$scope.slideEditor.cSlide].backgroundBlock = null;
            }
            $scope.toggleBlocks();
            $scope.$broadcast('slidePreviewUpdateEvent', {
                index: $scope.slideEditor.cSlide
            });
        } else if ('createNewBlock' === data.type) {
            var fi, cs = $scope.slides[$scope.slideEditor.cSlide],
                block = {};
                // angular.copy($scope.defBlock, block);
                // angular.copy($scope.defaults.blockOptions, block.options);
                block = angular.copy($scope.defBlock, {});
                block.options = angular.copy($scope.defaults.blockOptions, []);
                block.index = cs.blocks.length;

            switch (data.blockType) {
                case 'text':
                    block.type = 'text';
                    break;
                case 'button':
                    block.type = 'button';
                    block.content = '<p style="line-height:1;"><span style="font-size: 14px;">Button text..</span></p>';
                    block.link = true;
                    block.correctStyles['padding'] = 8;
                    block.correctStyles['bg-color'] = 'rgba(173,173,173,1)';
                    block.correctStyles['background-color'] = 'rgba(173,173,173,1)';
                    break;
                case 'shape':
                    block.type = 'shape';
                    block.correctStyles['top'] = '10%';
                    block.correctStyles['left'] = '10%';
                    block.correctStyles['bg-color'] = 'rgba(173,173,173,1)';
                    block.correctStyles['background-color'] = 'rgba(173,173,173,1)';
                    block.saveProportions = false;
                    break;
                case 'image':
                    block.type = 'image';
                    block.url = data.url;
                    block.base64 = data.base64;
                    block.imgName = data.name;
                    block.imgId = data.imgId;

                    if (data.full) {
                        block.isBackground = true;
                    }

                    // var img = angular.element('<img>');
                    // img.attr('src', data.base64 || data.url || $rootScope.defaultContent.img);
                    // cs.thumbnails.img.list.push(img[0]);
                    break;
                case 'video':
                    block.type = 'video';
                    block.video.videoType = data.videoType;
                    block.url = data.url;
                    fi = $scope.createFakeImg();
                    block.fakeImg = fi.img;
                    block.fakeImgStyles = fi.style;
                    block.isnocookie = data.isnocookie;

                    break;
            }
            cs.blockNumber += 1;
            block.title = block.type + cs.blockNumber;

            // $scope.slides[$scope.slideEditor.cSlide.index].blocks.push(block);
            $scope.$broadcast('editorEvent', {
                type: 'newBlock',
                index: $scope.slideEditor.cSlide,
                newBlock: block
            });
        }
    });

    $scope.$on('orderBlocksEvent', function(e, data) {
        var indexes = [];
        angular.forEach($scope.slides[$scope.slideEditor.cSlide].blocks, function(b) {
            indexes.push(b.styles['z-index']);
        });

        $scope.$broadcast('savingActionAddEvent', {
            event: {
                type: 'zIndex',
                slideIndex: $scope.slideEditor.cSlide,
                blockIndex: $scope.slideEditor.cBlock,
                oldIndexes: data.oldIndexes,
                newIndexes: indexes
            }
        });
    });

    // $scope.$on('customCssEvent', function(e, data) {
    //     var s = $scope.slides[$scope.slideEditor.cSlide],
    //         b = s.blocks[$scope.slideEditor.cBlock];
    //     if ('changeCss' === data.type) {
    //         angular.forEach(data.oldValue, function(value, key) {
    //             delete b.styles[key];
    //         });
    //         angular.forEach(data.newValue, function(value, key) {
    //             var allow = true;
    //             if ('' != key) {
    //                 angular.forEach($rootScope.dataCss, function(v) {
    //                     if (v === key) {
    //                         allow = false;
    //                     }
    //                 });
    //                 if (allow) {
    //                     b.styles[key] = value;
    //                 }
    //             }
    //         });
    //         if (!$scope.tmpStyle.customCss) {
    //             $scope.tmpStyle.customCss = angular.copy(data.oldValue, {});
    //             $scope.tmpStyle.styles = angular.copy(b.styles, {});
    //             $scope.tmpStyle.size = angular.copy(s.size, {});
    //         }
    //         $timeout.cancel($scope.tmpStyle.timer);
    //         $scope.tmpStyle.timer = $timeout(function() {
    //             $scope.tmpStyle.timer = null;
    //             $scope.$broadcast('savingActionAddEvent', {
    //                 event: {
    //                     type: 'setStyles',
    //                     customCss: true,
    //                     slideIndex: $scope.slideEditor.cSlide,
    //                     blockIndex: $scope.slideEditor.cBlock,
    //                     oldStyles: $scope.tmpStyle.styles,
    //                     newStyles: angular.copy(b.styles, {}),
    //                     oldCustomCss: $scope.tmpStyle.customCss,
    //                     newCustomCss: angular.copy(data.newValue, {}),
    //                     oldSize: $scope.tmpStyle.size,
    //                     newSize: angular.copy(s.size, {})
    //                 }
    //             });
    //             $scope.tmpStyle.styles = null;
    //             $scope.tmpStyle.customCss = null;
    //             $scope.tmpStyle.size = null;
    //         }, 450);
    //     }
    // });

    $scope.$on('slideMoveEvent', function(e, data) {
        var s, arr = [], oldSlides, oldActiveSlide;

        if ( null !== data.cIndex ) {
            if (data.cIndex !== $scope.slideEditor.cSlide) {
                $scope.activateSlide(data.cIndex);
            }
        } else {
            oldActiveSlide = $scope.slideEditor.cSlide;
            angular.forEach(data.elements, function(el, i) {
                s = $scope.slides[parseInt(angular.element(el.node).attr('index'))];

                if (s.focusClass === 'active') {
                    $scope.slideEditor.cSlide = i;
                }
                s.index = i;
                angular.forEach(s.blocks, function(b, j) {
                    if ('name' in b.ta && b.ta.name !== null && b.ta.name !== '') {
                        b.ta.name = 'slide' + i + 'text' + j;
                    }
                });
                arr.push(s);
            });

            $scope.$apply(function() {
                oldSlides = $scope.slides;
                $scope.slides = [];
            });

            $scope.$apply(function() {
                $scope.slides = arr;
                $scope.$broadcast('savingActionAddEvent', {
                    event: {
                        type: 'moveSlide',
                        newSlideIndex: $scope.slideEditor.cSlide,
                        oldSlideIndex: oldActiveSlide,
                        newSlides: arr,
                        oldSlides: oldSlides
                    }
                });
                $scope.toggleBlocks(null);
            });
        }

        $scope.$broadcast('slidePreviewUpdateEvent', {
            index: $scope.slideEditor.cSlide
        });
    });

    $scope.toggleBlocks = function(index) {
        $scope.slideEditor.cBlock = index;
        $scope.slides[$scope.slideEditor.cSlide].activeBlock = index;

        if (!$scope.$$phase) {
            $scope.$apply(function() {
                activeTab.currentTab.index = 0;
            });
        } else {
            activeTab.currentTab.index = 0;
        }

        if (null !== index && undefined !== index) {
            // $scope.slideEditor.title = $scope.slides[$scope.slideEditor.cSlide].blocks[$scope.slideEditor.cBlock].type;
            $scope.slideEditor.title = $scope.slides[$scope.slideEditor.cSlide].blocks[$scope.slideEditor.cBlock].title;
            $scope.slideEditor.flags.slide = false;
            $scope.slideEditor.flags.block = true;
        } else {
            $scope.slideEditor.title = 'Slide ' + ($scope.slideEditor.cSlide + 1) + '.';
            $scope.slideEditor.flags.slide = true;
            $scope.slideEditor.flags.block = false;
        }
    };

    $scope.outlineClick = function(e) {
        var b = angular.element(e.target);
        if (b[0].tagName.toLowerCase() !== 'i') {
            b = b.find('i');
        }

        if ($rootScope.outlineIsShow) {
            b.removeClass('flaticon-visibility-off');
            b.addClass('flaticon-eye-close-up');
        } else {
            b.removeClass('flaticon-eye-close-up');
            b.addClass('flaticon-visibility-off');
        }

        $rootScope.outlineIsShow = !$rootScope.outlineIsShow;
    }

    $scope.$on('toggleBlockEvent', function(e, data) {
        $scope.$broadcast('slidePreviewUpdateEvent', {
            index: $scope.slideEditor.cSlide
        });

        globalMenuAPI.close();

        if (data.newBlock) {
            $scope.$broadcast('savingActionAddEvent', {
                event: {
                    type: 'newBlock',
                    slideIndex: $scope.slideEditor.cSlide,
                    index: data.index,
                    options: data.options,
                    title: data.title,
                    blockType: data.blockType,
                    imgName: data.imgName,
                    base64: data.base64,
                    videoType: data.videoType,
                    url: data.url,
                    lastActiveBlock: $scope.slideEditor.cBlock
                }
            });
        }
        $scope.toggleBlocks(data.index);
    });

    // on remove
    $scope.$on('editorRmoveBlockEvent', function(e, data) {
        if (!data.noSaveAction) {
            $scope.$broadcast('savingActionAddEvent', {
                event: {
                    type: 'removeBlock',
                    slideIndex: $scope.slideEditor.cSlide,
                    blockIndex: $scope.slideEditor.cBlock,
                    block: data.node
                }
            });
        }
        $scope.$broadcast('slidePreviewUpdateEvent', {
            index: $scope.slideEditor.cSlide
        });
    });

    $scope.$on('removeSlideEvent', function(e, data) {
        var index = parseInt(data.index);
        $scope.removeSlide(index);
    });

    $scope.$on('savingActionToggle', function(e, data) {
        globalMenuAPI.close();
        if ('newSlide' === data.event.type) {
            /**
             * event: {
             *     type: newSlide ? 'newSlide' : 'activateSlide',
             *     index: index,
             *     slide: $scope.slides[index],
             *     lastActiveSlide: $scope.slideEditor.cSlide
             * }
             */
            if ('prev' === data.action) {
                $scope.slides[$scope.slideEditor.cSlide].focusClass = '';
                $scope.slideEditor.cSlide = data.event.slide.index;

                // angular.forEach($scope.slides[$scope.slideEditor.cSlide].blocks, function(b) {
                //     if ('text' === b.type && b.ta.isActive) {
                //         b.ta.isActive = false;
                //         b.node.innerHTML = b.content;
                //     }
                // });

                $scope.removeSlide(data.event.index, data.event.lastActiveSlide, true, data.deferred);
            } else {
                $scope.slides.push(data.event.slide);
                $scope.activateSlide(data.event.index, true, data.deferred);
            }
        } else if ('removeSlide' === data.event.type) {
            /**
             * event: {
             *     type: 'removeSlide',
             *     activeIndex: '',
             *     index: i,
             *     slide: s
             * }
             */
            if ('prev' === data.action) {
                var rewriteIndex = false, lastItem = data.event.index === $scope.slides.length, arr = [];
                angular.forEach($scope.slides, function(s, i) {
                    if (i === data.event.index) {
                        arr.push(data.event.slide);
                        rewriteIndex = true;
                    }

                    s.focusClass = '';
                    arr.push(s);
                    if (rewriteIndex) {
                        arr[arr.length - 1].index = arr.length - 1;
                    }
                });
                if (lastItem) {
                    arr.push(data.event.slide);
                }
                $scope.$apply(function() {
                    $scope.slides = arr;
                    $scope.activateSlide(data.event.activeIndex, true, data.deferred);
                });
            } else {
                $scope.slides[$scope.slideEditor.cSlide].focusClass = '';
                $scope.slideEditor.cSlide = data.event.activeIndex;
                $scope.removeSlide(data.event.index, undefined, true, data.deferred);
            }
        } else if ('moveSlide' === data.event.type) {
            /**
             *  event: {
             *      type: 'moveBlock',
             *      activeSlide: $scope.slideEditor.cSlide,
             *      oldActiveSlide: oldActiveSlide,
             *      newSlides: arr,
             *      oldSlides: oldSlides
             *  }
             */

            $scope.$apply(function() {
                $scope.slides = [];
            });
            $scope.$apply(function() {
                if ('prev' === data.action) {
                    $scope.slides = data.event.oldSlides;
                    $scope.slideEditor.cSlide = data.event.oldSlideIndex;
                    angular.forEach($scope.slides, function(s, i) {
                        s.index = i;
                        if (s.index !== data.event.oldSlideIndex) {
                            s.focusClass = '';
                        }
                    });
                    $scope.activateSlide(data.event.oldSlideIndex, true);
                    // $scope.slideEditor.cSlide = data.event.oldSlideIndex;
                } else {
                    $scope.slides = data.event.newSlides;
                    $scope.slideEditor.cSlide = data.event.newSlideIndex;
                    angular.forEach($scope.slides, function(s, i) {
                        s.index = i;
                        if (s.index !== data.event.newSlideIndex) {
                            s.focusClass = '';
                        }
                    });
                    $scope.activateSlide(data.event.newSlideIndex, true);
                    // $scope.slideEditor.cSlide = data.event.newSlideIndex;
                }
                $scope.toggleBlocks(null);
                data.deferred.resolve();
            });
        } else if ('newBlock' === data.event.type) {
            /**
             * event: {
             *     type: 'newBlock',
             *     slideIndex: $scope.slideEditor.cSlide,
             *     index: data.index,
             *     blockType: data.blockType,
             *     imgName: data.imgName,
             *     base64: data.base64,
             *     videoType: data.videoType,
             *     url: data.url,
             *     lastActiveBlock: $scope.slideEditor.cBlock
             * }
             */

            var action = function() {
                if ('prev' === data.action) {
                    $scope.$apply(function() {
                        $scope.$broadcast('editSlideEvent', {
                            type: 'remove',
                            lastActiveBlock: data.event.lastActiveBlock,
                            blockIndex: data.event.index,
                            noSaveAction: true,
                            cb: function() {
                                $scope.toggleBlocks(data.event.lastActiveBlock);
                                $scope.$broadcast('slidePreviewUpdateEvent', {
                                    index: $scope.slideEditor.cSlide,
                                    cb: function() {
                                        data.deferred.resolve();
                                    }
                                });
                            }
                        });
                    });
                } else {
                    $scope.$apply(function() {
                        var fi, cs = $scope.slides[$scope.slideEditor.cSlide],
                        block = {};
                        block = angular.copy($scope.defBlock, {});

                        if ('button' === data.event.blockType || 'shape' === data.event.blockType) {
                            block.correctStyles['bg-color'] = 'rgba(173,173,173,1)';
                            block.correctStyles['background-color'] = 'rgba(173,173,173,1)';

                            if ('button' === data.event.blockType) {
                                block.content = '<p style="line-height:1;"><span style="font-size: 14px;">Button text..</span></p>';
                                block.link = true;
                                block.correctStyles['padding'] = 8;
                            } else {
                                block.correctStyles['top'] = '10%';
                                block.correctStyles['left'] = '10%';
                                block.saveProportions = false;
                            }
                        }

                        // block.options = angular.copy($scope.defaults.blockOptions, []);
                        block.options = data.event.options;

                        block.index = cs.blocks.length;

                        block.title = data.event.title;


                        block.type = data.event.blockType;
                        block.url = data.event.url;
                        block.base64 = data.event.base64;
                        block.video.videoType = data.event.videoType;

                        fi = $scope.createFakeImg();
                        block.fakeImg = fi.img;
                        block.fakeImgStyles = fi.style;

                        $scope.$broadcast('editorEvent', {
                            type: 'newBlock',
                            noSaveAction: true,
                            index: $scope.slideEditor.cSlide,
                            newBlock: block,
                            cb: function() {
                                data.deferred.resolve();
                            }
                        });
                    });
                }
            };
            if ($scope.slideEditor.cSlide !== data.event.slideIndex) {
                $scope.$apply(function() {
                    $scope.activateSlide(data.event.slideIndex, true, false, function() {
                        action();
                    });
                });
            } else {
                action();
            }
        } else if ('removeBlock' === data.event.type) {
            /**
             * event: {
             *     type: 'removeBlock',
             *     slideIndex: $scope.slideEditor.cSlide,
             *     blockIndex: $scope.slideEditor.cBlock,
             *     block: data.node
             * }
             */

            var action = function() {
                if ('prev' === data.action) {
                    // add
                    $scope.$broadcast('editorEvent', {
                        type: 'newBlock',
                        noSaveAction: true,
                        inStore: true,
                        index: $scope.slideEditor.cSlide,
                        newBlock: data.event.block,
                        cb: function() {
                            $scope.toggleBlocks(data.event.blockIndex);
                            data.deferred.resolve();
                        }
                    });
                } else {
                    // remove
                    $scope.$broadcast('editSlideEvent', {
                        type: 'remove',
                        blockIndex: data.event.blockIndex,
                        lastActiveBlock: null,
                        noSaveAction: true,
                        cb: function() {
                            $scope.toggleBlocks(data.event.lastActiveBlock);
                            data.deferred.resolve();
                        }
                    });
                }
            };
            if ($scope.slideEditor.cSlide !== data.event.slideIndex) {
                $scope.$apply(function() {
                    $scope.activateSlide(data.event.slideIndex, true, false, function() {
                        action();
                    });
                });
            } else {
                action();
            }
        } else if ('setStyles' === data.event.type) {
            /**
             * event: {
             *     type: 'setStyles',
             *     slideIndex: $scope.slideEditor.cSlide,
             *     blockIndex: $scope.slideEditor.cBlock,
             *     oldStyles: $scope.tmpStyle.oldStyles,
             *     newStyles: angular.copy(s.styles, {}),
             *     oldCorrectStyles: $scope.tmpStyle.oldCorrectStyles,
             *     newCorrectStyles: angular.copy(s.correctStyles, {}),
             *     oldPanelStyles: $scope.tmpStyle.panelStyles,
             *     newPanelStyles: angular.copy(p.styles, {})
             *     oldSize: $scope.tmpStyle.size,
             *     newSize: angular.copy(s.size, {},
             *     oldFakeImg = $scope.tmpStyle.fakeImg,
             *     newFakeImg = angular.copy(b.fakeImgStyles, {}),
             *     oldContent: $scope.tmpStyle.content,
             *     newContent: angular.copy(b.content, {}),
             *     oldCustomCss: $scope.tmpStyle.customCss,
             *     newCustomCss: data.newValue,
             * }
             */

            $rootScope.dontsave = true;
            var s = $scope.slides[data.event.slideIndex],
                b = s.blocks[data.event.blockIndex],
                action = function() {
                    $scope.toggleBlocks(data.event.blockIndex);
                    $scope.$broadcast('activeBlockEvent', {
                        index: data.event.blockIndex,
                        cb: function() {
                            if ('prev' === data.action) {
                                $scope.$apply(function() {
                                    data.event.oldStyles && (b.styles = angular.copy(data.event.oldStyles, {}));
                                    data.event.oldCorrectStyles && (b.correctStyles = angular.copy(data.event.oldCorrectStyles, {}));
                                    data.event.oldPanelStyles && (s.panel.styles = angular.copy(data.event.oldPanelStyles, {}));
                                    data.event.oldSize && (b.size = angular.copy(data.event.oldSize, {}));
                                    data.event.oldFakeImg && (b.fakeImgStyles = angular.copy(data.event.oldFakeImg, {}));
                                    data.event.oldContent && (b.content = data.event.oldContent);

                                    if (undefined !== data.event.oldSaveProportions) {
                                        b.saveProportions = data.event.oldSaveProportions;
                                    }
                                    data.deferred.resolve();
                                });
                                if (data.event.oldCustomCss) {
                                    $scope.$apply(function() {
                                        b.customCss = angular.copy(data.event.oldCustomCss, {});
                                    });
                                }
                                // if (data.event.oldContent) {
                                //     b.node.innerHTML = data.event.oldContent;
                                //     $compile(angular.element(b.node).contents())($scope);
                                // }
                            } else {
                                $scope.$apply(function() {
                                    data.event.newStyles && (b.styles = angular.copy(data.event.newStyles, {}));
                                    data.event.newCorrectStyles && (b.correctStyles = angular.copy(data.event.newCorrectStyles, {}));
                                    data.event.newPanelStyles && (s.panel.styles = angular.copy(data.event.newPanelStyles, {}));
                                    data.event.newSize && (b.size = angular.copy(data.event.newSize, {}));
                                    data.event.newFakeImg && (b.fakeImgStyles = angular.copy(data.event.newFakeImg, {}));
                                    data.event.newContent && (b.content = data.event.newContent);
                                    if (undefined !== data.event.newSaveProportions) {
                                        b.saveProportions = data.event.newSaveProportions;
                                    }
                                    data.deferred.resolve();
                                });
                                if (data.event.newCustomCss) {
                                    $scope.$apply(function() {
                                        b.customCss = angular.copy(data.event.newCustomCss, {});
                                    });
                                }
                                // if (data.event.newContent) {
                                //     b.node.innerHTML = data.event.newContent;
                                //     $compile(angular.element(b.node).contents())($scope);
                                // }
                            }
                        }
                    });
                };

            if ($scope.slideEditor.cSlide !== data.event.slideIndex) {
                $scope.$apply(function() {
                    $scope.activateSlide(data.event.slideIndex, true, false, function() {
                        action();
                    });
                });
            } else {
                action();
            }

            // if (data.event.customCss) {
            //     $scope.$broadcast('customCssUpdateEvent');
            // }
        } else if ('canvasResize' === data.event.type) {
            /**
             * event: {
             *     type: 'canvasResize',
             *     slideIndex: cs.index,
             *     blockIndex: cb.index,
             *     oldSise: {},
             *     newSize: {}
             * }
             */

            var b = $scope.slides[data.event.slideIndex].blocks[data.event.blockIndex],
                setBlockIndex = function() {
                    if (null !== data.event.blockIndex && $scope.slideEditor.cBlock !== data.event.blockIndex) {
                        $scope.toggleBlocks(data.event.blockIndex);
                        $scope.$broadcast('activeBlockEvent', {
                            index: data.event.blockIndex,
                            cb: function() {
                                action();
                            }
                        });
                    } else {
                        action();
                    }
                },
                action = function() {
                    var w, h, p;
                    if ('prev' === data.action) {
                        w = parseInt(data.event.oldSize.width);
                        h = parseInt(data.event.oldSize.height);
                        p = data.event.oldProportions;
                    } else {
                        w = parseInt(data.event.newSize.width);
                        h = parseInt(data.event.newSize.height);
                        p = data.event.newProportions;
                    }

                    $timeout.cancel($scope.globalMenuTimer);

                    $scope.$broadcast('edtorZoomEvent', {type: 'resize', param: {
                        width: w,
                        height: h,
                        callback: function() {
                            $timeout(function() {
                                $scope.proportionsIsSet = p;
                                angular.forEach($scope.slides[data.event.slideIndex].blocks, function(b_) {
                                    var w_ = b_.node.offsetWidth + 'px',
                                        h_ = b_.node.offsetHeight + 'px';

                                    if (b_.isBackground) {
                                        angular.element(b_.outline).css({
                                            'top': (h - parseInt(h_)) / 2 + 'px',
                                            'left': (w - parseInt(w_)) / 2 + 'px',
                                        });
                                    }

                                    angular.element(b_.outline).css({
                                        'width': w_,
                                        'height': h_
                                    });
                                });
                            }, 0);
                        }
                    }});

                    $scope.$broadcast('slidePreviewSlideSizeEvent', { width: w, height: h, index: $scope.slideEditor.cSlide });
                    $scope.$$correctBlocksPosition();
                    null !== data.event.blockIndex && $scope.$broadcast('auxiliaryPanelUpdateSizeEvent');
                    data.deferred.resolve();
                };

            if ($scope.slideEditor.cSlide !== data.event.slideIndex) {
                $scope.$apply(function() {
                    $scope.activateSlide(data.event.slideIndex, true, false, function() {
                        setBlockIndex();
                    });
                });
            } else {
                setBlockIndex();
            }
        } else if ('zIndex' === data.event.type) {
            /**
             * event: {
             *    type: 'zIndex',
             *    slideIndex: $scope.slideEditor.cSlide,
             *    blockIndex: $scope.slideEditor.cBlock,
             *    oldIndexes: data.oldIndexes,
             *    newIndexes: indexes
             * }
             */

            var b = $scope.slides[data.event.slideIndex].blocks[data.event.blockIndex],
                setBlockIndex = function() {
                    if ($scope.slideEditor.cBlock !== data.event.blockIndex) {
                        $scope.toggleBlocks(data.event.blockIndex);
                        $scope.$broadcast('activeBlockEvent', {
                            index: data.event.blockIndex,
                            cb: function() {
                                action();
                            }
                        });
                    } else {
                        action();
                    }
                },
                action = function() {
                    angular.forEach($scope.slides[data.event.slideIndex].blocks, function(b, i) {
                        if ('prev' === data.action) {
                            b.styles['z-index'] = data.event.oldIndexes[i];
                        } else {
                            b.styles['z-index'] = data.event.newIndexes[i];
                        }
                    });
                    data.deferred.resolve();
                };

            if ($scope.slideEditor.cSlide !== data.event.slideIndex) {
                $scope.$apply(function() {
                    $scope.activateSlide(data.event.slideIndex, true, false, function() {
                        setBlockIndex();
                    });
                });
            } else {
                setBlockIndex();
            }
        } else if ('setBeckground' === data.event.type) {
            /**
             * event: {
             *     type: 'setBeckground',
             *     slideIndex: cs.index,
             *     blockIndex: cb.index,
             *     isBackground: cb.isBackground
             * }
             */

            var b = $scope.slides[data.event.slideIndex].blocks[data.event.blockIndex],
                setBlockIndex = function() {
                    if ($scope.slideEditor.cBlock !== data.event.blockIndex) {
                        $scope.toggleBlocks(data.event.blockIndex);
                        $scope.$broadcast('activeBlockEvent', {
                            index: data.event.blockIndex,
                            cb: function() {
                                action();
                            }
                        });
                    } else {
                        action();
                    }
                },
                action = function() {
                    b.backgroundOldStyle = data.event.backgroundOldStyle;
                    $scope.setAsBackground({ isBackground: 'prev' === data.action ? data.event.isBackground : !data.event.isBackground });
                    data.deferred.resolve();
                };

            if ($scope.slideEditor.cSlide !== data.event.slideIndex) {
                $scope.$apply(function() {
                    $scope.activateSlide(data.event.slideIndex, true, false, function() {
                        setBlockIndex();
                    });
                });
            } else {
                setBlockIndex();
            }
        }
    });

    $scope.$on('inputStyleEvent', function(ev, data) {
        var s = $scope.slides[$scope.slideEditor.cSlide],
            b = s.blocks[$scope.slideEditor.cBlock], e;
        if ('focus' === data.type) {
            // if (!$scope.tmpStyle.styles) {
            //     $scope.tmpStyle.styles = angular.copy(b.styles, {});
            // }
        } else if ('blur' === data.type) {
            if ($scope.tmpStyle.styles) {
                $scope.tmpStyle.timer = null;

                e = {
                    type: 'setStyles',
                    slideIndex: $scope.slideEditor.cSlide,
                    blockIndex: $scope.slideEditor.cBlock,
                    oldStyles: $scope.tmpStyle.styles,
                    newStyles: angular.copy(b.styles, {}),
                    oldPanelStyles: $scope.tmpStyle.panelStyles,
                    newPanelStyles: angular.copy(s.panel.styles, {}),
                    oldSize: $scope.tmpStyle.size,
                    newSize: angular.copy(s.size, {}),
                    oldFakeImg: $scope.tmpStyle.fakeImg,
                    newFakeImg: angular.copy(b.fakeImgStyles, {})
                };

                if (null !== $scope.tmpStyle.saveProportions) {
                    e.oldSaveProportions = $scope.tmpStyle.saveProportions;
                    e.newSaveProportions = b.saveProportions;
                }

                $scope.$broadcast('savingActionAddEvent', { event: e });
                $scope.tmpStyle.styles = null;
                $scope.tmpStyle.fakeImg = null;
                $scope.tmpStyle.panelStyles = null;
                $scope.tmpStyle.size = null;
                $scope.tmpStyle.saveProportions = null;
            }
        } else if ('change' === data.type) {
            if (!$scope.tmpStyle.styles) {
                $scope.tmpStyle.styles = angular.copy(b.styles, {});
                $scope.tmpStyle.styles[data.typeStyle] = data.oldValue;

                $scope.tmpStyle.panelStyles = angular.copy(s.panel.styles, {});
                $scope.tmpStyle.size = angular.copy(s.size, {});
                $scope.tmpStyle.fakeImg = angular.copy(b.fakeImgStyles, {});
            }
        }
    });

    $scope.$on('auxiliaryPanelMouseDownEvent', function(e, data) {
        var s = $scope.slides[$scope.slideEditor.cSlide],
            b = s.blocks[$scope.slideEditor.cBlock];

        if (!$scope.tmpStyle.styles) {
            $scope.tmpStyle.styles = angular.copy(b.styles, {});

            $scope.tmpStyle.panelStyles = angular.copy(s.panel.styles, {});
            $scope.tmpStyle.size = angular.copy(s.size, {});
            if (b.fakeImg) {
                $scope.tmpStyle.fakeImg = angular.copy(b.fakeImgStyles, {});
            }
        }
    });

    $scope.$on('auxiliaryPanelMouseUpEvent', function(e, data) {
        var s = $scope.slides[$scope.slideEditor.cSlide],
            b = s.blocks[$scope.slideEditor.cBlock], e;

        if ($scope.tmpStyle.styles) {
            $timeout.cancel($scope.tmpStyle.timer);
            if (data.move) {
                $scope.tmpStyle.timer = null;
                e = {
                    type: 'setStyles',
                    slideIndex: $scope.slideEditor.cSlide,
                    blockIndex: $scope.slideEditor.cBlock,
                    oldStyles: $scope.tmpStyle.styles,
                    newStyles: angular.copy(b.styles, {}),
                    oldPanelStyles: $scope.tmpStyle.panelStyles,
                    newPanelStyles: angular.copy(s.panel.styles, {}),
                    oldSize: $scope.tmpStyle.size,
                    newSize: angular.copy(s.size, {})
                };

                if (b.fakeImg) {
                    e.oldFakeImg = $scope.tmpStyle.fakeImg;
                    e.newFakeImg = angular.copy(b.fakeImgStyles, {});
                }

                if (null !== $scope.tmpStyle.saveProportions) {
                    e.oldSaveProportions = $scope.tmpStyle.saveProportions;
                    e.newSaveProportions = b.saveProportions;
                }


                $scope.$broadcast('savingActionAddEvent', {
                    event: e
                });
                $scope.tmpStyle.styles = null;
                $scope.tmpStyle.fakeImg = null;
                $scope.tmpStyle.panelStyles = null;
                $scope.tmpStyle.size = null;
                $scope.tmpStyle.saveProportions = null;
            } else {
                $scope.tmpStyle.styles = null;
                $scope.tmpStyle.fakeImg = null;
                $scope.tmpStyle.panelStyles = null;
                $scope.tmpStyle.size = null;
                $scope.tmpStyle.saveProportions = null;
            }
        }
    });

    $scope.$on('blockTextOldValueEvent', function(e, data) {
        // data.value
        var s = $scope.slides[$scope.slideEditor.cSlide],
            b = s.blocks[$scope.slideEditor.cBlock];

        if (!$scope.tmpStyle.content) {
            $scope.tmpStyle.content = data.value;

            $scope.tmpStyle.panelStyles = angular.copy(s.panel.styles, {});
            $scope.tmpStyle.size = angular.copy(s.size, {});
        }
    });

    $rootScope.$on('resizeAxiliaryPanel', function(e) {
        $scope.setStyles(undefined, undefined,  true);
    });

    $scope.$on('timelineSetActiveBlock', function(e, data) {
        $scope.$broadcast('slidePreviewUpdateEvent', {
            index: $scope.slideEditor.cSlide
        });

        $scope.$broadcast('activeBlockEvent', {
            index: data.index
        });

        if (data.index !== $scope.slideEditor.cBlock) {
            $scope.toggleBlocks(data.index);
        }

        if (data.bg) {
            $scope.setAsBackground();
        }
        data.callback && data.callback();
    });

    $scope.closeConstructor = function() {};

    angular.element(document).ready(function() {
        var i, timer, start = function(arr) {
            $scope.mainField = angular.element($window.document.getElementById('working-field'));
            $scope.$broadcast('edtorZoomEvent', { type: 'first-start' });

            if ('id' in $rootScope.idSlideshow) {} else { $scope.activateSlide(); }

            // timer = $timeout(function() {
            //     $rootScope.loader = true;
            // }, 300);

            angular.forEach(arr, function(s) {
                angular.forEach(s.blocks, function(b) {
                    b.content = b.content.replace(/&#39/g, '\'');
                    b.content = b.content.replace(/&#34/g, '\"');

                    if ("video" === b.type) {
                        b.fakeImg = ($scope.createFakeImg()).img;
                    }
                });
            });

            $scope.$$loadAllImg(function() {
                if (arr) {
                    $scope.slides = arr;
                }

                // $timeout.cancel(timer);
                // $rootScope.loader = false;
                if ($scope.slides.length > 0) {
                    $scope.activateSlide(0);
                    $timeout(function() {
                        $scope.allVisible = false;
                        if (arr) {
                            angular.forEach($scope.slides, function(slide, i) {
                                angular.forEach(slide.blocks, function(block, j) {
                                    if (block.isBackground) {
                                        $scope.setAsBackground(false, {slide: i, block: j});
                                    }
                                });
                            });

                            for (var i = 0; i < arr.length; i++) {
                                $scope.$broadcast('slidePreviewUpdateEvent', {
                                    index: i
                                });
                            }

                            $timeout(function() {
                                getHtmlSlideshow($scope, function(slideshowHTML) {
                                    $rootScope.oldSlideshow = JSON.stringify(slideshowHTML);
                                    $timeout.cancel(timer);
                                    $rootScope.$apply(function() {
                                        $rootScope.loader = false;
                                    });
                                    angular.element($window.document.getElementById('first-load')).remove();
                                });
                            }, 0);
                        } else {
                            $timeout.cancel(timer);
                            $rootScope.$apply(function() {
                                $rootScope.loader = false;
                            });
                            angular.element($window.document.getElementById('first-load')).remove();
                        }
                        if (!('id' in $rootScope.idSlideshow)) {
                            $scope.$broadcast('savingActionReset');
                        }
                    }, 0);
                } else {
                    $timeout.cancel(timer);
                    $rootScope.loader = false;
                    angular.element($window.document.getElementById('first-load')).remove();
                }
            }, arr);
        };

        $rootScope.loader = true;
        getResources([
            paths.json[0],
            paths.json[1],
            paths.json[2],
            paths.json[3]
        ], function(data) {
            var i, noready = false;
            if (data[0]) {
                $scope.defaults.slideshowOptions = data[0];
                $scope.slideshowOptions = angular.copy(data[0], []);
            }

            if (data[3]) {
                $scope.slideshowOptionsGroups = angular.copy(data[3], []);
            }

            $scope.defaults.slideOptions = data[1] && data[1];
            $scope.defaults.blockOptions = data[2] && data[2];

            for (i = 0; i < data.length; i++) {
                if (null === data[i]) {
                    noready = true;
                    break;
                }
            }

            $rootScope.idSlideshow = $location.search();

            if (!noready) {
                messages.ready();
                if (messages.status) {
                    $scope.closeConstructor = function(e) {
                        e.preventDefault();
                        e.stopPropagation();

                        var b = e.target, timer;

                        while ('button' !== b.tagName.toLowerCase()) {
                            b = b.parentNode;
                        }

                        b = angular.element(b);
                        b.attr('disabled', 'disabled');

                        timer = $timeout(function() {
                            b.addClass('loading');
                        }, 250);

                        getHtmlSlideshow($scope, function(slideshowHTML) {
                            var slideshow = JSON.stringify(slideshowHTML);

                            $timeout.cancel(timer);
                            b.removeClass('loading');
                            b.removeAttr('disabled');

                            function blockExist() {
                                var i, result = false;

                                if ($scope.slides.length) {
                                    for (i = 0; i < $scope.slides.length; i++) {
                                        if ($scope.slides[i].blocks.length) {
                                            result = true;
                                            break;
                                        }
                                    }
                                }

                                return result;
                            }

                            if (blockExist() && slideshow !== $rootScope.oldSlideshow) {
                                aModalWindowManager.show('Changes you made may not be saved.', {
                                    saveButtonCallBack: function() {
                                        saveSlideshow($scope, function(err) {
                                            messages.closeConstructor({id: $rootScope.idSlideshow.id});
                                            aModalWindowManager.hide();
                                        });
                                    },
                                    dSaveButtonCallBack: function() {
                                        messages.closeConstructor({id: $rootScope.idSlideshow.id});
                                        aModalWindowManager.hide();
                                    },
                                    cancelButtonCallBack: function() {
                                        aModalWindowManager.hide();
                                    }
                                });
                            } else {
                                messages.closeConstructor({id: $rootScope.idSlideshow.id});
                            }
                        });
                    };
                }
                if ('id' in $rootScope.idSlideshow && messages.status) {
                        messages.setCallbacks({
                            getSlideshowJSON: function(data) {
                                $scope.slideshowLoad(data, function(arr) {
                                    start(arr);
                                });
                            },
                            getSlideshowJSON_fail: function() {
                                $rootScope.idSlideshow = {};
                                start();
                            }
                        });
                        messages.getJSON({id: $rootScope.idSlideshow.id});
                } else {
                    $rootScope.idSlideshow = {};
                    start();
                }
            }
        });
    });

    $scope.slideshowLoad = function(data, callback) {
        var i, arr = [];
        // $scope.slideshowOptions = data[1];
        for (i = 0; i < data[1].length; i++) {
            $scope.slideshowOptions[lib.getOptionIndex($scope.slideshowOptions, data[1][i].name)].value = data[1][i].value;
        }

        angular.forEach($scope.slideshowOptions, function(o) {
            if ('values' in o) {
                o.value = o.value.toString();
                o.values[0] = o.values[0].toString();
                o.values[1] = o.values[1].toString();
            }
        });
        angular.forEach(data[0], function(slide, i) {
            slide.focusClass = '';
            // console.log(window.dataURLtoBlob && $window.URL.createObjectURL(window.dataURLtoBlob(slide.blocks[0].base64)));
            // slide.blocks[0] = window.dataURLtoBlob && $window.URL.createObjectURL(window.dataURLtoBlob(slide.blocks[0].base64));

            function removeTr(obj) {
                for (var i in obj) {
                    if ('$$hashKey' === i) {
                        delete obj[i];
                    } else if (angular.isObject(obj[i])) {
                        removeTr(obj[i]);
                    }
                }
            }
            removeTr(slide);

            angular.forEach(slide.blocks, function(b) {
                if (b.base64) {
                    b.url = b.base64;
                }
            });

            slide.panel.node = null;
            slide.node = angular.element('<div>')[0];

            arr.push(slide);
            // $scope.slides.push(slide);
        });
        callback(arr);
    };

    $rootScope.$watch('outlineIsShow', function(nv) {
        $scope.mainField || ($scope.mainField = angular.element($window.document.getElementById('working-field')));
        if (nv) {
            $scope.mainField.addClass('outline');
        } else {
            $scope.mainField.removeClass('outline');
        }
    });

    function setNewProportions(newValue, oldValue) {
        var cs, cb, i,
            old_w, old_h, new_w, new_h,
            bind;

        if ($rootScope.globalMenuIsOpen) {
            cs = $scope.slides[$scope.slideEditor.cSlide];
            if (cs) {
                cb = cs.blocks[$scope.slideEditor.cBlock];
                i = cb ? cb.index : null;
            } else {
                i = null;
            }

            old_w = oldValue[0] || newValue[0];
            old_h = oldValue[1] || newValue[1];
            new_w = newValue[0];
            new_h = newValue[1];
            bind = function(nv, ov, cs_, cb_) {
                $scope.$broadcast('edtorZoomEvent', { type: 'resize', param: {
                    width: nv[0],
                    height: nv[1],
                    callback: function() {
                        $timeout(function() {
                            angular.forEach(cs.blocks, function(b) {
                                var w_ = b.node.offsetWidth + 'px',
                                    h_ = b.node.offsetHeight + 'px';

                                angular.element(b.outline).css({
                                    'width': w_,
                                    'height': h_
                                });
                            });
                        }, 0);

                        $scope.$broadcast('savingActionAddEvent', {
                            event: {
                                type: 'canvasResize',
                                slideIndex: cs_.index,
                                blockIndex: i,
                                oldSize: { width: ov[0], height: ov[1] },
                                newSize: { width: nv[0], height: nv[1] }
                            }
                        });
                    }
                }});
            };
            $timeout.cancel($scope.globalMenuTimer);
            $scope.globalMenuTimer = $timeout(function() {
                bind([new_w, new_h], [old_w, old_h], cs, cb);
            }, 300);
        }
    }

    $scope.$watch('slideshowOptions[2].value', function(newValue, oldValue) {
        var other = lib.getOption($scope.slideshowOptions, 'base-height').value;
        setNewProportions([newValue, other], [oldValue, other]);
    });

    $scope.$watch('slideshowOptions[3].value', function(newValue, oldValue) {
        var other = lib.getOption($scope.slideshowOptions, 'base-width').value;
        setNewProportions([other, newValue], [other, oldValue]);
    });
}]);
constructorApp.service('slideshowAPI', ['$window', function($window) {
    var isStopSlideshow = false;
    return {
        stop: function() {
            if (!isStopSlideshow && $window.MagicSlideshow) {
                $window.MagicSlideshow.stop();
                isStopSlideshow = true;
            }
        },
        start: function() {
            if ($window.MagicSlideshow) {
                $window.MagicSlideshow.start();
                isStopSlideshow = false;
            }
        }
    };
}]);


constructorApp.service('parseSlide', [function() {
    var m = {
            trim: function(str) {
                return str.replace(/^\s+|\s+$/g, '');
            },

            copy: function(resource) {
                var o,
                    copyObj = function(object_) {
                        var i, obj = {};
                        for(i in object_) {
                            if (!object_.hasOwnProperty(i) || /^\$|^\$\$/.test(i)) continue;
                            if ('node' == i && '' !== object_[i] || 'wrapper' == i && '' !== object_[i]) {
                                obj[i] = object_[i].cloneNode(true);
                            } else if (object_[i] instanceof window.Object && !(object_[i] instanceof window.Function)) {
                                if (Array.isArray(object_[i])) {
                                    obj[i] = copyArray(object_[i]);
                                } else {
                                    obj[i] = copyObj(object_[i]);
                                }
                            } else {
                                obj[i] = object_[i];
                            }
                        }
                        return obj;
                    },
                    copyArray = function(array) {
                        var i, arr = [];
                        for (i = 0; i < array.length; i++) {
                            if (array[i] instanceof window.Object && !(array[i] instanceof window.Function)) {
                                if (Array.isArray(array[i])) {
                                    arr.push(copyArray(array[i]));
                                } else {
                                    arr.push(copyObj(array[i]));
                                }
                            } else {
                                arr.push(array[i]);
                            }
                        }
                        return arr;
                    };

                if (resource instanceof window.Object && !(resource instanceof window.Function)) {
                    o = Array.isArray(resource) ? copyArray(resource) : copyObj(resource);
                } else {
                    o = resource;
                }
                return o;
            },

            getImgName: function(src) {
                src = src.split('/');
                return src[src.length - 1];
            },

            refreshSlide: function(node, blocks) {
                var t = document.createElement('div');

                node.innerHTML = '';
                angular.forEach(blocks, function(b) {
                    node.appendChild(b.node);
                });
                t.appendChild(node);

                return t.innerHTML;
            }
        };
    return m;
}]);

constructorApp.service('loader', [function() {

    this.load = function(source /*string*/, callbacks /*obj*/, linking /*obj*/) {

        var _img = {
            node: document.createElement('img'),
            src: source
        },
        wrapper = document.createElement('div');

        angular.element(_img.node).css({
            'max-width': 'none',
            'max-height': 'none',
        });

        angular.element(_img.node).attr('src', _img.src);

        angular.element(wrapper).css({
            'position': 'absolute',
            'top': '-10000px',
            'left': '-10000px',
            'width': '10px',
            'height': '10px',
            'overflow': 'hidden'
        });

        callbacks || (callbacks = {});

        callbacks.onload || (callbacks.onload = function() {});
        callbacks.onerror || (callbacks.onerror = function() {});

        angular.element(_img.node).on('load', function(e) {
            angular.extend(e, {
                size: {
                    width: _img.node.offsetWidth,
                    height: _img.node.offsetHeight
                },
                img: _img.node,
                imgSourse: _img.src
            });
            angular.element(_img.node).off('load');
            angular.element(_img.node).off('error');
            callbacks.onload(e, linking);
            angular.element(wrapper).remove();
        });

        angular.element(_img.node).on('error', function(e) {
            callbacks.onerror(e, linking);
            angular.element(_img.node).off('load');
            angular.element(_img.node).off('error');
            angular.element(wrapper).remove();
        });

        angular.element(wrapper).append(_img.node)
        angular.element(document.body).append(wrapper);
    };
}]);

constructorApp.service('lib', ['parseSlide', '$rootScope', function(parseSlide, $rootScope) {
    var service = {
        checkArr: function(arr, value) {
            var r = false;
            angular.forEach(arr, function(v) {
                if (v === value) {
                    r = true;
                }
            });
            return r;
        },
        getDoc: function() {
            return (document.compatMode && 'backcompat' == document.compatMode.toLowerCase())
                ? document.body :
                document.documentElement;
        },

        getScroll: function() {
            return {'x': window.pageXOffset || service.getDoc().scrollLeft, 'y': window.pageYOffset || service.getDoc().scrollTop};
        },

        correctFraction: function(number) {
            number = parseFloat(number);
            number = parseInt(number * 10);
            number = number / 10;
            return number;
        },

        getOptionIndex: function(options, option) {
            for (var i = 0; i < options.length; i++) {
                if (option === options[i].name) {
                    return i;
                }
            }
            return false;
        },

        getOption: function(options, option) {
            var i = service.getOptionIndex(options, option);
            return false !== i ? options[i] : false;
        },

        getProportionsSize: function(block, style) {
            var side, prop, w, h, v,
                getProp = function() {
                    var res;
                    if ('image' === block.type) {
                        if ('width' === style) {
                            res = block.size.height / block.size.width;
                        } else {
                            res = block.size.width / block.size.height;
                        }
                    } else if ('video' === block.type) {
                        if ('width' === style) {
                            res = 9/16;
                        } else {
                            res = 16/9;
                        }
                    }
                    return res;
                };
            if ('width' === style || 'height' === style) {
                side = parseSlide.trim(block.styles[style]);
                v = parseFloat(side);
                if (isNaN(v) || !/^[0-9]+(\.{0,1}[0-9]+){0,1}\s*(px|%)$/.test(side)) { return; }

                w = $rootScope.slideSize.width / 100;
                h = $rootScope.slideSize.height / 100;

                if ('width' === style) {
                    if ('auto' !== block.styles.height) {
                        if (/%$/.test(side)) {
                            w *= v;
                            block.styles.height = service.correctFraction((w * getProp()) / h) + '%';
                        } else {
                            block.styles.height = service.correctFraction(v * getProp()) + 'px';
                        }
                    }
                } else {
                    if ('auto' !== block.styles.width) {
                        if (/%$/.test(side)) {
                            h *= v;
                            block.styles.width = service.correctFraction((h * getProp()) / w) + '%';
                        } else {
                            block.styles.width = service.correctFraction(v * getProp()) + 'px';
                        }
                    }
                }
            }
        },

        getPosition: function (el) {
            var l = 0, t = 0;

            if (!!document.documentElement.getBoundingClientRect) {
                var b = el.getBoundingClientRect(), docScroll = service.getScroll(), doc = service.getDoc();
                return {
                    'top':  b.top + docScroll.y - doc.clientTop,
                    'left': b.left + docScroll.x - doc.clientLeft
                };
            }

            do {
                l += el.offsetLeft || 0;
                t += el.offsetTop || 0;
                el = el.offsetParent;
            } while (el && !(/^(?:body|html)$/i).test(el.tagName));

            return { 'top': t, 'left': l };
        },
        camelize: function(str) {
            return str.replace(/-\D/g, function(m) {
                return m.charAt(1).toUpperCase();
            });
        },
        getBorder: function(node) {
            node = angular.element(node);
            var flag = 'none' === node.css('border-style');
            return {
                top: !flag ? (parseInt(node.css('border-top-width')) || 0) : 0,
                left: !flag ? (parseInt(node.css('border-left-width')) || 0) : 0,
                right: !flag ? (parseInt(node.css('border-right-width')) || 0) : 0,
                bottom: !flag ? (parseInt(node.css('border-bottom-width')) || 0) : 0
            };
        },
        getPadding: function(node) {
            node = angular.element(node);
            var flag = 'none' === node.css('padding');
            return {
                top: !flag ? (parseInt(node.css('padding-top')) || 0) : 0,
                left: !flag ? (parseInt(node.css('padding-left')) || 0) : 0,
                right: !flag ? (parseInt(node.css('padding-right')) || 0) : 0,
                bottom: !flag ? (parseInt(node.css('padding-bottom')) || 0) : 0
            };
        },
        obj: {
            positX: function(b) {
                var a, c;
                a = 0;
                c = b.getBoundingClientRect();
                b = document.body;
                a = document.documentElement;
                a = c.left + (a.scrollLeft || b && b.scrollLeft || 0) - (a.clientLeft || b.sclientLeft || 0);
                return Math.round(a);
            },
            positY: function(b) {
                var a, c;
                a = 0;
                c = b.getBoundingClientRect();
                b = document.body;
                a = document.documentElement;
                a = c.top + (a.scrollTop || b && b.scrollTop || 0) - (a.clientTop || b.sclientTop || 0);
                return Math.round(a);
            }
        },
        mouse: {
            pageX: function(b) {
                var a, c, d;
                d = b || event;
                return null == d.pageX && null != d.clientX ? (a = document.body, c = document.documentElement, b = c.scrollLeft || a && a.scrollLeft || 0, b = d.clientX + b - (c.clientLeft || a.clientLeft || 0)) : d.pageX;
            },
            pageY: function(b) {
                var a, c, d;
                d = b || event;
                return null == d.pageX && null != d.clientX ? (a = document.body, c = document.documentElement, b = c.scrollTop || a && a.scrollTop || 0, b = d.clientY + b - (c.clientTop || a.clientTop || 0)) : d.pageY;
            }
        },

        _getCssValue: (window.getComputedStyle) ?
        function(e, name){
            var css = window.getComputedStyle(e, null);

            return css ? css.getPropertyValue(name) || css[name] : null;
        }
        : function(e, name){
            var css = e.currentStyle,
                v = null;

            v = css ? css[ name ] : null;

            if ( null == v && e.style && e.style[ name ] ) {
                v = e.style[ name ];
            }

            return v;
        },

        getCss: function(el, p) {
            var v = null;

            v = service._getCssValue(el, p);

            if ( 'auto' === v ) {
                v = null;
            }

            if ( null !== v ) {
                if ('opacity' == p ) return $J.defined(v) ? parseFloat(v) : 1.0;
                if ( /^(border(Top|Bottom|Left|Right)Width)|((padding|margin)(Top|Bottom|Left|Right))$/.test(p) ) {
                    v = parseInt(v, 10) ? v : '0px';
                }
            }

            return v;
        }
    };
    return service;
}]);

constructorApp.service('convertFontSize', [function() {
    var ratio = {
        pt: 1 / 12,
        px: 1 / 20
    },
    check = function(number) {
        return 'string' === typeof number ? parseFloat(number) : number;
    },
    obj = {
        pxToEm: function(px) {
            var px_ = check(px);
            if (!isNaN(px_)) {
                return px_ * ratio.px + 'em';
            } else {
                return px;
            }
        },
        ptToEm: function(pt) {
            var pt_ = check(pt);
            if (!isNaN(pt_)) {
                return pt_ * ratio.pt + 'em';
            } else {
                return pt;
            }
        },
        convertToEm: function(number) {
            var result = number;
            if (/px/.test(number)) {
                result = obj.pxToEm(number);
            } else if (/pt/.test(number)) {
                result = obj.ptToEm(number);
            }
            return result;
        },
        convertInvestedEm: function(node) {
            var calcEm = function(n, lastEm) {
                n = angular.element(n);
                angular.forEach(n.children(), function(child) {
                    var fs, last = lastEm;
                    child = angular.element(child);
                    if ('span' === child[0].tagName.toLowerCase()) {
                        fs = child.css('font-size');
                        if ('' !== fs) {
                            fs = parseFloat(obj.convertToEm(fs));
                            child.css('font-size', (undefined !== lastEm ? (fs / lastEm) : fs) + 'em');
                            last = fs;
                        }
                    }
                    calcEm(child, last);
                });
            };
            calcEm(node);
        }
    };
    return obj;
}]);

constructorApp.service('messages', ['$window', function($window) {
    var iframe = ($window !== $window.top),
        _callbacks = {
            getSlideshowJSON: function() {},      // mssc-json
            getSlideshowJSON_fail: function() {}, // mssc-json-fail
            dataSaved: function() {},             // mssc-data-saved
            dataSaved_fail: function() {},        // mssc-data-saved-fail
            getImg: function() {},                // mssc-data-img
            getImg_fail: function() {},           // mssc-data-img-fail
            getVideo: function() {},              // mssc-data-video
            getVideo_fail: function() {}          // mssc-data-video-fail
        },
        post = function(_type, _data) {
            if (iframe) {
                parent.window.postMessage({
                    type: _type,
                    data: _data
                }, '*');
            }
        },

        msg = function(e) {
            var d = e.data || e.originalEvent.data;

            if ('mssConstructorMessage' in d) {
                switch(d.mssConstructorMessage) {
                    case 'mssc-json':
                        _callbacks.getSlideshowJSON(d.data);
                        break;
                    case 'mssc-json-fail':
                        _callbacks.getSlideshowJSON_fail(d.data);
                        break;
                    case 'mssc-data-saved':
                        _callbacks.dataSaved(d.data);
                        break;
                    case 'mssc-data-saved-fail':
                        _callbacks.dataSaved_fail(d.data);
                        break;
                    case 'mssc-data-img':
                        _callbacks.getImg(d.data);
                        break;
                    case 'mssc-data-img-fail':
                        _callbacks.getImg_fail(d.data);
                        break;
                    case 'mssc-data-video':
                        _callbacks.getVideo(d.data);
                        break;
                    case 'mssc-data-video-fail':
                        _callbacks.getVideo_fail(d.data);
                        break;
                }
            }
        };

    if (iframe) {
        angular.element($window).on('message', msg);
    }

    return {
        status: iframe,
        off: function() {
            angular.element($window).off('message', msg);
        },
        setCallbacks: function(callbacks) {
            angular.extend(_callbacks, callbacks || {});
        },
        save: function(data) {
            post('mssc-save', data);
        },
        getJSON: function(data) {
            post('mssc-get-json', data);
        },
        getImg: function() {
            post('mssc-get-img', {});
        },
        getVideo: function() {
            post('mssc-get-video', {});
        },
        ready: function() {
            post('mssc-ready', {});
        },
        closeConstructor: function(data) {
            post('mssc-close', data);
        }
    };
}]);
'use strict'

constructorApp.filter('blockTypes', [function() {
    return function(options, bg, type) {
        var opt = [],
            checkType = function(type_, types) {
                for (var i = 0; i < types.length; i++) {
                    if (type_ === types[i]) {
                        return true;
                    }
                }
                return false;
            },
            checkTypes = function(types) {
                var result = false;
                angular.forEach(types, function(v) {
                    if (checkType(type, types)) {
                        if ('image' === type) {
                            if (checkType('fullscreen', types)) {
                                if (bg) {
                                    result = true;
                                }
                            } else {
                                if (!bg) {
                                    result = true;
                                }
                            }
                        } else {
                            result = true;
                        }
                    }
                });
                return result;
            };

        if (options) {
            angular.forEach(options, function(v) {
                if (checkTypes(v.forTypes)) {
                    opt.push(v);
                }
            });
            return opt;
        }
    };
}]);

constructorApp.filter('timing', [function() {
    return function(blocks) {
        var bs = [];

        if (blocks && blocks.length > 0) {
            angular.forEach(blocks, function(block) {
                if ('fixed' !== block.options[3].value || 'fixed' !== block.options[9].value) {
                    bs.push(block);
                }
            });
            return bs;
        }
    };
}]);

constructorApp.filter('globalOptions', [function() {
    return function(options, isIframe) {
        var opt = [];
        if (options) {
            angular.forEach(options, function(v) {
                if ('width' !== v.name && 'height' !== v.name && "effect" !== v.name && "effect-speed" !== v.name && "effect-easing" !== v.name && "slide-duration" !== v.name) {
                    opt.push(v);
                }
            });
            return opt;
        }
    };
}]);

constructorApp.filter('globalOptionsByGroup', [function() {
    return function(options, group) {
        var opts = [];

        angular.forEach(options, function(option) {
            if (group === option.group) {
                opts.push(option);
            }
        });
        return opts;
    }
}]);

constructorApp.filter('globalOptionsByOrder', [function() {
    return function(options) {
        var i, n = options.length;
        for (i = 0; i < n; i++){
            var v = parseInt(options[i].order),
                el = options[i],
                j = i - 1;
            while (j >= 0 && parseInt(options[j].order) > v) {
               options[j + 1] = options[j];
               j--;
            }
            options[j + 1] = el;
        }
        return options;
    }
}]);
constructorApp.directive('stringToNumber', [function() {
    return {
        require: 'ngModel',
        link: function(scope, element, attrs, ngModel) {
            ngModel.$parsers.push(function(value) {
                return '' + value;
            });
            ngModel.$formatters.push(function(value) {
                return parseFloat(value, 10);
            });
        }
    };
}]);'use strict';

constructorApp.directive('slideshowOptions', ['$compile', function($compile) {
    var create = function(o) {
        var i, s = '', v,  el, selectOption = '';
        if ('input' === o.type) {
            if ('number' === o.valueType) {
                v = 'type="number" min="0" max="100000" string-to-number';
            } else {
                v = '';
            }

            el = '<input class="form-control"' + v + ' ng-model="slideshowOptions.value" option-input/>';
        } else {
            angular.forEach(o.values, function(v) {
                if (o.value === v) {
                    s = 'selected';
                }
                selectOption += '<option ' + s + ' name=' + v + '>' + v + '</option>';
                s = '';
            });

            el = '<select ng-model="slideshowOptions.value" class="e-select form-control" option-select name='+o.name+'>' + selectOption + '</select>'
        }
        return el;
    };

    return {
        restrict: 'A',
        scope: {
            slideshowOptions: '='
        },
        link: function(scope, element, attrs, ctrl, transclude) {
            scope.type = attrs.type;

            if (attrs.replace) {
                element.replaceWith($compile(create(scope.slideshowOptions))(scope));
            } else {
                element.html(create(scope.slideshowOptions));
                $compile(element.contents())(scope);
            }

            element.bind('$destroy', function() {
                scope.$destroy();
            });
        }
    };
}]);

constructorApp.directive('optionInput', ['$compile', function($compile) {
    return {
        restrict: 'A',
        link: function(scope, element, attrs) {
            var opt = scope.slideshowOptions,
                lastValue = 0;
            element.val(opt.value);

            element.bind('keyup', function(e) {
                var v = element.val(),
                    l = v.length;

                if (lastValue !== l) {
                    scope.$emit('blockOptionsEvent', {
                        type: scope.type,
                        name: opt.name,
                        value: v
                    });
                }
                lastValue = l;
            });
        }
    }
}]);

constructorApp.directive('optionSelect', ['$compile', function($compile) {
    return {
        restrict: 'A',
        link: function(scope, element, attrs) {
            var opt = scope.slideshowOptions;

            element.bind('change', function() {
                var v = element.val();
                scope.$emit('blockOptionsEvent', {
                    type: scope.type,
                    name: opt.name,
                    value: v
                });
            });
        }
    }
}]);
'use strict';

constructorApp.directive('setSlideshowSlides', ['$compile', 'slideshowAPI', '$window', function($compile, slideshowAPI, $window) {
    return {
        restrict: 'A',
        scope: {},
        link: function(scope, element, attrs) {
            var container = element.parent(),
                size = { width: 0, height: 0 },
                getSize = function() {
                    return {
                        width: container.parent()[0].offsetWidth,
                        height: container.parent()[0].offsetHeight
                    };
                },

                resize = function() {
                    size = getSize();
                },

                calcContainerSize = function() {
                    var width = parseInt(scope.$parent.slideshowOptions[2].value),
                        height = parseInt(scope.$parent.slideshowOptions[3].value),
                        value;

                    size = getSize();
                    value = size.width;

                    if (height / width * value > size.height) {
                        value = width / height * size.height;
                    }

                    container.css('max-width', value + 'px');
                };

            scope.$on('setSlideshowSlides_', function(e, data) {
                var opt = "";
                element[0].innerHTML = '';

                if (data.slides.length === 0 || data.blocksLength === 0) { return; }
                calcContainerSize();

                angular.forEach(data.slides, function(slide, i) {
                    element.append(slide);
                });

                angular.forEach(scope.$parent.slideshowOptions, function(o, i) {
                    if (scope.$parent.defaults.slideshowOptions[i].value !== o.value || scope.$parent.defaults.slideshowOptions[i].name === 'base-height') {
                        opt += (o.name + ': ' + o.value + '; ');
                    }
                });
                element.attr('data-options', opt);

                $compile(element.contents())(scope);
                slideshowAPI.start();
            });

            angular.element($window).bind('resize', resize);
            element.bind('$destroy', function() {
                angular.element($window).unbind('resize', resize);
                scope.$destroy();
            });
        }
    };
}]);'use strict';
constructorApp.factory('editSlideF', [function() {
    var scope = null;
    return {
        setScope: function(sc) {
            scope = sc;
        },
        blur: function(index) {
            scope.callEventAuxiliaryPanel(index);
        }
    };
}]);
constructorApp.directive('editSlide', [
    '$compile',
    'loader',
    '$timeout',
    '$window',
    '$rootScope',
    'parseSlide',
    'editSlideF',
    function($compile, loader, $timeout, $window, $rootScope, parseSlide, editSlideF) {

    return {
        restrict: 'A',
        scope: {
            editSlide: '=',
            globalHeight: '=',
            globalWidth: '='
        },

        controller: ['$scope', '$element', '$attrs', function($scope, $element, $attrs) {
            $scope.activeBlock = null;
            editSlideF.setScope($scope);
        }],

        link: function(scope, element, attrs) {
            var cs = scope.editSlide,
                watchers = [],

                newBlock = function(block, callback, load) {
                    var src;

                    switch (block.type) {
                        case 'text':
                            block.node = angular.element('<div ng-style="" data-mss-animation-block></div>')[0];
                            block.node.innerHTML = block.content;
                            if (!load) {
                                block.styles = angular.copy($rootScope.defCss, {});
                                block.styles['line-height'] = '1em';
                            }

                            block.saveProportions = false;

                            break;
                        case 'button':
                            block.node = angular.element('<a ng-style="" href="" data-mss-animation-block class="mss-slide-button"></a>')[0];
                            block.node.innerHTML = block.content;
                            if (!load) {
                                block.styles = angular.copy($rootScope.defCss, {});
                                block.styles['line-height'] = '1em';
                                block.styles['padding'] = block.correctStyles['padding'] + 'px';
                                block.styles['background-color'] = block.correctStyles['bg-color'];
                                block.styles['display'] = 'inline-block';
                            }

                            block.saveProportions = false;
                            break;
                        case 'shape':
                            block.node = angular.element('<div ng-style="" data-mss-animation-block ></div>')[0];
                            block.content = '';
                            if (!load) {
                                block.styles['top'] = '10%';
                                block.styles['left'] = '10%'
                                block.styles['width'] = '20%';
                                block.styles['height'] = '20%';
                                block.styles['background-color'] = block.correctStyles['bg-color'];
                                block.styles['display'] = 'inline-block';
                            }
                            break;
                        case 'image':
                            block.node = angular.element('<img ng-style="" ng-src="" data-mss-animation-block>')[0];

                            // tmp
                            if (block.url.length == 0) {
                                block.url = $rootScope.defaultContent.img;
                            }

                            !block.imgName && (block.imgName =  parseSlide.getImgName(block.url));

                            if (!load) {
                                block.styles = angular.copy($rootScope.defCss, {});
                                block.styles['width'] = '20%';
                            }
                            break;
                        case 'video':
                            // 'video-autoplay'
                            // 'video-fullsize'
                            if (!load) {
                                block.styles = angular.copy($rootScope.defCss, {});
                            }

                            if ('video' === block.video.videoType) {
                                if (block.url.length < 1) { // temp
                                    block.url = '../video/mov_bbb.mp4';
                                }
                                block.node = angular.element('<video src="' + block.url + '"  ng-style="" data-mss-animation-block controls></video>')[0];
                            } else if ('youtube' === block.video.videoType) {
                                src = "https://www.youtube" + (block.isnocookie ? "-nocookie" : "") + ".com/embed/";
                                if (block.url.length < 1) { // temp
                                    block.url = $rootScope.defaultContent.youtube;
                                }
                                block.node = angular.element('<iframe src="' + (src + block.url) + '"  ng-style="" data-mss-animation-block frameborder="0" allowfullscreen></iframe>')[0];
                            } else {
                                if (block.url.length < 1) { // temp
                                    block.url = $rootScope.defaultContent.vimeo;
                                }
                                src = "//player.vimeo.com/video/";
                                block.node = angular.element('<iframe src="' + (src + block.url) + '"  ng-style="" data-mss-animation-block frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>')[0];
                            }
                            break;
                    }
                    if (!load) {
                        block.styles['z-index'] = block.index + 1;
                    }

                    callback && callback(block);
                },

                el = function(block) {
                    var w = angular.element('<div>'),
                        o = angular.element('<div>');

                    w.addClass('block-wrapper')
                        .attr('block-wrapper', block.index);

                    if (block.isBackground) {
                        w.addClass('mss-centering-img');
                    }

                    o.addClass('outline-block')
                        .attr('outline-block', block.index);

                    block.wrapper = w[0];
                    block.outline = o[0];

                    block.wrapper.appendChild(block.node);
                    block.wrapper.appendChild(block.outline);

                    if (block.fakeImg) {
                        block.wrapper.appendChild(block.fakeImg[0]);
                    }

                    return block.wrapper;
                },

                refresh = function() {
                    if (cs.node) {
                        cs.node.innerHTML = '';
                        var pn = scope.editSlide.panel.node;
                        if (pn) {
                            if(cs.panel.scope) {
                                cs.panel.scopeDestroy.apply(cs.panel.scope);
                            }
                            pn.remove();
                        }

                        angular.element(scope.editSlide.node).attr('ng-style', '{"background-color": editSlide.styles["background-color"]}');

                        pn = angular.element('<div ng-show="editSlide.panel.show" ng-style="" class="auxiliary-panel" auxiliary-panel="editSlide"></div>');

                        pn.attr('ng-style', 'editSlide.panel.styles');
                        angular.element(cs.node).append(pn[0]);
                        scope.editSlide.panel.node = pn[0];

                        angular.forEach(cs.blocks, function(b, i) {
                            if (!b.node) {
                                newBlock(b, null, true);
                                angular.element(cs.node).append(el(b));
                                angular.element(b.wrapper).attr('slide-index', scope.editSlide.index);
                                // $compile(angular.element(b.wrapper))(scope);
                            } else {
                                angular.element(cs.node).append(el(b));
                            }
                            angular.element(b.wrapper).attr('block-node', 'editSlide.blocks['+i+']');
                            angular.element(b.wrapper).attr('ng-style', '{"z-index": editSlide.blocks['+i+'].styles["z-index"]}');

                            angular.element(b.wrapper).attr('slide-index', scope.editSlide.index);
                        });
                        element.append(cs.node);

                        $compile(element.contents())(scope);

                        // $rootScope.slideSize = {
                        //     width: cs.node.offsetWidth,
                        //     height: cs.node.offsetHeight
                        // };
                    }
                },

                pushBlock = function (b, isStore) {
                    var rewriteIndex = false, arr = [];
                    if (!isStore) {
                        scope.editSlide.blocks.push(b);
                    } else {
                        if (scope.editSlide.blocks.length > 0) {
                            angular.forEach(scope.editSlide.blocks, function(bl, i) {
                                if (b.index === i) {
                                    arr.push(b);
                                    rewriteIndex = true;
                                }
                                arr.push(bl);
                                if (rewriteIndex) {
                                    arr[arr.length - 1].index = arr.length - 1;
                                    angular.element(bl.wrapper).remove();
                                }
                            });

                            if (scope.editSlide.blocks.length === b.index) {
                                arr.push(b);
                            }
                        } else {
                            arr.push(b);
                        }

                        scope.editSlide.blocks = arr;
                    }
                },

                addBlock = function(b, timer, data) {
                    var handler,
                        cb = cs.blocks[cs.activeBlock];
                    b.load = true;

                    pushBlock(b, data.inStore);

                    angular.element(cs.node).append(el(b));
                    if (data.inStore) {
                        for (var i = b.index + 1; i < scope.editSlide.blocks.length; i++) {
                            angular.element(cs.node).append(scope.editSlide.blocks[i].wrapper);
                        }
                    }

                    if (data.noSaveAction) {
                        scope.editSlide.activeBlock = data.newBlock.index;
                    } else if (data.inStore) {
                        scope.editSlide.activeBlock = null;
                    } else {
                        scope.editSlide.activeBlock = scope.editSlide.blocks.length - 1;
                    }
                    angular.element(b.wrapper).attr('block-node', 'editSlide.blocks['+scope.editSlide.activeBlock+']');
                    angular.element(b.wrapper).attr('ng-style', '{"z-index": editSlide.blocks['+scope.editSlide.activeBlock+'].styles["z-index"]}');

                    angular.element(b.wrapper).attr('slide-index', scope.editSlide.index);
                    $compile(angular.element(b.wrapper))(scope);

                    $timeout.cancel(timer);
                    $rootScope.loader = false;

                    // scope.$emit('closeColorPickerEvent');
                    if (!data.inStore) {
                        scope.$emit('toggleBlockEvent', {
                            newBlock: !data.noSaveAction,
                            options: b.options,
                            blockType: b.type,
                            title: b.title,
                            imgName: b.imgName,
                            base64: b.base64,
                            url: b.url,
                            index: scope.editSlide.activeBlock
                        });
                    }
                };

            refresh();

            scope.$on('editorEvent', function(e, data) {
                var create;
                if ('newBlock' === data.type && scope.editSlide.index === data.index) {
                    create = function(nb, callback) {
                        var timer = $timeout(function() {
                            $rootScope.loader = true;
                        }, 300);
                        if ('image' === data.newBlock.type) {
                            loader.load(nb.url, {
                                onload: function (e) {
                                    nb.size = e.size;
                                    nb.styles.height = 'auto';

                                    nb.baseWidth = e.size.width;
                                    nb.baseHeight = e.size.height;

                                    addBlock(nb, timer, data);
                                    callback && callback();
                                    data.cb && data.cb();
                                    if (data.newBlock.isBackground) {
                                        scope.$parent.setAsBackground(true);
                                    }
                                }
                            });
                        } else {
                            addBlock(nb, timer, data);

                            if ('text' === nb.type) {
                                $timeout(function() {
                                    nb.size = {
                                        width: nb.node.offsetWidth,
                                        height: nb.node.offsetHeight
                                    };
                                    callback && callback();
                                    data.cb && data.cb();
                                }, 10);
                            } else {
                                callback && callback();
                                data.cb && data.cb();
                            }
                        }
                    };

                    if (undefined !== data.inStore) {
                        create(data.newBlock, function() {
                            // refresh();
                        });
                    } else {
                        newBlock(data.newBlock, create);
                        // if (data.newBlock.isBackground) {
                        //     scope.$parent.setAsBackground();
                        // }
                    }
                }
                // else if ('load' === data.type) {
                //     newBlock(data.block);
                //     angular.element(cs.node).append(el(data.block));

                //     // angular.element(data.block.wrapper).attr('block-node', 'editSlide.blocks['+scope.editSlide.activeBlock+']');
                //     // angular.element(data.block.wrapper).attr('ng-style', '{"z-index": editSlide.blocks['+scope.editSlide.activeBlock+'].styles["z-index"]}');

                //     angular.element(data.block.wrapper).attr('slide-index', scope.editSlide.index);
                //     $compile(angular.element(data.block.wrapper))(scope);
                // }
            });
            scope.$on('activeBlockEvent', function(e, data) {
                var edsc;
                var handler;
                var ocb = cs.blocks[scope.editSlide.activeBlock];

                scope.editSlide.activeBlock = data.index;
                data.cb && data.cb();
            });

            scope.callEventAuxiliaryPanel = function(index) {
                // if (scope.editSlide.activeBlock === index) {
                //     scope.$broadcast('auxiliaryPanelShowEvent');
                // }
            };

            scope.$on('editSlideEvent', function(e, data) {
                if ('remove' === data.type) {
                    var arr = [],
                        cs = scope.editSlide,
                        ci = undefined !== data.blockIndex ? data.blockIndex : cs.activeBlock,
                        cb = cs.blocks[ci];
                    if (undefined !== ci) {
                        cs.blocks[ci].wrapper.parentNode.removeChild(cs.blocks[ci].wrapper);
                        // $timeout(function() {
                            angular.forEach(cs.blocks, function(b, i) {
                                angular.element(b.wrapper).remove();
                                angular.element(b.node).removeClass('ng-scope');
                            });
                            // scope.$apply(function() {

                                cs.blocks.splice(ci, 1);

                                if (0 === cs.blocks.length) {
                                    cs.panel.show = false;
                                }

                                angular.forEach(cs.blocks, function(b, i) {
                                    angular.element(b.node).removeAttr('ng-src')
                                                            .removeAttr('ng-style');
                                    b.index = i;
                                });

                                if (null === data.lastActiveBlock || undefined === data.lastActiveBlock) {
                                    scope.editSlide.activeBlock = null;
                                    scope.editSlide.panel.show = false;
                                } else {
                                    scope.editSlide.activeBlock = data.lastActiveBlock;
                                }

                                refresh();

                                // only remove block
                                if (!data.noSaveAction) {
                                    scope.$emit('editorRmoveBlockEvent', {
                                        noSaveAction: data.prevBlock,
                                        index: ci,
                                        node: cb
                                    });
                                } else {
                                    data.cb && data.cb();
                                }
                            // });
                        // });
                    }
                }
            });

            watchers.push(scope.$watch('globalWidth', function(nv) {
                angular.forEach(scope.editSlide.blocks, function(_block) {
                    if ('text' === _block.type) {
                        angular.element(_block.node).css('max-width', nv + 'px');
                    }
                });
            }));

            watchers.push(scope.$watch('globalHeight', function(nv) {
                angular.forEach(scope.editSlide.blocks, function(_block) {
                    if ('text' === _block.type) {
                        angular.element(_block.node).css('max-height', nv + 'px');
                    }
                });
            }));

            element.bind('$destroy', function() {
                angular.forEach(watchers, function(watcher) {
                    watcher();
                });
                watchers = [];
                scope.$destroy();
            });
        }
    };
}]);

constructorApp.directive('blockNode', [
    '$compile',
    'editSlideF',
    'activeTab',
    function($compile, editSlideF, activeTab) {
    return {
        priority: 0,
        restrict: 'A',
        scope: {
            blockNode: '=',
            slideIndex: '='
        },
        link: function(scope, element, attrs) {
            var watch = scope.$watch('blockNode', function(nv) {
                    if (undefined !== nv) {
                        var block = nv;

                        angular.element(block.node).attr('index', block.index);
                        angular.element(block.node).attr('ng-style', 'blockNode.styles');
                        if (block.fakeImg) {
                            block.fakeImg.attr('ng-style', 'blockNode.fakeImgStyles');
                        }

                        // angular.element(block.wrapper).attr('ng-style', '{"z-index": blockNode.styles["z-index"]}');

                        if ('text' === block.type || 'button' === block.type) {
                            angular.element(block.node).attr('block-text', '');
                            angular.element(block.node).css({
                                'max-width': scope.$parent.globalWidth + 'px',
                                'max-height': scope.$parent.globalHeight + 'px'
                            });

                            if (block.link && 'text' === block.type) {
                                angular.element(block.node).attr('href', block.href);
                            }
                        } else if ('image' === block.type) {
                            angular.element(block.node).attr('ng-src', '{{blockNode.url}}');
                        }
                        element.bind('$destroy', function() {
                            scope.$destroy();
                        });

                        $compile(element.contents())(scope);
                    }
                });

            element.bind('$destroy', function() {
                watch();
                element.removeAttr('block-node');
                scope.$destroy();
            });
        }
    };
}]);

constructorApp.directive('blockText', ['$rootScope', '$timeout', function($rootScope, $timeout) {
    return {
        restrict: 'A',
        link: function(scope, element, attrs) {
            var watch = scope.$watch('blockNode.content', function(n, o) {
                    // if (parseInt(attrs.index) === scope.$parent.editSlide.activeBlock) {
                        element[0].innerHTML = n;
                        if (n && scope.$parent.editSlide && n !== o && !$rootScope.dontsave) {
                            scope.$emit('blockTextOldValueEvent', { value: o });
                            scope.$emit('blockTextReCalcEvent', { value: n });
                        }
                        $rootScope.dontsave = false;

                        // angular.element(scope.blockNode.outline).css({
                        //     'width': scope.blockNode.node.offsetWidth + 'px',
                        //     'height': scope.blockNode.node.offsetHeight + 'px'
                        // });
                    // }
                });

            // angular.element(scope.blockNode.node).bind('keydown', function() {
            //     $timeout(function() {
            //         angular.element(scope.blockNode.outline).css({
            //             'width': scope.blockNode.node.offsetWidth + 'px',
            //             'height': scope.blockNode.node.offsetHeight + 'px'
            //         });
            //     }, 0);
            // });

            element.bind('$destroy', function() {
                // angular.element(scope.blockNode.node).unbind('keydown');
                element.removeAttr('block-text');
                watch();
            });
        }
    };
}]);

constructorApp.directive('blockWrapper', [
    'editSlideF',
    '$rootScope',
    'acpManager',
    function(editSlideF, $rootScope, acpManager) {
    return {
        restrict: 'A',
        link: function(scope, element, attrs) {
            element.bind('click', function(e) {
                var newIndex, cb = scope.editSlide.blocks[scope.editSlide.activeBlock];
                e.preventDefault();
                // scope.$emit('closeColorPickerEvent');
                acpManager.close();

                newIndex = parseInt(element.children().attr('index'));

                scope.$apply(function() {
                    scope.editSlide.activeBlock = newIndex;
                });

                scope.$emit('toggleBlockEvent', {
                    index: scope.editSlide.activeBlock,
                    click: true
                });
            });

            element.bind('$destroy', function() {
                element.unbind('click');
            });
        }
    };
}]);

constructorApp.directive('outlineBlock', ['$timeout', '$rootScope', function($timeout, $rootScope) {
    return {
        restrict: 'A',
        link: function(scope, element, attrs) {
            var watchers = [];

            // watchers.push(scope.$watchGroup(['blockNode.styles.top', 'blockNode.styles.left', 'blockNode.styles.width', 'blockNode.styles.height'], function(nv) {
            watchers.push(scope.$watchGroup(['blockNode.styles.top', 'blockNode.styles.left', 'blockNode.styles.width', 'blockNode.styles.height', 'blockNode.styles.padding', 'blockNode.styles[\'border-width\']', 'blockNode.styles[\'border-style\']', 'blockNode.content'], function(nv) {
                $timeout(function() {
                    var tmp,
                        t = nv[0],
                        l = nv[1],
                        w = nv[2],
                        h = nv[3];

                    // if ('auto' === w || '' === w) {
                    if (w) {
                        w = scope.blockNode.node.offsetWidth + 'px';
                    }

                    // if ('auto' === h || '' === h) {
                    if (h) {
                        h = scope.blockNode.node.offsetHeight + 'px';
                    }

                    if (scope.blockNode && scope.blockNode.isBackground) {
                        if (/%/.test(h)) {
                            tmp = scope.blockNode.node.offsetHeight;
                            if (tmp) { h = tmp; }
                        }
                        t = ($rootScope.slideSize.height - parseInt(h)) / 2 + 'px';

                        if (/%/.test(w)) {
                            tmp = scope.blockNode.node.offsetWidth;
                            if (tmp) { w = tmp; }
                        }
                        l = ($rootScope.slideSize.width - parseInt(w)) / 2 + 'px';
                    }

                    if (!(/px$/.test(t)) && !(/%$/.test(t))) {
                        t = '0px';
                    }
                    if (!(/px$/.test(l)) && !(/%$/.test(l))) {
                        l = '0px';
                    }

                    element.css({
                        'top': t,
                        'left': l,
                        'width': w,
                        'height': h
                    });
                }, 0);
            }));


            // watchers.push(scope.$watch('blockNode.styles[\'z-index\']', function(nv, ov) {
            //     if (undefined !== nv) {
            //         element.css('z-index', nv);
            //     }
            // }));

            element.bind('$destroy', function() {
                angular.forEach(watchers, function(watcher) {
                    watcher();
                });
                watchers = [];
            });
        }
    };
}]);
'use strict';

constructorApp.directive('slideMove', ['$window', 'lib', 'globalMenuAPI', function($window, lib, globalMenuAPI) {
    var getMargin = function(node) {
            return {
                top: parseInt(lib.getCss(node, 'margin-top')) || 0,
                left: parseInt(lib.getCss(node, 'margin-left')) || 0,
                right: parseInt(lib.getCss(node, 'margin-right')) || 0,
                bottom: parseInt(lib.getCss(node, 'margin-bottom')) || 0
            };
        },
        getSize = function(node) {
            return {
                'width': node.offsetWidth,
                'height': node.offsetHeight
            };
        };
    return {
        restrict: 'A',
        link: function(scope, element, attrs) {
            var twin,
                twin2,
                els,
                removeFlag = false,
                removeButton = element.find('button'),
                currentIndex,
                currentArea,
                size = {},
                scroll = {},
                startPoint = {},
                parentPosition,
                lastTop, lastLeft,
                distanceHeight, distanceWidth,
                margin, currentTop, currentLeft,
                containerSize = {},
                container = element.parent()[0],

                getPosition = function(el) {
                    var p = lib.getPosition(el);
                    return {
                        top: p.top - parentPosition.top - scroll.top - margin.top,
                        left: p.left - parentPosition.left - scroll.left - margin.left
                    };
                },

                getAllElement = function() {
                    var i, arr = [],
                        nodes = container.childNodes;
                    for (var i = 0; i < nodes.length; i++) {
                        if (nodes[i].nodeType !== 3 && nodes[i].nodeType !== 8) {
                            arr.push({ node: nodes[i] });
                        }
                    }
                    return arr;
                },

                getAllPositions = function() {
                    var arr = getAllElement();

                    angular.forEach(arr, function(el, i) {
                        var p  = lib.getPosition(el.node);
                        if (element[0] === el.node) {
                            currentIndex = i;
                        }
                        el.pos = getPosition(el.node);
                    });

                    return arr;
                },

                prepare = function() {
                    els = getAllPositions();

                    twin = $window.document.createElement('div');
                    twin2 = $window.document.createElement('div');

                    angular.element(twin2).css({
                        'top': '0px',
                        'left': '0px',
                        'position': 'absolute',
                        'display': 'inline-block'
                    });

                    angular.element(twin).addClass('slide-min').css({
                        'width': size.width + 'px',
                        'height': size.height + 'px',
                        // 'display': 'inline-block',
                        // 'position': 'relative',
                        'border': 'none',
                        // 'margin': 'auto',
                        'margin-top': margin.top + 'px',
                        'margin-left': margin.left + 'px',
                        'margin-right': margin.right + 'px',
                        'margin-bottom': margin.bottom + 'px',
                        'vertical-aline':' top'
                    });
                    lastTop = els[currentIndex].pos.top;
                    currentTop = lastTop;
                    lastLeft = els[currentIndex].pos.left;
                    currentLeft = lastLeft;

                    element.css({
                        'top': lastTop + 'px',
                        'left': lastLeft + 'px',
                        'width': size.width + 'px',
                        'height': size.height + 'px',
                        'position': 'absolute',
                        'z-index': 10000000
                    });

                    element[0].parentNode.insertBefore(twin, element[0]);
                },

                area = function(curPos, otherPos) {
                    var result = false,
                        width = 0,
                        height = 0,
                        w = size.width - margin.left - margin.right,
                        h = size.height - margin.top - margin.bottom;

                    if (Math.abs(curPos.top - otherPos.top) < h) {
                        if (curPos.top > otherPos.top) {
                            height = otherPos.top + h - curPos.top;
                        } else {
                            height = curPos.top + h - otherPos.top;
                        }
                    }

                    if (Math.abs(curPos.left - otherPos.left) < w) {
                        if (curPos.left > otherPos.left) {
                            width = otherPos.left + w - curPos.left;
                        } else {
                            width = curPos.left + w - otherPos.left;
                        }
                    }

                    if (currentArea / 2 < width * height) {
                        result = true;
                    }
                    return result;
                },

                mousemove = function(e) {
                    e.preventDefault();

                    lastTop = lib.mouse.pageY(e) - startPoint.top - lib.obj.positY(container) - scroll.top - margin.top;
                    // lastLeft = lib.mouse.pageX(e) - startPoint.left - lib.obj.positX(container) - scroll.left - margin.left;

                    if (lastTop < 0 - margin.top) { lastTop = 0 - margin.top; }
                    // if (lastLeft < 0 - margin.left) { lastLeft = 0 - margin.left; }

                    if (lastTop + size.height > containerSize.height - margin.top) {
                        lastTop = containerSize.height - size.height - margin.top;
                    }


                    // off
                    // if (lastLeft + size.width > containerSize.width - margin.left) {
                    //     lastLeft = containerSize.width - size.width - margin.left;
                    // }

                    angular.forEach(els, function(el, i) {
                        if (i !== currentIndex) {
                            if (area({top: lastTop, left: lastLeft}, el.pos)) {
                                container.insertBefore(twin2, el.node);
                                container.insertBefore(el.node, twin);
                                container.insertBefore(twin, twin2);
                                container.removeChild(twin2);

                                el.pos = getPosition(el.node);
                            }
                        }
                    });


                    element.css({
                        'top': lastTop + 'px'
                        // 'left': lastLeft + 'px' // off
                    });
                },

                mouseup = function(e) {
                    if (1 === e.which) {
                        e.preventDefault();
                        angular.element($window.document).unbind('mousemove', mousemove);

                        element.css('cursore', '');
                        element.css({
                            'top': '',
                            'left': '',
                            'width': '',
                            'height': '',
                            'z-index': '',
                            'position': ''
                        });
                        container.insertBefore(element[0], twin);
                        angular.element(twin).remove();

                        var change = true, tmp = getAllElement(container);
                        angular.forEach(tmp, function(el, i) {
                            if (el.node === element[0] && i === currentIndex) {
                                change = false;
                            }
                        });

                        scope.$emit('slideMoveEvent', {
                            elements: tmp,
                            cIndex: change ? null : currentIndex
                        });

                        angular.element($window.document).unbind('mouseup');
                    }
                },

                removeMouseUp = function(e) {
                    var target;
                    if (1 === e.which) {
                        e.preventDefault();
                        removeFlag = false;
                        target = e.target;

                        while(target.tagName.toLowerCase() !== 'button') {
                            target = target.parentNode;
                        }

                        scope.$emit('removeSlideEvent', {
                            index: angular.element(target).attr('index')
                        });
                    }

                    removeButton.off('mouseup', removeMouseUp);
                };

            removeButton.on('mousedown', function(e) {
                if (1 === e.which) {
                    e.preventDefault();
                    removeFlag = true;
                    removeButton.on('mouseup', removeMouseUp);
                }
            });

            element.bind('mousedown', function(e) {
                if (1 === e.which && !removeFlag) {
                    e.preventDefault();
                    globalMenuAPI.close();

                    element.css('cursore', 'move');
                    size = getSize(element[0]);
                    containerSize = getSize(container);
                    margin = getMargin(element[0]);

                    currentArea = (size.width - margin.left - margin.right) * (size.height - margin.top - margin.bottom);

                    distanceHeight = (size.height / 2 + size.height / 8);
                    distanceWidth = (size.width / 2 + size.width / 8);

                    startPoint.top = lib.mouse.pageY(e) - lib.obj.positY(element[0]);
                    startPoint.left = lib.mouse.pageX(e) - lib.obj.positX(element[0]);

                    scroll.top = container.parentNode.scrollTop;
                    scroll.left = container.parentNode.scrollLeft;

                    parentPosition = lib.getPosition(container);

                    prepare();
                    angular.element($window.document).bind('mouseup', mouseup);
                    angular.element($window.document).bind('mousemove', mousemove);
                }
            });

            element.bind('$destroy', function() {
                removeButton.off('mousedown');
                element.unbind('mousedown');
            });
        }
    };
}]);
'use strict';

constructorApp.directive('section', [function() {
    return {
        restrict: 'A',
        scope: true,
        link: function(scope, element, attrs) {
            scope.open = false;
            var children = element.find('div');

            angular.element(children[1]).css('display', 'none');

            angular.element(children[0]).bind('mousedown', function(e) {
                if (1 === e.which) {
                    angular.element(children[0]).addClass('inversion');
                }
            });
            angular.element(children[0]).bind('mouseup', function(e) {
                if (1 === e.which) {
                    // angular.element(children[0]).removeClass('inversion');
                    if (scope.open) {
                        angular.element(children[0]).removeClass('inversion');
                        element.removeClass('open');
                        scope.open = false;
                        angular.element(children[1]).css('display', 'none');
                    } else {
                        element.addClass('open');
                        scope.open = true;
                        angular.element(children[1]).css('display', '');
                    }
                }
            });

            element.bind('$destroy', function() {
                var ch = angular.element(children[0]);
                ch.unbind('mousedown');
                ch.unbind('mouseup');
                scope.$destroy();
            });
        }
    };
}]);constructorApp.directive('colorPickerBlock', ['$compile', function($compile) {
    return {
        restrict: 'A',
        scope: true,
        require: '?ngModel',
        controller: ['$scope', '$element', '$attrs', function($scope, $element, $attrs) {
            var reg = new RegExp("\\s*r\\s*g\\s*b\\s*a\\s*\\(\\s*[0-9]\\s*[0-9]?\\s*[0-9]?\\s*,\\s*[0-9]\\s*[0-9]?\\s*[0-9]?\\s*,\\s*[0-9]\\s*[0-9]?\\s*[0-9]?\\s*,\\s*([0-1]|0\\s*\.\\s*[0-9]+)\\s*\\)\\s*");

            $scope.colors = { input: 'none', color: 'none' };

            $scope.getInputValue = function(value) {
                if (value) {
                    value = value.replace(/\s+/g, ' ');

                    if ('transparent' === value || 'none' === value || !reg.test(value)) {
                        // value = 'rgba(0,0,0,0)';
                        value = 'none';
                    } else {
                        var tmp = value.split('(')[1];
                        tmp = tmp.split(')')[0];
                        tmp = tmp.split(',');

                        for (var i = 0; i < 3; i++) {
                            if (parseInt(tmp[i]) > 255) {
                                tmp[i] = 255;
                            }
                        }
                        value = 'rgba(' + tmp.join(',') + ')';
                    }
                } else {
                    // value = 'rgba(0,0,0,0)';
                    value = 'none';
                }

                return value;
            };
        }],
        link: function(scope, element, attrs, ngModel) {
            var watchers = [],
                i = angular.element('<input class="form-control" ng-model="colors.input" input-mask>'),
                c = angular.element('<div text="transparent" ng-model="colors.color" ng-style="{\'background-color\': colors.color}" angular-color-picker="rgba" ></div>');

            if (!isNaN(ngModel.$viewValue)) {
                scope.colors = {
                    input: ngModel.$viewValue,
                    color: ngModel.$viewValue
                };
            }

            ngModel.$formatters.push(scope.getInputValue);

            watchers.push(scope.$watch(function () {
                return ngModel.$modelValue;
            }, function(newValue, oldValue) {
                if (newValue) {
                    scope.colors = {
                        input: ngModel.$viewValue,
                        color: ngModel.$viewValue
                    };
                }
            }));

            watchers.push(scope.$watch('colors.input', function(newValue, oldValue) {
                if (newValue !== oldValue) {
                    // scope.colors.color = scope.getInputValue(newValue);
                    scope.colors.color = newValue;
                    ngModel.$setViewValue(newValue);
                }
            }));

            watchers.push(scope.$watch('colors.color', function(newValue, oldValue) {
                if (newValue !== oldValue) {
                    scope.colors.input = newValue;
                    ngModel.$setViewValue(newValue);
                }
            }));

            element.append(c[0]);
            element.append(i[0]);
            $compile(element.contents())(scope);

            element.bind('$destroy', function() {
                angular.forEach(watchers, function(watcher) { watcher(); });
                scope.$destroy();
            });
        }
    };
}]);
'use strict';

constructorApp.directive('auxiliaryPanel', [
    '$compile',
    'lib',
    '$timeout',
    '$window',
    '$rootScope',
    'activeTab',
    'globalMenuAPI',
    'acpManager',
    function($compile, lib, $timeout, $window, $rootScope, activeTab, globalMenuAPI, acpManager) {
    var round = function(num, count) {
            var degree = Math.pow(10, count || 4);
            return Math.round(num * degree) / degree;
        },
        create = function(node) {
            return $window.document.createElement(node || 'div');
        },
        addClasses = function(el, arr) {
            if ('string' === typeof arr) {
                var t = [];
                t.push(arr);
                arr = t;
            }
            angular.forEach(arr, function(name) {
                angular.element(el).addClass(name);
            });
        },
        defined = function(v) {
            return undefined !== v;
        };
    return {
        restrict: 'A',
        scope: {
            auxiliaryPanel: '='
        },
        link: function(scope, element, attrs) {
            var cs = scope.auxiliaryPanel, proportion,
                parent = element.parent()[0],
                proportions, x, y, watch,
                elSize = {}, size = {},
                oldWidth, oldHeight,
                oldTop, oldLeft, cb = null, pos,
                elPos, customTop, customLeft,
                moveFlag = false,
                moveTop = false, moveLeft = false,
                dragFlag = false, ratio,
                // minHeight, minWidth,
                borderWidth = 0, borderHeight = 0,
                paddingWidth = 0, paddingHeight = 0,
                moveEv = false,
                topControl = create(),
                leftControl = create(),
                rightControl = create(),
                bottomControl = create(),
                topLeftControl = create(),
                topRightControl = create(),
                bottomLeftControl = create(),
                bottomRightControl = create(),
                // buttonEdit = create('button'),

                minWidth = 30,
                minHeight = 30,

                minWidthCorrect, minHeightCorrect,

                updateValues = function(values, save) {
                    var sign = 'px',
                        set = function() {
                            $timeout(function() {
                                var tmp;
                                if (defined(values.width)) {
                                    if ('string' === typeof values.width) {
                                        var sign2 = '';
                                        if ('video' === cb.type && 'auto' === values.width) {
                                            sign2 = 'px';
                                            values.width = cb.node.offsetWidth;
                                        }
                                        cb.styles.width = values.width + sign2;
                                        scope.auxiliaryPanel.panel.styles.width = cb.node.offsetWidth + sign;
                                    } else {
                                        tmp = round(values.width, 1);
                                        // cb.styles.width = tmp + sign;
                                        cb.styles.width = round(tmp - borderWidth - paddingWidth) + sign;


                                        // scope.auxiliaryPanel.panel.styles.width = tmp + borderWidth + paddingWidth + sign;
                                        scope.auxiliaryPanel.panel.styles.width = tmp + sign;
                                        // scope.auxiliaryPanel.panel.styles.width = cb.styles.width;
                                    }
                                } else {
                                    if (cb && 'text' === cb.type && 'auto' === cb.styles.width) {
                                        // scope.auxiliaryPanel.panel.styles.width = cb.node.offsetWidth + borderWidth + paddingWidth + 'px';
                                        scope.auxiliaryPanel.panel.styles.width = cb.node.offsetWidth + 'px';
                                    }
                                }
                                if (defined(values.height)) {
                                    if ('string' === typeof values.height) {
                                        var sign2 = '';
                                        if ('video' === cb.type && 'auto' === values.height) {
                                            sign2 = 'px';
                                            values.height = cb.node.offsetHeight;
                                        }
                                        cb.styles.height = values.height + sign2;
                                        scope.auxiliaryPanel.panel.styles.height = cb.node.offsetHeight + sign;
                                    } else {
                                        tmp = round(values.height, 1);
                                        // cb.styles.height = tmp + sign;
                                        cb.styles.height = round(tmp - borderHeight - paddingHeight) + sign;



                                        // scope.auxiliaryPanel.panel.styles.height = tmp + borderHeight + paddingHeight + sign;
                                        scope.auxiliaryPanel.panel.styles.height = tmp + sign;
                                        // scope.auxiliaryPanel.panel.styles.height = cb.styles.height;
                                    }
                                } else {
                                    if (cb && 'text' === cb.type && 'auto' === cb.styles.height) {
                                        // scope.auxiliaryPanel.panel.styles.height = cb.node.offsetHeight + borderHeight + paddingHeight + 'px';
                                        scope.auxiliaryPanel.panel.styles.height = cb.node.offsetHeight + 'px';
                                    }
                                }
                                if (defined(values.top)) {
                                    if ('string' === typeof values.top) {
                                        cb.styles.top = values.top;
                                    } else {
                                        cb.styles.top = round(values.top, 1) + sign;
                                    }

                                    if ('string' === typeof values.top) {
                                        scope.auxiliaryPanel.panel.styles.top = values.top;
                                    } else {
                                        scope.auxiliaryPanel.panel.styles.top = round(values.top, 1) + sign;
                                    }
                                }
                                if (defined(values.left)) {
                                    if ('string' === typeof values.left) {
                                        cb.styles.left = values.left;
                                    } else {
                                        cb.styles.left = round(values.left, 1) + sign;
                                    }

                                    if ('string' === typeof values.left) {
                                        scope.auxiliaryPanel.panel.styles.left = values.left;
                                    } else {
                                        scope.auxiliaryPanel.panel.styles.left = round(values.left, 1) + sign;
                                    }
                                }
                                if (cb.fakeImg) {
                                    var s = cb.styles;
                                    cb.fakeImgStyles.top = s.top;
                                    cb.fakeImgStyles.left = s.left;
                                    cb.fakeImgStyles.width = s.width;
                                    cb.fakeImgStyles.height = s.height;
                                }

                                if (save) { scope.$emit('auxiliaryPanelMouseUpEvent', { move: true }); }
                            }, 0);
                        };

                    if (!scope.$parent.$parent.$$phase) {
                        scope.$apply(function() {
                            set();
                        });
                    } else {
                        set();
                    }
                },

                false_ = function() {
                    return false;
                },

                correctSize = function() {
                    if (cb && 'auto' === cb.styles.width) {
                        updateValues({
                            // width : Math.round(element[0].offsetHeight * proportions.forWidth),
                            width : round(element[0].offsetHeight * (elSize.width / elSize.height), 1),
                            height: 'auto'
                        });
                    }
                },

                mouseUp = function(e, remove) {
                    e && e.preventDefault();
                    e && e.stopPropagation();
                    // correctSize();

                    angular.element($window.document.body).removeClass(proportion);

                    moveTop = false;
                    moveLeft = false;
                    moveFlag = false;
                    dragFlag = false;
                    proportion = false;
                    proportions = null;
                    element.css('cursor', '');

                    if (!remove) {
                        scope.$emit('auxiliaryPanelMouseUpEvent', {
                            move: moveEv
                        });
                    }

                    moveEv = false;

                    angular.element($window.document).unbind('mousemove', move);

                    angular.element($window.document).unbind('ondragstart', false_);
                    angular.element($window.document).unbind('onselectstart', false_);

                    angular.element($window.document).unbind('mouseup', mouseUp);
                },

                move = function(e) {
                    var t, l, correctTop, correctLeft, tmp,
                        currentWidth, currentHeight;

                    e.preventDefault();
                    e.stopPropagation();

                    if (!moveEv) {
                        moveEv = true;
                    }

                    t = e.clientY - pos.top - y;
                    l = e.clientX - pos.left - x;

                    t /= $rootScope.zoomIcon;
                    l /= $rootScope.zoomIcon;

                    if (dragFlag) {
                        if ('t' === proportion || 'l' === proportion || 'r' === proportion || 'b' === proportion) {
                            if ('l' === proportion || 'r' === proportion) {
                                if (cs.blocks[cs.activeBlock].saveProportions) {

                                    currentWidth = oldLeft - l;
                                    if ('r' === proportion) {
                                        currentWidth *= (-1);
                                    }
                                    currentWidth += oldWidth;
                                    currentHeight = proportions.forHeight * currentWidth;

                                    if ('r' === proportion) {
                                        moveLeft = false;
                                    }

                                    t = oldTop + ((oldHeight - currentHeight) / 2);


                                    if (currentWidth < minWidthCorrect) {
                                        if ('l' === proportion) {
                                            l -= (minWidthCorrect - currentWidth);
                                        } else {
                                            l += (minWidthCorrect - currentWidth);
                                        }

                                        currentWidth = minWidthCorrect;
                                        currentHeight = proportions.forHeight * currentWidth;

                                        if ('l' === proportion) {
                                            tmp = proportions.forHeight * (l - oldLeft);
                                        } else {
                                            tmp = proportions.forHeight * (oldLeft - l);
                                        }

                                        t = oldTop + tmp / 2;

                                        if (!tmp) { moveFlag = false; }
                                    } if (!moveFlag) {
                                        moveFlag = true;
                                    }
                                } else {
                                    t = null;
                                    moveTop = false;

                                    currentWidth = oldLeft - l;
                                    if ('r' === proportion) {
                                        moveFlag = false;
                                        currentWidth *= (-1);
                                    }
                                    currentWidth += oldWidth;

                                    if (currentWidth <= minWidth) {
                                        tmp = minWidth - currentWidth;
                                        if ('l' === proportion) {
                                            l -= tmp;
                                        } else {
                                            l += tmp;
                                        }
                                        currentWidth = minWidth;
                                    }
                                    currentHeight = elSize.height;
                                }
                            } else {
                                if (cs.blocks[cs.activeBlock].saveProportions) {
                                    currentHeight = oldTop - t;
                                    if ('b' === proportion) {
                                        currentHeight *= (-1);
                                    }
                                    currentHeight += oldHeight;
                                    currentWidth = proportions.forWidth * currentHeight;

                                    if ('b' === proportion) {
                                        moveTop = false;
                                    }
                                    l = oldLeft + ((oldWidth - currentWidth) / 2);

                                    if (currentHeight < minHeightCorrect) {
                                        if ('t' === proportion) {
                                            t -= (minHeightCorrect - currentHeight);
                                        } else {
                                            t += (minHeightCorrect - currentHeight);
                                        }

                                        currentHeight = minHeightCorrect;
                                        currentWidth = proportions.forWidth * currentHeight;

                                        if ('t' === proportion) {
                                            tmp = proportions.forWidth * (t - oldTop);
                                        } else {
                                            tmp = proportions.forWidth * (oldTop - t);
                                        }

                                        l = oldLeft + tmp / 2;

                                        if (!tmp) { moveFlag = false; }
                                    } else if (!moveFlag) {
                                        moveFlag = true;
                                    }
                                } else {
                                    l = null;
                                    moveLeft = false;
                                    currentHeight = oldTop - t;
                                    if ('b' === proportion) {
                                        moveFlag = false;
                                        currentHeight *= (-1);
                                    }
                                    currentHeight += oldHeight;

                                    if (currentHeight <= minHeight) {
                                        tmp = minHeight - currentHeight;
                                        if ('t' === proportion) {
                                            t -= tmp;
                                        } else {
                                            t += tmp;
                                        }
                                        currentHeight = minHeight;
                                    }
                                    currentWidth = elSize.width;
                                }
                            }
                        } else {
                            if ('bl' === proportion) {
                                t = null;

                                currentWidth = oldLeft - l + oldWidth;
                                // currentHeight = (e.clientY - pos.top) - (elPos.top - pos.top - document.body.scrollTop) - borderHeight - paddingHeight;
                                currentHeight = (e.clientY - pos.top) - (elPos.top - pos.top - document.body.scrollTop);
                                currentHeight /= $rootScope.zoomIcon;
                                if (cs.blocks[cs.activeBlock].saveProportions) {
                                    // if (elPos.top - pos.top + (proportions.forHeight * currentWidth) - document.body.scrollTop + borderHeight + paddingHeight < e.clientY - pos.top) {
                                    if (elPos.top - pos.top + (proportions.forHeight * currentWidth) - document.body.scrollTop < e.clientY - pos.top) {
                                        if (currentHeight <= minHeight && !ratio) {
                                            l -= (minWidth - currentWidth);
                                            currentHeight = minHeight;
                                        }

                                        currentWidth = proportions.forWidth * currentHeight;

                                        if (currentWidth <= minWidth && ratio) {
                                            l -= (minWidth - currentWidth);
                                            currentWidth = minWidth;
                                            currentHeight = proportions.forHeight * currentWidth;
                                        }

                                        customLeft = customLeft - (currentWidth - oldWidth);
                                        l = customLeft;
                                    } else {
                                        if (currentWidth <= minWidth && ratio) {
                                            l -= (minWidth - currentWidth);
                                            currentWidth = minWidth;
                                        }

                                        currentHeight = proportions.forHeight * currentWidth;

                                        if (currentHeight <= minHeight && !ratio) {
                                            correctLeft = (minHeight - currentHeight) * proportions.forWidth;
                                            currentHeight = minHeight;
                                            currentWidth = proportions.forWidth * currentHeight;
                                            l -= correctLeft;
                                        }
                                        customLeft = l;
                                    }
                                } else {
                                    if (currentWidth <= minWidth) {
                                        l -= (minWidth - currentWidth);
                                        currentWidth = minWidth;
                                    }
                                    if (currentHeight <= minHeight) {
                                        currentHeight = minHeight;
                                    }
                                }
                            } else if ('br' === proportion) {
                                t = null;
                                l = null;
                                // currentWidth = (e.clientX - pos.left) - (elPos.left - pos.left - document.body.scrollLeft) - borderWidth - paddingWidth;
                                // currentHeight = (e.clientY - pos.top) - (elPos.top - pos.top - document.body.scrollTop) - borderHeight - paddingHeight;
                                currentWidth = (e.clientX - pos.left) - (elPos.left - pos.left - document.body.scrollLeft);
                                currentHeight = (e.clientY - pos.top) - (elPos.top - pos.top - document.body.scrollTop);
                                currentWidth /= $rootScope.zoomIcon;
                                currentHeight /= $rootScope.zoomIcon;

                                if (cs.blocks[cs.activeBlock].saveProportions) {
                                    // if (elPos.top - pos.top + (proportions.forHeight * currentWidth) - document.body.scrollTop + borderHeight + paddingHeight < e.clientY - pos.top) {
                                    if (elPos.top - pos.top + (proportions.forHeight * currentWidth) - document.body.scrollTop < e.clientY - pos.top) {
                                        if (currentHeight <= minHeight && !ratio) {
                                            currentHeight = minHeight;
                                        }

                                        currentWidth = proportions.forWidth * currentHeight;

                                        if (currentWidth <= minWidth && ratio) {
                                            currentWidth = minWidth;
                                            currentHeight = proportions.forHeight * currentWidth;
                                        }
                                    } else {
                                        if (currentWidth <= minWidth && ratio) {
                                            currentWidth = minWidth;
                                        }
                                        currentHeight = proportions.forHeight * currentWidth;
                                        if (currentHeight <= minHeight && !ratio) {
                                            currentHeight = minHeight;
                                            currentWidth = proportions.forWidth * currentHeight;
                                        }
                                    }
                                } else {
                                    if (currentWidth <= minWidth) {
                                        currentWidth = minWidth;
                                    }
                                    if (currentHeight <= minHeight) {
                                        currentHeight = minHeight;
                                    }
                                }
                            } else if ('tr' === proportion) {
                                l = null;
                                currentHeight = oldTop - t + oldHeight;
                                // currentWidth = (e.clientX - pos.left) - (elPos.left - pos.left - document.body.scrollLeft) - borderWidth - paddingWidth;
                                currentWidth = (e.clientX - pos.left) - (elPos.left - pos.left - document.body.scrollLeft);
                                currentWidth /= $rootScope.zoomIcon;
                                if (cs.blocks[cs.activeBlock].saveProportions) {
                                    // if (elPos.left - pos.left + (proportions.forWidth * currentHeight) - document.body.scrollLeft + borderWidth + paddingWidth < e.clientX - pos.left) {
                                    if (elPos.left - pos.left + (proportions.forWidth * currentHeight) - document.body.scrollLeft < e.clientX - pos.left) {
                                        if (currentWidth <= minWidth && ratio) {
                                            t -= (minHeight - currentHeight);
                                            currentWidth = minWidth;
                                        }
                                        currentHeight = proportions.forHeight * currentWidth;

                                        if (currentHeight <= minHeight && !ratio) {
                                            t -= (minHeight - currentHeight);
                                            currentHeight = minHeight;
                                            currentWidth = proportions.forWidth * currentHeight;
                                        }

                                        customTop = customTop - (currentHeight - oldHeight);
                                        t = customTop;
                                    } else {
                                        if (currentHeight <= minHeight && !ratio) {
                                            t -= (minHeight - currentHeight);
                                            currentHeight = minHeight;
                                        }
                                        currentWidth = proportions.forWidth * currentHeight;

                                        if (currentWidth <= minWidth && ratio) {
                                            correctTop = (minWidth - currentWidth) * proportions.forHeight;
                                            currentWidth = minWidth;
                                            currentHeight = proportions.forHeight * currentWidth;
                                            t -= correctTop;
                                        }
                                        customTop = t;
                                    }
                                } else {
                                    if (currentWidth <= minWidth) {
                                        currentWidth = minWidth;
                                    }
                                    if (currentHeight <= minHeight) {
                                        t -= (minHeight - currentHeight);
                                        currentHeight = minHeight;
                                    }
                                }
                            } else {
                                currentHeight = oldTop - t + oldHeight;
                                currentWidth = oldLeft - l + oldWidth;
                                if (cs.blocks[cs.activeBlock].saveProportions) {
                                    if (customLeft - ((proportions.forWidth * currentHeight) - oldWidth) > e.clientX - pos.left) {
                                        if (currentWidth <= minWidth && ratio) {
                                            l -= (minWidth - currentWidth);
                                            currentWidth = minWidth;
                                        }

                                        currentHeight = proportions.forHeight * currentWidth;

                                        if (currentHeight <= minHeight && !ratio) {
                                            correctTop = (minWidth - currentWidth) * proportions.forHeight;
                                            currentHeight = minHeight;
                                            correctLeft = currentWidth;
                                            currentWidth = proportions.forWidth * currentHeight;
                                            t -= correctTop;
                                            l -= (currentWidth - correctLeft);
                                        }

                                        customTop = customTop - (currentHeight - oldHeight);
                                        t = customTop;
                                        customLeft = l;
                                    } else {
                                        if (currentHeight <= minHeight && !ratio) {
                                            t -= (minHeight - currentHeight);
                                            currentHeight = minHeight;
                                        }

                                        currentWidth = proportions.forWidth * currentHeight;

                                        if (currentWidth <= minWidth && ratio) {
                                            correctLeft = (minHeight - currentHeight) * proportions.forWidth;
                                            currentWidth = minWidth;
                                            correctTop = currentHeight;
                                            currentHeight = proportions.forHeight * currentWidth;
                                            l -= correctLeft;
                                            t -= (currentHeight - correctTop);
                                        }

                                        customLeft = customLeft - (currentWidth - oldWidth);
                                        l = customLeft;
                                        customTop = t;
                                    }
                                } else {
                                    if (currentWidth <= minWidth) {
                                        l -= (minWidth - currentWidth);
                                        currentWidth = minWidth;
                                    }
                                    if (currentHeight <= minHeight) {
                                        t -= (minHeight - currentHeight);
                                        currentHeight = minHeight;
                                    }
                                }
                            }
                        }

                        oldTop = t;
                        oldLeft = l;
                        oldWidth = currentWidth;
                        oldHeight = currentHeight;
                    }

                    updateValues({
                        top: (moveFlag && moveTop && t) ? Math.round(t, 1) : undefined,
                        left: (moveFlag && moveLeft && l) ? Math.round(l, 1) : undefined,
                        width: currentWidth,
                        height: currentHeight
                    });
                },

                resize = function(e) {
                    if (cb) {
                        $timeout(function() {
                            scope.auxiliaryPanel.panel.styles.top = cb.styles.top || (0 + 'px');
                            scope.auxiliaryPanel.panel.styles.left = cb.styles.left || (0 + 'px');
                            scope.auxiliaryPanel.panel.styles.width = (cb.node.offsetWidth || 0) + 'px';
                            scope.auxiliaryPanel.panel.styles.height = (cb.node.offsetHeight || 0) + 'px';
                        }, 0);
                    }

                    size.width = parent.offsetWidth;
                    size.height = parent.offsetHeight;
                };

            // angular.element(buttonEdit)
            //     .append('Edit')
            //     .addClass('mtb-button')
            //     .addClass('insert')
            //     .attr('text-editor-wysiwyg', 'cb')
            //     .css({
            //         'position': 'absolute',
            //         'top': '0',
            //         'right': '0',
            //         'transform': 'translateY(-125%)'
            //     });

            watch = scope.$watch('auxiliaryPanel.activeBlock', function(v, oldValue) {
                pos = lib.getPosition(parent);
                size.width = parent.offsetWidth;
                size.height = parent.offsetHeight;

                if (null !== v && undefined !== v && '' !== v) {
                    cb = cs.blocks[v];
                    scope.cb = cb;

                    $timeout(function() {
                        if ('button' === cb.type) {
                            angular.forEach([
                                topControl,
                                leftControl,
                                rightControl,
                                bottomControl,
                                topLeftControl,
                                topRightControl,
                                bottomLeftControl,
                                bottomRightControl
                            ], function(el) {
                                angular.element(el).css('display', 'none');
                            });
                        } else if ('text' === cb.type) {
                            // angular.element(topLeftControl).css('display', 'none');
                            // angular.element(topRightControl).css('display', 'none');
                            // angular.element(bottomLeftControl).css('display', 'none');
                            // angular.element(bottomRightControl).css('display', 'none');

                            angular.element(topControl).css('display', 'none');
                            angular.element(leftControl).css('display', 'none');
                            angular.element(rightControl).css('display', 'none');
                            angular.element(bottomControl).css('display', 'none');
                            // angular.element(buttonEdit).css('display', '');


                            angular.element(cb.node).addClass('transparent-select');
                        } else {
                            angular.element(topControl).css('display', '');
                            angular.element(leftControl).css('display', '');
                            angular.element(rightControl).css('display', '');
                            angular.element(bottomControl).css('display', '');
                            angular.element(topLeftControl).css('display', '');
                            angular.element(topRightControl).css('display', '');
                            angular.element(bottomLeftControl).css('display', '');
                            angular.element(bottomRightControl).css('display', '');
                            // angular.element(buttonEdit).css('display', 'none');
                        }

                        if (!cb.isBackground) {
                            updateValues({
                                top: /%$/.test(cb.styles.top) ? cb.styles.top : parseInt(cb.styles.top),
                                left: /%$/.test(cb.styles.left) ? cb.styles.left : parseInt(cb.styles.left),
                                width: cb.styles.width,
                                height: cb.styles.height
                            });
                            $timeout(function() {
                                scope.auxiliaryPanel.panel.show = true;
                            }, 0);
                        } else {
                            scope.auxiliaryPanel.panel.show = false;
                        }
                    }, 0);
                } else {
                    (oldValue || 0 === oldValue) && angular.element(cs.blocks[oldValue].node).removeClass('ta-border-shadow');
                    cb = null;
                    $timeout(function() {
                        scope.auxiliaryPanel.panel.show = false;
                    }, 0);
                }
            });

            scope.$on('auxiliaryPanelUpdateSizeEvent', function() {
                $timeout(function() {
                    var show = !cs.blocks[cs.activeBlock].isBackground;
                    pos = lib.getPosition(parent);
                    if (show && cb) {
                        updateValues({
                            top: /%$/.test(cb.styles.top) ? cb.styles.top : parseInt(cb.styles.top),
                            left: /%$/.test(cb.styles.left) ? cb.styles.left : parseInt(cb.styles.left),
                            width: cb.styles.width,
                            height: cb.styles.height
                        });
                    }
                    scope.auxiliaryPanel.panel.show = show;
                }, 0);
            });

            scope.$on('textEditorSaveText', function() { scope.$apply(); });

            scope.$on('auxiliaryPanelRestoreProportionsEvent', function() {
                var w, h, ch, save = false,
                    oldW, oldH;
                if ('text' !== cb.type && 'auto' !== cb.styles.height) {
                    oldW = parseInt(cb.styles.width);
                    oldH = parseInt(cb.styles.height);
                    scope.$emit('auxiliaryPanelMouseDownEvent');
                    if ('image' === cb.type) {
                        ch = cb.styles.width;
                        if (/%$/.test(ch)) {
                            w = ch = element[0].offsetWidth;
                        } else {
                            w = ch = parseInt(ch);
                        }
                        h = (cb.size.height / cb.size.width) * ch;
                        if (h < minHeight) {
                            h = minHeight;
                            w = (cb.size.width / cb.size.height) * h;
                        }
                    } else {
                        ch = cb.styles.width;
                        if (/%$/.test(ch)) {
                            w = element[0].offsetWidth;
                            h = 9 / 16 * w;
                        } else {
                            w = parseInt(ch);
                            h = 9 / 16 * w;
                        }

                        if (h < minHeight) {
                            h = minHeight;
                            w = (16 / 9) * h;
                        }
                    }
                    w = parseInt(w);
                    h = parseInt(h);

                    save = oldH !== h;

                    updateValues({
                        width: w,
                        height: h
                    }, save);
                }
            });

            element.bind('$destroy', function() {
                watch();
                mouseUp(null, true);
                angular.element(window).unbind('resize', resize);
                element.unbind('mousedown');
                scope.$destroy();
            });

            if (element[0].childNodes.length === 0) {
                addClasses(topControl, ['control', 'top']);
                addClasses(leftControl, ['control', 'left']);
                addClasses(rightControl, ['control', 'right']);
                addClasses(bottomControl, ['control', 'bottom']);

                addClasses(topLeftControl, ['control', 'top-left']);
                addClasses(topRightControl, ['control', 'top-right']);
                addClasses(bottomLeftControl, ['control', 'bottom-left']);
                addClasses(bottomRightControl, ['control', 'bottom-right']);


                element.append(topControl);
                element.append(leftControl);
                element.append(rightControl);
                element.append(bottomControl);
                element.append(topRightControl);
                element.append(bottomRightControl);
                element.append(bottomLeftControl);
                element.append(topLeftControl);
                // element.append(buttonEdit);

                // angular.element(buttonEdit).bind('mousedown', function(e) {
                //     scope.auxiliaryPanel.panel.show = false;
                //     scope.$emit('auxiliaryPanelClickEvent');
                // });

                scope.$on('auxiliaryPanelShowEvent', function() {
                    scope.auxiliaryPanel.panel.show = true;
                });
                // for remove
                cs.panel.scope = scope;
                cs.panel.scopeDestroy = scope.$destroy;
            } else {
                topControl = element[0].childNodes[0];
                leftControl = element[0].childNodes[1];
                rightControl = element[0].childNodes[2];
                bottomControl = element[0].childNodes[3];
                topRightControl = element[0].childNodes[4];
                bottomRightControl = element[0].childNodes[5];
                bottomLeftControl = element[0].childNodes[6];
                topLeftControl = element[0].childNodes[7];
                // buttonEdit = element[0].childNodes[8];
            }

            // element.unbind('mousedown');
            element.bind('mousedown', function(e) {
                if (1 === e.which) {
                    e.preventDefault();
                    e.stopPropagation();
                    globalMenuAPI.close();
                    acpManager.close();

                    pos = lib.getPosition(parent);

                    var border = lib.getBorder(cb.node),
                        padding = lib.getPadding(cb.node);

                    borderWidth = border.left + border.right;
                    borderHeight = border.top + border.bottom;

                    paddingWidth = padding.left + padding.right;
                    paddingHeight = padding.top + padding.bottom;

                    scope.$emit('auxiliaryPanelMouseDownEvent');

                    elPos = lib.getPosition(element[0]);
                    // elSize.width = element[0].offsetWidth - borderWidth - paddingWidth;
                    // elSize.height = element[0].offsetHeight - borderHeight - paddingHeight;
                    elSize.width = element[0].offsetWidth;
                    elSize.height = element[0].offsetHeight;
                    x = (e.clientX - pos.left) - (elPos.left - pos.left);
                    y = (e.clientY - pos.top) - (elPos.top - pos.top);

                    customLeft = e.clientX - pos.left - x;
                    customTop = e.clientY - pos.top - y;

                    customLeft /= $rootScope.zoomIcon;
                    customTop /= $rootScope.zoomIcon;

                    moveFlag = true;
                    moveTop = true;
                    moveLeft = true;

                    if (e.target !== element[0]) {
                        // minWidth = 30;
                        // minHeight = 30;

                        dragFlag = true;

                        oldWidth = elSize.width;
                        oldHeight = elSize.height;
                        oldTop = customTop;
                        oldLeft = customLeft;

                        proportions = {
                            forWidth: elSize.width / elSize.height,
                            forHeight: elSize.height / elSize.width
                        };

                        minWidthCorrect = proportions.forWidth >= 1 ?
                                            proportions.forWidth * minHeight : minHeight;

                        minHeightCorrect = proportions.forHeight >= 1 ?
                                            proportions.forHeight * minWidth : minWidth;

                        if (e.target === topControl) {
                            proportion = 't';
                        } else if (e.target === leftControl) {
                            proportion = 'l';
                        } else if (e.target === rightControl) {
                            proportion = 'r';
                        } else if (e.target === bottomControl) {
                            proportion = 'b';
                        } else {
                            ratio = proportions.forWidth < minWidth / minHeight;
                            if (e.target === topLeftControl) {
                                proportion = 'tl';
                            } else if (e.target === topRightControl) {
                                proportion = 'tr';
                            } else if (e.target === bottomLeftControl) {
                                proportion = 'bl';
                            } else if (e.target === bottomRightControl) {
                                proportion = 'br';
                            }
                        }
                        angular.element($window.document.body).addClass(proportion);
                    } else {
                        element.css('cursor', 'move');
                    }
                    angular.element($window.document).bind('mouseup', mouseUp);
                    angular.element($window.document).bind('mousemove', move);
                    angular.element($window.document).bind('ondragstart', false_);
                    angular.element($window.document).bind('onselectstart', false_);
                }
            });

            angular.element(window).unbind('resize', resize);
            angular.element(window).bind('resize', resize);

            $compile(element.contents())(scope);
        }
    }
}]);
'use strict';

constructorApp.directive('slidePreview', ['$compile', '$window', '$rootScope', 'convertFontSize', function($compile, $window, $rootScope, convertFontSize) {
    return {
        restrict: 'A',
        scope: {
            slidePreview: '='
        },
        link: function(scope, element, attrs) {
            var i, watch, slideshow, p, blocks,
                width, height, slide,
                setHeight =  function(proportions) {
                    angular.element(slideshow).css('height', slideshow.offsetWidth * proportions + 'px');
                },
                correctShadow = function(value, w, h, isBox) {
                    if (!value) { return value; }

                    value = value.split(' ');

                    value[0] = (parseInt(value[0]) * w) + 'px';
                    value[1] = (parseInt(value[1]) * h) + 'px';
                    value[2] = (parseInt(value[2]) * w) + 'px';
                    if (isBox) {
                        value[3] = (parseInt(value[3]) * w) + 'px';
                    }

                    return value.join(' ');
                },
                update = function(b) {
                    var style = {},
                        w = element[0].offsetWidth,
                        h = element[0].offsetHeight,
                        bWidth, bHeight, tmp,

                        correctPos = function(pos, num) {
                            var px = /px$/.test(pos);
                            pos = parseFloat(pos);
                            if (px) {
                                pos = (pos / num * 100);
                            }
                            return pos;
                        },
                        correctSize = function(s, num) {
                            var px;
                            if (typeof s === 'string') {
                                px = /px$/.test(s);
                            } else {
                                px = true;
                            }

                            s = parseFloat(s);
                            if (px) {
                                s = s / (num / 100);
                            }
                            return s;
                        };

                    b.styles['position'] = 'absolute';
                    if ('text' === b.type || 'button' === b.type || 'shape' === b.type) {
                        b.styles['font-size'] = (w / width * parseFloat(b.styles['font-size']));
                        if (b.styles['font-size'] < 1) {
                            b.styles['font-size'] = 1;
                        }
                        b.styles['font-size'] += 'px';

                        if ('button' === b.type) {
                            b.styles['padding'] = w / width * parseInt(b.styles['padding']) + 'px';
                        } else {
                            b.styles['padding'] = '0px';
                        }

                        b.styles['border-width'] = '1px';

                        if ('auto' !== b.styles['height']) {
                            b.styles['height'] = correctSize(b.styles['height'], height) + '%';
                        }

                        if ('auto' !== b.styles['width']) {
                            b.styles['width'] = correctSize(b.styles['width'], width) + '%';
                        }

                        b.styles['box-shadow'] = correctShadow(b.styles['box-shadow'], w / width, h / height, true);
                        b.styles['text-shadow'] = correctShadow(b.styles['text-shadow'], w / width, h / height);
                        convertFontSize.convertInvestedEm(b.node);
                    } else if ('image' === b.type) {
                        b.styles['padding'] = '0px';
                        b.styles['border-width'] = '1px';

                        if (b.isBackground) {
                            // b.styles['width'] = '100%';
                            // b.styles['height'] = '100%';

                            // if (width / height >= b.size.width / b.size.height) {
                            //     tmp = b.size.height >= h ? h : b.size.height;
                            //     bHeight = tmp;
                            //     bWidth = b.size.width / b.size.height * tmp;
                            // } else {
                            //     tmp = b.size.width >= w ? w : b.size.width;
                            //     bWidth = tmp;
                            //     bHeight = b.size.height / b.size.width * tmp;
                            // }
                            // b.styles['width'] = bWidth + 'px';
                            // b.styles['height'] = bHeight + 'px';

                            // b.styles['top'] = (h - bHeight) / 2 + 'px';
                            // b.styles['left'] = (w - bWidth) / 2 + 'px';
                        } else {
                            b.styles['width'] = correctSize(b.styles['width'], width) + '%';
                            if ('auto' !== b.styles['height']) {
                                b.styles['height'] = correctSize(b.styles['height'], height) + '%';
                            }
                        }
                        b.styles['box-shadow'] = correctShadow(b.styles['box-shadow'], w / width, h / height, true);
                    } else {

                        b.styles['width'] = correctSize(b.styles['width'], width) + '%';
                        b.styles['height'] = correctSize(b.styles['height'], height) + '%';
                    }

                    if (!b.isBackground) {
                        b.styles['top'] = correctPos(b.styles['top'], height) + '%';
                        b.styles['left'] = correctPos(b.styles['left'], width) + '%';
                    }
                    angular.element(b.node).css(b.styles);
                },
                getSize = function(forcibly) {
                    if (!width || forcibly) {
                        width = $rootScope.slideSize.width || scope.slidePreview.node.offsetWidth;
                    }
                    if (!height || forcibly) {
                        height = $rootScope.slideSize.height || scope.slidePreview.node.offsetHeight;
                    }
                },
                createSlide_ = function(index) {
                    var d = $window.document.createElement('div'), stl;

                    // width || (width = scope.slidePreview.node.offsetWidth);
                    // height || (height = scope.slidePreview.node.offsetHeight);

                    getSize();

                    element[0].innerHTML = '';
                    blocks = [];
                    slide = $window.document.createElement('div');
                    angular.element(slide).attr('ng-style', '{"background-color": slidePreview.styles["background-color"]}');
                    angular.element(slide).css('height', '100%');

                    angular.forEach(scope.slidePreview.blocks, function(b) {
                        var node;
                        if ('video' === b.type) {
                            // node = new Image();
                            // node.src = 'img/videos-icon-608x240.png';
                            node = angular.element('<div></div>')[0];
                            angular.element(node).css({ 'background-image': 'url(constructor/img/video-player.png)' }).addClass('video');
                        } else if ('text' === b.type) {
                            node = angular.element('<div></div>')[0];
                            node.innerHTML = b.content;
                            angular.element(node).css('word-wrap', 'break-word');
                        } else {
                            if (b.node) {
                                node = b.node.cloneNode(true);
                            } else {
                                node = new Image();
                                node.src = b.url;
                            }
                        }

                        blocks.push({
                            type: b.type,
                            node: node,
                            size: b.size,
                            styles: angular.copy(b.styles, {}),
                            isBackground: b.isBackground
                        });

                        if ('video' === b.type) {
                            stl = blocks[blocks.length - 1].styles;
                            if ('auto' === stl['width']) {
                                stl['width'] = b.node.offsetWidth + 'px';
                            }
                            if ('auto' === stl['height']) {
                                stl['height'] = b.node.offsetHeight + 'px';
                            }
                        } else if ('image' === b.type) {
                            blocks[blocks.length - 1].node.src = b.url;
                        } else if ('shape' !== b.type) {
                            if (!blocks[blocks.length - 1].node.firstChild) {
                                blocks[blocks.length - 1].node.innerHTML = 'Text...';
                            }
                        }

                        angular.element(blocks[blocks.length - 1].node)
                            .removeAttr('ng-style')
                            .removeAttr('ng-if')
                            .removeAttr('ng-src')
                            .removeAttr('block-text')
                            .removeAttr('ng-scope')
                            .removeAttr('index');

                        update(blocks[undefined === index ? index : blocks.length - 1]);

                        slide.appendChild(blocks[blocks.length - 1].node);

                        if (b.isBackground) {
                            angular.element(blocks[blocks.length - 1].node.parentNode).addClass('mss-centering-img');
                        }
                    });
                    d.appendChild(slide);
                    element.html(d.innerHTML);
                    $compile(element.contents())(scope);
                };
            slideshow = element[0];
            // createSlide_();
            setHeight(parseFloat(attrs.spHeight) / parseFloat(attrs.spWidth));

            scope.$on('slidePreviewUpdateEvent', function(e, data) {
                if (scope.slidePreview.index === data.index) {
                    createSlide_(data.index);
                    setHeight(parseFloat(attrs.spHeight) / parseFloat(attrs.spWidth));
                }
                data.cb && data.cb();
            });

            scope.$on('slidePreviewSlideSizeEvent', function(e, data) {
                width = data.width;
                height = data.height;
                setHeight(height / width);
                createSlide_(data.index);
            });

            for (i = 0; i < scope.slidePreview.blocks.length; i++) {
                createSlide_(i);
            }

            if (!element.children().length) {
                element.html('<div style="height: 100%;" ng-style="{\'background-color\': slidePreview.styles[\'background-color\']};"></div>');
                // $compile(element.contents())(scope);
            }
            $compile(element.contents())(scope);

            element.bind('$destroy', function() {
                scope.$destroy();
            });
        }
    };
}]);
'use strict';

constructorApp.directive('elseif', [ '$compile', function($compile) {
    return {
        restrict: 'A',
        scope: { elseif: '=' },
        link: function(scope, element, attrs) {
            var html = "<div class=\"col-sm-9\">";

            if (scope.elseif.units) {
                html += "\
                    <div class=\"input-group\">\
                        <div slideshow-options=\"elseif\" type=\"slideshow\" replace=\"true\"></div>\
                        <span class=\"input-group-addon\">{{elseif.units}}</span>\
                    </div>\
                ";
            } else {
                html += "<div slideshow-options=\"elseif\" type=\"slideshow\" replace=\"true\"></div>";
            }

            if (scope.elseif.description) {
                html += "<p class=\"help-block\" ng-bind-html=\"elseif.description\"></p>";
            }

            html += "</div>";

            element.replaceWith($compile(html)(scope));
            element.bind('$destroy', function() {
                scope.$destroy();
            });
        }
    };
}]);
'use strict';

constructorApp.service('imgToDataURL', [function() {
    return function(url, outputFormat, callback, quality) {
        var canvas = document.createElement('CANVAS'),
            ctx = canvas.getContext('2d'),
            img = new Image(), dataURL;

        img.onload = function() {
            canvas.height = img.height;
            canvas.width = img.width;
            try {
                ctx.drawImage(img, 0, 0);
                dataURL = canvas.toDataURL(outputFormat, quality);
                callback(null, dataURL);
            } catch (e) {
                callback(e, null);
            }
            canvas = img = null;
        };

        img.onerror = function(e) {
            callback(e, null);
        };

        img.src = url;
    };
}]);

constructorApp.factory('getHtmlSlideshow', ['$window', 'imgToDataURL', 'loader', 'messages', function($window, imgToDataURL, loader, messages) {
    var nameAndType = function(str) {
        var type;
        str = str.split('.');
        type = getMimeType(str.splice(str.length - 1, 1)[0]);
        str = str.join('');
        return {
            name: str,
            mimeType: type
        };
    },

    getCdata = function(id) {
        // return '<![cdata[' + id + ']]>';
        return '<![magicslideshow[' + id + ']]>';
    },

    getMimeType = function(type) {
        var result;
        switch (type) {
            case 'png':
            // case 'jpg':
            case 'gif': // сохранить может а конвертировать нет
            case 'bmp': // don't support
            case 'tiff':
            case 'x-icon':
            case 'svg+xml':
            case 'xxx':
                result = 'png';
                break;
            case 'gif':
                result = 'gif';
                break;
            case 'jpg':
                result = 'jpg';
                break;
            case 'jpeg':
                result = 'png';
                break;
            case 'webp':
                result = 'webp';
                break;
            default:
                result = 'png';
                break;
        }
        return result;
    },

    baseReplace = function(str) {
        return str ? str.replace(/^data:image\/(png|webp|jpeg);base64,/, '') : '';
    };

    return function(scope, callback_, spaces, zip) {
        var html,
            newline = '',
            size = {'base-width': 0, 'base-height': 0 },
            loadAllImg = function(callback) {
                var imgNames = [],
                    nextBlock = function(index, slide, cb) {
                        if (index < slide.blocks.length) {
                            var b = slide.blocks[index];

                            if ('image' === b.type) {
                                var i, name, mimeType, unique = true;

                                name = nameAndType(b.imgName);
                                mimeType = getMimeType(name.mimeType);
                                name = name.name;

                                for (i = 0; i < imgNames.length; i++) {
                                    if (imgNames[i] === name) {
                                        unique = false;
                                        break;
                                    }
                                }

                                if (unique) {
                                    imgNames.push(name);
                                    if (b.base64) {
                                        var data = b.base64;
                                        data = baseReplace(data);

                                        // images.file(name+'.'+mimeType, data, {base64: true});
                                        zip && zip.file(name+'.'+mimeType, data, {base64: true});
                                        nextBlock(++index, slide, cb);
                                    } else {
                                        loader.load(b.url, {
                                            onload: function (e) {
                                                imgToDataURL(b.url, 'image/' + mimeType, function(err, data) {
                                                    if (!err) {
                                                        data = baseReplace(data);

                                                        // images.file(name+'.'+mimeType, data, {base64: true});
                                                        zip && zip.file(name+'.'+mimeType, data, {base64: true});
                                                        nextBlock(++index, slide, cb);
                                                    } else {
                                                        b.otherDomain = true;
                                                        nextBlock(++index, slide, cb);
                                                    }
                                                }, 1);
                                            },
                                            error: function(e) {
                                                nextBlock(++index, slide, cb);
                                            }
                                        });
                                    }
                                } else {
                                    nextBlock(++index, slide, cb);
                                }
                            } else {
                                nextBlock(++index, slide, cb);
                            }
                        } else {
                            cb && cb();
                        }
                    },

                    nextSlide = function(slideIndex) {
                        if (slideIndex < scope.slides.length) {
                            nextBlock(0, scope.slides[slideIndex], function() {
                                nextSlide(++slideIndex);
                            });
                        } else {
                            callback && callback();
                        }
                    };
                nextSlide(0);
            },
            getSlide = function(slide, index) {
                var img, blocks = '', sld,
                    cloneSlide = scope.saveSlide(index),
                    children = cloneSlide.childNodes,
                    tag = '</div>',
                    wrapper = $window.document.createElement('div');

                angular.forEach(slide.blocks, function(b, i) {
                    var name, mimeType, url_,
                        w = $window.document.createElement('div');

                    if ('image' === b.type) {
                        img = children[i];

                        if (b.link) {
                            img.firstChild.removeAttribute('src');
                            img.firstChild.setAttribute('tempsrc', '');
                        } else {
                            img.removeAttribute('src');
                            img.setAttribute('tempsrc', '');
                        }

                        w.appendChild(img.cloneNode(true));
                        img = w.innerHTML;

                        if (!b.otherDomain && !messages.status) {
                            name = nameAndType(b.imgName);
                            mimeType = getMimeType(name.mimeType);
                            name = name.name;
                            img = img.replace(/tempsrc=""/, 'src="images/' + (name + '.' + mimeType) + '"');
                        } else {
                            if (messages.status && null !== b.imgId) {
                                url_ = getCdata(b.imgId);
                            } else {
                                url_ = b.url;
                            }
                            img = img.replace(/tempsrc=""/, 'src="' + url_ + '"');
                        }

                        img = img.replace(/ ng-scope/, '');

                        blocks += ((spaces ? '                ' : '') + img + newline);
                    } else {
                        w.appendChild(children[i].cloneNode(true));
                        blocks += ((spaces ? '                ' : '') + w.innerHTML + newline);
                    }
                });

                wrapper.appendChild(cloneSlide);
                cloneSlide.innerHTML = '{delimiter}';

                sld = wrapper.innerHTML.split('{delimiter}')[0];
                sld = sld.replace(/ng-scope/, '');
                sld += newline;
                sld += blocks;

                sld += ((spaces ? '            ' : '') + tag);
                return sld;
            };

        if (spaces) { newline = '\n'; }
        loadAllImg(function() {
            var v, dataOptions = '', slides = '';

            angular.forEach(scope.slides, function(s, i) {
                spaces && (slides += ('            <!-- slide ' + ( i + 1 ) + ' -->\n'));
                slides += ((spaces ? '            ' : '') + getSlide(s, i) + newline);
            });

            size['base-width'] = scope.mainField[0].offsetWidth;
            size['base-height'] = scope.mainField[0].offsetHeight;

            angular.forEach(scope.slideshowOptions, function(opt, i) {
                if (true === opt.value || false === opt.value) { opt.value += ''; }
                // if (scope.defaults.slideshowOptions[i].value !== opt.value || scope.defaults.slideshowOptions[i].name === 'base-height' || scope.defaults.slideshowOptions[i].name === 'base-width') {
                    // if ('base-width' === opt.name || 'base-height' === opt.name) {
                    //     v = size[opt.name];
                    // } else {
                        v = opt.value;
                    // }
                    dataOptions += (opt.name + ':' + v + ';');
                // }
            });

            html = (spaces ? '        ' : '') + '<div class="MagicSlideshow" data-options="' + dataOptions + '">' + newline + slides + (spaces ? '        ' : '') + '</div>' + newline;

            callback_ && callback_(html);
        });
    };
}]);

constructorApp.directive('gZip', ['$window', '$http', '$timeout', 'getHtmlSlideshow', 'imgToDataURL', 'aInfobarManager', 'paths', function($window, $http, $timeout, getHtmlSlideshow, imgToDataURL, aInfobarManager, paths) {
    var getComponent = function(url, callback) {
            $http.post(url, {})
            .success(function(data, state) {
                if (200 !== state) {
                    data = null;
                }
                callback(data);
            }).error(function(data) {
                callback();
            });
        },

        baseReplace = function(str) {
            return str ? str.replace(/^data:image\/(png|webp|jpeg);base64,/, '') : '';
        };
    return {
        restrict: 'A',
        // scope: false,
        link: function(scope, element, attrs) {
            var createZip = function() {
                var zip = new $window.JSZip(),
                    js, css, images, html,
                    dataOptions = '', content,
                    slides = '',

                    getComponents = function(callback) {
                        var result = {
                                js: null,
                                css: []
                            },
                            // count = 6,
                            count = 4,
                            allLoded = function() {
                                if (0 === count) {
                                    callback(result);
                                }
                            };

                        result.css.push({
                            img: true,
                            name: 'magicarrows.eot',
                            path: 'css/themes/fonts/',
                            data: ' '
                        });

                        result.css.push({
                            img: true,
                            name: 'magicarrows.svg',
                            path: 'css/themes/fonts/',
                            data: ' '
                        });

                        result.css.push({
                            img: true,
                            name: 'magicarrows.ttf',
                            path: 'css/themes/fonts/',
                            data: ' '
                        });


                        result.css.push({
                            img: true,
                            name: 'magicarrows.woff',
                            path: 'css/themes/fonts/',
                            data: ' '
                        });

                        getComponent(paths.zipMagicSLideshow + '/magicslideshow.js', function(data_) {
                            result.js = {
                                name: 'magicslideshow.js',
                                path: 'js/',
                                data: data_
                            };
                            count--;
                            allLoded();
                        });

                        getComponent(paths.zipMagicSLideshow + '/magicslideshow.css', function(data_) {
                            result.css.push({
                                name: 'magicslideshow.css',
                                path: 'css/',
                                data: data_
                            });
                            count--;
                            allLoded();
                        });

                        getComponent(paths.zipMagicSLideshow + '/themes/default/magicslideshow.defaults.css', function(data_) {
                            result.css.push({
                                name: 'magicslideshow.defaults.css',
                                path: 'css/themes/default/',
                                data: data_
                            });
                            count--;
                            allLoded();
                        });

                        // imgToDataURL(paths.zipMagicSLideshow + '/themes/default/graphics/buttons.png', 'image/png', function(err, data_) {
                        //     data_ = baseReplace(data_);
                        //     result.css.push({
                        //         img: true,
                        //         name: 'buttons.png',
                        //         path: 'css/themes/default/graphics/',
                        //         data: err ? null : data_
                        //     });
                        //     count--;
                        //     allLoded();
                        // });

                        // imgToDataURL(paths.zipMagicSLideshow + '/themes/default/graphics/buttons@2x.png', 'image/png', function(err, data_) {
                        //     data_ = baseReplace(data_);
                        //     result.css.push({
                        //         img: true,
                        //         name: 'buttons@2x.png',
                        //         path: 'css/themes/default/graphics/',
                        //         data: err ? null : data_
                        //     });
                        //     count--;
                        //     allLoded();
                        // });

                        imgToDataURL(paths.zipMagicSLideshow + '/themes/default/graphics/loader.gif', 'image/gif', function(err, data_) {
                            data_ = baseReplace(data_);
                            result.css.push({
                                img: true,
                                name: 'loader.gif',
                                path: 'css/themes/default/graphics/',
                                // data: err ? null : data_
                                data: ' '
                            });
                            count--;
                            allLoded();
                        });
                    };

                images = zip.folder("images");

                var timer = $timeout(function() {
                    element.addClass('loading');
                }, 200);

                getHtmlSlideshow(scope.$parent, function(slideshowHTML) {
                    var v, size = {'base-width': 0, 'base-height': 0},
                        jsSrc = 'http://www.magictoolbox.com/static/magicslideshow/magicslideshow.js',
                        cssSrc = 'http://www.magictoolbox.com/static/magicslideshow/magicslideshow.css';

                    getComponents(function(data) {
                        var create = true;
                        if (data.js.data) {
                            zip.file(data.js.path + data.js.name, data.js.data);
                            jsSrc = 'js/magicslideshow.js';
                        }

                        angular.forEach(data.css, function(f) {
                            if (!f.data) {
                                create = false;
                            }
                        });

                        if (create) {
                            cssSrc = 'css/magicslideshow.css';
                            angular.forEach(data.css, function(f) {
                                if (f.img) {
                                    zip.file(f.path + f.name, f.data, {base64: true});

                                } else {
                                    zip.file(f.path + f.name, f.data);
                                }
                            });
                        }


                        html =  '<!doctype html>\n' +
                                '<html>\n' +
                                '    <!-- magictoolbox.com -->\n' +
                                '    <head>\n' +
                                '        <title>Magic Slideshow</title>\n' +
                                '        \n' +
                                '        <!-- magicslideshow css -->\n' +
                                '        <link rel="stylesheet" href="' + cssSrc + '">\n' +
                                '        \n' +
                                '        <!-- magicslideshow js -->\n' +
                                '        <script src="' + jsSrc + '"></script>\n' +
                                '        \n' +
                                '    </head>\n' +
                                '    <body>\n' + slideshowHTML +
                                '    </body>\n' +
                                '</html>\n';

                        zip.file("index.html", html);

                        $timeout.cancel(timer);
                        element.removeClass('loading');
                        element.removeAttr('disabled');

                        content = zip.generate({type:"blob"});
                        $window.saveAs(content, "magicslideshow.zip");
                        aInfobarManager.showMessage('Slideshow loaded.');
                    });
                }, true, images);
            };



            element.bind('click', function(e) {
                element.addClass('loading');
                element.attr('disabled', 'disabled');
                createZip(e);
            });

            element.bind('$destroy', function() {
                element.bind('click');
            });
        }
    };
}]);
'use strict';

constructorApp.directive('hideField', [function() {
    return {
        restrict: 'A',
        scope: {
            hideField: '='
        },
        link: function(scope, element, attrs) {
            var watch = scope.$watch('hideField', function(nv) {
                if (nv) {
                    element.css('visibility', 'visible');
                } else {
                    element.css('visibility', 'hidden');
                }
            });
            element.bind('$destroy', function() {
                watch();
                scope.$destroy();
            });
        }
    };
}]);'use strict';

constructorApp.directive('savingAction', ['$compile', '$document', '$timeout', '$q', 'globalMenuAPI', '$rootScope', function($compile, $document, $timeout, $q, globalMenuAPI, $rootScope) {
    return {
        restrict: 'A',
        scope: true,
        controller: ['$scope', '$element', '$attrs', function($scope, $element, $attrs) {
            var MAX_SIZE = 15;
            $scope.stek = [];
            $scope.position = -1;
            $scope.prev = {
                node: null,
                disabled: true
            };

            $scope.next = {
                node: null,
                disabled: true
            };

            $scope.push = function(event) {
                $scope.clearHistory();
                if ($scope.stek.length === MAX_SIZE) {
                    $scope.stek.shift();
                } else {
                    $scope.position++;
                }
                $scope.stek.push(event);

                if (!$scope.next.disabled) {
                    $scope.next.disabled = true;
                }
                // if ($scope.prev.disabled && $scope.position > 0) {
                    $scope.prev.disabled = false;
                // }
            };

            $scope.clearHistory = function() {
                var i, arr = [];
                if ($scope.position < $scope.stek.length - 1) {
                    for (i = 0; i <= $scope.position; i++) {
                        arr.push($scope.stek[i]);
                    }
                    $scope.stek = arr;
                    if (!$scope.next.disabled) {
                        $scope.next.disabled = true;
                    }
                }
            };

            $scope.nextStep = function() {
                var l = $scope.stek.length;
                if ($scope.position < l - 1) {
                    $scope.position++;
                    $scope.$apply(function() {
                        if ($scope.position === l - 1) {
                            $scope.next.disabled = true;
                        }
                        if ($scope.prev.disabled) {
                            $scope.prev.disabled = false;
                        }
                    });
                    return $scope.stek[$scope.position];
                }
            };

            $scope.prevStep = function() {
                if ($scope.position >= 0) {
                    var s = $scope.stek[$scope.position];
                    $scope.position -= 1;
                    $scope.$apply(function() {
                        if ($scope.position === -1) {
                            $scope.prev.disabled = true;
                        }
                        if ($scope.next.disabled) {
                            $scope.next.disabled = false;
                        }
                    });
                    return s;
                }
            };
        }],

        link: function(scope, element, attrs) {
            var ctrl = false,
                shift = false,
                tmp,
                deferred,
                kd = function(e) {
                    if (ctrl || e.metaKey) {
                        if (90 === e.keyCode) { // ctrl + z
                            if (shift) {
                                nextClick(e);
                            } else {
                                prevClick(e);
                            }
                        } else if (89 === e.keyCode && !shift) { // ctrl + y
                            nextClick(e);
                        }
                    }
                    if (17 === e.keyCode) {
                        ctrl = true;
                    }
                    if (16 === e.keyCode) {
                        shift = true;
                    }
                },
                ku = function(e) {
                    if (17 === e.keyCode) {
                        ctrl = false;
                    }
                    if (16 === e.keyCode) {
                        shift = false;
                    }
                },
                prevClick = function(e) {
                    globalMenuAPI.close();
                    if (scope.position >= 0 && !deferred) {
                        deferred = $q.defer();
                        scope.$emit('savingActionToggle', {
                            action: 'prev',
                            deferred: deferred,
                            event: scope.prevStep()
                        });
                        deferred.promise.then(function() {
                            deferred = null;
                        });
                    }
                },
                nextClick = function(e) {
                    globalMenuAPI.close();
                    if (scope.position !== scope.stek.length - 1 && !deferred) {
                        deferred = $q.defer();
                        scope.$emit('savingActionToggle', {
                            action: 'next',
                            deferred: deferred,
                            event: scope.nextStep()
                        });
                        deferred.promise.then(function() {
                            deferred = null;
                        });
                    }
                };

            scope.prev.node = angular.element(document.querySelector('#control-button-prev'));
            scope.next.node = angular.element(document.querySelector('#control-button-next'));
            scope.prev.node.attr('ng-disabled', 'prev.disabled');
            scope.next.node.attr('ng-disabled', 'next.disabled');

            scope.$on('savingActionAddEvent', function(e, data) {
                if (!scope.$$phase) {
                    scope.$apply(function() {
                        scope.push(data.event);
                    });
                } else {
                    scope.push(data.event);
                }
            });

            scope.$on('savingActionReset', function(e, data) {
                scope.position = -1;
                scope.prev.disabled = true;
                scope.stek = [];
            });

            scope.prev.node.bind('click', prevClick);
            scope.next.node.bind('click', nextClick);

            $document.bind('keydown', kd);
            $document.bind('keyup', ku);

            element.bind('$destroy', function() {
                $document.unbind('keydown', kd);
                $document.unbind('keyup', ku);
                scope.$destroy();
            });

            $compile(element.contents())(scope);
        }
    };
}]);
'use strict';

constructorApp.directive('inputStyle', [function() {
    return {
        restrict: 'A',
        scope: {
            inputStyle: '='
        },
        link: function(scope, element, attrs) {
            var focusFlag = false,
                ts = attrs.typeStyle,
                watch = scope.$watch('inputStyle', function(nv, ov) {
                    if (focusFlag) {
                        scope.$emit('inputStyleEvent', {
                            type: 'change',
                            typeStyle: ts,
                            oldValue: ov,
                            newValue: nv
                        });
                    }
                }),

                focus = function(e) {
                    focusFlag = true;
                    scope.$emit('inputStyleEvent', {
                        type: 'focus'
                    });
                },

                blur = function(e) {
                    focusFlag = false;
                    scope.$emit('inputStyleEvent', {
                        type: 'blur'
                    });
                };

            element.bind('focus', focus);
            element.bind('blur', blur);
            element.bind('$destroy', function() {
                watch();
                element.unbind('focus', focus);
                element.unbind('blur', blur);
                scope.$destroy();
            });
        }
    };
}]);'use strict';

constructorApp.directive('buttonCheckbox', ['$compile', function($compile) {
    return {
        restrict: 'A',
        scope: {
            buttonCheckbox: '='
        },
        link: function(scope, element, attrs) {
            var lastButton, watch,
                buttons = [],
                ae = angular.element,
                set = function(node) {
                    ae(node).attr('disabled', 'disabled');
                    ae(node).addClass('disabled');

                    if (lastButton) {
                        ae(lastButton).removeAttr('disabled');
                        ae(lastButton).removeClass('disabled');    
                    }
                };

            watch = scope.$watch('buttonCheckbox', function(newValue) {
                if (newValue) {
                    angular.forEach(buttons, function(b) {
                        if (newValue === b.attr) {
                            set(b.node);
                            lastButton = b.node;
                        }
                    });    
                }
            });

            angular.forEach(element.find('button'), function(b, i) {
                buttons.push({
                    node: b,
                    attr: ae(b).attr('bcb')
                });

                ae(b).bind('mousedown', function(e) {
                    scope.$emit('buttonCheckboxEvent', {
                        target: ae(e.target).attr('bcb')
                    });
                });
            });

            element.bind('$destroy', function() {
                watch();
                scope.$destroy();
            });
        }
    };
}]);'use strict';

constructorApp.service('activeTab', [function() {
    this.currentTab = {
        index: 0
    };
}]);

constructorApp.directive('tabs', ['$compile', 'activeTab', 'globalMenuAPI', '$timeout', function($compile, activeTab, globalMenuAPI, $timeout) {
    return {
        restrict: 'A',
        scope: true,
        link: function(scope, element, attrs, ctrl) {
            var lastTab,
                watchers = [],
                cl = 'active',
                children = element[0].children[0].children[0].children,
                buttons = [],
                containerTabs = angular.element('<div class="container-tabs"></div>'),
                animationLine = angular.element('<div class="tabs-animation-line"></div>'),
                indicatorLine = angular.element('<div class="tabs-indicator-line"></div>'),

                createTab = function(name, index) {
                    var button = angular.element('<button index="' + index + '" id="tab-' + name + '">' + (name.charAt(0).toUpperCase() + name.substr(1)) +'</button>');
                    button.bind('click', function(e) {
                        var tab, index, v;
                        e.preventDefault();
                        e.stopPropagation();

                        tab = angular.element(e.target);
                        index = tab.attr('index');

                        if (lastTab.attr('index') !== index) {
                            scope.$apply(function() {
                                scope.currentTab.index = parseInt(index);
                            });
                        }
                        globalMenuAPI.close();
                    });
                    buttons.push(button);
                    return button;
                },

                getValues = function(node) {
                    return {
                        width: node[0].offsetWidth,
                        left: node[0].offsetLeft
                    }
                },

                setValues = function(node) {
                    var v = getValues(node);
                    if (v.width > 0) {
                        indicatorLine.css({
                            'width': v.width + 'px',
                            'left': v.left + 'px'
                        });
                    }
                };

            scope.currentTab = activeTab.currentTab;
            scope.currentTab.index = parseInt(attrs.tabs);

            if (isNaN(scope.currentTab.index) || scope.currentTab.index >= children.length) {
                scope.currentTab.index = 0;
            }

            angular.forEach(children, function(ch, i) {
                var ach = angular.element(ch),
                    tab = createTab(ach.attr('tab'), i);

                ach.attr('ng-show', i + ' == currentTab');

                ach.addClass('content');

                if (i === scope.currentTab.index) {
                    tab.addClass('active');
                    lastTab = tab;
                }
                containerTabs.append(tab[0]);
            });

            indicatorLine.css({ 'width': '0px', 'left': '0px' });

            animationLine.append(indicatorLine[0]);
            containerTabs.append(animationLine[0]);

            containerTabs.attr('count', children.length);
            element[0].insertBefore(containerTabs[0], element[0].firstChild);
            // element.append(containerTabs[0]);
            // element.append(scroll[0]);
            setValues(lastTab);
            watchers.push(scope.$watch('currentTab.index', function(nv, ov) {
                var tab, v;
                if (undefined !== nv && nv !== ov) {
                    tab = buttons[nv];
                    if (tab && lastTab.attr('index') !== nv && tab !== lastTab) {
                        tab.addClass(cl);
                        lastTab.removeClass(cl);
                        lastTab = tab;
                    }
                }
                $timeout(function() {
                    setValues(lastTab);
                }, 0);
            }));

            watchers.push(scope.$parent.$parent.$watch('slideEditor.flags.slide', function() {
                $timeout(function() {
                    setValues(lastTab);
                }, 0);
            }));

            element.bind('$destroy', function() {
                angular.forEach(watchers, function(watcher) { watcher(); });
                scope.$destroy();
            });

        }
    };
}]);
'use strict';

constructorApp.directive('resizeField', ['$window', '$timeout', function($window, $timeout) {
    return {
        restrict: 'A',
        link: function(scope, element, attrs) {
            var timer;
            angular.element($window).bind('resize', function(e) {
                // $timeout.cancel(timer);
                // timer = $timeout(function() {
                //     scope.calcCanvasSize();
                //     scope.$$correctBlocksPosition();
                // }, 200);
            });

            element.bind('$destroy', function() {
                angular.element($window).unbind('resize');
            });
        }
    };
}]);'use strict';

constructorApp.directive('keepColor', ['$timeout', function($timeout) {
    return {
        restrict: 'A',
        require: '?ngModel',
        link: function(scope, element, attrs, ngModel) {
            var s = attrs.keepColor,
                watch;
            watch = scope.$watch(function () {
                return ngModel.$modelValue;
            }, function(newValue, oldValue) {
                if (newValue) {
                    scope.$emit('keepColorEvent', {
                        oldValue: oldValue,
                        style: s
                    });
                }
            });

            element.bind('$destroy', function() {
                watch();
                scope.$destroy();
            });
        }
    };
}]);'use strict';

constructorApp.directive('controlLine', ['lib', '$document','$window', 'globalMenuAPI', function(lib, $document, $window, globalMenuAPI) {
    return {
        restrict: 'A',
        scope: true,
        link: function(scope, element, attrs) {
            var minTopHeight = 250,
                minBottomHeight = 20,
                containerPositionY,
                containerHeight,
                correctSize,

                bottomContent = element.parent(),
                container = bottomContent.parent(),
                topContent = angular.element(container.children()[0]),

                move = function(e) {
                    var t, b;
                    if (1 === e.which) {
                        e.stopPropagation();
                        e.preventDefault();
                        t = e.pageY - containerPositionY - correctSize;
                        if (t < minTopHeight) {
                            t = minTopHeight;
                        }

                        b = containerHeight - t;
                        if (b < minBottomHeight) {
                            b = minBottomHeight;
                            t = containerHeight - b;
                        }

                        scope.$emit('controlLineEventResize');

                        setCss(t, b);
                    }
                },

                mouseDown = function(e) {
                    if (1 === e.which) {
                        e.stopPropagation();
                        e.preventDefault();
                        !containerHeight && (containerHeight = container[0].offsetHeight);
                        correctSize = e.pageY - lib.obj.positY(element[0]);
                        containerPositionY = lib.obj.positY(container[0]);

                        globalMenuAPI.close();

                        container.addClass('move');
                        $document.bind('mousemove', move);
                        $document.bind('mouseup', mouseUp);
                    }
                },

                mouseUp = function(e) {
                    if (1 === e.which) {
                        e.stopPropagation();
                        e.preventDefault();
                        container.removeClass('move');
                        $document.unbind('mousemove', move);
                        $document.unbind('mouseup', mouseUp);
                    }
                },

                resize = function() {
                    var top, bottom,
                        oldContainerHeight = containerHeight;
                    containerHeight = container[0].offsetHeight;

                    bottom = bottomContent[0].offsetHeight / oldContainerHeight * containerHeight;
                    top = containerHeight - bottom;

                    scope.$emit('controlLineEventResize');
                    setCss(top, bottom);
                },

                setCss = function(top, bottom) {
                    topContent.css('height', top + 'px');
                    bottomContent.css('height', bottom + 'px');
                };

            element.bind('mousedown', mouseDown);
            angular.element($window).bind('resize', resize);

            element.bind('$destroy', function() {
                element.unbind('mousedown', mouseDown);
                angular.element($window).unbind('resize', resize);
                scope.$destroy();
            });

            element.append('<span class="cl-title">Animation timeline</span>');
            element.append('<span class="cl-control"></span>');
        }
    };
}]);'use strict';

constructorApp.factory('tl', [function() {
    var f = { maxScale: { value: 0 }, width: { value: 0}, activeBlock: { value: null } };
    return f;
}]);

constructorApp.directive('timeline', ['$compile', 'tl', '$timeout', 'globalMenuAPI', function($compile, tl, $timeout, globalMenuAPI) {
    return {
        restrict: 'A',
        scope: {
            timeline: '=',
            activeBlock: '='
        },
        template:   '<div class="tl-time-scale" time-scale="timeline.slideOptions[3].value"></div>' +
                    '<div class="tl-container">' +
                        '<div class="tl-wrapper">' +
                            '<div class="tl-wrapper-without-scroll">' +
                                '<div class="tl-content" timeline-content="timeline"></div>' +
                            '</div>' +
                        '</div>' +
                    '</div>',
        link: function(scope, element, attrs) {
            var el = false,
                lastScale,
                watchers = [],
                calcMaxScale = function(index, calc) {
                    var last = 0,
                        scale = parseInt(scope.timeline.slideOptions[3].value),
                        calcBlock = function(b) {
                            var tmp = 0,
                                leftD = 0,
                                leftS = 0,
                                rightD = 0,
                                rightS = 0;

                            if ('fixed' !== b.options[3].value) {
                                leftD = parseInt(b.options[6].value);
                                leftS = parseInt(b.options[4].value);
                            }
                            if ('fixed' !== b.options[9].value) {
                                rightD = parseInt(b.options[15].value);
                                rightS = parseInt(b.options[10].value);
                            }

                            tmp += leftD;
                            tmp += leftS;

                            if (tmp < rightD) {
                                if (rightD) {
                                    tmp = rightD;
                                }
                            }

                            tmp += rightS;

                            if (last < tmp) last = tmp;
                        };

                    if (undefined === index) {
                        angular.forEach(scope.timeline.blocks, function(b) {
                            calcBlock(b);
                        });
                    } else {
                        calcBlock(scope.timeline.blocks[index]);
                        if (scale < lastScale) {
                            scale = lastScale;
                        }
                    }

                    if (last > scale) {
                        scale = last;
                    }

                    lastScale = scale;
                    tl.maxScale.value = scale;
                    
                    scope.$broadcast('drawCanvas', {scale: lastScale});
                };

            watchers.push(scope.$watch('timeline.index', function(nv) {
                if (undefined !== nv) {
                    el = true;
                    lastScale && (lastScale = parseInt(scope.timeline.slideOptions[3].value));
                    tl.maxScale.value && (tl.maxScale.value = parseInt(scope.timeline.slideOptions[3].value));

                    $timeout(function() {
                        scope.$broadcast('drawCanvas', {scale: lastScale});
                    }, 0);
                }
            }));

            watchers.push(scope.$on('tlRecalcCanvas', function(e) {
                e.stopPropagation();
                if (el) {
                    calcMaxScale();
                    scope.$broadcast('tlRecalcAll');
                }
            }));

            watchers.push(scope.$watch('timeline.slideOptions[3].value', function(nv, ov) {
                if (undefined !== nv && el && nv !== ov) {
                    calcMaxScale(undefined, true);
                    scope.$broadcast('tlRecalcAll');
                }
            }));

            watchers.push(scope.$watch('activeBlock', function(nv, ov) {
                tl.activeBlock.value = nv;
            }));

            element.bind('mousedown', function() {
                globalMenuAPI.close();
            });

            element.bind('$destroy', function() {
                element.unbind('mousedown');
                angular.forEach(watchers, function(watcher) {
                    watcher();
                });
                watchers = [];
                scope.$destroy();
            });
        }
    };
}]);

constructorApp.directive('timeScale', ['tl', function(tl) {
    var getStep = function(allScale /* ms */, containerWidth, font) {
        var i, s, result, step, lastStep,
            steps = [100, 200, 500],
            coefficient = 1,
            textWidth, text = "00000",
            canvas = angular.element('<canvas>'),
            context = canvas[0].getContext('2d');

        if (!allScale || !containerWidth) return 100;

        context.font = font || "10px Arial";
        context.textAlign = 'center';
        context.fillStyle = 'back';
        context.fillText(text, canvas[0].width / 2, canvas[0].height / 2);

        textWidth = context.measureText(text).width;
        lastStep = steps[0];

        while (!result) {
            for (i = 0; i < steps.length; i++) {
                step = steps[i] * coefficient;
                s = allScale / step;
                s *= textWidth;

                if (s <= containerWidth) {
                    result = step;
                    break;
                }
                lastStep = step;
            }
            coefficient *= 10;
        }

        return result;
    };
    return {
        restrict: 'A',
        scope: {
            timeScale: '='
        },
        link: function(scope, element, attrs) {
            var slideId = attrs.slideId,
                font = "10px Arial",
                watchers = [],
                leftPadding = 5,
                canvas = angular.element('<canvas>'),
                context = canvas[0].getContext('2d'),
                draw = function(ts) {
                    var lineSize, step, p, pos, ms, stepPos,
                        sts = parseInt(scope.timeScale),
                        sum = ts || sts, tmp,

                        // width = scope.width.value || element[0].offsetWidth,
                        width = element[0].offsetWidth,
                        height = element[0].offsetHeight,

                        scaleWidth = scope.width.value + leftPadding,

                        round = function(value) {
                            value = value / 10;
                            value = Math.round(value);
                            value /= 100;
                            return value;
                        };

                    canvas[0].width = width;
                    canvas[0].height = height;

                    context.clearRect(0, 0, canvas.width, canvas.height);

                    step = getStep(ts, scaleWidth - leftPadding, font);

                    if (ts > sts) {
                        context.fillStyle = '#bebebe';
                        tmp = sts / ts * (scaleWidth - leftPadding);
                        context.fillRect(tmp + leftPadding, 0, width - tmp, height);
                        context.fillStyle = 'black';
                    }

                    stepPos = step / sum * (scaleWidth - leftPadding);
                    pos = leftPadding;
                    ms = 0;

                    context.beginPath();
                    context.moveTo(0, height);
                    context.lineTo(width, height);
                    context.stroke();
                    context.closePath();

                    while(pos < scaleWidth) {
                        if (ms &&  ms % 1000 === 0 ) {
                            lineSize = 8;
                        } else {
                            lineSize = 5;
                        }

                        p = Math.floor(pos) + 0.5;

                        context.beginPath();
                        context.moveTo(p, height);
                        context.lineTo(p, height - lineSize);
                        context.stroke();
                        context.closePath();

                        
                        context.font = font;
                        context.lineWidth = 1;

                        context.textAlign = "center";

                        context.fillText(round(ms) + 's', p , height - 12);

                        pos += stepPos;
                        ms += step;


                        if (pos >= scaleWidth && pos - scaleWidth <= 0.5) {
                            pos = scaleWidth - 0.5;
                        }
                    }
                };

            scope.width = tl.width;

            watchers.push(scope.$on('drawCanvas', function(e, data) {
                draw(data.scale);
            }));

            element.bind('$destroy', function() {
                angular.forEach(watchers, function(watcher) {
                    watcher();
                });
                watchers = [];
                scope.$destroy();
            });

            element.append(canvas[0]);
        }
    };
}]);

constructorApp.directive('timelineContent', ['$compile', 'tl', '$window', '$timeout', function($compile, tl, $window, $timeout) {
    return {
        restrict: 'A',
        scope: {
            timelineContent: '='
        },
        link: function(scope, element, attrs) {
            var timer = null,
                line = angular.element('<div class="tl-line" ng-repeat="block in timelineContent.blocks | timing" timeline-item="block"></div>'),
                resize = function() {
                    $timeout.cancel(timer);
                    $timeout(function() {
                        tl.width.value = element[0].offsetWidth;
                        scope.$emit('tlRecalcCanvas');
                    }, 100);
                };

            element.append(line[0]);
            tl.width.value = element[0].offsetWidth;

            angular.element($window).bind('resize', resize);

            element.bind('$destroy', function() {
                angular.element($window).unbind('resize', resize);
                scope.$destroy();
            });
            
            $compile(element.contents())(scope);
        }
    };
}]);

constructorApp.directive('timelineItem', ['$compile', 'tl', 'globalMenuAPI', function($compile, tl, globalMenuAPI) {
    return {
        restrict: 'A',
        scope: {
            timelineItem: '='
        },
        link: function(scope, element, attrs) {
            var minSpeed = 50,
                stock = 3,
                watchers = [],
                line = angular.element('<div class="tl-line-scale"></div>'),

                leftLine = angular.element('<div class="tl-control-line tl-control-line-left" ' +
                                                'ng-show="leftIsShow" ' +
                                                'min="0" ' +
                                                'max="max" ' +
                                                'delay="timelineItem.options[6].value" ' +
                                                'speed="timelineItem.options[4].value" ' +
                                                'is-mouse-doown="isMouseDown" ' +
                                                'tl-control-line="left"></div>'),

                centerLine = angular.element('<div ng-show="centerIsShow" class="tl-control-line tl-center-line"></div>'),

                rightLine = angular.element('<div class="tl-control-line tl-control-line-right" ' +
                                                'ng-show="rightIsShow" ' +
                                                'min="min" ' +
                                                'max="slideSpeed.value" ' +
                                                'delay="timelineItem.options[15].value" ' +
                                                'speed="timelineItem.options[10].value" ' +
                                                'is-mouse-doown="isMouseDown" ' +
                                                'tl-control-line="right"></div>'),

                calcMinMax = function() {
                    var leftd = parseInt(scope.timelineItem.options[6].value),
                        lefts = parseInt(scope.timelineItem.options[4].value),
                        rightd = parseInt(scope.timelineItem.options[15].value);

                    scope.min = scope.leftIsShow ? (leftd + lefts) : 0;

                    if (scope.rightIsShow) {
                        scope.max = (leftd + lefts > rightd) ? leftd + lefts : rightd;
                    } else {
                        scope.max = tl.maxScale.value;
                    }
                },

                getMinMax = function() {
                    return {
                        left: {
                            min: 0,
                            max: scope.max
                        },
                        right: {
                            min: scope.min,
                            max: tl.maxScale.value
                        }
                    };
                },

                calcWidthCenterLine = function() {
                    var width, l, w;
                    if (scope.leftIsShow && scope.rightIsShow) {
                        width = element[0].offsetWidth;

                        w = (scope.max - scope.min) / tl.maxScale.value * width;
                        w += (stock*2);
                        l = scope.min / tl.maxScale.value * width;
                        l -= stock;
                        centerLine.css({ 'left': l + 'px', 'width': w + 'px' });
                    }
                },

                mouseDown = function(e) {
                    var ind = scope.timelineItem.index;
                    scope.$apply(function() { tl.activeBlock.value = ind; });
                    scope.$emit('timelineSetActiveBlock', { index: ind });
                };

            scope.leftIsShow = false;
            scope.rightIsShow = false;
            scope.centerIsShow = false;
            scope.isMouseDown = false;
            scope.activeBlock = tl.activeBlock;
            scope.slideSpeed = tl.maxScale;

            calcMinMax();

            line.append(leftLine[0]);
            line.append(centerLine[0]);
            line.append(rightLine[0]);
            
            element.append(line[0]);


            watchers.push(scope.$watch('timelineItem.options[3].value', function(nv) {
                scope.leftIsShow = 'fixed' !== nv;
                if (scope.rightIsShow) {
                    calcMinMax();
                    if (parseInt(scope.timelineItem.options[15].value) < parseInt(scope.timelineItem.options[6].value) + parseInt(scope.timelineItem.options[4].value)) {
                        scope.$emit('tlRecalcCanvas');
                    } else {
                        scope.$broadcast('tlRecalcLines', getMinMax());
                    }
                }
                scope.centerIsShow = scope.leftIsShow && scope.rightIsShow;
            }));

            watchers.push(scope.$watch('timelineItem.options[9].value', function(nv) {
                scope.rightIsShow = 'fixed' !== nv;
                if (scope.rightIsShow) {
                    calcMinMax();
                    if (scope.leftIsShow && scope.min + parseInt(scope.timelineItem.options[10].value) > tl.maxScale.value) {
                        scope.$emit('tlRecalcCanvas');
                    } else {
                        scope.$broadcast('tlRecalcLines', getMinMax());
                    }
                }
                scope.centerIsShow = scope.leftIsShow && scope.rightIsShow;
            }));

            watchers.push(scope.$watch('timelineItem.options[15].value', function(nv) {
                if (scope.rightIsShow) {
                    if (!scope.isMouseDown) {
                        scope.$emit('tlRecalcCanvas');
                    } else {
                        calcMinMax();
                        calcWidthCenterLine();
                        scope.$broadcast('tlRecalcMinMax', getMinMax());
                    }
                }
            }));

            watchers.push(scope.$watch('timelineItem.options[10].value', function(nv) {
                if (scope.rightIsShow) {
                    if (!scope.isMouseDown) {
                        scope.$emit('tlRecalcCanvas');
                    }
                }
            }));

            watchers.push(scope.$watchGroup(['timelineItem.options[6].value', 'timelineItem.options[4].value'], function(nv) {
                if (scope.leftIsShow) {
                    if (!scope.isMouseDown) {
                        scope.$emit('tlRecalcCanvas');
                    } else {
                        calcMinMax();
                        calcWidthCenterLine();
                        scope.$broadcast('tlRecalcMinMax', getMinMax());
                    }
                }
                calcWidthCenterLine();
            }));

            watchers.push(scope.$on('tlRecalcAll', function(e, data) {
                if (scope.leftIsShow && scope.rightIsShow) {
                    var ld = parseInt(scope.timelineItem.options[6].value),
                        ls = parseInt(scope.timelineItem.options[4].value),
                        rd = parseInt(scope.timelineItem.options[15].value);

                    if (ld + ls > rd) {
                        scope.timelineItem.options[15].value = ld + ls;
                    }
                }

                calcMinMax();
                calcWidthCenterLine();
                scope.$broadcast('tlRecalcLines', getMinMax());
            }));


            watchers.push(scope.$watch(scope.leftIsShow, function(nv) {
                if (undefined !== nv) calcMinMax();
            }));

            watchers.push(scope.$watch(scope.rightIsShow, function(nv) {
                if (undefined !== nv) calcMinMax();
            }));

            element.bind('mousedown', mouseDown);
            watchers.push(scope.$on('timelineMouseDown', function(e) {
                e.stopPropagation();
                mouseDown();
                globalMenuAPI.close();
            }));

            watchers.push(scope.$watch('activeBlock.value', function(nv, ov) {
                if (scope.timelineItem.index === nv) {
                    element.addClass('active');
                } else {
                    element.removeClass('active');
                }
            }));

            element.bind('$destroy', function() {
                angular.forEach(watchers, function(watcher) {
                    watcher();
                });
                element.unbind('mousedown', mouseDown);
                watchers = [];
                scope.$destroy();
            });

            $compile(element.contents())(scope);
        }
    };
}]);

constructorApp.directive('tlControlLine', ['lib', '$document', 'tl',  function(lib, $document, tl) {
    return {
        restrict: 'A',
        scope: {
            delay: '=',
            speed: '=',
            min: '=',
            max: '=',
            isMouseDoown: '='
        },
        link: function(scope, element, attrs) {
            var wrapper = angular.element('<div class="tl-control-line-wrapper"></div>'),
                leftControl = angular.element('<div class="tl-mouse-control-left"></div>'),
                rightControl = angular.element('<div class="tl-mouse-control-right"></div>'),
                events = [],

                mainContainer = element.parent().parent().parent().parent().parent().parent().parent().parent().parent(),

                left, right, width, elPos, elCorrect, min, max,
                minWidth,
                containerWidth = element.parent()[0].offsetWidth,
                containerPos = 0,

                curentEvent = '',
                moves = {
                    elementMove: function(e) {
                        if (1 === e.which) {
                            e.stopPropagation();
                          
                            left = (e.pageX - containerPos) - elPos;

                            if (left < min) {
                                left = min;
                            } else if (left + width > max) {
                                left = max - width;
                            }

                            right = left + width;

                            setCss(left, width);
                            calcDS(true);
                        }
                    },
                    leftControlMove: function(e) {
                        if (1 === e.which) {
                            var oldLeft = left;
                            e.stopPropagation();

                            left = (e.pageX - containerPos) - elPos;

                            if (left < min) {
                                left = min;
                            }

                            width += (oldLeft - left);

                            if (minWidth > width) {
                                width = minWidth;
                                left = right - minWidth;
                            }
                            
                            setCss(left, width);
                            calcDS(true);
                        }
                    },
                    rightControlMove: function(e) {
                        if (1 === e.which) {
                            e.stopPropagation();
                            var pos = (e.pageX - containerPos) + elCorrect;
                            width = pos - left;

                            if (width < minWidth) {
                                width = minWidth;
                            } else if (left + width > max) {
                                width = max - left;
                            }

                            right = left + width;

                            setCss(left, width);
                            calcDS(true);
                            scope.$apply();
                        }
                    }
                },

                mouseUp = function(e) {
                    if (1 === e.which) {
                        e.stopPropagation();

                        $document.unbind('mousemove', moves[curentEvent]);
                        $document.unbind('mouseup', mouseUp);
                        mainContainer.removeClass('col-move');
                        element.removeClass('col-move');
                        scope.$apply(function() {
                            scope.isMouseDoown = false;
                        });
                    }
                },

                setCss = function(l, w) {
                    element.css({ 'left': l + 'px', 'width': w  + 'px'});
                },

                calcDS = function(apply) {
                    var f = function() {
                        scope.delay = Math.round(left / containerWidth * tl.maxScale.value);
                        scope.speed = Math.round(width / containerWidth * tl.maxScale.value);
                    };

                    // console.log(scope.$$phase);
                    // console.log(scope.$parent.$parent.$parent.$parent.$parent.$$phase);
                    // console.log(scope.$parent.$parent.$parent.$parent.$parent.$parent.$$phase);

                    if (!scope.$$phase && apply) {
                        scope.$apply(function() { f(); });
                    } else {
                        f();
                    }
                },

                calcLeft = function() {
                    return scope.delay / tl.maxScale.value * containerWidth;
                },

                calcWidth = function() {
                    return scope.speed / tl.maxScale.value * containerWidth;
                },

                calcMin = function() { // ms to px
                    var result = 0;
                    if (scope.min) {
                        result = scope.min / tl.maxScale.value * containerWidth;
                    }
                    return result;
                },

                calcMax = function() { // ms to px
                    var result;
                    if (scope.max) {
                        result = scope.max / tl.maxScale.value * containerWidth;
                    } else {
                        result = containerWidth;
                    }
                    return result;
                },

                calcMinWidth = function() {
                    var minMs = 50;
                    minWidth = minMs / tl.maxScale.value * containerWidth;
                },

                recalc = function() {
                    if (!scope.isMouseDown) {
                        containerWidth = element.parent()[0].offsetWidth,
                        min = calcMin();
                        max = calcMax();

                        left = calcLeft();
                        width = calcWidth();

                        if (left < min) {
                            left = min;
                        }

                        if (left + width > max) {
                            width = Math.abs(max - left);
                        }

                        right = left + width;

                        // calcDS();
                        setCss(left, width);
                    }
                },

                elMouseDown = function(e) {
                    if (1 === e.which) {
                        defaultEvents(e);
                        element.addClass('col-move');
                        curentEvent = 'elementMove';
                        containerPos = lib.obj.positX(element.parent()[0]);
                        elPos = e.pageX - lib.obj.positX(element[0]);
                        addingEvents();
                    }
                },

                lMouseDown = function(e) {
                    if (1 === e.which) {
                        defaultEvents(e);
                        curentEvent = 'leftControlMove';
                        containerPos = lib.obj.positX(element.parent()[0]);
                        elPos = e.pageX - lib.obj.positX(element[0]);
                        addingEvents();
                    }
                },

                rMouseDown = function(e) {
                    var halfSize;
                    if (1 === e.which) {
                        defaultEvents(e);
                        curentEvent = 'rightControlMove';

                        containerPos = lib.obj.positX(element.parent()[0]);
                        halfSize = rightControl[0].offsetWidth / 2;
                        elCorrect = e.offsetX;

                        if (e.offsetX > halfSize) {
                            elCorrect = halfSize - e.offsetX;
                            elCorrect -= 1;
                        } else {
                            elCorrect = halfSize - e.offsetX;
                        }

                        addingEvents();
                    }
                },

                defaultEvents = function(e) {
                    e.stopPropagation();
                    scope.isMouseDoown = true;
                    mainContainer.addClass('col-move');
                    scope.$emit('timelineMouseDown');
                },

                addingEvents = function() {
                    $document.bind('mousemove', moves[curentEvent]);
                    $document.bind('mouseup', mouseUp);
                };

            calcMinWidth();

            left = calcLeft();
            width = calcWidth();
            right = left + width;

            setCss(left, width);

            element.bind('mousedown', elMouseDown);
            leftControl.bind('mousedown', lMouseDown);
            rightControl.bind('mousedown', rMouseDown);

            events.push(scope.$on('tlRecalcMinMax', function(e, data) {
                scope.min = data[attrs.tlControlLine].min;
                scope.max = data[attrs.tlControlLine].max;
                min = calcMin();
                max = calcMax();
            }));

            events.push(scope.$on('tlRecalcLines', function(e, data) {
                scope.min = data[attrs.tlControlLine].min;
                scope.max = data[attrs.tlControlLine].max;
                recalc();
            }));

            events.push(scope.$watchGroup(['delay', 'speed'], function(nv) {
                recalc();
            }));

            wrapper.append(leftControl[0]);
            wrapper.append(angular.element('<div class="tl-stick-left"></div>')[0]);
            wrapper.append(angular.element('<div class="tl-stick-right"></div>')[0]);
            wrapper.append(rightControl[0]);
            element.append(wrapper[0]);

            element.bind('$destroy', function() {
                angular.forEach(events, function(ev) {
                    ev();
                });
                element.unbind('mousedown', elMouseDown);
                leftControl.unbind('mousedown', lMouseDown);
                rightControl.unbind('mousedown', rMouseDown);
                events = [];
                scope.$destroy();
            });
        }
    };
}]);
'use strict';

constructorApp.directive('lbOneBlock', ['$compile', function($compile) {
    return {
        restrict: 'A',
        scope: {
            lbOneBlock: '='
        },
        link: function(scope, element, attrs) {
            element.bind('click', function(e) {
                e.preventDefault();
                scope.$emit('timelineSetActiveBlock', { index: scope.lbOneBlock.index });
            });

            element.bind('mouseover', function(e) {
                e.preventDefault();
                angular.element(scope.lbOneBlock.node).addClass('over');
                angular.element(scope.lbOneBlock.outline).addClass('over');
            });

            element.bind('mouseout', function(e) {
                e.preventDefault();
                angular.element(scope.lbOneBlock.node).removeClass('over');
                angular.element(scope.lbOneBlock.outline).removeClass('over');
            });
            
            element.bind('$destroy', function() {
                element.unbind('click');
                element.unbind('mouseover');
                element.unbind('mouseout');
                scope.$destroy();
            });
        }
    };
}]);'use strict';

constructorApp.directive('controlPanelBlocks', ['$compile', '$document', '$rootScope', function($compile, $document, $rootScope) {
    return {
        restrict: 'A',
        scope: {
            controlPanelBlocks: '='
        },
        link: function(scope, element, attrs) {
            var kd = function(e) {
                    // 8 === e.keyCode - backspace; we need to remove text from text editor
                    if (46 === e.keyCode && !$rootScope.globalMenuIsOpen && !$rootScope.colorPickerOpened && !$rootScope.newItemWindowIsOpened &&
                        !($document[0].activeElement && $document[0].activeElement.tagName && 'input' === $document[0].activeElement.tagName.toLowerCase())) {
                        e.preventDefault();
                        e.stopPropagation();
                        if (scope.controlPanelBlocks.blocks.length > 0) {
                            scope.$emit('controlPanelBlocksEvent', { type: 'remove' });
                        }
                    }
                },

                imgButton = angular.element(document.querySelector('#control-button-add-new-image')),
                videoButton = angular.element(document.querySelector('#control-button-add-new-video')),
                textButton = angular.element(document.querySelector('#control-button-add-new-text')),
                buttonButton = angular.element(document.querySelector('#control-button-add-new-button')),
                shapeButton = angular.element(document.querySelector('#control-button-add-new-shape')),
                removeButton = angular.element(document.querySelector('#control-button-remove-block'));

            imgButton.attr('block-type', 'img');
            imgButton.attr('new-item', '');

            videoButton.attr('block-type', 'video');
            videoButton.attr('new-item', '');

            textButton.bind('click', function(e) {
                scope.$emit('controlPanelBlocksEvent', { type: 'createNewBlock', blockType: 'text' });
            });

            buttonButton.bind('click', function(e) {
                scope.$emit('controlPanelBlocksEvent', { type: 'createNewBlock', blockType: 'button' });
            });

            shapeButton.bind('click', function(e) {
                scope.$emit('controlPanelBlocksEvent', { type: 'createNewBlock', blockType: 'shape' });
            });

            removeButton.bind('click', function() {
                if (scope.controlPanelBlocks.blocks.length > 0) {
                    scope.$emit('controlPanelBlocksEvent', { type: 'remove' });
                }
            });

            $document.bind('keydown', kd);

            $compile(element.contents())(scope);
            element.bind('$destroy', function() {
                $document.unbind('keydown', kd);
                textButton.unbind('click');
                buttonButton.unbind('click');
                shapeButton.unbind('click');
                removeButton.unbind('click');
                scope.$destroy();
            });
        }
    };
}]);

constructorApp.directive('newItem', ['$document', '$compile', '$timeout', '$window', 'parseSlide', '$rootScope', 'messages', function($document, $compile, $timeout, $window, parseSlide, $rootScope, messages) {
    return {
        restrict: 'A',
        scope: {},
        link: function(scope, element, attrs) {
            var bg,
                watchers = [],
                bgField,

                addImg = function(url, base64, name) {
                    var _imgId = null;
                    if (angular.isObject(url)) {
                        _imgId = url.imgId;
                        url = url.url;
                    }
                    scope.$emit('controlPanelBlocksEvent', {
                        type: 'createNewBlock',
                        blockType: 'image',
                        url: url,
                        imgId: _imgId,
                        name: name,
                        base64: base64,
                        full: bg
                    });
                },

                addVideo = function(videoType, url, isnocookie) {
                    scope.$emit('controlPanelBlocksEvent', {
                        type: 'createNewBlock',
                        blockType: 'video',
                        videoType: videoType,
                        isnocookie: isnocookie,
                        url: url
                    });
                };

            if (messages.status) {
                messages.setCallbacks({
                    getImg: function(data) {
                        $rootScope.newItemWindowIsOpened = false;
                        addImg(data, null);
                    },
                    getImg_fail: function(data) {
                        $rootScope.newItemWindowIsOpened = false;
                    },
                    getVideo: function(data) {},
                    getVideo_fail: function(data) {}
                });
            }

            element.bind('click', function(e) {
                var activeClass = 'active',
                    lastTabButton, tabs,
                    field, content, title,
                    firstTab, secondTab,
                    img, inp, drop, insert, transform,
                    videoContainer,
                    regexpYoutube = /(?:(youtube|youtube-nocookie)\.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu\.be\/)([^"&?\/ ]{11})/i,
                    regexpVimeo = /vimeo.com\/(.+)/;

                bg = !!angular.element(e.target).attr('bg');
                $rootScope.newItemWindowIsOpened = true;

                if (messages.status && attrs.blockType === 'img') {
                    messages.getImg();
                    return;
                }

                if (attrs.blockType === 'img') {

                    firstTab = 'Uploading';
                    secondTab = 'Insert URL';
                    title = 'Insert image';

                    content =   '<div class="c-content-img">' +
                                    '<div id="c-drop" class="c-upload" ng-show="0==tabIndex">' +
                                        '<span class="c-drop-container">' +
                                            'Drag and drop image upload<br>' +
                                            'or<br>' +
                                            '<button id="c-upload-button" class="btn btn-primary">Chose image for upload</button>' +
                                        '</span>' +
                                        '<input id="c-upload-input" type="file" accept="image/jpg,image/jpeg,image/png,image/gif" multiple="false">' +
                                    '</div>' +
                                    '<div class="c-insertUrl" ng-show="1==tabIndex">' +
                                        '<div class="c-display-url">' +
                                            '<form class="form-horizontal">' +
                                                '<div class="form-group">' +
                                                    '<label for="c-img-url" class="col-sm-3 control-label">Insert a link to the image</label>' +
                                                    '<div class="col-sm-7">' +
                                                        '<input class="form-control" ng-model="imgUrl" id="c-img-url" type="text">' +
                                                    '</div>' +
                                                    '<div class="col-sm-2">' +
                                                        '<div ng-show="loaderIsShow" class="loader spinner">' +
                                                            '<div class="rect rect1"></div>' +
                                                            '<div class="rect rect2"></div>' +
                                                            '<div class="rect rect3"></div>' +
                                                            '<div class="rect rect4"></div>' +
                                                        '</div>' +
                                                    '</div>' +
                                                '</div>' +
                                            '</form>' +
                                        '</div>' +
                                        '<div class="c-display-img">' +
                                            '<image ng-show="imgIsShow" id="c-img" ng-src="{{imgUrl}}">' +
                                            '<span  ng-show="!imgIsShow">Сan not upload the image</span>' +
                                        '</div>' +
                                    '</div>' +
                                '</div>';
                } else {
                    firstTab = 'YouTube';
                    secondTab = 'Vimeo';
                    title = 'Insert video';

                    content =   '<div class="c-content-video">' +
                                    '<div class="c-insertUrl">' +
                                        '<div class="c-display-url">' +
                                            '<form class="form-horizontal">' +
                                                '<div class="form-group">' +
                                                    '<label for="c-video-url" class="col-sm-3 control-label">Insert a link to the {{name}} video</label>' +
                                                    '<div class="col-sm-7">' +
                                                        // '<input class="form-control" ng-model="videoUrl" id="c-video-url" type="text" placeholder="html or url or ID">' +
                                                        '<input class="form-control" ng-model="videoUrl" id="c-video-url" type="text">' +
                                                    '</div>' +
                                                    '<div class="col-sm-2">' +
                                                        '<div ng-show="loaderIsShow" class="loader spinner">' +
                                                            '<div class="rect rect1"></div>' +
                                                            '<div class="rect rect2"></div>' +
                                                            '<div class="rect rect3"></div>' +
                                                            '<div class="rect rect4"></div>' +
                                                        '</div>' +
                                                    '</div>' +
                                                '</div>' +
                                            '</form>' +
                                        '</div>' +
                                        '<div id="c-display-video" class="c-display-video">' +
                                            // '<image ng-show="imgIsShow" id="c-video" ng-src="{{imgUrl}}">' +
                                            // '<span  ng-show="!imgIsShow">Сan not upload the image</span>' +
                                        '</div>' +
                                    '</div>' +
                                '</div>';
                }

                scope.disableOk = false;
                scope.tabIndex = 0;
                scope.imgUrl = '';
                scope.loaderIsShow = false;
                scope.imgIsShow = true;
                scope.videoTitle = 'youtube';
                scope.name = 'YouTube';
                scope.videoUrl = '';
                scope.iframe = '';
                scope.videoID = '';

                field = angular.element(
                    '<div class="c-main-field">' +
                        '<div class="c-background-field"></div>' +
                        '<div class="c-working-field">' +
                            '<div id="c-top-field">' +
                                '<span class="c-title">' + title + '</span>' +
                                '<div id="c-tabs">' +
                                    '<button id="c-firstTab" class="active"><span>' + firstTab + '</span></button>' +
                                    '<button id="c-secondTab"><span>' + secondTab + '</span></button>' +
                                '</div>' +
                            '</div>' +
                            '<div id="c-center-field">' + content + '</div>' +
                            '<div id="c-bottom-field">' +
                                '<div class="c-controls">' +
                                    '<button id="c-ok" ng-disabled="!disableOk" class="btn btn-primary" ng-click="ok()">OK</button>' +
                                    '<button class="btn btn-default" ng-click="cansel()">Cancel</button>' +
                                '</div>' +
                            '</div>' +
                        '</div>' +
                    '</div>'
                );

                bgField = angular.element(field.children()[0])

                scope.cansel = function() {
                    $rootScope.newItemWindowIsOpened = false;
                    field.remove();
                };

                bgField.on('mousedown', function() {
                    scope.cansel();
                    return false;
                });

                scope.ok = function() {
                    if (attrs.blockType === 'img') {
                        addImg(scope.imgUrl, null);
                    } else {
                        addVideo(scope.videoTitle, scope.videoID, scope.isnocookie);
                    }
                    scope.cansel();
                };

                angular.element($document[0].body).append(field);
                $compile(field.contents())(scope);

                tabs = angular.element($document[0].getElementById('c-tabs')).find('button');
                lastTabButton = tabs[0];

                angular.forEach(tabs, function(b, i) {
                    angular.element(b).bind('click', function(e) {
                        var target = e.target;

                        while('button' !== target.tagName.toLowerCase()) {
                            target = target.parentNode;
                        }

                        if (lastTabButton !== target) {
                            angular.element(lastTabButton).removeClass(activeClass);
                            lastTabButton = target;
                            angular.element(lastTabButton).addClass(activeClass);

                            scope.$apply(function() {
                                scope.tabIndex = i;
                            });
                        }
                    });
                });

                if (attrs.blockType === 'img') {
                    img = angular.element($document[0].getElementById('c-img'));
                    img[0].onload = img[0].onerror = function(e) {
                        scope.$apply(function() {
                            scope.loaderIsShow = false;
                            scope.disableOk = e.type === 'load';
                            scope.imgIsShow = e.type === 'load';
                        });
                    };

                    watchers.push(scope.$watch('imgUrl', function(newValue) {
                        if (newValue && '' !== newValue) {
                            scope.loaderIsShow = true;
                            scope.imgIsShow = true;
                            scope.disableOk = false;
                        } else {
                            scope.loaderIsShow = false;
                            scope.imgIsShow = '' === newValue;
                            scope.disableOk = false;
                        }
                    }));


                    transform = function(file) {
                        // addImg(file.name, $window.URL.createObjectURL(file));

                        var reader = new $window.FileReader();
                        reader.onloadend = function(e) {
                            // addImg(file.name, e.target.result);
                            addImg($window.URL.createObjectURL(file), e.target.result, file.name);
                            scope.cansel();
                        };
                        reader.readAsDataURL(file);
                    };

                    inp = angular.element($document[0].getElementById('c-upload-input'));

                    inp.bind('change', function() {
                        if (inp[0].files[0]) {
                            transform(inp[0].files[0]);
                        }
                    });

                    angular.element($document[0].getElementById('c-upload-button')).bind('click', function(e) {
                        inp[0].click();
                        e.target.blur();
                    });

                    drop = angular.element($document[0].getElementById('c-drop'));

                    if ($window.File && $window.FileReader && $window.FileList && $window.Blob) {
                        drop.bind("dragenter", function(e) {
                            e.stopPropagation();
                            e.preventDefault();
                        });

                        drop.bind("dragover", function(e) {
                            e.stopPropagation();
                            e.preventDefault();
                        });

                        drop.bind('drop', function(e) {
                            if(!e.dataTransfer.files) {
                                return;
                            } else {
                                e.stopPropagation();
                                e.preventDefault();
                                transform(e.dataTransfer.files[0]);
                            }
                        });
                    }
                } else {
                    watchers.push(scope.$watch('tabIndex', function(v) {
                        scope.videoTitle = v ? 'vimeo' : 'youtube';
                        scope.name = v ? 'Vimeo' : 'YouTube';
                        scope.videoUrl = '';
                        scope.loaderIsShow = false;
                    }));

                    videoContainer = angular.element($document[0].getElementById('c-display-video'));

                    watchers.push(scope.$watch('videoUrl', function(newValue) {
                        var video, regexp, videoId = '', ev;
                        if (newValue && '' !== newValue) {
                            ev = function(e) {
                                scope.$apply(function() {
                                    scope.loaderIsShow = false;
                                    scope.disableOk = e.type === 'load';
                                });
                            };
                            scope.loaderIsShow = true;
                            scope.disableOk = false;
                            regexp = ('youtube' === scope.videoTitle) ? regexpYoutube : regexpVimeo;

                            newValue = parseSlide.trim(newValue);

                            videoId = regexp.exec(newValue + '') || ['', 'youtube' === scope.videoTitle ? newValue : ('video/' + newValue)];

                            var isNocookie = false;
                            if (videoId.length > 0) {
                                if (!/<iframe.+iframe>/.test(newValue)) {
                                    if ('youtube' === scope.videoTitle) {
                                        isNocookie = videoId[1] === "youtube-nocookie";
                                        videoId = videoId[2];
                                        newValue = '<iframe width="560" height="315" src="https://www.youtube' + (isNocookie ? '-nocookie' : '') +'.com/embed/' + videoId + '" frameborder="0" allowfullscreen></iframe>';
                                    } else {
                                        videoId = videoId[1];
                                        if (!/video/.test(videoId)) {
                                            videoId = 'video/' + videoId;
                                        }
                                        newValue = '<iframe src="https://player.vimeo.com/' + videoId + '" width="500" height="281" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>';
                                    }
                                }

                                video = angular.element(newValue);
                                video.bind('load', ev);
                                video.bind('error', ev);

                                videoContainer[0].innerHTML = '';
                                videoContainer.append(video[0]);

                                if ('vimeo' === scope.videoTitle) {
                                    // videoId = /\/(\d+[\/]*)$/.exec(videoId)[1];
                                    // videoId = /\/([0-9]+)/.exec(videoId)[1];
                                    videoId = /\/([0-9]+)/.exec(videoId);
                                    if (videoId && videoId.length) {
                                        videoId = videoId[1];
                                    }
                                }

                                scope.videoID = videoId;
                                scope.isnocookie = isNocookie;
                            }
                        } else {
                            scope.loaderIsShow = false;
                            scope.disableOk = false;
                            videoContainer[0].innerHTML = '';
                            scope.videoID = '';
                            scope.isnocookie =  false;
                        }
                    }));

                    watchers.push(scope.$watch('iframe', function(newValue) {
                        if (newValue && '' !== newValue) {
                            videoContainer[0].innerHTML = scope.iframe;
                        }
                    }));
                }

                $timeout(function() {
                    scope.$apply();
                }, 0);
            });
            element.bind('$destroy', function() {
                angular.forEach(watchers, function(ev) {
                    ev();
                });
                watchers = [];
                bgField.off('mousedown');
                element.unbind('click');
                scope.$destroy();
            });
        }
    };
}]);
'use strict';

constructorApp.service('orderBlocksApi', [function() {
    var api = {
        getBlockIndex: function(desiredZIndex, allBlocks) {
            var i, b;
            for(i = 0; i < allBlocks.length; i++) {
                b = allBlocks[i];
                if (b.styles['z-index'] === desiredZIndex) {
                    return b;
                }
            }
            return null;
        },

        change: function(nextBlock, currentBlock) {
            var zIndex = currentBlock.styles['z-index'];
            currentBlock.styles['z-index'] = nextBlock.styles['z-index'];
            nextBlock.styles['z-index'] = zIndex;
        },

        sorting: function(arr, reverse) {
            var i, j, tmp;
            for (i = 0; i < arr.length; i++) {
                for (j = 1; j < arr.length; j++) {
                    if (arr[i].styles['z-index'] > arr[i].styles['z-index']) {
                        tmp = arr[i];
                        arr[i] = arr[j];
                        arr[j] = tmp;
                    }
                }
            }

            reverse && (arr = arr.reverse());

            return arr;
        },

        setDesiredZIndex: function(desiredZIndex, currentBlock, allBlocks) {
            var i, b, ci = currentBlock.styles['z-index'];

            if (ci !== desiredZIndex) {
                for (i = ci + 1; i <= desiredZIndex; i++) {
                    b = api.getBlockIndex(i, allBlocks);
                    b && api.change(b, currentBlock);
                }
            }
        },

        setFirstZIndex: function(currentBlock, allBlocks) {
            var i, b, ci = currentBlock.styles['z-index'];

            if (1 !== ci) {
                for (i = ci - 1; i > 0; i--) {
                    b = api.getBlockIndex(i, allBlocks);
                    b && api.change(b, currentBlock);
                }
            }
        }
    };
    return api;
}]);

constructorApp.directive('orderBlocks', ['$compile', 'orderBlocksApi', function($compile, orderBlocksApi) {
    return {
        restrict: 'A',
        scope: {
            orderBlocks: '=',
            currentBlock: '=',
            currentIndex: '='
        },
        link: function(scope, element, attrs) {
            var buttons = element.find('button'),
                oldIndexes_, watch,

                getBlocks = function(max) {
                    var i, j, b = [],
                        min = 0,
                        zIndex = scope.currentBlock.styles['z-index'];

                    if (scope.orderBlocks.backgroundBlock) {
                        min = 1;
                    }

                    oldIndexes_ = [];
                    angular.forEach(scope.orderBlocks.blocks, function(block, i) {
                        var zi = block.styles['z-index'];
                        oldIndexes_.push(zi);
                        if (scope.currentBlock.index !== block.index) {
                            if (max) {
                                if (zIndex < zi) {
                                    b.push(block);
                                }
                            } else {
                                if (zIndex > zi && zi > min) {
                                    b.push(block);
                                }
                            }
                        }
                    });

                    return orderBlocksApi.sorting(b, !max);
                },

                saveingAction = function() {
                    scope.$emit('orderBlocksEvent', { oldIndexes: oldIndexes_ });
                },

                oneStep = function(side /* forward, backward */, noSaveAction) {
                    var top = 'forward' === side,
                        bs = getBlocks(top),
                        l = bs.length,
                        dd = l < 2;

                    if (l == 0) return;

                    scope.$apply(function() {
                        orderBlocksApi.change(bs[0], scope.currentBlock);

                        scope.forwarDisabled = (dd && top);
                        scope.frontDisabled = (dd && top);
                        scope.backwarDisabled = (dd && !top);
                        scope.backDisabled = (dd && !top);
                        !noSaveAction && saveingAction();
                    });
                },

                stepToTheEnd = function(side /* forward, backward */, noSaveAction) {
                    var top = 'forward' === side;
                    angular.forEach(getBlocks(top), function(b) {
                        orderBlocksApi.change(b, scope.currentBlock);
                    });

                    scope.forwarDisabled  = top;
                    scope.frontDisabled = top;
                    scope.backwarDisabled = !top;
                    scope.backDisabled = !top;

                    (!scope.$$phase && !scope.$parent.$$phase) && scope.$apply();
                    !noSaveAction && saveingAction();
                },

                checkButtons = function() {
                    var bks = getBlocks(true);

                    if (bks.length < 1 && !scope.currentBlock.isBackground) {
                        scope.forwarDisabled  = true;
                        scope.frontDisabled = true;
                    } else {
                        scope.forwarDisabled  = false;
                        scope.frontDisabled = false;
                    }

                    bks = getBlocks();

                    if (bks.length < 1 && !scope.currentBlock.isBackground) {
                        scope.backwarDisabled = true;
                        scope.backDisabled = true;
                    } else {
                        scope.backwarDisabled = false;
                        scope.backDisabled = false;
                    }
                };

            scope.forwarDisabled = false;
            scope.backwarDisabled = false;
            scope.frontDisabled = false;
            scope.backDisabled = false;

            watch = scope.$watch('currentIndex', function(nv, ov) {
                checkButtons();
            });

            scope.$on('checkButtonsEvent', function() {
                checkButtons();
            });

            angular.forEach(buttons, function(b, i) {
                b = angular.element(b);
                switch(i) {
                    case 0: // forward
                        b.attr('ng-disabled', 'forwarDisabled');
                        b.bind('click', function(e) { oneStep('forward'); });
                        break;
                    case 1: // backward
                        b.attr('ng-disabled', 'backwarDisabled');
                        b.bind('click', function(e) { oneStep('backward'); });
                        break;
                    case 2: // front
                        b.attr('ng-disabled', 'frontDisabled');
                        b.bind('click', function(e) { stepToTheEnd('forward'); });
                        break;
                    case 3: // back
                        b.attr('ng-disabled', 'backDisabled');
                        b.bind('click', function(e) { stepToTheEnd('backward'); });
                        break;
                };
            });

            $compile(element.contents())(scope);
            element.bind('$destroy', function() {
                watch();
                angular.forEach(buttons, function(b) {
                    angular.element(b).unbind('click');
                });
                scope.$destroy();
            });
        }
    };
}]);'use strict';

constructorApp.factory('globalMenuAPI', ['$rootScope', function($rootScope) {
    var open = false,
        element;
    return {
        open: function() {
            if (!open) {
                $rootScope.globalMenuIsOpen = true;
                open = true;
            }
        },
        close: function() {
            if (open) {
                $rootScope.globalMenuIsOpen = false;
                open = false;
            }
        },
        _set: function(el) {
            element = el;
        }
    };
}]);

constructorApp.directive('globalMenu', ['$rootScope', 'globalMenuAPI', function($rootScope, globalMenuAPI) {
    return {
        restrict: 'A',
        link: function(scope, element, attrs) {
            var open = false;
            scope.$on('openGlobalMenu', function() {
                if (!open) {
                    open = true;
                }
            });

            globalMenuAPI._set(element);

            scope.globalMenuClose = function() {
                globalMenuAPI.close();
            };

            element.bind('$destroy', function() {
                scope.$off('openGlobalMenu');
                scope.$off('closeGlobalMenu');
            });
        }
    };
}]);
'use strict';

constructorApp.directive('slideBgImage', ['$compile', function($compile) {
    return {
        restrict: 'A',
        scope: {
            slideBgImage: '='
        },
        template:   '<img src="">' +
                    '<figcaption>' +
                        '<div class="btn-group">' +
                            '<button class="btn btn-default" ng-disabled="setdd" new-item block-type="img" bg="true">Set</button>' +
                            '<button class="btn btn-default" ng-disabled="cleandd" ng-click="clean()">Сlean</button>' +
                        '</div>' +
                    '</figcaption>',
        link: function(scope, element, attrs) {
            var watch, img = element.find('img');

            scope.emptyImg = 'constructor/img/transparent2.jpg';
            scope.setdd = false;
            scope.cleandd = false;

            scope.clean = function() {
                scope.slideBgImage.backgroundBlock.isBackground = false;
                scope.$emit('timelineSetActiveBlock', {
                    index: scope.slideBgImage.backgroundBlock.index,
                    bg: true
                });
            };

            watch = scope.$watch('slideBgImage.backgroundBlock', function(nv) {
                if (nv) {
                    scope.cleandd = false;
                    scope.setdd = true;
                    img.attr('ng-src', '{{slideBgImage.backgroundBlock.url}}');
                    img.attr('title', 'Background-image');
                } else {
                    scope.cleandd = true;
                    scope.setdd = false;
                    img.attr('ng-src', '{{emptyImg}}');
                    img.attr('title', 'Empty');
                }
                $compile(img)(scope);
            });
            
            element.bind('$destroy', function() {
                watch();
                scope.$destroy();
            });
        }
    };
}]);'use strict';

constructorApp.directive('slideshowPreview', ['$compile', '$document', 'slideshowAPI', 'activeTab', '$rootScope', function($compile, $document, slideshowAPI, activeTab, $rootScope) {
    return {
        restrict: 'A',
        link: function(scope, element, attrs) {
            var container = angular.element($document[0].getElementById('slideshow-preview')),
                bClose = angular.element($document[0].getElementById('sp-close')),
                slideshow = angular.element($document[0].getElementById('slideshow')),
                events = ['-webkit-transitionend', 'transitionend'],
                firstStart = false,

                resizeContainer = slideshow.parent(),
                size = { width: 0, height: 0 },

                getSize = function() {
                    return {
                        width: resizeContainer.parent()[0].offsetWidth,
                        height: resizeContainer.parent()[0].offsetHeight
                    };
                },

                trEnd = function(e) {
                    container.unbind(e.type);
                    bClose.css('display', '');
                    slideshow.css('display', '');
                    if (scope.slides.length === 0 || scope.slides.length === 1 && scope.slides[0].blocks.length === 0) { return; }
                    setSlideshow();
                },

                getOptions = function() {
                    var i, opt = {};
                    for (i = 0; i < scope.slideshowOptions.length; i++) {
                        opt[scope.slideshowOptions[i].name] = scope.slideshowOptions[i].value;
                    }
                    return opt;
                },

                calcContainerSize = function() {
                    var width = parseInt(scope.slideshowOptions[2].value),
                        height = parseInt(scope.slideshowOptions[3].value),
                        opt = getOptions(),
                        value;

                    size = getSize();
                    value = size.width;

                    if (height / width * value > size.height) {
                        value = width / height * size.height;
                    }

                    if ('none' !== opt['selectors']) {
                        if ('thumbnails' === opt['selectors-style']) {
                            value = value - (width / height * (parseInt(opt['selectors-size']) + 16));
                        } else {
                            value -= (width / height *30);
                        }
                    }

                    resizeContainer.css('max-width', value + 'px');
                },

                getSlides = function() {
                    var arr = [],
                        slides = scope.slides,
                        oldSlideIndex = scope.slideEditor.cSlide;

                    angular.forEach(slides, function(s, i) {
                        arr.push(scope.saveSlide(i));
                    });

                    scope.slideEditor.cSlide = oldSlideIndex;
                    return arr;
                },

                setSlideshow = function() {
                    var opt = "", size = {'base-width': 0, 'base-height': 0}, v,
                        slides = getSlides();

                    // TODO
                    if (!firstStart) {
                        firstStart = true;
                        slideshowAPI.stop();
                    }

                    slideshow[0].innerHTML = '';

                    calcContainerSize();
                    angular.forEach(slides, function(slide, i) {
                        slideshow.append(slide);
                    });

                    size['base-width'] = scope.mainField[0].offsetWidth;
                    size['base-height'] = scope.mainField[0].offsetHeight;

                    angular.forEach(scope.slideshowOptions, function(o, i) {
                        // if (scope.defaults.slideshowOptions[i].value !== o.value || scope.defaults.slideshowOptions[i].name === 'base-width' || scope.defaults.slideshowOptions[i].name === 'base-height') {
                        //     if ('base-width' === o.name || 'base-height' === o.name) {
                        //         v = size[o.name];
                        //     } else {
                        //         v = o.value;
                        //     }
                        //
                        //     opt += (o.name + ': ' + v + '; ');
                        // }
                        opt += (o.name + ': ' + o.value + '; ');
                    });

                    slideshow.attr('data-options', opt);
                    slideshowAPI.start();
                    slideshow.addClass('sp-border');
                };

            bClose.css('display', 'none');
            slideshow.css('display', 'none');

            element.bind('click', function() {
                var cb = scope.slides[scope.slideEditor.cSlide].blocks[scope.slideEditor.cBlock];
                angular.forEach(events, function(ev) {
                    container.bind(ev, trEnd);
                });

                if (cb && 'text' === cb.type) {
                    angular.element(cb.node).addClass('transparent-select')
                        .removeClass('ta-border-shadow');

                    activeTab.currentTab.index = 0; // TODO
                }

                scope.$broadcast('activeBlockEvent', { index: null });
                scope.toggleBlocks(null);

                container.addClass('sp-show');
            });

            bClose.bind('click', function(e) {
                scope.activateSlide(0);
                bClose.css('display', 'none');
                slideshow.removeClass('sp-border');
                slideshowAPI.stop();
                slideshow.css('display', 'none');
                container.removeClass('sp-show');
            });

            element.bind('$destroy', function() {
                angular.forEach(events, function(ev) {
                    container.unbind(ev);
                });
                bClose.unbind('click');
                element.unbind('click');
            });
        }
    };
}]);
'use strict';

constructorApp.directive('mouseWheel', ['acpManager', 'globalMenuAPI', function(acpManager, globalMenuAPI) {
    return {
        restrict: 'A',
        scope: true,
        link: function(scope, element, attrs) {
            element.bind('wheel', function() {
                acpManager.close();
                globalMenuAPI.close();
            });

            element.bind('$destroy', function() {
                element.unbind('mousewheel');
                scope.$destroy();
            });
        }
    };
}]);'use strict';

constructorApp.directive('edtorZoom', ['lib', '$rootScope', '$timeout', '$window', function(lib, $rootScope, $timeout, $window) {
    var scaleRound = function(value, decimal) {
        var s = decimal || 4,
            num = 10 * s;
        value = value * num;
        value = Math.round(value);
        value /= num;
        return value;
    };
    return {
        restrict: 'A',
        scope: false,
        link: function(scope, element, attrs) {
            var inst = { scope: scope },
                firstStart = false,
                width, height,
                mainWidth, mainHeight,
                bWidthIndex, bHeightIndex,
                watchers = [],
                fitValue = null,
                zoomOut = angular.element(document.getElementById("control-button-lens-zoom-out")),
                zoomIn = angular.element(document.getElementById("control-button-lens-zoom-in")),

                setScale = function(scale) {
                    correctPosition(scale);
                    element.css({
                        '-webkit-transform': 'scale(' + scale + ')',
                        'transform': 'scale(' + scale + ')'
                    });
                },

                owerflow = function(auto) {
                    var el = angular.element($window.document.getElementById('working-field')),
                        value = auto ? '' : 'hidden';

                    el.css({'overflow': value});
                },

                setParentStyle = function(scale) {
                    var t = 0, l = 0,
                        w, h,
                        el = element.parent();

                    w = width * scale;
                    h = height * scale;

                    t = (mainHeight - h) / 2;
                    l = (mainWidth - w) / 2;
                    if (t < 0) {
                        t = 0;
                    }
                    if (l < 0) {
                        l = 0;
                    }

                    el.css({
                        'top': t + 'px',
                        'left': l + 'px',
                        'width': w + 'px',
                        'height': h + 'px'
                    });
                },

                newLabel = function(scale) {
                    var newArr = [], flag = false,
                        clearArr = JSON.parse(JSON.stringify(scope.$parent.zoomIconsDefault));

                    angular.forEach(clearArr, function(label) {
                        if (!flag && label.value >= scale) {
                            flag = true;
                            if (label.value !== scale) {
                                newArr.push({
                                    fit: true,
                                    value: scale,
                                    label: scaleRound(scale * 100, 1) + '% (Fit)'
                                });
                            } else {
                                label.fit = true;
                                label.label = label.label + ' (Fit)';
                            }
                        }

                        newArr.push(label);
                    });

                    if (!flag) {
                        newArr.push({
                            fit: true,
                            value: scale,
                            label: scaleRound(scale * 100, 1) + '% (Fit)'
                        });
                    }

                    scope.$parent.zoomIcons = newArr;

                    // scope.$parent.zoomIcons.unshift({});
                    // $timeout(function() {
                    //     scope.$parent.zoomIcons.shift();
                    // }, 0);
                },

                calcScale = function(dontInstall) {
                    var scale = 1;

                    if (mainWidth / mainHeight >= width / height) {
                        //h
                        scale = mainHeight / height;
                    } else {
                        //w
                        scale = mainWidth / width;
                    }

                    if (!dontInstall) {
                        fitValue = scale;
                        scope.$parent.zoomIcon = scale;
                        scope.zoomIcon = scale;
                        $rootScope.zoomIcon = scale;
                    }

                    newLabel(scale);

                    return scale;
                },

                getIndex = function(value) {
                    var i, result = 0,
                        icons = scope.$parent.zoomIcons;

                    for (i = 0; i < icons.length; i++) {
                        if (value === icons[i].value) {
                            result = i;
                            break;
                        }
                    }

                    return result;
                },

                correctPosition = function(scale) {
                    var top, left, el;

                    if (scale <= 1) {
                        scale -= 1;
                        top = height * scale / 2;
                        left = width * scale / 2;
                    } else {
                        top = (height * scale - height) / 2;
                        left = (width * scale - width) / 2;
                    }

                    scope.slideEditor.editorStyles['top'] = top + 'px';
                    scope.slideEditor.editorStyles['left'] = left + 'px';
                },

                setParameters = function(w, h) {
                    $rootScope.slideSize.width = w;
                    $rootScope.slideSize.height = h;

                    scope.slideEditor.editorStyles['width'] = w + 'px';
                    scope.slideEditor.editorStyles['height'] = h + 'px';

                    mainWidth = scope.mainField[0].offsetWidth;
                    mainHeight = scope.mainField[0].offsetHeight;
                },

                resize = function() {
                    var scale;
                    mainWidth = scope.mainField[0].offsetWidth;
                    mainHeight = scope.mainField[0].offsetHeight;
                    if (null === fitValue || fitValue === scope.$parent.zoomIcon) {
                        scale = calcScale();
                        scope.$parent.zoomIcon = scale;
                    } else {
                        fitValue = calcScale(true);
                        scale = scope.$parent.zoomIcon;
                    }
                    setParentStyle(scale);
                    setScale(scale);
                };

                zoomOut.on('click', function() {
                    var i, l = scope.$parent.zoomIcons.length;

                    for (i = 0; i < l; i++) {
                        if (scope.$parent.zoomIcons[i].value === scope.zoomIcon) {
                            if (i !== 0) {
                                var scale = scope.$parent.zoomIcons[i - 1].value;

                                scope.zoomIcon = scale;
                                $rootScope.zoomIcon = scale;
                                scope.$parent.zoomIcon = scale;

                                scope.$apply();
                            }
                            break;
                        }
                    }

                    return false;
                });

                zoomIn.on('click', function() {
                    var i, l = scope.$parent.zoomIcons.length;

                    for (i = 0; i < l; i++) {
                        if (scope.$parent.zoomIcons[i].value === scope.zoomIcon) {
                            if (i !== l - 1) {
                                var scale = scope.$parent.zoomIcons[i + 1].value;

                                scope.zoomIcon = scale;
                                $rootScope.zoomIcon = scale;
                                scope.$parent.zoomIcon = scale;

                                scope.$apply();
                            }
                            break;
                        }
                    }

                    return false;
                });

            scope.zoomOutDisable = false;
            scope.zoomInDisable = false;

            scope.$on('edtorZoomEvent', function(e, data) {
                var scale;

                if ('first-start' === data.type) {
                    firstStart = true;
                    bWidthIndex = lib.getOptionIndex(scope.slideshowOptions, 'base-width');
                    bHeightIndex = lib.getOptionIndex(scope.slideshowOptions, 'base-height');
                    width = parseFloat(scope.slideshowOptions[bWidthIndex].value);
                    height = parseFloat(scope.slideshowOptions[bHeightIndex].value);

                    setParameters(width, height);

                    scale = calcScale();
                    setParentStyle(scale);
                    setScale(scale);
                } else if ('resize' === data.type) {
                    // data.param
                    width = scope.slideshowOptions[bWidthIndex].value;
                    height = parseInt(data.param.height / data.param.width * width);

                    scope.slideshowOptions[bWidthIndex].value = width;
                    scope.slideshowOptions[bHeightIndex].value = height;

                    setParameters(width, height);

                    if (null === fitValue || fitValue === scope.$parent.zoomIcon) {
                        scale = calcScale();
                    } else {
                        calcScale(true);
                        scale = scope.$parent.zoomIcon;
                    }
                    setParentStyle(scale);
                    setScale(scale);

                    data.param.callback && data.param.callback();
                } else if ('control-line' === data.type) {
                    resize();
                }
            });

            watchers.push(scope.$watch('zoomIcon', function(newValue, oldValue) {
                var index;
                if (firstStart) {
                    newValue = parseFloat(newValue);
                    if (null === fitValue || fitValue === newValue) {
                        newValue = calcScale();
                        owerflow();
                    } else {
                        scope.$parent.zoomIcon = newValue;
                        $rootScope.zoomIcon = newValue;
                        owerflow('auto');
                    }

                    index = getIndex(newValue);
                    scope.zoomOutDisable = (index === 0);
                    scope.zoomInDisable = (index === scope.$parent.zoomIcons.length - 1);

                    setParentStyle(newValue);
                    setScale(newValue);
                }
            }));

            watchers.push(scope.$watch('zoomOutDisable', function(newValue, oldValue) {
                if (firstStart) {
                    if (newValue) {
                        zoomOut.attr('disabled', 'disable');
                    } else {
                        zoomOut.removeAttr('disabled', 'disable');
                    }
                }
            }));

            watchers.push(scope.$watch('zoomInDisable', function(newValue, oldValue) {
                if (firstStart) {
                    if (newValue) {
                        zoomIn.attr('disabled', 'disable');
                    } else {
                        zoomIn.removeAttr('disabled', 'disable');
                    }
                }
            }));

            angular.element($window).bind('resize', resize);

            element.bind('$destroy', function() {
                angular.element($window).unbind('resize', resize);
                angular.forEach(watchers, function(watcher) {
                    watcher();
                });
                zoomIn.off('click');
                zoomOut.off('click');
                watchers = [];
            });
        }
    };
}]);
'use strict';

constructorApp.service('saveSlideshow', ['$rootScope', 'messages', '$location', 'getHtmlSlideshow', function($rootScope, messages, $location, getHtmlSlideshow) {
    var cb;
    messages.setCallbacks({
        dataSaved: function(data) {
            if (null !== data.id && $rootScope.idSlideshow.id !== data.id) {
                $rootScope.idSlideshow.id = data.id;
                $location.path('/ss_l');
                $location.search({id: data.id});
            }
            cb(false);
        },
        dataSaved_fail: function() {
            cb(true);
        }
    });

    return function(scope, callback) {
        var params, ss = '', opt = '', id = '';
        ss = $rootScope.getSlideshowJSON();
        opt = ss.options || 'null';
        id = ss.id;
        ss = ss.slideshow || 'null';

        cb = callback;

        getHtmlSlideshow(scope, function(slideshowHTML) {
            var slideshow = JSON.stringify(slideshowHTML);
            $rootScope.oldSlideshow = slideshow;
            messages.save({
                id: id,
                data: {
                    json: '[' + ss + ',' + opt +']',
                    html: slideshow
                }
            });
        });
    }
}]);

constructorApp.directive('saveSlideshow', ['$location', '$rootScope', 'messages', 'getHtmlSlideshow', 'aInfobarManager', 'saveSlideshow', function($location, $rootScope, messages, getHtmlSlideshow, aInfobarManager, saveSlideshow) {
    return {
        restrict: 'A',
        scope: true,
        link: function(scope, element, attrs) {
            var url = $location.absUrl().replace(/index.php.*/, '');
            url = url.split($location.host() + '')[1];

            element.on('click', function() {
                element.addClass('loading');
                element.attr('disabled', 'disabled');

                saveSlideshow(scope, function(err) {
                    if (!err) {
                        aInfobarManager.showMessage('Slideshow saved.');
                    }

                    element.removeClass('loading');
                    element.removeAttr('disabled');
                });
            });

            element.on('$destroy', function() {
                element.off('click');
                scope.$destroy();
            });
        }
    };
}]);
/*  angular-summernote v0.8.1 | (c) 2016 JeongHoon Byun | MIT license */
/* global angular */
angular.module('summernote', []).controller('SummernoteController', ['$scope', '$attrs', '$timeout', function($scope, $attrs, $timeout) {
    'use strict';

    var currentElement,
        summernoteConfig = angular.copy($scope.summernoteConfig) || {};

    if (angular.isDefined($attrs.height))      { summernoteConfig.height = +$attrs.height;          }
    if (angular.isDefined($attrs.minHeight))   { summernoteConfig.minHeight = +$attrs.minHeight;    }
    if (angular.isDefined($attrs.maxHeight))   { summernoteConfig.maxHeight = +$attrs.maxHeight;    }
    if (angular.isDefined($attrs.placeholder)) { summernoteConfig.placeholder = $attrs.placeholder; }
    if (angular.isDefined($attrs.focus))       { summernoteConfig.focus = true;                     }
    if (angular.isDefined($attrs.airmode))     { summernoteConfig.airMode = true;                   }
    if (angular.isDefined($attrs.lang)) {
        if (!angular.isDefined($.summernote.lang[$attrs.lang])) {
            throw new Error('"' + $attrs.lang + '" lang file must be exist.');
        }
        summernoteConfig.lang = $attrs.lang;
    }

    summernoteConfig.callbacks = summernoteConfig.callbacks || {};

    if (angular.isDefined($attrs.onInit)) {
        summernoteConfig.callbacks.onInit = function(evt) {
            $scope.init({evt:evt});
        };
    }
    if (angular.isDefined($attrs.onEnter)) {
        summernoteConfig.callbacks.onEnter = function(evt) {
            $scope.enter({evt:evt});
        };
    }
    if (angular.isDefined($attrs.onFocus)) {
        summernoteConfig.callbacks.onFocus = function(evt) {
            $scope.focus({evt:evt});
        };
    }
    if (angular.isDefined($attrs.onPaste)) {
        summernoteConfig.callbacks.onPaste = function(evt) {
            $scope.paste({evt:evt});
        };
    }
    if (angular.isDefined($attrs.onKeyup)) {
        summernoteConfig.callbacks.onKeyup = function(evt) {
            $scope.keyup({evt:evt});
        };
    }
    if (angular.isDefined($attrs.onKeydown)) {
        summernoteConfig.callbacks.onKeydown = function(evt) {
            $scope.keydown({evt:evt});
        };
    }
    if (angular.isDefined($attrs.onImageUpload)) {
        summernoteConfig.callbacks.onImageUpload = function(files) {
            $scope.imageUpload({files:files, editable: $scope.editable});
        };
    }
    if (angular.isDefined($attrs.onMediaDelete)) {
        summernoteConfig.callbacks.onMediaDelete = function(target) {
            // make new object that has information of target to avoid error:isecdom
            var removedMedia = {attrs: {}};
            removedMedia.tagName = target[0].tagName;
            angular.forEach(target[0].attributes, function(attr) {
                removedMedia.attrs[attr.name] = attr.value;
            });
            $scope.mediaDelete({target: removedMedia});
        };
    }

    this.activate = function(scope, element, ngModel) {
        var updateNgModel = function() {
            var newValue = element.summernote('code');
            if (element.summernote('isEmpty')) { newValue = ''; }
            if (ngModel && ngModel.$viewValue !== newValue) {
                $timeout(function() {
                    ngModel.$setViewValue(newValue);
                }, 0);
            }
        };

        var originalOnChange = summernoteConfig.callbacks.onChange;
        summernoteConfig.callbacks.onChange = function (contents) {
            $timeout(function () {
                if (element.summernote('isEmpty')) {
                    contents = '';
                }
                updateNgModel();
            }, 0);
            if (angular.isDefined($attrs.onChange)) {
                $scope.change({contents: contents, editable: $scope.editable});
            } else if (angular.isFunction(originalOnChange)) {
                originalOnChange.apply(this, arguments);
            }
        };
        if (angular.isDefined($attrs.onBlur)) {
            summernoteConfig.callbacks.onBlur = function (evt) {
                (!summernoteConfig.airMode) && element.blur();
                $scope.blur({evt: evt});
            };
        }
        element.summernote(summernoteConfig);

        var editor$ = element.next('.note-editor'), unwatchNgModel;
        editor$.find('.note-toolbar').click(function() {
            updateNgModel();

            // sync ngModel in codeview mode
            if (editor$.hasClass('codeview')) {
                editor$.on('keyup', updateNgModel);
                if (ngModel) {
                    unwatchNgModel = scope.$watch(function () {
                        return ngModel.$modelValue;
                    }, function(newValue) {
                        editor$.find('.note-codable').val(newValue);
                    });
                }
            } else {
                editor$.off('keyup', updateNgModel);
                if (angular.isFunction(unwatchNgModel)) {
                    unwatchNgModel();
                }
            }
        });

        if (ngModel) {
            ngModel.$render = function() {
                if (ngModel.$viewValue) {
                    element.summernote('code', ngModel.$viewValue);
                } else {
                    element.summernote('empty');
                }
            };
        }

        // set editable to avoid error:isecdom since Angular v1.3
        if (angular.isDefined($attrs.editable)) {
            $scope.editable = editor$.find('.note-editable');
        }
        if (angular.isDefined($attrs.editor)) {
            $scope.editor = element;
        }

        currentElement = element;
        // use jquery Event binding instead $on('$destroy') to preserve options data of DOM
        element.on('$destroy', function() {
            element.summernote('destroy');
            $scope.summernoteDestroyed = true;
        });
    };

    $scope.$on('$destroy', function () {
        // when destroying scope directly
        if (!$scope.summernoteDestroyed) {
            currentElement.summernote('destroy');
        }
    });
}])
 .directive('summernote', [function() {
    'use strict';

    return {
        restrict: 'EA',
        transclude: 'element',
        replace: true,
        require: ['summernote', '?ngModel'],
        controller: 'SummernoteController',
        scope: {
            summernoteConfig: '=config',
            editable: '=',
            editor: '=',
            init: '&onInit',
            enter: '&onEnter',
            focus: '&onFocus',
            blur: '&onBlur',
            paste: '&onPaste',
            keyup: '&onKeyup',
            keydown: '&onKeydown',
            change: '&onChange',
            imageUpload: '&onImageUpload',
            mediaDelete: '&onMediaDelete'
        },
        template: '<div class="summernote"></div>',
        link: function(scope, element, attrs, ctrls, transclude) {
            var summernoteController = ctrls[0],
                ngModel = ctrls[1];

            if (!ngModel) {
                transclude(scope, function(clone, scope) {
                    // to prevent binding to angular scope (It require `tranclude: 'element'`)
                    element.append(clone.html());
                });
                summernoteController.activate(scope, element, ngModel);
            } else {
                var clearWatch = scope.$watch(function() { return ngModel.$viewValue; }, function(value) {
                    clearWatch();
                    element.append(value);
                    summernoteController.activate(scope, element, ngModel);
                }, true);
            }
        }
    };
}]);
(function() {
    'use strict';
var acp = angular.module('angularColorPicker', []),

    ae = angular.element,
    each = angular.forEach;

acp.value('acpOptions', {
    // set the path to the bgGradient.png
    'imgPath': '../img/bgGradient.png',
    'imgPathLine': '../img/transparent-mini.png',
    'startPosition': {
        'x': 'center', // %, px, center, root
        'y': 'center' // %, px, center, root
    },
    'topPanel': true,
    'singleton': true
});
acp.service('acpLib', [function() {
    var api =  {
        pareseRgb: function(rgb) {
            var result = [];
            if ('none' !== rgb && 'transparent' !== rgb) {
                rgb = rgb.split('(')[1];
                rgb = rgb.split(')')[0];
                rgb = rgb.split(',');
                angular.forEach(rgb, function(v) {
                    result.push(parseFloat(v));
                });
                return result;
            } else {
                return rgb;
            }
        },
        pareseRgba: function(value) {
            var rgb, alpha;
            if ('none' !== value && 'transparent' !== value) {
                rgb = api.pareseRgb(value);
                alpha = parseFloat(rgb[3]);
                rgb = [rgb[0], rgb[1], rgb[2]];
            } else {
                alpha = 1;
                rgb = value;
            }

            return {
                rgb: rgb,
                alpha: alpha
            };
        },
        pareseHex: function(hex) {
            var result = [], l, count = 2, step = 2, pos = 0;
            if ('none' !== hex && 'transparent' !== hex) {
                hex = hex.replace('#', '');
                l = hex.length;
                if (6 === l || 3 === l) {
                    if (3 === l) {
                        count = 1;
                        step = 1;
                    }
                    while(l !== pos) {
                        result.push(parseInt(hex.substr(pos, count), 16));
                        pos += step;
                    }
                } else {
                    result = [255, 255, 255];
                }
                return result;
            } else {
                return hex;
            }
        },
        cleanString: function(str) {
            return str.replace(/\s+/g, '');
        },
        obj: {
            positX: function(b) {
                var a, c;
                a = 0;
                c = b.getBoundingClientRect();
                b = document.body;
                a = document.documentElement;
                a = c.left + (a.scrollLeft || b && b.scrollLeft || 0) - (a.clientLeft || b.sclientLeft || 0);
                return Math.round(a);
            },
            positY: function(b) {
                var a, c;
                a = 0;
                c = b.getBoundingClientRect();
                b = document.body;
                a = document.documentElement;
                a = c.top + (a.scrollTop || b && b.scrollTop || 0) - (a.clientTop || b.sclientTop || 0);
                return Math.round(a);
            }
        },
        mouse: {
            pageX: function(b) {
                var a, c, d;
                d = b || event;
                return null == d.pageX && null != d.clientX ? (a = document.body, c = document.documentElement, b = c.scrollLeft || a && a.scrollLeft || 0, b = d.clientX + b - (c.clientLeft || a.clientLeft || 0)) : d.pageX;
            },
            pageY: function(b) {
                var a, c, d;
                d = b || event;
                return null == d.pageX && null != d.clientX ? (a = document.body, c = document.documentElement, b = c.scrollTop || a && a.scrollTop || 0, b = d.clientY + b - (c.clientTop || a.clientTop || 0)) : d.pageY;
            }
        },
        convertRgbToHex: function(rgb) {
            return  ('0' + parseInt(rgb[0],10).toString(16)).slice(-2) +
                    ('0' + parseInt(rgb[1],10).toString(16)).slice(-2) +
                    ('0' + parseInt(rgb[2],10).toString(16)).slice(-2);
        },
        hsv_rgb: function (H,S,V){
            var f , p, q , t, lH;
            var R, G, B;

            S /= 100;
            V /= 100;

            lH = Math.floor(H / 60);

            f = H / 60 - lH;
            p = V * (1 - S);
            q = V * (1 - S * f);
            t = V * (1 - (1 - f) * S);

            switch (lH) {
                case 0: R = V; G = t; B = p; break;
                case 1: R = q; G = V; B = p; break;
                case 2: R = p; G = V; B = t; break;
                case 3: R = p; G = q; B = V; break;
                case 4: R = t; G = p; B = V; break;
                case 5: R = V; G = p; B = q; break;
            }

            return [parseInt(R * 255), parseInt(G * 255), parseInt(B * 255)];
        },
        rgb_hsv: function(rgb) {
            var hsv = [],
                h, s, v, min,
                cr, cg, cb;
            if (rgb && rgb.length > 0) {
                v = Math.max(rgb[0], rgb[1], rgb[2]);
                min = Math.min(rgb[0], rgb[1], rgb[2]);

                if (0 === v) {
                    s = 0;
                } else {
                    s = (v - min) / v;
                }

                if (0 === s) {
                    // uncertainty
                    h = 359;
                } else {
                    cr = (v - rgb[0]) / (v - min);
                    cg = (v - rgb[1]) / (v - min);
                    cb = (v - rgb[2]) / (v - min);

                    if (rgb[0] === v) {
                        h = cb - cg;
                    }

                    if (rgb[1] === v) {
                        h = 2 + cr - cb;
                    }
                    if (rgb[2] === v) {
                        h = 4 + cg - cr;
                    }
                    h = h * 60;

                    // leading to positive
                    if (h < 0) {
                        h = h + 360;
                    }
                }
                hsv.push(h);
                hsv.push(s);
                hsv.push(v);
            }
            return hsv;
        }
    };
    return api;
}]);
acp.service('acpManager', ['acpModel', '$rootScope', function(acpModel, $rootScope) {
    var api = {
        close: function() {
            if ($rootScope.colorPickerOpened) {
                try {
                    var instance = acpModel.getInstance($rootScope.colorPickerOpened);
                    instance.scope.close();
                } catch(e) {}
            }
        }
    };
    return api;
}]);
acp.factory('acpModel', [function() {
    var colorPickers = {},

    api = {
        checkInstance: function(name) {
            return (name && colorPickers[name]) ? true : false;
        },
        getInstance: function(name) {
            return colorPickers[name];
        },
        removeInstance: function(name) {
            if (api.checkInstance(name)) {
                delete colorPickers[name];
            }
        },
        newInstance: function(name) {
            api.removeInstance(name);
            return colorPickers[name] = {
                blockBGColor: 'red',
                rgb: 'rgb(255,255,255)',
                tmpRgb: [255,255,255],
                rgba: 'rgba(255,255,255,0)',
                hex: '#ffffff',
                hue: 0,
                none: false,
                text: 'none', // none, default
                alpha: 0,
                noneFlag: false,
                transparent: false,
                transparentFlag: false,
                picker: {
                    V: 100,
                    S: 100
                }
            };
        }
    };
    return api;
}]);
acp.directive('angularColorPicker', ['$compile', '$document', 'acpModel', 'acpLib', '$rootScope', 'acpManager', '$timeout', 'acpOptions',
    function($compile, $document, acpModel, acpLib, $rootScope, acpManager, $timeout, acpOptions) {
    return {
        restrict: 'A',
        scope: {},
        require: '?ngModel',
        link: function(scope, element, attrs, ngModel) {
            var id,
                instance, ngModelFlag = false,
                container,
                type,

                click = function(e) {
                    var value, rgb, alpha = 1;
                    e.stopPropagation();
                    e.preventDefault();
                    acpOptions.singleton && acpManager.close();
                    scope.firstStart = false;

                    type = acpLib.cleanString(attrs.angularColorPicker);

                    if ('rgb' !== type && 'rgba' !== type && 'hex' !== type) {
                        type = 'rgb';
                    }

                    $rootScope.angularColorPickerElement = element;
                    id = attrs.id || 'angular-color-picker-' + Date.now(),

                    instance = acpModel.newInstance(id);

                    if (undefined !== attrs.text) {
                        instance.text = 'default';
                        if ('none' === attrs.text) {
                            instance.noneFlag = true;
                        } else {
                            instance.transparentFlag = true;
                        }
                    }

                    container = ae('<div>');
                    container.addClass('color-picker');
                    container.attr('acp-window', '');
                    container.attr('name', id);

                    instance.scope = scope;

                    ae($document[0].body).append(container[0]);

                    if (attrs.ngModel && ngModel.$valid && (value = acpLib.cleanString(ngModel.$viewValue))) {
                        if (/rgba/.test(value)) {
                            rgb = acpLib.pareseRgba(value);
                            alpha = rgb.alpha;
                            rgb = rgb.rgb;
                            instance.rgba = value;
                            instance.rgb = 'rgb(' + rgb + ')';
                        } else if (/rgb/.test(value)) {
                            rgb = acpLib.pareseRgb(value);
                            instance.rgb = value;
                            instance.rgba = 'rgba(' + rgb + ',' + instance.alpha + ')';
                            alpha = 1;
                        } else {
                            rgb = acpLib.pareseHex(value);
                            instance.rgb = 'rgb(' + rgb + ')';
                            instance.rgba = 'rgba(' + rgb + ',' + instance.alpha + ')';
                            alpha = 1;
                        }

                        instance.tmpRgb = rgb;
                        // $timeout(function() {
                            if ('none' === rgb || 'transparent' === rgb) {
                                scope.firstStart = true;

                                instance.rgb = 'rgb(0,0,0)';
                                instance.tmpRgb = [0,0,0];
                                instance.rgba = 'rgba(0,0,0,0)';
                                instance.hex = '#000';
                                instance.hsv = 'none' === rgb ? 'none' : 'transparent';
                                instance.hue = 0;
                                instance.alpha = 0;
                                // instance.picker.V = 100;
                                // instance.picker.S = 100;
                                instance.picker.V = 0;
                                instance.picker.S = 0;
                                instance.blockBGColor = 'red';
                                instance.none = 'none' === rgb;
                                instance.transparent = 'transparent' === rgb;
                            } else {
                                instance.hex = '#' + acpLib.convertRgbToHex(rgb);
                                instance.hsv = acpLib.rgb_hsv(rgb);
                                instance.alpha = alpha;
                                instance.none = false;
                                instance.transparent = false;
                            }
                            instance.lastAlpha = instance.alpha;
                        // }, 0);
                        ngModelFlag = true;
                    }

                    $document.bind('mousedown', mouseDown);
                    $compile(container)(scope);
                    $rootScope.colorPickerOpened = id;
                },

                mouseDown = function(e) {
                    var target = e.target;
                    e.stopPropagation();
                    e.preventDefault();
                    while (target && target !== container[0]) {
                        target = target.parentNode;
                    }
                    if (target === container[0]) {
                        return;
                    }
                    scope.close();
                };

            scope.close = function() {
                if ($rootScope.colorPickerOpened) {
                    $rootScope.colorPickerOpened = false;
                    acpModel.removeInstance(id);
                    ngModelFlag = false;
                    container.remove();
                    $document.unbind('mousedown', mouseDown);
                }
            },

            type = acpLib.cleanString(attrs.angularColorPicker);

            if ('rgb' !== type && 'rgba' !== type && 'hex' !== type) {
                type = 'rgb';
            }

            scope.$on('acpEvent', function(e, data) {
                e.stopPropagation();
                // instance.rgb
                // instance.cleanRgb TODO
                // instance.hex

                if (ngModelFlag) {
                    // ngModel.$setViewValue('' !== instance[type] ? instance[type] : (instance.noneFlag ? 'none' : 'transparent'));
                    if (data.none) {
                        ngModel.$setViewValue(instance.noneFlag ? 'none' : 'transparent');
                    } else {
                        ngModel.$setViewValue(instance[type]);
                    }
                }
            });
            scope.$on('closeAcp', function(e) {
                e.stopPropagation();
                scope.close();
            });

            element.unbind('click', click);
            element.bind('click', click);
        }
    };
}]);
acp.directive('acpWindow', ['acpLib', 'acpModel', 'acpOptions', '$window', '$rootScope', function(acpLib, acpModel, acpOptions, $window, $rootScope) {
    return {
        restrict: 'A',
        scope: true,
        template:   '<div ng-show="isTopPanelShow" class="control-panel" acp-control-panel></div>' +
                    '<div class="main-panel" acp-main-panel></div>',
        link: function(scope, element, attrs) {
            var _x, _y,
                x = acpOptions.startPosition.x,
                y = acpOptions.startPosition.y;

            scope.cpSize = {
                width: element[0].offsetWidth,
                height: element[0].offsetHeight
            };

            scope.lastInstance = {};

            scope.clientSize = {
                width: $window.document.documentElement.clientWidth,
                height: $window.document.documentElement.clientHeight,
            };

            scope.instance = acpModel.getInstance(attrs.name);
            scope.isTopPanelShow = acpOptions.topPanel;

            scope.checkboxChange = function() {
                var inst = scope.instance, n = true;

                if (inst.none || inst.transparent) {
                    inst.lastAlpha = inst.alpha;
                    inst.alpha = 0;
                } else {
                    inst.alpha = inst.lastAlpha || 1;
                    n = false;
                }
                scope.setAlphaPosition();
                scope.$emit('acpEvent', { none: n });
            };

            if ('root' === x) {
                x = acpLib.obj.positX($rootScope.angularColorPickerElement[0]);

                x += ($rootScope.angularColorPickerElement[0].offsetWidth / 2 - scope.cpSize.width / 2);

                if (x < 0) {
                    x = 10;
                } else if (x + scope.cpSize.width > scope.clientSize.width - 10) {
                    x = scope.clientSize.width - scope.cpSize.width - 10;
                }

                x += 'px';
            } else if (x !== 'center') {
                _x = parseFloat(x);
                if (isNaN(_x) || undefined === _x) {
                    x = 'center';
                }
            }

            if ('root' === y) {
                y = acpLib.obj.positY($rootScope.angularColorPickerElement[0]);

                if (y - scope.cpSize.height - $rootScope.angularColorPickerElement[0].offsetHeight / 2 - 10 > 0) {
                    y = y - scope.cpSize.height - $rootScope.angularColorPickerElement[0].offsetHeight / 2 - 10;
                } else {
                    y += (10 + $rootScope.angularColorPickerElement[0].offsetHeight);
                }

                y += 'px';
            } else if (y !== 'center') {
                _y = parseFloat(y);
                if (isNaN(_y) || undefined === _y) {
                    y = 'center';
                }
            }

            element.css({
                'top': (y === 'center') ? (scope.clientSize.height / 2 - scope.cpSize.height / 2) + 'px' : y,
                'left': (x === 'center') ? (scope.clientSize.width / 2 - scope.cpSize.width / 2) + 'px' : x
            });

            scope.$apply();
            element.bind('$destroy', function() {
                scope.$destroy();
            });
        }
    };
}]);

acp.directive('acpControlPanel', ['$window', 'acpLib', 'acpOptions', function($window, acpLib, acpOptions) {
    return {
        restrict: 'A',
        template: '<button class="close-button"></button>',
        link: function(scope, element, attrs) {
            var button = element[0].childNodes[0],
                startPointX = 0,
                startPointY = 0,

                move = function(e) {
                    var top, left;

                    top = acpLib.mouse.pageY(e) - startPointY;
                    left = acpLib.mouse.pageX(e) - startPointX;

                    top < 0 && (top = 0);
                    left < 0 && (left = 0);

                    if (left + scope.cpSize.width > scope.clientSize.width) {
                        left = scope.clientSize.width - scope.cpSize.width;
                    }

                    if (top + scope.cpSize.height > scope.clientSize.height) {
                        top = scope.clientSize.height - scope.cpSize.height;
                    }

                    element.parent().css({
                        'top': top + 'px',
                        'left': left + 'px'
                    });
                },

                mouseUp = function(e) {
                    if (1 === e.which) {
                        element.css('cursor', '');
                        ae($window.document).unbind('mousemove', move);
                        ae($window.document).unbind('mouseup', mouseUp);
                    }
                };

            acpOptions.topPanel && element.addClass('show');

            element.bind('mousedown', function(e) {
                if (1 === e.which && e.target !== button) {
                    e.preventDefault();
                    element.css('cursor', 'move');
                    startPointX = acpLib.mouse.pageX(e) - acpLib.obj.positX(element[0]);
                    startPointY = acpLib.mouse.pageY(e) - acpLib.obj.positY(element[0]);
                    ae($window.document).bind('mouseup', mouseUp);
                    ae($window.document).bind('mousemove', move);
                }
            });
            ae(button).bind('click', function(e) {
                scope.$emit('closeAcp');
            });

            element.bind('$destroy', function() {
                element.unbind('mousedown');
                ae(button).unbind('click');
            });
        }
    };
}]);
acp.directive('acpMainPanel', ['$compile', function($compile) {
    return {
        restrict: 'A',
        template:   '<div class="block-picker" acp-block="blockBGColor"></div>' +
                    '<div class="controls-wrapper-picker">' +
                        '<div class="out-color-wrapper">' +
                            '<div class="out-color" acp-out></div>' +
                        '</div>' +
                        '<div class="lines-picker">' +
                            '<div class="line-wrapper">' +
                                '<div class="line-piker" acp-line></div>' +
                            '</div>'+
                            '<div class="line-wrapper">' +
                                '<div class="alpha-piker" acp-alpha></div>' +
                            '</div>'+
                        '</div>' +
                    '</div>',
                    // '<div class="text" ng-show="{{instance.noneFlag || instance.transparentFlag}}">' +
                    //     '<label ng-show="instance.noneFlag"><input ng-model="instance.none" type="checkbox" ng-change="checkboxChange()"><span> {{instance.text}}</span></label>' +
                    //     '<label ng-show="instance.transparentFlag"><input ng-model="instance.transparent" type="checkbox" ng-change="checkboxChange()"><span> transparent</span></label>' +
                    // '</div>',
        link: function(scope, element, attrs) {
            var watch, t = angular.element('<div class="text">' +
                        '<label ng-show="instance.noneFlag"><input ng-model="instance.none" type="checkbox" ng-change="checkboxChange()"><span> {{instance.text}}</span></label>' +
                        '<label ng-show="instance.transparentFlag"><input ng-model="instance.transparent" type="checkbox" ng-change="checkboxChange()"><span> transparent</span></label>' +
                    '</div>');

            watch = scope.$watch('instance', function(nv) {
                if (nv) {
                    if (scope.instance.noneFlag || scope.instance.transparentFlag) {
                        element.append(t[0]);
                        $compile(t)(scope);
                    }
                }
            });

            element.bind('mousedown', function(e) {
                e.preventDefault();
                e.stopPropagation();
            });

            element.bind('$destroy', function() {
                watch();
                element.unbind('mousedown');
            });
        }
    };
}]);

acp.directive('acpAlpha', ['$compile', 'acpOptions', 'acpLib', '$window', function($compile, acpOptions, acpLib, $window) {
    var round = function(value) {
        value = value * 100;
        value = Math.round(value);
        value /= 100;
        return value;
    };
    return {
        restrict: 'A',
        template:   '<div class="circle-control"></div>' +
                    '<div class="cAlpha">' +
                        '<img src="' + acpOptions.imgPathLine + '">' +
                        '<div></div>' +
                    '</div>',
        link: function(scope, element, attrs) {
            var pos, tmp = 0,
                watchers = [],
                arrows = element[0].childNodes[0],
                line = {
                    width: 165,
                    height: 14,
                    node: element[0].childNodes[1],
                    gradient: element[0].childNodes[1].childNodes[1]
                },

                rgba_ = function() {
                    scope.instance.rgba = 'rgba(' + scope.instance.tmpRgb + ',' + scope.instance.alpha + ')';
                },

                getAlpha = function (e) {
                    var left;

                    left = acpLib.mouse.pageX(e) - pos;
                    left = (left < 0 )? 0 : left;
                    left = (left > line.width) ? line.width : left;

                    arrows.style.left = left + 'px';

                    scope.$apply(function() {
                        scope.instance.alpha = round(left / (line.width / 100) / 100);
                        line.gradient.style.background = 'linear-gradient(to right, transparent, ' + scope.instance.rgb + ')';
                        rgba_();
                        scope.$emit('acpEvent', {});
                    });
                },
                setPosition = function(al) {
                    var left = line.width / 100 * (al * 100);
                    arrows.style.left = left + 'px';
                },

                move = function(e) {
                    getAlpha(e);
                },
                mouseUp = function(e) {
                    e.preventDefault();
                    ae($window.document).unbind('mousemove', move);
                    ae($window.document).unbind('mouseup', mouseUp);
                };

            // scope.instance && setPosition(scope.instance.alpha);

            scope.setAlphaPosition = function() {
                if (scope.instance) {
                    setPosition(scope.instance.alpha);
                    rgba_();
                }
            };

            scope.setAlphaPosition();

            ae(arrows).bind('mousedown', function(e) {
                if (1 === e.which) {
                    e.preventDefault();
                    scope.instance.none = false;
                    scope.instance.transparent = false;
                    if (scope.firstStart) {
                        scope.firstStart = false;
                    }
                    pos = acpLib.obj.positX(line.node);
                    move(e);
                    ae($window.document).bind('mouseup', mouseUp);
                    ae($window.document).bind('mousemove', move);
                }
            });

            ae(arrows.node).bind('click', getAlpha);

            ae(line.node).bind('click', function(e) {
                if (1 === e.which) {
                    scope.instance.none = false;
                    scope.instance.transparent = false;
                    if (scope.firstStart) {
                        scope.firstStart = false;
                    }
                    pos = acpLib.obj.positX(line.node);
                    move(e);
                }
            });

            ae(line.node).bind('mousedown', function(e) {
                if (1 === e.which) {
                    e.preventDefault();
                    e.stopPropagation();
                    pos = acpLib.obj.positX(line.node);
                    ae($window.document).bind('mouseup', mouseUp);
                    ae($window.document).bind('mousemove', move);
                }
            });

            watchers.push(scope.$watch('instance', function(v) {
                if (undefined !== v) {
                    setPosition(scope.instance.alpha);
                }
            }));

            watchers.push(scope.$watch('instance.rgb', function(v) {
                if (undefined !== v) {
                    line.gradient.style.background = 'linear-gradient(to right, transparent, ' + v + ')';
                }
            }));

            watchers.push(scope.$watch('firstStart', function (nv, ov) {
                if (undefined !== nv && false === nv && true === ov) {
                    setPosition(scope.instance.alpha);
                }
            }));

            element.bind('$destroy', function() {
                angular.forEach(watchers, function(watcher) {
                    watcher();
                });
                watchers = [];
                ae(arrows.node).unbind('click');
                ae(line.node).unbind('click');
                ae(arrows).unbind('mousedown');
                ae(line.node).unbind('mousedown');
            });
        }
    };
}]);

acp.directive('acpLine', ['$compile', '$window', 'acpLib', function($compile, $window, acpLib) {
    var rgb_ = function (canvas, h, w) {
            var gradient, hue, color, canvas, gradient, i;

            canvas = canvas.getContext("2d");

            // gradient = canvas.createLinearGradient( w / 2, h, w / 2, 0);
            gradient = canvas.createLinearGradient( w, h / 2, 0, h / 2);

            hue = [
                [255,0,0],
                [255,255,0],
                [0,255,0],
                [0,255,255],
                [0,0,255],
                [255,0,255],
                [255,0,0]
            ];

            for (i = 0; i <= 6; i++) {
                color = 'rgb('+hue[i][0]+','+hue[i][1]+','+hue[i][2]+')';
                gradient.addColorStop(i*1/6, color);
            }
            canvas.fillStyle = gradient;
            canvas.fillRect(0, 0, w, h);
        };

    return {
        restrict: 'A',
        template:   '<div class="circle-control"></div>' +
                    '<canvas width="165" height="14" class="cLine"></canvas>',

        link: function(scope, element, attrs) {
            var pos, tmp = 0,
                watchers = [],
                arrows = element[0].childNodes[0],
                line = {
                    width: 165,
                    height: 14,
                    node: element[0].childNodes[1]
                },
                getColor = function (e) {
                    var left, rgb;

                    left = acpLib.mouse.pageX(e) - pos;
                    left = (left < 0) ? 0 : left;
                    left = (left > line.width) ? line.width : left;

                    arrows.style.left = left + 'px';
                    tmp =  Math.round(left / ( line.width / 360 ));
                    tmp = Math.abs(tmp - 360);
                    tmp = (tmp == 360) ? 0 : tmp;

                    scope.instance.hue = tmp;

                    rgb = acpLib.hsv_rgb(tmp, scope.instance.picker.S, scope.instance.picker.V);
                    scope.$apply(function() {
                        scope.instance.blockBGColor = 'rgb(' + acpLib.hsv_rgb(tmp, 100, 100) + ')';
                        scope.instance.rgb = 'rgb(' + rgb + ')';
                        scope.instance.rgba = 'rgba(' + rgb + ',' + scope.instance.alpha +')';
                        scope.instance.hex = '#' + acpLib.convertRgbToHex(rgb);
                        scope.instance.tmpRgb = rgb;
                        scope.$emit('acpEvent', {});
                    });
                },
                setPosition = function(h) {
                    var left = 165 - 165 / (360 / h);

                    arrows.style.left = left + 'px';
                    scope.instance.hue = h;
                    scope.instance.blockBGColor = 'rgb(' + acpLib.hsv_rgb(h, 100, 100) + ')';
                },
                move = function(e) {
                    getColor(e);
                },
                mouseUp = function(e) {
                    e.preventDefault();
                    ae($window.document).unbind('mousemove', move);
                    ae($window.document).unbind('mouseup', mouseUp);
                };

            line.node.width = line.width;
            line.node.height = line.height;

            rgb_(line.node, line.height, line.width);

            ae(arrows).bind('mousedown', function(e) {
                if (1 === e.which) {
                    e.preventDefault();
                    e.stopPropagation();
                    scope.instance.none = false;
                    scope.instance.transparent = false;
                    if (scope.firstStart) {
                        scope.firstStart = false;
                        scope.instance.alpha = 1;
                    }
                    pos = acpLib.obj.positX(line.node);
                    ae($window.document).bind('mouseup', mouseUp);
                    ae($window.document).bind('mousemove', move);
                }
            });

            ae(arrows.node).bind('click', getColor);

            ae(line.node).bind('click', function(e) {
                scope.instance.none = false;
                scope.instance.transparent = false;
                getColor(e);
            });

            ae(line.node).bind('mousedown', function(e) {
                if (1 === e.which) {
                    e.preventDefault();
                    e.stopPropagation();
                    pos = acpLib.obj.positX(line.node);
                    ae($window.document).bind('mouseup', mouseUp);
                    ae($window.document).bind('mousemove', move);
                }
            });

            watchers.push(scope.$watch('instance.hsv', function(v) {
                if (v && v.length > 0) {
                    if ('none' === v || 'transparent' === v) {
                        v = [359, 0, 0];
                    }
                    setPosition(v[0]);
                }
            }));

            element.bind('$destroy', function() {
                angular.forEach(watchers, function(watcher) {
                    watcher();
                });
                watchers = [];
                ae(arrows.node).unbind('click');
                ae(line.node).unbind('click');
                ae(arrows).unbind('mousedown');
                ae(line.node).unbind('mousedown');
            });
        }
    };
}]);
acp.directive('acpBlock', ['$compile', '$window', 'acpLib', 'acpOptions', function($compile, $window, acpLib, acpOptions) {
    return {
        restrict: 'A',
        template: '<img src="' + acpOptions.imgPath + '">' +
                    '<div class="circle"></div>',
        link: function(scope, element, attrs) {
            var watchers = [],
                block = element[0],
                circle = block.childNodes[1],
                bPstX, bPstY, bWi, bHe, cW, cH, pxY, pxX,
                getColor = function (e) {
                    var rgb, top, left, S, V;

                    element.bind('dragstart', function() {
                        return false;
                    });

                    element.bind('onselectstart', function() {
                        return false;
                    });

                    left = acpLib.mouse.pageX(e) - bPstX - cW/2;
                    left = (left < 0) ? 0 : left;
                    left = (left > bWi) ? bWi  : left;

                    ae(circle).css('left', left + 'px');

                    S = Math.ceil(left / pxX);

                    top = acpLib.mouse.pageY(e) - bPstY - cH/2;
                    top = (top > bHe) ? bHe : top;
                    top = (top < 0) ? 0 : top;

                    ae(circle).css('top', top + 'px');

                    V = Math.ceil(Math.abs(top / pxY - 100));

                    // ae(circle).css('border-color', V < 50 ? '#fff' : '#000');

                    scope.instance.picker.S = S;
                    scope.instance.picker.V = V;

                    rgb = acpLib.hsv_rgb(scope.instance.hue, S, V);
                    scope.$apply(function() {
                        scope.instance.rgb = 'rgb(' + rgb + ')';
                        scope.instance.rgba = 'rgba(' + rgb + ',' + scope.instance.alpha +')';
                        scope.instance.tmpRgb = rgb;
                        scope.instance.hex = '#' + acpLib.convertRgbToHex(rgb);
                        scope.$emit('acpEvent', {});
                    });
                },
                setPosition = function(hsv) {
                    var top = bHe - bHe / (255 / hsv[2]),
                        left = bWi / (1 / hsv[1]);

                    scope.instance.picker.S = Math.ceil(left / pxX);
                    scope.instance.picker.V = Math.ceil(Math.abs(top / pxY - 100));

                    ae(circle).css({
                        'top': top + 'px',
                        'left': left + 'px'
                    });
                },
                move = function(e) {
                    bPstX = acpLib.obj.positX(block);
                    bPstY = acpLib.obj.positY(block);
                    getColor(e);
                },
                mouseUp = function(e) {
                    e.preventDefault();
                    ae($window.document).unbind('mousemove', move);
                    ae($window.document).unbind('mouseup', mouseUp);
                };

            watchers.push(scope.$watch('instance.blockBGColor', function(v) {
                element.css('background-color', v);
            }));

            cW = circle.offsetWidth;
            cH = circle.offsetHeight;
            bWi = block.offsetWidth - cW;
            bHe = block.offsetHeight - cH;
            pxY = bHe / 100;
            pxX = bWi / 100;

            element.bind('click', function(e) {
                getColor(e);
            });

            element.bind('mousedown', function(e) {
                if (1 === e.which) {
                    e.preventDefault();
                    e.stopPropagation();
                    scope.instance.none = false;
                    scope.instance.transparent = false;
                    if (scope.firstStart) {
                        scope.firstStart = false;
                        scope.instance.alpha = 1;
                    }
                    move(e);
                    ae($window.document).bind('mouseup', mouseUp);
                    ae($window.document).bind('mousemove', move);
                }
            });

            watchers.push(scope.$watch('instance.hsv', function(v) {
                if (v && v.length > 0) {
                    if ('none' === v || 'transparent' === v) {
                        v = [359, 0, 0];
                    }
                    setPosition(v);
                }
            }));

            element.bind('$destroy', function() {
                angular.forEach(watchers, function(watcher) {
                    watcher();
                });
                watchers = [];
                element.unbind('click');
                element.unbind('mousedown');
            });
        }
    };
}]);

acp.directive('acpOut', ['$compile', 'acpOptions', function($compile, acpOptions) {
    return {
        restrict: 'A',
        scope: false,
        template: '<div class="bg-img"></div><div></div>',
        link: function(scope, element, attrs) {
            var watch, ch = element.children();

            ae(ch[0]).css('background-image', 'url(' + acpOptions.imgPathLine + ')');

            watch = scope.$watch('instance.rgba', function(v) {
                ch.css('background-color', v);
            });

            element.bind('$destroy', function() {
                watch();
            });
        }
    };
}]);
})();
(function() {
    'use strict';

    var aInfobar = angular.module('angularInfobar', []);

    aInfobar.value('aInfobarOptions', {
        'showTime': 2000,
        'enterTime': 500,
        'exitTime': 1000
    });

    aInfobar.service('aInfobarManager', ['aInfobarModel', function(aInfobarModel) {
        return {
            showMessage: function(innerHTML) {
                aInfobarModel.newInstance(innerHTML);
            },
            hideMessage: function(id) {
                aInfobarModel.removeInstance(id);
            }
        };
    }]);

    aInfobar.service('aInfobarModel', ['$compile', '$document', function($compile, $document) {
        var instances = {},
            create = function(innerHTML) {
                var id = 'aInfobar-' + (new Date().getTime()),
                    node = angular.element('<div>'),
                    content = angular.element('<div>');

                node.addClass('aInfobar');
                node.attr('a-infobar', '');
                node.attr('id', id);

                content.addClass('aInfobar-content');
                content[0].innerHTML = innerHTML;

                node.append(content[0]);

                return {
                    id: id,
                    node: node,
                    content: content,
                    message: innerHTML
                };
            };

        return {
            newInstance: function(innerHTML) {
                var instance = create(innerHTML);
                instances[instance.id] = instance;

                angular.element($document[0].body).append(instance.node[0]);

                $compile(instance.node[0]) (angular.element($document[0].body).scope().$new(true));

                return instance.id;
            },

            removeInstance: function(id) {
                instances[id].node.remove();
                delete instances[id];
            }
        };
    }]);

    aInfobar.directive('aInfobar', ['aInfobarModel', 'aInfobarOptions', '$document', function(aInfobarModel, aInfobarOptions, $document) {
        return {
            restrict: 'A',
            link: function(scope, element, attrs) {
                var button = angular.element('<button>'),
                    first = false,
                    exit = function() {
                        element.on('transitionend', function(e) {
                            element.off(e.type);
                            aInfobarModel.removeInstance(attrs.id);
                        });
                        
                        element.css({
                            'opacity': '0',
                            '-webkit-transition': 'opacity ' + aInfobarOptions.enterTime + 'ms ease-out ' + aInfobarOptions.showTime + 'ms',
                            'transition': 'opacity ' + aInfobarOptions.enterTime + 'ms ease-out ' + aInfobarOptions.showTime + 'ms'
                        });
                    };

                button.addClass('aInfobar-control btn btn-default glyphicon glyphicon-remove');
                button.on('click', function() {
                    aInfobarModel.removeInstance(attrs.id);
                });

                element.append(button[0]);

                element.on('transitionend', function(e) {
                    element.off(e.type);
                    first = true;
                    exit();
                });

                element.on('mouseover mouseout', function(e) {
                    var related = e.relatedTarget;
                    while (related && related !== element[0]) {
                        related = related.parentNode;
                    }
                    if (related == element[0]) {
                        return;
                    }

                    if (first) {
                        if ('mouseover' === e.type) {
                            element.off('transitionend');
                            element.css({
                                'opacity': '1',
                                '-webkit-transition': 'none',
                                'transition': 'none'
                            });
                        } else {
                            exit();
                        }
                    }
                });

                element[0].offsetHeight; // render

                element.css({
                    'top': '25px',
                    '-webkit-transition': 'top ' + aInfobarOptions.enterTime + 'ms ease-out 100ms',
                    'transition': 'top ' + aInfobarOptions.enterTime + 'ms ease-out 100ms'
                });

                element.on('$destroy', function() {
                    button.off('click');
                    element.off('mouseover mouseout');
                    element.off('transitionend');
                    scope.$destroy();
                });
            }
        };
    }]);
})();(function() {
    'use strict';

    var mw = angular.module('aModalWindow', []);

    mw.value('aModalWindowOptions', {
        saveButtonText: 'Save & Close',
        dSaveButtonText: 'Don\'t save',
        cancelButtonText: 'Cancel'
    });

    mw.service('aModalWindowManager', ['aModalWindowModel', function(aModalWindowModel) {
        // return function(text, callbacks) {
        //     aModalWindowModel.show(text, callbacks);
        // };

        return {
            show: function(text, callbacks) {
                aModalWindowModel.show(text, callbacks);
            },
            hide: function() {
                aModalWindowModel.hide();
            }
        };
    }]);

    mw.service('aModalWindowModel', [function() {
        var instance = {
            currentWindow: null,
            textNode: null,
            saveB: null,
            dSaveB: null,
            cancelB: null,
            callbacks: {
                saveButtonCallBack: function() {},
                dSaveButtonCallBack: function() {},
                cancelButtonCallBack: function() {}
            }
        },

        obj = {
            setWindow: function(node, tNode, saveB, dSaveB, cancelB) {
                instance.currentWindow = node;
                instance.textNode      = tNode;
                instance.saveB         = saveB,
                instance.dSaveB        = dSaveB,
                instance.cancelB       = cancelB;
            },

            setCallbacks: function(callbacks) {
                if (callbacks) {
                    if (callbacks.saveButtonCallBack)
                        instance.callbacks.saveButtonCallBack = callbacks.saveButtonCallBack;
                    if (callbacks.dSaveButtonCallBack)
                        instance.callbacks.dSaveButtonCallBack = callbacks.dSaveButtonCallBack;
                    if (callbacks.cancelButtonCallBack)
                        instance.callbacks.cancelButtonCallBack = callbacks.cancelButtonCallBack;
                } else {
                    instance.callbacks = {
                        saveButtonCallBack: function() {},
                        dSaveButtonCallBack: function() {},
                        cancelButtonCallBack: function() {}
                    };
                }
            },

            show: function(text, callbacks) {
                if(text) {
                    instance.textNode[0].innerHTML = text;
                }

                obj.setCallbacks(callbacks);

                instance.saveB.on('click', function(e) {
                    e.preventDefault();
                    e.stopPropagation();
                    instance.saveB.css({'position': 'relative'});
                    instance.saveB.addClass('loading');
                    instance.callbacks.saveButtonCallBack()
                });

                instance.dSaveB.on('click', function(e) {
                    e.preventDefault();
                    e.stopPropagation();
                    instance.callbacks.dSaveButtonCallBack();
                });

                instance.cancelB.on('click', function(e) {
                    e.preventDefault();
                    e.stopPropagation();
                    instance.callbacks.cancelButtonCallBack();
                });

                instance.currentWindow.addClass('show');
            },

            hide: function() {
                obj.setCallbacks();
                instance.saveB.css({'position': ''});
                instance.saveB.removeClass('loading');
                instance.saveB.off('click');
                instance.dSaveB.off('click');
                instance.cancelB.off('click');
                instance.currentWindow.removeClass('show');
            }
        };

        return obj;
    }]);

    mw.directive('aModalWindow', ['aModalWindowOptions', 'aModalWindowModel', function(aModalWindowOptions, aModalWindowModel) {
        return {
            restrict: 'A',
            link: function(scope, element, attrs) {
                element.addClass('a-modal-window');
                var node = angular.element('<div>'),
                    textNode = angular.element('<div>'),
                    controllsWrapper = angular.element('<div>'),
                    saveButtonText = angular.element('<button>'),
                    dSaveButtonText = angular.element('<button>'),
                    cancelButtonText = angular.element('<button>');

                node.addClass('view-wrapper');
                textNode.addClass('text-container');
                controllsWrapper.addClass('controlls-wrapper');
                saveButtonText.addClass('save-button mtb-button insert');
                dSaveButtonText.addClass('d-save-button mtb-button');
                cancelButtonText.addClass('cancel-button mtb-button');


                saveButtonText[0].innerHTML = aModalWindowOptions.saveButtonText;
                dSaveButtonText[0].innerHTML = aModalWindowOptions.dSaveButtonText;
                cancelButtonText[0].innerHTML = aModalWindowOptions.cancelButtonText;

                node.append(textNode);
                controllsWrapper.append(cancelButtonText);
                controllsWrapper.append(dSaveButtonText);
                controllsWrapper.append(saveButtonText);

                node.append(controllsWrapper);

                aModalWindowModel.setWindow(element, textNode, saveButtonText, dSaveButtonText, cancelButtonText);
                element.append(node);

                element.on('$destroy', function() {
                    element.removeClass('show');
                    element.removeClass('a-modal-window');

                    saveButtonText.off('click');
                    dSaveButtonText.off('click');
                    cancelButtonText.off('click');

                    element[0].innerHTML = '';

                    scope.$destroy();
                });
            }
        };
    }]);
})();
})();