<|start_filename|>catalog/view/theme/default/javascript/d_visual_designer/model/content.js<|end_filename|>
(function(){
    this.subscribe('content/save', function(data) {
        var blocks = this.getState().blocks[data.designer_id]

        var send_data = {
            setting: JSON.stringify(blocks),
            route:this.getState().config.route[data.designer_id],
            id:this.getState().config.id[data.designer_id],
            field_name:this.getState().config.field_name[data.designer_id]
        }

        $.ajax({
            url: 'index.php?route=extension/d_visual_designer/designer/save',
            dataType: 'json',
            type: 'post',
            data: send_data,
            context: this,
            success: function(json){
                if(json.success) {
                    this.dispatch('save_content_success');
                } else {
                    this.dispatch('save_content_permission');
                }
            },
            error: function(){
                this.dispatch('save_content_permission');
            }
        })
    });
    this.subscribe('content/update', function(data){
        var blocks = this.getState().blocks[data.designer_id]
        var send_data = {
            setting: JSON.stringify(blocks)
        }

        $.ajax({
            url: 'index.php?route=extension/d_visual_designer/designer/updateBlocks',
            dataType: 'json',
            type: 'post',
            data: send_data,
            context: this,
            success: function(json){
                if(json.success) {
                    var oldBlocks = this.getState().blocks
                    oldBlocks[data.designer_id] = json.blocks
                    this.updateState({blocks: oldBlocks})
                }
            }
        })
    })
}.bind(d_visual_designer))()

<|start_filename|>admin/view/javascript/d_visual_designer/library/select2/select2.font.css<|end_filename|>
.select2-dropdown.select2-dropdown--below {
    width: 230px !important;
    z-index: 9999 !important;
}
.select2-results__options li {
    padding:1px !important;
}
.select2-results__options li div {
    background: url("img/fontsList.gif") !important;
    background-repeat: no-repeat;
    overflow: hidden;
    text-indent: -999px;
    height: 29px;
}
#select2-select_fontfamily-container {
    text-align: left !important;
    width: 200px !important;
}
.select2.select2-container{
    width: 230px !important;
    z-index: 9999 !important;
}
.select2.select2-container .select2-selection__rendered{
    text-align: left !important;
    width: 220px !important;
}
.select2.select2-container .select2-selection{
    width: 230px !important;
    z-index: 9999 !important;
    padding: 6px 12px;
}

<|start_filename|>admin/view/javascript/d_visual_designer/gulp/gulpfile.js<|end_filename|>
var gulp = require('gulp');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
var cleanCSS = require('gulp-clean-css');
var del = require('del');
var sass = require('gulp-sass');
var sourcemaps = require('gulp-sourcemaps');
var autoprefixer = require('gulp-autoprefixer');
var stripCssComments = require('gulp-strip-css-comments');
var browserSync = require("browser-sync");
var path = require("path");
var fs = require("fs");
var glob = require("glob")

//script paths
var jsDest = '../dist/';

var sassDest = '../../../stylesheet/d_visual_designer/'

var baseDir = path.resolve(__dirname, "../../../../");


gulp.task('clean', function () {
    return del(jsDest + '**', {force: true});
});

gulp.task('copy', ['copy-fonts', 'copy-img'], function () {
    gulp.start(['iconsets', 'iconsetsPro'])
});

gulp.task('iconsetsPro', function () {
    const dirs = fs.readdirSync('../library/iconsetsPro').filter(function(dir) {
        return fs.lstatSync('../library/iconsetsPro/'+dir).isDirectory()
    })
    for (var key in dirs) {
        if(fs.existsSync('../library/iconsetsPro/'+dirs[key]+'.js')){
            del('../library/iconsets/'+dirs[key]+'.js')
        }
        var getContent = require('../library/iconsetsPro/'+dirs[key]+'/index.js')
        var content = getContent()
        fs.writeFileSync('../iconset/'+dirs[key]+'.js', content.content)
    }
});

gulp.task('iconsets', function () {
    const dirs = fs.readdirSync('../library/iconsets').filter(function(dir) {
        return fs.lstatSync('../library/iconsets/'+dir).isDirectory()
    })
    for (var key in dirs) {
        if(fs.existsSync('../library/iconsets/'+dirs[key]+'.js')){
            del('../library/iconsets/'+dirs[key]+'.js')
        }
        var getContent = require('../library/iconsets/'+dirs[key]+'/index.js')
        var content = getContent()
        fs.writeFileSync('../library/iconsets/'+dirs[key]+'.js', content.content)
    }
    gulp.start(['scripts', 'styles'])
});


gulp.task('iconsets', function () {
    const dirs = fs.readdirSync('../library/iconsets').filter(function(dir) {
        return fs.lstatSync('../library/iconsets/'+dir).isDirectory()
    })
    for (var key in dirs) {
        if(fs.existsSync('../library/iconsets/'+dirs[key]+'.js')){
            del('../library/iconsets/'+dirs[key]+'.js')
        }
        var getContent = require('../library/iconsets/'+dirs[key]+'/index.js')
        var content = getContent()
        fs.writeFileSync('../library/iconsets/'+dirs[key]+'.js', content.content)
    }
    gulp.start(['scripts', 'styles'])
});

gulp.task('copy-fonts', function () {
    return gulp.src([
        "../library/icon-fonts/fonts/*",
        "../library/fontIconPicker/fonts/*",
        "../library/summernote/fonts/*"
    ])
        .pipe(gulp.dest(jsDest + 'fonts/'));
});

gulp.task('copy-img', function () {
    return gulp.src([
        "../library/bootstrap-colorpicker/img/*",
        "../library/select2/img/*"
    ])
        .pipe(gulp.dest(jsDest + 'img/'));
});

gulp.task('scripts', function () {
    return gulp.src([
        "../library/jquery-ui/jquery-ui.js",
        "../library/jquery.serializejson.js",
        "../library/underscore-min.js",
        "../library/bootstrap-colorpicker/bootstrap-colorpicker.min.js",
        "../library/bootstrap-switch/bootstrap-switch.min.js",
        "../library/summernote/summernote-cleaner.js",
        "../library/select2/select2.full.min.js",
        "../library/fontset.js",
        "../library/iconsets/*.js"
    ])
        .pipe(concat('vd-libraries.min.js'))
        .pipe(uglify())
        .pipe(gulp.dest(jsDest));
});

gulp.task('styles', function () {
    return gulp.src([
        "../library/icon-fonts/elusive-icons.scss",
        "../library/icon-fonts/fontawesome.scss",
        "../library/icon-fonts/ionicons.scss",
        "../library/icon-fonts/map-icons.scss",
        "../library/icon-fonts/material-design-iconic-font.scss",
        "../library/icon-fonts/octicons.scss",
        "../library/icon-fonts/typicons.scss",
        "../library/icon-fonts/weather-icons.scss",
        "../library/bootstrap-colorpicker/bootstrap-colorpicker.min.css",
        "../library/bootstrap-switch/bootstrap-switch.min.css",
        "../library/summernote/summernote.css",
        "../library/select2/select2-bootstrap.min.css",
        "../library/select2/select2.font.css",
        "../library/select2/select2.min.css",
        "../library/jquery-ui/jquery-ui.css"
    ])
    .pipe(sass({outputStyle: "compressed"}).on("error", sass.logError))
    .pipe(concat('vd-libraries.min.css'))
    .pipe(cleanCSS())
    .pipe(stripCssComments({preserve: false}))
    .pipe(gulp.dest(jsDest));
});

gulp.task('build_library', ['clean'], function () {
    gulp.start('copy')
});

gulp.task('sass', function () {
    return gulp.src(sassDest + '*.scss')

        .pipe(sourcemaps.init())
        .pipe(sass({outputStyle: 'compressed'}).on('error', sass.logError))
        .pipe(autoprefixer({
            browsers: ['last 15 versions']
        }))
        .pipe(sourcemaps.write('./'))
        .pipe(gulp.dest(sassDest))
        .pipe(browserSync.reload({stream: true}));
});

gulp.task('sass:watch', function () {
    gulp.watch([sassDest + '*.scss', sassDest + 'core/*.scss'], ['sass']);
});


gulp.task("browser_sync_init", function () {
    if (typeof process.env.HOST !== "undefined") {
        browserSync({
            proxy: process.env.HOST
        });
    }
})

gulp.task("build_sass", ["browser_sync_init"], function () {
    if (typeof process.env.HOST !== "undefined") {
        gulp.watch([
            baseDir + "/controller/extension/d_visual_designer/**/*.php",
            baseDir + "/view/template/extension/d_visual_designer/**/*.tag"
        ], browserSync.reload);
    }
    gulp.start(["sass", "sass:watch"]);
})

<|start_filename|>admin/view/javascript/d_visual_designer/model/block_front.js<|end_filename|>
(function(){
    /**
     * Full update block setting with Ajax Request
     */
    this.subscribe('block/setting/update', function(data){
        this.updateSetting(data)
    })

    this.updateSetting = function(data) {
        var block_info = this.getState().blocks[data.designer_id][data.block_id]
        var send_data = {
            setting: JSON.stringify(block_info.setting),
            type:block_info.type
        }
        var blocks = this.getState().blocks

        $.ajax({
            url: 'index.php?route=extension/d_visual_designer/designer/updateSetting&'+this.getState().config.url_token,
            type: 'post',
            dataType: 'json',
            data: send_data,
            context: this,
            success: function(json) {
                if(json['success']){
                    this.dispatch('block/setting/update/begin')
                    var blocks = this.getState().blocks

                    blocks[data.designer_id][data.block_id].setting = _.extend({}, json.setting)
                    this.updateState({blocks: blocks})
                    this.dispatch('history/backup', {block_id: data.block_id, designer_id: data.designer_id, fast: false})
                    if(!_.isUndefined(data.callback)) {
                        data.callback()
                    }
                }
            },
            complete: function() {
                this.dispatch('block/setting/update/end', {designer_id: data.designer_id})
            }
        })
    }


    /**
     * Update setting without Ajax request
     */

    this.subscribe('block/setting/fastUpdate', function(data){
        var blocks = this.getState().blocks
        blocks[data.designer_id][data.block_id].setting = _.extend({}, data.setting)
        this.updateState({blocks: blocks})
        this.dispatch('history/backup', {block_id: data.block_id, designer_id: data.designer_id, fast: true})
    })


    this.subscribe('block/layout/update', function(data){
        var block_config = _.find(this.getState().config.blocks, function(block){
            return block.type == data.type
        })
        var result = {
            new: [],
            update: [],
            delete: []
        }
        var indexSize = 0
        var blocks = this.getState().blocks
        var childBlocks = this.getBlocks(data.designer_id, data.block_id)
        if(_.size(data.size) >= _.size(childBlocks)){
            for (var key in childBlocks) {
                blocks[data.designer_id][childBlocks[key].id].setting.global.size=data.size[indexSize]
                result.update.push(childBlocks[key].id)
                indexSize++;
            }
        }

        if(_.size(data.size) < _.size(childBlocks)){
            for (var key in childBlocks) {
                if(indexSize < _.size(data.size)){
                    blocks[data.designer_id][childBlocks[key].id].setting.global.size=data.size[indexSize]
                    result.update.push(childBlocks[key].id)
                    
                } else {
                    result.delete.push(childBlocks[key].id)
                    delete blocks[data.designer_id][childBlocks[key].id];
                }
                indexSize++;
            }
        }

        this.updateState({blocks: blocks})

        if(_.size(data.size) > _.size(childBlocks)){
            for(var i=indexSize; i< _.size(data.size); i++){
                var block_id = this.newBlock(data.designer_id, block_config.setting.child, data.block_id, {size:data.size[i]});
                result.new.push(block_id)
            }
        }
        
        this.dispatch('block/layout/update/success', {result: result, designer_id: data.designer_id})
    })
        /**
     * Create new Block
     */
    this.newBlock = function(designer_id, type, target, default_setting, user_setting, edit_setting){
        var default_setting = _.isUndefined(default_setting) ? null : default_setting
        var user_setting = _.isUndefined(user_setting) ? null : user_setting
        var edit_setting = _.isUndefined(edit_setting) ? null : edit_setting

        var block_config = _.find(this.getState().config.blocks, function(block){
            return block.type == type
        })
        var childBlocks = this.getBlocks(designer_id, target)
        if(!_.isEmpty(childBlocks)){
            var lastBlock = _.max(childBlocks, function(value){
                return value.sort_order
            })
        } else{
            var lastBlock = {}
        }

        var blocks = this.getState().blocks
        var block_id = type+'_'+Math.random().toString(36).substring(2, 9)
        blocks[designer_id][block_id] = {
            setting: JSON.parse(JSON.stringify(block_config.setting_default)),
            parent: target,
            id: block_id,
            type: type,
            sort_order: !_.isEmpty(lastBlock)? lastBlock.sort_order + 1 : 0
        }
        if(!_.isNull(default_setting)){
            blocks[designer_id][block_id].setting.global = _.extend({}, blocks[designer_id][block_id].setting.global, default_setting)
        }
        if(!_.isNull(edit_setting)){
            blocks[designer_id][block_id].setting.edit = _.extend({}, blocks[designer_id][block_id].setting.edit, edit_setting)
        }
        if(!_.isNull(user_setting)){
            blocks[designer_id][block_id].setting.user = _.extend({}, blocks[designer_id][block_id].setting.user, user_setting)
        }
        this.updateState({blocks: blocks})
        if(_.isNull(user_setting) || _.isNull(edit_setting)) {
            this.dispatch('block/setting/update', {designer_id, block_id})
        }
        return block_id
    }
}.bind(d_visual_designer))()

<|start_filename|>admin/view/javascript/d_visual_designer/model/block.js<|end_filename|>
(function(){
    this.subscribe('block/new', function(data) {
        var block_config = _.find(this.getState().config.blocks, function(block){
            return block.type == data.type
        })
        var blocks = {}
        if(block_config.setting.level_min == 3 && data.level == 0){
            var section_wrapper_id = this.newBlock(data.designer_id, 'section_wrapper', '');
            var row_id = this.newBlock(data.designer_id, 'row', section_wrapper_id);
            var column_id = this.newBlock(data.designer_id, 'column', row_id);
            data.target = column_id
        }
        var new_block_id = this.newBlock(data.designer_id, data.type, data.target)
        if(block_config.setting.child) {
            var new_child_block_id = this.newBlock(data.designer_id, block_config.setting.child, new_block_id);
            var block_child_config = _.find(this.getState().config.blocks, function(block){
                return block.type == block_config.setting.child
            })
            if(block_child_config.setting.child) {
                this.newBlock(data.designer_id, block_child_config.setting.child, new_child_block_id);
            }
        }
        this.dispatch('block/create/success', {block_id: new_block_id, type: data.type, designer_id: data.designer_id})
    }.bind(this));
    this.subscribe('block/remove', function(data) {

        var block_config = _.find(this.getState().config.blocks, function(block){
            return block.type == data.type
        })

        var blocks = this.getState().blocks

        var parent = blocks[data.designer_id][data.block_id].parent

        if(parent != ''){
            var block_config_parent = _.find(this.getState().config.blocks, function(block){
                return block.type == blocks[data.designer_id][parent].type
            })

            var childBlocks = this.getBlocks(data.designer_id, parent)

            if (block_config_parent.setting.child && _.size(childBlocks) == 1){
                data.block_id = parent
            }
        }

        this.removeBlock(data.designer_id, data.block_id)
        
        this.dispatch('block/remove/success')
        $('body').trigger('remove_block_success', {'title': block_config.title});
    }.bind(this));

    this.removeBlock = function(designer_id, block_id) {
        
        var blocks = this.getState().blocks

        blocks[designer_id] = _.pick(blocks[designer_id], function(value, key, object){
            return block_id != value.id
        })

        this.updateState({blocks: blocks})
        
        var childBlocks = this.getBlocks(designer_id, block_id)
        if(_.size(childBlocks) > 0) {
            for(var key in childBlocks){
                this.removeBlock(designer_id, childBlocks[key].id)
            }
        }
    }

    this.subscribe('block/move/start', function(data) {
        var blocks = JSON.parse(JSON.stringify(this.getState().blocks))
        blocks[data.designer_id][data.block_id].parent = null
        this.updateState({blocks: blocks})
    })

    this.subscribe('block/move', function(data){
        var block_info = this.getState().blocks[data.designer_id][data.block_id]
        if(block_info.parent != data.target) {
            var childBlocks = this.getBlocks(data.designer_id, data.target)
            var blocks = JSON.parse(JSON.stringify(this.getState().blocks))
            for(var key in childBlocks) {
                if(blocks[data.designer_id][childBlocks[key].id].sort_order >= data.sort_order)
                {
                    blocks[data.designer_id][childBlocks[key].id].sort_order += 1
                }
            }

            blocks[data.designer_id][data.block_id].parent = data.target
            blocks[data.designer_id][data.block_id].sort_order = data.sort_order
            this.updateState({blocks: blocks})

            if(data.start_under_id != ''){
                var block_config_parent = _.find(this.getState().config.blocks, function(block){
                    return block.type == blocks[data.designer_id][data.start_under_id].type
                })
    
                var childBlocks = this.getBlocks(data.designer_id, data.start_under_id)
    
                if (block_config_parent.setting.child && _.size(childBlocks) == 0){
                    data.block_id = data.start_under_id
                    this.removeBlock(data.designer_id, data.block_id)
                }
            }
    
        }
        if(data.success){
            data.success()
        }
        this.dispatch('block/move/success')
    })
    this.subscribe('block/layout/update', function(data){
        var block_config = _.find(this.getState().config.blocks, function(block){
            return block.type == data.type
        })
        var indexSize = 0
        var blocks = this.getState().blocks
        var childBlocks = this.getBlocks(data.designer_id, data.block_id)
        if(_.size(data.size) >= _.size(childBlocks)){
            for (var key in childBlocks) {
                blocks[data.designer_id][childBlocks[key].id].setting.global.size=data.size[indexSize]
                indexSize++;
            }
        }

        if(_.size(data.size) < _.size(childBlocks)){
            for (var key in childBlocks) {
                if(indexSize < _.size(data.size)){
                    blocks[data.designer_id][childBlocks[key].id].setting.global.size=data.size[indexSize]
                    
                } else {
                    delete blocks[data.designer_id][childBlocks[key].id];
                }
                indexSize++;
            }
        }

        this.updateState({blocks: blocks})

        if(_.size(data.size) > _.size(childBlocks)){
            for(var i=indexSize; i< _.size(data.size); i++){
                this.newBlock(data.designer_id, block_config.setting.child, data.block_id, {size:data.size[i]});
            }
        }
        
        this.dispatch('block/layout/update/success')
    })
    /**
     * Full update block setting with Ajax Request
     */
    this.subscribe('block/setting/update', function(data){
        var block_info = this.getState().blocks[data.designer_id][data.block_id]
        var send_data = {
            setting: JSON.stringify(block_info.setting),
            type:block_info.type
        }
        var blocks = this.getState().blocks

        $.ajax({
            url: 'index.php?route=extension/d_visual_designer/designer/updateSetting&'+this.getState().config.url_token,
            type: 'post',
            dataType: 'json',
            data: send_data,
            context: this,
            success: function(json) {
                if(json['success']){
                    this.dispatch('block/setting/update/begin')
                    var blocks = this.getState().blocks

                    blocks[data.designer_id][data.block_id].setting = _.extend({}, json.setting)
                    this.updateState({blocks: blocks})
                    this.dispatch('history/backup', {block_id: data.block_id, designer_id: data.designer_id, fast: false})
                }
            },
            complete: function() {
                this.dispatch('block/setting/update/end', {designer_id: data.designer_id})
            }
        })
    })

    /**
     * Update setting without Ajax request
     */

    this.subscribe('block/setting/fastUpdate', function(data){
        var blocks = this.getState().blocks
        blocks[data.designer_id][data.block_id].setting = _.extend({}, data.setting)
        this.updateState({blocks: blocks})
        this.dispatch('history/backup', {block_id: data.block_id, designer_id: data.designer_id, fast: true})
    })
    /**
     * Clone target block
     */
    this.subscribe('block/clone', function(data){
        var block_info = this.getState().blocks[data.designer_id][data.target]
        var block_config = _.find(this.getState().config.blocks, function(block){
            return block.type == block_info.type
        })
        var block_id = this.newBlock(data.designer_id, block_info.type, block_info.parent, block_info.setting.global, block_info.setting.user, block_info.setting.edit)
        this.cloneBlocks(data.designer_id, block_info.id, block_id)
        this.dispatch('block/clone/success')
    })

    /**
     * Update param sort_order in child blocks for selected block
     */
    this.updateSortOrder = function(designer_id, block_id){
        var blocks = JSON.parse(JSON.stringify(this.getState().blocks))
        if(!_.isEmpty(block_id)){
            var container =$('#'+designer_id).find('[id='+block_id+']').children('.block-content')
        } else {
            var container = $('#'+designer_id).find('#sortable')
        }

        for (var i = 0; i < container.get(0).children.length; i++) {
            if(container.get(0).children[i].classList.contains('block-container')) {
                var index = container.get(0).children[i].id
                blocks[designer_id][index].sort_order = i
            }
        }

        this.updateState({blocks: blocks})
    }

    /**
     * Clone blocks by parent_id
     */
    this.cloneBlocks = function(designer_id, parent_id, new_parent_id){
        var blocks = this.getBlocks(designer_id, parent_id)
        if(_.size(blocks)){
            for (var key in blocks){
                var block_id = this.newBlock(designer_id, blocks[key].type, new_parent_id, blocks[key].setting.global, blocks[key].setting.user, blocks[key].setting.edit)
                this.cloneBlocks(designer_id, blocks[key].id, block_id)
            }
        }
    }

    /**
     * Create new Block
     */
    this.newBlock = function(designer_id, type, target, default_setting, user_setting, edit_setting){
        var default_setting = _.isUndefined(default_setting) ? null : default_setting
        var user_setting = _.isUndefined(user_setting) ? null : user_setting
        var edit_setting = _.isUndefined(edit_setting) ? null : edit_setting

        var block_config = _.find(this.getState().config.blocks, function(block){
            return block.type == type
        })
        var childBlocks = this.getBlocks(designer_id, target)
        if(!_.isEmpty(childBlocks)){
            var lastBlock = _.max(childBlocks, function(value){
                return value.sort_order
            })
        } else{
            var lastBlock = {}
        }

        var blocks = this.getState().blocks
        var block_id = type+'_'+Math.random().toString(36).substring(2, 9)
        blocks[designer_id][block_id] = {
            setting: JSON.parse(JSON.stringify(block_config.setting_default)),
            parent: target,
            id: block_id,
            type: type,
            sort_order: !_.isEmpty(lastBlock)? lastBlock.sort_order + 1 : 0
        }
        if(!_.isNull(default_setting)){
            blocks[designer_id][block_id].setting.global = _.extend({}, blocks[designer_id][block_id].setting.global, default_setting)
        }
        if(!_.isNull(edit_setting)){
            blocks[designer_id][block_id].setting.edit = _.extend({}, blocks[designer_id][block_id].setting.edit, edit_setting)
        }
        if(!_.isNull(user_setting)){
            blocks[designer_id][block_id].setting.user = _.extend({}, blocks[designer_id][block_id].setting.user, user_setting)
        }
        this.updateState({blocks: blocks})
        if(_.isNull(user_setting) || _.isNull(edit_setting)) {
            this.dispatch('block/setting/update', {designer_id, block_id})
        }
        return block_id
    }
}.bind(d_visual_designer))()

<|start_filename|>admin/view/javascript/d_visual_designer/main.js<|end_filename|>
function vd() {
    
    riot.observable(this);

    this.initState = function(state){
        this.state = state;
    };

    this.initLocal = function(local){
        this.local = local;
    };

    this.initOptions = function(options){
        this.options = options;
    };

    this.updateState = function(data){
        this.state = _.extend(this.state, data);
        riot.update();
    };

    this.getOptions = function(path) {
        var keys = path.split('.');
        var option = this.options;
        
        for (key in keys) {
            if(typeof option[keys[key]] === undefined){
                option = path;
                break
            } else {
                option = option[keys[key]]
            }
        }
        return option
    };

    this.getLocal = function(path) {
        var keys = path.split('.');
        var text = this.local;
        
        for (key in keys) {
            if(typeof text[keys[key]] == undefined){
                text = path;
                break
            } else {
                text = text[keys[key]]
            }
        }
        return text
    };

    this.getBlocks = function (designer_id, parent_id) {
        var childBlocks = _.extend({}, this.state.blocks[designer_id]);

        childBlocks = _.pick(childBlocks, function(item) {
            return item.parent === parent_id
        });

        var sortedBlocks = _.sortBy(childBlocks, function(value){
            return value.sort_order;
        });

        return sortedBlocks
    };

    this.getState = function(){
        return this.state
    };

    this.dispatch = function(action, state){
        this.trigger(action, state);
    };

    this.subscribe = function(action, callback){
        this.on(action, callback);
    }
}

var d_visual_designer = new vd();

<|start_filename|>admin/view/javascript/d_visual_designer/model/template.js<|end_filename|>
(function(){
    this.subscribe('template/save', function(data) {
        var blocks = this.getState().blocks[data.designer_id]
        var send_data = data.setting;
        send_data.setting = JSON.stringify(blocks)
        $.ajax({
            url: 'index.php?route=extension/d_visual_designer/template/save&'+this.getState().config.url_token,
            dataType: 'json',
            type: 'post',
            data: send_data,
            context: this,
            success: function(json){
                if(json.success) {
                    this.updateState({templates: json.templates})
                }
                this.dispatch('template/save/success', {designer_id: data.designer_id})
            }
        })
    });
    this.subscribe('template/load', function(data) {
        var send_data = {
            config: data.config,
            template_id: data.template_id
        }
        $.ajax({
            url: 'index.php?route=extension/d_visual_designer/template/getTemplate&'+this.getState().config.url_token,
            dataType: 'json',
            type: 'post',
            data: send_data,
            context: this,
            success: function(json){
                if(json.success){
                    var blocks = this.getState().blocks
                    blocks[data.designer_id] = json.setting
                    this.updateState({blocks:blocks})
                }
                this.dispatch('template/load/success', {designer_id: data.designer_id})
            }
        })
    });
}.bind(d_visual_designer))()

<|start_filename|>admin/view/javascript/d_visual_designer/model/frontend.js<|end_filename|>
(function(){
    this.initExternalDesigner = function(d_visual_designer) {
        this.external_vd = d_visual_designer
    }

    this.subscribe('designer/external/init', function(data) {
        this.external_vd = data.external_vd

        this.externalEvents()

        var blocks = JSON.parse(JSON.stringify(this.getStateExternal().blocks))

        for(var designer_id in blocks){
            this.dispatch('content/designer/init', {designer_id: designer_id})
            this.updateBlocks(designer_id, blocks[designer_id])
        }
        
        riot.update()
    })

    this.externalEvents = function(){
        this.external_vd.subscribe('popup/addBlock', function(data) { this.dispatch('popup/addBlock', data) }.bind(this)) 

        this.external_vd.subscribe('block/layout/begin', function(data) { this.dispatch('block/layout/begin', data) }.bind(this)) 

        this.external_vd.subscribe('block/setting/begin', function(data) { 
            this.dispatch('block/setting/begin', data) 
        }.bind(this)) 
        this.external_vd.subscribe('template/list', function(data) { 
            if(!_.isUndefined(data.empty)){
                this.dispatch('template/list', data) 
            }
        }.bind(this)) 

        this.external_vd.subscribe('save_content_success', function() {
            this.alert_handler(this.getLocal('designer.text_success_update'), 'success')
            this.dispatch('save_content_success')
        }.bind(this))

        this.external_vd.subscribe('save_content_permission', function() {
            this.alert_handler(this.getLocal('designer.error_permission'), 'error')
            this.dispatch('save_content_permission')
        }.bind(this))

        this.external_vd.subscribe('block/clone/complete', function(data) { 
            var block_info = this.getStateExternal().blocks[data.designer_id][data.block_id]
            var block_config = _.find(this.getState().config.blocks, function(block){
                return block.type == block_info.type
            })
            var blocks = this.getState().blocks
            blocks[data.designer_id][data.block_id] = JSON.parse(JSON.stringify(block_info))
            blocks[data.designer_id][data.block_id].setting.edit = block_config.setting_default.edit
            this.updateState({blocks: blocks})
        }.bind(this)) 
        this.external_vd.subscribe('block/create/success', function(data) { 
            var block_info = this.getStateExternal().blocks[data.designer_id][data.block_id]
            var block_config = _.find(this.getState().config.blocks, function(block){
                return block.type == block_info.type
            })
            var blocks = this.getState().blocks
            blocks[data.designer_id][data.block_id] = JSON.parse(JSON.stringify(block_info))
            blocks[data.designer_id][data.block_id].setting.edit = block_config.setting_default.edit
            this.updateState({blocks: blocks})
            this.dispatch('block/create/success', data) 
        }.bind(this)) 
        this.external_vd.subscribe('block/child/create', function(data){
            var blocks = this.getState().blocks
            var externalBlocks = this.external_vd.getState().blocks
            blocks[data.designer_id][data.block_id] = JSON.parse(JSON.stringify(externalBlocks[data.designer_id][data.block_id]))
            this.updateState({blocks: blocks})
            this.updateSetting(data)
        }.bind(this))
    }

    this.subscribe('block/new', function(data){
        this.external_vd.dispatch('block/new', data)
    })
    this.subscribe('block/setting/fastUpdate', function(data){
        this.external_vd.dispatch('block/setting/fastUpdate', data)
    })
    this.subscribe('block/setting/update', function(data){
        var blocks = this.getStateExternal().blocks
        if(!_.isUndefined(blocks[data.designer_id][data.block_id])){
            this.external_vd.dispatch('block/setting/update', data)
        }
    })
    this.subscribe('history/undo', function(data){
        this.external_vd.dispatch('history/undo', data)
    })
    this.subscribe('history/return', function(data){
        this.external_vd.dispatch('history/return', data)
    })
    this.subscribe('template/load/success', function(data){
        var blocks = this.getState().blocks[data.designer_id]
        var blocksExternal = this.getStateExternal().blocks
        blocksExternal[data.designer_id] = JSON.parse(JSON.stringify(blocks))
        this.updateStateExternal({blocks: blocksExternal})
        this.external_vd.dispatch('content/update', {designer_id: data.designer_id})
    })
    this.subscribe('block/layout/update/success', function(data){
        var blocks = this.getState().blocks[data.designer_id]
        var blocksExternal = this.getStateExternal().blocks
        var result = data.result
        for(var key in result.delete) {
            delete blocksExternal[data.designer_id][result.delete[key]]
        }
        for(var key in result.update) {
            blocksExternal[data.designer_id][result.update[key]].setting.global = blocks[result.update[key]].setting.global
        }
        for(var key in result.new) {
            blocksExternal[data.designer_id][result.new[key]] = blocks[result.new[key]]
            blocksExternal[data.designer_id][result.new[key]].setting.edit = false
            this.external_vd.dispatch('block/setting/update', {designer_id: data.designer_id, block_id: result.new[key]})
        }
        this.updateStateExternal({blocks: blocksExternal})
    })

    this.subscribe('template/save/success', function() {
        this.alert_handler(this.getLocal('designer.text_success_template_save'), 'success')
    })
    this.subscribe('clone_block_success', function(data) {
        this.alert_handler(data.title + this.getLocal('designer.text_success_clone_block'), 'success')
    })
    this.subscribe('remove_block_success', function(data) {
        this.alert_handler(data.title + this.getLocal('designer.text_success_remove_block'), 'success')
    })

    this.alert_handler = function(text, type)
    {
        if(type == 'error') {
            alertify.error(text);
        }
        if(type == 'success') {
            alertify.success(text);
        }
    }

    this.updateBlocks = function(designer_id, blocks) {
        $.ajax({
            url: this.getState().config.update_settings_url,
            data: {blocks: JSON.stringify(blocks)},
            type: 'post',
            dataType: 'json',
            context: this,
            success: function(json){
                if(json['success']) {
                    var vdBlocks = this.getState().blocks
                    vdBlocks[designer_id] = json.blocks
                    this.updateState({blocks:vdBlocks})
                }
            }
        })
    }

    this.getStateExternal = function(){
        return this.external_vd.state
    };
    this.updateStateExternal = function(data){
        return this.external_vd.updateState(data)
    };

    this.dispatchExternal = function(action, state){
        this.external_vd.trigger(action, state);
    };

    this.subscribeExternal = function(action, callback){
        this.external_vd.on(action, callback);
    }
}.bind(d_visual_designer))()

<|start_filename|>admin/view/stylesheet/d_shopunity/scss/image.css<|end_filename|>
.img-sm {
  width: 70px;
  overflow: hidden; }

/*# sourceMappingURL=image.css.map */


<|start_filename|>catalog/view/theme/default/stylesheet/d_visual_designer/gallery/gallery.css<|end_filename|>
.image-grid {
  overflow: auto;
  clear: both;
  list-style: none;
  padding: 0;
  margin: 0;
  margin-left: -20px; }
  .image-grid > li {
    margin-left: 20px; }
  .image-grid > img {
    width: 100%; }

.image-additional {
  max-width: 78px; }
  .image-additional a {
    margin-bottom: 20px;
    padding: 5px;
    display: block;
    border: 1px solid #ddd; }

.image-grid .image-additional {
  float: left;
  margin-left: 20px; }

/*# sourceMappingURL=gallery.css.map */


<|start_filename|>catalog/view/theme/default/javascript/d_visual_designer/model/style.js<|end_filename|>
(function(){
    /**
     * Render style for block
     */
    this.subscribe('block/style/update', function(data) {
        var block_info = this.getState().blocks[data.designer_id][data.block_id]

        var baseSelector = '[data-id='+data.block_id+'] .block-content[data-is="vd-block-'+block_info.type+'"]'
        $('head').find('style#'+data.designer_id+'-'+data.block_id).remove();

        var styleTag = '<style id="'+data.designer_id+'-'+data.block_id+'">';

        for(var key in data.styles) {
            styleTag += baseSelector+' '+key+'{';
            for(var name in data.styles[key]){
                if(data.styles[key][name]){
                    styleTag += name + ':'+data.styles[key][name]+';'
                }
            }
            styleTag += '}';
        }
        styleTag += '<style>'
        $('head').append(styleTag);
    })
    /**
     * Render style for block
     */
    this.subscribe('block/style/media/update', function(data) {
        var block_info = this.getState().blocks[data.designer_id][data.block_id]

        var baseSelector = '[data-id='+data.block_id+'] .block-content[data-is="vd-block-'+block_info.type+'"]'
        $('head').find('style#media-'+data.designer_id+'-'+data.block_id).remove();
        var medias = {
            'phone': '@media screen and (max-width: 767px)',
            'tablet': '@media screen and (min-width: 768px) and (max-width: 991px)',
            'desktop': '@media screen and (min-width: 992px)'
        }
        var styleTag = '<style id="media-'+data.designer_id+'-'+data.block_id+'">';

        for(var key in data.styles) {
            styleTag += medias[key]+'{';
 
            var styles = data.styles[key]
            for (var selector in styles) {
                styleTag += baseSelector+' '+selector+'{';
                for(var name in styles[selector]){
                    if(styles[selector][name]){
                        styleTag += name + ':'+styles[selector][name]+';'
                    }
                }
                styleTag += '}';
            }

            styleTag += '}';
        }
        styleTag += '<style>'
        
        $('head').append(styleTag);
    })
}.bind(d_visual_designer))()

<|start_filename|>admin/view/javascript/d_visual_designer/model/content.js<|end_filename|>
(function(){
    this.initContent = function(){
        $('.d_visual_designer, .d_visual_designer_backend').each(function(index, el){

            var send_data = {
                id: this.getState().config.id,
                route: this.getState().config.route
            }
            if(el.classList.contains('d_visual_designer_backend')){
                send_data['field_name'] = el.dataset["name"]
                if(typeof el.dataset["content"] !== 'undefined') {
                    send_data['content'] = el.dataset["content"]
                } else {
                    send_data['content'] = ''
                }
            } else {
                send_data['field_name'] = el.name
                send_data['content'] = el.value
            }

            $.ajax({
                url: 'index.php?route=extension/d_visual_designer/designer/loadSetting&'+this.getState().config.url_token,
                data: {setting: JSON.stringify(send_data)},
                type: 'post',
                dataType: 'json',
                context: this,
                beforeSend: function() {
                    if(el.classList.contains('d_visual_designer')){
                        $(el).closest('div').append('<div id="visual-designer-loader" class="la-ball-scale-ripple-multiple la-dark la-2x"><div></div><div></div><div></div></div>');
                        if ($(el).next().hasClass('note-editor')) {
                            $(el).next().fadeTo('slow', 0.5);
                        }else if ($(el).next().hasClass('cke')) {
                            $(el).next().fadeTo('slow', 0.5);
                        }  else {
                            $(el).fadeTo('slow', 0.5);
                        }
                    } else {
                        $(el).closest('div').append('<div id="visual-designer-static" class="la-ball-scale-ripple-multiple la-dark la-2x"><div></div><div></div><div></div></div>');
                    }
                },
                success: function(json){
                   if(json.success) {
                        var config = this.getState().config
                        config.independent[json.designer_id] = el.classList.contains('d_visual_designer_backend')?true: false
                        this.updateState({config: config})

                        var content = this.getState().content
                        content[json.designer_id] = json.content
                        this.updateState({content: content})

                        var blocks = this.getState().blocks
                        blocks[json.designer_id] = json.blocks
                        this.updateState({blocks: blocks})

                        $(el).before('<visual-designer id="'+json.designer_id+'" class="'+json.designer_id+'"></visual-designer>');
                        riot.mount(document.getElementById(json.designer_id))
                        this.dispatch('content/designer/init', {designer_id: json.designer_id})
                        setTimeout(function(){
                            this.dispatch('content/mode/update', {designer_id: json.designer_id, 'mode': 'designer'})
                        }.bind(this), 500)
                       
                   }
                },
                complete: function(){
                    if(el.classList.contains('d_visual_designer')){
                        $(el).closest('div').find('div#visual-designer-loader').remove();
                        if ($(el).next().hasClass('note-editor')) {
                            $(el).next().fadeTo('slow', 1);
                        } else if ($(el).next().hasClass('cke')) {
                            $(el).next().fadeTo('slow', 1);
                        } else {
                            $(el).fadeTo('slow', 1);
                        }
                    } else {
                        $(el).closest('div').find('div#visual-designer-static').remove();
                    }
                }
            })

        }.bind(this));
    };

    this.subscribe('block/setting/update/end', function(data){
        this.dispatch('designer/update/content', {designer_id: data.designer_id})
    });

    this.subscribe('content/mode/update',function(data){
        var config = this.getState().config
        config.mode[data.designer_id] = data.mode
        this.updateState({config: config})
        this.dispatch('content/mode/update/success', {designer_id: data.designer_id})
    });

    this.subscribe('content/update',function(data){
        var content = this.getState().content
        content[data.designer_id] = data.content
        this.updateState({content: content})
        this.dispatch('designer/update/blocks', {designer_id: data.designer_id, post_action: ['content/update/success'].concat(data.post_action)})
    });

    this.subscribe('content/codeview', function(data) {
        this.dispatch('designer/update/content', {designer_id: data.designer_id, post_action: ['content/codeview/success']})
    })
}.bind(d_visual_designer))()

<|start_filename|>catalog/view/theme/default/javascript/d_visual_designer/core/block.js<|end_filename|>
function vd_block(tag) {
    tag.mixin({store:d_visual_designer})
    tag.state = {
        top: tag.parent ? tag.parent.getState().top : tag,
        level: tag.parent.getState().level,
        setting: JSON.parse(JSON.stringify(tag.opts.block.setting))
    }

    tag.state_updated = false
    tag.state_always_update = !_.isUndefined(arguments[1])? !arguments[1] : false

    tag.shouldUpdate = function(data, nextOpts) {
        return !_.isEqual(nextOpts.block.setting, tag.getState().setting) || tag.state_updated || this.state_always_update
    }

    this.controlDisable = function() {
        this.state_always_update = true
    }

    tag.on('update', function(){
        tag.setState('setting', JSON.parse(JSON.stringify(tag.opts.block.setting)))
    })

    tag.on('updated', function(){
        tag.state_updated = false
    })

    tag.initState = function(data) {
        tag.setState(data)
        tag.state_updated = false
    }


    tag.getState = function() {
        if(!_.isUndefined(arguments[0])){
            return !_.isUndefined(tag.state[arguments[0]]) ? tag.state[arguments[0]] : null
        } else {
            return tag.state
        }
    }

    tag.setState = function(){
        tag.state_updated = false
        if(_.isObject(arguments[0])){
            for(var key in arguments[0]){
                tag.state_updated = !_.isEqual(arguments[0][key], tag.state[key])
                tag.state[key] = arguments[0][key]
            }
        } else {
            tag.state_updated = !_.isEqual(arguments[1], tag.state[arguments[0]])
            tag.state[arguments[0]] = arguments[1]
        }
    }
}

<|start_filename|>catalog/view/theme/default/javascript/d_visual_designer/model/block_front.js<|end_filename|>
(function(){
    /**
     * Full update block setting with Ajax Request
     */
    this.subscribe('block/setting/update', function(data){
        var block_info = this.getState().blocks[data.designer_id][data.block_id]
        var send_data = {
            setting: JSON.stringify(block_info.setting),
            type:block_info.type
        }
        var blocks = this.getState().blocks

        $.ajax({
            url: 'index.php?route=extension/d_visual_designer/designer/updateSetting',
            type: 'post',
            dataType: 'json',
            data: send_data,
            context: this,
            success: function(json) {
                if(json['success']){
                    this.dispatch('block/setting/update/begin')
                    var blocks = this.getState().blocks

                    blocks[data.designer_id][data.block_id].setting = _.extend({}, json.setting)
                    this.updateState({blocks: blocks})
                    this.dispatch('history/backup', {block_id: data.block_id, designer_id: data.designer_id, fast: false})
                    if(this.getState().config.save_change){
                        this.dispatch('content/save', {designer_id: data.designer_id});
                    }
                }
            },
            complete: function() {
                setTimeout(function() {
                    this.dispatch('block/setting/update/end')
                }.bind(this), 2000);
                
            }
        })
    })
}.bind(d_visual_designer))()

<|start_filename|>admin/view/javascript/d_visual_designer/library/iconsets/fontawesome/index.js<|end_filename|>
module.exports = function(){
    var icons = require('./icons.json')
    var content = "window.iconset = window.iconset? window.iconset : {};window.iconset['fontawesome']=["
    delete icons[0]
    for (var key in icons) {
        var styles = icons[key].styles
        for(var styleKey in styles) {
            content +='"fa'+styles[styleKey].substring(0,1)+' fa-'+key+'",';
        }
    }
    content+="]"

    return {content: content}
}

<|start_filename|>catalog/view/javascript/d_visual_designer/gulp/gulpfile.js<|end_filename|>
/*jslint node: true */
"use strict";

var gulp = require("gulp");
var concat = require("gulp-concat");
var uglify = require("gulp-uglify");
var cleanCSS = require("gulp-clean-css");
var del = require("del");
var sass = require("gulp-sass");
var sourcemaps = require("gulp-sourcemaps");
var autoprefixer = require("gulp-autoprefixer");
var browserSync = require("browser-sync");
var path = require("path");

//script paths
var jsDest = "../dist/";

var sassDest = "../../../theme/default/stylesheet/d_visual_designer/";

var baseDir = path.resolve(__dirname, "../../../../");

gulp.task("clean", function () {
    return del(jsDest + "**", {force: true});
});

gulp.task("copy", ["copy-fonts"], function () {
    gulp.start(["basic-scripts", "basic-styles"]);
});

gulp.task("copy-fonts", function () {
    return gulp.src([
        "../library/icon-fonts/fonts/*"
    ])
        .pipe(gulp.dest(jsDest + "fonts/"));
});

gulp.task("basic-scripts", function () {
    return gulp.src([
        "../library/sharrre/jquery.sharrre.min.js",
        "../library/magnific/jquery.magnific-popup.min.js",
        "../library/chart/Chart.min.js",
        "../library/pie-chart.js",
        "../library/circle-progress.js",
        "../library/owl-carousel/owl.carousel.min.js",
        "../library/webfont.js",
        "../library/underscore-min.js",
        "../library/fastclone.js"
    ])
        .pipe(concat("vd-basic-libraries.min.js"))
        .pipe(uglify())
        .pipe(gulp.dest(jsDest));
});

gulp.task("basic-styles", function () {
    return gulp.src([
        "../library/sharrre/style.css",
        "../library/magnific/magnific-popup.css",
        "../library/owl-carousel/owl.carousel.scss",
        "../library/owl-carousel/owl.transitions.scss",
        "../library/animate.css",
        "../library/icon-fonts/elusive-icons.scss",
        "../library/icon-fonts/fontawesome.scss",
        "../library/icon-fonts/ionicons.scss",
        "../library/icon-fonts/map-icons.scss",
        "../library/icon-fonts/material-design-iconic-font.scss",
        "../library/icon-fonts/octicons.scss",
        "../library/icon-fonts/typicons.scss",
        "../library/icon-fonts/weather-icons.scss"
    ])
        .pipe(sass({outputStyle: "compressed"}).on("error", sass.logError))
        .pipe(concat("vd-basic-libraries.min.css"))
        .pipe(cleanCSS())
        .pipe(gulp.dest(jsDest));
});


gulp.task("build_library", ["clean"], function () {
    gulp.start("copy")
});

gulp.task("sass", function () {
    return gulp.src(sassDest + "*.scss")
        .pipe(sourcemaps.init())
        .pipe(sass({outputStyle: "compressed"}).on("error", sass.logError))
        .pipe(autoprefixer({
            browsers: ["last 15 versions"]
        }))
        .pipe(sourcemaps.write("./"))
        .pipe(gulp.dest(sassDest))
        .pipe(browserSync.reload({stream: true}));
});
gulp.task("sass:blocks", function () {
    return gulp.src(sassDest + "blocks/*.scss")
        .pipe(sourcemaps.init())
        .pipe(sass({outputStyle: "compressed"}).on("error", sass.logError))
        .pipe(autoprefixer({
            browsers: ["last 15 versions"]
        }))
        .pipe(sourcemaps.write("./blocks/"))
        .pipe(gulp.dest(sassDest+'blocks/'))
        .pipe(browserSync.reload({stream: true}));
});

gulp.task("sass:watch", function () {
    gulp.watch([sassDest + "*.scss", sassDest + "core/*.scss", sassDest+"blocks/*.scss"], ["sass", "sass:blocks"]);
});

gulp.task("browser_sync_init", function () {
    if (typeof process.env.HOST !== "undefined") {
        browserSync({
            proxy: process.env.HOST
        });
    }
})

gulp.task("build_sass", ["browser_sync_init"], function () {
    if (typeof process.env.HOST !== "undefined") {
        gulp.watch([
            baseDir + "/controller/extension/d_visual_designer/**/*.php",
            baseDir + "/view/theme/default/template/extension/d_visual_designer/**/*.tag"
        ], browserSync.reload);
    }
    gulp.start(["sass", "sass:blocks", "sass:watch"]);
})

<|start_filename|>catalog/view/theme/default/javascript/d_visual_designer/core/component.js<|end_filename|>
function vd_component(tag) {
    tag.mixin({store:d_visual_designer})
    
    tag.state = {
        top: !_.isNull(tag.parent) ? tag.parent.getState().top : tag,
        level: !_.isNull(tag.parent) ? tag.parent.getState().level: null,
        opts: JSON.parse(JSON.stringify(tag.opts))
    }

    tag.state_updated = false
    tag.state_always_update = !_.isUndefined(arguments[1])? !arguments[1] : false

    tag.shouldUpdate = function(data, nextOpts) {
        return !_.isEqual(nextOpts, tag.getState('opts')) || tag.state_updated || this.state_always_update
    }

    this.controlDisable = function() {
        this.state_always_update = true
    }

    tag.on('update', function(){
        tag.setState('opts', JSON.parse(JSON.stringify(tag.opts)))
    })

    tag.on('updated', function(){
        tag.state_updated = false
    })

    tag.initState = function(data) {
        tag.setState(data)
        tag.state_updated = false
    }

    tag.getState = function() {
        if(!_.isUndefined(arguments[0])){
            return !_.isUndefined(tag.state[arguments[0]]) ? tag.state[arguments[0]] : null
        } else {
            return tag.state
        }
    }

    tag.setState = function(){
        if(_.isObject(arguments[0])){
            for(var key in arguments[0]){
                tag.state[key] = arguments[0][key]
            }
        } else {
            tag.state[arguments[0]] = arguments[1]
        }

        tag.state_updated = true
    }
}

<|start_filename|>catalog/view/theme/default/javascript/d_visual_designer/core/sortable.js<|end_filename|>
function vd_sortable(options) {

    this.under_id = ''
    this.drag_id = ''
    this.drag_type = ''
    this.start_under_id = ''
    this.dragging = false
    this.itemsHorizontal = false
    this.allowZones = null
    this.sortableItems = {}
    this.store = d_visual_designer

    var defaults = {
        designer_id: ''
    }

    for (var name in defaults) {
        !(name in options) && (options[name] = defaults[name]);
    }

    if (!$('.helper-sortable').size()) {
        $('body').append('<div class="helper-sortable" style="display:none;"></div>')
    }

    $('body').mousemove(function (event) {
        if(this.dragging) {
            $('.helper-sortable').css({
                left: event.pageX,
                top: event.pageY
            });
        }
    }.bind(this));

    /**
    * Init Sortable for new tag
    **/
    this.store.subscribe('sortable/init', function(data){
        if(options.designer_id == data.designer_id) {
            if(data.block_id != ''){
                var block_info = this.store.getState().blocks[data.designer_id][data.block_id]
                var block_config = _.find(this.store.getState().config.blocks, function(block){
                    return block.type == block_info.type
                })
                if(!block_config.setting.child && block_config.setting.child_blocks) {
                    if (!this.sortableItems.all) {
                        this.sortableItems.all = {}
                    }
                    if(!this.sortableItems.all[block_info.id]){
                        this.sortableItems.all[block_info.id] = {
                            id: block_info.id,
                            block_config: block_config
                        }
                    }
                }
                if(block_config.setting.child && block_config.setting.child_blocks){
                    var child_type = block_config.setting.child
                    if (!this.sortableItems[child_type]) {
                        this.sortableItems[child_type] = {}
                    }
                    if(!this.sortableItems[child_type][block_info.id]){
                        this.sortableItems[child_type][block_info.id] = {
                            id: block_info.id,
                            block_config: block_config
                        }
                    }
                }
            } else {
                if (!this.sortableItems['row']) {
                    this.sortableItems['row'] = {
                        '': {
                            id: ''
                        }
                    }
                }
            }
        }
    }.bind(this))

    /**
    * Start new drag and drog
    **/
    this.store.subscribe('block/drag/start', function (data) {
        if(options.designer_id == data.designer_id) {
            var block_config = _.find(this.store.getState().config.blocks, function (block) {
                return block.type == data.type
            })
            var block_info = this.store.getState().blocks[data.designer_id][data.block_id]
            $('.helper-sortable').html('<img class="icon" src="' + block_config.image + '" width="32px" height="32px"/>' + block_config.title)
            $('.helper-sortable').show()

            var drag = this.store.getState().drag

            drag[data.designer_id] = true
            this.drag_id = data.block_id

            this.under_id = block_info.parent
            this.start_under_id = block_info.parent
            this.start_sort_order = block_info.sort_order
            this.drag_type = data.type
            this.dragging = true

            if (this.sortableItems[this.drag_type]) {
                this.allowZones = this.sortableItems[this.drag_type]
                this.itemsHorizontal = false
            } else {
                this.allowZones = this.sortableItems.all
                this.itemsHorizontal = false
            }

            for (var key in this.allowZones) {
                var blockId = this.allowZones[key].id
                if (key != '') {
                    var container = $('.block-container[data-id="' + blockId + '"]')
                } else {
                    var container = $('[id=sortable][data-vd_id="' + options.designer_id + '"][data-id="' + blockId + '"]')
                }
                container.on("mouseenter", function (event) {
                    if (this.dragging) {
                        var underId = $(event.currentTarget).data('id')
                        this.store.dispatch('block/placeholder/show', {
                            designer_id: options.designer_id,
                            block_id: underId
                        })
                        this.under_id = underId
                    }
                }.bind(this));
                container.on("mouseleave", function (event) {
                    if (this.dragging) {
                        var underId = $(event.currentTarget).data('id')
                        this.store.dispatch('block/placeholder/hide', {
                            designer_id: options.designer_id,
                            block_id: underId
                        })
                        this.under_id = this.start_under_id
                    }
                }.bind(this));
            }

            this.store.dispatch('block/move/start', {designer_id: options.designer_id, block_id: this.drag_id})
            this.store.dispatch('block/placeholder/show', {designer_id: options.designer_id, block_id: this.under_id})
            this.store.updateState({drag: drag})
        }

    }.bind(this))

    $('body').on('mouseup', function(){
        if(this.dragging){
            this.store.dispatch('sortable/end', {designer_id: options.designer_id, block_id: this.start_under_id, sort_order: this.start_sort_order})
        }
    }.bind(this))

    /**
    * End Drag and Drop
    **/
    this.store.subscribe('sortable/end', function(data){
        if(data.designer_id == options.designer_id) {
            $('.helper-sortable').hide()
            for (var key in this.allowZones) {
                var blockId = this.allowZones[key].id
                if (key != '') {
                    var container = $('.block-container[data-id="' + blockId + '"]')
                } else {
                    var container = $('[id=sortable][data-vd_id="' + options.designer_id + '"][data-id="' + blockId + '"]')
                }
                container.off("mouseenter");
                container.off("mouseleave");
            }
            this.allowZones = null
            this.dragging = false
            this.store.dispatch('block/placeholder/hide', {designer_id: options.designer_id, block_id: this.under_id})
            this.store.dispatch('block/move', {
                block_id: this.drag_id,
                target: this.under_id,
                start_under_id: this.start_under_id,
                designer_id: options.designer_id,
                sort_order: data.sort_order,
                success: function () {
                    var drag = this.store.getState().drag
                    drag[options.designer_id] = false
                    this.store.updateState({drag: drag})
                }.bind(this)
            })
            this.start_under_id = '';
        }
    }.bind(this))
}

<|start_filename|>catalog/view/javascript/d_visual_designer/library/fastclone.js<|end_filename|>
_.cloneToDepth = _.clone = function(obj, depth) {
    if (typeof obj !== 'object') return obj;
    var clone = _.isArray(obj) ? obj.slice() : _.extend({}, obj);
    if (!_.isUndefined(depth) && (depth > 0)) {
      for (var key in clone) {
        clone[key] = _.clone(clone[key], depth-1);
      }
    }
    return clone;
  };

<|start_filename|>admin/view/javascript/d_visual_designer/model/history.js<|end_filename|>
(function(){
    this.subscribe('history/backup', function(data) {
        this.updateHistory(data.designer_id, data.block_id, data.fast)
    });
    this.subscribe('history/undo', function(data) {
        this.undoHistory(data.designer_id, data.block_id, data.fast)
    });
    this.subscribe('history/return', function(data) {
        this.returnHistory(data.designer_id, data.block_id)
    });
    this.subscribe('content/designer/init', function(data){
        this.state.history[data.designer_id] = {}
    })
    this.updateHistory = function(designer_id, block_id, fast) {
        var block_info = this.getState().blocks[designer_id][block_id]
        if(_.isUndefined(this.state.history[designer_id][block_id])){
            this.state.history[designer_id][block_id] = []
        }
        _.mapObject(this.state.history[designer_id][block_id], function(value) {
            value.active = false
            return value
        })
        this.state.history[designer_id][block_id].push({setting: JSON.parse(JSON.stringify(block_info.setting)), active: true, fast: fast, sort_order: _.size(this.state.history[designer_id][block_id])})
    }
    this.getHistory = function(designer_id, block_id) {
        if(_.isUndefined(this.state.history[designer_id][block_id])){
            return []
        } else {
            return this.state.history[designer_id][block_id]
        }
    }
    this.undoHistory = function(designer_id, block_id, fast) {
        var history = this.getHistory(designer_id, block_id)
        var currentHistory = _.where(history, {active: true})
        history = _.filter(history, function(value){ return value.fast == fast })
        var minHistory = _.min(history, function(value){ return value.sort_order})
        if(!_.isEmpty(currentHistory) && currentHistory[0].sort_order > minHistory.sort_order ) {
            var lastIndex = _.findLastIndex(history, function(value){ return value.sort_order < currentHistory[0].sort_order})
            var nextHistory = history[lastIndex]
            var blocks = this.getState().blocks

            blocks[designer_id][block_id].setting = nextHistory.setting

            this.state.history[designer_id][block_id] = _.map(this.state.history[designer_id][block_id], function(value) {
                if(value.sort_order == nextHistory.sort_order) {
                    value.active = true
                } else {
                    value.active = false
                }
                return value
            })

            this.updateState({blocks: blocks})
        }
    }
    this.returnHistory = function(designer_id, block_id) {
        var history = this.getHistory(designer_id, block_id)
        var currentHistory = _.where(history, {active: true})
        var maxHistory = _.max(history, function(value){ return value.sort_order})
        if(!_.isEmpty(currentHistory) && currentHistory[0].sort_order < maxHistory.sort_order ) {
            var lastIndex = _.findIndex(history, function(value){ return value.sort_order > currentHistory[0].sort_order})
            var nextHistory = history[lastIndex]
            var blocks = this.getState().blocks

            blocks[designer_id][block_id].setting = nextHistory.setting

            this.state.history[designer_id][block_id] = _.map(this.state.history[designer_id][block_id], function(value) {
                if(value.sort_order == nextHistory.sort_order) {
                    value.active = true
                } else {
                    value.active = false
                }
                return value
            })

            this.updateState({blocks: blocks})
        }
    }
}.bind(d_visual_designer))()

<|start_filename|>admin/view/javascript/d_visual_designer/model/designer.js<|end_filename|>
(function(){

    this.subscribe('designer/update/blocks',function(data){
        var contents = this.getState().content
        $.ajax({
            url: 'index.php?route=extension/d_visual_designer/designer/updateContent&'+this.getState().config.url_token,
            dataType: 'json',
            type: 'post',
            data: {content: contents[data.designer_id]},
            context: this,
            success: function(json){
                if(json.success) {
                    var blocks = this.getState().blocks
                    blocks[data.designer_id] = json.setting
                    this.updateState({blocks: blocks})

                    if(!_.isEmpty(data.post_action)){
                        for (var key in data.post_action) {
                            this.dispatch(data.post_action[key], {designer_id: data.designer_id})
                        }
                    }

                    this.dispatch('designer/update/blocks/success', {designer_id: data.designer_id})
                }
            }
        })
    });

    this.subscribe('designer/update/content',function(data){
        var blocks = this.getState().blocks[data.designer_id]
        var send_data = {
            setting: JSON.stringify(blocks)
        }
        $.ajax({
            url: 'index.php?route=extension/d_visual_designer/designer/getContent&'+this.getState().config.url_token,
            dataType: 'json',
            type: 'post',
            data: send_data,
            context: this,
            success: function(json){
                
                if(json.success) {
                    content = this.getState().content
                    content[data.designer_id] = json.content
                    this.updateState({content: content})
                    if(!_.isEmpty(data.post_action)){
                        for (var key in data.post_action) {
                            this.dispatch(data.post_action[key], {designer_id: data.designer_id})
                        }
                    }
                    this.dispatch('designer/update/content/success', {designer_id: data.designer_id, content: json.content})
                } else {
                    this.dispatch('designer/update/content/failed', {designer_id: data.designer_id, error: json.error})
                }
            }
        })
    })

    this.subscribe('designer/frontend',function(data){
        var config = this.getState().config

        var url_param = ''

        if(!_.isUndefined(config.route_info['frontend_full_param']) && config.route_info.frontend_full_param){
            url_param = '&field_name='+data.fieldName
        }
        $.ajax({
            type: 'post',
            url: data.form.attr('action'),
            data: data.form.serialize(),
            context: this,
            success: function(response) {
                window.location.href = config.frontend+url_param
            }
        });
    })
}.bind(d_visual_designer))()