htmlEditor.js 9.3 KB
define('htmlEditor', ['ace', 'ace/snippets/scopes'], function () {
    var snippetManager = ace.require("ace/snippets").snippetManager;
    var Editor = ace.require("./editor").Editor;

    ace.config.set("basePath", "/mobilemode/admin/dep/ace");
    
    (function() {
        var insertSnippet = snippetManager.insertSnippet;
        
        snippetManager.insertSnippet = function(editor, content) {
			var FOCUS_PLACEHOLDER = "::focus"; // 需要focus的占位符
            var mode = editor.session.getMode();

            if(!content.match(/\${.+}|\$[0-9]/g) && ~mode.$id.match(/(javascript|html)/g)) { // mode中默认${1}, ${2}...为占位符, 当为默认mode时, 则不转义$
                content = content.replace(/\$/g, "\\$"); // $作为函数关键字时 需要转移 如果$f,$u等函数
            }
            
			insertSnippet.call(snippetManager ,editor, content);

            if(~content.indexOf(FOCUS_PLACEHOLDER)) { // 有占位符时, 删除占位符的同时, 将光标定位到该处
                editor.find(FOCUS_PLACEHOLDER);
                editor.remove(FOCUS_PLACEHOLDER);
            }
            editor.focus();
        };

        this.insertSnippet = function(content) {
            snippetManager.insertSnippet(this, content);
        };
        
    }).call(Editor.prototype);    

    function importCssText() {
        if(document.head.querySelector("#htmlEditorCss")) return;

        var style = document.createElement("style");

        style.type = "text/css";
        style.id = "htmlEditorCss";
        style.innerHTML = "\
.ace_editor * {\
    font: 12px/normal 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace;\
}";
        document.head.appendChild(style);
    }

    // 修复 #620952 设计器源码模式内容太多时最后一行被遮挡的问题
    // https://github.com/ajaxorg/ace/issues/3856
    var dom = ace.require("ace/lib/dom")

    dom.scrollbarWidth_orig = dom.scrollbarWidth_orig || dom.scrollbarWidth
    dom.scrollbarWidth = function (doc) { return Math.max(20, dom.scrollbarWidth_orig(doc)) }

    return {
        editor: function (el, mode, includeScopes) {
            var editor = ace.edit(el);

            importCssText(); // 修复编辑器字体受样式影响的问题
            editor.session.setMode("ace/mode/" + mode);
            editor.$blockScrolling = Infinity;
            editor.setShowPrintMargin(false); // 移除打印边距
            // enable autocompletion and snippets
            editor.setOptions({
                enableBasicAutocompletion: true,
                enableSnippets: true,
                enableLiveAutocompletion: true,
                includeScopes: includeScopes
            });
            editor.focus();

            return editor;
        },
        ace: ace
    };
});

define("custom-language_tools", ['language-tools'], function () {

    ace.define("ace/autocomplete/Mobile_NS_completer", ["ace/snippets", "require"], function (require) {
        var snippetManager = require("../snippets").snippetManager,
            lang = require("../lib/lang");

        return {
            getCompletions: function (editor, session, pos, prefix, callback, autocomplete) {
                var snippetMap = snippetManager.snippetMap;
                var completions = [];
                var isMobNS = false, identifier;
                var state = editor.session.getState(pos.row);
                // 获取是否与mode的关键字匹配 如果没有匹配 说明当前输入的上下文中不允许输入js
                var keyCompletions = session.$mode.getCompletions(state, session, pos, prefix).length; 
                var includeScopes = editor.$includeScopes || [];

                if (!keyCompletions || !~includeScopes.indexOf("Mobile_NS")) return callback(null, completions);

                this.identifier.every(function(ident) {
                    if(ident == prefix.slice(0, ident.length)) {
                        isMobNS = true;
                        identifier = ident;
                        return false;
                    }
                    return true;
                });

                var snippets = snippetMap.Mobile_NS || [];

                for (var i = snippets.length; i--;) {
                    var s = snippets[i],
                        isMatch = s.content.toLowerCase().indexOf(prefix.toLowerCase()) != -1 && prefix.indexOf(identifier) != -1,
                        caption = s.name || s.tabTrigger;

                    if (!caption || !isMobNS)
                        continue;
                    
                    completions.push({
                        value: isMatch ? identifier + caption : '', // filter会首先根据去value的值 否则caption
                        caption: caption,
                        title: s.title,
                        snippet: s.content,
                        meta: s.tabTrigger && !s.name ? s.tabTrigger + "\u21E5 " : "snippet",
                        type: "snippet",
                        layout: s.layout
                    });
                }

                if(isMobNS && autocomplete) {
                    autocomplete.base = session.doc.createAnchor(pos.row, pos.column - prefix.length + identifier.length);
                }
                
                callback(null, completions);
            },
            getDocTooltip: function (item) {
                if (item.layout) {
                    item.docHTML = [
                        "<b>", lang.escapeHTML(item.title), "</b>", "<hr></hr>", item.layout
                    ].join("");
                }
            },
            identifierRegexps: [/[a-zA-Z_\.\\$]/],
            identifier: ['Mobile_NS.', '$']
        };
    });

    ace.require(["ace/ext/language_tools", "ace/autocomplete/Mobile_NS_completer"], function (tool, Mobile_NS_completer) {
        tool.addCompleter(Mobile_NS_completer);
    });
});

// 自定义ace属性
define('ace/snippets/scopes', ['custom-language_tools', 'jquery'], function () {
    var loadSnippetText = {
        "Mobile_NS": {
            init: function () {
                return $.ajax({
                    url: "/api/mobilemode/admin/function/snippet",
                    cache: false
                });
            },
            snippets: ""
        }
    };

    var parseSnippets = function (snippets) {
        var snippetText = "";

        snippets = (snippets || []).map(function (snippet, index) {
                var snippetTextObj = {};

                snippetTextObj.content = snippet.snippet;
                snippetTextObj.snippet = snippet.snippetFace;
                snippetTextObj.name = snippet.snippetFace;
                snippetTextObj.layout = snippet.noteContent;
                snippetTextObj.title = snippet.noteTitle;

                return snippetTextObj;
            });

        return snippets;
    };

    ace.define('ace/snippets/scopes', ["require", "exports", "module"], function (require) {
        var Editor = require('ace/editor').Editor,
            config = require('ace/config'),
            snippetManager = require("../snippets").snippetManager;

        snippetManager.files = {} || snippetManager.files;

        var loadSnippetFile = function (id) {
            if (!id || snippetManager.files[id])
                return;
            var snippetFilePath = id.replace("mode", "snippets"),
                mode = id.replace(/.*\/(.*)$/g, "$1");
            snippetManager.files[id] = {};
            config.loadModule(snippetFilePath, function (m) {
                if (m) {
                    snippetManager.files[id] = m;
                    if (!m.snippets && m.snippetText) {
                        if (loadSnippetText[mode]) {
                            m.snippets = loadSnippetText[mode].snippets;
                        } else {
                            m.snippets = snippetManager.parseSnippetFile(m.snippetText);
                        }
                    }

                    snippetManager.register(m.snippets || [], mode);//m.scope
                    if (m.includeScopes) {
                        snippetManager.snippetMap[m.scope].includeScopes = m.includeScopes;
                        m.includeScopes.forEach(function (x) {
                            loadSnippetFile("ace/mode/" + x);
                        });
                    }
                }
            });
        };

        config.defineOptions(Editor.prototype, "editor", {
            includeScopes: { // 设置依赖mode
                set: function (val) {
                    if (Array.isArray(val) && val.length > 0) {
                        val.forEach(function (x) {
                            if (loadSnippetText[x]) {
                                $.when(loadSnippetText[x].init()) // 异步加载关键字列表
                                    .done(function (res) {
                                        var snippets = JSON.parse(res).data;

                                        loadSnippetText[x].snippets = parseSnippets(snippets);
                                        loadSnippetFile("ace/mode/" + x);
                                    });
                            } else {
                                loadSnippetFile("ace/mode/" + x);
                            }
                        });
                    }
                },
                value: []
            }
        });
    });

    return ace.require(["ace/snippets/scopes"]);
});