1 define(["core"], function() { 2 3 window.codeMirrors = []; 4 var crTheme = "monokai", 5 saveUrl = "/common/js/test/business/saveCode.php", 6 itemHtml = '<div style="margin:10px;"><h2 style="font-size:16px;margin-bottom:5px;"></h2><button attr="run">运行代码</button><button attr="format">整理选中代码</button></div>', 7 itemNames = []; 8 9 var getSelectedRange = function(editor) { 10 return { from: editor.getCursor(true), to: editor.getCursor(false) }; 11 }; 12 13 var showInfo = function(msg, isError) { 14 var mask = $("<div class=\"we_mask\"></div>").appendTo("body"); 15 var info = $("<div class=\"coderunner_info\"></div>").appendTo("body"); 16 info.append("<p>"+msg+"</p>"); 17 18 var time = isError ? 2500 : 1000; 19 20 setTimeout(function() { 21 mask.remove(); 22 info.remove(); 23 }, time); 24 }; 25 26 var getMode = function(v) { 27 switch (v) { 28 case "javascript": 29 return "javascript"; 30 break; 31 case "html": 32 return "htmlmixed"; 33 break; 34 case "css": 35 return "css"; 36 break; 37 default: 38 return "javascript"; 39 } 40 }; 41 42 var execCode = function(editor, div, mode) { 43 var v = editor.getValue(); 44 switch (mode) { 45 case "javascript": 46 $we.utils.exec(v); 47 break; 48 case "htmlmixed": 49 var demoDiv = div.find('div[attr="demo"]'); 50 if (!demoDiv.length) { 51 demoDiv = $("<div attr=\"demo\" style=\"border: 1px solid #eee;\"></div>").appendTo(div); 52 } 53 demoDiv.html("<h2>Demo:</h2>"+v); 54 break; 55 case "css": 56 $we.utils.addStyleSheet(v); 57 break; 58 } 59 }; 60 61 var saveCode = function(editor, index) { 62 if (window.location.protocol != "http:" || 63 ($we.conf.ENV.__SITE != "localhost" && $we.conf.ENV.__SITE != "dev")) { 64 showInfo("当前环境不允许保存", true); 65 return; 66 } 67 if (!confirm("确定要保存代码到本地么?")) return; 68 var v = editor.getValue(); 69 $.post(saveUrl, { 70 code: v, 71 index: index 72 }, function(data) { 73 if (typeof data == "object") { 74 if (data.errno == 0) { 75 showInfo(data.msg); 76 } else { 77 showInfo(data.msg, true); 78 } 79 } 80 }, "json"); 81 }; 82 83 var setItem = function(index) { 84 var v = $(this).val(); 85 var div = $(itemHtml).appendTo($("body")); 86 var mode_v = getMode($(this).attr("class")); 87 88 try { 89 var cm = CodeMirror(div[0], { 90 value: v, 91 mode: mode_v, 92 lineNumbers: true, 93 indentUnit: 4, 94 tabSize: 4, 95 indentWithTabs: true, 96 theme: crTheme, 97 onKeyEvent: function(o, e) { 98 var code = e.keyCode || e.which; 99 if (e.type != "keydown") return; 100 101 if (e.metaKey || e.ctrlKey) { 102 if (code == 82) { 103 execCode(o, div, mode_v); 104 e.stop(); 105 return; 106 } 107 if (code == 83) { 108 saveCode(o, index); 109 e.stop(); 110 return; 111 } 112 } 113 if (e.altKey) { 114 altScroll(code); 115 e.stop(); 116 return; 117 } 118 } 119 }); 120 } catch (e) { return; } 121 122 123 div.attr("id", "we_coderunner_" + (index+1)); 124 125 codeMirrors.push(cm); 126 127 div.find('button[attr="run"]').on("click", function() { 128 execCode(cm, div, mode_v); 129 }); 130 131 div.find('button[attr="format"]').on("click", function() { 132 var range = getSelectedRange(cm); 133 cm.autoFormatRange(range.from, range.to); 134 }); 135 136 div.find("h2").html(index + 1 + ". " + $(this).attr("title")); 137 itemNames.push($(this).attr("title")); 138 139 if ($(this).attr("autorun") === "true") { 140 execCode(cm, div, mode_v); 141 } 142 143 $(this).remove(); 144 }; 145 146 var scrollTo = function(to, cb) { 147 var body = (window.opera) ? (document.compatMode == "CSS1Compat" ? $('html') : $('body')) : $('html,body'); 148 cb = cb || function(){}; 149 150 $(body).animate({scrollTop: $(to).offset().top}, 300, function() { 151 window.location.hash = to; 152 cb(); 153 }); 154 }; 155 156 var altScroll = function(code) { 157 var dirStart = 49, 158 dirEnd = 48 + itemNames.length; 159 if (code >= dirStart && code <= dirEnd) { 160 var num = code-48, 161 menu_i = "#we_coderunner_"+num; 162 scrollTo(menu_i, function() { 163 codeMirrors[num-1].focus(); 164 }); 165 } 166 }; 167 168 var _dirHtml = [ 169 '<div class="we_sh_directory">', 170 '<h3>目录</h3>', 171 '<a class="toggler" href="javascript:void(0);">[收起]</a>', 172 '<div attr="content"><ol></ol></div>', 173 '</div>' 174 ].join(""), 175 _dirItemHtml = '<li><a href="#we_coderunner_$index$" name="#we_coderunner_$index$">$name$</a></li>'; 176 177 var setDir = function(items) { 178 var dir = $(_dirHtml).appendTo($("body")); 179 180 dir.find('a.toggler').click(function(e) { 181 var el = e.target; 182 dir.find('div[attr="content"]').slideToggle(300, function() { 183 if ($(this).is(":hidden")) 184 $(el).html("[展开]"); 185 else 186 $(el).html("[收起]"); 187 }); 188 }); 189 190 $(items).each(function(index) { 191 var str = $we.string.replaceTmpl(_dirItemHtml, { 192 index: index+1, 193 name: this.toString() 194 }); 195 var item = $(str).appendTo(dir.find("ol")); 196 197 item.find("a").click(function(e) { 198 var el = e.target, 199 to = $(el).attr("name"); 200 201 scrollTo(to); 202 e.preventDefault(); 203 }); 204 }); 205 206 $(document).on("keydown", function(e) { 207 var code = e.keyCode || e.which; 208 if (e.altKey) { 209 altScroll(code); 210 } 211 }); 212 }; 213 214 var setCss = function() { 215 var css = [ 216 '.CodeMirror { border: 1px solid #eee; }', 217 '.CodeMirror-scroll {', 218 'height: auto;', 219 'overflow-y: hidden;', 220 'overflow-x: auto;', 221 '};'].join(""); 222 $we.utils.addStyleSheet(css); 223 }; 224 225 var run = function() { 226 $('textarea[attr="coderunner"]').hide(); 227 228 var path = $we.conf.ENV.__PLUGIN + '/codemirror/'; 229 require(["plugin/codemirror/codemirror-compressed"], function() { 230 $('textarea[attr="coderunner"]').each(setItem); 231 setDir(itemNames); 232 setCss(); 233 }); 234 $we.requireCss(path+"lib/codemirror.css"); 235 $we.requireCss(path+'theme/'+crTheme+'.css'); 236 }; 237 238 return function() { 239 $(document).ready(function() { 240 run(); 241 }); 242 }; 243 });