美文网首页程序员
使用chrome extension解决gitlab在线编辑时输

使用chrome extension解决gitlab在线编辑时输

作者: w3cmark | 来源:发表于2017-11-29 11:44 被阅读0次

    先上一张gif效果图:

    gitlab-chrome-input-bug.gif

    我们团队内部搭建了gitlab作为代码托管,目前的版本是GitLab Community Edition 8.17.5 9a564a8,在升级到这个版本时,发现在chrome下,在线编辑无法正常输入中文了,出现如上动图的错乱效果,而在firefox是正常的。

    一开始怀疑是chrome更新版本后的问题,但是github的在线编辑是正常的,后来通过chrome开发者工具debug,发现是gitlab使用的在线编辑器有问题。无论gitlab还是github,这种在线编辑代码都是借助于一些web编辑器实现的,比如aceeditor,而这里gitlab用的正是aceeditor,因此第一时间跑去aceeditor官网,嗯,人家的是正常的。所以gitlab出现这种问题的原因就是aceeditor编辑器的版本在新版chrome下的bug。

    找到问题源头,解决办法也就有眉目了:

    • 直接更新GitLab Community Edition版本到最新版,看看官方是否更换了aceeditor编辑器的版本解决了这个问题。

    • 升级gitlab,可能会担心升级过程会不会有什么新问题,特别是大版本更新就更要慎重。既然这样,那就直接自己在现版本手动去更新aceeditor编辑器,理论上找到gitlab的安装,找到编辑器的相关文件,替换成新的版本。前提是你要摸索清gitlab的目录结构,完整替换编辑器版本。听起来有点麻烦,而且也有一定风险~

    • 这里介绍另一种思路,通过chrome extension在打开编辑页时替换编辑器。这种不是治本的方案,但感觉也是一种思路,刚好团队本身有一个在用从chrome插件,所以把解决方案放进现有的插件即可。这个方案可能适用性和参考意义不大,但这种思路说不定能给到你一些新的想法呢

    下面详细说下第三种方案的操作细节:
    (涉及到chrome extension的相关细节,这里就不详细描述,默认你拥有chrome extension的开发能力)

    下载最新版的aceeditor编辑器

    这一步很简单,直接去官网下载即可aceeditor,然后把编辑器的相关文件放到chrome插件下,比如:

    |--src  //插件源码
    |    |--js
    |    |    |--lib
    |    |    |    |--src-min-noconflict  //aceeditor
    

    到时候打包插件时会一起打包的。

    加载编辑器文件

    什么时候去加载新版的编辑器文件呢?因为我们只需要在gitlab编辑界面才用到,所以通过URL匹配来识别当前是编辑界面,然后再去加载aceeditor相关文件。另外还可以根据当前的编辑文件类型,来加载对应的编辑器文件,然后再通过chrome.tabs.executeScript来实现。

    chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {
        // when complete
        if (changeInfo.status === 'complete') {
    
            if(/https:\/\/(你的系统域名)\/.+\/(edit|blob)\/.+/ig.test(tab.url)){
                var newurl = tab.url.replace('(你的系统域名)',''),
                    r_file_suffix = /((?!(\.|\/))[\s\S])+\.([a-z]+)/ig;
                newurl.match(r_file_suffix);
                var file_suffix = RegExp.$3,
                    jsFiles = [
                    '/js/lib/jquery-2.1.3.min.js',
                    '/js/lib/src-min-noconflict/ace.js'
                    ];
                //根据文件类型
                switch(file_suffix){
                    case 'js':
                    jsFiles.push('/js/lib/src-min-noconflict/mode-javascript.js');
                    break;
                    case 'tmpl':
                    jsFiles.push('/js/lib/src-min-noconflict/mode-html.js');
                    break;
                    case 'md':
                    jsFiles.push('/js/lib/src-min-noconflict/mode-markdown.js');
                    break;
                    default :
                    jsFiles.push('/js/lib/src-min-noconflict/mode-'+ file_suffix +'.js');
                }
                //替换编辑器以及保存等逻辑
                jsFiles.push('/js/fixgitlabinput.js');
    
                chrome.tabs.executeScript(tabId, {
                    code: 'var injected = window.octotreeInjected; window.octotreeInjected = true; injected;',
                    runAt: 'document_start'
                }, function (res) {
    
                    var cssFiles = ['/css/fixgitlabedit.css'];
    
                    eachTask([function (cb) {
                      return eachItem(cssFiles, inject('insertCSS'), cb);
                    }, function (cb) {
                      return eachItem(jsFiles, inject('executeScript'), cb);
                    }]);
    
                    function inject(fn) {
                      return function (file, cb) {
                        chrome.tabs[fn](tabId, { file: file, runAt: 'document_start' }, cb);
                      };
                    }
                });
            }
        }
    });
    

    替换操作

    加载到编辑器文件,那最后一步就是进行编辑器替换,以及新编辑器的初始化,最后还要在保存时把新编辑器的内容提交。
    这些逻辑放进了单独js文件fixgitlabinput.js处理。
    这里我选择通过插入一个新的按钮来进行新编辑器的切换:

    var fix_btn = '<span class="fix-btn" id="js-fix-btn">中文编辑</span>';
    $('body').append(fix_btn);
    

    当点击这个按钮时,会做两件事:
    (1)根据当前地址,获取目前编辑文件的内容
    (2)把获取到的文件内容用新的编辑器初始化,并隐藏旧版的编辑器,显示新版的编辑器

    var fix_btn = '<a href="#fixgitlabedit" class="fix-btn" id="js-fix-btn">中文编辑</a>';
    $('body').append(fix_btn);
    
    if(location.hash == '#fixgitlabedit'){
         //传入当前地址和文件类型
        fixeditor(curhref, file_mode);
        $('#js-fix-btn').hide();
    }
    
    function fixeditor(curhref, file_mode){
        //隐藏旧的编辑器
        $('#editor').hide();
    
        var fix_div = '<pre id="js-fix-editor" class="fix-editor"><pre>',
            new_editor,
            $old_editor_par = $('#editor').parent();
        // 插入新的编辑器
        $old_editor_par.append(fix_div);
    
        var $form_actions = $('form .form-actions');
    
        //隐藏旧的保存按钮
        $form_actions.find('.btn.commit-btn.js-commit-button.btn-create').hide();
        var new_submit_btn = '<button name="button" class="btn btn-create new-submit-btn">Commit Changes</button>';
    
        //插入新的保存按钮
        $form_actions.prepend(new_submit_btn);
    
        //保存操作
        $form_actions.on('click', '.new-submit-btn', function(e){
            if($(this).hasClass('disabled')){return;}
            e.preventDefault();
            $(this).addClass('disabled');
            //获取编辑器的内容,aceeditor提供的方法
            var new_val = new_editor.getValue();
            $('#file-content').val(new_val);
            $("form.form-horizontal.js-quick-submit.js-requires-input.js-edit-blob-form")[0].submit();
        })
    
        // 根据当前地址获取文件内容
        getHttpRequest(curhref, function(data){
            var r_editor_text = /\<pre class="js-edit-mode-pane" id="editor"\>([\s\S]*)\<\/pre\>/igm;
            data.match(r_editor_text);
            var editor_text = RegExp.$1;
            $old_editor_par.find('#js-fix-editor').html(editor_text);
            //获取编辑器的内容,aceeditor提供的方法
            new_editor = ace.edit("js-fix-editor");
            new_editor.session.setMode("ace/mode/"+file_mode);
        });
    }
    
    function getHttpRequest(href, callback){
        var xhr = new XMLHttpRequest();
        xhr.open("GET", href, true);
        xhr.onreadystatechange = function() {
          if (xhr.readyState == 4) {
            var data = xhr.responseText;
            typeof callback == 'function' && callback(data);
          }
        }
        xhr.send();
    }
    

    到这里,就可以正常输入中文并保存了,对于没有接触chrome插件开发的人来说可能比较麻烦,so,就当新想法的折腾呗~

    相关文章

      网友评论

        本文标题:使用chrome extension解决gitlab在线编辑时输

        本文链接:https://www.haomeiwen.com/subject/pxsubxtx.html