summaryrefslogtreecommitdiff
path: root/codemirror_ui/js/codemirror-ui.js
diff options
context:
space:
mode:
Diffstat (limited to 'codemirror_ui/js/codemirror-ui.js')
-rw-r--r--codemirror_ui/js/codemirror-ui.js505
1 files changed, 505 insertions, 0 deletions
diff --git a/codemirror_ui/js/codemirror-ui.js b/codemirror_ui/js/codemirror-ui.js
new file mode 100644
index 0000000..d246132
--- /dev/null
+++ b/codemirror_ui/js/codemirror-ui.js
@@ -0,0 +1,505 @@
+/* Demonstration of embedding CodeMirror in a bigger application. The
+* interface defined here is a mess of prompts and confirms, and
+* should probably not be used in a real project.
+*/
+//var CodeMirrorUI = Class.create();
+
+function CodeMirrorUI(place, options, mirrorOptions) {
+ this.initialize(place, options, mirrorOptions);
+}
+
+CodeMirrorUI.prototype = {
+
+ initialize: function(textarea, options, mirrorOptions) {
+ var defaultOptions = {
+ searchMode: 'popup', // other options are 'inline' and 'dialog'. The 'dialog' option needs work.
+ imagePath: 'images/silk',
+ path: 'js',
+ buttons: ['search', 'undo', 'redo', 'jump', 'reindentSelection', 'reindent','about'],
+ saveCallback: function() {},
+ }
+ this.textarea = textarea
+ this.options = options;
+ this.setDefaults(this.options, defaultOptions);
+
+ this.buttonDefs = {
+ 'save': ["Save", "save", this.options.imagePath + "/page_save.png", this.save],
+ 'search': ["Search/Replace", "find_replace_popup", this.options.imagePath + "/find.png", this.find_replace_popup],
+ 'searchClose': ["Close", "find_replace_popup_close", this.options.imagePath + "/cancel.png", this.find_replace_popup_close],
+ 'searchDialog': ["Search/Replace", "find_replace_window", this.options.imagePath + "/find.png", this.find_replace_window],
+ 'undo': ["Undo", "undo", this.options.imagePath + "/arrow_undo.png", this.undo],
+ 'redo': ["Redo", "redo", this.options.imagePath + "/arrow_redo.png", this.redo],
+ 'jump': ["Jump to line #", "jump", this.options.imagePath + "/page_go.png", this.jump],
+ 'reindentSelection': ["Reformat selection", "reindentSelect", this.options.imagePath + "/text_indent.png", this.reindentSelection],
+ 'reindent': ["Reformat whole document", "reindent", this.options.imagePath + "/page_refresh.png", this.reindent],
+ 'about': ["About CodeMirror-UI", "about", this.options.imagePath + "/help.png", this.about]
+ };
+
+ //place = CodeMirror.replace(place)
+
+ this.home = document.createElement("div");
+ this.textarea.parentNode.insertBefore(this.home, this.textarea);
+ /*if (place.appendChild)
+ place.appendChild(this.home);
+ else
+ place(this.home);
+ */
+ this.self = this;
+
+ var onChange = this.editorChanged.cmuiBind(this);
+ // preserve custom onChance handler
+ if (mirrorOptions.onChange) {
+ mirrorOptions.onChange = function() {
+ mirrorOptions.onChange();
+ onChange();
+ }
+ } else {
+ mirrorOptions.onChange = onChange;
+ }
+ mir = CodeMirror.fromTextArea(this.textarea, mirrorOptions);
+ //console.log(mir);
+ this.mirror = mir;
+
+ this.initButtons();
+
+ //this.initWordWrapControl(); // CodeMirror v2 does not support word wrapping
+
+ if (this.options.searchMode == 'inline') {
+ this.initFindControl();
+ } else if (this.options.searchMode == 'popup') {
+ this.initPopupFindControl();
+ }
+
+ if (this.saveButton) this.addClass(this.saveButton,'inactive');
+ if (this.undoButton) this.addClass(this.undoButton,'inactive');
+ if (this.redoButton) this.addClass(this.redoButton,'inactive');
+ },
+ setDefaults: function(object, defaults) {
+ for (var option in defaults) {
+ if (!object.hasOwnProperty(option))
+ object[option] = defaults[option];
+ }
+ },
+ toTextArea: function() {
+ this.home.parentNode.removeChild(this.home);
+ this.mirror.toTextArea();
+ },
+ initButtons: function() {
+ this.buttonFrame = document.createElement("div");
+ this.buttonFrame.className = "codemirror-ui-clearfix codemirror-ui-button-frame";
+ this.home.appendChild(this.buttonFrame);
+ for (var i = 0; i < this.options.buttons.length; i++) {
+ var buttonId = this.options.buttons[i];
+ var buttonDef = this.buttonDefs[buttonId];
+ this.addButton(buttonDef[0], buttonDef[1], buttonDef[2], buttonDef[3], this.buttonFrame);
+ }
+
+ //this.makeButton("Search", "search");
+ //this.makeButton("Replace", "replace");
+ //this.makeButton("Current line", "line");
+ //this.makeButton("Jump to line", "jump");
+ //this.makeButton("Insert constructor", "macro");
+ //this.makeButton("Indent all", "reindent");
+ },
+ /*
+ * This is left over from the MirrorFrame demo.
+ * Get rid of it quick.
+ */
+ /*
+ makeButton : function(name, action){
+ var button = document.createElement("input");
+ button.type = "button";
+ button.value = name;
+ this.home.appendChild(button);
+ button.onclick = function(){
+ self[action].call(self);
+ };
+ },
+ */
+ createFindBar: function() {
+ var findBar = document.createElement("div");
+ findBar.className = "codemirror-ui-find-bar";
+
+ this.findString = document.createElement("input");
+ this.findString.type = "text";
+ this.findString.size = 8;
+
+ this.findButton = document.createElement("input");
+ this.findButton.type = "button";
+ this.findButton.className = "button mainaction";
+ this.findButton.value = "Find";
+ this.findButton.onclick = function(){this.find()}.cmuiBind(this);
+
+ this.connect(this.findString, "keyup", function(e){
+ var code = e.keyCode;
+ if (code == 13){
+ this.find(this.mirror.getCursor(false))
+ }else{
+ if(!this.findString.value == ""){
+ this.find(this.mirror.getCursor(true))
+ }
+ }
+ this.findString.focus();
+
+ }.cmuiBind(this) );
+
+ var regLabel = document.createElement("label");
+ regLabel.title = "Regular Expressions"
+ this.regex = document.createElement("input");
+ this.regex.type = "checkbox"
+ this.regex.className = "codemirror-ui-checkbox"
+ regLabel.appendChild(this.regex);
+ regLabel.appendChild(document.createTextNode("RegEx"));
+
+ var caseLabel = document.createElement("label");
+ caseLabel.title = "Case Sensitive"
+ this.caseSensitive = document.createElement("input");
+ this.caseSensitive.type = "checkbox"
+ this.caseSensitive.className = "codemirror-ui-checkbox"
+ caseLabel.appendChild(this.caseSensitive);
+ caseLabel.appendChild(document.createTextNode("A/a"));
+
+ this.replaceString = document.createElement("input");
+ this.replaceString.type = "text";
+ this.replaceString.size = 8;
+
+ this.connect(this.replaceString, "keyup", function(e){
+ var code = e.keyCode;
+ if (code == 13){
+ this.replace()
+ }
+ }.cmuiBind(this) );
+
+ this.replaceButton = document.createElement("input");
+ this.replaceButton.type = "button";
+ this.replaceButton.className = "button";
+ this.replaceButton.value = "Replace";
+ this.replaceButton.onclick = this.replace.cmuiBind(this);
+
+ var replaceAllLabel = document.createElement("label");
+ replaceAllLabel.title = "Replace All"
+ this.replaceAll = document.createElement("input");
+ this.replaceAll.type = "checkbox"
+ this.replaceAll.className = "codemirror-ui-checkbox"
+ replaceAllLabel.appendChild(this.replaceAll);
+ replaceAllLabel.appendChild(document.createTextNode("All"));
+
+ findBar.appendChild(this.findString);
+ findBar.appendChild(this.findButton);
+ findBar.appendChild(caseLabel);
+ findBar.appendChild(regLabel);
+
+ findBar.appendChild(this.replaceString);
+ findBar.appendChild(this.replaceButton);
+ findBar.appendChild(replaceAllLabel);
+ return findBar;
+ },
+ initPopupFindControl: function() {
+ var findBar = this.createFindBar();
+
+ this.popupFindWrap = document.createElement("div");
+ this.popupFindWrap.className = "codemirror-ui-popup-find-wrap";
+
+ this.popupFindWrap.appendChild(findBar);
+
+ var buttonDef = this.buttonDefs['searchClose'];
+ this.addButton(buttonDef[0], buttonDef[1], buttonDef[2], buttonDef[3], this.popupFindWrap);
+
+ this.buttonFrame.appendChild(this.popupFindWrap);
+
+ },
+ initFindControl: function() {
+ var findBar = this.createFindBar();
+ this.buttonFrame.appendChild(findBar);
+ },
+ find: function( start ) {
+ var isCaseSensitive = this.caseSensitive.checked;
+ if(start == null){
+ start = this.mirror.getCursor();
+ }
+ var findString = this.findString.value;
+ if (findString == null || findString == '') {
+ alert('You must enter something to search for.');
+ return;
+ }
+ if (this.regex.checked) {
+ findString = new RegExp(findString, !isCaseSensitive ? "i" : "");
+ }
+
+ this.cursor = this.mirror.getSearchCursor(findString, start, !isCaseSensitive );
+ var found = this.cursor.findNext();
+ if (found) {
+ this.mirror.setSelection(this.cursor.from(),this.cursor.to())
+ //this.cursor.select();
+ } else {
+ if (confirm("No more matches. Should we start from the top?")) {
+ this.cursor = this.mirror.getSearchCursor(findString, 0, !isCaseSensitive);
+ found = this.cursor.findNext();
+ if (found) {
+ this.mirror.setSelection(this.cursor.from(),this.cursor.to())
+ //this.cursor.select();
+ } else {
+ alert("No matches found.");
+ }
+ }
+ }
+ },
+ replace: function() {
+ var findString = this.findString.value,
+ replaceString = this.replaceString.value,
+ isCaseSensitive = this.caseSensitive.checked,
+ isRegex = this.regex.checked,
+ regFindString = isRegex ? new RegExp(findString, !isCaseSensitive ? "i" : "") : "";
+
+ if (this.replaceAll.checked) {
+ var cursor = this.mirror.getSearchCursor(isRegex ? regFindString : findString, 0, !isCaseSensitive);
+ while (cursor.findNext())
+ this.mirror.replaceRange(
+ isRegex ? cursor.pos.match[0].replace(regFindString, replaceString) : replaceString
+ ,cursor.from(),cursor.to());
+ //cursor.replace(this.replaceString.value);
+ } else {
+ this.mirror.replaceRange(
+ isRegex ? this.cursor.pos.match[0].replace(regFindString, replaceString) : replaceString
+ ,this.cursor.from(),this.cursor.to())
+ //this.cursor.replace(this.replaceString.value);
+ this.find();
+ }
+ },
+ initWordWrapControl: function() {
+ var wrapDiv = document.createElement("div");
+ wrapDiv.className = "codemirror-ui-wrap"
+
+ var label = document.createElement("label");
+
+ this.wordWrap = document.createElement("input");
+ this.wordWrap.type = "checkbox"
+ this.wordWrap.checked = true;
+ label.appendChild(this.wordWrap);
+ label.appendChild(document.createTextNode("Word Wrap"));
+ this.wordWrap.onchange = this.toggleWordWrap.cmuiBind(this);
+ wrapDiv.appendChild(label);
+ this.buttonFrame.appendChild(wrapDiv);
+ },
+ toggleWordWrap: function() {
+ if (this.wordWrap.checked) {
+ this.mirror.setTextWrapping("nowrap");
+ } else {
+ this.mirror.setTextWrapping("");
+ }
+ },
+ addButton: function(name, action, image, func, frame) {
+ var button = document.createElement("a");
+ //button.href = "#";
+ button.className = "codemirror-ui-button " + action;
+ button.title = name;
+ button.func = func.cmuiBind(this);
+ button.onclick = function(event) {
+ //alert(event.target);
+ event.target.func();
+ return false;
+ //this.self[action].call(this);
+ //eval("this."+action)();
+ }
+ .cmuiBind(this, func);
+ var img = document.createElement("img");
+ img.src = image;
+ img.border = 0;
+ img.func = func.cmuiBind(this);
+ button.appendChild(img);
+ frame.appendChild(button);
+ if (action == 'save') {
+ this.saveButton = button;
+ }
+ if (action == 'undo') {
+ this.undoButton = button;
+ }
+ if (action == 'redo') {
+ this.redoButton = button;
+ }
+ },
+ classNameRegex: function(className) {
+ var regex = new RegExp("(.*) *" + className + " *(.*)");
+ return regex;
+ },
+ addClass: function(element, className) {
+ if (!element.className.match(this.classNameRegex(className))) {
+ element.className += " " + className;
+ }
+ },
+ removeClass: function(element, className) {
+ var m = element.className.match(this.classNameRegex(className))
+ if (m) {
+ element.className = m[1] + " " + m[2];
+ }
+ },
+ editorChanged: function() {
+ if(!this.mirror) {
+ return
+ }
+ var his = this.mirror.historySize();
+ if (his['undo'] > 0) {
+ this.removeClass(this.saveButton, 'inactive');
+ this.removeClass(this.undoButton, 'inactive');
+ } else {
+ this.addClass(this.saveButton, 'inactive');
+ this.addClass(this.undoButton, 'inactive');
+ }
+ if (his['redo'] > 0) {
+ this.removeClass(this.redoButton, 'inactive');
+ } else {
+ this.addClass(this.redoButton, 'inactive');
+ }
+ //alert("undo size = " + his['undo'] + " and redo size = " + his['redo']);
+ },
+ save: function() {
+ this.options.saveCallback();
+ this.addClass(this.saveButton, 'inactive');
+ },
+ undo: function() {
+ this.mirror.undo();
+ },
+ redo: function() {
+ this.mirror.redo();
+ },
+ replaceSelection: function(newVal) {
+ this.mirror.replaceSelection(newVal);
+ this.searchWindow.focus();
+ },
+ raise_search_window: function() {
+ //alert('raising window!');
+ this.searchWindow.focus();
+ },
+ find_replace_window: function() {
+ if (this.searchWindow == null) {
+ this.searchWindow = window.open(this.options.path + "find_replace.html", "mywindow", "scrollbars=1,width=400,height=350,modal=yes");
+ this.searchWindow.codeMirrorUI = this;
+ }
+ this.searchWindow.focus();
+ },
+ find_replace_popup: function() {
+ //alert('Hello!');
+ this.popupFindWrap.className = "codemirror-ui-popup-find-wrap active";
+ this.findString.focus();
+ },
+ find_replace_popup_close: function() {
+ //alert('Hello!');
+ this.popupFindWrap.className = "codemirror-ui-popup-find-wrap";
+ },
+ /*
+ find_replace: function(){
+ this.find_replace = document.createElement("div");
+ this.find_replace.className = "codemirror-search-replace";
+ this.find_replace.innerHTML = "Just a test!";
+ this.home.appendChild(this.find_replace);
+ },
+
+ search: function(){
+ var text = prompt("Enter search term:", "");
+ if (!text)
+ return;
+
+ var first = true;
+ do {
+ var cursor = this.mirror.getSearchCursor(text, first);
+ first = false;
+ while (cursor.findNext()) {
+ cursor.select();
+ if (!confirm("Search again?"))
+ return;
+ }
+ }
+ while (confirm("End of document reached. Start over?"));
+ },
+
+ replace: function(){
+ // This is a replace-all, but it is possible to implement a
+ // prompting replace.
+ var from = prompt("Enter search string:", ""), to;
+ if (from)
+ to = prompt("What should it be replaced with?", "");
+ if (to == null)
+ return;
+
+ var cursor = this.mirror.getSearchCursor(from, false);
+ while (cursor.findNext())
+ cursor.replace(to);
+ },
+ */
+ jump: function() {
+ var line = prompt("Jump to line:", "");
+ if (line && !isNaN(Number(line))) {
+ this.mirror.setCursor(Number(line),0);
+ this.mirror.setSelection({line:Number(line),ch:0},{line:Number(line)+1,ch:0});
+ this.mirror.focus();
+ }
+ },
+ /*
+ line: function(){
+ alert("The cursor is currently at line " + this.mirror.currentLine());
+ this.mirror.focus();
+ },
+
+ macro: function(){
+ var name = prompt("Name your constructor:", "");
+ if (name)
+ this.mirror.replaceSelection("function " + name + "() {\n \n}\n\n" + name + ".prototype = {\n \n};\n");
+ },
+ */
+ reindent: function() {
+ var lineCount = this.mirror.lineCount();
+ for(var line = 0; line < lineCount; line++) {
+ this.mirror.indentLine(line);
+ }
+ },
+ about : function() {
+ string = "CodeMirror-UI was written by Jeremy Green (http://www.octolabs.com/) as a light interface around CodeMirror by Marijn Haverbeke (http://codemirror.net)."
+ string += "\n\n"
+ string += "Documentation and the code can be found at https://github.com/jagthedrummer/codemirror-ui/."
+ alert(string);
+ },
+ reindentSelection: function() {
+ var cur = this.mirror.getCursor()
+ //console.log(cur)
+ var start = this.mirror.getCursor(true)["line"]
+ var end = this.mirror.getCursor(false)["line"]
+ for(var line = start; line <= end; line++) {
+ this.mirror.indentLine(line);
+ }
+ //this.mirror.reindentSelection();
+
+ },
+ // Event handler registration. If disconnect is true, it'll return a
+ // function that unregisters the handler.
+ // Borrowed from CodeMirror + modified
+ connect: function (node, type, handler, disconnect) {
+ /*function wrapHandler(event) {
+ handler(new Event(event || window.event));
+ }*/
+
+ if (typeof node.addEventListener == "function") {
+ node.addEventListener(type, handler, false);
+ if (disconnect)
+ return function() {
+ node.removeEventListener(type, handler, false);
+ };
+ } else {
+ node.attachEvent("on" + type, handler);
+ if (disconnect)
+ return function() {
+ node.detachEvent("on" + type, handler);
+ };
+ }
+ }
+};
+
+/*
+ * This makes coding callbacks much more sane
+ */
+Function.prototype.cmuiBind = function(scope) {
+ var _function = this;
+
+ return function() {
+ return _function.apply(scope, arguments);
+ }
+}