All files / src/helperComponents AceEditor.vue

2.7% Statements 1/37
0% Branches 0/14
0% Functions 0/9
2.7% Lines 1/37
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166                                      1x                                                                                                                                                                                                                                                                                                    
<template>
    <div class="aceEditor--main">
        <div class="aceEditor--topbar">
            <div class="aceEditor--subcontainer" v-if="showThemeToggle">
                <button @click="toggleDarkMode" class="btn btn-xs btn-default"> {{'Toggle dark mode'|translate}}</button>
            </div>
            <div class="aceEditor--subcontainer" v-if="showLangSelector">
                <select class="aceEditor--langselect" v-model="lang">
                    <option value="html">HTML</option>
                    <option value="javascript">JavaScript</option>
                    <option value="css">CSS</option>
                </select>
            </div>
        </div>
        <div class="aceEditor--editor" :id="thisId" ></div>
    </div>
</template>
 
<script>
import debounce from 'lodash/debounce';
 
export default {
    name: 'AceEditor',
    props: {
        value: {
            type: String,
            required: true,
        },
        applyExternalChange: {type: Boolean, default: false},
        thisId: {
            type: String,
            default: ()=>`vue-ace-editor-${Math.round(Math.random()*100000)}`
        },
        options: {type: Object, default: ()=> {
            return {
                autoScrollEditorIntoView: true,
                wrap: true,
                maxLines: 80,
                minLines: 10
            }}
        },
        showLangSelector: {type: Boolean, default: true},
        showThemeToggle: {type: Boolean, default: true},
        baseLang: {type: String, default: 'html'}
    },
    data: function() {
        return {
            lang: 'html',
            darkMode: false,
            editor: null,
            contentBackup: "",
        };
    },
    methods: {
        toggleDarkMode(){
            if(this.darkMode) {
                this.editor.setTheme("ace/theme/solarized_light");
            } else {
                this.editor.setTheme("ace/theme/solarized_dark");
            }
            this.darkMode = !this.darkMode;
        },
        resizeEditor(){
            event.target.innerHeight
            this.editor.resize();
        }
    },
    watch: {
        lang: function(newLang) {
            if(this.editor != null) {
                this.editor.getSession().setMode("ace/mode/" + newLang);
            }
        },
        value: function(newValue) {
            if(this.editor != null && this.applyExternalChange) {
                this.editor.setValue((this.value || ''), 1);
                this.$emit('external-change-applied');
            }
        },
    },
    beforeDestroy: function() {
        this.editor.destroy();
        this.editor.container.remove();
    },
    created(){
        this.lang = this.baseLang;
    },
    mounted() {
        this.editor = ace.edit(this.thisId);
 
        this.$emit("init", this.editor);
 
        this.editor.setOption("enableemmet", true);
        this.editor.getSession().setMode("ace/mode/" + this.lang);
        this.editor.setTheme("ace/theme/solarized_light");
        
        this.editor.setValue((this.value || ''), 1);
        this.contentBackup = this.value;
 
        this.editor.on("change", () => {
            let content = this.editor.getValue();
            this.$emit("input", content);
            this.contentBackup = content;
        });
 
        if (this.options != null) {
            this.editor.setOptions(this.options);
        }
 
        jQuery('.aceEditor--main').on('resize', (e)=>{
            this.editor.resize(true);
        });
 
        jQuery('#'+this.thisId).on('contextmenu', (e)=>{
            e.preventDefault();
            e.stopPropagation();
            return false;
        });
    }
};
</script>
 
<style lang="scss" scoped>
    .aceEditor--main {
        padding: 0.2rem;
 
        .aceEditor--topbar{
            height: 3rem;
            padding: 0.2rem;
            background-color: rgb(196, 196, 196);
            display: flex;
            flex-wrap: nowrap;
            align-items: space-around;
            align-content: space-around;
            .aceEditor--subcontainer {
                flex: 1;
                &:first-child {
                    text-align: left;
                }
                &:last-child {
                    text-align: right;
                }
            }
            .aceEditor--darkmodeswitch {
                border-radius: 0;
                align-self: flex-start;
                padding: 0.4rem;
                height: 2.2rem;
                margin: 0.2rem;
            }
 
            .aceEditor--langselect {
                border-radius: 0;
                align-self: flex-end;
                height: 2.2rem;
                margin: 0.2rem;
            }
        }
 
        .aceEditor--editor {
            min-height: 10rem;
            resize: vertical;
        }
    }
</style>