Files
ICEcoder/lib/coder.js
Matt Pass 7eef976619 Shift key, Save As and loading mask
shiftKeyDown now detected
Loading mask hidden on load
Setting ctrlKeyDown to false on all functions to avoid stickiness
Same for shiftKeyDown
Save As functionality added
Window no longer opens on CTRL+Enter if it's a new file
2012-02-23 18:14:01 +00:00

953 lines
35 KiB
JavaScript

// 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: 15, // Initial width of the files pane
minFilesW: 15, // Min width of the files pane
maxFilesW: 250, // Max width of the files pane
selectedTab: 0, // The tab that's currently selected
changedContent: [], // Binary array to indicate which tabs have changed
ctrlKeyDown: false, // Indicates if CTRL keydown
shiftKeyDown: false, // Indicates if Shift keydown
delKeyDown: false, // Indicates if DEL keydown
canSwitchTabs: true, // Stops switching of tabs when trying to close
openFiles: [], // Array of open file URLs
cMInstances: [], // List of CodeMirror instance no's
nextcMInstance: 1, // Next available CodeMirror instance no
selectedFiles: [], // Array of selected files
findMode: false, // States if we're in find/replace mode
lockedNav: false, // Nav is locked or not
// Don't consider these tags as part of nesting as they're singles, JS or PHP code blocks
tagNestExceptions: ["!DOCTYPE","meta","link","img","br","hr","input","script","?"],
// On load, set aliases, set the layout and get the nest location
init: function() {
var aliasArray = ["header","files","account","filesFrame","editor","tabsBar","findBar","content","footer","nestValid","nestDisplay","charDisplay"];
ICEcoder.tD = top.document;
// Create our ID aliases
for (var i=0;i<aliasArray.length;i++) {
ICEcoder[aliasArray[i]] = ICEcoder.tD.getElementById(aliasArray[i]);
}
// Set layout & the nest location
ICEcoder.setLayout();
// Hide the loading screen
top.document.getElementById('loadingMask').style.visibility = "hidden";
},
// Set out our layout according to the browser size
setLayout: function() {
var winW, winH, headerH, footerH, accountH, uploadH, tabsBarH, findBarH, cMCSS;
// Determin width & height available
if (window.innerWidth) {
var winW = window.innerWidth;
var winH = window.innerHeight;
} else {
var winW = document.body.clientWidth;
var winH = document.body.clientHeight;
}
// Apply sizes to various elements of the page
headerH = 40, footerH = 30, accountH = 50, uploadH = 40, tabsBarH = 21, findBarH = 28;
header.style.width = tabsBar.style.width = findBar.style.width = winW + "px";
files.style.width = editor.style.left = this.filesW + "px";
account.style.height = accountH + "px";
filesFrame.style.height = (winH-headerH-accountH-footerH-uploadH) + "px";
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
document.all ? strCSS = 'rules' : strCSS = 'cssRules';
cMCSS = ICEcoder.content.contentWindow.document;
cMCSS.styleSheets[2][strCSS][1].style['width'] = ICEcoder.content.style.width;
cMCSS.styleSheets[2][strCSS][1].style['height'] = ICEcoder.content.style.height;
cMCSS.styleSheets[2][strCSS][2].style['width'] = ICEcoder.content.style.width;
},
// Clean up our loaded code
contentCleanUp: function() {
var fileName;
fileName = ICEcoder.openFiles[ICEcoder.selectedTab-1];
if (fileName.indexOf(".js")<0&&fileName.indexOf(".css")<0) {
var cM, content;
cM = ICEcoder.getcMInstance();
content = cM.getValue();
content = content.replace(' & ',' &amp; ');
content = content.replace('<ICEcoder:/:textarea>','</textarea>');
// Then set the content in the editor & clear the history
cM.setValue(content);
cM.clearHistory();
}
},
// Work out the nesting depth location on demand and update our display if required
getNestLocation: function(updateNestDisplay) {
var cM, openTag, nestCheck, startPos, tagStart, canDoTheEndTag, tagEnd, tagEndJS, fileName;
cM = ICEcoder.getcMInstance();
nestCheck = cM.getValue();
// Set up array to store nest data, a var to establish if a tag is open and another to establish if we're in a code block
ICEcoder.htmlTagArray = [], openTag = false, ICEcoder.codeBlock = false;
// For every character from the start to our caret position
for(var i=0;i<=ICEcoder.caretPos;i++) {
// If we find a < tag and we're not within a tag, change the open tag state & set our start position
if(nestCheck.charAt(i)=="<" && openTag==false) {
openTag=true;
startPos=i+1;
// Get the tag name and if it's the start of a code block, set the var for that
tagStart=nestCheck.substr(startPos,nestCheck.length).split(" ")[0].split(">")[0].split("\n")[0];
if (tagStart=="script"||tagStart=="?") {ICEcoder.codeBlock=true}
if (tagStart!="") {ICEcoder.tagStart = tagStart}
};
// If we find a > tag and we're within a tag or codeblock
if(nestCheck.charAt(i)==">" && (openTag||ICEcoder.codeBlock)) {
// Get the tag name
tagString=nestCheck.substr(0,i);
tagString=tagString.substr(tagString.lastIndexOf('<')+1,tagString.length);
tagString=tagString.split(" ")[0];
ICEcoder.tagString = tagString;
canDoTheEndTag=true;
// Check it's not on our list of exceptions
for (var j=0;j<ICEcoder.tagNestExceptions.length;j++) {
if (tagString==ICEcoder.tagNestExceptions[j]) {
canDoTheEndTag=false;
}
}
if (canDoTheEndTag) {
// Get this end tag name
tagEnd=nestCheck.substr(0,i);
tagEndJS=tagEnd.substr(tagEnd.lastIndexOf('<'),tagEnd.length);
tagEnd=tagEnd.substr(tagEnd.lastIndexOf('<')+1,tagEnd.length);
tagEnd=tagEnd.substr(tagEnd.lastIndexOf(' ')+1,tagEnd.length);
tagEnd=tagEnd.substr(tagEnd.lastIndexOf('\t')+1,tagEnd.length);
tagEnd=tagEnd.substr(tagEnd.lastIndexOf(';')+1,tagEnd.length);
if (!ICEcoder.codeBlock) {
// OK, we can do something further as we're not in a code block
// If it's the same as the previously logged tag preceeded by /, it's the equivalent end tag
if (tagEnd=="/"+ICEcoder.htmlTagArray[ICEcoder.htmlTagArray.length-1]) {
// So remove the last logged tag, thereby going up one in the nest
ICEcoder.htmlTagArray.pop();
} else {
// Otherwise it's a different tag, add it to the end
ICEcoder.htmlTagArray.push(tagString);
}
} else if (
((ICEcoder.tagStart=="script"||ICEcoder.tagStart=="/script")&&tagEndJS=="</script")||
(ICEcoder.tagStart=="?"&&tagEnd=="?")) {
ICEcoder.codeBlock=false;
}
}
// Reset our open tag state ready for next time
openTag=false;
}
}
// Now we've built up our nest depth array, if we're due to show it in the display
if (updateNestDisplay) {
// Clear the display
ICEcoder.nestDisplay.innerHTML = "";
if ("undefined" != typeof ICEcoder.openFiles[ICEcoder.selectedTab-1]) {
fileName = ICEcoder.openFiles[ICEcoder.selectedTab-1];
if (fileName.indexOf(".js")<0&&fileName.indexOf(".css")<0) {
// Then for all the array items, output as the nest display
for (var i=0;i<ICEcoder.htmlTagArray.length;i++) {
ICEcoder.nestDisplay.innerHTML += ICEcoder.htmlTagArray[i];
if(i<ICEcoder.htmlTagArray.length-1) {ICEcoder.nestDisplay.innerHTML += " &gt; "};
}
}
}
}
},
// Detect keys/combos plus identify our area and set the vars, perform actions
interceptKeys: function(area, evt) {
var key;
key = evt.keyCode ? evt.keyCode : evt.which ? evt.which : evt.charCode;
// DEL (Delete file)
if (key==46 && area == "files") {
top.ICEcoder.delKeyDown = true;
top.ICEcoder.deleteFile();
return false;
// CTRL key down
} else if(key==17) {
top.ICEcoder.ctrlKeyDown = true;
return false;
// Shift key down
} else if(key==16) {
top.ICEcoder.shiftKeyDown = true;
return false;
// CTRL+F (Find)
} else if(key==70 && top.ICEcoder.ctrlKeyDown==true) {
top.document.getElementById('find').focus();
top.ICEcoder.ctrlKeyDown = false;
return false;
// CTRL+G (Go to Line)
} else if(key==71 && top.ICEcoder.ctrlKeyDown==true) {
top.document.getElementById('goToLineNo').focus();
top.ICEcoder.ctrlKeyDown = false;
return false;
// CTRL+S (Save)
} else if(key==83 && top.ICEcoder.ctrlKeyDown==true) {
if(top.ICEcoder.shiftKeyDown==true) {
top.ICEcoder.saveFile('saveAs');
top.ICEcoder.shiftKeyDown = false;
} else {
top.ICEcoder.saveFile();
}
top.ICEcoder.ctrlKeyDown = false;
return false;
// CTRL+Enter (Open Webpage)
} else if(key==13 && top.ICEcoder.ctrlKeyDown==true && top.ICEcoder.openFiles[top.ICEcoder.selectedTab-1] != "/[NEW]") {
window.open(top.ICEcoder.openFiles[top.ICEcoder.selectedTab-1]);
top.ICEcoder.ctrlKeyDown = false;
return false;
// ESC (Comment/Uncomment line)
} else if(key==27 && area == "content") {
top.ICEcoder.lineCommentToggle();
return false;
// Any other key
} else {
return key;
}
},
// Reset the state of keys back to the normal state
resetKeys: function(evt) {
var key;
key = evt.keyCode ? evt.keyCode : evt.which ? evt.which : evt.charCode;
if (key==17) {top.ICEcoder.ctrlKeyDown = false;}
if (key==16) {top.ICEcoder.shiftKeyDown = false;}
if (key==46) {top.ICEcoder.delKeyDown = false;}
},
// Set the width of the file manager on demand
changeFilesW: function(expandContract) {
var expandContract;
if (!ICEcoder.lockedNav) {
if ("undefined" != typeof ICEcoder.changeFilesInt) {clearInterval(ICEcoder.changeFilesInt)};
ICEcoder.changeFilesInt = setInterval(function() {ICEcoder.changeFilesWStep(expandContract)},10);
}
},
// Expand/contract the file manager in half-steps
changeFilesWStep: function (expandContract) {
if (expandContract=="expand") {
ICEcoder.filesW < ICEcoder.maxFilesW-1 ? ICEcoder.filesW += Math.ceil((ICEcoder.maxFilesW-ICEcoder.filesW)/2) : ICEcoder.filesW = ICEcoder.maxFilesW;
} else {
ICEcoder.filesW > ICEcoder.minFilesW+1 ? ICEcoder.filesW -= Math.ceil((ICEcoder.filesW-ICEcoder.minFilesW)/2) : ICEcoder.filesW = ICEcoder.minFilesW;
}
if ((expandContract=="expand" && ICEcoder.filesW == ICEcoder.maxFilesW)||(expandContract=="contract" && ICEcoder.filesW == ICEcoder.minFilesW)) {
clearInterval(ICEcoder.changeFilesInt);
}
// Redo the layout to match
ICEcoder.setLayout();
},
// Change tabs by reloading content
switchTab: function(newTab) {
var cM;
// Identify tab that's currently selected & show the instance
ICEcoder.selectedTab = newTab;
cM = ICEcoder.getcMInstance();
// Switch mode
ICEcoder.switchMode();
// Set all cM instances to be hidden, then make our selected instance visable
for (var i=0;i<ICEcoder.cMInstances.length;i++) {
ICEcoder.content.contentWindow['cM'+ICEcoder.cMInstances[i]].setOption('theme','icecoder hidden');
}
cM.setOption('theme','icecoder visible');
// Focus on our selected instance
cM = ICEcoder.getcMInstance();
cM.focus();
// Highlight the selected tab
ICEcoder.redoTabHighlight(ICEcoder.selectedTab);
},
// Reset all tabs to be without a highlight and then highlight the selected
redoTabHighlight: function(selectedTab) {
for(var i=1;i<=10;i++) {
ICEcoder.changedContent[i-1]==1 ? bgVPos = -44 : bgVPos = 0;
i==selectedTab ? ICEcoder.changedContent[selectedTab-1]==1 ? bgVPos = -33 : bgVPos = -22 : bgVPos = bgVPos;
document.getElementById('tab'+i).style.backgroundPosition = "0px "+bgVPos+"px";
}
},
// Starts a new file by setting a few vars & clearing the editor
newTab: function() {
var cM;
ICEcoder.cMInstances.push(ICEcoder.nextcMInstance);
ICEcoder.selectedTab = ICEcoder.cMInstances.length;
ICEcoder.content.contentWindow.createNewCMInstance(ICEcoder.nextcMInstance);
ICEcoder.thisFileFolderType='file';
ICEcoder.thisFileFolderLink=shortURLStarts+'/[NEW]';
ICEcoder.openFile();
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");
ICEcoder.nextcMInstance++;
},
// Create a new tab for a file
createNewTab: function() {
var closeTabLink;
// Push new file into array
top.ICEcoder.openFiles.push(top.ICEcoder.shortURL);
// Setup a new tab
closeTabLink = '<a nohref onClick="parent.ICEcoder.closeTab('+(top.ICEcoder.openFiles.length)+')"><img src="images/nav-close.gif"></a>';
top.document.getElementById('tab'+(top.ICEcoder.openFiles.length)).style.display = "inline-block";
top.document.getElementById('tab'+(top.ICEcoder.openFiles.length)).innerHTML = top.ICEcoder.openFiles[top.ICEcoder.openFiles.length-1] + " " + closeTabLink;
// Highlight it and state it's selected
top.ICEcoder.redoTabHighlight(top.ICEcoder.openFiles.length);
top.ICEcoder.selectedTab=top.ICEcoder.openFiles.length;
// Add a new value ready to indicate if this content has been changed
top.ICEcoder.changedContent.push(0);
},
// Create a new tab for a file
renameTab: function(tabNum,newName) {
var closeTabLink;
// Push new file into array
top.ICEcoder.openFiles[tabNum] = newName;
// Setup a new tab
closeTabLink = '<a nohref onClick="parent.ICEcoder.closeTab('+tabNum+')"><img src="images/nav-close.gif"></a>';
top.document.getElementById('tab'+tabNum).innerHTML = top.ICEcoder.openFiles[tabNum] + " " + closeTabLink;
},
// Indicate if the nesting structure of the code is OK
updateNestingIndicator: function () {
var cM, fileName;
cM = ICEcoder.getcMInstance();
fileName = ICEcoder.openFiles[ICEcoder.selectedTab-1];
ICEcoder.caretPos=cM.getValue().length;
ICEcoder.getNestLocation();
// Nesting is OK if at the end of the file we have no nests left, or it's a JS or CSS file
if (ICEcoder.htmlTagArray.length==0||fileName.indexOf(".js")>0||fileName.indexOf(".css")>0) {
ICEcoder.nestValid.style.backgroundColor="#00bb00";
ICEcoder.nestValid.innerHTML = "Nesting OK";
} else {
ICEcoder.nestValid.style.backgroundColor="#ff0000";
ICEcoder.nestValid.innerHTML = "Nesting Broken";
}
},
// Get the caret position on demand
getCaretPosition: function() {
var cM, content, line, char, charPos, charCount;
cM = ICEcoder.getcMInstance();
content = cM.getValue();
line = cM.getCursor().line;
char = cM.getCursor().ch;
charPos = 0;
for (var i=0;i<line;i++) {
charCount = content.indexOf("\n",charPos);
charPos=charCount+1;
}
ICEcoder.caretPos=(charPos+char-1);
ICEcoder.getNestLocation('yes');
},
// Update the code type, line & character display
updateCharDisplay: function() {
var cM;
cM = ICEcoder.getcMInstance();
ICEcoder.caretLocationType();
ICEcoder.charDisplay.innerHTML = ICEcoder.caretLocType + ", Line: " + (cM.getCursor().line+1) + ", Char: " + cM.getCursor().ch;
},
// Determine which area of the document we're in
caretLocationType: function () {
var cM, caretLocType, caretChunk, fileName;
cM = ICEcoder.getcMInstance();
caretLocType = "Unknown";
caretChunk = cM.getValue().substr(0,ICEcoder.caretPos+1);
if (caretChunk.lastIndexOf("<script")>caretChunk.lastIndexOf("</script>")&&caretLocType=="Unknown") {caretLocType = "JavaScript"};
if (caretChunk.lastIndexOf("<?")>caretChunk.lastIndexOf("?>")&&caretLocType=="Unknown") {caretLocType = "PHP"};
if (caretChunk.lastIndexOf("<")>caretChunk.lastIndexOf(">")&&caretLocType=="Unknown") {caretLocType = "HTML"};
if (caretLocType=="Unknown") {caretLocType = "Content"};
var fileName;
fileName = ICEcoder.openFiles[ICEcoder.selectedTab-1];
if (fileName.indexOf(".js")>0) {caretLocType="JavaScript"};
if (fileName.indexOf(".css")>0) {caretLocType="CSS"};
ICEcoder.caretLocType = caretLocType;
// If we're in a JS or PHP code block, add that to the nest display
if (caretLocType=="JavaScript"||caretLocType=="PHP") {
ICEcoder.nestDisplay.innerHTML += " &gt; " + caretLocType;
}
},
// Alter array indicating which files have changed
redoChangedContent: function(evt) {
var key;
key = evt.keyCode ? evt.keyCode : evt.which ? evt.which : evt.charCode;
// Exclude a few keys such as Escape...
if (top.ICEcoder.ctrlKeyDown==false && key!=27 && key!=20 && (key<16||key>19) && (key<37||key>40) && (key!=144||key!=145) && (key!=44||key!=45) && (key<33||key>36) && (key!=91||key!=92) && (key<112||key>123)) {
ICEcoder.changedContent[ICEcoder.selectedTab-1] = 1;
ICEcoder.redoTabHighlight(ICEcoder.selectedTab);
}
},
// Close the tab upon request
closeTab: function(closeTabNum) {
var cM, okToRemove;
cM = ICEcoder.getcMInstance();
okToRemove = true;
if (ICEcoder.changedContent[closeTabNum-1]==1) {
okToRemove = confirm('You have made changes.\n\nAre you sure you want to close without saving?');
}
if (okToRemove) {
// recursively copy over all tabs & data from the tab to the right, if there is one
for (var i=closeTabNum;i<ICEcoder.openFiles.length;i++) {
ICEcoder.tD.getElementById('tab'+i).innerHTML = ICEcoder.tD.getElementById('tab'+(i+1)).innerHTML;
ICEcoder.openFiles[i-1] = ICEcoder.openFiles[i];
// reduce the tab reference number on the closeTab link by 1
ICEcoder.tD.getElementById('tab'+i).innerHTML = ICEcoder.tD.getElementById('tab'+i).innerHTML.replace(("closeTab("+(i+1)+")"),"closeTab("+i+")");
}
// hide the instance we're closing by setting the hide class, clear the value & remove from the array
ICEcoder.content.contentWindow['cM'+top.ICEcoder.cMInstances[closeTabNum-1]].setOption('theme','icecoder hidden');
ICEcoder.content.contentWindow['cM'+top.ICEcoder.cMInstances[closeTabNum-1]].setValue('');
top.ICEcoder.cMInstances.splice(closeTabNum-1,1);
// clear the rightmost tab (or only one left in a 1 tab scenario) & remove from the array
ICEcoder.tD.getElementById('tab'+ICEcoder.openFiles.length).style.display = "none";
ICEcoder.tD.getElementById('tab'+ICEcoder.openFiles.length).innerHTML = "";
ICEcoder.openFiles.pop();
// Determin the new selectedTab number, reduced by 1 if we have some tabs, 0 for a reset state
ICEcoder.openFiles.length>0 ? ICEcoder.selectedTab-=1 : ICEcoder.selectedTab = 0;
if (ICEcoder.openFiles.length>0 && ICEcoder.selectedTab==0) {ICEcoder.selectedTab=1};
// hide the content area if we have no tabs open
if (ICEcoder.openFiles.length==0) {
ICEcoder.tD.getElementById('content').style.visibility = "hidden";
} else {
// Switch the mode & the tab
ICEcoder.switchMode();
ICEcoder.switchTab(ICEcoder.selectedTab);
}
// Highlight the selected tab after splicing the change state out of the array
top.ICEcoder.changedContent.splice(closeTabNum-1,1);
top.parent.ICEcoder.redoTabHighlight(ICEcoder.selectedTab);
}
// Lastly, stop it from trying to also switch tab
top.ICEcoder.canSwitchTabs=false;
},
// Setup the file manager
fileManager: function() {
ICEcoder.filesFrame = top.document.getElementById('filesFrame');
if (!ICEcoder.filesFrame.contentWindow.document.getElementsByTagName) {return;};
var aMenus = ICEcoder.filesFrame.contentWindow.document.getElementsByTagName("LI");
for (var i=0; i<aMenus.length; i++) {
var mclass = aMenus[i].className;
if (mclass.indexOf("pft-directory") > -1) {
var submenu=aMenus[i].childNodes;
for (var j=0; j<submenu.length; j++) {
if (submenu[j].tagName == "A") {
submenu[j].onclick = function() {
var node = this.nextSibling;
while (1) {
if (node != null) {
if (node.tagName == "UL") {
var d = (node.style.display == "none")
node.style.display = (d) ? "block" : "none";
this.className = (d) ? "open" : "closed";
return false;
}
node = node.nextSibling;
} else {
return false;
}
}
return false;
}
submenu[j].className = (mclass.indexOf("open") > -1) ? "open" : "closed";
}
if (submenu[j].tagName == "UL")
submenu[j].style.display = (mclass.indexOf("open") > -1) ? "block" : "none";
}
}
}
return false;
},
// Note which files or foldets we are over on mouseover/mouseout
overFileFolder: function(type, link) {
ICEcoder.thisFileFolderType=type;
ICEcoder.thisFileFolderLink=link;
},
// Select file or folder on demand
selectFileFolder: function() {
var resetFile, shortURL, foundSelectedFile, foundShortURL, foundFile, resetFile;
// If we've clicked somewhere other than a file/folder
if (top.ICEcoder.thisFileFolderLink=="") {
if (!top.ICEcoder.ctrlKeyDown) {
// Deselect all files
for (var i=0;i<=top.ICEcoder.selectedFiles.length;i++) {
if (top.ICEcoder.selectedFiles[i]) {
resetFile = top.ICEcoder.filesFrame.contentWindow.document.getElementById(top.ICEcoder.selectedFiles[i]);
resetFile.style.backgroundColor="#dddddd";
resetFile.style.color="#000000";
}
}
// Set our arrray to contain 0 items
top.ICEcoder.selectedFiles.length = 0;
}
} else {
// We clicked a file/folder. Work out a shortened URL for the file, with pipes instead of slashes
shortURL = top.ICEcoder.thisFileFolderLink.substr((top.ICEcoder.thisFileFolderLink.indexOf(shortURLStarts)+top.shortURLStarts.length),top.ICEcoder.thisFileFolderLink.length).replace(/\//g,"|");
// If we have the CTRL key down
if (top.ICEcoder.ctrlKeyDown) {
foundSelectedFile=false;
// Reset all files to not be highlighted
for (i=0;i<=top.ICEcoder.selectedFiles.length;i++) {
if (top.ICEcoder.selectedFiles[i]==shortURL) {
resetFile = ICEcoder.filesFrame.contentWindow.document.getElementById(top.ICEcoder.selectedFiles[i]);
resetFile.style.backgroundColor="#dddddd";
resetFile.style.color="#000000";
top.ICEcoder.selectedFiles.splice(i);
foundSelectedFile=true;
}
}
if (!foundSelectedFile) {
foundFile = ICEcoder.filesFrame.contentWindow.document.getElementById(shortURL);
foundFile.style.backgroundColor="#888888";
foundFile.style.color="#f8f8f8";
top.ICEcoder.selectedFiles.push(shortURL);
}
// We are single clicking
} else {
// First deselect all files
for (i=0;i<top.ICEcoder.selectedFiles.length;i++) {
resetFile = ICEcoder.filesFrame.contentWindow.document.getElementById(top.ICEcoder.selectedFiles[i]);
resetFile.style.backgroundColor="#dddddd";
resetFile.style.color="#000000";
}
// Set our arrray to contain 0 items
top.ICEcoder.selectedFiles.length = 0;
// Add our URL and highlight the file
top.ICEcoder.selectedFiles.push(shortURL);
foundFile = ICEcoder.filesFrame.contentWindow.document.getElementById(shortURL);
foundFile.style.backgroundColor="#888888";
foundFile.style.color="#f8f8f8";
}
}
// Adjust the file & replace select values depending on if we have files selected
if (!top.ICEcoder.selectedFiles[0]) {
document.findAndReplace.target[2].innerHTML = "all files";
document.findAndReplace.target[3].innerHTML = "all filenames";
} else {
document.findAndReplace.target[2].innerHTML = "selected files";
document.findAndReplace.target[3].innerHTML = "selected filenames";
}
},
// Create a new file (start & instant save)
newFile: function() {
top.ICEcoder.newTab();
top.ICEcoder.saveFile();
},
// Create a new folder
newFolder: function() {
var newFolder;
newFolder = prompt('Enter Folder Path','/');
if (newFolder) {
filesFrame.contentWindow.frames['fileControl'].location.href="lib/file-control.php?action=newFolder&file="+newFolder.replace(/\//g,"|");
}
},
// Open a file on demand
openFile: function() {
if (top.ICEcoder.thisFileFolderLink!="" && top.ICEcoder.thisFileFolderType=="file") {
var shortURL, canOpenFile;
// work out a shortened URL for the file
shortURL = top.ICEcoder.thisFileFolderLink.replace(/\|/g,"/");
shortURL = shortURL.substr((shortURL.indexOf(shortURLStarts)+shortURLStarts.length),shortURL.length);
// No reason why we can't open a file (so far)
canOpenFile = true;
// Limit to 10 files open at a time
if (top.ICEcoder.openFiles.length<10) {
// check if we've already got it in our array
for (var i=0;i<top.ICEcoder.openFiles.length;i++) {
if (top.ICEcoder.openFiles[i]==shortURL && shortURL!="/[NEW]") {
// we have, so don't bother opening again
canOpenFile = false;
// instead, switch to that tab
top.ICEcoder.switchTab(i+1);
}
}
} else {
// show a message because we have 10 files open
alert('Sorry, you can only have 10 files open at a time!');
canOpenFile = false;
}
// if we're still OK to open it...
if (canOpenFile) {
top.ICEcoder.shortURL = shortURL;
if (shortURL!="/[NEW]") {
// replace forward slashes with pipes so it get be placed in a querystring
top.ICEcoder.thisFileFolderLink = top.ICEcoder.thisFileFolderLink.replace(/\//g,"|");
ICEcoder.filesFrame.contentWindow.frames['fileControl'].location.href = "lib/file-control.php?action=load&file="+top.ICEcoder.thisFileFolderLink;
} else {
top.ICEcoder.createNewTab();
}
}
}
},
// Save a file on demand
saveFile: function(saveAs) {
var saveType;
if (saveAs) {saveType = "saveAs"} else {saveType = "save"};
filesFrame.contentWindow.frames['fileControl'].location.href="lib/file-control.php?action=save&file="+ICEcoder.openFiles[ICEcoder.selectedTab-1].replace(/\//g,"|")+"&saveType="+saveType;
},
// Prompt a rename dialog on demand
renameFile: function() {
var renamedFile, shortURL;
shortURL = top.ICEcoder.rightClickedFile.substr((top.ICEcoder.rightClickedFile.indexOf(shortURLStarts)+top.shortURLStarts.length),top.ICEcoder.rightClickedFile.length).replace(/\|/g,"/");
renamedFile = false;
renamedFile = prompt('Please enter the new name for',shortURL);
if (renamedFile) {
for (var i=0;i<top.ICEcoder.openFiles.length;i++) {
if(top.ICEcoder.openFiles[i]==shortURL.replace(/\|/g,"/")) {
// rename array item and the tab
top.ICEcoder.openFiles[i] = renamedFile;
closeTabLink = '<a nohref onClick="top.ICEcoder.files.contentWindow.closeTab('+(i+1)+')"><img src="images/nav-close.gif"></a>';
top.document.getElementById('tab'+(i+1)).innerHTML = top.ICEcoder.openFiles[i] + " " + closeTabLink;
}
}
ICEcoder.filesFrame.contentWindow.frames['fileControl'].location.href = "lib/file-control.php?action=rename&file="+renamedFile+"&oldFileName="+top.ICEcoder.rightClickedFile.replace(/\|/g,"/");
}
},
// Delete a file on demand
deleteFile: function() {
var delFiles, selectedFilesList;
delFiles = confirm('Delete:\n\n'+top.ICEcoder.selectedFiles.toString().replace(/\|/g,"/").replace(/,/g,"\n")+'?');
// Upon supply a new name, rename tabs and update filename on server
if (delFiles) {
selectedFilesList = "";
for (var i=0;i<top.ICEcoder.selectedFiles.length;i++) {
selectedFilesList += top.ICEcoder.selectedFiles[i];
if (i<top.ICEcoder.selectedFiles.length-1) {selectedFilesList+=";"}
}
ICEcoder.filesFrame.contentWindow.frames['fileControl'].location.href = "lib/file-control.php?action=delete&file="+selectedFilesList;
};
},
// Show menu on right clicking in file manager
showMenu: function() {
if ("undefined" != typeof top.ICEcoder.thisFileFolderLink && top.ICEcoder.thisFileFolderLink!="") {
document.getElementById('fileMenu').style.display = "inline-block";
document.getElementById('fileMenu').style.left = (top.ICEcoder.mouseX+20) + "px";
document.getElementById('fileMenu').style.top = (top.ICEcoder.mouseY+80) + "px";
}
return false;
},
// Show & hide target element
showHide: function(doVis,elem) {
doVis=="show" ? elem.style.visibility='visible' : elem.style.visibility='hidden';
},
// Update find & replace options based on user selection
findReplaceOptions: function() {
var rText, replace, rTarget;
rText = document.getElementById('rText').style.display;
replace = document.getElementById('replace').style.display;
rTarget = document.getElementById('rTarget').style.display;
document.findAndReplace.connector.value=="and" ? document.getElementById('rText').style.display = document.getElementById('replace').style.display = document.getElementById('rTarget').style.display = "inline-block" : document.getElementById('rText').style.display = document.getElementById('replace').style.display = document.getElementById('rTarget').style.display = "none";
},
// Find & replace text according to user selections
findReplace: function(action,resultsOnly) {
var find, findLen, cM, content, lineCount, numChars, charsToCursor, charCount, startPos, endPos;
// Determine our find string, in lowercase and the length of that
find = parent.parent.document.getElementById('find').value.toLowerCase();
findLen = find.length;
// If we have something to find
if (findLen>0) {
cM = ICEcoder.getcMInstance();
content = cM.getValue().toLowerCase();
// Find & replace the next instance?
if (document.findAndReplace.connector.value=="and" && cM.getSelection()==find) {
cM.replaceSelection(document.getElementById('replace').value);
}
if (!top.ICEcoder.findMode||parent.parent.document.getElementById('find').value!=ICEcoder.lastsearch) {
ICEcoder.results = [];
for (var i=0;i<content.length;i++) {
if (content.substr(i,findLen)==find) {
ICEcoder.results.push(i);
}
}
// Also remember the last search term made
ICEcoder.lastsearch = find;
}
// If we have results
if (ICEcoder.results.length>0) {
// Show results only
if (resultsOnly) {
parent.parent.document.getElementById('results').innerHTML = ICEcoder.results.length + " results";
// We need to take action instead
} else {
lineCount=1;
numChars=0;
for (var i=0;i<content.length;i++) {
if (content.indexOf('\n',i)==i && lineCount<=cM.getCursor().line) {
lineCount++;
numChars=i;
}
}
charsToCursor = numChars+cM.getCursor().ch;
ICEcoder.findResult = 0;
for (var i=0;i<ICEcoder.results.length;i++) {
if (ICEcoder.results[i]<=charsToCursor) {
ICEcoder.findResult++;
}
}
if (ICEcoder.findResult>ICEcoder.results.length-1) {ICEcoder.findResult=0};
parent.parent.document.getElementById('results').innerHTML = "Highlighted result "+(ICEcoder.findResult+1)+" of "+ICEcoder.results.length+" results";
lineCount=0;
for (var i=0;i<ICEcoder.results[ICEcoder.findResult];i++) {
if (content.indexOf('\n',i)==i) {
lineCount++;
}
}
charCount = ICEcoder.results[ICEcoder.findResult]-content.lastIndexOf('\n',ICEcoder.results[ICEcoder.findResult])-1;
startPos = new Object();
startPos.line = lineCount;
startPos.ch = charCount;
endPos = new Object();
endPos.line = lineCount;
endPos.ch = charCount+findLen;
// Finally, highlight our selection
cM = ICEcoder.getcMInstance();
cM.setSelection(startPos, endPos);
cM.focus();
top.ICEcoder.findMode = true;
}
} else {
parent.parent.document.getElementById('results').innerHTML = "No results";
}
} else {
parent.parent.document.getElementById('results').innerHTML = "";
}
},
// Go to a specific line number
goToLine: function() {
var cM;
cM = ICEcoder.getcMInstance();
cM.setCursor(document.getElementById('goToLineNo').value-1);
cM.focus();
return false;
},
// Switch the CodeMirror mode on demand
switchMode: function() {
var cM;
cM = ICEcoder.getcMInstance();
fileName = ICEcoder.openFiles[ICEcoder.selectedTab-1];
if (fileName.indexOf('.js')>0) {
cM.setOption("mode","javascript");
} else if (fileName.indexOf('.css')>0) {
cM.setOption("mode","css");
} else {
cM.setOption("mode","application/x-httpd-php");
}
},
// Lock & unlock the file manager navigation on demand
lockUnlockNav: function() {
var lockIcon;
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";
},
// Determine the CodeMirror instance we're using on demand
getcMInstance: function(newTab) {
var cM;
if (newTab=="new") {
cM = top.ICEcoder.content.contentWindow['cM'+ICEcoder.cMInstances[ICEcoder.selectedTab-1]];
} else if (ICEcoder.openFiles.length==0) {
cM = top.ICEcoder.content.contentWindow['cM1'];
} else {
cM = top.ICEcoder.content.contentWindow['cM'+ICEcoder.cMInstances[ICEcoder.selectedTab-1]];
}
return cM;
},
// Start running plugin intervals according to given specifics
startPluginIntervals: function(plugURL,plugTarget,plugTimer) {
// For this window instances
if (plugTarget=="_parent"||plugTarget=="_top"||plugTarget=="_self"||plugTarget=="") {
setInterval('window.location=\''+plugURL+'\'',plugTimer*1000*60);
// for pluginActions iframe instances
} else if (plugTarget=="pluginActions") {
setInterval('document.getElementById(\'pluginActions\').src=\''+plugURL+'\'',plugTimer*1000*60);
// for _blank or named target window instances
} else {
setInterval('window.open(\''+plugURL+'\',\''+plugTarget+'\')',plugTimer*1000*60);
}
},
// Comment or uncomment line on keypress
lineCommentToggle: function() {
var cM, lineContent, cursorPos;
cM = ICEcoder.getcMInstance();
cursorPos = cM.getCursor().ch;
lineContent = cM.getLine(cM.getCursor().line);
if (ICEcoder.caretLocType=="JavaScript"||ICEcoder.caretLocType=="PHP") {
if (lineContent.slice(0,3)!="// ") {
cM.setLine(cM.getCursor().line, "// " + lineContent);
cM.setCursor(cM.getCursor().line, cursorPos+3);
} else {
cM.setLine(cM.getCursor().line, lineContent.slice(3,lineContent.length));
cM.setCursor(cM.getCursor().line, cursorPos-3);
}
} else if (ICEcoder.caretLocType=="CSS") {
if (lineContent.slice(0,3)!="/* ") {
cM.setLine(cM.getCursor().line, "/* " + lineContent + " */");
cM.setCursor(cM.getCursor().line, cursorPos+3);
} else {
cM.setLine(cM.getCursor().line, lineContent.slice(3,lineContent.length).slice(0,lineContent.length-5));
cM.setCursor(cM.getCursor().line, cursorPos-3);
}
} else {
if (lineContent.slice(0,4)!="<!--") {
cM.setLine(cM.getCursor().line, "<!--" + lineContent + "//-->");
cM.setCursor(cM.getCursor().line, cursorPos+4);
} else {
cM.setLine(cM.getCursor().line, lineContent.slice(4,lineContent.length).slice(0,lineContent.length-9));
cM.setCursor(cM.getCursor().line, cursorPos-4);
}
}
},
// Get the mouse position on demand
getMouseXY: function(e) {
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;
} else {
top.ICEcoder.mouseX = e.pageX;
top.ICEcoder.mouseY = e.pageY;
}
scrollTop = top.document.getElementById('filesFrame').contentWindow.document.body.scrollTop;
top.ICEcoder.mouseY -= scrollTop;
}
};