/ Published in: JavaScript
Expand |
Embed | Plain Text
/* * Created October 19, 2010 by Josh Atkins * Updated December 7, 2010 * Released into the public domain */ function get(elmnt) { return document.getElementById(elmnt); } function find_index(array, string) { i = 0; for(i=0;i<array.length;i++) { if(array[i]==string) break; } return array[i] == string ? i : -1; } var commands = ['bold', 'italic', 'underline', 'strikethrough', 'justifyleft', 'justifycenter', 'justifyright', 'insertunorderedlist', 'insertorderedlist', 'indent', 'outdent', 'subscript', 'superscript', 'insertlink', 'unlink', 'selectimage', 'inserttable', 'insertrowabove', 'insertrowbelow', 'insertcolumnbefore', 'insertcolumnafter'], titles = ['Bold', 'Italic', 'Underline', 'Strikethrough', 'Left Align', 'Center Align', 'Right Align', 'Insert Bulleted List', 'Insert Numbered List', 'Indent Text', 'Outdent Text', 'Subscript', 'Superscript', 'Insert Link', 'Remove Link', 'Insert Image', 'Insert Table', 'Insert Table Row Above', 'Insert Table Row Below', 'Insert Table Column Before', 'Insert Table Column After'], wysiwygCount = 0, wysiwygs = Array(), currentWYSIWYG = null, i, n, wysiwygContainer, wysiwyg, toolbar, button, buttonLink, buttonImage, cmd_value, cmd_true_or_false, click_code, tableDialog, tableRowsLabel, tableRowsInput, tableColumnsLabel, tableColumnsInput, tableInsertButton, tableHeading, newTable, newTableBody, newTableRow, newTableColumn, tableCount = 0, currentTable, cursorPosition, table, textAreaID, newTitles, commandsLength; function toggleVisibility(elmnt) { get(elmnt).className = get(elmnt).className == 'hidden' ? '' : 'hidden'; return get(elmnt).className == ''; } function positionBelow(elmntAbove, elmntBelow) { get(elmntBelow).style.top = get(elmntAbove).offsetTop + get(elmntAbove).offsetHeight + 'px'; get(elmntBelow).style.left = get(elmntAbove).offsetLeft + 'px'; if(get(elmntBelow).style.position!='absolute') get(elmntBelow).style.position = 'absolute'; } function replaceTextAreaWithWYSIWYG(textArea, onlyCommands, wysiwygWidth, wysiwygHeight) { wysiwygs[wysiwygCount] = textArea; // security issues? wysiwygCount++; wysiwygContainer = document.createElement('div'); wysiwygContainer.id = 'wysiwygContainer' + wysiwygCount; wysiwygContainer.className = 'wysiwyg'; wysiwyg = document.createElement('iframe'); wysiwyg.id = 'WYSIWYG' + wysiwygCount; wysiwyg.className = 'wysiwyg'; wysiwyg.frameBorder = '0'; tableDialog = document.createElement('fieldset'); tableDialog.id = 'fieldsetInsertTable' + wysiwygCount; tableDialog.className = 'hidden'; tableHeading = document.createElement('h2'); tableHeading.innerHTML = 'Insert Table'; tableRowsLabel = document.createElement('label'); tableRowsLabel.htmlFor = 'txtRowsInput' + wysiwygCount; tableRowsLabel.innerHTML = 'Number of rows:'; tableRowsInput = document.createElement('input'); tableRowsInput.type = 'text'; tableRowsInput.id = 'txtRowsInput' + wysiwygCount; tableColumnsLabel = document.createElement('label'); tableColumnsLabel.htmlFor = 'txtColumnsInput' + wysiwygCount; tableColumnsLabel.innerHTML = 'Number of columns:'; tableColumnsInput = document.createElement('input'); tableColumnsInput.type = 'text'; tableColumnsInput.id = 'txtColumnsInput' + wysiwygCount; tableInsertButton = document.createElement('button'); tableInsertButton.innerHTML = 'Insert'; tableInsertButton.setAttribute('onclick', 'return insertTable();'); insertLinkDialog = document.createElement('fieldset'); insertLinkDialog.id = 'fieldsetInsertLink' + wysiwygCount; insertLinkDialog.className = 'hidden'; insertLinkLabel = document.createElement('label'); insertLinkLabel.id = 'lblLinkLabel' + wysiwygCount; insertLinkLabel.htmlFor = 'txtLinkURL' + wysiwygCount; insertLinkLabel.innerHTML = 'URL:'; insertLinkInput = document.createElement('input'); insertLinkInput.type = 'text'; insertLinkInput.id = 'txtLinkURL' + wysiwygCount; insertLinkButton = document.createElement('button'); insertLinkButton.innerHTML = 'Insert'; insertLinkButton.setAttribute('onclick', 'wysiwygCommand(get(\'txtLinkURL'+wysiwygCount+'\').value, false, \'createlink\'); get(\'txtLinkURL'+wysiwygCount+'\').value = \'\'; get(\'btn'+wysiwygCount+'cmdinsertlink\').className = toggleVisibility(\'fieldsetInsertLink'+wysiwygCount+'\') ? \'pressed\' : \'\'; return false;'); toolbar = document.createElement('ul'); toolbar.id = 'ulWYSIWYGToolbar' + wysiwygCount; toolbar.className = 'wysiwyg'; if(onlyCommands) { var newCommands = new Array(), commandIndex; newTitles = new Array(); for(onlyCommand in onlyCommands) { commandIndex = find_index(commands, onlyCommands[onlyCommand]); newCommands.push(commands[commandIndex]); newTitles.push(titles[commandIndex]); } } commandsLength = newCommands ? newCommands.length : commands.length; for(i=0;i<commandsLength;i++) { button = document.createElement('li'); buttonLink = document.createElement('a'); buttonLink.href = '#'; buttonLink.setAttribute('onclick', 'return false;'); buttonImage = document.createElement('img'); buttonImage.id = 'btn' + wysiwygCount + 'cmd' + (newCommands ? newCommands[i] : commands[i]); buttonImage.src = '/assets/images/wysiwyg/' + (newCommands? newCommands[i] : commands[i]) + '.gif'; buttonImage.alt = newTitles ? newTitles[i] : titles[i]; buttonImage.title = newTitles ? newTitles[i] : titles[i]; switch(commands[i]) { case 'insertlink': click_function = 'positionBelow(\'btn'+wysiwygCount+'cmdinsertlink\', \'fieldsetInsertLink'+wysiwygCount+'\'); this.className = toggleVisibility(\'fieldsetInsertLink'+wysiwygCount+'\') ? \'pressed\' : \'\';'; break; case 'selectimage': click_function = 'positionBelow(\'btn'+wysiwygCount+'cmdselectimage\', \'divImages\'); this.className = toggleVisibility(\'divImages\') ? \'pressed\' : \'\''; break; case 'inserttable': click_function = 'positionBelow(\'btn'+wysiwygCount+'cmdinserttable\', \'fieldsetInsertTable'+wysiwygCount+'\'); this.className = toggleVisibility(\'fieldsetInsertTable'+wysiwygCount+'\') ? \'pressed\' : \'\';'; break; case 'insertrowabove': click_function = 'insertRow(true);'; break; case 'insertcolumnbefore': click_function = 'insertColumn(true);'; break; case 'insertrowbelow': click_function = 'insertRow(false);'; break; case 'insertcolumnafter': click_function = 'insertColumn(false);'; break; default: click_function = 'textAreaID = \''+textArea+'\'; currentWYSIWYG = this.parentNode.parentNode.parentNode.parentNode.id.substring(16); wysiwygCommand(this.id.substring(3));'; } buttonImage.setAttribute('onclick', click_function); buttonImage.setAttribute('onmousedown', renewPageLock); buttonLink.appendChild(buttonImage) button.appendChild(buttonLink); toolbar.appendChild(button); } wysiwygContainer.appendChild(toolbar); wysiwygContainer.appendChild(insertLinkDialog); wysiwygContainer.appendChild(tableDialog); wysiwygContainer.appendChild(wysiwyg); brClear = document.createElement('br'); brClear.className = 'clear'; wysiwygContainer.appendChild(brClear); get(textArea).parentNode.insertBefore(wysiwygContainer, get(textArea)); insertLinkDialog.appendChild(insertLinkLabel); insertLinkDialog.appendChild(insertLinkInput); insertLinkDialog.appendChild(insertLinkButton); tableDialog.appendChild(tableHeading); tableDialog.appendChild(tableRowsLabel); tableDialog.appendChild(tableRowsInput); tableDialog.appendChild(document.createElement('br')); tableDialog.appendChild(tableColumnsLabel); tableDialog.appendChild(tableColumnsInput); tableDialog.appendChild(document.createElement('br')); tableDialog.appendChild(tableInsertButton); textAreaID = textArea; initializeWYSIWYG(wysiwygCount, textAreaID, wysiwygWidth, wysiwygHeight); } function initializeWYSIWYG(wysiwygID, textArea, wysiwygWidth, wysiwygHeight) { get('WYSIWYG'+wysiwygID).parentNode.style.width = wysiwygWidth || get(textAreaID).offsetWidth + 'px'; get('WYSIWYG'+wysiwygID).parentNode.style.height = wysiwygHeight || get(textAreaID).offsetHeight + 'px'; get('WYSIWYG'+wysiwygID).contentDocument.write('<br />'+textArea); get('WYSIWYG'+wysiwygID).contentDocument.body.innerHTML = get(textArea).value; get('WYSIWYG'+wysiwygID).contentDocument.body.style.fontFamily = 'Arial'; get('WYSIWYG'+wysiwygID).contentDocument.body.style.fontSize = '10pt'; get('WYSIWYG'+wysiwygID).contentDocument.designMode = 'on'; get('WYSIWYG'+wysiwygID).contentDocument.body.id = 'editor' + wysiwygID; wysiwygs[parseInt(wysiwygID)-1] = textArea; get('WYSIWYG'+wysiwygID).contentDocument.execCommand('styleWithCSS', true, null); get('WYSIWYG'+wysiwygID).height = get('wysiwygContainer'+wysiwygID).offsetHeight - get('ulWYSIWYGToolbar'+wysiwygID).offsetHeight - 58 + 'px'; textAreaID = textArea; get(textAreaID).className = 'hidden'; get('WYSIWYG'+wysiwygID).contentDocument.addEventListener('mouseup', function() { currentWYSIWYG = this.body.id.substring(6); textAreaID = wysiwygs[parseInt(this.body.id.substring(6))-1]; updateButtonStates(); }, false); get('WYSIWYG'+wysiwygID).contentDocument.addEventListener('keyup', function(e) { updateTextArea(); updateButtonStates(); }, false); get('WYSIWYG'+wysiwygID).contentDocument.addEventListener('keypress', function(e) { currentWYSIWYG = this.body.id.substring(6); textAreaID = wysiwygs[parseInt(this.body.id.substring(6))-1]; handleKeyPress(e); return false; }, true); } function insertImage(id, name) { wysiwygCommand("<a href=\"/uploads/view/" + id + "\"><img src=\"/uploads/download/" + id + "/resized\" alt=\"" + name + "\" title=\"" + name + "\" /></a>", null, "inserthtml"); get('btn'+currentWYSIWYG+'cmdselectimage').className = toggleVisibility('divImages') ? 'pressed' : ''; updateTextArea(); } function updateTextArea() { get(textAreaID).value = get('WYSIWYG'+currentWYSIWYG).contentDocument.body.innerHTML; get('WYSIWYG'+currentWYSIWYG).contentWindow.focus(); } function wysiwygCommand(value, true_or_false, called_from_func_cmd) { if(!value) value = null; if(!true_or_false) true_or_false = false; if(called_from_func_cmd) get('WYSIWYG'+currentWYSIWYG).contentDocument.execCommand(called_from_func_cmd, true_or_false, value); else get('WYSIWYG'+currentWYSIWYG).contentDocument.execCommand(value.substring(0, currentWYSIWYG.length+3)==currentWYSIWYG+'cmd' ? value.substring(currentWYSIWYG.length+3) : value, false, null);//cmd_value, cmd_true_or_false); updateButtonStates(); } function updateButtonStates() { for(i=0;i<=13;i++) { if(get('btn'+currentWYSIWYG+'cmd'+commands[i])) try { get('btn'+currentWYSIWYG+'cmd'+commands[i]).className = get('WYSIWYG'+currentWYSIWYG).contentDocument.queryCommandState(commands[i]) ? 'pressed' : ''; } catch(err) { } if(i==6) i = 9; } updateTextArea(); } function insertTable() { newTable = document.createElement('table'); tableCount++; for(i=0;i<parseInt(get('txtRowsInput'+currentWYSIWYG).value);i++) { newTableRow = document.createElement('tr'); for(n=0;n<parseInt(get('txtColumnsInput'+currentWYSIWYG).value);n++) { newTableCell = document.createElement('td'); newTableCell.style.border = '1px solid #d3d3d3'; newTableCell.style.width = '5em'; newTableCell.style.height = '1.8em'; newTableCell.style.fontSize = '80%'; newTableCell.style.verticalAlign = 'top'; newTableRow.appendChild(newTableCell); } newTable.appendChild(newTableRow); } cursorPosition = get('WYSIWYG'+currentWYSIWYG).contentWindow.getSelection().getRangeAt(0).startOffset; get('WYSIWYG'+currentWYSIWYG).contentDocument.body.innerHTML = get('WYSIWYG'+currentWYSIWYG).contentDocument.body.innerHTML.substring(0, cursorPosition) + "<table id=\"table"+tableCount+"\" style=\"border-collapse: collapse; border: 1px solid white; margin: 0.5em;\">" + newTable.innerHTML + "</table>" + get('WYSIWYG'+currentWYSIWYG).contentDocument.body.innerHTML.substring(cursorPosition); get('btn'+currentWYSIWYG+'cmdinserttable').className = toggleVisibility('fieldsetInsertTable'+currentWYSIYWG) ? 'pressed' : ''; get('txtRowsInput'+currentWYSIWYG).value = ''; get('txtColumnsInput'+currentWYSIWYG).value = ''; updateTextArea(); return false; } function insertRow(aboveCurrentRow) { tableRow = get('WYSIWYG'+currentWYSIWYG).contentWindow.getSelection().focusNode.parentNode.parentNode; if(tableRow=='[object HTMLTableRowElement]') { newTableRow = document.createElement('tr'); for(i=0;i<tableRow.childNodes.length;i++) { newTableCell = document.createElement('td'); newTableCell.style.border = '1px solid #d3d3d3'; newTableCell.style.width = '5em'; newTableCell.style.height = '1.8em'; newTableCell.style.fontSize = '80%'; newTableCell.style.verticalAlign = 'top'; newTableRow.appendChild(newTableCell); } tableRow.parentNode.insertBefore(newTableRow, aboveCurrentRow==true?tableRow:tableRow.nextSibling); } } function insertColumn(afterCurrentColumn) { tableRow = get('WYSIWYG'+currentWYSIWYG).contentWindow.getSelection().focusNode.parentNode.parentNode; if(tableRow=='[object HTMLTableRowElement]') { cellIndex = get('WYSIWYG'+currentWYSIWYG).contentWindow.getSelection().focusNode.parentNode.cellIndex; table = tableRow.parentNode; for(i=0;i<table.childNodes.length;i++) { newTableCell = document.createElement('td'); newTableCell.style.border = '1px solid #d3d3d3'; newTableCell.style.width = '5em'; newTableCell.style.height = '1.8em'; newTableCell.style.fontSize = '80%'; newTableCell.style.verticalAlign = 'top'; table.childNodes[i].insertBefore(newTableCell, afterCurrentColumn==true?table.childNodes[i].childNodes[cellIndex]:table.childNodes[i].childNodes[cellIndex].nextSibling); } } updateTextArea(); } function handleKeyPress(keyEvent) { charCode = keyEvent.charCode; if(charCode>97) charCode -= 32; if(keyEvent.ctrlKey) { switch(charCode) { case 66: // bold wysiwygCommand('bold'); break; case 73: // italic wysiwygCommand('italic'); break; case 85: // underline wysiwygCommand('underline'); break; case 76: // left align wysiwygCommand('justifyleft'); break; case 69: // center align wysiwygCommand('justifycenter'); break; case 82: // right align wysiwygCommand('justifyright'); break; } keyEvent.preventDefault(); } } function offsetRight(element) { return document.body.offsetWidth - (document.getElementById(element).offsetLeft + document.getElementById(element).offsetWidth); } function offsetBottom(element) { return document.getElementById(element).offsetTop + document.getElementById(element).offsetHeight; }
Comments
Subscribe to comments
You need to login to post a comment.

This looks interesting.... does it work? I tried in a simple html file and it seems no?
I like the coding style, if it works I am sure other devs can extend how they want.