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 });