Lisp Addin Call .dcl File - lisp

I'm trying to both learn and implement some lisp code for a cad addin, but I'm running into a calling issue. I'm currently trying to add an error handling for when the user activates this addin, but the file itself is either not located in the correct directory or the file is not saved to a location. I came across a method that will allow me to ask the user a question with a message box, but the lisp file isn't pulling the dcl file. How should this error be resolved?
Scope: The big picture is for the user to either click a button on the ribbon or by typing a command, and all of the files in the same folder as the open, active drawing will receive a revision update.
Application: DraftSight is where the lisp file is being added.
Original Tutorial: Here's the link to the original tutorial where I found the code to build the message box.
Error Message from DraftSight
Code I'm building:
;; Global Constants
(defconstant msgboxPath "C:\\Users\\GarrettB\\Documents\\Visual Studio Code\\DraftSight LISP")
;;
(defun C:ProjectRev()
;; Pulls the directory from the active file
(setq dirPath (vl-catch-all-apply getvar 'dwgprefix))
;; Checks for an error
(if not (vl-catch-all-error-p dirPath)
(progn ; No error - Ask user if this is the right path
(setq UserRespond (lspYesNoCancel "Is this the correct path?" dirfile "" "PROJECT REVISION"))
(princ (type UserRespond))
(princ UserRespond)
;; if yes then continue
;; else ask for correct directory (function call)
;; (setq dirPath (browseForFolder "Select the project folder: " 1 "d:\\"))
);progn
(progn ; Error - File is not saved to a directory
;; ask for correct directory (function call)
;; (setq dirPath (browseForFolder "Select the project folder: " 1 "d:\\"))
);progn
);if
;; WORK IN PROGRESS
;; Gather drawings into a list
;; Copy drawings and place into "Past revisions" folder
;; Add revision to drawings
;; Modify drawing's names
;; Save, close, and end
)
;; Source: https://forums.autodesk.com/t5/visual-lisp-autolisp-and-general/lisp-on-all-dwg-directory/td-p/6214507
;; Browses the current directory for .dwg files
(defun browseForFolder (title options rootFolder / sh folder folderobject result)
(vl-load-com)
(setq sh (vla-getInterfaceObject (vlax-get-acad-object) "Shell.Application")) ; sets the Shell Terminal variable
;; Obtaining starting location
(setq folder (vlax-invoke-method sh 'BrowseForFolder
(vla-get-hwnd (vlax-get-acad-object)) title options rootFolder)) ; User sets the folder path and file name as an object?
(vlax-release-object sh) ;-------------------------------------------; Releases the shell application object
(setq sh nil) ;------------------------------------------------------; Sets the sh variable to nothing
; If folder is not nil
(if folder
(progn
;; Conversion
(setq folderobject (vlax-get-property folder 'Self)) ; Sets the folder path as an object
(setq result (vlax-get-property FolderObject 'Path)) ; Sets the folder path as a string
;; Release and nullify
(vlax-release-object folder) ;-----; Releases the folder path and file name as an object?
(vlax-release-object FolderObject) ; Releases the folder path as a string
(setq folder nil) ;----------------; Sets the folder variable to nothing
(setq FolderObject nil) ;----------; Sets the FolderObject variable to nothing
;; Returning variable
result
); progn
); if
); defun browserForFolder
;; Source: https://www.afralisp.net/dialog-control-language/tutorials/the-autolisp-message-box.php
;; Lisp code from tutorial
(defun lspYesNoCancel (message1 message2 message3 main)
;; Creating dialoge box
(setq dcl_id (load_dialog strcat(msgboxPath "\\" "msgbox.dcl")))
;; Error prevention
(if (not (new_dialog "lspYesNoCancel" dcl_id)) (exit))
;; Dialoge Message
(set_tile "message1" message1)
(set_tile "message2" message2)
(set_tile "message3" message3)
(set_tile "main" main)
;; Command Buttons
(action_tile "no" "(done_dialog) (setq result \"F\")")
(action_tile "yes" "(done_dialog) (setq result T)")
(action_tile "cancel" "(done_dialog) (setq result nil)")
;; Interaction
(start_dialog) ; Show dialog box
(unload_dialog dcl_id) ; Close dialoge box
(princ)
)
Here's the msgbox.dcl file
// Source: https://www.afralisp.net/dialog-control-language/tutorials/the-autolisp-message-box.php
////////////////////////////////////////////////
lspOkCancel : dialog {
key = "main";
: column {
: text {key = "message1";}
: text {key = "message2";}
: text {key = "message3";}
}
: row {
: spacer {width = 1;}
: button {
label = "OK";
key = "accept";
width = 12;
fixed_width = true;
mnemonic = "O";
is_default = true;
}
: button {
label = "Cancel";
key = "cancel";
width = 12;
fixed_width = true;
mnemonic = "C";
is_cancel = true;
}
: spacer { width = 1;}
}
}
////////////////////////////////////////////////
lspYesNo : dialog {
key = "main";
: column {
: text {key = "message1";}
: text {key = "message2";}
: text {key = "message3";}
}
: row {
: spacer {width = 1;}
: button {
label = "Yes";
key = "yes";
width = 12;
fixed_width = true;
mnemonic = "Y";
is_default = true;
}
: button {
label = "No";
key = "no";
width = 12;
fixed_width = true;
mnemonic = "N";
is_cancel = true;
}
: spacer { width = 1;}
}
}
////////////////////////////////////////////
lspOkOnly : dialog {
key = "main";
: column {
: text {key = "message1";}
: text {key = "message2";}
: text {key = "message3";}
}
: row {
: spacer { width = 1; }
: button {
label = "OK";
key = "accept";
width = 12;
fixed_width = true;
mnemonic = "O";
is_default = true;
alignment = centered;
}
: spacer { width = 1;}
}
}
////////////////////////////////////////////////
lspYesNoCancel : dialog {
key = "main";
: column {
: text {Key = "message1";}
: text {key = "message2";}
: text {key = "message3";}
}
: row {
: spacer {width = 1;}
: button {
label = "Yes";
key = "yes";
width = 12;
fixed_width = true;
mnemonic = "Y";
is_default = true;
}
: button {
label = "No";
key = "no";
width = 12;
fixed_width = true;
mnemonic = "N";
}
: button {
label = "Cancel";
key = "cancel";
width = 12;
fixed_width = true;
mnemonic = "C";
is_cancel = true;
}
: spacer {width = 1;}
}
}
////////////////////////////////////////////
lspRentryCancel : dialog {
key = "main";
: column {
: text {key = "message1";}
: text {key = "message2";}
: text {key = "message3";}
}
: row {
: spacer { width = 1; }
: button {
label = "Rentry";
key = "rentry";
width = 12;
fixed_width = true;
mnemonic = "R";
is_default = true;
}
: button {
label = "Cancel";
key = "Cancel";
width = 12;
fixed_width = true;
mnemonic = "C";
is_cancel = true;
}
: spacer {width = 1;}
}
}
////////////////////////////////////////////

I think the problem is in line:
(setq dcl_id (load_dialog strcat(msgboxPath "\\" "msgbox.dcl")))
Where should be rather:
(setq dcl_id (load_dialog ( strcat msgboxPath "\\" "msgbox.dcl")))

Related

Autolisp DCL - Alignment and Sizing Tiles

I'm trying to adjust the sizes and locations of the tiles in this DCL dialog box. Basically, I want to make the edit-boxes in the Client box, Job box, and Miscellaneous box to be the same width. However, they each start at different widths due to the different sizes of the text tile's labels. Just setting the width to a fixed value for both edit-box and text tiles doesn't seem to be fixing the issue for me. How do I need to change this code to make the tiles within this dialog box uniform?
As a bonus, I want to also adjust the tiles in the Revision box. I'm assuming this will be using the same solution. I want to have the widths of the edit-boxes of different widths with the labels centered above them.
I have found that DCL files are a slow and painful process for me. Any help with building this dialog box would be helpful. Thank you for your time.
AutoLisp Code:
(defun C:Test01 (/ sPathAndName sDCLModuleName dclFile bContinue)
;; Initializing
(setq sPathAndName "[File's location and name]")
(setq sDCLModuleName "TitleRevUpdate")
(setq bContinue T)
;; File Exists
(if (not (findfile sPathAndName))(progn
(princ "\nError: The DCL file was not found.\n")
(setq bContinue nil)
));if<-progn
;; DCL File
(if bContinue (progn
(setq dclFile (load_dialog sPathAndName))
(if (>= 0 dclFile)(progn
(princ "\nError: DCL file cannot be loaded.\n")
(setq bContinue nil)
));if<-progn
));if<-progn
;; Creating a new module
(if bContinue
(setq bContinue (new_dialog sDCLModuleName dclFile "" '(-1 -1)))
);if
;; Build and run DCL module
(if bContinue (progn
;; User Form
(princ "\nstart_dialog : ")(princ (start_dialog))(terpri)
(unload_dialog dclFile)
));if<-progn
);C:Test01
DCL Code:
TitleRevUpdate : dialog {
key = "Title" ;
label = "Update Title Block and Revision" ;
// Title
: boxed_column {
key = "Column_TitleBoxes" ;
label = "Title" ;
// Client
: boxed_column {
key = "Client_Box" ;
label = "Client" ;
: row { // Row 01 - Name
key = "Row_Client_Name" ;
width = 15 ;
: text {
key = "txt_Client_Name" ;
alignment = right ;
label = "Client's Name" ;
width = 10 ;
}// text
: edit_box {
key = "edbx_Client_Name" ;
alignment = left ;
width = 10 ;
}// edit_box
} //row
: row { // Row 02 - Location
key = "Row_Client_Loc" ;
: text {
key = "txt_Client_Loc" ;
alignment = right ;
label = "Client's Location" ;
width = 10 ;
}// text
: edit_box {
key = "edbx_Client_Loc" ;
alignment = left ;
width = 10 ;
}// edit_box
} //row
} //boxed_column
: spacer {
}// spacer
// Job
: boxed_column {
key = "Job_Box" ;
label = "Job" ;
: row { // Row 03 - Name
key = "Row_Job_Name" ;
: text {
key = "txt_Job_Name" ;
label = "Job's Name" ;
}// text
: edit_box {
key = "edbx_Job_Name" ;
}// edit_box
} //row
: row { // Row 04 - Number
key = "Row_Job_Number" ;
: text {
key = "txt_Job_Number" ;
label = "Job's Number" ;
}// text
: edit_box {
key = "edbx_Job_Number" ;
}// edit_box
} //row
} //boxed_column
: spacer {
}// spacer
// Miscellaneous
: boxed_column {
key = "Miscellaneous_Box" ;
label = "Miscellaneous" ;
: row { // Row 05 - Creator's Initials
key = "Row_Creator_Name" ;
: text {
key = "txt_Creator_Name" ;
label = "Creator's Name" ;
}// text
: edit_box {
key = "edbx_Creator_Name" ;
}// edit_box
} //row
: row { // Row 06 - Date of Creation
key = "Row_Date" ;
: text {
key = "txt_TitleDate" ;
label = "Date" ;
}// text
: edit_box {
key = "edbx_TitleDate" ;
}// edit_box
} //row
: row { // Row 07 - Issued For
key = "Row_Issued_For" ;
: text {
key = "txt_Issued_For" ;
label = "Issued For" ;
}// text
: edit_box {
key = "edbx_Issued_For" ;
}// edit_box
} //row
} //boxed_column
} //boxed_column
: spacer {
}// spacer
// Revision
: boxed_column {
key = "Column_Revision" ;
label = "Revision" ;
: row { // Row 08 - Quick Choices
key = "Row_Buttons" ;
: button {
key = "btn_IFC" ;
label = "Issued for Construction" ;
}// button
: button {
key = "tbn_AB" ;
label = "As Built" ;
}// button
: radio_column {
key = "RadioCol_WriteMethod" ;
: radio_button {
key = "rbtn_Owt" ;
label = "Clear && Overwrite" ;
}// radio_button
: radio_button {
key = "rbtn_Apnd" ;
label = "Append / New Line" ;
}// radio_button
} //radio_column
} //row
: spacer {
}// spacer
: row { // Row 09 - Rev Labels
key = "Row_Labels" ;
: text {
key = "txt_Rev" ;
label = "Rev" ;
}// text
: text {
key = "txt_Initials" ;
label = "Initials" ;
}// text
: text {
key = "txt_Description" ;
label = "Description" ;
}// text
: text {
key = "txt_RevDate" ;
label = "Date" ;
}// text
} //row
: row { // Row 10 - Rev Edit Boxes
key = "Row_Rev" ;
: edit_box {
key = "edbx_Rev" ;
}// edit_box
: edit_box {
key = "edbx_Initials" ;
}// edit_box
: edit_box {
key = "edbx_Date" ;
}// edit_box
: edit_box {
key = "edbx_RevDate" ;
}// edit_box
} //row
} //boxed_column
: spacer {
}// spacer
// Return Commands
: row { // Row 11 - Buttons
key = "Row_Return" ;
: button {
key = "btn_DWGs" ;
action = "(done_dialog 2)" ;
label = "Show Drawings" ;
}// button
: button {
key = "btn_Confirm" ;
action = "(done_dialog 1)" ;
is_enabled = true ;
label = "Confirm" ;
}// button
: button {
key = "btn_Cancel" ;
action = "(done_dialog 0)" ;
is_default = true ;
label = "Cancel" ;
}// button
} //row
: spacer {
}// spacer
} // TitleRevUpdate
The key to edit box alignment in standard DCL is to set the width attribute to be the same for all edit boxes (and large enough to accommodate the text and editing area of the largest edit box in the group), set the fixed_width attribute to true for all edit boxes, and then control the size of the edit box itself using the edit_width attribute.
You don't need separate text tiles when working with edit boxes, instead, you can use the label attribute of the edit_box tile.
For example, the upper section of your DCL could be revised to the following:
TitleRevUpdate : dialog
{
key = "Title" ;
label = "Update Title Block and Revision" ;
spacer;
// Title
: boxed_column
{
label = "Title" ;
// Client
: boxed_column
{
label = "Client" ;
: edit_box
{
label = "Client's Name:";
key = "edbx_Client_Name";
alignment = left;
width = 52;
fixed_width = true;
edit_width = 30;
}
: edit_box
{
label = "Client's Location:" ;
key = "edbx_Client_Loc" ;
alignment = left;
width = 52;
fixed_width = true;
edit_width = 30;
}
spacer;
}
spacer;
// Job
: boxed_column
{
label = "Job";
: edit_box
{
label = "Job's Name:";
key = "edbx_Job_Name";
alignment = left;
width = 52;
fixed_width = true;
edit_width = 30;
}
: edit_box
{
label = "Job's Number:" ;
key = "edbx_Job_Number" ;
alignment = left;
width = 52;
fixed_width = true;
edit_width = 30;
}
spacer;
}
spacer;
// Miscellaneous
: boxed_column
{
label = "Miscellaneous" ;
: edit_box
{
key = "edbx_Creator_Name" ;
label = "Creator's Name:" ;
alignment = left;
width = 52;
fixed_width = true;
edit_width = 30;
}
: edit_box
{
key = "edbx_TitleDate" ;
label = "Date:" ;
alignment = left;
width = 52;
fixed_width = true;
edit_width = 30;
}
: edit_box
{
key = "edbx_Issued_For" ;
label = "Issued For:" ;
alignment = left;
width = 52;
fixed_width = true;
edit_width = 30;
}
spacer;
}
spacer;
}
spacer;
// Return Commands
: row
{
key = "Row_Return" ;
fixed_width = true;
alignment = centered;
: button
{
key = "btn_DWGs" ;
action = "(done_dialog 2)" ;
label = "Drawings" ;
fixed_width = true;
width = 16;
}
: button
{
key = "btn_Confirm" ;
action = "(done_dialog 1)" ;
is_enabled = true ;
label = "Confirm" ;
fixed_width = true;
width = 16;
}
: button
{
key = "btn_Cancel" ;
action = "(done_dialog 0)" ;
is_default = true ;
label = "Cancel" ;
fixed_width = true;
width = 16;
}
}
spacer;
}
To yield the following GUI:
And given that all of the tiles are sharing the same attribute values, you can define a named tile to condense the code much further, e.g.:
myeditbox : edit_box
{
alignment = left;
width = 52;
fixed_width = true;
edit_width = 30;
}
mybutton : button
{
fixed_width = true;
width = 16;
}
TitleRevUpdate : dialog
{
key = "Title" ;
label = "Update Title Block and Revision" ;
spacer;
: boxed_column
{
label = "Title" ;
: boxed_column
{
label = "Client" ;
: myeditbox { label = "Client's Name:"; key = "edbx_Client_Name"; }
: myeditbox { label = "Client's Location:"; key = "edbx_Client_Loc" ; }
spacer;
}
spacer;
: boxed_column
{
label = "Job";
: myeditbox { label = "Job's Name:"; key = "edbx_Job_Name"; }
: myeditbox { label = "Job's Number:"; key = "edbx_Job_Number"; }
spacer;
}
spacer;
: boxed_column
{
label = "Miscellaneous" ;
: myeditbox { label = "Creator's Name:"; key = "edbx_Creator_Name"; }
: myeditbox { label = "Date:"; key = "edbx_TitleDate"; }
: myeditbox { label = "Issued For:"; key = "edbx_Issued_For"; }
spacer;
}
spacer;
}
spacer;
: row
{
key = "Row_Return" ;
fixed_width = true;
alignment = centered;
: mybutton { key = "btn_DWGs"; action = "(done_dialog 2)"; label = "Drawings"; }
: mybutton { key = "btn_Confirm"; action = "(done_dialog 1)"; label = "Confirm"; is_enabled = true; }
: mybutton { key = "btn_Cancel" ; action = "(done_dialog 0)"; label = "Cancel"; is_default = true; }
}
spacer;
}
Except
width = 10 ;
You need also
fixed_width = true;
on each edit_box

OpenXML / Xceed insert Table without empty lines

I have an existing.docx document with some text. All I want is to insert programmatically a table to a specific place. So my idea was to add a Keyword where the table should be inserted. There are no empty lines, before and after the keyword.
After the insertion of the table I add \n, before and after the table, for an empty line but somehow the Xceed library adds three after the table and two before the table.
Here is how I'm doing it:
using (DocX document = DocX.Load(#"C:\Users\rk\Desktop\test.docx"))
{
var IntTableSoftwareLocation = document.FindAll("Table").FirstOrDefault();
document.ReplaceText("Table", "");
var tableSoftware = document.InsertTable(IntTableSoftwareLocation, 3, 5);
tableSoftware.InsertParagraphBeforeSelf("\n");
tableSoftware.InsertParagraphAfterSelf("\n");
tableSoftware.SetBorder(TableBorderType.InsideH, new Border());
tableSoftware.SetBorder(TableBorderType.InsideV, new Border());
tableSoftware.SetBorder(TableBorderType.Left, new Border());
tableSoftware.SetBorder(TableBorderType.Bottom, new Border());
tableSoftware.SetBorder(TableBorderType.Top, new Border());
tableSoftware.SetBorder(TableBorderType.Right, new Border());
//Header
tableSoftware.Rows[0].Cells[0].Paragraphs[0].Append("Col1").Bold().Font("Arial").FontSize(11d);
tableSoftware.Rows[0].Cells[1].Paragraphs[0].Append("Col2").Bold().Font("Arial").FontSize(11d);
tableSoftware.Rows[0].Cells[2].Paragraphs[0].Append("Col3").Bold().Font("Arial").FontSize(11d);
tableSoftware.Rows[0].Cells[3].Paragraphs[0].Append("Col4.").Bold().Font("Arial").FontSize(11d);
tableSoftware.Rows[0].Cells[4].Paragraphs[0].Append("Col5").Bold().Font("Arial").FontSize(11d);
//Content
string TextToInsert = "Some Text";
//Column width
for (int i = 0; i < tableSoftware.RowCount; i++)
{
for (int x = 0; x < tableSoftware.ColumnCount; x++)
{
#region set column width
if (x == 0)
{
tableSoftware.Rows[i].Cells[x].Width = 28.3; // 1cm
}
else if (x == 1)
{
tableSoftware.Rows[i].Cells[x].Width = 318;
}
else if (x == 2)
{
tableSoftware.Rows[i].Cells[x].Width = 50;
}
else if (x == 3)
{
tableSoftware.Rows[i].Cells[x].Width = 28.3;
}
else if (x == 4)
{
tableSoftware.Rows[i].Cells[x].Width = 64;
}
#endregion
}
}
tableSoftware.Rows[2].Cells[1].Paragraphs[0].Append(TextToInsert + "\n").FontSize(11d).Bold().Font("Arial");
tableSoftware.Rows[2].Cells[2].Paragraphs[0].Append("User").Font("Arial").Alignment = Alignment.center;
tableSoftware.Rows[2].Cells[2].VerticalAlignment = VerticalAlignment.Center;
tableSoftware.Rows[2].Cells[3].Paragraphs[0].Append("1").Font("Arial").Alignment = Alignment.center;
tableSoftware.Rows[2].Cells[3].VerticalAlignment = VerticalAlignment.Center;
tableSoftware.Rows[2].Cells[4].Paragraphs[0].Append("2.199,00 €").Font("Arial").Alignment = Alignment.right;
tableSoftware.Rows[2].Cells[4].VerticalAlignment = VerticalAlignment.Center;
document.Save();
}
And thats how my docx Document looks like:
laksjdf
Table
alskdfjs
Ok, this is how it should be done:
//Find the Paragraph by keyword
var paraTable = document.Paragraphs.FirstOrDefault(x => x.Text.Contains("Table"));
// Remove the Keyword
paraTable.RemoveText(0);
//Insert the table into Paragraph
var table = paraTable.InsertTableAfterSelf(3, 5);
No strange empty lines anymore

VS Code extension how to edit in context?

Her is the class I use automatically capitalize true, false, ...
export class StUpdater {
private _lines: number;
private _strings: Array<string>;
constructor() {
this._lines = 0;
this._strings = ['true', 'false', 'exit', 'continue', 'return'];
}
Update(Cntx: boolean = false) {
let editor = window.activeTextEditor;
if (!editor || (editor.document.languageId != 'st')) {
window.showErrorMessage('No editor!')
return;
}
let doc = editor.document;
if (Cntx == false) {
if (this._lines >= doc.lineCount) {
this._lines = doc.lineCount;
return;
}
this._lines = doc.lineCount;
let AutoFormat = workspace.getConfiguration('st').get('autoFormat');
if (!AutoFormat) {
return;
}
}
let edit = new WorkspaceEdit();
for (let line = 0; line < doc.lineCount; line++) {
const element = doc.lineAt(line);
for (let i = 0; i < this._strings.length; i++) {
let str = this._strings[i];
let last_char = 0;
while (element.text.indexOf(str, last_char) >= 0) {
let char = element.text.indexOf(str, last_char);
last_char = char + str.length;
edit.replace(
doc.uri,
new Range(
new Position(line, char),
new Position(line, last_char)
),
str.toUpperCase()
);
}
}
}
return workspace.applyEdit(edit);
}
public dispose() {
}
}
This code works fine, but I do not want to replace it inside the string or comment. How do I do that? I cannot find preg version of replace and even if I do, in one line I do not know if it is comment or not if it is multiple line comment.
If I understand you correctly you want capitalize only certain elements (identifiers probably), but not words in comments or strings, correct? That requires to identify lexical elements in the text, which is a mapping of a range of letters to a lexical type. This is usually done by a lexer. It's not difficult to write one by hand which walks over the characters on top of your current processing and find those ranges that can be manipulated.

How can i customize code formatting for javascript?

For example i need spaces between parentheses and arguments:
var myPrivateMethod = function( name, value ) {
for ( var i = 0, l = this.stack.lenght; i < l; i-- ) {
this.stack[ i ][ name ] = value;
}
};
vs default VS Code JS formatting
var myPrivateMethod = function (name, value) {
for (var i = 0, l = this.stack.lenght; i < l; i--) {
this.stack[i][name] = value;
}
}
You can check this 'beautify' extension for visual studio code: https://marketplace.visualstudio.com/items?itemName=HookyQR.beautify
I am not sure it has the ability to add spaces between parentheses and arguments but it allows you customize code formatting.

execCommand without a selection? (set font, size etc)

I can get my custom WYSIWYG editor to apply styling to selected text no problem:
pnlDocumentEditor_IFrame.document.execCommand(cmd, ui, opt)
.. but what I need to be able to do is allow the user to set a font, or font size, or bold etc so that text typed AFTER this command is issued will have that style applied.
Is this possible? All execCommands I've tried seem to only work on selected text.
Appling execCommand on certain element, WITHOUT selecting it with mouse, can be done with this function:
jsFiddle example
function execCommandOnElement(el, commandName, value) {
if (typeof value == "undefined") {
value = null;
}
if (typeof window.getSelection != "undefined") {
// Non-IE case
var sel = window.getSelection();
// Save the current selection
var savedRanges = [];
for (var i = 0, len = sel.rangeCount; i < len; ++i) {
savedRanges[i] = sel.getRangeAt(i).cloneRange();
}
// Temporarily enable designMode so that
// document.execCommand() will work
document.designMode = "on";
// Select the element's content
sel = window.getSelection();
var range = document.createRange();
range.selectNodeContents(el);
sel.removeAllRanges();
sel.addRange(range);
// Execute the command
document.execCommand(commandName, false, value);
// Disable designMode
document.designMode = "off";
// Restore the previous selection
sel = window.getSelection();
sel.removeAllRanges();
for (var i = 0, len = savedRanges.length; i < len; ++i) {
sel.addRange(savedRanges[i]);
}
} else if (typeof document.body.createTextRange != "undefined") {
// IE case
var textRange = document.body.createTextRange();
textRange.moveToElementText(el);
textRange.execCommand(commandName, false, value);
}
}
And example usage:
var testDiv = document.getElementById("test");
execCommandOnElement(testDiv, "Bold");
execCommandOnElement(testDiv, "ForeColor", "red");
Source: set execcommand just for a div