Compare commits
64 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2237c91067 | ||
|
|
98a08fddf8 | ||
|
|
21cdcb20b4 | ||
|
|
47547b2ae8 | ||
|
|
6e9af92471 | ||
|
|
cc7df4222a | ||
|
|
25b5af50c2 | ||
|
|
7c8c728ad4 | ||
|
|
655fef4baa | ||
|
|
a27db58031 | ||
|
|
7c0cb2d1c3 | ||
|
|
229a089d45 | ||
|
|
49ca9d75f9 | ||
|
|
745903d133 | ||
|
|
54bf805548 | ||
|
|
2ac674f5c6 | ||
|
|
2b5a16be70 | ||
|
|
1fbe9df342 | ||
|
|
1217d2d05e | ||
|
|
432795026c | ||
|
|
ab23eaa6ff | ||
|
|
4583c0c713 | ||
|
|
d3a961f13f | ||
|
|
7a97af2c1d | ||
|
|
750cc59fd5 | ||
|
|
dfcf54d412 | ||
|
|
5fd1c35d85 | ||
|
|
21b61bd027 | ||
|
|
7fa28c6d8b | ||
|
|
97e396794a | ||
|
|
b096ef3606 | ||
|
|
74b0d86c36 | ||
|
|
319c509318 | ||
|
|
5703a040be | ||
|
|
6752b8ef50 | ||
|
|
7062560eaa | ||
|
|
3be433c910 | ||
|
|
bd0969e870 | ||
|
|
ffbac321a4 | ||
|
|
222f6589a9 | ||
|
|
a2245775a9 | ||
|
|
d594050166 | ||
|
|
2665055558 | ||
|
|
3e41afb0a6 | ||
|
|
f1ec4a2453 | ||
|
|
98f1ace910 | ||
|
|
401a3a7abb | ||
|
|
6a0cc816a9 | ||
|
|
4bafb3aaa1 | ||
|
|
782aac54e4 | ||
|
|
06dd46c24f | ||
|
|
bc50886250 | ||
|
|
4264c479ad | ||
|
|
b3afe9458e | ||
|
|
1382277c74 | ||
|
|
d1df67338d | ||
|
|
ccc5b9d30a | ||
|
|
86142ca5f1 | ||
|
|
b55fe4856c | ||
|
|
d5df587cc3 | ||
|
|
0665d10a7c | ||
|
|
43f7089106 | ||
|
|
fcb7722a55 | ||
|
|
7c5a005784 |
@@ -1,29 +0,0 @@
|
||||
// TODO number prefixes
|
||||
(function() {
|
||||
// Really primitive kill-ring implementation.
|
||||
var killRing = [];
|
||||
function addToRing(str) {
|
||||
killRing.push(str);
|
||||
if (killRing.length > 50) killRing.shift();
|
||||
}
|
||||
function getFromRing() { return killRing[killRing.length - 1] || ""; }
|
||||
function popFromRing() { if (killRing.length > 1) killRing.pop(); return getFromRing(); }
|
||||
|
||||
CodeMirror.keyMap.emacs = {
|
||||
"Ctrl-X": function(cm) {cm.setOption("keyMap", "emacs-Ctrl-X");},
|
||||
"Ctrl-W": function(cm) {addToRing(cm.getSelection()); cm.replaceSelection("");},
|
||||
"Ctrl-Alt-W": function(cm) {addToRing(cm.getSelection()); cm.replaceSelection("");},
|
||||
"Alt-W": function(cm) {addToRing(cm.getSelection());},
|
||||
"Ctrl-Y": function(cm) {cm.replaceSelection(getFromRing());},
|
||||
"Alt-Y": function(cm) {cm.replaceSelection(popFromRing());},
|
||||
"Ctrl-/": "undo", "Shift-Ctrl--": "undo", "Shift-Alt-,": "goDocStart", "Shift-Alt-.": "goDocEnd",
|
||||
"Ctrl-S": "findNext", "Ctrl-R": "findPrev", "Ctrl-G": "clearSearch", "Shift-Alt-5": "replace",
|
||||
"Ctrl-Z": "undo", "Cmd-Z": "undo", "Alt-/": "autocomplete",
|
||||
fallthrough: ["basic", "emacsy"]
|
||||
};
|
||||
|
||||
CodeMirror.keyMap["emacs-Ctrl-X"] = {
|
||||
"Ctrl-S": "save", "Ctrl-W": "save", "S": "saveAll", "F": "open", "U": "undo", "K": "close",
|
||||
auto: "emacs", nofallthrough: true
|
||||
};
|
||||
})();
|
||||
@@ -1,500 +0,0 @@
|
||||
// Supported keybindings:
|
||||
//
|
||||
// Cursor movement:
|
||||
// h, j, k, l
|
||||
// e, E, w, W, b, B
|
||||
// Ctrl-f, Ctrl-b
|
||||
// Ctrl-n, Ctrl-p
|
||||
// $, ^, 0
|
||||
// G
|
||||
// ge, gE
|
||||
// gg
|
||||
// f<char>, F<char>, t<char>, T<char>
|
||||
// Ctrl-o, Ctrl-i TODO (FIXME - Ctrl-O wont work in Chrome)
|
||||
// /, ?, n, N TODO (does not work)
|
||||
// #, * TODO
|
||||
//
|
||||
// Entering insert mode:
|
||||
// i, I, a, A, o, O
|
||||
// s
|
||||
// ce, cb (without support for number of actions like c3e - TODO)
|
||||
// cc
|
||||
// S, C TODO
|
||||
// cf<char>, cF<char>, ct<char>, cT<char>
|
||||
//
|
||||
// Deleting text:
|
||||
// x, X
|
||||
// J
|
||||
// dd, D
|
||||
// de, db (without support for number of actions like d3e - TODO)
|
||||
// df<char>, dF<char>, dt<char>, dT<char>
|
||||
//
|
||||
// Yanking and pasting:
|
||||
// yy, Y
|
||||
// p, P
|
||||
// p'<char> TODO - test
|
||||
// y'<char> TODO - test
|
||||
// m<char> TODO - test
|
||||
//
|
||||
// Changing text in place:
|
||||
// ~
|
||||
// r<char>
|
||||
//
|
||||
// Visual mode:
|
||||
// v, V TODO
|
||||
//
|
||||
// Misc:
|
||||
// . TODO
|
||||
//
|
||||
|
||||
|
||||
(function() {
|
||||
var count = "";
|
||||
var sdir = "f";
|
||||
var buf = "";
|
||||
var yank = 0;
|
||||
var mark = [];
|
||||
function emptyBuffer() { buf = ""; }
|
||||
function pushInBuffer(str) { buf += str; };
|
||||
function pushCountDigit(digit) { return function(cm) {count += digit;} }
|
||||
function popCount() { var i = parseInt(count); count = ""; return i || 1; }
|
||||
function iterTimes(func) {
|
||||
for (var i = 0, c = popCount(); i < c; ++i) func(i, i == c - 1);
|
||||
}
|
||||
function countTimes(func) {
|
||||
if (typeof func == "string") func = CodeMirror.commands[func];
|
||||
return function(cm) { iterTimes(function () { func(cm); }) };
|
||||
}
|
||||
|
||||
function iterObj(o, f) {
|
||||
for (var prop in o) if (o.hasOwnProperty(prop)) f(prop, o[prop]);
|
||||
}
|
||||
function iterList(l, f) {
|
||||
for (var i in l) f(l[i]);
|
||||
}
|
||||
function toLetter(ch) {
|
||||
// T -> t, Shift-T -> T, '*' -> *, "Space" -> " "
|
||||
if (ch.slice(0, 6) == "Shift-") {
|
||||
return ch.slice(0, 1);
|
||||
} else {
|
||||
if (ch == "Space") return " ";
|
||||
if (ch.length == 3 && ch[0] == "'" && ch[2] == "'") return ch[1];
|
||||
return ch.toLowerCase();
|
||||
}
|
||||
}
|
||||
var SPECIAL_SYMBOLS = "~`!@#$%^&*()_-+=[{}]\\|/?.,<>:;\"\'1234567890";
|
||||
function toCombo(ch) {
|
||||
// t -> T, T -> Shift-T, * -> '*', " " -> "Space"
|
||||
if (ch == " ") return "Space";
|
||||
var specialIdx = SPECIAL_SYMBOLS.indexOf(ch);
|
||||
if (specialIdx != -1) return "'" + ch + "'";
|
||||
if (ch.toLowerCase() == ch) return ch.toUpperCase();
|
||||
return "Shift-" + ch.toUpperCase();
|
||||
}
|
||||
|
||||
var word = [/\w/, /[^\w\s]/], bigWord = [/\S/];
|
||||
function findWord(line, pos, dir, regexps) {
|
||||
var stop = 0, next = -1;
|
||||
if (dir > 0) { stop = line.length; next = 0; }
|
||||
var start = stop, end = stop;
|
||||
// Find bounds of next one.
|
||||
outer: for (; pos != stop; pos += dir) {
|
||||
for (var i = 0; i < regexps.length; ++i) {
|
||||
if (regexps[i].test(line.charAt(pos + next))) {
|
||||
start = pos;
|
||||
for (; pos != stop; pos += dir) {
|
||||
if (!regexps[i].test(line.charAt(pos + next))) break;
|
||||
}
|
||||
end = pos;
|
||||
break outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
return {from: Math.min(start, end), to: Math.max(start, end)};
|
||||
}
|
||||
function moveToWord(cm, regexps, dir, where) {
|
||||
var cur = cm.getCursor(), ch = cur.ch, line = cm.getLine(cur.line), word;
|
||||
while (true) {
|
||||
word = findWord(line, ch, dir, regexps);
|
||||
ch = word[where == "end" ? "to" : "from"];
|
||||
if (ch == cur.ch && word.from != word.to) ch = word[dir < 0 ? "from" : "to"];
|
||||
else break;
|
||||
}
|
||||
cm.setCursor(cur.line, word[where == "end" ? "to" : "from"], true);
|
||||
}
|
||||
function joinLineNext(cm) {
|
||||
var cur = cm.getCursor(), ch = cur.ch, line = cm.getLine(cur.line);
|
||||
CodeMirror.commands.goLineEnd(cm);
|
||||
if (cur.line != cm.lineCount()) {
|
||||
CodeMirror.commands.goLineEnd(cm);
|
||||
cm.replaceSelection(" ", "end");
|
||||
CodeMirror.commands.delCharRight(cm);
|
||||
}
|
||||
}
|
||||
function delTillMark(cm, cHar) {
|
||||
var i = mark[cHar];
|
||||
if (i === undefined) {
|
||||
// console.log("Mark not set"); // TODO - show in status bar
|
||||
return;
|
||||
}
|
||||
var l = cm.getCursor().line, start = i > l ? l : i, end = i > l ? i : l;
|
||||
cm.setCursor(start);
|
||||
for (var c = start; c <= end; c++) {
|
||||
pushInBuffer("\n"+cm.getLine(start));
|
||||
cm.removeLine(start);
|
||||
}
|
||||
}
|
||||
function yankTillMark(cm, cHar) {
|
||||
var i = mark[cHar];
|
||||
if (i === undefined) {
|
||||
// console.log("Mark not set"); // TODO - show in status bar
|
||||
return;
|
||||
}
|
||||
var l = cm.getCursor().line, start = i > l ? l : i, end = i > l ? i : l;
|
||||
for (var c = start; c <= end; c++) {
|
||||
pushInBuffer("\n"+cm.getLine(c));
|
||||
}
|
||||
cm.setCursor(start);
|
||||
}
|
||||
function goLineStartText(cm) {
|
||||
// Go to the start of the line where the text begins, or the end for whitespace-only lines
|
||||
var cur = cm.getCursor(), firstNonWS = cm.getLine(cur.line).search(/\S/);
|
||||
cm.setCursor(cur.line, firstNonWS == -1 ? line.length : firstNonWS, true);
|
||||
}
|
||||
|
||||
function charIdxInLine(cm, cHar, motion_options) {
|
||||
// Search for cHar in line.
|
||||
// motion_options: {forward, inclusive}
|
||||
// If inclusive = true, include it too.
|
||||
// If forward = true, search forward, else search backwards.
|
||||
// If char is not found on this line, do nothing
|
||||
var cur = cm.getCursor(), line = cm.getLine(cur.line), idx;
|
||||
var ch = toLetter(cHar), mo = motion_options;
|
||||
if (mo.forward) {
|
||||
idx = line.indexOf(ch, cur.ch + 1);
|
||||
if (idx != -1 && mo.inclusive) idx += 1;
|
||||
} else {
|
||||
idx = line.lastIndexOf(ch, cur.ch);
|
||||
if (idx != -1 && !mo.inclusive) idx += 1;
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
function moveTillChar(cm, cHar, motion_options) {
|
||||
// Move to cHar in line, as found by charIdxInLine.
|
||||
var idx = charIdxInLine(cm, cHar, motion_options), cur = cm.getCursor();
|
||||
if (idx != -1) cm.setCursor({line: cur.line, ch: idx});
|
||||
}
|
||||
|
||||
function delTillChar(cm, cHar, motion_options) {
|
||||
// delete text in this line, untill cHar is met,
|
||||
// as found by charIdxInLine.
|
||||
// If char is not found on this line, do nothing
|
||||
var idx = charIdxInLine(cm, cHar, motion_options);
|
||||
var cur = cm.getCursor();
|
||||
if (idx !== -1) {
|
||||
if (motion_options.forward) {
|
||||
cm.replaceRange("", {line: cur.line, ch: cur.ch}, {line: cur.line, ch: idx});
|
||||
} else {
|
||||
cm.replaceRange("", {line: cur.line, ch: idx}, {line: cur.line, ch: cur.ch});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function enterInsertMode(cm) {
|
||||
// enter insert mode: switch mode and cursor
|
||||
if (!cm) console.log("call enterInsertMode with 'cm' as an argument");
|
||||
popCount();
|
||||
cm.setOption("keyMap", "vim-insert");
|
||||
}
|
||||
|
||||
// main keymap
|
||||
var map = CodeMirror.keyMap.vim = {
|
||||
// Pipe (|); TODO: should be *screen* chars, so need a util function to turn tabs into spaces?
|
||||
"'|'": function(cm) {
|
||||
cm.setCursor(cm.getCursor().line, popCount() - 1, true);
|
||||
},
|
||||
"'^'": function(cm) { popCount(); goLineStartText(cm);},
|
||||
"A": function(cm) {
|
||||
cm.setCursor(cm.getCursor().line, cm.getCursor().ch+1, true);
|
||||
enterInsertMode(cm);
|
||||
},
|
||||
"Shift-A": function(cm) { CodeMirror.commands.goLineEnd(cm); enterInsertMode(cm);},
|
||||
"I": function(cm) { enterInsertMode(cm);},
|
||||
"Shift-I": function(cm) { goLineStartText(cm); enterInsertMode(cm);},
|
||||
"O": function(cm) {
|
||||
CodeMirror.commands.goLineEnd(cm);
|
||||
CodeMirror.commands.newlineAndIndent(cm);
|
||||
enterInsertMode(cm);
|
||||
},
|
||||
"Shift-O": function(cm) {
|
||||
CodeMirror.commands.goLineStart(cm);
|
||||
cm.replaceSelection("\n", "start");
|
||||
cm.indentLine(cm.getCursor().line);
|
||||
enterInsertMode(cm);
|
||||
},
|
||||
"G": function(cm) { cm.setOption("keyMap", "vim-prefix-g");},
|
||||
"Shift-D": function(cm) {
|
||||
// commented out verions works, but I left original, cause maybe
|
||||
// I don't know vim enouth to see what it does
|
||||
/* var cur = cm.getCursor();
|
||||
var f = {line: cur.line, ch: cur.ch}, t = {line: cur.line};
|
||||
pushInBuffer(cm.getRange(f, t));
|
||||
cm.replaceRange("", f, t);
|
||||
*/
|
||||
emptyBuffer();
|
||||
mark["Shift-D"] = cm.getCursor(false).line;
|
||||
cm.setCursor(cm.getCursor(true).line);
|
||||
delTillMark(cm,"Shift-D"); mark = [];
|
||||
},
|
||||
|
||||
"S": function (cm) {
|
||||
countTimes(function (_cm) {
|
||||
CodeMirror.commands.delCharRight(_cm);
|
||||
})(cm);
|
||||
enterInsertMode(cm);
|
||||
},
|
||||
"M": function(cm) {cm.setOption("keyMap", "vim-prefix-m"); mark = [];},
|
||||
"Y": function(cm) {cm.setOption("keyMap", "vim-prefix-y"); emptyBuffer(); yank = 0;},
|
||||
"Shift-Y": function(cm) {
|
||||
emptyBuffer();
|
||||
mark["Shift-D"] = cm.getCursor(false).line;
|
||||
cm.setCursor(cm.getCursor(true).line);
|
||||
yankTillMark(cm,"Shift-D"); mark = [];
|
||||
},
|
||||
"/": function(cm) {var f = CodeMirror.commands.find; f && f(cm); sdir = "f";},
|
||||
"'?'": function(cm) {
|
||||
var f = CodeMirror.commands.find;
|
||||
if (f) { f(cm); CodeMirror.commands.findPrev(cm); sdir = "r"; }
|
||||
},
|
||||
"N": function(cm) {
|
||||
var fn = CodeMirror.commands.findNext;
|
||||
if (fn) sdir != "r" ? fn(cm) : CodeMirror.commands.findPrev(cm);
|
||||
},
|
||||
"Shift-N": function(cm) {
|
||||
var fn = CodeMirror.commands.findNext;
|
||||
if (fn) sdir != "r" ? CodeMirror.commands.findPrev(cm) : fn.findNext(cm);
|
||||
},
|
||||
"Shift-G": function(cm) {
|
||||
count == "" ? cm.setCursor(cm.lineCount()) : cm.setCursor(parseInt(count)-1);
|
||||
popCount();
|
||||
CodeMirror.commands.goLineStart(cm);
|
||||
},
|
||||
"'$'": function (cm) {
|
||||
countTimes("goLineEnd")(cm);
|
||||
if (cm.getCursor().ch) CodeMirror.commands.goColumnLeft(cm);
|
||||
},
|
||||
nofallthrough: true, style: "fat-cursor"
|
||||
};
|
||||
|
||||
// standard mode switching
|
||||
iterList(["d", "t", "T", "f", "F", "c", "r"],
|
||||
function (ch) {
|
||||
CodeMirror.keyMap.vim[toCombo(ch)] = function (cm) {
|
||||
cm.setOption("keyMap", "vim-prefix-" + ch);
|
||||
emptyBuffer();
|
||||
};
|
||||
});
|
||||
|
||||
function addCountBindings(keyMap) {
|
||||
// Add bindings for number keys
|
||||
keyMap["0"] = function(cm) {
|
||||
count.length > 0 ? pushCountDigit("0")(cm) : CodeMirror.commands.goLineStart(cm);
|
||||
};
|
||||
for (var i = 1; i < 10; ++i) keyMap[i] = pushCountDigit(i);
|
||||
}
|
||||
addCountBindings(CodeMirror.keyMap.vim);
|
||||
|
||||
// main num keymap
|
||||
// Add bindings that are influenced by number keys
|
||||
iterObj({
|
||||
"H": "goColumnLeft", "L": "goColumnRight", "J": "goLineDown",
|
||||
"K": "goLineUp", "Left": "goColumnLeft", "Right": "goColumnRight",
|
||||
"Down": "goLineDown", "Up": "goLineUp", "Backspace": "goCharLeft",
|
||||
"Space": "goCharRight",
|
||||
"B": function(cm) {moveToWord(cm, word, -1, "end");},
|
||||
"E": function(cm) {moveToWord(cm, word, 1, "end");},
|
||||
"W": function(cm) {moveToWord(cm, word, 1, "start");},
|
||||
"Shift-B": function(cm) {moveToWord(cm, bigWord, -1, "end");},
|
||||
"Shift-E": function(cm) {moveToWord(cm, bigWord, 1, "end");},
|
||||
"Shift-W": function(cm) {moveToWord(cm, bigWord, 1, "start");},
|
||||
"X": function(cm) {CodeMirror.commands.delCharRight(cm);},
|
||||
"P": function(cm) {
|
||||
var cur = cm.getCursor().line;
|
||||
if (buf!= "") {
|
||||
CodeMirror.commands.goLineEnd(cm);
|
||||
cm.replaceSelection(buf, "end");
|
||||
}
|
||||
cm.setCursor(cur+1);
|
||||
},
|
||||
"Shift-X": function(cm) {CodeMirror.commands.delCharLeft(cm);},
|
||||
"Shift-J": function(cm) {joinLineNext(cm);},
|
||||
"Shift-P": function(cm) {
|
||||
var cur = cm.getCursor().line;
|
||||
if (buf!= "") {
|
||||
CodeMirror.commands.goLineUp(cm);
|
||||
CodeMirror.commands.goLineEnd(cm);
|
||||
cm.replaceSelection(buf, "end");
|
||||
}
|
||||
cm.setCursor(cur+1);
|
||||
},
|
||||
"'~'": function(cm) {
|
||||
var cur = cm.getCursor(), cHar = cm.getRange({line: cur.line, ch: cur.ch}, {line: cur.line, ch: cur.ch+1});
|
||||
cHar = cHar != cHar.toLowerCase() ? cHar.toLowerCase() : cHar.toUpperCase();
|
||||
cm.replaceRange(cHar, {line: cur.line, ch: cur.ch}, {line: cur.line, ch: cur.ch+1});
|
||||
cm.setCursor(cur.line, cur.ch+1);
|
||||
},
|
||||
"Ctrl-B": function(cm) {CodeMirror.commands.goPageUp(cm);},
|
||||
"Ctrl-F": function(cm) {CodeMirror.commands.goPageDown(cm);},
|
||||
"Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown",
|
||||
"U": "undo", "Ctrl-R": "redo"
|
||||
}, function(key, cmd) { map[key] = countTimes(cmd); });
|
||||
|
||||
// empty key maps
|
||||
iterList([
|
||||
"vim-prefix-d'",
|
||||
"vim-prefix-y'",
|
||||
"vim-prefix-df",
|
||||
"vim-prefix-dF",
|
||||
"vim-prefix-dt",
|
||||
"vim-prefix-dT",
|
||||
"vim-prefix-c",
|
||||
"vim-prefix-cf",
|
||||
"vim-prefix-cF",
|
||||
"vim-prefix-ct",
|
||||
"vim-prefix-cT",
|
||||
"vim-prefix-",
|
||||
"vim-prefix-f",
|
||||
"vim-prefix-F",
|
||||
"vim-prefix-t",
|
||||
"vim-prefix-T",
|
||||
"vim-prefix-r",
|
||||
"vim-prefix-m"
|
||||
],
|
||||
function (prefix) {
|
||||
CodeMirror.keyMap[prefix] = {
|
||||
auto: "vim",
|
||||
nofallthrough: true
|
||||
};
|
||||
});
|
||||
|
||||
CodeMirror.keyMap["vim-prefix-g"] = {
|
||||
"E": countTimes(function(cm) { moveToWord(cm, word, -1, "start");}),
|
||||
"Shift-E": countTimes(function(cm) { moveToWord(cm, bigWord, -1, "start");}),
|
||||
"G": function (cm) { cm.setCursor({line: 0, ch: cm.getCursor().ch});},
|
||||
auto: "vim", nofallthrough: true, style: "fat-cursor"
|
||||
};
|
||||
|
||||
CodeMirror.keyMap["vim-prefix-d"] = {
|
||||
"D": countTimes(function(cm) {
|
||||
pushInBuffer("\n"+cm.getLine(cm.getCursor().line));
|
||||
cm.removeLine(cm.getCursor().line);
|
||||
}),
|
||||
"'": function(cm) {
|
||||
cm.setOption("keyMap", "vim-prefix-d'");
|
||||
emptyBuffer();
|
||||
},
|
||||
"E": countTimes("delWordRight"),
|
||||
"B": countTimes("delWordLeft"),
|
||||
auto: "vim", nofallthrough: true, style: "fat-cursor"
|
||||
};
|
||||
// FIXME - does not work for bindings like "d3e"
|
||||
addCountBindings(CodeMirror.keyMap["vim-prefix-d"]);
|
||||
|
||||
CodeMirror.keyMap["vim-prefix-c"] = {
|
||||
"E": function (cm) {
|
||||
countTimes("delWordRight")(cm);
|
||||
enterInsertMode(cm);
|
||||
},
|
||||
"B": function (cm) {
|
||||
countTimes("delWordLeft")(cm);
|
||||
enterInsertMode(cm);
|
||||
},
|
||||
"C": function (cm) {
|
||||
iterTimes(function (i, last) {
|
||||
CodeMirror.commands.deleteLine(cm);
|
||||
if (i) {
|
||||
CodeMirror.commands.delCharRight(cm);
|
||||
if (last) CodeMirror.commands.deleteLine(cm);
|
||||
}
|
||||
});
|
||||
enterInsertMode(cm);
|
||||
},
|
||||
auto: "vim", nofallthrough: true, style: "fat-cursor"
|
||||
};
|
||||
|
||||
iterList(["vim-prefix-d", "vim-prefix-c", "vim-prefix-"], function (prefix) {
|
||||
iterList(["f", "F", "T", "t"],
|
||||
function (ch) {
|
||||
CodeMirror.keyMap[prefix][toCombo(ch)] = function (cm) {
|
||||
cm.setOption("keyMap", prefix + ch);
|
||||
emptyBuffer();
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
var MOTION_OPTIONS = {
|
||||
"t": {inclusive: false, forward: true},
|
||||
"f": {inclusive: true, forward: true},
|
||||
"T": {inclusive: false, forward: false},
|
||||
"F": {inclusive: true, forward: false}
|
||||
};
|
||||
|
||||
function setupPrefixBindingForKey(m) {
|
||||
CodeMirror.keyMap["vim-prefix-m"][m] = function(cm) {
|
||||
mark[m] = cm.getCursor().line;
|
||||
};
|
||||
CodeMirror.keyMap["vim-prefix-d'"][m] = function(cm) {
|
||||
delTillMark(cm,m);
|
||||
};
|
||||
CodeMirror.keyMap["vim-prefix-y'"][m] = function(cm) {
|
||||
yankTillMark(cm,m);
|
||||
};
|
||||
CodeMirror.keyMap["vim-prefix-r"][m] = function (cm) {
|
||||
var cur = cm.getCursor();
|
||||
cm.replaceRange(toLetter(m),
|
||||
{line: cur.line, ch: cur.ch},
|
||||
{line: cur.line, ch: cur.ch + 1});
|
||||
CodeMirror.commands.goColumnLeft(cm);
|
||||
};
|
||||
// all commands, related to motions till char in line
|
||||
iterObj(MOTION_OPTIONS, function (ch, options) {
|
||||
CodeMirror.keyMap["vim-prefix-" + ch][m] = function(cm) {
|
||||
moveTillChar(cm, m, options);
|
||||
};
|
||||
CodeMirror.keyMap["vim-prefix-d" + ch][m] = function(cm) {
|
||||
delTillChar(cm, m, options);
|
||||
};
|
||||
CodeMirror.keyMap["vim-prefix-c" + ch][m] = function(cm) {
|
||||
delTillChar(cm, m, options);
|
||||
enterInsertMode(cm);
|
||||
};
|
||||
});
|
||||
};
|
||||
for (var i = 65; i < 65 + 26; i++) { // uppercase alphabet char codes
|
||||
var ch = String.fromCharCode(i);
|
||||
setupPrefixBindingForKey(toCombo(ch));
|
||||
setupPrefixBindingForKey(toCombo(ch.toLowerCase()));
|
||||
}
|
||||
iterList(SPECIAL_SYMBOLS, function (ch) {
|
||||
setupPrefixBindingForKey(toCombo(ch));
|
||||
});
|
||||
setupPrefixBindingForKey("Space");
|
||||
|
||||
CodeMirror.keyMap["vim-prefix-y"] = {
|
||||
"Y": countTimes(function(cm) { pushInBuffer("\n"+cm.getLine(cm.getCursor().line+yank)); yank++; }),
|
||||
"'": function(cm) {cm.setOption("keyMap", "vim-prefix-y'"); emptyBuffer();},
|
||||
auto: "vim", nofallthrough: true, style: "fat-cursor"
|
||||
};
|
||||
|
||||
CodeMirror.keyMap["vim-insert"] = {
|
||||
// TODO: override navigation keys so that Esc will cancel automatic indentation from o, O, i_<CR>
|
||||
"Esc": function(cm) {
|
||||
cm.setCursor(cm.getCursor().line, cm.getCursor().ch-1, true);
|
||||
cm.setOption("keyMap", "vim");
|
||||
},
|
||||
"Ctrl-N": "autocomplete",
|
||||
"Ctrl-P": "autocomplete",
|
||||
fallthrough: ["default"]
|
||||
};
|
||||
})();
|
||||
@@ -1,146 +0,0 @@
|
||||
/**
|
||||
* Tag-closer extension for CodeMirror.
|
||||
*
|
||||
* This extension adds a "closeTag" utility function that can be used with key bindings to
|
||||
* insert a matching end tag after the ">" character of a start tag has been typed. It can
|
||||
* also complete "</" if a matching start tag is found. It will correctly ignore signal
|
||||
* characters for empty tags, comments, CDATA, etc.
|
||||
*
|
||||
* The function depends on internal parser state to identify tags. It is compatible with the
|
||||
* following CodeMirror modes and will ignore all others:
|
||||
* - htmlmixed
|
||||
* - xml
|
||||
*
|
||||
* See demos/closetag.html for a usage example.
|
||||
*
|
||||
* @author Nathan Williams <nathan@nlwillia.net>
|
||||
* Contributed under the same license terms as CodeMirror.
|
||||
*/
|
||||
(function() {
|
||||
/** Option that allows tag closing behavior to be toggled. Default is true. */
|
||||
CodeMirror.defaults['closeTagEnabled'] = true;
|
||||
|
||||
/** Array of tag names to add indentation after the start tag for. Default is the list of block-level html tags. */
|
||||
CodeMirror.defaults['closeTagIndent'] = ['applet', 'blockquote', 'body', 'button', 'div', 'dl', 'fieldset', 'form', 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'html', 'iframe', 'layer', 'legend', 'object', 'ol', 'p', 'select', 'table', 'ul'];
|
||||
|
||||
/**
|
||||
* Call during key processing to close tags. Handles the key event if the tag is closed, otherwise throws CodeMirror.Pass.
|
||||
* - cm: The editor instance.
|
||||
* - ch: The character being processed.
|
||||
* - indent: Optional. Omit or pass true to use the default indentation tag list defined in the 'closeTagIndent' option.
|
||||
* Pass false to disable indentation. Pass an array to override the default list of tag names.
|
||||
*/
|
||||
CodeMirror.defineExtension("closeTag", function(cm, ch, indent) {
|
||||
if (!cm.getOption('closeTagEnabled')) {
|
||||
throw CodeMirror.Pass;
|
||||
}
|
||||
|
||||
var mode = cm.getOption('mode');
|
||||
|
||||
if (mode == 'text/html') {
|
||||
|
||||
/*
|
||||
* Relevant structure of token:
|
||||
*
|
||||
* htmlmixed
|
||||
* className
|
||||
* state
|
||||
* htmlState
|
||||
* type
|
||||
* context
|
||||
* tagName
|
||||
* mode
|
||||
*
|
||||
* xml
|
||||
* className
|
||||
* state
|
||||
* tagName
|
||||
* type
|
||||
*/
|
||||
|
||||
var pos = cm.getCursor();
|
||||
var tok = cm.getTokenAt(pos);
|
||||
var state = tok.state;
|
||||
|
||||
if (state.mode && state.mode != 'html') {
|
||||
throw CodeMirror.Pass; // With htmlmixed, we only care about the html sub-mode.
|
||||
}
|
||||
|
||||
if (ch == '>') {
|
||||
var type = state.htmlState ? state.htmlState.type : state.type; // htmlmixed : xml
|
||||
|
||||
if (tok.className == 'tag' && type == 'closeTag') {
|
||||
throw CodeMirror.Pass; // Don't process the '>' at the end of an end-tag.
|
||||
}
|
||||
|
||||
cm.replaceSelection('>'); // Mode state won't update until we finish the tag.
|
||||
pos = {line: pos.line, ch: pos.ch + 1};
|
||||
cm.setCursor(pos);
|
||||
|
||||
tok = cm.getTokenAt(cm.getCursor());
|
||||
state = tok.state;
|
||||
type = state.htmlState ? state.htmlState.type : state.type; // htmlmixed : xml
|
||||
|
||||
if (tok.className == 'tag' && type != 'selfcloseTag') {
|
||||
var tagName = state.htmlState ? state.htmlState.context.tagName : state.tagName; // htmlmixed : xml
|
||||
if (tagName.length > 0) {
|
||||
insertEndTag(cm, indent, pos, tagName);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Undo the '>' insert and allow cm to handle the key instead.
|
||||
cm.setSelection({line: pos.line, ch: pos.ch - 1}, pos);
|
||||
cm.replaceSelection("");
|
||||
|
||||
} else if (ch == '/') {
|
||||
if (tok.className == 'tag' && tok.string == '<') {
|
||||
var tagName = state.htmlState ? (state.htmlState.context ? state.htmlState.context.tagName : '') : state.context.tagName; // htmlmixed : xml # extra htmlmized check is for '</' edge case
|
||||
if (tagName.length > 0) {
|
||||
completeEndTag(cm, pos, tagName);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
throw CodeMirror.Pass; // Bubble if not handled
|
||||
});
|
||||
|
||||
function insertEndTag(cm, indent, pos, tagName) {
|
||||
if (shouldIndent(cm, indent, tagName)) {
|
||||
cm.replaceSelection('\n\n</' + tagName + '>', 'end');
|
||||
cm.indentLine(pos.line + 1);
|
||||
cm.indentLine(pos.line + 2);
|
||||
cm.setCursor({line: pos.line + 1, ch: cm.getLine(pos.line + 1).length});
|
||||
} else {
|
||||
cm.replaceSelection('</' + tagName + '>');
|
||||
cm.setCursor(pos);
|
||||
}
|
||||
}
|
||||
|
||||
function shouldIndent(cm, indent, tagName) {
|
||||
if (typeof indent == 'undefined' || indent == null || indent == true) {
|
||||
indent = cm.getOption('closeTagIndent');
|
||||
}
|
||||
if (!indent) {
|
||||
indent = [];
|
||||
}
|
||||
return indexOf(indent, tagName.toLowerCase()) != -1;
|
||||
}
|
||||
|
||||
// C&P from codemirror.js...would be nice if this were visible to utilities.
|
||||
function indexOf(collection, elt) {
|
||||
if (collection.indexOf) return collection.indexOf(elt);
|
||||
for (var i = 0, e = collection.length; i < e; ++i)
|
||||
if (collection[i] == elt) return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
function completeEndTag(cm, pos, tagName) {
|
||||
cm.replaceSelection('/' + tagName + '>');
|
||||
cm.setCursor({line: pos.line, ch: pos.ch + tagName.length + 2 });
|
||||
}
|
||||
|
||||
})();
|
||||
@@ -1,23 +0,0 @@
|
||||
.CodeMirror-dialog {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.CodeMirror-dialog > div {
|
||||
position: absolute;
|
||||
top: 0; left: 0; right: 0;
|
||||
background: white;
|
||||
border-bottom: 1px solid #eee;
|
||||
z-index: 15;
|
||||
padding: .1em .8em;
|
||||
overflow: hidden;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.CodeMirror-dialog input {
|
||||
border: none;
|
||||
outline: none;
|
||||
background: transparent;
|
||||
width: 20em;
|
||||
color: inherit;
|
||||
font-family: monospace;
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
// Open simple dialogs on top of an editor. Relies on dialog.css.
|
||||
|
||||
(function() {
|
||||
function dialogDiv(cm, template) {
|
||||
var wrap = cm.getWrapperElement();
|
||||
var dialog = wrap.insertBefore(document.createElement("div"), wrap.firstChild);
|
||||
dialog.className = "CodeMirror-dialog";
|
||||
dialog.innerHTML = '<div>' + template + '</div>';
|
||||
return dialog;
|
||||
}
|
||||
|
||||
CodeMirror.defineExtension("openDialog", function(template, callback) {
|
||||
var dialog = dialogDiv(this, template);
|
||||
var closed = false, me = this;
|
||||
function close() {
|
||||
if (closed) return;
|
||||
closed = true;
|
||||
dialog.parentNode.removeChild(dialog);
|
||||
}
|
||||
var inp = dialog.getElementsByTagName("input")[0];
|
||||
if (inp) {
|
||||
CodeMirror.connect(inp, "keydown", function(e) {
|
||||
if (e.keyCode == 13 || e.keyCode == 27) {
|
||||
CodeMirror.e_stop(e);
|
||||
close();
|
||||
me.focus();
|
||||
if (e.keyCode == 13) callback(inp.value);
|
||||
}
|
||||
});
|
||||
inp.focus();
|
||||
CodeMirror.connect(inp, "blur", close);
|
||||
}
|
||||
return close;
|
||||
});
|
||||
|
||||
CodeMirror.defineExtension("openConfirm", function(template, callbacks) {
|
||||
var dialog = dialogDiv(this, template);
|
||||
var buttons = dialog.getElementsByTagName("button");
|
||||
var closed = false, me = this, blurring = 1;
|
||||
function close() {
|
||||
if (closed) return;
|
||||
closed = true;
|
||||
dialog.parentNode.removeChild(dialog);
|
||||
me.focus();
|
||||
}
|
||||
buttons[0].focus();
|
||||
for (var i = 0; i < buttons.length; ++i) {
|
||||
var b = buttons[i];
|
||||
(function(callback) {
|
||||
CodeMirror.connect(b, "click", function(e) {
|
||||
CodeMirror.e_preventDefault(e);
|
||||
close();
|
||||
if (callback) callback(me);
|
||||
});
|
||||
})(callbacks[i]);
|
||||
CodeMirror.connect(b, "blur", function() {
|
||||
--blurring;
|
||||
setTimeout(function() { if (blurring <= 0) close(); }, 200);
|
||||
});
|
||||
CodeMirror.connect(b, "focus", function() { ++blurring; });
|
||||
}
|
||||
});
|
||||
})();
|
||||
@@ -1,294 +0,0 @@
|
||||
// ============== Formatting extensions ============================
|
||||
// A common storage for all mode-specific formatting features
|
||||
if (!CodeMirror.modeExtensions) CodeMirror.modeExtensions = {};
|
||||
|
||||
// Returns the extension of the editor's current mode
|
||||
CodeMirror.defineExtension("getModeExt", function () {
|
||||
var mname = CodeMirror.resolveMode(this.getOption("mode")).name;
|
||||
var ext = CodeMirror.modeExtensions[mname];
|
||||
if (!ext) throw new Error("No extensions found for mode " + mname);
|
||||
return ext;
|
||||
});
|
||||
|
||||
// If the current mode is 'htmlmixed', returns the extension of a mode located at
|
||||
// the specified position (can be htmlmixed, css or javascript). Otherwise, simply
|
||||
// returns the extension of the editor's current mode.
|
||||
CodeMirror.defineExtension("getModeExtAtPos", function (pos) {
|
||||
var token = this.getTokenAt(pos);
|
||||
if (token && token.state && token.state.mode)
|
||||
return CodeMirror.modeExtensions[token.state.mode == "html" ? "htmlmixed" : token.state.mode];
|
||||
else
|
||||
return this.getModeExt();
|
||||
});
|
||||
|
||||
// Comment/uncomment the specified range
|
||||
CodeMirror.defineExtension("commentRange", function (isComment, from, to) {
|
||||
var curMode = this.getModeExtAtPos(this.getCursor());
|
||||
if (isComment) { // Comment range
|
||||
var commentedText = this.getRange(from, to);
|
||||
this.replaceRange(curMode.commentStart + this.getRange(from, to) + curMode.commentEnd
|
||||
, from, to);
|
||||
if (from.line == to.line && from.ch == to.ch) { // An empty comment inserted - put cursor inside
|
||||
this.setCursor(from.line, from.ch + curMode.commentStart.length);
|
||||
}
|
||||
}
|
||||
else { // Uncomment range
|
||||
var selText = this.getRange(from, to);
|
||||
var startIndex = selText.indexOf(curMode.commentStart);
|
||||
var endIndex = selText.lastIndexOf(curMode.commentEnd);
|
||||
if (startIndex > -1 && endIndex > -1 && endIndex > startIndex) {
|
||||
// Take string till comment start
|
||||
selText = selText.substr(0, startIndex)
|
||||
// From comment start till comment end
|
||||
+ selText.substring(startIndex + curMode.commentStart.length, endIndex)
|
||||
// From comment end till string end
|
||||
+ selText.substr(endIndex + curMode.commentEnd.length);
|
||||
}
|
||||
this.replaceRange(selText, from, to);
|
||||
}
|
||||
});
|
||||
|
||||
// Applies automatic mode-aware indentation to the specified range
|
||||
CodeMirror.defineExtension("autoIndentRange", function (from, to) {
|
||||
var cmInstance = this;
|
||||
this.operation(function () {
|
||||
for (var i = from.line; i <= to.line; i++) {
|
||||
cmInstance.indentLine(i, "smart");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Applies automatic formatting to the specified range
|
||||
CodeMirror.defineExtension("autoFormatRange", function (from, to) {
|
||||
var absStart = this.indexFromPos(from);
|
||||
var absEnd = this.indexFromPos(to);
|
||||
// Insert additional line breaks where necessary according to the
|
||||
// mode's syntax
|
||||
var res = this.getModeExt().autoFormatLineBreaks(this.getValue(), absStart, absEnd);
|
||||
var cmInstance = this;
|
||||
|
||||
// Replace and auto-indent the range
|
||||
this.operation(function () {
|
||||
cmInstance.replaceRange(res, from, to);
|
||||
var startLine = cmInstance.posFromIndex(absStart).line;
|
||||
var endLine = cmInstance.posFromIndex(absStart + res.length).line;
|
||||
for (var i = startLine; i <= endLine; i++) {
|
||||
cmInstance.indentLine(i, "smart");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Define extensions for a few modes
|
||||
|
||||
CodeMirror.modeExtensions["css"] = {
|
||||
commentStart: "/*",
|
||||
commentEnd: "*/",
|
||||
wordWrapChars: [";", "\\{", "\\}"],
|
||||
autoFormatLineBreaks: function (text) {
|
||||
return text.replace(new RegExp("(;|\\{|\\})([^\r\n])", "g"), "$1\n$2");
|
||||
}
|
||||
};
|
||||
|
||||
CodeMirror.modeExtensions["javascript"] = {
|
||||
commentStart: "/*",
|
||||
commentEnd: "*/",
|
||||
wordWrapChars: [";", "\\{", "\\}"],
|
||||
|
||||
getNonBreakableBlocks: function (text) {
|
||||
var nonBreakableRegexes = [
|
||||
new RegExp("for\\s*?\\(([\\s\\S]*?)\\)"),
|
||||
new RegExp("'([\\s\\S]*?)('|$)"),
|
||||
new RegExp("\"([\\s\\S]*?)(\"|$)"),
|
||||
new RegExp("//.*([\r\n]|$)")
|
||||
];
|
||||
var nonBreakableBlocks = new Array();
|
||||
for (var i = 0; i < nonBreakableRegexes.length; i++) {
|
||||
var curPos = 0;
|
||||
while (curPos < text.length) {
|
||||
var m = text.substr(curPos).match(nonBreakableRegexes[i]);
|
||||
if (m != null) {
|
||||
nonBreakableBlocks.push({
|
||||
start: curPos + m.index,
|
||||
end: curPos + m.index + m[0].length
|
||||
});
|
||||
curPos += m.index + Math.max(1, m[0].length);
|
||||
}
|
||||
else { // No more matches
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
nonBreakableBlocks.sort(function (a, b) {
|
||||
return a.start - b.start;
|
||||
});
|
||||
|
||||
return nonBreakableBlocks;
|
||||
},
|
||||
|
||||
autoFormatLineBreaks: function (text) {
|
||||
var curPos = 0;
|
||||
var reLinesSplitter = new RegExp("(;|\\{|\\})([^\r\n])", "g");
|
||||
var nonBreakableBlocks = this.getNonBreakableBlocks(text);
|
||||
if (nonBreakableBlocks != null) {
|
||||
var res = "";
|
||||
for (var i = 0; i < nonBreakableBlocks.length; i++) {
|
||||
if (nonBreakableBlocks[i].start > curPos) { // Break lines till the block
|
||||
res += text.substring(curPos, nonBreakableBlocks[i].start).replace(reLinesSplitter, "$1\n$2");
|
||||
curPos = nonBreakableBlocks[i].start;
|
||||
}
|
||||
if (nonBreakableBlocks[i].start <= curPos
|
||||
&& nonBreakableBlocks[i].end >= curPos) { // Skip non-breakable block
|
||||
res += text.substring(curPos, nonBreakableBlocks[i].end);
|
||||
curPos = nonBreakableBlocks[i].end;
|
||||
}
|
||||
}
|
||||
if (curPos < text.length - 1) {
|
||||
res += text.substr(curPos).replace(reLinesSplitter, "$1\n$2");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
else {
|
||||
return text.replace(reLinesSplitter, "$1\n$2");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CodeMirror.modeExtensions["xml"] = {
|
||||
commentStart: "<!--",
|
||||
commentEnd: "-->",
|
||||
wordWrapChars: [">"],
|
||||
|
||||
autoFormatLineBreaks: function (text) {
|
||||
var lines = text.split("\n");
|
||||
var reProcessedPortion = new RegExp("(^\\s*?<|^[^<]*?)(.+)(>\\s*?$|[^>]*?$)");
|
||||
var reOpenBrackets = new RegExp("<", "g");
|
||||
var reCloseBrackets = new RegExp("(>)([^\r\n])", "g");
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
var mToProcess = lines[i].match(reProcessedPortion);
|
||||
if (mToProcess != null && mToProcess.length > 3) { // The line starts with whitespaces and ends with whitespaces
|
||||
lines[i] = mToProcess[1]
|
||||
+ mToProcess[2].replace(reOpenBrackets, "\n$&").replace(reCloseBrackets, "$1\n$2")
|
||||
+ mToProcess[3];
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return lines.join("\n");
|
||||
}
|
||||
};
|
||||
|
||||
CodeMirror.modeExtensions["htmlmixed"] = {
|
||||
commentStart: "<!--",
|
||||
commentEnd: "-->",
|
||||
wordWrapChars: [">", ";", "\\{", "\\}"],
|
||||
|
||||
getModeInfos: function (text, absPos) {
|
||||
var modeInfos = new Array();
|
||||
modeInfos[0] =
|
||||
{
|
||||
pos: 0,
|
||||
modeExt: CodeMirror.modeExtensions["xml"],
|
||||
modeName: "xml"
|
||||
};
|
||||
|
||||
var modeMatchers = new Array();
|
||||
modeMatchers[0] =
|
||||
{
|
||||
regex: new RegExp("<style[^>]*>([\\s\\S]*?)(</style[^>]*>|$)", "i"),
|
||||
modeExt: CodeMirror.modeExtensions["css"],
|
||||
modeName: "css"
|
||||
};
|
||||
modeMatchers[1] =
|
||||
{
|
||||
regex: new RegExp("<script[^>]*>([\\s\\S]*?)(</script[^>]*>|$)", "i"),
|
||||
modeExt: CodeMirror.modeExtensions["javascript"],
|
||||
modeName: "javascript"
|
||||
};
|
||||
|
||||
var lastCharPos = (typeof (absPos) !== "undefined" ? absPos : text.length - 1);
|
||||
// Detect modes for the entire text
|
||||
for (var i = 0; i < modeMatchers.length; i++) {
|
||||
var curPos = 0;
|
||||
while (curPos <= lastCharPos) {
|
||||
var m = text.substr(curPos).match(modeMatchers[i].regex);
|
||||
if (m != null) {
|
||||
if (m.length > 1 && m[1].length > 0) {
|
||||
// Push block begin pos
|
||||
var blockBegin = curPos + m.index + m[0].indexOf(m[1]);
|
||||
modeInfos.push(
|
||||
{
|
||||
pos: blockBegin,
|
||||
modeExt: modeMatchers[i].modeExt,
|
||||
modeName: modeMatchers[i].modeName
|
||||
});
|
||||
// Push block end pos
|
||||
modeInfos.push(
|
||||
{
|
||||
pos: blockBegin + m[1].length,
|
||||
modeExt: modeInfos[0].modeExt,
|
||||
modeName: modeInfos[0].modeName
|
||||
});
|
||||
curPos += m.index + m[0].length;
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
curPos += m.index + Math.max(m[0].length, 1);
|
||||
}
|
||||
}
|
||||
else { // No more matches
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Sort mode infos
|
||||
modeInfos.sort(function sortModeInfo(a, b) {
|
||||
return a.pos - b.pos;
|
||||
});
|
||||
|
||||
return modeInfos;
|
||||
},
|
||||
|
||||
autoFormatLineBreaks: function (text, startPos, endPos) {
|
||||
var modeInfos = this.getModeInfos(text);
|
||||
var reBlockStartsWithNewline = new RegExp("^\\s*?\n");
|
||||
var reBlockEndsWithNewline = new RegExp("\n\\s*?$");
|
||||
var res = "";
|
||||
// Use modes info to break lines correspondingly
|
||||
if (modeInfos.length > 1) { // Deal with multi-mode text
|
||||
for (var i = 1; i <= modeInfos.length; i++) {
|
||||
var selStart = modeInfos[i - 1].pos;
|
||||
var selEnd = (i < modeInfos.length ? modeInfos[i].pos : endPos);
|
||||
|
||||
if (selStart >= endPos) { // The block starts later than the needed fragment
|
||||
break;
|
||||
}
|
||||
if (selStart < startPos) {
|
||||
if (selEnd <= startPos) { // The block starts earlier than the needed fragment
|
||||
continue;
|
||||
}
|
||||
selStart = startPos;
|
||||
}
|
||||
if (selEnd > endPos) {
|
||||
selEnd = endPos;
|
||||
}
|
||||
var textPortion = text.substring(selStart, selEnd);
|
||||
if (modeInfos[i - 1].modeName != "xml") { // Starting a CSS or JavaScript block
|
||||
if (!reBlockStartsWithNewline.test(textPortion)
|
||||
&& selStart > 0) { // The block does not start with a line break
|
||||
textPortion = "\n" + textPortion;
|
||||
}
|
||||
if (!reBlockEndsWithNewline.test(textPortion)
|
||||
&& selEnd < text.length - 1) { // The block does not end with a line break
|
||||
textPortion += "\n";
|
||||
}
|
||||
}
|
||||
res += modeInfos[i - 1].modeExt.autoFormatLineBreaks(textPortion);
|
||||
}
|
||||
}
|
||||
else { // Single-mode text
|
||||
res = modeInfos[0].modeExt.autoFormatLineBreaks(text.substring(startPos, endPos));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
};
|
||||
@@ -1,134 +0,0 @@
|
||||
(function () {
|
||||
function forEach(arr, f) {
|
||||
for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]);
|
||||
}
|
||||
|
||||
function arrayContains(arr, item) {
|
||||
if (!Array.prototype.indexOf) {
|
||||
var i = arr.length;
|
||||
while (i--) {
|
||||
if (arr[i] === item) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return arr.indexOf(item) != -1;
|
||||
}
|
||||
|
||||
function scriptHint(editor, keywords, getToken) {
|
||||
// Find the token at the cursor
|
||||
var cur = editor.getCursor(), token = getToken(editor, cur), tprop = token;
|
||||
// If it's not a 'word-style' token, ignore the token.
|
||||
if (!/^[\w$_]*$/.test(token.string)) {
|
||||
token = tprop = {start: cur.ch, end: cur.ch, string: "", state: token.state,
|
||||
className: token.string == "." ? "property" : null};
|
||||
}
|
||||
// If it is a property, find out what it is a property of.
|
||||
while (tprop.className == "property") {
|
||||
tprop = getToken(editor, {line: cur.line, ch: tprop.start});
|
||||
if (tprop.string != ".") return;
|
||||
tprop = getToken(editor, {line: cur.line, ch: tprop.start});
|
||||
if (tprop.string == ')') {
|
||||
var level = 1;
|
||||
do {
|
||||
tprop = getToken(editor, {line: cur.line, ch: tprop.start});
|
||||
switch (tprop.string) {
|
||||
case ')': level++; break;
|
||||
case '(': level--; break;
|
||||
default: break;
|
||||
}
|
||||
} while (level > 0)
|
||||
tprop = getToken(editor, {line: cur.line, ch: tprop.start});
|
||||
if (tprop.className == 'variable')
|
||||
tprop.className = 'function';
|
||||
else return; // no clue
|
||||
}
|
||||
if (!context) var context = [];
|
||||
context.push(tprop);
|
||||
}
|
||||
return {list: getCompletions(token, context, keywords),
|
||||
from: {line: cur.line, ch: token.start},
|
||||
to: {line: cur.line, ch: token.end}};
|
||||
}
|
||||
|
||||
CodeMirror.javascriptHint = function(editor) {
|
||||
return scriptHint(editor, javascriptKeywords,
|
||||
function (e, cur) {return e.getTokenAt(cur);});
|
||||
}
|
||||
|
||||
function getCoffeeScriptToken(editor, cur) {
|
||||
// This getToken, it is for coffeescript, imitates the behavior of
|
||||
// getTokenAt method in javascript.js, that is, returning "property"
|
||||
// type and treat "." as indepenent token.
|
||||
var token = editor.getTokenAt(cur);
|
||||
if (cur.ch == token.start + 1 && token.string.charAt(0) == '.') {
|
||||
token.end = token.start;
|
||||
token.string = '.';
|
||||
token.className = "property";
|
||||
}
|
||||
else if (/^\.[\w$_]*$/.test(token.string)) {
|
||||
token.className = "property";
|
||||
token.start++;
|
||||
token.string = token.string.replace(/\./, '');
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
CodeMirror.coffeescriptHint = function(editor) {
|
||||
return scriptHint(editor, coffeescriptKeywords, getCoffeeScriptToken);
|
||||
}
|
||||
|
||||
var stringProps = ("charAt charCodeAt indexOf lastIndexOf substring substr slice trim trimLeft trimRight " +
|
||||
"toUpperCase toLowerCase split concat match replace search").split(" ");
|
||||
var arrayProps = ("length concat join splice push pop shift unshift slice reverse sort indexOf " +
|
||||
"lastIndexOf every some filter forEach map reduce reduceRight ").split(" ");
|
||||
var funcProps = "prototype apply call bind".split(" ");
|
||||
var javascriptKeywords = ("break case catch continue debugger default delete do else false finally for function " +
|
||||
"if in instanceof new null return switch throw true try typeof var void while with").split(" ");
|
||||
var coffeescriptKeywords = ("and break catch class continue delete do else extends false finally for " +
|
||||
"if in instanceof isnt new no not null of off on or return switch then throw true try typeof until void while with yes").split(" ");
|
||||
|
||||
function getCompletions(token, context, keywords) {
|
||||
var found = [], start = token.string;
|
||||
function maybeAdd(str) {
|
||||
if (str.indexOf(start) == 0 && !arrayContains(found, str)) found.push(str);
|
||||
}
|
||||
function gatherCompletions(obj) {
|
||||
if (typeof obj == "string") forEach(stringProps, maybeAdd);
|
||||
else if (obj instanceof Array) forEach(arrayProps, maybeAdd);
|
||||
else if (obj instanceof Function) forEach(funcProps, maybeAdd);
|
||||
for (var name in obj) maybeAdd(name);
|
||||
}
|
||||
|
||||
if (context) {
|
||||
// If this is a property, see if it belongs to some object we can
|
||||
// find in the current environment.
|
||||
var obj = context.pop(), base;
|
||||
if (obj.className == "variable")
|
||||
base = window[obj.string];
|
||||
else if (obj.className == "string")
|
||||
base = "";
|
||||
else if (obj.className == "atom")
|
||||
base = 1;
|
||||
else if (obj.className == "function") {
|
||||
if (window.jQuery != null && (obj.string == '$' || obj.string == 'jQuery') &&
|
||||
(typeof window.jQuery == 'function'))
|
||||
base = window.jQuery();
|
||||
else if (window._ != null && (obj.string == '_') && (typeof window._ == 'function'))
|
||||
base = window._();
|
||||
}
|
||||
while (base != null && context.length)
|
||||
base = base[context.pop().string];
|
||||
if (base != null) gatherCompletions(base);
|
||||
}
|
||||
else {
|
||||
// If not, just look in the window object and any local scope
|
||||
// (reading into JS mode internals to get at the local variables)
|
||||
for (var v = token.state.localVars; v; v = v.next) maybeAdd(v.name);
|
||||
gatherCompletions(window);
|
||||
forEach(keywords, maybeAdd);
|
||||
}
|
||||
return found;
|
||||
}
|
||||
})();
|
||||
@@ -1,51 +0,0 @@
|
||||
(function() {
|
||||
if (!CodeMirror.modeURL) CodeMirror.modeURL = "../mode/%N/%N.js";
|
||||
|
||||
var loading = {};
|
||||
function splitCallback(cont, n) {
|
||||
var countDown = n;
|
||||
return function() { if (--countDown == 0) cont(); }
|
||||
}
|
||||
function ensureDeps(mode, cont) {
|
||||
var deps = CodeMirror.modes[mode].dependencies;
|
||||
if (!deps) return cont();
|
||||
var missing = [];
|
||||
for (var i = 0; i < deps.length; ++i) {
|
||||
if (!CodeMirror.modes.hasOwnProperty(deps[i]))
|
||||
missing.push(deps[i]);
|
||||
}
|
||||
if (!missing.length) return cont();
|
||||
var split = splitCallback(cont, missing.length);
|
||||
for (var i = 0; i < missing.length; ++i)
|
||||
CodeMirror.requireMode(missing[i], split);
|
||||
}
|
||||
|
||||
CodeMirror.requireMode = function(mode, cont) {
|
||||
if (typeof mode != "string") mode = mode.name;
|
||||
if (CodeMirror.modes.hasOwnProperty(mode)) return ensureDeps(mode, cont);
|
||||
if (loading.hasOwnProperty(mode)) return loading[mode].push(cont);
|
||||
|
||||
var script = document.createElement("script");
|
||||
script.src = CodeMirror.modeURL.replace(/%N/g, mode);
|
||||
var others = document.getElementsByTagName("script")[0];
|
||||
others.parentNode.insertBefore(script, others);
|
||||
var list = loading[mode] = [cont];
|
||||
var count = 0, poll = setInterval(function() {
|
||||
if (++count > 100) return clearInterval(poll);
|
||||
if (CodeMirror.modes.hasOwnProperty(mode)) {
|
||||
clearInterval(poll);
|
||||
loading[mode] = null;
|
||||
ensureDeps(mode, function() {
|
||||
for (var i = 0; i < list.length; ++i) list[i]();
|
||||
});
|
||||
}
|
||||
}, 200);
|
||||
};
|
||||
|
||||
CodeMirror.autoLoadMode = function(instance, mode) {
|
||||
if (!CodeMirror.modes.hasOwnProperty(mode))
|
||||
CodeMirror.requireMode(mode, function() {
|
||||
instance.setOption("mode", instance.getOption("mode"));
|
||||
});
|
||||
};
|
||||
}());
|
||||
@@ -1,51 +0,0 @@
|
||||
// Utility function that allows modes to be combined. The mode given
|
||||
// as the base argument takes care of most of the normal mode
|
||||
// functionality, but a second (typically simple) mode is used, which
|
||||
// can override the style of text. Both modes get to parse all of the
|
||||
// text, but when both assign a non-null style to a piece of code, the
|
||||
// overlay wins, unless the combine argument was true, in which case
|
||||
// the styles are combined.
|
||||
|
||||
CodeMirror.overlayParser = function(base, overlay, combine) {
|
||||
return {
|
||||
startState: function() {
|
||||
return {
|
||||
base: CodeMirror.startState(base),
|
||||
overlay: CodeMirror.startState(overlay),
|
||||
basePos: 0, baseCur: null,
|
||||
overlayPos: 0, overlayCur: null
|
||||
};
|
||||
},
|
||||
copyState: function(state) {
|
||||
return {
|
||||
base: CodeMirror.copyState(base, state.base),
|
||||
overlay: CodeMirror.copyState(overlay, state.overlay),
|
||||
basePos: state.basePos, baseCur: null,
|
||||
overlayPos: state.overlayPos, overlayCur: null
|
||||
};
|
||||
},
|
||||
|
||||
token: function(stream, state) {
|
||||
if (stream.start == state.basePos) {
|
||||
state.baseCur = base.token(stream, state.base);
|
||||
state.basePos = stream.pos;
|
||||
}
|
||||
if (stream.start == state.overlayPos) {
|
||||
stream.pos = stream.start;
|
||||
state.overlayCur = overlay.token(stream, state.overlay);
|
||||
state.overlayPos = stream.pos;
|
||||
}
|
||||
stream.pos = Math.min(state.basePos, state.overlayPos);
|
||||
if (stream.eol()) state.basePos = state.overlayPos = 0;
|
||||
|
||||
if (state.overlayCur == null) return state.baseCur;
|
||||
if (state.baseCur != null && combine) return state.baseCur + " " + state.overlayCur;
|
||||
else return state.overlayCur;
|
||||
},
|
||||
|
||||
indent: base.indent && function(state, textAfter) {
|
||||
return base.indent(state.base, textAfter);
|
||||
},
|
||||
electricChars: base.electricChars
|
||||
};
|
||||
};
|
||||
@@ -1,49 +0,0 @@
|
||||
CodeMirror.runMode = function(string, modespec, callback, options) {
|
||||
var mode = CodeMirror.getMode(CodeMirror.defaults, modespec);
|
||||
var isNode = callback.nodeType == 1;
|
||||
var tabSize = (options && options.tabSize) || CodeMirror.defaults.tabSize;
|
||||
if (isNode) {
|
||||
var node = callback, accum = [], col = 0;
|
||||
callback = function(text, style) {
|
||||
if (text == "\n") {
|
||||
accum.push("<br>");
|
||||
col = 0;
|
||||
return;
|
||||
}
|
||||
var escaped = "";
|
||||
// HTML-escape and replace tabs
|
||||
for (var pos = 0;;) {
|
||||
var idx = text.indexOf("\t", pos);
|
||||
if (idx == -1) {
|
||||
escaped += CodeMirror.htmlEscape(text.slice(pos));
|
||||
col += text.length - pos;
|
||||
break;
|
||||
} else {
|
||||
col += idx - pos;
|
||||
escaped += CodeMirror.htmlEscape(text.slice(pos, idx));
|
||||
var size = tabSize - col % tabSize;
|
||||
col += size;
|
||||
for (var i = 0; i < size; ++i) escaped += " ";
|
||||
pos = idx + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (style)
|
||||
accum.push("<span class=\"cm-" + CodeMirror.htmlEscape(style) + "\">" + escaped + "</span>");
|
||||
else
|
||||
accum.push(escaped);
|
||||
}
|
||||
}
|
||||
var lines = CodeMirror.splitLines(string), state = CodeMirror.startState(mode);
|
||||
for (var i = 0, e = lines.length; i < e; ++i) {
|
||||
if (i) callback("\n");
|
||||
var stream = new CodeMirror.StringStream(lines[i]);
|
||||
while (!stream.eol()) {
|
||||
var style = mode.token(stream, state);
|
||||
callback(stream.current(), style, i, stream.start);
|
||||
stream.start = stream.pos;
|
||||
}
|
||||
}
|
||||
if (isNode)
|
||||
node.innerHTML = accum.join("");
|
||||
};
|
||||
@@ -1,114 +0,0 @@
|
||||
// Define search commands. Depends on dialog.js or another
|
||||
// implementation of the openDialog method.
|
||||
|
||||
// Replace works a little oddly -- it will do the replace on the next
|
||||
// Ctrl-G (or whatever is bound to findNext) press. You prevent a
|
||||
// replace by making sure the match is no longer selected when hitting
|
||||
// Ctrl-G.
|
||||
|
||||
(function() {
|
||||
function SearchState() {
|
||||
this.posFrom = this.posTo = this.query = null;
|
||||
this.marked = [];
|
||||
}
|
||||
function getSearchState(cm) {
|
||||
return cm._searchState || (cm._searchState = new SearchState());
|
||||
}
|
||||
function dialog(cm, text, shortText, f) {
|
||||
if (cm.openDialog) cm.openDialog(text, f);
|
||||
else f(prompt(shortText, ""));
|
||||
}
|
||||
function confirmDialog(cm, text, shortText, fs) {
|
||||
if (cm.openConfirm) cm.openConfirm(text, fs);
|
||||
else if (confirm(shortText)) fs[0]();
|
||||
}
|
||||
function parseQuery(query) {
|
||||
var isRE = query.match(/^\/(.*)\/$/);
|
||||
return isRE ? new RegExp(isRE[1]) : query;
|
||||
}
|
||||
var queryDialog =
|
||||
'Search: <input type="text" style="width: 10em"/> <span style="color: #888">(Use /re/ syntax for regexp search)</span>';
|
||||
function doSearch(cm, rev) {
|
||||
var state = getSearchState(cm);
|
||||
if (state.query) return findNext(cm, rev);
|
||||
dialog(cm, queryDialog, "Search for:", function(query) {
|
||||
cm.operation(function() {
|
||||
if (!query || state.query) return;
|
||||
state.query = parseQuery(query);
|
||||
if (cm.lineCount() < 2000) { // This is too expensive on big documents.
|
||||
for (var cursor = cm.getSearchCursor(query); cursor.findNext();)
|
||||
state.marked.push(cm.markText(cursor.from(), cursor.to(), "CodeMirror-searching"));
|
||||
}
|
||||
state.posFrom = state.posTo = cm.getCursor();
|
||||
findNext(cm, rev);
|
||||
});
|
||||
});
|
||||
}
|
||||
function findNext(cm, rev) {cm.operation(function() {
|
||||
var state = getSearchState(cm);
|
||||
var cursor = cm.getSearchCursor(state.query, rev ? state.posFrom : state.posTo);
|
||||
if (!cursor.find(rev)) {
|
||||
cursor = cm.getSearchCursor(state.query, rev ? {line: cm.lineCount() - 1} : {line: 0, ch: 0});
|
||||
if (!cursor.find(rev)) return;
|
||||
}
|
||||
cm.setSelection(cursor.from(), cursor.to());
|
||||
state.posFrom = cursor.from(); state.posTo = cursor.to();
|
||||
})}
|
||||
function clearSearch(cm) {cm.operation(function() {
|
||||
var state = getSearchState(cm);
|
||||
if (!state.query) return;
|
||||
state.query = null;
|
||||
for (var i = 0; i < state.marked.length; ++i) state.marked[i].clear();
|
||||
state.marked.length = 0;
|
||||
})}
|
||||
|
||||
var replaceQueryDialog =
|
||||
'Replace: <input type="text" style="width: 10em"/> <span style="color: #888">(Use /re/ syntax for regexp search)</span>';
|
||||
var replacementQueryDialog = 'With: <input type="text" style="width: 10em"/>';
|
||||
var doReplaceConfirm = "Replace? <button>Yes</button> <button>No</button> <button>Stop</button>";
|
||||
function replace(cm, all) {
|
||||
dialog(cm, replaceQueryDialog, "Replace:", function(query) {
|
||||
if (!query) return;
|
||||
query = parseQuery(query);
|
||||
dialog(cm, replacementQueryDialog, "Replace with:", function(text) {
|
||||
if (all) {
|
||||
cm.compoundChange(function() { cm.operation(function() {
|
||||
for (var cursor = cm.getSearchCursor(query); cursor.findNext();) {
|
||||
if (typeof query != "string") {
|
||||
var match = cm.getRange(cursor.from(), cursor.to()).match(query);
|
||||
cursor.replace(text.replace(/\$(\d)/, function(w, i) {return match[i];}));
|
||||
} else cursor.replace(text);
|
||||
}
|
||||
})});
|
||||
} else {
|
||||
clearSearch(cm);
|
||||
var cursor = cm.getSearchCursor(query, cm.getCursor());
|
||||
function advance() {
|
||||
var start = cursor.from(), match;
|
||||
if (!(match = cursor.findNext())) {
|
||||
cursor = cm.getSearchCursor(query);
|
||||
if (!(match = cursor.findNext()) ||
|
||||
(cursor.from().line == start.line && cursor.from().ch == start.ch)) return;
|
||||
}
|
||||
cm.setSelection(cursor.from(), cursor.to());
|
||||
confirmDialog(cm, doReplaceConfirm, "Replace?",
|
||||
[function() {doReplace(match);}, advance]);
|
||||
}
|
||||
function doReplace(match) {
|
||||
cursor.replace(typeof query == "string" ? text :
|
||||
text.replace(/\$(\d)/, function(w, i) {return match[i];}));
|
||||
advance();
|
||||
}
|
||||
advance();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
CodeMirror.commands.find = function(cm) {clearSearch(cm); doSearch(cm);};
|
||||
CodeMirror.commands.findNext = doSearch;
|
||||
CodeMirror.commands.findPrev = function(cm) {doSearch(cm, true);};
|
||||
CodeMirror.commands.clearSearch = clearSearch;
|
||||
CodeMirror.commands.replace = replace;
|
||||
CodeMirror.commands.replaceAll = function(cm) {replace(cm, true);};
|
||||
})();
|
||||
@@ -1,16 +0,0 @@
|
||||
.CodeMirror-completions {
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
overflow: hidden;
|
||||
-webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
|
||||
-moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
|
||||
box-shadow: 2px 3px 5px rgba(0,0,0,.2);
|
||||
}
|
||||
.CodeMirror-completions select {
|
||||
background: #fafafa;
|
||||
outline: none;
|
||||
border: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-family: monospace;
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
(function() {
|
||||
CodeMirror.simpleHint = function(editor, getHints) {
|
||||
// We want a single cursor position.
|
||||
if (editor.somethingSelected()) return;
|
||||
var result = getHints(editor);
|
||||
if (!result || !result.list.length) return;
|
||||
var completions = result.list;
|
||||
function insert(str) {
|
||||
editor.replaceRange(str, result.from, result.to);
|
||||
}
|
||||
// When there is only one completion, use it directly.
|
||||
if (completions.length == 1) {insert(completions[0]); return true;}
|
||||
|
||||
// Build the select widget
|
||||
var complete = document.createElement("div");
|
||||
complete.className = "CodeMirror-completions";
|
||||
var sel = complete.appendChild(document.createElement("select"));
|
||||
// Opera doesn't move the selection when pressing up/down in a
|
||||
// multi-select, but it does properly support the size property on
|
||||
// single-selects, so no multi-select is necessary.
|
||||
if (!window.opera) sel.multiple = true;
|
||||
for (var i = 0; i < completions.length; ++i) {
|
||||
var opt = sel.appendChild(document.createElement("option"));
|
||||
opt.appendChild(document.createTextNode(completions[i]));
|
||||
}
|
||||
sel.firstChild.selected = true;
|
||||
sel.size = Math.min(10, completions.length);
|
||||
var pos = editor.cursorCoords();
|
||||
complete.style.left = pos.x + "px";
|
||||
complete.style.top = pos.yBot + "px";
|
||||
document.body.appendChild(complete);
|
||||
// If we're at the edge of the screen, then we want the menu to appear on the left of the cursor.
|
||||
var winW = window.innerWidth || Math.max(document.body.offsetWidth, document.documentElement.offsetWidth);
|
||||
if(winW - pos.x < sel.clientWidth)
|
||||
complete.style.left = (pos.x - sel.clientWidth) + "px";
|
||||
// Hack to hide the scrollbar.
|
||||
if (completions.length <= 10)
|
||||
complete.style.width = (sel.clientWidth - 1) + "px";
|
||||
|
||||
var done = false;
|
||||
function close() {
|
||||
if (done) return;
|
||||
done = true;
|
||||
complete.parentNode.removeChild(complete);
|
||||
}
|
||||
function pick() {
|
||||
insert(completions[sel.selectedIndex]);
|
||||
close();
|
||||
setTimeout(function(){editor.focus();}, 50);
|
||||
}
|
||||
CodeMirror.connect(sel, "blur", close);
|
||||
CodeMirror.connect(sel, "keydown", function(event) {
|
||||
var code = event.keyCode;
|
||||
// Enter
|
||||
if (code == 13) {CodeMirror.e_stop(event); pick();}
|
||||
// Escape
|
||||
else if (code == 27) {CodeMirror.e_stop(event); close(); editor.focus();}
|
||||
else if (code != 38 && code != 40) {
|
||||
close(); editor.focus();
|
||||
// Pass the event to the CodeMirror instance so that it can handle things like backspace properly.
|
||||
editor.triggerOnKeyDown(event);
|
||||
setTimeout(function(){CodeMirror.simpleHint(editor, getHints);}, 50);
|
||||
}
|
||||
});
|
||||
CodeMirror.connect(sel, "dblclick", pick);
|
||||
|
||||
sel.focus();
|
||||
// Opera sometimes ignores focusing a freshly created node
|
||||
if (window.opera) setTimeout(function(){if (!done) sel.focus();}, 100);
|
||||
return true;
|
||||
};
|
||||
})();
|
||||
@@ -1,101 +0,0 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>CodeMirror: C-like mode</title>
|
||||
<link rel="stylesheet" href="../../lib/codemirror.css">
|
||||
<script src="../../lib/codemirror.js"></script>
|
||||
<script src="clike.js"></script>
|
||||
<link rel="stylesheet" href="../../doc/docs.css">
|
||||
<style>.CodeMirror {border: 2px inset #dee;}</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>CodeMirror: C-like mode</h1>
|
||||
|
||||
<form><textarea id="code" name="code">
|
||||
/* C demo code */
|
||||
|
||||
#include <zmq.h>
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <malloc.h>
|
||||
|
||||
typedef struct {
|
||||
void* arg_socket;
|
||||
zmq_msg_t* arg_msg;
|
||||
char* arg_string;
|
||||
unsigned long arg_len;
|
||||
int arg_int, arg_command;
|
||||
|
||||
int signal_fd;
|
||||
int pad;
|
||||
void* context;
|
||||
sem_t sem;
|
||||
} acl_zmq_context;
|
||||
|
||||
#define p(X) (context->arg_##X)
|
||||
|
||||
void* zmq_thread(void* context_pointer) {
|
||||
acl_zmq_context* context = (acl_zmq_context*)context_pointer;
|
||||
char ok = 'K', err = 'X';
|
||||
int res;
|
||||
|
||||
while (1) {
|
||||
while ((res = sem_wait(&context->sem)) == EINTR);
|
||||
if (res) {write(context->signal_fd, &err, 1); goto cleanup;}
|
||||
switch(p(command)) {
|
||||
case 0: goto cleanup;
|
||||
case 1: p(socket) = zmq_socket(context->context, p(int)); break;
|
||||
case 2: p(int) = zmq_close(p(socket)); break;
|
||||
case 3: p(int) = zmq_bind(p(socket), p(string)); break;
|
||||
case 4: p(int) = zmq_connect(p(socket), p(string)); break;
|
||||
case 5: p(int) = zmq_getsockopt(p(socket), p(int), (void*)p(string), &p(len)); break;
|
||||
case 6: p(int) = zmq_setsockopt(p(socket), p(int), (void*)p(string), p(len)); break;
|
||||
case 7: p(int) = zmq_send(p(socket), p(msg), p(int)); break;
|
||||
case 8: p(int) = zmq_recv(p(socket), p(msg), p(int)); break;
|
||||
case 9: p(int) = zmq_poll(p(socket), p(int), p(len)); break;
|
||||
}
|
||||
p(command) = errno;
|
||||
write(context->signal_fd, &ok, 1);
|
||||
}
|
||||
cleanup:
|
||||
close(context->signal_fd);
|
||||
free(context_pointer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* zmq_thread_init(void* zmq_context, int signal_fd) {
|
||||
acl_zmq_context* context = malloc(sizeof(acl_zmq_context));
|
||||
pthread_t thread;
|
||||
|
||||
context->context = zmq_context;
|
||||
context->signal_fd = signal_fd;
|
||||
sem_init(&context->sem, 1, 0);
|
||||
pthread_create(&thread, 0, &zmq_thread, context);
|
||||
pthread_detach(thread);
|
||||
return context;
|
||||
}
|
||||
</textarea></form>
|
||||
|
||||
<script>
|
||||
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
|
||||
lineNumbers: true,
|
||||
matchBrackets: true,
|
||||
mode: "text/x-csrc"
|
||||
});
|
||||
</script>
|
||||
|
||||
<p>Simple mode that tries to handle C-like languages as well as it
|
||||
can. Takes two configuration parameters: <code>keywords</code>, an
|
||||
object whose property names are the keywords in the language,
|
||||
and <code>useCPP</code>, which determines whether C preprocessor
|
||||
directives are recognized.</p>
|
||||
|
||||
<p><strong>MIME types defined:</strong> <code>text/x-csrc</code>
|
||||
(C code), <code>text/x-c++src</code> (C++
|
||||
code), <code>text/x-java</code> (Java
|
||||
code), <code>text/x-csharp</code> (C#).</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,727 +0,0 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>CodeMirror: CoffeeScript mode</title>
|
||||
<link rel="stylesheet" href="../../lib/codemirror.css">
|
||||
<script src="../../lib/codemirror.js"></script>
|
||||
<script src="coffeescript.js"></script>
|
||||
<style>.CodeMirror {border-top: 1px solid silver; border-bottom: 1px solid silver;}</style>
|
||||
<link rel="stylesheet" href="../../doc/docs.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>CodeMirror: CoffeeScript mode</h1>
|
||||
<form><textarea id="code" name="code">
|
||||
# CoffeeScript mode for CodeMirror
|
||||
# Copyright (c) 2011 Jeff Pickhardt, released under
|
||||
# the MIT License.
|
||||
#
|
||||
# Modified from the Python CodeMirror mode, which also is
|
||||
# under the MIT License Copyright (c) 2010 Timothy Farrell.
|
||||
#
|
||||
# The following script, Underscore.coffee, is used to
|
||||
# demonstrate CoffeeScript mode for CodeMirror.
|
||||
#
|
||||
# To download CoffeeScript mode for CodeMirror, go to:
|
||||
# https://github.com/pickhardt/coffeescript-codemirror-mode
|
||||
|
||||
# **Underscore.coffee
|
||||
# (c) 2011 Jeremy Ashkenas, DocumentCloud Inc.**
|
||||
# Underscore is freely distributable under the terms of the
|
||||
# [MIT license](http://en.wikipedia.org/wiki/MIT_License).
|
||||
# Portions of Underscore are inspired by or borrowed from
|
||||
# [Prototype.js](http://prototypejs.org/api), Oliver Steele's
|
||||
# [Functional](http://osteele.com), and John Resig's
|
||||
# [Micro-Templating](http://ejohn.org).
|
||||
# For all details and documentation:
|
||||
# http://documentcloud.github.com/underscore/
|
||||
|
||||
|
||||
# Baseline setup
|
||||
# --------------
|
||||
|
||||
# Establish the root object, `window` in the browser, or `global` on the server.
|
||||
root = this
|
||||
|
||||
|
||||
# Save the previous value of the `_` variable.
|
||||
previousUnderscore = root._
|
||||
|
||||
### Multiline
|
||||
comment
|
||||
###
|
||||
|
||||
# Establish the object that gets thrown to break out of a loop iteration.
|
||||
# `StopIteration` is SOP on Mozilla.
|
||||
breaker = if typeof(StopIteration) is 'undefined' then '__break__' else StopIteration
|
||||
|
||||
|
||||
#### Docco style single line comment (title)
|
||||
|
||||
|
||||
# Helper function to escape **RegExp** contents, because JS doesn't have one.
|
||||
escapeRegExp = (string) -> string.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1')
|
||||
|
||||
|
||||
# Save bytes in the minified (but not gzipped) version:
|
||||
ArrayProto = Array.prototype
|
||||
ObjProto = Object.prototype
|
||||
|
||||
|
||||
# Create quick reference variables for speed access to core prototypes.
|
||||
slice = ArrayProto.slice
|
||||
unshift = ArrayProto.unshift
|
||||
toString = ObjProto.toString
|
||||
hasOwnProperty = ObjProto.hasOwnProperty
|
||||
propertyIsEnumerable = ObjProto.propertyIsEnumerable
|
||||
|
||||
|
||||
# All **ECMA5** native implementations we hope to use are declared here.
|
||||
nativeForEach = ArrayProto.forEach
|
||||
nativeMap = ArrayProto.map
|
||||
nativeReduce = ArrayProto.reduce
|
||||
nativeReduceRight = ArrayProto.reduceRight
|
||||
nativeFilter = ArrayProto.filter
|
||||
nativeEvery = ArrayProto.every
|
||||
nativeSome = ArrayProto.some
|
||||
nativeIndexOf = ArrayProto.indexOf
|
||||
nativeLastIndexOf = ArrayProto.lastIndexOf
|
||||
nativeIsArray = Array.isArray
|
||||
nativeKeys = Object.keys
|
||||
|
||||
|
||||
# Create a safe reference to the Underscore object for use below.
|
||||
_ = (obj) -> new wrapper(obj)
|
||||
|
||||
|
||||
# Export the Underscore object for **CommonJS**.
|
||||
if typeof(exports) != 'undefined' then exports._ = _
|
||||
|
||||
|
||||
# Export Underscore to global scope.
|
||||
root._ = _
|
||||
|
||||
|
||||
# Current version.
|
||||
_.VERSION = '1.1.0'
|
||||
|
||||
|
||||
# Collection Functions
|
||||
# --------------------
|
||||
|
||||
# The cornerstone, an **each** implementation.
|
||||
# Handles objects implementing **forEach**, arrays, and raw objects.
|
||||
_.each = (obj, iterator, context) ->
|
||||
try
|
||||
if nativeForEach and obj.forEach is nativeForEach
|
||||
obj.forEach iterator, context
|
||||
else if _.isNumber obj.length
|
||||
iterator.call context, obj[i], i, obj for i in [0...obj.length]
|
||||
else
|
||||
iterator.call context, val, key, obj for own key, val of obj
|
||||
catch e
|
||||
throw e if e isnt breaker
|
||||
obj
|
||||
|
||||
|
||||
# Return the results of applying the iterator to each element. Use JavaScript
|
||||
# 1.6's version of **map**, if possible.
|
||||
_.map = (obj, iterator, context) ->
|
||||
return obj.map(iterator, context) if nativeMap and obj.map is nativeMap
|
||||
results = []
|
||||
_.each obj, (value, index, list) ->
|
||||
results.push iterator.call context, value, index, list
|
||||
results
|
||||
|
||||
|
||||
# **Reduce** builds up a single result from a list of values. Also known as
|
||||
# **inject**, or **foldl**. Uses JavaScript 1.8's version of **reduce**, if possible.
|
||||
_.reduce = (obj, iterator, memo, context) ->
|
||||
if nativeReduce and obj.reduce is nativeReduce
|
||||
iterator = _.bind iterator, context if context
|
||||
return obj.reduce iterator, memo
|
||||
_.each obj, (value, index, list) ->
|
||||
memo = iterator.call context, memo, value, index, list
|
||||
memo
|
||||
|
||||
|
||||
# The right-associative version of **reduce**, also known as **foldr**. Uses
|
||||
# JavaScript 1.8's version of **reduceRight**, if available.
|
||||
_.reduceRight = (obj, iterator, memo, context) ->
|
||||
if nativeReduceRight and obj.reduceRight is nativeReduceRight
|
||||
iterator = _.bind iterator, context if context
|
||||
return obj.reduceRight iterator, memo
|
||||
reversed = _.clone(_.toArray(obj)).reverse()
|
||||
_.reduce reversed, iterator, memo, context
|
||||
|
||||
|
||||
# Return the first value which passes a truth test.
|
||||
_.detect = (obj, iterator, context) ->
|
||||
result = null
|
||||
_.each obj, (value, index, list) ->
|
||||
if iterator.call context, value, index, list
|
||||
result = value
|
||||
_.breakLoop()
|
||||
result
|
||||
|
||||
|
||||
# Return all the elements that pass a truth test. Use JavaScript 1.6's
|
||||
# **filter**, if it exists.
|
||||
_.filter = (obj, iterator, context) ->
|
||||
return obj.filter iterator, context if nativeFilter and obj.filter is nativeFilter
|
||||
results = []
|
||||
_.each obj, (value, index, list) ->
|
||||
results.push value if iterator.call context, value, index, list
|
||||
results
|
||||
|
||||
|
||||
# Return all the elements for which a truth test fails.
|
||||
_.reject = (obj, iterator, context) ->
|
||||
results = []
|
||||
_.each obj, (value, index, list) ->
|
||||
results.push value if not iterator.call context, value, index, list
|
||||
results
|
||||
|
||||
|
||||
# Determine whether all of the elements match a truth test. Delegate to
|
||||
# JavaScript 1.6's **every**, if it is present.
|
||||
_.every = (obj, iterator, context) ->
|
||||
iterator ||= _.identity
|
||||
return obj.every iterator, context if nativeEvery and obj.every is nativeEvery
|
||||
result = true
|
||||
_.each obj, (value, index, list) ->
|
||||
_.breakLoop() unless (result = result and iterator.call(context, value, index, list))
|
||||
result
|
||||
|
||||
|
||||
# Determine if at least one element in the object matches a truth test. Use
|
||||
# JavaScript 1.6's **some**, if it exists.
|
||||
_.some = (obj, iterator, context) ->
|
||||
iterator ||= _.identity
|
||||
return obj.some iterator, context if nativeSome and obj.some is nativeSome
|
||||
result = false
|
||||
_.each obj, (value, index, list) ->
|
||||
_.breakLoop() if (result = iterator.call(context, value, index, list))
|
||||
result
|
||||
|
||||
|
||||
# Determine if a given value is included in the array or object,
|
||||
# based on `===`.
|
||||
_.include = (obj, target) ->
|
||||
return _.indexOf(obj, target) isnt -1 if nativeIndexOf and obj.indexOf is nativeIndexOf
|
||||
return true for own key, val of obj when val is target
|
||||
false
|
||||
|
||||
|
||||
# Invoke a method with arguments on every item in a collection.
|
||||
_.invoke = (obj, method) ->
|
||||
args = _.rest arguments, 2
|
||||
(if method then val[method] else val).apply(val, args) for val in obj
|
||||
|
||||
|
||||
# Convenience version of a common use case of **map**: fetching a property.
|
||||
_.pluck = (obj, key) ->
|
||||
_.map(obj, (val) -> val[key])
|
||||
|
||||
|
||||
# Return the maximum item or (item-based computation).
|
||||
_.max = (obj, iterator, context) ->
|
||||
return Math.max.apply(Math, obj) if not iterator and _.isArray(obj)
|
||||
result = computed: -Infinity
|
||||
_.each obj, (value, index, list) ->
|
||||
computed = if iterator then iterator.call(context, value, index, list) else value
|
||||
computed >= result.computed and (result = {value: value, computed: computed})
|
||||
result.value
|
||||
|
||||
|
||||
# Return the minimum element (or element-based computation).
|
||||
_.min = (obj, iterator, context) ->
|
||||
return Math.min.apply(Math, obj) if not iterator and _.isArray(obj)
|
||||
result = computed: Infinity
|
||||
_.each obj, (value, index, list) ->
|
||||
computed = if iterator then iterator.call(context, value, index, list) else value
|
||||
computed < result.computed and (result = {value: value, computed: computed})
|
||||
result.value
|
||||
|
||||
|
||||
# Sort the object's values by a criterion produced by an iterator.
|
||||
_.sortBy = (obj, iterator, context) ->
|
||||
_.pluck(((_.map obj, (value, index, list) ->
|
||||
{value: value, criteria: iterator.call(context, value, index, list)}
|
||||
).sort((left, right) ->
|
||||
a = left.criteria; b = right.criteria
|
||||
if a < b then -1 else if a > b then 1 else 0
|
||||
)), 'value')
|
||||
|
||||
|
||||
# Use a comparator function to figure out at what index an object should
|
||||
# be inserted so as to maintain order. Uses binary search.
|
||||
_.sortedIndex = (array, obj, iterator) ->
|
||||
iterator ||= _.identity
|
||||
low = 0
|
||||
high = array.length
|
||||
while low < high
|
||||
mid = (low + high) >> 1
|
||||
if iterator(array[mid]) < iterator(obj) then low = mid + 1 else high = mid
|
||||
low
|
||||
|
||||
|
||||
# Convert anything iterable into a real, live array.
|
||||
_.toArray = (iterable) ->
|
||||
return [] if (!iterable)
|
||||
return iterable.toArray() if (iterable.toArray)
|
||||
return iterable if (_.isArray(iterable))
|
||||
return slice.call(iterable) if (_.isArguments(iterable))
|
||||
_.values(iterable)
|
||||
|
||||
|
||||
# Return the number of elements in an object.
|
||||
_.size = (obj) -> _.toArray(obj).length
|
||||
|
||||
|
||||
# Array Functions
|
||||
# ---------------
|
||||
|
||||
# Get the first element of an array. Passing `n` will return the first N
|
||||
# values in the array. Aliased as **head**. The `guard` check allows it to work
|
||||
# with **map**.
|
||||
_.first = (array, n, guard) ->
|
||||
if n and not guard then slice.call(array, 0, n) else array[0]
|
||||
|
||||
|
||||
# Returns everything but the first entry of the array. Aliased as **tail**.
|
||||
# Especially useful on the arguments object. Passing an `index` will return
|
||||
# the rest of the values in the array from that index onward. The `guard`
|
||||
# check allows it to work with **map**.
|
||||
_.rest = (array, index, guard) ->
|
||||
slice.call(array, if _.isUndefined(index) or guard then 1 else index)
|
||||
|
||||
|
||||
# Get the last element of an array.
|
||||
_.last = (array) -> array[array.length - 1]
|
||||
|
||||
|
||||
# Trim out all falsy values from an array.
|
||||
_.compact = (array) -> item for item in array when item
|
||||
|
||||
|
||||
# Return a completely flattened version of an array.
|
||||
_.flatten = (array) ->
|
||||
_.reduce array, (memo, value) ->
|
||||
return memo.concat(_.flatten(value)) if _.isArray value
|
||||
memo.push value
|
||||
memo
|
||||
, []
|
||||
|
||||
|
||||
# Return a version of the array that does not contain the specified value(s).
|
||||
_.without = (array) ->
|
||||
values = _.rest arguments
|
||||
val for val in _.toArray(array) when not _.include values, val
|
||||
|
||||
|
||||
# Produce a duplicate-free version of the array. If the array has already
|
||||
# been sorted, you have the option of using a faster algorithm.
|
||||
_.uniq = (array, isSorted) ->
|
||||
memo = []
|
||||
for el, i in _.toArray array
|
||||
memo.push el if i is 0 || (if isSorted is true then _.last(memo) isnt el else not _.include(memo, el))
|
||||
memo
|
||||
|
||||
|
||||
# Produce an array that contains every item shared between all the
|
||||
# passed-in arrays.
|
||||
_.intersect = (array) ->
|
||||
rest = _.rest arguments
|
||||
_.select _.uniq(array), (item) ->
|
||||
_.all rest, (other) ->
|
||||
_.indexOf(other, item) >= 0
|
||||
|
||||
|
||||
# Zip together multiple lists into a single array -- elements that share
|
||||
# an index go together.
|
||||
_.zip = ->
|
||||
length = _.max _.pluck arguments, 'length'
|
||||
results = new Array length
|
||||
for i in [0...length]
|
||||
results[i] = _.pluck arguments, String i
|
||||
results
|
||||
|
||||
|
||||
# If the browser doesn't supply us with **indexOf** (I'm looking at you, MSIE),
|
||||
# we need this function. Return the position of the first occurrence of an
|
||||
# item in an array, or -1 if the item is not included in the array.
|
||||
_.indexOf = (array, item) ->
|
||||
return array.indexOf item if nativeIndexOf and array.indexOf is nativeIndexOf
|
||||
i = 0; l = array.length
|
||||
while l - i
|
||||
if array[i] is item then return i else i++
|
||||
-1
|
||||
|
||||
|
||||
# Provide JavaScript 1.6's **lastIndexOf**, delegating to the native function,
|
||||
# if possible.
|
||||
_.lastIndexOf = (array, item) ->
|
||||
return array.lastIndexOf(item) if nativeLastIndexOf and array.lastIndexOf is nativeLastIndexOf
|
||||
i = array.length
|
||||
while i
|
||||
if array[i] is item then return i else i--
|
||||
-1
|
||||
|
||||
|
||||
# Generate an integer Array containing an arithmetic progression. A port of
|
||||
# [the native Python **range** function](http://docs.python.org/library/functions.html#range).
|
||||
_.range = (start, stop, step) ->
|
||||
a = arguments
|
||||
solo = a.length <= 1
|
||||
i = start = if solo then 0 else a[0]
|
||||
stop = if solo then a[0] else a[1]
|
||||
step = a[2] or 1
|
||||
len = Math.ceil((stop - start) / step)
|
||||
return [] if len <= 0
|
||||
range = new Array len
|
||||
idx = 0
|
||||
loop
|
||||
return range if (if step > 0 then i - stop else stop - i) >= 0
|
||||
range[idx] = i
|
||||
idx++
|
||||
i+= step
|
||||
|
||||
|
||||
# Function Functions
|
||||
# ------------------
|
||||
|
||||
# Create a function bound to a given object (assigning `this`, and arguments,
|
||||
# optionally). Binding with arguments is also known as **curry**.
|
||||
_.bind = (func, obj) ->
|
||||
args = _.rest arguments, 2
|
||||
-> func.apply obj or root, args.concat arguments
|
||||
|
||||
|
||||
# Bind all of an object's methods to that object. Useful for ensuring that
|
||||
# all callbacks defined on an object belong to it.
|
||||
_.bindAll = (obj) ->
|
||||
funcs = if arguments.length > 1 then _.rest(arguments) else _.functions(obj)
|
||||
_.each funcs, (f) -> obj[f] = _.bind obj[f], obj
|
||||
obj
|
||||
|
||||
|
||||
# Delays a function for the given number of milliseconds, and then calls
|
||||
# it with the arguments supplied.
|
||||
_.delay = (func, wait) ->
|
||||
args = _.rest arguments, 2
|
||||
setTimeout((-> func.apply(func, args)), wait)
|
||||
|
||||
|
||||
# Memoize an expensive function by storing its results.
|
||||
_.memoize = (func, hasher) ->
|
||||
memo = {}
|
||||
hasher or= _.identity
|
||||
->
|
||||
key = hasher.apply this, arguments
|
||||
return memo[key] if key of memo
|
||||
memo[key] = func.apply this, arguments
|
||||
|
||||
|
||||
# Defers a function, scheduling it to run after the current call stack has
|
||||
# cleared.
|
||||
_.defer = (func) ->
|
||||
_.delay.apply _, [func, 1].concat _.rest arguments
|
||||
|
||||
|
||||
# Returns the first function passed as an argument to the second,
|
||||
# allowing you to adjust arguments, run code before and after, and
|
||||
# conditionally execute the original function.
|
||||
_.wrap = (func, wrapper) ->
|
||||
-> wrapper.apply wrapper, [func].concat arguments
|
||||
|
||||
|
||||
# Returns a function that is the composition of a list of functions, each
|
||||
# consuming the return value of the function that follows.
|
||||
_.compose = ->
|
||||
funcs = arguments
|
||||
->
|
||||
args = arguments
|
||||
for i in [funcs.length - 1..0] by -1
|
||||
args = [funcs[i].apply(this, args)]
|
||||
args[0]
|
||||
|
||||
|
||||
# Object Functions
|
||||
# ----------------
|
||||
|
||||
# Retrieve the names of an object's properties.
|
||||
_.keys = nativeKeys or (obj) ->
|
||||
return _.range 0, obj.length if _.isArray(obj)
|
||||
key for key, val of obj
|
||||
|
||||
|
||||
# Retrieve the values of an object's properties.
|
||||
_.values = (obj) ->
|
||||
_.map obj, _.identity
|
||||
|
||||
|
||||
# Return a sorted list of the function names available in Underscore.
|
||||
_.functions = (obj) ->
|
||||
_.filter(_.keys(obj), (key) -> _.isFunction(obj[key])).sort()
|
||||
|
||||
|
||||
# Extend a given object with all of the properties in a source object.
|
||||
_.extend = (obj) ->
|
||||
for source in _.rest(arguments)
|
||||
obj[key] = val for key, val of source
|
||||
obj
|
||||
|
||||
|
||||
# Create a (shallow-cloned) duplicate of an object.
|
||||
_.clone = (obj) ->
|
||||
return obj.slice 0 if _.isArray obj
|
||||
_.extend {}, obj
|
||||
|
||||
|
||||
# Invokes interceptor with the obj, and then returns obj.
|
||||
# The primary purpose of this method is to "tap into" a method chain,
|
||||
# in order to perform operations on intermediate results within
|
||||
the chain.
|
||||
_.tap = (obj, interceptor) ->
|
||||
interceptor obj
|
||||
obj
|
||||
|
||||
|
||||
# Perform a deep comparison to check if two objects are equal.
|
||||
_.isEqual = (a, b) ->
|
||||
# Check object identity.
|
||||
return true if a is b
|
||||
# Different types?
|
||||
atype = typeof(a); btype = typeof(b)
|
||||
return false if atype isnt btype
|
||||
# Basic equality test (watch out for coercions).
|
||||
return true if `a == b`
|
||||
# One is falsy and the other truthy.
|
||||
return false if (!a and b) or (a and !b)
|
||||
# One of them implements an `isEqual()`?
|
||||
return a.isEqual(b) if a.isEqual
|
||||
# Check dates' integer values.
|
||||
return a.getTime() is b.getTime() if _.isDate(a) and _.isDate(b)
|
||||
# Both are NaN?
|
||||
return false if _.isNaN(a) and _.isNaN(b)
|
||||
# Compare regular expressions.
|
||||
if _.isRegExp(a) and _.isRegExp(b)
|
||||
return a.source is b.source and
|
||||
a.global is b.global and
|
||||
a.ignoreCase is b.ignoreCase and
|
||||
a.multiline is b.multiline
|
||||
# If a is not an object by this point, we can't handle it.
|
||||
return false if atype isnt 'object'
|
||||
# Check for different array lengths before comparing contents.
|
||||
return false if a.length and (a.length isnt b.length)
|
||||
# Nothing else worked, deep compare the contents.
|
||||
aKeys = _.keys(a); bKeys = _.keys(b)
|
||||
# Different object sizes?
|
||||
return false if aKeys.length isnt bKeys.length
|
||||
# Recursive comparison of contents.
|
||||
return false for key, val of a when !(key of b) or !_.isEqual(val, b[key])
|
||||
true
|
||||
|
||||
|
||||
# Is a given array or object empty?
|
||||
_.isEmpty = (obj) ->
|
||||
return obj.length is 0 if _.isArray(obj) or _.isString(obj)
|
||||
return false for own key of obj
|
||||
true
|
||||
|
||||
|
||||
# Is a given value a DOM element?
|
||||
_.isElement = (obj) -> obj and obj.nodeType is 1
|
||||
|
||||
|
||||
# Is a given value an array?
|
||||
_.isArray = nativeIsArray or (obj) -> !!(obj and obj.concat and obj.unshift and not obj.callee)
|
||||
|
||||
|
||||
# Is a given variable an arguments object?
|
||||
_.isArguments = (obj) -> obj and obj.callee
|
||||
|
||||
|
||||
# Is the given value a function?
|
||||
_.isFunction = (obj) -> !!(obj and obj.constructor and obj.call and obj.apply)
|
||||
|
||||
|
||||
# Is the given value a string?
|
||||
_.isString = (obj) -> !!(obj is '' or (obj and obj.charCodeAt and obj.substr))
|
||||
|
||||
|
||||
# Is a given value a number?
|
||||
_.isNumber = (obj) -> (obj is +obj) or toString.call(obj) is '[object Number]'
|
||||
|
||||
|
||||
# Is a given value a boolean?
|
||||
_.isBoolean = (obj) -> obj is true or obj is false
|
||||
|
||||
|
||||
# Is a given value a Date?
|
||||
_.isDate = (obj) -> !!(obj and obj.getTimezoneOffset and obj.setUTCFullYear)
|
||||
|
||||
|
||||
# Is the given value a regular expression?
|
||||
_.isRegExp = (obj) -> !!(obj and obj.exec and (obj.ignoreCase or obj.ignoreCase is false))
|
||||
|
||||
|
||||
# Is the given value NaN -- this one is interesting. `NaN != NaN`, and
|
||||
# `isNaN(undefined) == true`, so we make sure it's a number first.
|
||||
_.isNaN = (obj) -> _.isNumber(obj) and window.isNaN(obj)
|
||||
|
||||
|
||||
# Is a given value equal to null?
|
||||
_.isNull = (obj) -> obj is null
|
||||
|
||||
|
||||
# Is a given variable undefined?
|
||||
_.isUndefined = (obj) -> typeof obj is 'undefined'
|
||||
|
||||
|
||||
# Utility Functions
|
||||
# -----------------
|
||||
|
||||
# Run Underscore.js in noConflict mode, returning the `_` variable to its
|
||||
# previous owner. Returns a reference to the Underscore object.
|
||||
_.noConflict = ->
|
||||
root._ = previousUnderscore
|
||||
this
|
||||
|
||||
|
||||
# Keep the identity function around for default iterators.
|
||||
_.identity = (value) -> value
|
||||
|
||||
|
||||
# Run a function `n` times.
|
||||
_.times = (n, iterator, context) ->
|
||||
iterator.call context, i for i in [0...n]
|
||||
|
||||
|
||||
# Break out of the middle of an iteration.
|
||||
_.breakLoop = -> throw breaker
|
||||
|
||||
|
||||
# Add your own custom functions to the Underscore object, ensuring that
|
||||
# they're correctly added to the OOP wrapper as well.
|
||||
_.mixin = (obj) ->
|
||||
for name in _.functions(obj)
|
||||
addToWrapper name, _[name] = obj[name]
|
||||
|
||||
|
||||
# Generate a unique integer id (unique within the entire client session).
|
||||
# Useful for temporary DOM ids.
|
||||
idCounter = 0
|
||||
_.uniqueId = (prefix) ->
|
||||
(prefix or '') + idCounter++
|
||||
|
||||
|
||||
# By default, Underscore uses **ERB**-style template delimiters, change the
|
||||
# following template settings to use alternative delimiters.
|
||||
_.templateSettings = {
|
||||
start: '<%'
|
||||
end: '%>'
|
||||
interpolate: /<%=(.+?)%>/g
|
||||
}
|
||||
|
||||
|
||||
# JavaScript templating a-la **ERB**, pilfered from John Resig's
|
||||
# *Secrets of the JavaScript Ninja*, page 83.
|
||||
# Single-quote fix from Rick Strahl.
|
||||
# With alterations for arbitrary delimiters, and to preserve whitespace.
|
||||
_.template = (str, data) ->
|
||||
c = _.templateSettings
|
||||
endMatch = new RegExp("'(?=[^"+c.end.substr(0, 1)+"]*"+escapeRegExp(c.end)+")","g")
|
||||
fn = new Function 'obj',
|
||||
'var p=[],print=function(){p.push.apply(p,arguments);};' +
|
||||
'with(obj||{}){p.push(\'' +
|
||||
str.replace(/\r/g, '\\r')
|
||||
.replace(/\n/g, '\\n')
|
||||
.replace(/\t/g, '\\t')
|
||||
.replace(endMatch,"<22><><EFBFBD>")
|
||||
.split("'").join("\\'")
|
||||
.split("<22><><EFBFBD>").join("'")
|
||||
.replace(c.interpolate, "',$1,'")
|
||||
.split(c.start).join("');")
|
||||
.split(c.end).join("p.push('") +
|
||||
"');}return p.join('');"
|
||||
if data then fn(data) else fn
|
||||
|
||||
|
||||
# Aliases
|
||||
# -------
|
||||
|
||||
_.forEach = _.each
|
||||
_.foldl = _.inject = _.reduce
|
||||
_.foldr = _.reduceRight
|
||||
_.select = _.filter
|
||||
_.all = _.every
|
||||
_.any = _.some
|
||||
_.contains = _.include
|
||||
_.head = _.first
|
||||
_.tail = _.rest
|
||||
_.methods = _.functions
|
||||
|
||||
|
||||
# Setup the OOP Wrapper
|
||||
# ---------------------
|
||||
|
||||
# If Underscore is called as a function, it returns a wrapped object that
|
||||
# can be used OO-style. This wrapper holds altered versions of all the
|
||||
# underscore functions. Wrapped objects may be chained.
|
||||
wrapper = (obj) ->
|
||||
this._wrapped = obj
|
||||
this
|
||||
|
||||
|
||||
# Helper function to continue chaining intermediate results.
|
||||
result = (obj, chain) ->
|
||||
if chain then _(obj).chain() else obj
|
||||
|
||||
|
||||
# A method to easily add functions to the OOP wrapper.
|
||||
addToWrapper = (name, func) ->
|
||||
wrapper.prototype[name] = ->
|
||||
args = _.toArray arguments
|
||||
unshift.call args, this._wrapped
|
||||
result func.apply(_, args), this._chain
|
||||
|
||||
|
||||
# Add all ofthe Underscore functions to the wrapper object.
|
||||
_.mixin _
|
||||
|
||||
|
||||
# Add all mutator Array functions to the wrapper.
|
||||
_.each ['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], (name) ->
|
||||
method = Array.prototype[name]
|
||||
wrapper.prototype[name] = ->
|
||||
method.apply(this._wrapped, arguments)
|
||||
result(this._wrapped, this._chain)
|
||||
|
||||
|
||||
# Add all accessor Array functions to the wrapper.
|
||||
_.each ['concat', 'join', 'slice'], (name) ->
|
||||
method = Array.prototype[name]
|
||||
wrapper.prototype[name] = ->
|
||||
result(method.apply(this._wrapped, arguments), this._chain)
|
||||
|
||||
|
||||
# Start chaining a wrapped Underscore object.
|
||||
wrapper::chain = ->
|
||||
this._chain = true
|
||||
this
|
||||
|
||||
|
||||
# Extracts the result from a wrapped and chained object.
|
||||
wrapper::value = -> this._wrapped
|
||||
</textarea></form>
|
||||
<script>
|
||||
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {});
|
||||
</script>
|
||||
|
||||
<p><strong>MIME types defined:</strong> <code>text/x-coffeescript</code>.</p>
|
||||
|
||||
<p>The CoffeeScript mode was written by Jeff Pickhardt (<a href="LICENSE">license</a>).</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,55 +0,0 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>CodeMirror: CSS mode</title>
|
||||
<link rel="stylesheet" href="../../lib/codemirror.css">
|
||||
<script src="../../lib/codemirror.js"></script>
|
||||
<script src="css.js"></script>
|
||||
<style>.CodeMirror {background: #f8f8f8;}</style>
|
||||
<link rel="stylesheet" href="../../doc/docs.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>CodeMirror: CSS mode</h1>
|
||||
<form><textarea id="code" name="code">
|
||||
/* Some example CSS */
|
||||
|
||||
@import url("something.css");
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 3em 6em;
|
||||
font-family: tahoma, arial, sans-serif;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
#navigation a {
|
||||
font-weight: bold;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2.5em;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.7em;
|
||||
}
|
||||
|
||||
h1:before, h2:before {
|
||||
content: "::";
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: courier, monospace;
|
||||
font-size: 80%;
|
||||
color: #418A8A;
|
||||
}
|
||||
</textarea></form>
|
||||
<script>
|
||||
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {});
|
||||
</script>
|
||||
|
||||
<p><strong>MIME types defined:</strong> <code>text/css</code>.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,77 +0,0 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>CodeMirror: JavaScript mode</title>
|
||||
<link rel="stylesheet" href="../../lib/codemirror.css">
|
||||
<script src="../../lib/codemirror.js"></script>
|
||||
<script src="javascript.js"></script>
|
||||
<link rel="stylesheet" href="../../doc/docs.css">
|
||||
<style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>CodeMirror: JavaScript mode</h1>
|
||||
|
||||
<div><textarea id="code" name="code">
|
||||
// Demo code (the actual new parser character stream implementation)
|
||||
|
||||
function StringStream(string) {
|
||||
this.pos = 0;
|
||||
this.string = string;
|
||||
}
|
||||
|
||||
StringStream.prototype = {
|
||||
done: function() {return this.pos >= this.string.length;},
|
||||
peek: function() {return this.string.charAt(this.pos);},
|
||||
next: function() {
|
||||
if (this.pos < this.string.length)
|
||||
return this.string.charAt(this.pos++);
|
||||
},
|
||||
eat: function(match) {
|
||||
var ch = this.string.charAt(this.pos);
|
||||
if (typeof match == "string") var ok = ch == match;
|
||||
else var ok = ch && match.test ? match.test(ch) : match(ch);
|
||||
if (ok) {this.pos++; return ch;}
|
||||
},
|
||||
eatWhile: function(match) {
|
||||
var start = this.pos;
|
||||
while (this.eat(match));
|
||||
if (this.pos > start) return this.string.slice(start, this.pos);
|
||||
},
|
||||
backUp: function(n) {this.pos -= n;},
|
||||
column: function() {return this.pos;},
|
||||
eatSpace: function() {
|
||||
var start = this.pos;
|
||||
while (/\s/.test(this.string.charAt(this.pos))) this.pos++;
|
||||
return this.pos - start;
|
||||
},
|
||||
match: function(pattern, consume, caseInsensitive) {
|
||||
if (typeof pattern == "string") {
|
||||
function cased(str) {return caseInsensitive ? str.toLowerCase() : str;}
|
||||
if (cased(this.string).indexOf(cased(pattern), this.pos) == this.pos) {
|
||||
if (consume !== false) this.pos += str.length;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
var match = this.string.slice(this.pos).match(pattern);
|
||||
if (match && consume !== false) this.pos += match[0].length;
|
||||
return match;
|
||||
}
|
||||
}
|
||||
};
|
||||
</textarea></div>
|
||||
|
||||
<script>
|
||||
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
|
||||
lineNumbers: true,
|
||||
matchBrackets: true
|
||||
});
|
||||
</script>
|
||||
|
||||
<p>JavaScript mode supports a single configuration
|
||||
option, <code>json</code>, which will set the mode to expect JSON
|
||||
data rather than a JavaScript program.</p>
|
||||
|
||||
<p><strong>MIME types defined:</strong> <code>text/javascript</code>, <code>application/json</code>.</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,48 +0,0 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>CodeMirror: PHP mode</title>
|
||||
<link rel="stylesheet" href="../../lib/codemirror.css">
|
||||
<script src="../../lib/codemirror.js"></script>
|
||||
<script src="../xml/xml.js"></script>
|
||||
<script src="../javascript/javascript.js"></script>
|
||||
<script src="../css/css.js"></script>
|
||||
<script src="../clike/clike.js"></script>
|
||||
<script src="php.js"></script>
|
||||
<style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
|
||||
<link rel="stylesheet" href="../../doc/docs.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>CodeMirror: PHP mode</h1>
|
||||
|
||||
<form><textarea id="code" name="code">
|
||||
<?php
|
||||
function hello($who) {
|
||||
return "Hello " . $who;
|
||||
}
|
||||
?>
|
||||
<p>The program says <?= hello("World") ?>.</p>
|
||||
<script>
|
||||
alert("And here is some JS code"); // also colored
|
||||
</script>
|
||||
</textarea></form>
|
||||
|
||||
<script>
|
||||
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
|
||||
lineNumbers: true,
|
||||
matchBrackets: true,
|
||||
mode: "application/x-httpd-php",
|
||||
indentUnit: 4,
|
||||
indentWithTabs: true,
|
||||
enterMode: "keep",
|
||||
tabMode: "shift"
|
||||
});
|
||||
</script>
|
||||
|
||||
<p>Simple HTML/PHP mode based on
|
||||
the <a href="../clike/">C-like</a> mode. Depends on XML,
|
||||
JavaScript, CSS, and C-like modes.</p>
|
||||
|
||||
<p><strong>MIME types defined:</strong> <code>application/x-httpd-php</code> (HTML with PHP code), <code>text/x-php</code> (plain, non-wrapped PHP code).</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,171 +0,0 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>CodeMirror: Ruby mode</title>
|
||||
<link rel="stylesheet" href="../../lib/codemirror.css">
|
||||
<script src="../../lib/codemirror.js"></script>
|
||||
<script src="ruby.js"></script>
|
||||
<style>
|
||||
.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}
|
||||
.cm-s-default span.cm-arrow { color: red; }
|
||||
</style>
|
||||
<link rel="stylesheet" href="../../doc/docs.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>CodeMirror: Ruby mode</h1>
|
||||
<form><textarea id="code" name="code">
|
||||
# Code from http://sandbox.mc.edu/~bennet/ruby/code/poly_rb.html
|
||||
#
|
||||
# This program evaluates polynomials. It first asks for the coefficients
|
||||
# of a polynomial, which must be entered on one line, highest-order first.
|
||||
# It then requests values of x and will compute the value of the poly for
|
||||
# each x. It will repeatly ask for x values, unless you the user enters
|
||||
# a blank line. It that case, it will ask for another polynomial. If the
|
||||
# user types quit for either input, the program immediately exits.
|
||||
#
|
||||
|
||||
#
|
||||
# Function to evaluate a polynomial at x. The polynomial is given
|
||||
# as a list of coefficients, from the greatest to the least.
|
||||
def polyval(x, coef)
|
||||
sum = 0
|
||||
coef = coef.clone # Don't want to destroy the original
|
||||
while true
|
||||
sum += coef.shift # Add and remove the next coef
|
||||
break if coef.empty? # If no more, done entirely.
|
||||
sum *= x # This happens the right number of times.
|
||||
end
|
||||
return sum
|
||||
end
|
||||
|
||||
#
|
||||
# Function to read a line containing a list of integers and return
|
||||
# them as an array of integers. If the string conversion fails, it
|
||||
# throws TypeError. If the input line is the word 'quit', then it
|
||||
# converts it to an end-of-file exception
|
||||
def readints(prompt)
|
||||
# Read a line
|
||||
print prompt
|
||||
line = readline.chomp
|
||||
raise EOFError.new if line == 'quit' # You can also use a real EOF.
|
||||
|
||||
# Go through each item on the line, converting each one and adding it
|
||||
# to retval.
|
||||
retval = [ ]
|
||||
for str in line.split(/\s+/)
|
||||
if str =~ /^\-?\d+$/
|
||||
retval.push(str.to_i)
|
||||
else
|
||||
raise TypeError.new
|
||||
end
|
||||
end
|
||||
|
||||
return retval
|
||||
end
|
||||
|
||||
#
|
||||
# Take a coeff and an exponent and return the string representation, ignoring
|
||||
# the sign of the coefficient.
|
||||
def term_to_str(coef, exp)
|
||||
ret = ""
|
||||
|
||||
# Show coeff, unless it's 1 or at the right
|
||||
coef = coef.abs
|
||||
ret = coef.to_s unless coef == 1 && exp > 0
|
||||
ret += "x" if exp > 0 # x if exponent not 0
|
||||
ret += "^" + exp.to_s if exp > 1 # ^exponent, if > 1.
|
||||
|
||||
return ret
|
||||
end
|
||||
|
||||
#
|
||||
# Create a string of the polynomial in sort-of-readable form.
|
||||
def polystr(p)
|
||||
# Get the exponent of first coefficient, plus 1.
|
||||
exp = p.length
|
||||
|
||||
# Assign exponents to each term, making pairs of coeff and exponent,
|
||||
# Then get rid of the zero terms.
|
||||
p = (p.map { |c| exp -= 1; [ c, exp ] }).select { |p| p[0] != 0 }
|
||||
|
||||
# If there's nothing left, it's a zero
|
||||
return "0" if p.empty?
|
||||
|
||||
# *** Now p is a non-empty list of [ coef, exponent ] pairs. ***
|
||||
|
||||
# Convert the first term, preceded by a "-" if it's negative.
|
||||
result = (if p[0][0] < 0 then "-" else "" end) + term_to_str(*p[0])
|
||||
|
||||
# Convert the rest of the terms, in each case adding the appropriate
|
||||
# + or - separating them.
|
||||
for term in p[1...p.length]
|
||||
# Add the separator then the rep. of the term.
|
||||
result += (if term[0] < 0 then " - " else " + " end) +
|
||||
term_to_str(*term)
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
#
|
||||
# Run until some kind of endfile.
|
||||
begin
|
||||
# Repeat until an exception or quit gets us out.
|
||||
while true
|
||||
# Read a poly until it works. An EOF will except out of the
|
||||
# program.
|
||||
print "\n"
|
||||
begin
|
||||
poly = readints("Enter a polynomial coefficients: ")
|
||||
rescue TypeError
|
||||
print "Try again.\n"
|
||||
retry
|
||||
end
|
||||
break if poly.empty?
|
||||
|
||||
# Read and evaluate x values until the user types a blank line.
|
||||
# Again, an EOF will except out of the pgm.
|
||||
while true
|
||||
# Request an integer.
|
||||
print "Enter x value or blank line: "
|
||||
x = readline.chomp
|
||||
break if x == ''
|
||||
raise EOFError.new if x == 'quit'
|
||||
|
||||
# If it looks bad, let's try again.
|
||||
if x !~ /^\-?\d+$/
|
||||
print "That doesn't look like an integer. Please try again.\n"
|
||||
next
|
||||
end
|
||||
|
||||
# Convert to an integer and print the result.
|
||||
x = x.to_i
|
||||
print "p(x) = ", polystr(poly), "\n"
|
||||
print "p(", x, ") = ", polyval(x, poly), "\n"
|
||||
end
|
||||
end
|
||||
rescue EOFError
|
||||
print "\n=== EOF ===\n"
|
||||
rescue Interrupt, SignalException
|
||||
print "\n=== Interrupted ===\n"
|
||||
else
|
||||
print "--- Bye ---\n"
|
||||
end
|
||||
</textarea></form>
|
||||
<script>
|
||||
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
|
||||
mode: "text/x-ruby",
|
||||
tabMode: "indent",
|
||||
matchBrackets: true,
|
||||
indentUnit: 4
|
||||
});
|
||||
</script>
|
||||
|
||||
<p><strong>MIME types defined:</strong> <code>text/x-ruby</code>.</p>
|
||||
|
||||
<p>Development of the CodeMirror Ruby mode was kindly sponsored
|
||||
by <a href="http://ubalo.com/">Ubalo</a>, who hold
|
||||
the <a href="LICENSE">license</a>.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,44 +0,0 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>CodeMirror: XML mode</title>
|
||||
<link rel="stylesheet" href="../../lib/codemirror.css">
|
||||
<script src="../../lib/codemirror.js"></script>
|
||||
<script src="xml.js"></script>
|
||||
<style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
|
||||
<link rel="stylesheet" href="../../doc/docs.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>CodeMirror: XML mode</h1>
|
||||
<form><textarea id="code" name="code">
|
||||
<html style="color: green">
|
||||
<!-- this is a comment -->
|
||||
<head>
|
||||
<title>HTML Example</title>
|
||||
</head>
|
||||
<body>
|
||||
The indentation tries to be <em>somewhat &quot;do what
|
||||
I mean&quot;</em>... but might not match your style.
|
||||
</body>
|
||||
</html>
|
||||
</textarea></form>
|
||||
<script>
|
||||
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
|
||||
mode: {name: "xml", alignCDATA: true},
|
||||
lineNumbers: true
|
||||
});
|
||||
</script>
|
||||
<p>The XML mode supports two configuration parameters:</p>
|
||||
<dl>
|
||||
<dt><code>htmlMode (boolean)</code></dt>
|
||||
<dd>This switches the mode to parse HTML instead of XML. This
|
||||
means attributes do not have to be quoted, and some elements
|
||||
(such as <code>br</code>) do not require a closing tag.</dd>
|
||||
<dt><code>alignCDATA (boolean)</code></dt>
|
||||
<dd>Setting this to true will force the opening tag of CDATA
|
||||
blocks to not be indented.</dd>
|
||||
</dl>
|
||||
|
||||
<p><strong>MIME types defined:</strong> <code>application/xml</code>, <code>text/html</code>.</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -44,17 +44,16 @@ Early version of the web based IDE which allows for creation of websites in the
|
||||
$ git clone git@github:mattpass/ICEcoder
|
||||
```
|
||||
|
||||
####Step 2: Upload all the files
|
||||
####Step 2: Upload the files (Linux or Windows hosting OK)
|
||||
```
|
||||
Linux or Windows hosting OK
|
||||
Upload to a new sub-dir URL such as yourdomain.com/_coder
|
||||
Set public write permissions on the lib/settings.php file
|
||||
Set public write permissions on the lib/config.php file
|
||||
```
|
||||
|
||||
####Step 3: Start coding
|
||||
```
|
||||
Visit the sub-dir URL in your browser and enter a password
|
||||
Now you're setup, auto-logged in too and ready to code
|
||||
Now you're setup, auto-logged in and ready to code!
|
||||
```
|
||||
|
||||
Suitable for commercial & non-commercial projects, just let me know if it's useful to you and any cool customisations you make to it. I take no responsibility for anything, your usage is all down to you.
|
||||
|
||||
83
editor.php
@@ -1,16 +1,17 @@
|
||||
<?php include("lib/config.php");?>
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html style="margin: 0px">
|
||||
<html style="margin: 0">
|
||||
<head>
|
||||
<title>CodeMirror 2: ICE Coders Editor of Choice</title>
|
||||
<?php include("lib/settings.php");?>
|
||||
<link rel="stylesheet" href="<?php echo $codeMirrorDir; ?>/lib/codemirror.css">
|
||||
<script src="<?php echo $codeMirrorDir; ?>/lib/codemirror.js"></script>
|
||||
<script src="<?php echo $codeMirrorDir; ?>/mode/xml/xml.js"></script>
|
||||
<script src="<?php echo $codeMirrorDir; ?>/mode/javascript/javascript.js"></script>
|
||||
<script src="<?php echo $codeMirrorDir; ?>/mode/coffeescript/coffeescript.js"></script>
|
||||
<script src="<?php echo $codeMirrorDir; ?>/mode/css/css.js"></script>
|
||||
<script src="<?php echo $codeMirrorDir; ?>/mode/clike/clike.js"></script>
|
||||
<script src="<?php echo $codeMirrorDir; ?>/mode/css/css.js"></script>
|
||||
<script src="<?php echo $codeMirrorDir; ?>/mode/javascript/javascript.js"></script>
|
||||
<script src="<?php echo $codeMirrorDir; ?>/mode/xml/xml.js"></script>
|
||||
<script src="<?php echo $codeMirrorDir; ?>/mode/coffeescript/coffeescript.js"></script>
|
||||
<script src="<?php echo $codeMirrorDir; ?>/mode/php/php.js"></script>
|
||||
<script src="<?php echo $codeMirrorDir; ?>/mode/ruby/ruby.js"></script>
|
||||
<script src="<?php echo $codeMirrorDir; ?>/lib/util/searchcursor.js"></script>
|
||||
@@ -24,19 +25,75 @@ if ($theme=="default") {
|
||||
}
|
||||
?>
|
||||
<style type="text/css">
|
||||
.CodeMirror {position: absolute; width: 0px; background-color: #fff}
|
||||
.CodeMirror {position: absolute; width: 0; background-color: #fff; top: 0px; z-index: 1}
|
||||
.CodeMirror-scroll {width: 100px; height: 100px;}
|
||||
.cm-s-visible {display: block; top: 0px}
|
||||
.cm-s-visible {display: block; top: 0}
|
||||
.cm-s-hidden {display: none; top: 4000px}
|
||||
.cm-s-activeLine {background: #002 !important;}
|
||||
.cm-s-activeLine {background: #000 !important;}
|
||||
// Make sure this next one remains the 5th item, updated with JS
|
||||
.cm-tab:after {position: relative; display: inline-block; width: 0px; left: -1.4em; overflow: visible; color: #aaa; content: "<?php if ($visibleTabs) {?>\21e5<?;};?>";}
|
||||
.cm-tab:after {position: relative; display: inline-block; width: 0; left: -1.4em; overflow: visible; color: #aaa; content: "<?php if ($visibleTabs) {?>\21e5<?;};?>";}
|
||||
span.CodeMirror-matchhighlight {background: #555}
|
||||
.CodeMirror-focused span.CodeMirror-matchhighlight {color: #000; background: #555; !important}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body style="margin: 0px" onKeyDown="return top.ICEcoder.interceptKeys('content', event);" onKeyUp="top.ICEcoder.resetKeys(event);">
|
||||
<body onLoad="top.ICEcoder.updateFileFolderCount()" style="color: #fff; margin: 0" onKeyDown="return top.ICEcoder.interceptKeys('content', event);" onKeyUp="top.ICEcoder.resetKeys(event);">
|
||||
|
||||
<div style="margin: 32px 43px; font-family: arial; font-size: 10px; color: #dddddd">
|
||||
<?php if($_SESSION['userLevel'] == 10) {
|
||||
echo '<div style="float: left; margin-right: 50px">'.PHP_EOL;
|
||||
echo '<h2 style="color: rgba(0,198,255,0.7)">server</h2>'.PHP_EOL;
|
||||
echo '<span style="color:#888">Server name, OS & IP:</span><br>'.PHP_EOL;
|
||||
echo $_SERVER['SERVER_NAME'].' '.$_SERVER['SERVER_SOFTWARE'].' '.$_SERVER['SERVER_ADDR'].'<br><br>'.PHP_EOL;
|
||||
echo '<span style="color:#888">Root:</span><br>'.PHP_EOL;
|
||||
echo $_SERVER['DOCUMENT_ROOT'].'<br><br>'.PHP_EOL;
|
||||
echo '<span style="color:#888">PHP version:</span><br>'.PHP_EOL;
|
||||
echo phpversion().'<br><br>'.PHP_EOL;
|
||||
echo '<span style="color:#888">Date & time:</span><br>'.PHP_EOL;
|
||||
echo '<span id="serverDT"></span><br><br><br>'.PHP_EOL;
|
||||
echo '</div>'.PHP_EOL;
|
||||
|
||||
echo '<div style="float: left">'.PHP_EOL;
|
||||
echo '<h2 style="color: rgba(0,198,255,0.7)">files</h2>'.PHP_EOL;
|
||||
echo '<span style="color:#888">Last 10 files opened:</span><br>'.PHP_EOL;
|
||||
$last10FilesArray = explode(",",$last10Files);
|
||||
for ($i=0;$i<count($last10FilesArray);$i++) {
|
||||
if ($last10Files=="") {
|
||||
echo '[none]<br><br>';
|
||||
} else {
|
||||
echo '<a style="cursor:pointer" onClick="top.ICEcoder.openFile(top.fullPath+\''.str_replace("|","/",$last10FilesArray[$i]).'\')">';
|
||||
echo str_replace("|","/",$last10FilesArray[$i]);
|
||||
echo '</a><br>'.PHP_EOL;
|
||||
if ($i==count($last10FilesArray)-1) {echo '<br>'.PHP_EOL;};
|
||||
}
|
||||
}
|
||||
echo '<span style="color:#888">File & folder count:</span><br>'.PHP_EOL;
|
||||
echo '<div id="fileFolderCounts"></div><br><br><br>'.PHP_EOL;
|
||||
echo '</div>'.PHP_EOL;
|
||||
|
||||
echo '<div style="clear: both">'.PHP_EOL;
|
||||
echo '<h2 style="color: rgba(0,198,255,0.7)">your device</h2>'.PHP_EOL;
|
||||
echo '<span style="color:#888">Browser:</span><br>'.PHP_EOL;
|
||||
echo $_SERVER['HTTP_USER_AGENT'].'<br><br>'.PHP_EOL;
|
||||
echo '<span style="color:#888">Your IP:</span><br>'.PHP_EOL;
|
||||
echo $_SERVER['REMOTE_ADDR'].PHP_EOL;
|
||||
echo '</div>'.PHP_EOL;
|
||||
}; ?>
|
||||
<script>
|
||||
var nDT=<?php echo time()*1000;?>;
|
||||
setInterval(function(){
|
||||
var s=(new Date(nDT+=1e3)+'').split(' '),
|
||||
d=s[2]*1,
|
||||
t=s[4].split(':'),
|
||||
p=t[0]>11?'pm':'am',
|
||||
e=d%20==1|d>30?'st':d%20==2?'nd':d%20==3?'rd':'th';
|
||||
t[0]=--t[0]%12+1;
|
||||
if (document.getElementById('serverDT')) {
|
||||
document.getElementById('serverDT').innerHTML=[s[0],d+e,s[1],s[3],t.join(':')+p].join(' ');
|
||||
}
|
||||
},1000);
|
||||
</script>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function createNewCMInstance(num) {
|
||||
@@ -48,8 +105,8 @@ function createNewCMInstance(num) {
|
||||
mode: "application/x-httpd-php",
|
||||
lineNumbers: true,
|
||||
lineWrapping: true,
|
||||
indentUnit: 4,
|
||||
tabSize: 4,
|
||||
indentUnit: top.tabWidth,
|
||||
tabSize: top.tabWidth,
|
||||
indentWithTabs: true,
|
||||
electricChars: false,
|
||||
onCursorActivity: function() {
|
||||
@@ -79,7 +136,7 @@ function createNewCMInstance(num) {
|
||||
}
|
||||
},
|
||||
onKeyEvent: function(instance, e) {
|
||||
top.ICEcoder.redoChangedContent(event);
|
||||
top.ICEcoder.redoChangedContent(e);
|
||||
top.ICEcoder.findReplace('find',true,false);
|
||||
top.ICEcoder.getCaretPosition();
|
||||
top.ICEcoder.updateCharDisplay();
|
||||
|
||||
21
files.php
@@ -74,6 +74,7 @@ function fileManager_dir($directory, $return_link, $first_call=true) {
|
||||
if( $this_file != "." && $this_file != ".." && $bannedFile == false) {
|
||||
if( is_dir("$directory/$this_file") ) {
|
||||
// Directory
|
||||
$dirCount++;
|
||||
$dirRep = str_replace("\\","/",$directory);
|
||||
$link = str_replace("[link]", "$dirRep/" . urlencode($this_file), $return_link);
|
||||
$link = str_replace("//","/",$link);
|
||||
@@ -99,6 +100,8 @@ function fileManager_dir($directory, $return_link, $first_call=true) {
|
||||
}
|
||||
} else {
|
||||
// File
|
||||
$fileCount++;
|
||||
$fileBytes+=filesize($link);
|
||||
// Get extension (prefix 'ext-' to prevent invalid classes from extensions that begin with numbers)
|
||||
$ext = "ext-" . substr($this_file, strrpos($this_file, ".") + 1);
|
||||
$dirRep = str_replace("\\","/",$directory);
|
||||
@@ -119,7 +122,7 @@ function fileManager_dir($directory, $return_link, $first_call=true) {
|
||||
}
|
||||
$fileManager .= "<li class=\"pft-file " . strtolower($ext) . "\"><a nohref onMouseOver=\"top.ICEcoder.overFileFolder('file','$link')\" onMouseOut=\"top.ICEcoder.overFileFolder('file','')\" style=\"position: relative; left:-22px; cursor: pointer\"> <span id=\"".str_replace("/","|",str_replace($docRoot,"",$link))."\">" . htmlspecialchars($this_file) . "</span> ".$fileAtts."</a></li>";
|
||||
} else {
|
||||
$fileAtts = "<img src=\"images/file-manager-icons/padlock.png\" style=\"cursor: pointer\" onClick=\"alert('Sorry, you need higher admin level rights to view.')\">";
|
||||
$fileAtts = "<img src=\"images/padlock.png\" style=\"cursor: pointer\" onClick=\"alert('Sorry, you need higher admin level rights to view.')\">";
|
||||
$fileManager .= "<li class=\"pft-file " . strtolower($ext) . "\" style=\"cursor: default\"><span style=\"position: relative; left:-22px; color: #888\"> [HIDDEN] ".$fileAtts."</span></li>";
|
||||
}
|
||||
}
|
||||
@@ -127,7 +130,12 @@ function fileManager_dir($directory, $return_link, $first_call=true) {
|
||||
}
|
||||
$fileManager .= "</ul>";
|
||||
}
|
||||
return $fileManager;
|
||||
$varOutput = "";
|
||||
if ($dirCount) {$varOutput .= "top.ICEcoder.dirCount+=".$dirCount.";".PHP_EOL;};
|
||||
if ($fileCount) {$varOutput .= "top.ICEcoder.fileCount+=".$fileCount.";".PHP_EOL;};
|
||||
if ($fileBytes) {$varOutput .= "top.ICEcoder.fileBytes+=".$fileBytes.";".PHP_EOL;};
|
||||
// After outputting the fileManager, output the JS vars, but only the first time
|
||||
return $fileManager."<script>if (top.ICEcoder.dirCount==0) {".PHP_EOL.$varOutput."}</script>";
|
||||
}
|
||||
|
||||
// For PHP4 compatibility
|
||||
@@ -146,12 +154,19 @@ function php4_scandir($dir) {
|
||||
<head>
|
||||
<title>ICE Coder File Manager</title>
|
||||
<link rel="stylesheet" type="text/css" href="lib/files.css">
|
||||
|
||||
<script src="lib/coder.js" type="text/javascript"></script>
|
||||
</head>
|
||||
|
||||
<body onLoad="top.ICEcoder.fileManager()" onDblClick="top.ICEcoder.openFile()" onKeyDown="return top.ICEcoder.interceptKeys('files', event);" onKeyUp="top.ICEcoder.resetKeys(event);">
|
||||
<div onClick="top.ICEcoder.refreshFileManager()" class="refresh"><img src="images/file-manager-icons/refresh.png"></div>
|
||||
<div onClick="top.ICEcoder.refreshFileManager()" class="refresh"><img src="images/refresh.png"></div>
|
||||
<script>
|
||||
top.ICEcoder.dirCount = 0;
|
||||
top.ICEcoder.fileCount = 0;
|
||||
top.ICEcoder.fileBytes = 0;
|
||||
</script>
|
||||
<?php
|
||||
|
||||
echo fileManager($_SERVER['DOCUMENT_ROOT'], "[link]");
|
||||
?>
|
||||
|
||||
|
||||
BIN
images/blank.gif
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
images/file-manager-icons.png
Normal file
|
After Width: | Height: | Size: 6.4 KiB |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 294 B |
|
Before Width: | Height: | Size: 954 B |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 342 B |
|
Before Width: | Height: | Size: 386 B |
BIN
images/full-screen.gif
Normal file
|
After Width: | Height: | Size: 73 B |
BIN
images/ice-coder.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 752 B After Width: | Height: | Size: 752 B |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
BIN
images/restored-screen.gif
Normal file
|
After Width: | Height: | Size: 65 B |
|
Before Width: | Height: | Size: 551 B After Width: | Height: | Size: 551 B |
44
index.php
@@ -10,12 +10,18 @@ if (!$allowedIP) {
|
||||
header('Location: /');
|
||||
};
|
||||
|
||||
// Test for latest CodeMirror version
|
||||
if ($testcMVersion) {
|
||||
$cMLatestVer = json_encode(file_get_contents("http://codemirror.net/latest-version.txt"));
|
||||
$cMLatestVer = rtrim(ltrim($cMLatestVer,"\""),"\"\\n");
|
||||
if ($cMThisVer<$cMLatestVer) {
|
||||
echo '<script>alert(\'Code Mirror '.$cMLatestVer.' now released\n\nPlease upgrade\');</script>';
|
||||
// Check for updates of ICEcoder & CodeMirror
|
||||
if ($checkUpdates) {
|
||||
$ICEcoderLatestVer = json_encode(file_get_contents("http://icecoder.net/latest-version.txt"));
|
||||
$ICEcoderLatestVer = rtrim(ltrim($ICEcoderLatestVer,"\""),"\"\\n");
|
||||
if (ltrim($versionNo,"v ")<ltrim($ICEcoderLatestVer,"v ")) {
|
||||
echo '<script>alert(\'ICEcoder '.$ICEcoderLatestVer.' now released\n\nPlease upgrade\');</script>';
|
||||
} else {
|
||||
$cMLatestVer = json_encode(file_get_contents("http://codemirror.net/latest-version.txt"));
|
||||
$cMLatestVer = rtrim(ltrim($cMLatestVer,"\""),"\"\\n");
|
||||
if ($cMThisVer<$cMLatestVer) {
|
||||
echo '<script>alert(\'Code Mirror '.$cMLatestVer.' now released\n\nPlease upgrade\');</script>';
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -24,11 +30,13 @@ if ($testcMVersion) {
|
||||
<html>
|
||||
<head>
|
||||
<title>ICE Coder - <?php echo $versionNo;?></title>
|
||||
<meta name="robots" content="noindex, nofollow">
|
||||
<link rel="stylesheet" type="text/css" href="lib/coder.css">
|
||||
<script>
|
||||
shortURLStarts = "<?php echo $shortURLStarts;?>";
|
||||
theme = "<?php if ($theme=="default") {echo 'icecoder';} else {echo $theme;};?>";
|
||||
tabsIndent = <?php if ($tabsIndent) {echo 'true';} else {echo 'false';};?>;
|
||||
tabWidth = <?php echo $tabWidth; ?>;
|
||||
<?
|
||||
$docRoot = str_replace("\\","/",$_SERVER['DOCUMENT_ROOT']);
|
||||
if (strrpos($docRoot,"/")==strlen($docRoot)-1) {$docRoot = substr($docRoot,0,strlen($docRoot)-1);};
|
||||
@@ -42,9 +50,9 @@ window.onbeforeunload = function() {
|
||||
}
|
||||
}
|
||||
|
||||
lastOpenFiles = [<?php
|
||||
if ($lastOpenedFiles!="" && $_SESSION['userLevel'] == 10) {
|
||||
$openFilesArray = explode(",",$lastOpenedFiles);
|
||||
previousFiles = [<?php
|
||||
if ($previousFiles!="" && $_SESSION['userLevel'] == 10) {
|
||||
$openFilesArray = explode(",",$previousFiles);
|
||||
for ($i=0;$i<count($openFilesArray);$i++) {
|
||||
echo "'".$openFilesArray[$i]."'";
|
||||
if ($i<count($openFilesArray)-1) {echo ",";};
|
||||
@@ -85,14 +93,15 @@ lastOpenFiles = [<?php
|
||||
<a href="javascript:top.ICEcoder.renameFile(top.ICEcoder.rightClickedFile)" onMouseOver="document.getElementById('fileMenu').style.display='inline-block'">Rename</a>
|
||||
<a href="javascript:window.open(top.ICEcoder.rightClickedFile.substr((top.ICEcoder.rightClickedFile.indexOf(shortURLStarts)+top.shortURLStarts.length),top.ICEcoder.rightClickedFile.length))" onMouseOver="document.getElementById('fileMenu').style.display='inline-block'">View Webpage</a>
|
||||
</span>
|
||||
<a href="javascript:top.ICEcoder.zipIt(top.ICEcoder.rightClickedFile)" onMouseOver="document.getElementById('fileMenu').style.display='inline-block'">Zip It!</a>
|
||||
</div>
|
||||
|
||||
<div id="header" class="header" onContextMenu="return false">
|
||||
<div class="plugins" id="pluginsContainer">
|
||||
<?php echo $pluginsDisplay; ?>
|
||||
</div>
|
||||
<div class="version"><?php echo $versionNo;?></div>
|
||||
<img src="images/ice-coder.gif" class="logo" onClick="ICEcoder.helpScreen('show')" onContextMenu="ICEcoder.settingsScreen('show')">
|
||||
<div class="version"><?php echo $versionNo;?></div><img src="images/full-screen.gif" id="screenMode" class="screenModeIcon" onClick="top.ICEcoder.fullScreenSwitcher()">
|
||||
<img src="images/ice-coder.png" class="logo" onClick="ICEcoder.helpScreen('show')" onContextMenu="ICEcoder.settingsScreen('show')">
|
||||
</div>
|
||||
|
||||
<div id="files" class="files" onMouseOver="ICEcoder.changeFilesW('expand')" onMouseOut="ICEcoder.changeFilesW('contract'); top.document.getElementById('fileMenu').style.display='none';">
|
||||
@@ -108,13 +117,13 @@ lastOpenFiles = [<?php
|
||||
<div class="accountOptions">
|
||||
<a nohref title="Save" onClick="ICEcoder.fMIcon('save')"><img src="images/save.png" alt="Save" id="fMSave" style="opacity: 0.3"></a>
|
||||
<a nohref title="Open" onClick="ICEcoder.fMIcon('open')"><img src="images/open.png" alt="Open" id="fMOpen" style="margin-left: 7px; opacity: 0.3"></a>
|
||||
<a nohref title="New File" onClick="ICEcoder.fMIcon('newFile')"><img src="images/new-file.png" alt="New File" id="fMNewFile" style="margin: 8px 0px 0px 10px; opacity: 0.3"></a>
|
||||
<a nohref title="New Folder" onClick="ICEcoder.fMIcon('newFolder')"><img src="images/new-folder.png" alt="New Folder" id="fMNewFolder" style="margin: 9px 0px 0px 5px; opacity: 0.3"></a>
|
||||
<a nohref title="Delete" onClick="ICEcoder.fMIcon('delete')"><img src="images/delete.png" alt="Delete" id="fMDelete" style="margin: 9px 0px 0px 5px; opacity: 0.3"></a>
|
||||
<a nohref title="Rename" onClick="ICEcoder.fMIcon('rename')"><img src="images/rename.png" alt="Rename" id="fMRename" style="margin: 9px 0px 0px 5px; opacity: 0.3"></a>
|
||||
<a nohref title="View" onClick="ICEcoder.fMIcon('view')"><img src="images/view.png" alt="View" id="fMView" style="margin: 9px 0px 0px 5px; opacity: 0.3"></a>
|
||||
<a nohref title="New File" onClick="ICEcoder.fMIcon('newFile')"><img src="images/new-file.png" alt="New File" id="fMNewFile" style="margin: 8px 0 0 10px; opacity: 0.3"></a>
|
||||
<a nohref title="New Folder" onClick="ICEcoder.fMIcon('newFolder')"><img src="images/new-folder.png" alt="New Folder" id="fMNewFolder" style="margin: 9px 0 0 5px; opacity: 0.3"></a>
|
||||
<a nohref title="Delete" onClick="ICEcoder.fMIcon('delete')"><img src="images/delete.png" alt="Delete" id="fMDelete" style="margin: 9px 0 0 5px; opacity: 0.3"></a>
|
||||
<a nohref title="Rename" onClick="ICEcoder.fMIcon('rename')"><img src="images/rename.png" alt="Rename" id="fMRename" style="margin: 9px 0 0 5px; opacity: 0.3"></a>
|
||||
<a nohref title="View" onClick="ICEcoder.fMIcon('view')"><img src="images/view.png" alt="View" id="fMView" style="margin: 9px 0 0 5px; opacity: 0.3"></a>
|
||||
</div>
|
||||
<a nohref style="cursor: pointer" onClick="ICEcoder.lockUnlockNav()"><img src="images/file-manager-icons/padlock.png" id="fmLock" class="lock"></a>
|
||||
<a nohref style="cursor: pointer" onClick="ICEcoder.lockUnlockNav()"><img src="images/padlock.png" id="fmLock" class="lock"></a>
|
||||
</div>
|
||||
<iframe id="filesFrame" class="frame" name="ff" src="files.php" style="opacity: 0" onLoad="this.style.opacity='1'"></iframe>
|
||||
<div class="serverMessage" id="serverMessage"></div>
|
||||
@@ -174,6 +183,7 @@ lastOpenFiles = [<?php
|
||||
</div>
|
||||
|
||||
<script>
|
||||
ICEcoder.initAliases();
|
||||
ICEcoder.setLayout('dontSetEditor');
|
||||
</script>
|
||||
|
||||
|
||||
@@ -9,10 +9,10 @@ dl, dt, dd, ol, ul, li,
|
||||
fieldset, form, label, legend,
|
||||
table, caption, tbody, tfoot, thead, tr, th, td {
|
||||
font-family: arial, verdana, helvetica, sans-serif;
|
||||
border: 0px;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
outline: 0px;
|
||||
border: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
outline: 0;
|
||||
font-size: 12px;
|
||||
vertical-align: top;
|
||||
}
|
||||
@@ -28,13 +28,13 @@ body {overflow: hidden;
|
||||
h1 {font-size: 36px; font-weight: normal; color: #888; margin-bottom: 20px}
|
||||
h2 {font-size: 18px; font-weight: normal; color: #fff}
|
||||
|
||||
.blackMask {position: fixed; display: table; width: 100%; height: 100%; top: 0px; left: 0px; visibility: hidden; background-color: rgba(0,0,0,0.8); text-align: center; z-index: 100}
|
||||
.blackMask {position: fixed; display: table; width: 100%; height: 100%; top: 0; left: 0; visibility: hidden; background-color: rgba(0,0,0,0.8); text-align: center; z-index: 100}
|
||||
.blackMask .popupVCenter {#position: absolute; display: table-cell; #top: 50%; vertical-align: middle; text-align: center}
|
||||
.popupVCenter .popup {#position: relative; #top: -50%; text-align: center; color: #fff; font-size: 10px}
|
||||
.whiteGlow {
|
||||
-webkit-box-shadow: 0px 0px 8px 2px rgba(255,255,255,0.6);
|
||||
-moz-box-shadow: 0px 0px 8px 2px rgba(255,255,255,0.6);
|
||||
box-shadow: 0px 0px 8px 2px rgba(255,255,255,0.6);
|
||||
-webkit-box-shadow: 0 0 8px 2px rgba(255,255,255,0.6);
|
||||
-moz-box-shadow: 0 0 8px 2px rgba(255,255,255,0.6);
|
||||
box-shadow: 0 0 8px 2px rgba(255,255,255,0.6);
|
||||
}
|
||||
|
||||
.circleOutside {background-color: rgba(0,0,0,0); border:5px solid rgba(0,183,229,0.9); opacity:.9; border-top:5px solid rgba(0,0,0,0); border-left:5px solid rgba(0,0,0,0); border-radius:50px; box-shadow: 0 0 35px #2187e7;
|
||||
@@ -60,32 +60,33 @@ h2 {font-size: 18px; font-weight: normal; color: #fff}
|
||||
100% { -webkit-transform:rotate(-360deg);}
|
||||
}
|
||||
|
||||
.progressBar {top: 0px; left: 0px; width:100%; height:1px; margin:2px 0; background:#2187e7; position:absolute; box-shadow:0px 0px 10px 1px rgba(0,198,255,0.7);
|
||||
.progressBar {top: 0; left: 0; width:100%; height:1px; margin:2px 0; background:#2187e7; position:absolute; box-shadow:0 0 10px 1px rgba(0,198,255,0.7);
|
||||
-moz-animation:fullexpand 10s ease-out; -webkit-animation:fullexpand 10s ease-out;
|
||||
}
|
||||
@-moz-keyframes fullexpand {
|
||||
0% { width:0px;}
|
||||
0% { width:0;}
|
||||
100%{ width:100%;}
|
||||
}
|
||||
@-webkit-keyframes fullexpand {
|
||||
0% { width:0px;}
|
||||
0% { width:0;}
|
||||
100%{ width:100%;}
|
||||
}
|
||||
|
||||
.header {position: absolute; display: inline-block; width: 100%; height: 40px; background-color: #fff; text-align: right; z-index: 2}
|
||||
.header {position: absolute; display: inline-block; top: 0; left: 0; width: 100%; height: 40px; background-color: #fff; text-align: right; z-index: 2}
|
||||
.header .plugins {position: absolute; display: inline-block; left: 15px; top: 3px}
|
||||
.header .plugins img {position: relative; display: inline-block; margin-right: 15px}
|
||||
.header .screenModeIcon {position: absolute; top: 5px; right: 178px; cursor: pointer}
|
||||
.header .version {position: relative; display: inline-block; margin-top: 25px; font-size: 10px; color: #bbb}
|
||||
.header .logo {position: relative; margin: 5px 10px 0px 5px; cursor: pointer}
|
||||
.header .logo {position: relative; margin: 5px 10px 0 5px; cursor: pointer}
|
||||
|
||||
.files {position: absolute; display: inline-block; height: 100%; width: 250px; background-color: #444; background-image: url('../images/files-arrow.gif'); background-repeat: no-repeat; background-position: 100% 50%; overflow: hidden; z-index: 1;
|
||||
-webkit-box-shadow: 0px 0px 10px 4px rgba(0,0,0,0.4);
|
||||
-moz-box-shadow: 0px 0px 10px 4px rgba(0,0,0,0.4);
|
||||
box-shadow: 0px 0px 10px 4px rgba(0,0,0,0.4);
|
||||
.files {position: absolute; display: inline-block; top: 0; left: 0; height: 100%; width: 250px; background-color: #444; background-image: url('../images/files-arrow.gif'); background-repeat: no-repeat; background-position: 100% 50%; overflow: hidden; z-index: 1;
|
||||
-webkit-box-shadow: 0 0 10px 4px rgba(0,0,0,0.4);
|
||||
-moz-box-shadow: 0 0 10px 4px rgba(0,0,0,0.4);
|
||||
box-shadow: 0 0 10px 4px rgba(0,0,0,0.4);
|
||||
}
|
||||
.files .account {display: inline-block; height: 50px; width: 250px; margin-top: 40px; background-color: #888}
|
||||
.files .accountLoginContainer {position: absolute; width: 250px; height: 50px; z-index: 1}
|
||||
.files .accountLoginContainer .accountLogin {position: absolute; width: 250px; height: 50px; top: 0px; background-color: #666;
|
||||
.files .accountLoginContainer .accountLogin {position: absolute; width: 250px; height: 50px; top: 0; background-color: #666;
|
||||
-webkit-transition: top 0.3s;
|
||||
-moz-transition: top 0.3s;
|
||||
-o-transition: top 0.3s;
|
||||
@@ -96,15 +97,15 @@ h2 {font-size: 18px; font-weight: normal; color: #fff}
|
||||
.files .accountPassword {position: relative; border: 1px solid #888; background-color: #999; height: 18px; width: 140px; margin-left: 14px; margin-top: 15px}
|
||||
.files input:focus, .findReplace input:focus, .findReplace select:focus, .accountPassword:focus {
|
||||
outline: none;
|
||||
-webkit-box-shadow: 0px 0px 10px 1px rgba(0,198,255,0.7);
|
||||
-moz-box-shadow: 0px 0px 10px 1px rgba(0,198,255,0.7);
|
||||
box-shadow: 0px 0px 10px 1px rgba(0,198,255,0.7);
|
||||
-webkit-box-shadow: 0 0 10px 1px rgba(0,198,255,0.7);
|
||||
-moz-box-shadow: 0 0 10px 1px rgba(0,198,255,0.7);
|
||||
box-shadow: 0 0 10px 1px rgba(0,198,255,0.7);
|
||||
}
|
||||
.files .button {position: absolute; border: 0px; background: #999; color: #555; height:20px; margin-top: 16px; margin-left: 5px; font-size: 11px; cursor: pointer}
|
||||
.files .button {position: absolute; border: 0; background: #999; color: #555; height:20px; margin-top: 16px; margin-left: 5px; font-size: 11px; cursor: pointer}
|
||||
.files .button:hover {background-color: #444; color: #eee}
|
||||
.files .lock {position: relative; margin-left: 225px; margin-top: -20px; z-index: 1}
|
||||
.files .frame {display: inline-block; width: 250px}
|
||||
.files .serverMessage {position: absolute; display: inline-block; width: 450px; bottom: 0px; margin-bottom: 30px; background-color: rgba(255,255,255,0.8); font-size: 10px; padding: 7px 12px; opacity: 0;
|
||||
.files .serverMessage {position: absolute; display: inline-block; width: 450px; bottom: 0; margin-bottom: 30px; background-color: rgba(255,255,255,0.8); font-size: 10px; padding: 7px 12px; opacity: 0;
|
||||
-webkit-transition: all 0.2s;
|
||||
-moz-transition: all 0.2s;
|
||||
-o-transition: all 0.2s;
|
||||
@@ -112,53 +113,53 @@ h2 {font-size: 18px; font-weight: normal; color: #fff}
|
||||
}
|
||||
.files .serverMessage b {font-size: 10px}
|
||||
|
||||
.editor {position: absolute; display: inline-block; top: 0px; left: 15px; width: 2400px}
|
||||
.editor {position: absolute; display: inline-block; top: 0; left: 15px; width: 2400px}
|
||||
.editor .tabsBar {display: inline-block; height: 22px; width: 2400px; margin-top: 40px; padding-left: 41px; background-color: #888;}
|
||||
.tabsBar .tab {display: inline-block; display: none; background-image: url('../images/nav-bg.gif'); background-repeat: repeat-x; background-position: 0px 0px; padding: 5px 8px 2px 8px; font-size: 10px; border-left: solid 1px #fff; border-right: solid 1px #777; color: #fff; cursor: pointer;
|
||||
.tabsBar .tab {display: inline-block; display: none; background-image: url('../images/nav-bg.gif'); background-repeat: repeat-x; background-position: 0 0; padding: 5px 8px 2px 8px; font-size: 10px; border-left: solid 1px #fff; border-right: solid 1px #777; color: #fff; cursor: pointer;
|
||||
-webkit-transition: all 0.15s;
|
||||
-moz-transition: all 0.15s;
|
||||
-o-transition: all 0.15s;
|
||||
transition: all 0.15s;
|
||||
}
|
||||
.tabsBar .tab .closeTab {margin: 1px 0px 0px 5px; border-radius: 6px}
|
||||
.tabsBar .newTab {display: inline-block; background-image: url('../images/nav-bg.gif'); background-repeat: repeat-x; background-position: 0px 0px; padding: 6px 5px 1px 5px; border-left: solid 1px #fff; border-right: solid 1px #777; cursor: pointer;}
|
||||
.tabsBar .tab .closeTab {margin: 1px 0 0 5px; border-radius: 6px}
|
||||
.tabsBar .newTab {display: inline-block; background-image: url('../images/nav-bg.gif'); background-repeat: repeat-x; background-position: 0 0; padding: 6px 5px 1px 5px; border-left: solid 1px #fff; border-right: solid 1px #777; cursor: pointer;}
|
||||
.editor .findBar {display: inline-block; height: 28px; width: 2400px; color: #fff; background-color: #141414}
|
||||
.findBar .findReplace {position: absolute; z-index: 1}
|
||||
.findReplace select {position: relative; font-size: 10px; margin: 8px 2px 0px 2px; top: -2px;}
|
||||
.findReplace .findText {display: inline-block; height: 21px; font-size: 10px; margin: 8px 2px 0px 2px; margin-left: 43px}
|
||||
.findReplace select {position: relative; font-size: 10px; margin: 8px 2px 0 2px; top: -2px;}
|
||||
.findReplace .findText {display: inline-block; height: 21px; font-size: 10px; margin: 8px 2px 0 2px; margin-left: 43px}
|
||||
.findReplace .find {position: relative; width: 120px; height: 16px; border: 0; top: -2px; font-size: 10px; padding-left: 5px}
|
||||
.findReplace .findTextPlural {display: inline-block; height: 21px; font-size: 10px; margin: 8px 2px 0px 0px}
|
||||
.findReplace .replaceAction {margin: 0px 2px 0px 0px; top: -2px}
|
||||
.findReplace .replaceText {height: 21px; font-size: 10px; margin: 8px 2px 0px 2px}
|
||||
.findReplace .findTextPlural {display: inline-block; height: 21px; font-size: 10px; margin: 8px 2px 0 0}
|
||||
.findReplace .replaceAction {margin: 0 2px 0 0; top: -2px}
|
||||
.findReplace .replaceText {height: 21px; font-size: 10px; margin: 8px 2px 0 2px}
|
||||
.findReplace .replace {position: relative; width: 120px; height: 16px; border: 0; top: -2px; font-size: 10px; padding-left: 5px}
|
||||
.findReplace .targetText {height: 21px; font-size: 10px; margin: 8px 2px 0px 2px}
|
||||
.findReplace .targetText {height: 21px; font-size: 10px; margin: 8px 2px 0 2px}
|
||||
.findReplace .submit {position: relative; top: -2px; height: 17px; border: 1px solid #bbb; background-color: #f8f8f8; font-size: 10px; cursor: pointer}
|
||||
.findReplace .results {position: relative; display: inline-block; width: 200px; height: 20px; font-size: 10px; margin: 8px 0px 0px 20px}
|
||||
.findReplace .results {position: relative; display: inline-block; width: 200px; height: 20px; font-size: 10px; margin: 8px 0 0 20px}
|
||||
.findBar .codeAssist {position: fixed; display: inline-block; width: 100px; right: 74px; top: 70px; height: 21px; font-size: 10px; z-index: 1}
|
||||
.findBar .codeAssist input {margin-top: -1px}
|
||||
.findBar .goLine {position: fixed; display: inline-block; width: 100px; right: -10px; top: 70px; height: 21px; font-size: 10px; z-index: 1}
|
||||
.goLine .goToLine {width: 25px; height: 16px; border: 0; font-size: 10px; margin: -3px 0px 0px 3px}
|
||||
.goLine .goToLine {width: 25px; height: 16px; border: 0; font-size: 10px; margin: -3px 0 0 3px}
|
||||
.editor .code {position: relative; display: inline-block; top: 28px; width: 600px; height: 600px; visibility: hidden}
|
||||
|
||||
.footer {position: fixed; display: inline-block; width: 100%; height: 30px; bottom: 0px; background-color: rgba(0,0,0,0.7); left: 0px; z-index: 2}
|
||||
.footer .nesting {display: inline-block; padding: 5px 8px; margin: 4px 0px 0px 15px; font-weight: bold; font-size: 10px; color: #fff; background-color: #0b0}
|
||||
.footer .nestLoc {position: absolute; display: inline-block; width: 120px; padding: 5px 0px 0px 8px; margin-top: 3px; left: 112px; font-weight: bold; font-size: 12px; color: #fff; text-align: right}
|
||||
.footer .nestDisplay {position: absolute; display: inline-block; padding: 5px 0px 0px 8px; margin-top: 3px; left: 255px; font-size: 12px; color: #fff; text-align: right}
|
||||
.footer .charDisplay {position: absolute; display: inline-block; padding: 5px 0px 0px 8px; margin-top: 3px; left: 100%; font-weight: bold; font-size: 12px; color: #fff; text-align: right; width: 200px; text-align: right; margin-left: -220px}
|
||||
.footer {position: fixed; display: inline-block; width: 100%; height: 30px; bottom: 0; background-color: rgba(0,0,0,0.7); left: 0; z-index: 2}
|
||||
.footer .nesting {display: inline-block; padding: 5px 8px; margin: 4px 0 0 15px; font-weight: bold; font-size: 10px; color: #fff; background-color: #0b0}
|
||||
.footer .nestLoc {position: absolute; display: inline-block; width: 120px; padding: 5px 0 0 8px; margin-top: 3px; left: 112px; font-weight: bold; font-size: 12px; color: #fff; text-align: right}
|
||||
.footer .nestDisplay {position: absolute; display: inline-block; padding: 5px 0 0 8px; margin-top: 3px; left: 255px; font-size: 12px; color: #fff; text-align: right}
|
||||
.footer .charDisplay {position: absolute; display: inline-block; padding: 5px 0 0 8px; margin-top: 3px; left: 100%; font-weight: bold; font-size: 12px; color: #fff; text-align: right; width: 200px; text-align: right; margin-left: -220px}
|
||||
|
||||
.textbox {
|
||||
-webkit-box-shadow: inset 1px 1px 2px 0px rgba(0,0,0,0.4);
|
||||
-moz-box-shadow: inset 1px 1px 2px 0px rgba(0,0,0,0.4);
|
||||
box-shadow: inset 1px 1px 2px 0px rgba(0,0,0,0.4);
|
||||
-webkit-box-shadow: inset 1px 1px 2px 0 rgba(0,0,0,0.4);
|
||||
-moz-box-shadow: inset 1px 1px 2px 0 rgba(0,0,0,0.4);
|
||||
box-shadow: inset 1px 1px 2px 0 rgba(0,0,0,0.4);
|
||||
}
|
||||
|
||||
.fileMenu {position: absolute; display: none; left: 0px; top: 0px; background-color: #333; z-index: 10}
|
||||
.fileMenu a {display: block; padding: 2px 5px; background-color: #444; color: #eee; text-decoration: none}
|
||||
.fileMenu {position: absolute; display: none; left: 0; top: 0; background-color: #333; z-index: 10}
|
||||
.fileMenu a {display: block; padding: 2px 5px; background-color: #333; color: #eee; text-decoration: none}
|
||||
.fileMenu a:hover {background-color: #666}
|
||||
|
||||
.screenContainer {position: absolute; display: table; width: 100%; height: 100%; top: 0px; left: 0px; text-align: center}
|
||||
.screenContainer {position: absolute; display: table; width: 100%; height: 100%; top: 0; left: 0; text-align: center}
|
||||
.screenContainer .screenVCenter {#position: absolute; display: table-cell; #top: 50%; vertical-align: middle; text-align: center}
|
||||
.screenVCenter .screenCenter {#position: relative; #top: -50%; text-align: center; display: inline}
|
||||
.screenCenter .version {position: relative; display: block; margin: 5px 0px 15px 0px; font-size: 10px; color: #bbb}
|
||||
.screenCenter .version {position: relative; display: block; margin: 5px 0 15px 0; font-size: 10px; color: #bbb}
|
||||
.screenCenter .accountPassword {border: 1px solid #888; height: 18px}
|
||||
.screenCenter .button {border: 0px; background: #666; color: #fff; height: 22px; cursor: pointer}
|
||||
.screenCenter .button {border: 0; background: #666; color: #fff; height: 22px; cursor: pointer}
|
||||
166
lib/coder.js
@@ -1,9 +1,3 @@
|
||||
// ICE coder by Matt Pass
|
||||
// Free to use it for your own purposes, commercial or not, just let me know of any cool uses or customisations. :)
|
||||
// No warranty or liability accepted for anything, all responsibility of use is your own.
|
||||
// Latest version: https://github.com/mattpass/ICEcoder
|
||||
// Twitter: @mattpass
|
||||
|
||||
var ICEcoder = {
|
||||
// Define settings
|
||||
filesW: 250, // Initial width of the files pane
|
||||
@@ -33,15 +27,18 @@ var ICEcoder = {
|
||||
// Don't consider these tags as part of nesting as they're singles, JS, PHP or Ruby code blocks
|
||||
tagNestExceptions: ["!DOCTYPE","meta","link","img","br","hr","input","script","?php","?","%"],
|
||||
|
||||
// On load, set aliases, set the layout and get the nest location
|
||||
init: function(login) {
|
||||
// Set our aliases
|
||||
initAliases: function() {
|
||||
var aliasArray = ["header","files","account","accountLogin","fmLock","filesFrame","editor","tabsBar","findBar","content","footer","nestValid","nestDisplay","charDisplay"];
|
||||
|
||||
// Create our ID aliases
|
||||
for (var i=0;i<aliasArray.length;i++) {
|
||||
ICEcoder[aliasArray[i]] = top.document.getElementById(aliasArray[i]);
|
||||
}
|
||||
},
|
||||
|
||||
// On load, set the layout and get the nest location
|
||||
init: function(login) {
|
||||
// Set layout & the nest location
|
||||
ICEcoder.setLayout();
|
||||
|
||||
@@ -65,15 +62,15 @@ var ICEcoder = {
|
||||
|
||||
// Apply sizes to various elements of the page
|
||||
headerH = 40, footerH = 30, accountH = 50, tabsBarH = 21, findBarH = 28;
|
||||
header.style.width = tabsBar.style.width = findBar.style.width = winW + "px";
|
||||
files.style.width = accountLogin.style.width = editor.style.left = this.filesW + "px";
|
||||
account.style.height = accountH + "px";
|
||||
fmLock.style.marginLeft = (this.filesW-27) + "px";
|
||||
filesFrame.style.height = (winH-headerH-accountH-footerH) + "px";
|
||||
this.header.style.width = this.tabsBar.style.width = this.findBar.style.width = winW + "px";
|
||||
this.files.style.width = this.accountLogin.style.width = this.editor.style.left = this.filesW + "px";
|
||||
this.account.style.height = this.accountH + "px";
|
||||
this.fmLock.style.marginLeft = (this.filesW-27) + "px";
|
||||
this.filesFrame.style.height = (winH-headerH-accountH-footerH) + "px";
|
||||
|
||||
// If we need to set the editor sizes
|
||||
if (!dontSetEditor) {
|
||||
editor.style.width = ICEcoder.content.style.width = (winW-this.filesW) + "px";
|
||||
this.editor.style.width = ICEcoder.content.style.width = (winW-this.filesW) + "px";
|
||||
ICEcoder.content.style.height = (winH-headerH-footerH-tabsBarH-findBarH) + "px";
|
||||
|
||||
// Resize the CodeMirror instances to match the window size
|
||||
@@ -372,16 +369,21 @@ var ICEcoder = {
|
||||
|
||||
// Reset all tabs to be without a highlight and then highlight the selected
|
||||
redoTabHighlight: function(selectedTab) {
|
||||
var bgVPos, tColor;
|
||||
var cM, bgVPos, tColor, fileLink;
|
||||
|
||||
cM = ICEcoder.getcMInstance();
|
||||
for(var i=1;i<=ICEcoder.changedContent.length;i++) {
|
||||
if (document.getElementById('closeTabButton'+i)) {
|
||||
ICEcoder.changedContent[i-1]==1 ? document.getElementById('closeTabButton'+i).style.backgroundColor = "#b00" : document.getElementById('closeTabButton'+i).style.backgroundColor = "rgba(255,255,255,0.3)";
|
||||
ICEcoder.changedContent[i-1]==1 && cM.historySize().undo>0 ? document.getElementById('closeTabButton'+i).style.backgroundColor = "#b00" : document.getElementById('closeTabButton'+i).style.backgroundColor = "rgba(255,255,255,0.3)";
|
||||
}
|
||||
i==selectedTab ? tColor = "#000" : tColor = "#fff";
|
||||
if ("undefined" != typeof top.ICEcoder.openFiles[i-1] && top.ICEcoder.openFiles[i-1] != "/[NEW]") {
|
||||
fileLink = top.ICEcoder.filesFrame.contentWindow.document.getElementById(top.ICEcoder.openFiles[i-1].replace(/\//g,"|"));
|
||||
i==selectedTab ? fileLink.style.backgroundColor = "#4499dd" : fileLink.style.backgroundColor = "rgba(255,255,255,0.15)";
|
||||
}
|
||||
document.getElementById('tab'+i).style.color = tColor;
|
||||
i==selectedTab ? bgVPos = -22 : bgVPos = 0;
|
||||
document.getElementById('tab'+i).style.backgroundPosition = "0px "+bgVPos+"px";
|
||||
document.getElementById('tab'+i).style.backgroundPosition = "0 "+bgVPos+"px";
|
||||
}
|
||||
ICEcoder.changedContent[selectedTab-1]==1 ? top.ICEcoder.fMIconVis('fMSave',1) : top.ICEcoder.fMIconVis('fMSave',0.3);
|
||||
},
|
||||
@@ -400,7 +402,6 @@ var ICEcoder = {
|
||||
|
||||
cM = ICEcoder.getcMInstance('new');
|
||||
ICEcoder.switchTab(ICEcoder.openFiles.length);
|
||||
ICEcoder.content.style.visibility='visible';
|
||||
|
||||
cM.setLineClass(ICEcoder['cMActiveLine'+ICEcoder.selectedTab], null);
|
||||
ICEcoder['cMActiveLine'+ICEcoder.selectedTab] = cM.setLineClass(0, "cm-s-activeLine");
|
||||
@@ -426,7 +427,7 @@ var ICEcoder = {
|
||||
// Add a new value ready to indicate if this content has been changed
|
||||
top.ICEcoder.changedContent.push(0);
|
||||
|
||||
top.ICEcoder.setLastOpenedFiles();
|
||||
top.ICEcoder.setPreviousFiles();
|
||||
},
|
||||
|
||||
// Create a new tab for a file
|
||||
@@ -559,7 +560,6 @@ var ICEcoder = {
|
||||
|
||||
// hide the content area if we have no tabs open
|
||||
if (ICEcoder.openFiles.length==0) {
|
||||
top.document.getElementById('content').style.visibility = "hidden";
|
||||
top.ICEcoder.fMIconVis('fMView',0.3);
|
||||
} else {
|
||||
// Switch the mode & the tab
|
||||
@@ -570,7 +570,7 @@ var ICEcoder = {
|
||||
top.ICEcoder.changedContent.splice(closeTabNum-1,1);
|
||||
top.parent.ICEcoder.redoTabHighlight(ICEcoder.selectedTab);
|
||||
|
||||
top.ICEcoder.setLastOpenedFiles();
|
||||
top.ICEcoder.setPreviousFiles();
|
||||
}
|
||||
// Lastly, stop it from trying to also switch tab
|
||||
top.ICEcoder.canSwitchTabs=false;
|
||||
@@ -593,7 +593,7 @@ var ICEcoder = {
|
||||
while (1) {
|
||||
if (node != null) {
|
||||
if (node.tagName == "UL") {
|
||||
var d = (node.style.display == "none")
|
||||
var d = (node.style.display == "none");
|
||||
node.style.display = (d) ? "block" : "none";
|
||||
this.className = (d) ? "open" : "closed";
|
||||
return false;
|
||||
@@ -613,6 +613,8 @@ var ICEcoder = {
|
||||
}
|
||||
}
|
||||
}
|
||||
aMenus[0].childNodes[0].className = "open";
|
||||
aMenus[0].childNodes[1].style.display = "block";
|
||||
return false;
|
||||
},
|
||||
|
||||
@@ -696,7 +698,19 @@ var ICEcoder = {
|
||||
|
||||
// Select or deselect file
|
||||
selectDeselectFile: function(action,file) {
|
||||
action == "select" ? file.style.backgroundColor="#888" : file.style.backgroundColor="transparent";
|
||||
var isOpen;
|
||||
|
||||
top.ICEcoder.openFiles.indexOf(file.id.replace(/\|/g,"/")) > -1 ? isOpen = true : isOpen = false;
|
||||
|
||||
if (top.ICEcoder.openFiles[top.ICEcoder.selectedTab-1] == file.id.replace(/\|/g,"/")) {
|
||||
file.style.backgroundColor="#4499dd";
|
||||
} else {
|
||||
if (action=="select") {
|
||||
file.style.backgroundColor="#888";
|
||||
} else {
|
||||
isOpen ? file.style.backgroundColor = "rgba(255,255,255,0.15)" : file.style.backgroundColor="transparent";
|
||||
}
|
||||
}
|
||||
action == "select" ? file.style.color="#fff" : file.style.color="#eee";
|
||||
},
|
||||
|
||||
@@ -720,7 +734,11 @@ var ICEcoder = {
|
||||
},
|
||||
|
||||
// Open a file on demand
|
||||
openFile: function() {
|
||||
openFile: function(fileLink) {
|
||||
if (fileLink) {
|
||||
top.ICEcoder.thisFileFolderLink=fileLink;
|
||||
top.ICEcoder.thisFileFolderType="file";
|
||||
}
|
||||
if (top.ICEcoder.thisFileFolderLink!="" && top.ICEcoder.thisFileFolderType=="file") {
|
||||
var shortURL, canOpenFile;
|
||||
|
||||
@@ -792,7 +810,7 @@ var ICEcoder = {
|
||||
top.ICEcoder.serverQueue("add","lib/file-control.php?action=rename&file="+renamedFile+"&oldFileName="+top.ICEcoder.rightClickedFile.replace(/\|/g,"/"));
|
||||
top.ICEcoder.serverMessage('<b>Renaming to</b><br>'+renamedFile);
|
||||
|
||||
top.ICEcoder.setLastOpenedFiles();
|
||||
top.ICEcoder.setPreviousFiles();
|
||||
}
|
||||
},
|
||||
|
||||
@@ -963,11 +981,11 @@ var ICEcoder = {
|
||||
},
|
||||
|
||||
// Go to a specific line number
|
||||
goToLine: function() {
|
||||
goToLine: function(lineNo) {
|
||||
var cM;
|
||||
|
||||
cM = ICEcoder.getcMInstance();
|
||||
cM.setCursor(document.getElementById('goToLineNo').value-1);
|
||||
cM.setCursor(lineNo ? lineNo-1 : document.getElementById('goToLineNo').value-1);
|
||||
cM.focus();
|
||||
return false;
|
||||
},
|
||||
@@ -999,7 +1017,7 @@ var ICEcoder = {
|
||||
|
||||
lockIcon = top.document.getElementById('fmLock');
|
||||
ICEcoder.lockedNav ? ICEcoder.lockedNav = false : ICEcoder.lockedNav = true;
|
||||
ICEcoder.lockedNav ? lockIcon.src="images/file-manager-icons/padlock.png" : lockIcon.src="images/file-manager-icons/padlock-disabled.png";
|
||||
ICEcoder.lockedNav ? lockIcon.src="images/padlock.png" : lockIcon.src="images/padlock-disabled.png";
|
||||
},
|
||||
|
||||
// Determine the CodeMirror instance we're using on demand
|
||||
@@ -1091,11 +1109,11 @@ var ICEcoder = {
|
||||
var tempX, tempY, scrollTop, IE;
|
||||
|
||||
IE = document.all ? true : false;
|
||||
if (!IE) {document.captureEvents(Event.MOUSEMOVE)};
|
||||
if (IE) {
|
||||
top.ICEcoder.mouseX = event.clientX + document.body.scrollLeft;
|
||||
top.ICEcoder.mouseY = event.clientY + document.body.scrollTop;
|
||||
top.ICEcoder.mouseX = e.clientX + document.body.scrollLeft;
|
||||
top.ICEcoder.mouseY = e.clientY + document.body.scrollTop;
|
||||
} else {
|
||||
document.captureEvents(Event.MOUSEMOVE);
|
||||
top.ICEcoder.mouseX = e.pageX;
|
||||
top.ICEcoder.mouseY = e.pageY;
|
||||
}
|
||||
@@ -1395,31 +1413,27 @@ var ICEcoder = {
|
||||
top.ICEcoder.dontSelect = true;
|
||||
},
|
||||
|
||||
// Set the current lastOpenedFiles in the settings file
|
||||
setLastOpenedFiles: function() {
|
||||
var lastOpenedFiles;
|
||||
// Set the current previousFiles in the settings file
|
||||
setPreviousFiles: function() {
|
||||
var previousFiles;
|
||||
|
||||
lastOpenedFiles = "";
|
||||
previousFiles = "";
|
||||
// Generate a comma seperated list
|
||||
for (var i=0;i<top.ICEcoder.openFiles.length;i++) {
|
||||
if (top.ICEcoder.openFiles[i]!="" && top.ICEcoder.openFiles[i].indexOf("[NEW]")==-1) {
|
||||
lastOpenedFiles += top.ICEcoder.openFiles[i].replace(/\//g,"|");
|
||||
if (i<top.ICEcoder.openFiles.length-1) {lastOpenedFiles += ","};
|
||||
previousFiles += top.ICEcoder.openFiles[i].replace(/\//g,"|");
|
||||
if (i<top.ICEcoder.openFiles.length-1) {previousFiles += ","};
|
||||
}
|
||||
}
|
||||
if (lastOpenedFiles!="") {
|
||||
// Then send through to the settings page to update setting
|
||||
top.ICEcoder.serverQueue("add","lib/settings.php?saveFiles="+lastOpenedFiles);
|
||||
} else {
|
||||
top.ICEcoder.serverMessage();
|
||||
top.ICEcoder.serverQueue("del",0);
|
||||
}
|
||||
if (previousFiles=="") {previousFiles="CLEAR"};
|
||||
// Then send through to the settings page to update setting
|
||||
top.ICEcoder.serverQueue("add","lib/settings.php?saveFiles="+previousFiles);
|
||||
},
|
||||
|
||||
// Opens the last files we had open
|
||||
autoOpenFiles: function() {
|
||||
for (var i=0;i<=top.lastOpenFiles.length-1;i++) {
|
||||
top.ICEcoder.rightClickedFile=top.ICEcoder.thisFileFolderLink=top.fullPath+top.lastOpenFiles[i].replace('|','/');
|
||||
for (var i=0;i<=top.previousFiles.length-1;i++) {
|
||||
top.ICEcoder.rightClickedFile=top.ICEcoder.thisFileFolderLink=top.fullPath+top.previousFiles[i].replace('|','/');
|
||||
top.ICEcoder.thisFileFolderType='file';
|
||||
top.ICEcoder.openFile();
|
||||
}
|
||||
@@ -1435,6 +1449,10 @@ var ICEcoder = {
|
||||
top.document.getElementById('loadingMask').style.visibility = "hidden";
|
||||
if (loginAttempt) {
|
||||
if (loginAttempt == "loginOK") {
|
||||
if (top.ICEcoder.openFiles.length==0) {
|
||||
top.ICEcoder.content.style.visibility='visible';
|
||||
top.ICEcoder.content.src = "editor.php";
|
||||
}
|
||||
top.document.getElementById('accountLogin').style.top = "-50px";
|
||||
setTimeout(function() {top.document.getElementById('accountLoginContainer').style.display = "none";},300);
|
||||
} else {
|
||||
@@ -1461,7 +1479,7 @@ var ICEcoder = {
|
||||
},
|
||||
|
||||
// Update the settings used when we make a change to them
|
||||
useNewSettings: function(themeURL,tabsIndent,codeAssist,lockedNav,visibleTabs,refreshFM) {
|
||||
useNewSettings: function(themeURL,tabsIndent,codeAssist,lockedNav,visibleTabs,tabWidth,refreshFM) {
|
||||
var styleNode, strCSS, cMCSS;
|
||||
|
||||
// Add new stylesheet for selected theme
|
||||
@@ -1492,6 +1510,12 @@ var ICEcoder = {
|
||||
cMCSS = ICEcoder.content.contentWindow.document;
|
||||
visibleTabs ? cMCSS.styleSheets[2][strCSS][5].style['content'] = '"\\21e5"' : cMCSS.styleSheets[2][strCSS][5].style['content'] = '" "';
|
||||
|
||||
top.tabWidth = tabWidth;
|
||||
for (var i=0;i<ICEcoder.cMInstances.length;i++) {
|
||||
ICEcoder.content.contentWindow['cM'+ICEcoder.cMInstances[i]].setOption("indentUnit", top.tabWidth);
|
||||
ICEcoder.content.contentWindow['cM'+ICEcoder.cMInstances[i]].setOption("tabSize", top.tabWidth);
|
||||
}
|
||||
|
||||
// Finally, refresh the file manager if we need to
|
||||
if (refreshFM) {top.ICEcoder.refreshFileManager()};
|
||||
},
|
||||
@@ -1500,5 +1524,53 @@ var ICEcoder = {
|
||||
updateResultsDisplay: function(showHide) {
|
||||
ICEcoder.findReplace('find',true,false);
|
||||
document.getElementById('results').style.display = showHide == "show" ? 'inline-block' : 'none';
|
||||
},
|
||||
|
||||
// Show file & folder count in server info screen
|
||||
updateFileFolderCount: function() {
|
||||
var fileText, dirText, unitSize, unitText, dContainer;
|
||||
|
||||
top.ICEcoder.dirCount > 1 ? dirText = "folders" : dirText = "folder";
|
||||
top.ICEcoder.fileCount > 1 ? fileText = "files" : fileText = "file";
|
||||
// Change into kilobytes
|
||||
unitSize = Math.ceil(top.ICEcoder.fileBytes/1024);
|
||||
unitText = "kb";
|
||||
// Maybe we should show in megabytes?
|
||||
if (unitSize >= 1024) {
|
||||
unitSize = unitSize / 1024;
|
||||
unitText = "mb";
|
||||
}
|
||||
// Update the display
|
||||
dContainer = top.ICEcoder.content.contentWindow.document.getElementById('fileFolderCounts');
|
||||
if (dContainer) {
|
||||
dContainer.innerHTML = top.ICEcoder.fileCount+" "+fileText+", "+top.ICEcoder.dirCount+" "+dirText+"<br>~ "+unitSize+" "+unitText;
|
||||
}
|
||||
},
|
||||
|
||||
// Toggle full screen on/off
|
||||
fullScreenSwitcher: function() {
|
||||
var screenIcon;
|
||||
|
||||
screenIcon = top.document.getElementById('screenMode');
|
||||
|
||||
// Future use
|
||||
if ("undefined" != typeof document.cancelFullScreen) {
|
||||
document.fullScreen ? document.cancelFullScreen() : document.body.requestFullScreen();
|
||||
// Moz specific
|
||||
} else if ("undefined" != typeof document.mozCancelFullScreen) {
|
||||
document.mozFullScreen ? document.mozCancelFullScreen() : document.body.mozRequestFullScreen();
|
||||
// Chrome specific
|
||||
} else if ("undefined" != typeof document.webkitCancelFullScreen) {
|
||||
document.webkitIsFullScreen ? document.webkitCancelFullScreen() : document.body.webkitRequestFullScreen();
|
||||
}
|
||||
|
||||
screenIcon.src.indexOf("images/full-screen.gif") > -1 ? screenIcon.src = "images/restored-screen.gif" : screenIcon.src = "images/full-screen.gif";
|
||||
|
||||
},
|
||||
|
||||
// Pass target file/folder to Zip It!
|
||||
zipIt: function(tgt) {
|
||||
tgt=tgt.replace(top.fullPath+"/","").replace(/\//g,"|");
|
||||
top.ICEcoder.filesFrame.contentWindow.frames['fileControl'].location.href="plugins/zip-it/index.php?zip="+tgt;
|
||||
}
|
||||
};
|
||||
25
lib/config.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
$versionNo = "v 0.7.3";
|
||||
$codeMirrorDir = "CodeMirror-2.25";
|
||||
$cMThisVer = 2.25;
|
||||
$tabsIndent = true;
|
||||
$checkUpdates = false;
|
||||
$openLastFiles = true;
|
||||
$findFilesExclude = array("_coder",".doc",".gif",".jpg",".jpeg",".pdf",".png",".swf",".xml",".zip");
|
||||
$codeAssist = true;
|
||||
$visibleTabs = false;
|
||||
$lockedNav = true;
|
||||
$accountPassword = "";
|
||||
$restrictedFiles = array("wp-",".php",".rb",".sql");
|
||||
$bannedFiles = array("_coder","wp-",".exe");
|
||||
$allowedIPs = array("*");
|
||||
$plugins = array(
|
||||
array("Database Admin","images/database.png","margin-top: 3px","plugins/adminer/adminer-3.3.3-mysql-en.php","_blank",""),
|
||||
array("Batch Image Processor","images/images.png","margin-top: 5px","http://birme.net","_blank",""),
|
||||
array("Zip It!","images/zip-it.png","margin-top: 3px","plugins/zip-it/index.php?zip=|","fileControl:<b>Zipping Open Files</b>","10")
|
||||
);
|
||||
$theme = "default";
|
||||
$tabWidth = 4;
|
||||
$previousFiles = "";
|
||||
$last10Files = "";
|
||||
?>
|
||||
@@ -263,7 +263,7 @@ if (action=="save") {
|
||||
if ("undefined" != typeof newFileName) {
|
||||
top.ICEcoder.serverMessage('<b>Saving</b><br>'+newFileName);
|
||||
}
|
||||
document.saveFile.contents.innerHTML = top.document.getElementById('saveTemp1').value;
|
||||
document.saveFile.contents.value = top.document.getElementById('saveTemp1').value;
|
||||
document.saveFile.submit();
|
||||
} else {
|
||||
top.ICEcoder.serverMessage();top.ICEcoder.serverQueue("del",0);
|
||||
|
||||
@@ -9,56 +9,62 @@ dl, dt, dd, ol, ul, li,
|
||||
fieldset, form, label, legend,
|
||||
table, caption, tbody, tfoot, thead, tr, th, td {
|
||||
font-family: arial, verdana, helvetica, sans-serif;
|
||||
border: 0px;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
outline: 0px;
|
||||
border: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
outline: 0;
|
||||
font-size: 12px;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
body {margin: 0px; overflow: auto}
|
||||
body {margin: 0; overflow: auto}
|
||||
|
||||
.refresh {float: right; margin-right: 15px; cursor: pointer}
|
||||
|
||||
.fileManager {
|
||||
margin: 15px 0px 15px 22px;
|
||||
margin: 15px 0 15px 22px;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-o-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.fileManager span {font-family: helvetica, arial, swiss, verdana;}
|
||||
.fileManager a {color: #eee; text-decoration: none;}
|
||||
.fileManager .open {font-style: italic;}
|
||||
.fileManager .closed {font-style: normal;}
|
||||
.fileManager .pft-directory {list-style-image: url(../images/file-manager-icons/directory.png);}
|
||||
.fileManager li {margin-left: 15px;}
|
||||
.fileManager span {font-family: helvetica, arial, swiss, verdana}
|
||||
.fileManager a {color: #eee; text-decoration: none}
|
||||
.fileManager .open {font-style: italic}
|
||||
.fileManager .closed {font-style: normal}
|
||||
.fileManager .pft-directory, .fileManager .pft-file {list-style-image: url(../images/blank.gif)}
|
||||
.fileManager li {margin-left: 15px}
|
||||
|
||||
/* Default file */
|
||||
.fileManager LI.pft-file { list-style-image: url(../images/file-manager-icons/file.png); }
|
||||
.fileManager LI.pft-directory:before, .fileManager LI.pft-file:before {
|
||||
position: absolute; display: block; width: 16px; height: 16px; content: ""; margin-top: -2px; margin-left: -23px; background:url(../images/file-manager-icons.png) no-repeat 0 0;
|
||||
}
|
||||
@media screen and (-webkit-min-device-pixel-ratio:0) { /* hacked for chrome and safari */
|
||||
.fileManager LI.pft-directory:before, .fileManager LI.pft-file:before {
|
||||
margin-top: -19px;
|
||||
}
|
||||
}
|
||||
.fileManager LI.pft-file:before {background-position: -16px 0}
|
||||
|
||||
/* Additional file types */
|
||||
.fileManager LI.ext-coffee { list-style-image: url(../images/file-manager-icons/coffee.png); }
|
||||
.fileManager LI.ext-css { list-style-image: url(../images/file-manager-icons/css.png); }
|
||||
.fileManager LI.ext-doc { list-style-image: url(../images/file-manager-icons/doc.png); }
|
||||
.fileManager LI.ext-gif { list-style-image: url(../images/file-manager-icons/gif.png); }
|
||||
.fileManager LI.ext-htm { list-style-image: url(../images/file-manager-icons/html.png); }
|
||||
.fileManager LI.ext-html { list-style-image: url(../images/file-manager-icons/html.png); }
|
||||
.fileManager LI.ext-jpg { list-style-image: url(../images/file-manager-icons/jpg.png); }
|
||||
.fileManager LI.ext-jpeg { list-style-image: url(../images/file-manager-icons/jpg.png); }
|
||||
.fileManager LI.ext-js { list-style-image: url(../images/file-manager-icons/js.png); }
|
||||
/*.fileManager LI.ext-pdf { list-style-image: url(../images/file-manager-icons/pdf.png); } */
|
||||
.fileManager LI.ext-php { list-style-image: url(../images/file-manager-icons/php.png); }
|
||||
.fileManager LI.ext-png { list-style-image: url(../images/file-manager-icons/png.png); }
|
||||
.fileManager LI.ext-rb { list-style-image: url(../images/file-manager-icons/ruby.png); }
|
||||
.fileManager LI.ext-rbx { list-style-image: url(../images/file-manager-icons/ruby.png); }
|
||||
.fileManager LI.ext-rhtml { list-style-image: url(../images/file-manager-icons/ruby.png); }
|
||||
.fileManager LI.ext-ruby { list-style-image: url(../images/file-manager-icons/ruby.png); }
|
||||
/*.fileManager LI.ext-sql { list-style-image: url(../images/file-manager-icons/sql.png); } */
|
||||
/*.fileManager LI.ext-swf { list-style-image: url(../images/file-manager-icons/swf.png); } */
|
||||
.fileManager LI.ext-txt { list-style-image: url(../images/file-manager-icons/txt.png); }
|
||||
/*.fileManager LI.ext-xls { list-style-image: url(../images/file-manager-icons/xls.png); } */
|
||||
/*.fileManager LI.ext-xml { list-style-image: url(../images/file-manager-icons/xml.png); } */
|
||||
/*.fileManager LI.ext-zip { list-style-image: url(../images/file-manager-icons/zip.png); } */
|
||||
.fileManager LI.ext-coffee:before {background-position: -32px 0}
|
||||
.fileManager LI.ext-css:before {background-position: -48px 0}
|
||||
.fileManager LI.ext-gif:before {background-position: -64px 0}
|
||||
.fileManager LI.ext-htm:before {background-position: -80px 0}
|
||||
.fileManager LI.ext-html:before {background-position: -80px 0}
|
||||
.fileManager LI.ext-jpg:before {background-position: -96px 0}
|
||||
.fileManager LI.ext-jpeg:before {background-position: -96px 0}
|
||||
.fileManager LI.ext-js:before {background-position: -112px 0}
|
||||
/*.fileManager LI.ext-pdf:before {background-position: -???px 0} */
|
||||
.fileManager LI.ext-php:before {background-position: -128px 0}
|
||||
.fileManager LI.ext-png:before {background-position: -144px 0}
|
||||
.fileManager LI.ext-rb:before {background-position: -160px 0}
|
||||
.fileManager LI.ext-rbx:before {background-position: -160px 0}
|
||||
.fileManager LI.ext-rhtml:before {background-position: -160px 0}
|
||||
.fileManager LI.ext-ruby:before {background-position: -160px 0}
|
||||
/*.fileManager LI.ext-sql:before {background-position: -???px 0} */
|
||||
/*.fileManager LI.ext-swf:before {background-position: -???px 0} */
|
||||
.fileManager LI.ext-txt:before {background-position: -176px 0}
|
||||
/*.fileManager LI.ext-xml:before {background-position: -???px 0} */
|
||||
.fileManager LI.ext-zip:before {background-position: -192px 0}
|
||||
@@ -8,10 +8,10 @@ b, u, i, center,
|
||||
dl, dt, dd, ol, ul, li,
|
||||
fieldset, form, label, legend,
|
||||
table, caption, tbody, tfoot, thead, tr, th, td {
|
||||
border: 0px;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
outline: 0px;
|
||||
border: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
outline: 0;
|
||||
font-size: 12px;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
@@ -8,10 +8,10 @@ b, u, i, center,
|
||||
dl, dt, dd, ol, ul, li,
|
||||
fieldset, form, label, legend,
|
||||
table, caption, tbody, tfoot, thead, tr, th, td {
|
||||
border: 0px;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
outline: 0px;
|
||||
border: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
outline: 0;
|
||||
font-size: 12px;
|
||||
vertical-align: top;
|
||||
}
|
||||
@@ -32,4 +32,4 @@ hr {border: 0; height: 1px; background-color: #888}
|
||||
.results .resultsPane a {color: rgba(0,198,255,0.7); text-decoration: none}
|
||||
.results .resultsPane a:hover {text-decoration: underline}
|
||||
.replace {position: absolute; margin-top: -28px; right: 20px; padding: 5px 10px; font-size: 14px; background-color: rgba(0,198,255,0.7); cursor: pointer}
|
||||
.replaceAll {position: absolute; bottom: 0px; right: 20px; padding: 5px 10px; font-size: 18px; background-color: rgba(0,198,255,0.7); cursor: pointer}
|
||||
.replaceAll {position: absolute; bottom: 0; right: 20px; padding: 5px 10px; font-size: 18px; background-color: rgba(0,198,255,0.7); cursor: pointer}
|
||||
@@ -8,10 +8,10 @@ b, u, i, center,
|
||||
dl, dt, dd, ol, ul, li,
|
||||
fieldset, form, label, legend,
|
||||
table, caption, tbody, tfoot, thead, tr, th, td {
|
||||
border: 0px;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
outline: 0px;
|
||||
border: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
outline: 0;
|
||||
font-size: 12px;
|
||||
vertical-align: top;
|
||||
}
|
||||
@@ -33,13 +33,13 @@ h2 {font-size: 18px; font-weight: normal; color: #fff}
|
||||
.settings .logo {position: relative; margin-top: 2px}
|
||||
.settings .version {position: relative; display: block; margin-top: 5px; margin-bottom: 10px; font-size: 10px; color: #bbb}
|
||||
.settings .settingsColumn1 {width: 220px; height: 560px; padding: 20px; float: left}
|
||||
.settings .settingsColumn2 {width: 420px; height: 560px; padding: 20px 20px 20px 0px; float: left}
|
||||
.settings .settingsColumn2 {width: 420px; height: 560px; padding: 20px 20px 20px 0; float: left}
|
||||
.settings input, .settings textarea {border: 1px solid #555; background-color: #444; color: #fff}
|
||||
.settings input:focus, .settings textarea:focus {
|
||||
outline: none;
|
||||
-webkit-box-shadow: 0px 0px 10px 1px rgba(0,198,255,0.7);
|
||||
-moz-box-shadow: 0px 0px 10px 1px rgba(0,198,255,0.7);
|
||||
box-shadow: 0px 0px 10px 1px rgba(0,198,255,0.7);
|
||||
-webkit-box-shadow: 0 0 10px 1px rgba(0,198,255,0.7);
|
||||
-moz-box-shadow: 0 0 10px 1px rgba(0,198,255,0.7);
|
||||
box-shadow: 0 0 10px 1px rgba(0,198,255,0.7);
|
||||
}
|
||||
.settings .plugins {font-family: arial, verdana, helvetica, sans-serif; width: 410px; height: 123px; overflow: hidden}
|
||||
.settings .update {position: absolute; bottom: 0px; right: 20px; padding: 5px 10px; font-size: 18px; background-color: rgba(0,198,255,0.7); opacity: 0.1; cursor: pointer}
|
||||
.settings .update {position: absolute; bottom: 0; right: 20px; padding: 5px 10px; font-size: 18px; background-color: rgba(0,198,255,0.7); opacity: 0.1; cursor: pointer}
|
||||
@@ -12,20 +12,20 @@
|
||||
<script src="../<?php echo $codeMirrorDir; ?>/mode/javascript/javascript.js"></script>
|
||||
|
||||
<style type="text/css">
|
||||
.CodeMirror {position: absolute; width: 0px; background-color: #fff; font-family: monospace}
|
||||
.CodeMirror {position: absolute; width: 0; background-color: #fff; font-family: monospace}
|
||||
.CodeMirror-scroll {height: 220px; width: 420px; overflow: hidden}
|
||||
.cm-s-visible {display: block; top: 0px}
|
||||
.cm-s-visible {display: block; top: 0}
|
||||
.cm-s-hidden {display: none; top: 4000px}
|
||||
.cm-s-activeLine {background: #002 !important;}
|
||||
// Make sure this next one remains the 5th item, updated with JS
|
||||
.cm-tab:after {position: relative; display: inline-block; width: 0px; left: -1.4em; overflow: visible; color: #aaa; content: "<?php if($visibleTabs) {echo '\21e5';};?>";}
|
||||
.cm-tab:after {position: relative; display: inline-block; width: 0; left: -1.4em; overflow: visible; color: #aaa; content: "<?php if($visibleTabs) {echo '\21e5';};?>";}
|
||||
span.CodeMirror-matchhighlight {background: #555}
|
||||
.CodeMirror-focused span.CodeMirror-matchhighlight {color: #000; background: #555; !important}
|
||||
</style>
|
||||
|
||||
<link rel="stylesheet" href="editor.css">
|
||||
<?php
|
||||
$themeArray = array("ambiance","blackboard","cobalt","eclipse","elegant","lesser-dark","monokai","neat","night","rubyblue","xq-dark");
|
||||
$themeArray = array("ambiance","blackboard","cobalt","eclipse","elegant","erlang-dark","lesser-dark","monokai","neat","night","rubyblue","xq-dark");
|
||||
for ($i=0;$i<count($themeArray)-1;$i++) {
|
||||
echo '<link rel="stylesheet" href="../'.$codeMirrorDir.'/theme/'.$themeArray[$i].'.css">'.PHP_EOL;
|
||||
}
|
||||
@@ -79,9 +79,12 @@ for ($i=0;$i<count($themeArray)-1;$i++) {
|
||||
<h1>settings</h1>
|
||||
<h2>functionality</h2>
|
||||
<input type="checkbox" onclick="showButton()" name="tabsIndent" value="true"<?php if($tabsIndent) {echo ' checked';};?>> tab indents selection<br>
|
||||
<input type="checkbox" onclick="showButton()" name="testcMVersion" value="true"<?php if($testcMVersion) {echo ' checked';};?>> test codemirror version on load<br>
|
||||
<input type="checkbox" onclick="showButton()" name="checkUpdates" value="true"<?php if($checkUpdates) {echo ' checked';};?>> check for updates on load<br>
|
||||
<input type="checkbox" onclick="showButton()" name="openLastFiles" value="true"<?php if($openLastFiles) {echo ' checked';};?>> auto open last files on login<br>
|
||||
<br>
|
||||
when finding in files, exclude:<br>
|
||||
<input type="text" onkeydown="showButton()" name="findFilesExclude" value="<?php for($i=0;$i<=count($findFilesExclude)-1;$i++) {echo $findFilesExclude[$i]; if ($i<count($findFilesExclude)-1) {echo ', ';};}; ?>"><br>
|
||||
<br>
|
||||
|
||||
<h2>assisting</h2>
|
||||
<input type="checkbox" onclick="showButton()" name="codeAssist" value="true"<?php if($codeAssist) {echo ' checked';};?>> code assist<br>
|
||||
@@ -153,11 +156,19 @@ function findSequence(goal) {
|
||||
}
|
||||
return find(1,"1");
|
||||
}</textarea>
|
||||
<br>
|
||||
|
||||
<span style="position: absolute; top: 520px">
|
||||
tab width <span style="font-size: 10px; color: #888">chars</span><br>
|
||||
<input type="text" name="tabWidth" id="tabWidth" style="width: 30px" onkeydown="showButton()" onkeyup="changeTabWidth()" value="<?php echo $tabWidth;?>">
|
||||
</span>
|
||||
|
||||
<script>
|
||||
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
|
||||
lineNumbers: true,
|
||||
readOnly: "nocursor",
|
||||
indentUnit: top.tabWidth,
|
||||
tabSize: top.tabWidth,
|
||||
theme: "<?php if ($theme=="default") {echo 'icecoder';} else {echo $theme;}; ?>"
|
||||
});
|
||||
|
||||
@@ -168,6 +179,12 @@ function selectTheme() {
|
||||
editor.setOption("theme", theme);
|
||||
}
|
||||
|
||||
function changeTabWidth() {
|
||||
var tabWidth = document.getElementById("tabWidth").value;
|
||||
editor.setOption("indentUnit", tabWidth);
|
||||
editor.setOption("tabSize", tabWidth);
|
||||
}
|
||||
|
||||
var showButton = function() {
|
||||
document.getElementById('updateButton').style.opacity = 1;
|
||||
}
|
||||
|
||||
107
lib/settings.php
@@ -12,48 +12,22 @@ function generateHash($plainText,$salt=null) {
|
||||
return $salt.sha1($salt.$plainText);
|
||||
}
|
||||
|
||||
// -----------------
|
||||
// Start of settings
|
||||
// -----------------
|
||||
// Settings are stored in this file
|
||||
include("config.php");
|
||||
|
||||
$versionNo = "v 0.6.8";
|
||||
$codeMirrorDir = "CodeMirror-2.25";
|
||||
$cMThisVer = 2.25;
|
||||
$tabsIndent = true;
|
||||
$testcMVersion = false;
|
||||
$openLastFiles = true;
|
||||
$codeAssist = true;
|
||||
$visibleTabs = false;
|
||||
$lockedNav = true;
|
||||
$accountPassword = "";
|
||||
$restrictedFiles = array("wp-",".php",".rb",".sql");
|
||||
$bannedFiles = array("_coder","wp-",".exe");
|
||||
$allowedIPs = array("*");
|
||||
$plugins = array(
|
||||
array("Database Admin","images/database.png","margin-top: 3px","plugins/adminer/adminer-3.3.3-mysql-en.php","_blank",""),
|
||||
array("Batch Image Processor","images/images.png","margin-top: 5px","http://birme.net","_blank",""),
|
||||
array("Backup","images/backup-open-files.png","margin-top: 3px","plugins/backupOpenFiles/index.php","fileControl:<b>Zipping Open Files</b>","10")
|
||||
);
|
||||
$theme = "default";
|
||||
$lastOpenedFiles = "";
|
||||
|
||||
// ---------------
|
||||
// End of settings
|
||||
// ---------------
|
||||
|
||||
|
||||
// Update this settings file?
|
||||
// Update this config file?
|
||||
if (isset($_POST["theme"]) && $_POST["theme"] && $_SESSION['userLevel'] == 10) {
|
||||
$settingsFile = 'settings.php';
|
||||
$settingsFile = 'config.php';
|
||||
$settingsContents = file_get_contents($settingsFile);
|
||||
// Replace our lastOpenedFiles var with the the current
|
||||
// Replace our settings vars
|
||||
$repPosStart = strpos($settingsContents,'$tabsIndent');
|
||||
$repPosEnd = strpos($settingsContents,'$lastOpenedFiles');
|
||||
$repPosEnd = strpos($settingsContents,'$previousFiles');
|
||||
|
||||
// Prepare all our vars
|
||||
if ($_POST['tabsIndent']) {$tabsIndent = "true";} else {$tabsIndent = "false";};
|
||||
if ($_POST['testcMVersion']) {$testcMVersion = "true";} else {$testcMVersion = "false";};
|
||||
if ($_POST['checkUpdates']) {$checkUpdates = "true";} else {$checkUpdates = "false";};
|
||||
if ($_POST['openLastFiles']) {$openLastFiles = "true";} else {$openLastFiles = "false";};
|
||||
$findFilesExclude = 'array("'.str_replace(', ','","',$_POST['findFilesExclude']).'")';
|
||||
if ($_POST['codeAssist']) {$codeAssist = "true";} else {$codeAssist = "false";};
|
||||
if ($_POST['visibleTabs']) {$visibleTabs = "true";} else {$visibleTabs = "false";};
|
||||
if ($_POST['lockedNav']) {$lockedNav = "true";} else {$lockedNav = "false";};
|
||||
@@ -63,10 +37,12 @@ if (isset($_POST["theme"]) && $_POST["theme"] && $_SESSION['userLevel'] == 10) {
|
||||
$allowedIPs = 'array("'.str_replace(', ','","',$_POST['allowedIPs']).'")';
|
||||
$plugins = 'array('.PHP_EOL.' array('.PHP_EOL.' '.str_replace('====================','),'.PHP_EOL.' array(',$_POST['plugins']).'))';
|
||||
$theme = $_POST['theme'];
|
||||
$tabWidth = $_POST['tabWidth']*1;
|
||||
|
||||
$settingsNew = '$tabsIndent = '.$tabsIndent.';'.PHP_EOL;
|
||||
$settingsNew .= '$testcMVersion = '.$testcMVersion.';'.PHP_EOL;
|
||||
$settingsNew .= '$checkUpdates = '.$checkUpdates.';'.PHP_EOL;
|
||||
$settingsNew .= '$openLastFiles = '.$openLastFiles.';'.PHP_EOL;
|
||||
$settingsNew .= '$findFilesExclude = '.$findFilesExclude.';'.PHP_EOL;
|
||||
$settingsNew .= '$codeAssist = '.$codeAssist.';'.PHP_EOL;
|
||||
$settingsNew .= '$visibleTabs = '.$visibleTabs.';'.PHP_EOL;
|
||||
$settingsNew .= '$lockedNav = '.$lockedNav.';'.PHP_EOL;
|
||||
@@ -76,15 +52,17 @@ if (isset($_POST["theme"]) && $_POST["theme"] && $_SESSION['userLevel'] == 10) {
|
||||
$settingsNew .= '$allowedIPs = '.$allowedIPs.';'.PHP_EOL;
|
||||
$settingsNew .= '$plugins = '.$plugins.';'.PHP_EOL;
|
||||
$settingsNew .= '$theme = "'.$theme.'";'.PHP_EOL;
|
||||
$settingsNew .= '$tabWidth = '.$tabWidth.';'.PHP_EOL;
|
||||
|
||||
// Compile our new settings
|
||||
$settingsContents = substr($settingsContents,0,$repPosStart).$settingsNew.substr($settingsContents,($repPosEnd),strlen($settingsContents));
|
||||
// Now update this file
|
||||
$fh = fopen($settingsFile, 'w') or die("can't update settings file");
|
||||
// Now update the config file
|
||||
$fh = fopen($settingsFile, 'w') or die("Can't update config file. Please set public write permissions on lib/config.php");
|
||||
fwrite($fh, $settingsContents);
|
||||
fclose($fh);
|
||||
|
||||
// OK, now this file is updated, update our current session with new arrays
|
||||
// OK, now the config file has been updated, update our current session with new arrays
|
||||
$_SESSION['findFilesExclude'] = $findFilesExclude = explode(", ",$_POST['findFilesExclude']);
|
||||
$_SESSION['restrictedFiles'] = $restrictedFiles = explode(", ",$_POST['restrictedFiles']);
|
||||
$_SESSION['bannedFiles'] = $bannedFiles = explode(", ",$_POST['bannedFiles']);
|
||||
$_SESSION['allowedIPs'] = $allowedIPs = explode(", ",$_POST['allowedIPs']);
|
||||
@@ -93,21 +71,40 @@ if (isset($_POST["theme"]) && $_POST["theme"] && $_SESSION['userLevel'] == 10) {
|
||||
// Do we need a file manager refresh?
|
||||
if ($_POST['changedFileSettings']=="true") {$refreshFM="true";} else {$refreshFM="false";};
|
||||
// With all that worked out, we can now hide the settings screen and apply the new settings
|
||||
echo "<script>top.ICEcoder.settingsScreen('hide');top.ICEcoder.useNewSettings('".$themeURL."',".$tabsIndent.",".$codeAssist.",".$lockedNav.",".$visibleTabs.",".$refreshFM.");</script>";
|
||||
echo "<script>top.ICEcoder.settingsScreen('hide');top.ICEcoder.useNewSettings('".$themeURL."',".$tabsIndent.",".$codeAssist.",".$lockedNav.",".$visibleTabs.",".$tabWidth.",".$refreshFM.");</script>";
|
||||
}
|
||||
|
||||
// Save the currently opened files for next time
|
||||
if (isset($_GET["saveFiles"]) && $_GET['saveFiles']) {
|
||||
if ($_SESSION['userLevel'] == 10) {
|
||||
$settingsFile = 'settings.php';
|
||||
$settingsFile = 'config.php';
|
||||
$settingsContents = file_get_contents($settingsFile);
|
||||
// Replace our lastOpenedFiles var with the the current
|
||||
$repPosStart = strpos($settingsContents,'lastOpenedFiles = "')+19;
|
||||
|
||||
// Replace our previousFiles var with the the current
|
||||
$repPosStart = strpos($settingsContents,'previousFiles = "')+18;
|
||||
$repPosEnd = strpos($settingsContents,'";',$repPosStart)-$repPosStart;
|
||||
$settingsContents = substr($settingsContents,0,$repPosStart).$_GET['saveFiles'].substr($settingsContents,($repPosStart+$repPosEnd),strlen($settingsContents));
|
||||
// Now update this file
|
||||
$fh = fopen($settingsFile, 'w') or die("can't update settings file");
|
||||
fwrite($fh, $settingsContents);
|
||||
if ($_GET['saveFiles']!="CLEAR") {$saveFiles=$_GET['saveFiles'];} else {$saveFiles="";};
|
||||
$settingsContents1 = substr($settingsContents,0,$repPosStart).$saveFiles.substr($settingsContents,($repPosStart+$repPosEnd),strlen($settingsContents));
|
||||
// Now update the config file
|
||||
$fh = fopen($settingsFile, 'w') or die("Can't update config file. Please set public write permissions on lib/config.php");
|
||||
fwrite($fh, $settingsContents1);
|
||||
|
||||
// Update our top10Files var?
|
||||
$saveFilesArray = explode(",",$saveFiles);
|
||||
$last10FilesArray = explode(",",$last10Files);
|
||||
for ($i=0;$i<count($saveFilesArray);$i++) {
|
||||
$inLast10Files = in_array($saveFilesArray[$i],$last10FilesArray);
|
||||
if (!$inLast10Files && $saveFilesArray[$i] !="") {
|
||||
$repPosStart = strpos($settingsContents1,'last10Files = "')+16;
|
||||
$repPosEnd = strpos($settingsContents1,'";',$repPosStart)-$repPosStart;
|
||||
if ($last10Files!="") {$commaExtra=",";} else {$commaExtra="";};
|
||||
if (count($last10FilesArray)>=10) {$last10Files=substr($last10Files,0,strrpos($last10Files,','));};
|
||||
$settingsContents2 = substr($settingsContents1,0,$repPosStart).$saveFilesArray[$i].$commaExtra.$last10Files.substr($settingsContents1,($repPosStart+$repPosEnd),strlen($settingsContents1));
|
||||
// Now update the config file
|
||||
$fh = fopen($settingsFile, 'w') or die("Can't update config file. Please set public write permissions on lib/config.php");
|
||||
fwrite($fh, $settingsContents2);
|
||||
}
|
||||
}
|
||||
fclose($fh);
|
||||
}
|
||||
echo '<script>top.ICEcoder.serverMessage();top.ICEcoder.serverQueue("del",0);</script>';
|
||||
@@ -118,6 +115,7 @@ if (!isset($_SESSION['userLevel'])) {$_SESSION['userLevel'] = 0;};
|
||||
if(isset($_POST['loginPassword']) && generateHash($_POST['loginPassword'],$accountPassword)==$accountPassword) {$_SESSION['userLevel'] = 10;};
|
||||
$_SESSION['userLevel'] = $_SESSION['userLevel'];
|
||||
|
||||
if (!isset($_SESSION['findFilesExclude'])) {$_SESSION['findFilesExclude'] = $findFilesExclude;}
|
||||
if (!isset($_SESSION['restrictedFiles'])) {$_SESSION['restrictedFiles'] = $restrictedFiles;}
|
||||
if (!isset($_SESSION['bannedFiles'])) {$_SESSION['bannedFiles'] = $bannedFiles;}
|
||||
if (!isset($_SESSION['allowedIPs'])) {$_SESSION['allowedIPs'] = $allowedIPs;}
|
||||
@@ -158,7 +156,7 @@ if ((isset($_POST["theme"]) && $_POST["theme"] && $_SESSION['userLevel'] == 10)
|
||||
$pluginsDisplay = "";
|
||||
for ($i=0;$i<count($plugins);$i++) {
|
||||
$target = explode(":",$plugins[$i][4]);
|
||||
$pluginsDisplay .= '<a href="'.$plugins[$i][3].'" target="'.$target[0].'"><img src="'.$plugins[$i][1].'" style="'.$plugins[$i][2].'" alt="'.$plugins[$i][0].'"></a>';
|
||||
$pluginsDisplay .= '<a href="'.$plugins[$i][3].'" title="'.$plugins[$i][0].'" target="'.$target[0].'"><img src="'.$plugins[$i][1].'" style="'.$plugins[$i][2].'" alt="'.$plugins[$i][0].'"></a>';
|
||||
};
|
||||
|
||||
// If we're updating, replace the plugin display with our newly established one
|
||||
@@ -191,6 +189,11 @@ if ((isset($_POST["theme"]) && $_POST["theme"] && $_SESSION['userLevel'] == 10)
|
||||
if ($openLastFiles) {
|
||||
$onLoadExtras .= ";top.ICEcoder.autoOpenFiles()";
|
||||
}
|
||||
|
||||
// Show server data if we're logged in
|
||||
if ($_SESSION['userLevel'] == 10) {
|
||||
$onLoadExtras .= ";top.ICEcoder.content.style.visibility='visible'";
|
||||
}
|
||||
}
|
||||
|
||||
// If we're due to show the settings screen
|
||||
@@ -204,12 +207,12 @@ if ($accountPassword == "" && isset($_GET['settings'])) {
|
||||
<link rel="stylesheet" type="text/css" href="coder.css">
|
||||
</head>
|
||||
|
||||
<body style="background-color: #fff">
|
||||
<body>
|
||||
|
||||
<div class="screenContainer">
|
||||
<div class="screenVCenter">
|
||||
<div class="screenCenter">
|
||||
<img src="../images/ice-coder.gif">
|
||||
<img src="../images/ice-coder.png">
|
||||
<div class="version"><?php echo $versionNo;?></div>
|
||||
<form name="settingsUpdate" action="../index.php" method="POST">
|
||||
<input type="password" name="accountPassword" class="accountPassword">
|
||||
@@ -230,12 +233,12 @@ if ($accountPassword == "" && isset($_GET['settings'])) {
|
||||
// If we're setting a password
|
||||
if (isset($_POST['accountPassword'])) {
|
||||
$password = generateHash($_POST['accountPassword']);
|
||||
$settingsFile = 'lib/settings.php';
|
||||
$settingsFile = 'lib/config.php';
|
||||
$settingsContents = file_get_contents($settingsFile);
|
||||
// Replace our empty password with the one submitted by user
|
||||
$settingsContents = str_replace('$accountPassword = "";','$accountPassword = "'.$password.'";',$settingsContents);
|
||||
// Now update this file
|
||||
$fh = fopen($settingsFile, 'w') or die("can't update settings file");
|
||||
// Now update the config file
|
||||
$fh = fopen($settingsFile, 'w') or die("Can't update config file. Please set public write permissions on lib/config.php");
|
||||
fwrite($fh, $settingsContents);
|
||||
fclose($fh);
|
||||
// Set the session user level
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<body>
|
||||
<script>
|
||||
top.ICEcoder.serverMessage("<b>Zipping Open Files</b>");
|
||||
</script>
|
||||
<?php
|
||||
// ------------------------------------
|
||||
// backupOpenFiles by Matt Pass
|
||||
// Will backups open files in ICE coder
|
||||
// ------------------------------------
|
||||
|
||||
// If we have no post data for the 1st item, set a form up ready to post back
|
||||
if (!isset($_POST['fileName1'])) {
|
||||
echo '<form name="zipFiles" id="zipFiles" action="index.php" method="POST">'.PHP_EOL;
|
||||
for ($i=1;$i<=10;$i++) {
|
||||
echo '<input type="hidden" name="fileName'.$i.'" id="fName'.$i.'" value="" style="display: none">'.PHP_EOL;
|
||||
echo '<textarea name="fileContent'.$i.'" id="fContent'.$i.'" style="display: none"></textarea>'.PHP_EOL;
|
||||
}
|
||||
echo '</form>'.PHP_EOL;
|
||||
?>
|
||||
<script>
|
||||
// Populate values for file names & contents
|
||||
for (i=1;i<=top.ICEcoder.openFiles.length;i++) {
|
||||
document.getElementById('fName'+i).value = top.ICEcoder.openFiles[i-1];
|
||||
document.getElementById('fContent'+i).value = top.ICEcoder.content.contentWindow['cM'+i].getValue();
|
||||
}
|
||||
if (top.ICEcoder.openFiles.length>0) {
|
||||
document.zipFiles.submit();
|
||||
}
|
||||
</script>
|
||||
<?php
|
||||
;} else {
|
||||
// Folder name & filename of the zip
|
||||
$zipItSaveLocation = '../../backups/';
|
||||
$zipItFileName = time().'.zip';
|
||||
|
||||
// Make the dir if it doesn't exist
|
||||
if (!is_dir($zipItSaveLocation)) {
|
||||
mkdir($zipItSaveLocation, 0777);
|
||||
}
|
||||
|
||||
// Start a class
|
||||
Class zipIt {
|
||||
public function zipFilesUp($zipName='') {
|
||||
// OK, if we've got at least one file to add
|
||||
if($_POST['fileName1']!=="") {
|
||||
$zip = new ZipArchive();
|
||||
// Return if we have a problem creating/overwriting our zip
|
||||
if($zip->open($zipName,$overwriteZip ? ZIPARCHIVE::OVERWRITE : ZIPARCHIVE::CREATE) !== true) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Otherwise, we're OK to add our string into a new file (incl dirs) in the zip, so do that
|
||||
for($i=1;$i<=10;$i++) {
|
||||
$fName = 'fileName'.$i;
|
||||
if($_POST[$fName]!=="") {
|
||||
$zip->addFromString(ltrim($_POST[$fName],"/"), $_POST['fileContent'.$i]);
|
||||
}
|
||||
}
|
||||
|
||||
$zip->close();
|
||||
|
||||
// We've been successful, so return with a positive response
|
||||
return file_exists($zipName);
|
||||
|
||||
} else {
|
||||
// If we had 0 files, return
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Trigger the class
|
||||
$zipItDoZip = new zipIt();
|
||||
$zipItAddToZip = $zipItDoZip->zipFilesUp($zipItSaveLocation.$zipItFileName);
|
||||
if (!$zipItAddToZip) {echo '<script>alert("Could not zip files up!");</script>';};
|
||||
;};
|
||||
?>
|
||||
|
||||
<script>
|
||||
top.ICEcoder.serverMessage();
|
||||
top.ICEcoder.serverQueue("del",0);
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
71
plugins/zip-it/index.php
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
// -----------------------------------------------
|
||||
// Zip-It! for ICEcoder v0.9.0 by Matt Pass
|
||||
// Will backup requested files/folders in ICEcoder
|
||||
// -----------------------------------------------
|
||||
include("../../lib/settings.php");
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>Zip It! for ICEcoder</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<?
|
||||
$zipItSaveLocation = '../../backups/';
|
||||
if ($_GET['zip']=="|") {$zipItFileName = "root";} else {$zipItFileName = str_replace("|","_",$_GET['zip']);};
|
||||
$zipItFileName .= '-'.time().'.zip';
|
||||
|
||||
if (!is_dir($zipItSaveLocation)) {mkdir($zipItSaveLocation, 0777);}
|
||||
|
||||
Class zipIt {
|
||||
public function zipFilesUp($zipName='') {
|
||||
$zipFiles = array();
|
||||
$zipTgt = str_replace("|","/",$_GET['zip']);
|
||||
if (strpos($_GET['zip'],"/")!==0) {$zipTgt = "/".$zipTgt;};
|
||||
$addItem = $_SERVER['DOCUMENT_ROOT'].$zipTgt;
|
||||
if (is_dir($addItem)) {
|
||||
$dirStack = array($addItem);
|
||||
while (!empty($dirStack)) {
|
||||
$currentDir = array_pop($dirStack);
|
||||
$dir = dir($currentDir);
|
||||
while (false !== ($node = $dir->read())) {
|
||||
if (($node == '.') || ($node == '..')) {continue;}
|
||||
if (is_dir($currentDir.$node) && !strpos($currentDir.$node,"_coder")) {
|
||||
array_push($dirStack,$currentDir.$node.'/');
|
||||
}
|
||||
if (is_file($currentDir.$node)) {$zipFiles[] = $currentDir.$node;}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(file_exists($addItem)) {$zipFiles[] = $addItem;}
|
||||
}
|
||||
if(count($zipFiles)) {
|
||||
$zip = new ZipArchive();
|
||||
if($zip->open($zipName,ZIPARCHIVE::CREATE)!== true) {return false;}
|
||||
foreach($zipFiles as $file) {
|
||||
$zip->addFile($file,str_replace($_SERVER['DOCUMENT_ROOT']."/","",$file));
|
||||
}
|
||||
$zip->close();
|
||||
return file_exists($zipName);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if($_SESSION['userLevel']==10) {
|
||||
$zipItDoZip = new zipIt();
|
||||
echo '<script>top.ICEcoder.serverMessage("<b>Zipping Files</b>");</script>';
|
||||
$zipItAddToZip = $zipItDoZip->zipFilesUp($zipItSaveLocation.$zipItFileName);
|
||||
if (!$zipItAddToZip) {
|
||||
echo '<script>alert("Could not zip files up!");</script>';
|
||||
} else {
|
||||
echo '<script>setTimeout(function(){top.ICEcoder.serverMessage();top.ICEcoder.serverQueue("del",0);},500);</script>';
|
||||
}
|
||||
}
|
||||
?>
|
||||
</body>
|
||||
|
||||
</html>
|
||||