Fixes for bug 192569 (allow foreign transactions to be added to the queue)
mozilla/editor/idl/nsIEditor.idl mozilla/editor/libeditor/base/nsEditor.cpp mozilla/editor/libeditor/base/PlaceholderTxn.cpp mozilla/editor/libeditor/html/nsHTMLCSSUtils.cpp mozilla/editor/libeditor/html/nsHTMLEditor.cpp mozilla/editor/libeditor/text/nsTextEditRules.cpp - Renamed nsIEditor::Do() to nsIEditor::DoTransaction() so that it can be called from JavaScript. - Cleaned up nsEditor::Begin/EndUpdateViewBatch() so that nothing happens outside the check of mUpdateCount. - Modified PlaceholderTxn.cpp so that it checks to see if a merged transaction implements nsPIEditorTransaction before attempting to cast it to (EditorTxn*). mozilla/editor/ui/composer/content/EditorCommandsDebug.js mozilla/editor/ui/composer/content/editorOverlay.xul mozilla/editor/ui/composer/locale/en-US/editorOverlay.dtd - Added debug menu items to test execution of foreign transactions via the txnmgr and editor. r=jfrancis@netscape.com sr=sfraser@netscape.com
This commit is contained in:
Родитель
d18471017d
Коммит
086e9f0622
|
@ -177,14 +177,14 @@ interface nsIEditor : nsISupports
|
|||
*/
|
||||
readonly attribute nsITransactionManager transactionManager;
|
||||
|
||||
/** do() fires a transaction.
|
||||
/** doTransaction() fires a transaction.
|
||||
* It is provided here so clients can create their own transactions.
|
||||
* If a transaction manager is present, it is used.
|
||||
* Otherwise, the transaction is just executed directly.
|
||||
*
|
||||
* @param aTxn the transaction to execute
|
||||
*/
|
||||
void do(in nsITransaction txn);
|
||||
void doTransaction(in nsITransaction txn);
|
||||
|
||||
|
||||
/** turn the undo system on or off
|
||||
|
|
|
@ -152,6 +152,14 @@ NS_IMETHODIMP PlaceholderTxn::Merge(nsITransaction *aTransaction, PRBool *aDidMe
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// check to see if aTransaction is one of the editor's
|
||||
// private transactions. If not, we want to avoid merging
|
||||
// the foreign transaction into our placeholder since we
|
||||
// don't know what it does.
|
||||
|
||||
nsCOMPtr<nsPIEditorTransaction> pTxn = do_QueryInterface(aTransaction);
|
||||
if (!pTxn) return NS_OK; // it's foreign so just bail!
|
||||
|
||||
EditTxn *editTxn = (EditTxn*)aTransaction; //XXX: hack, not safe! need nsIEditTransaction!
|
||||
// determine if this incoming txn is a placeholder txn
|
||||
nsCOMPtr<nsIAbsorbingTransaction> plcTxn;// = do_QueryInterface(editTxn);
|
||||
|
|
|
@ -452,9 +452,9 @@ nsEditor::GetSelection(nsISelection **aSelection)
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsEditor::Do(nsITransaction *aTxn)
|
||||
nsEditor::DoTransaction(nsITransaction *aTxn)
|
||||
{
|
||||
if (gNoisy) { printf("Editor::Do ----------\n"); }
|
||||
if (gNoisy) { printf("Editor::DoTransaction ----------\n"); }
|
||||
|
||||
nsresult result = NS_OK;
|
||||
|
||||
|
@ -480,9 +480,9 @@ nsEditor::Do(nsITransaction *aTxn)
|
|||
plcTxn->Init(mPlaceHolderName, mSelState, this);
|
||||
mSelState = nsnull; // placeholder txn took ownership of this pointer
|
||||
|
||||
// finally we QI to an nsITransaction since that's what Do() expects
|
||||
// finally we QI to an nsITransaction since that's what DoTransaction() expects
|
||||
nsCOMPtr<nsITransaction> theTxn = do_QueryInterface(plcTxn);
|
||||
Do(theTxn); // we will recurse, but will not hit this case in the nested call
|
||||
DoTransaction(theTxn); // we will recurse, but will not hit this case in the nested call
|
||||
|
||||
if (mTxnMgr)
|
||||
{
|
||||
|
@ -509,6 +509,25 @@ nsEditor::Do(nsITransaction *aTxn)
|
|||
|
||||
if (aTxn)
|
||||
{
|
||||
// XXX: Why are we doing selection specific batching stuff here?
|
||||
// XXX: Most entry points into the editor have auto variables that
|
||||
// XXX: should trigger Begin/EndUpdateViewBatch() calls that will make
|
||||
// XXX: these selection batch calls no-ops.
|
||||
// XXX:
|
||||
// XXX: I suspect that this was placed here to avoid multiple
|
||||
// XXX: selection changed notifications from happening until after
|
||||
// XXX: the transaction was done. I suppose that can still happen
|
||||
// XXX: if an embedding application called DoTransaction() directly
|
||||
// XXX: to pump its own transactions through the system, but in that
|
||||
// XXX: case, wouldn't we want to use Begin/EndUpdateViewBatch() or
|
||||
// XXX: its auto equivalent nsAutoUpdateViewBatch to ensure that
|
||||
// XXX: selection listeners have access to accurate frame data?
|
||||
// XXX:
|
||||
// XXX: Note that if we did add Begin/EndUpdateViewBatch() calls
|
||||
// XXX: we will need to make sure that they are disabled during
|
||||
// XXX: the init of the editor for text widgets to avoid layout
|
||||
// XXX: re-entry during initial reflow. - kin
|
||||
|
||||
// get the selection and start a batch change
|
||||
nsCOMPtr<nsISelection>selection;
|
||||
result = GetSelection(getter_AddRefs(selection));
|
||||
|
@ -517,6 +536,7 @@ nsEditor::Do(nsITransaction *aTxn)
|
|||
nsCOMPtr<nsISelectionPrivate>selPrivate(do_QueryInterface(selection));
|
||||
|
||||
selPrivate->StartBatchChanges();
|
||||
|
||||
if (mTxnMgr) {
|
||||
result = mTxnMgr->DoTransaction(aTxn);
|
||||
}
|
||||
|
@ -1051,7 +1071,7 @@ nsEditor::SetAttribute(nsIDOMElement *aElement, const nsAString & aAttribute, co
|
|||
ChangeAttributeTxn *txn;
|
||||
nsresult result = CreateTxnForSetAttribute(aElement, aAttribute, aValue, &txn);
|
||||
if (NS_SUCCEEDED(result)) {
|
||||
result = Do(txn);
|
||||
result = DoTransaction(txn);
|
||||
}
|
||||
// The transaction system (if any) has taken ownwership of txn
|
||||
NS_IF_RELEASE(txn);
|
||||
|
@ -1087,7 +1107,7 @@ nsEditor::RemoveAttribute(nsIDOMElement *aElement, const nsAString& aAttribute)
|
|||
ChangeAttributeTxn *txn;
|
||||
nsresult result = CreateTxnForRemoveAttribute(aElement, aAttribute, &txn);
|
||||
if (NS_SUCCEEDED(result)) {
|
||||
result = Do(txn);
|
||||
result = DoTransaction(txn);
|
||||
}
|
||||
// The transaction system (if any) has taken ownwership of txn
|
||||
NS_IF_RELEASE(txn);
|
||||
|
@ -1136,7 +1156,7 @@ NS_IMETHODIMP nsEditor::CreateNode(const nsAString& aTag,
|
|||
nsresult result = CreateTxnForCreateElement(aTag, aParent, aPosition, &txn);
|
||||
if (NS_SUCCEEDED(result))
|
||||
{
|
||||
result = Do(txn);
|
||||
result = DoTransaction(txn);
|
||||
if (NS_SUCCEEDED(result))
|
||||
{
|
||||
result = txn->GetNewNode(aNewNode);
|
||||
|
@ -1183,7 +1203,7 @@ NS_IMETHODIMP nsEditor::InsertNode(nsIDOMNode * aNode,
|
|||
InsertElementTxn *txn;
|
||||
nsresult result = CreateTxnForInsertElement(aNode, aParent, aPosition, &txn);
|
||||
if (NS_SUCCEEDED(result)) {
|
||||
result = Do(txn);
|
||||
result = DoTransaction(txn);
|
||||
}
|
||||
// The transaction system (if any) has taken ownwership of txn
|
||||
NS_IF_RELEASE(txn);
|
||||
|
@ -1227,7 +1247,7 @@ nsEditor::SplitNode(nsIDOMNode * aNode,
|
|||
nsresult result = CreateTxnForSplitNode(aNode, aOffset, &txn);
|
||||
if (NS_SUCCEEDED(result))
|
||||
{
|
||||
result = Do(txn);
|
||||
result = DoTransaction(txn);
|
||||
if (NS_SUCCEEDED(result))
|
||||
{
|
||||
result = txn->GetNewNode(aNewLeftNode);
|
||||
|
@ -1288,7 +1308,7 @@ nsEditor::JoinNodes(nsIDOMNode * aLeftNode,
|
|||
JoinElementTxn *txn;
|
||||
result = CreateTxnForJoinNode(aLeftNode, aRightNode, &txn);
|
||||
if (NS_SUCCEEDED(result)) {
|
||||
result = Do(txn);
|
||||
result = DoTransaction(txn);
|
||||
}
|
||||
|
||||
// The transaction system (if any) has taken ownwership of txn
|
||||
|
@ -1334,7 +1354,7 @@ NS_IMETHODIMP nsEditor::DeleteNode(nsIDOMNode * aElement)
|
|||
DeleteElementTxn *txn;
|
||||
result = CreateTxnForDeleteElement(aElement, &txn);
|
||||
if (NS_SUCCEEDED(result)) {
|
||||
result = Do(txn);
|
||||
result = DoTransaction(txn);
|
||||
}
|
||||
|
||||
// The transaction system (if any) has taken ownwership of txn
|
||||
|
@ -2493,7 +2513,7 @@ NS_IMETHODIMP nsEditor::InsertTextIntoTextNodeImpl(const nsAString& aStringToIns
|
|||
|
||||
// XXX we may not need these view batches anymore. This is handled at a higher level now I believe
|
||||
BeginUpdateViewBatch();
|
||||
result = Do(txn);
|
||||
result = DoTransaction(txn);
|
||||
EndUpdateViewBatch();
|
||||
|
||||
mRangeUpdater.SelAdjInsertText(aTextNode, aOffset, aStringToInsert);
|
||||
|
@ -2713,7 +2733,7 @@ NS_IMETHODIMP nsEditor::DeleteText(nsIDOMCharacterData *aElement,
|
|||
}
|
||||
}
|
||||
|
||||
result = Do(txn);
|
||||
result = DoTransaction(txn);
|
||||
|
||||
// let listeners know what happened
|
||||
if (mActionListeners)
|
||||
|
@ -4300,85 +4320,96 @@ nsEditor::JoinNodeDeep(nsIDOMNode *aLeftNode,
|
|||
|
||||
nsresult nsEditor::BeginUpdateViewBatch()
|
||||
{
|
||||
NS_PRECONDITION(mUpdateCount>=0, "bad state");
|
||||
NS_PRECONDITION(mUpdateCount >= 0, "bad state");
|
||||
|
||||
nsCOMPtr<nsISelection>selection;
|
||||
nsresult rv = GetSelection(getter_AddRefs(selection));
|
||||
if (NS_SUCCEEDED(rv) && selection)
|
||||
{
|
||||
nsCOMPtr<nsISelectionPrivate>selPrivate(do_QueryInterface(selection));
|
||||
selPrivate->StartBatchChanges();
|
||||
}
|
||||
|
||||
if (nsnull!=mViewManager)
|
||||
if (0 == mUpdateCount)
|
||||
{
|
||||
if (0==mUpdateCount)
|
||||
// Turn off selection updates and notifications.
|
||||
|
||||
nsCOMPtr<nsISelection> selection;
|
||||
GetSelection(getter_AddRefs(selection));
|
||||
|
||||
if (selection)
|
||||
{
|
||||
mViewManager->BeginUpdateViewBatch();
|
||||
nsCOMPtr<nsIPresShell> presShell;
|
||||
rv = GetPresShell(getter_AddRefs(presShell));
|
||||
if (NS_SUCCEEDED(rv) && presShell)
|
||||
presShell->BeginReflowBatching();
|
||||
nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryInterface(selection));
|
||||
selPrivate->StartBatchChanges();
|
||||
}
|
||||
mUpdateCount++;
|
||||
|
||||
// Turn off view updating.
|
||||
|
||||
if (mViewManager)
|
||||
mViewManager->BeginUpdateViewBatch();
|
||||
|
||||
// Turn off reflow.
|
||||
|
||||
nsCOMPtr<nsIPresShell> presShell;
|
||||
GetPresShell(getter_AddRefs(presShell));
|
||||
|
||||
if (presShell)
|
||||
presShell->BeginReflowBatching();
|
||||
}
|
||||
|
||||
mUpdateCount++;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult nsEditor::EndUpdateViewBatch()
|
||||
{
|
||||
NS_PRECONDITION(mUpdateCount>0, "bad state");
|
||||
NS_PRECONDITION(mUpdateCount > 0, "bad state");
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsISelectionController> selCon = do_QueryReferent(mSelConWeak,&rv);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
if (!selCon)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsCOMPtr<nsIPresShell> ps = do_QueryReferent(mPresShellWeak);
|
||||
nsCOMPtr<nsICaret> caret;
|
||||
if (!ps)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
rv = ps->GetCaret(getter_AddRefs(caret));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
if (!caret)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (mViewManager)
|
||||
if (mUpdateCount <= 0)
|
||||
{
|
||||
mUpdateCount--;
|
||||
if (0==mUpdateCount)
|
||||
mUpdateCount = 0;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mUpdateCount--;
|
||||
|
||||
if (0 == mUpdateCount)
|
||||
{
|
||||
// Hide the caret with an StCaretHider. By the time it goes out
|
||||
// of scope and tries to show the caret, reflow and selection changed
|
||||
// notifications should've happened so the caret should have enough info
|
||||
// to draw at the correct position.
|
||||
|
||||
nsCOMPtr<nsICaret> caret;
|
||||
nsCOMPtr<nsIPresShell> presShell;
|
||||
GetPresShell(getter_AddRefs(presShell));
|
||||
|
||||
if (presShell)
|
||||
presShell->GetCaret(getter_AddRefs(caret));
|
||||
|
||||
StCaretHider caretHider(caret);
|
||||
|
||||
PRUint32 flags = 0;
|
||||
|
||||
GetFlags(&flags);
|
||||
|
||||
// Turn reflow back on.
|
||||
//
|
||||
// Make sure we enable reflowing before we call
|
||||
// mViewManager->EndUpdateViewBatch(). This will make sure that any
|
||||
// new updates caused by a reflow, that may happen during the
|
||||
// EndReflowBatching(), get included if we force a refresh during
|
||||
// the mViewManager->EndUpdateViewBatch() call.
|
||||
|
||||
if (presShell)
|
||||
{
|
||||
PRUint32 flags = 0;
|
||||
|
||||
rv = GetFlags(&flags);
|
||||
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
StCaretHider caretHider(caret);
|
||||
|
||||
// Make sure we enable reflowing before we call
|
||||
// mViewManager->EndUpdateViewBatch(). This will make sure that any
|
||||
// new updates caused by a reflow, that may happen during the
|
||||
// EndReflowBatching(), get included if we force a refresh during
|
||||
// the mViewManager->EndUpdateViewBatch() call.
|
||||
|
||||
PRBool forceReflow = PR_TRUE;
|
||||
|
||||
if (flags & nsIPlaintextEditor::eEditorUseAsyncUpdatesMask)
|
||||
forceReflow = PR_FALSE;
|
||||
|
||||
nsCOMPtr<nsIPresShell> presShell;
|
||||
rv = GetPresShell(getter_AddRefs(presShell));
|
||||
if (NS_SUCCEEDED(rv) && presShell)
|
||||
presShell->EndReflowBatching(forceReflow);
|
||||
presShell->EndReflowBatching(forceReflow);
|
||||
}
|
||||
|
||||
// Turn view updating back on.
|
||||
|
||||
if (mViewManager)
|
||||
{
|
||||
PRUint32 updateFlag = NS_VMREFRESH_IMMEDIATE;
|
||||
|
||||
if (flags & nsIPlaintextEditor::eEditorUseAsyncUpdatesMask)
|
||||
|
@ -4386,13 +4417,16 @@ nsresult nsEditor::EndUpdateViewBatch()
|
|||
|
||||
mViewManager->EndUpdateViewBatch(updateFlag);
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISelection>selection;
|
||||
nsresult selectionResult = GetSelection(getter_AddRefs(selection));
|
||||
if (NS_SUCCEEDED(selectionResult) && selection) {
|
||||
nsCOMPtr<nsISelectionPrivate>selPrivate(do_QueryInterface(selection));
|
||||
selPrivate->EndBatchChanges();
|
||||
// Turn selection updating and notifications back on.
|
||||
|
||||
nsCOMPtr<nsISelection>selection;
|
||||
GetSelection(getter_AddRefs(selection));
|
||||
|
||||
if (selection) {
|
||||
nsCOMPtr<nsISelectionPrivate>selPrivate(do_QueryInterface(selection));
|
||||
selPrivate->EndBatchChanges();
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -4439,7 +4473,7 @@ nsEditor::DeleteSelectionImpl(nsIEditor::EDirection aAction)
|
|||
}
|
||||
}
|
||||
|
||||
res = Do(txn);
|
||||
res = DoTransaction(txn);
|
||||
|
||||
if (mActionListeners)
|
||||
{
|
||||
|
|
|
@ -470,7 +470,7 @@ nsHTMLCSSUtils::SetCSSProperty(nsIDOMElement *aElement, nsIAtom * aProperty, con
|
|||
result = txn->DoTransaction();
|
||||
}
|
||||
else {
|
||||
result = mHTMLEditor->Do(txn);
|
||||
result = mHTMLEditor->DoTransaction(txn);
|
||||
}
|
||||
}
|
||||
// The transaction system (if any) has taken ownwership of txn
|
||||
|
@ -492,7 +492,7 @@ nsHTMLCSSUtils::RemoveCSSProperty(nsIDOMElement *aElement, nsIAtom * aProperty,
|
|||
result = txn->DoTransaction();
|
||||
}
|
||||
else {
|
||||
result = mHTMLEditor->Do(txn);
|
||||
result = mHTMLEditor->DoTransaction(txn);
|
||||
}
|
||||
}
|
||||
// The transaction system (if any) has taken ownwership of txn
|
||||
|
|
|
@ -768,7 +768,7 @@ nsHTMLEditor::SetDocumentTitle(const nsAString &aTitle)
|
|||
//Don't let Rules System change the selection
|
||||
nsAutoTxnsConserveSelection dontChangeSelection(this);
|
||||
|
||||
result = nsEditor::Do(txn);
|
||||
result = nsEditor::DoTransaction(txn);
|
||||
}
|
||||
// The transaction system (if any) has taken ownwership of txn
|
||||
NS_IF_RELEASE(txn);
|
||||
|
@ -3614,7 +3614,7 @@ nsHTMLEditor::RemoveStyleSheet(const nsAString &aURL)
|
|||
if (!txn) rv = NS_ERROR_NULL_POINTER;
|
||||
if (NS_SUCCEEDED(rv))
|
||||
{
|
||||
rv = Do(txn);
|
||||
rv = DoTransaction(txn);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
mLastStyleSheetURL.Truncate(); // forget it
|
||||
|
||||
|
@ -4293,7 +4293,7 @@ nsHTMLEditor::StyleSheetLoaded(nsICSSStyleSheet* aSheet, PRBool aNotify)
|
|||
if (!txn) rv = NS_ERROR_NULL_POINTER;
|
||||
if (NS_SUCCEEDED(rv))
|
||||
{
|
||||
rv = Do(txn);
|
||||
rv = DoTransaction(txn);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
{
|
||||
// Get the URI, then url spec from the sheet
|
||||
|
|
|
@ -1189,7 +1189,7 @@ nsTextEditRules::ReplaceNewlines(nsIDOMRange *aRange)
|
|||
res = mEditor->CreateTxnForDeleteText(textNode, offset, 1, (DeleteTextTxn**)&txn);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!txn) return NS_ERROR_OUT_OF_MEMORY;
|
||||
res = mEditor->Do(txn);
|
||||
res = mEditor->DoTransaction(txn);
|
||||
if (NS_FAILED(res)) return res;
|
||||
// The transaction system (if any) has taken ownwership of txn
|
||||
NS_IF_RELEASE(txn);
|
||||
|
|
|
@ -443,11 +443,127 @@ function PrintTxnList(txnList, prefixStr)
|
|||
|
||||
if (txn)
|
||||
{
|
||||
txn = txn.QueryInterface(Components.interfaces.nsPIEditorTransaction);
|
||||
desc = txn.txnDescription;
|
||||
try {
|
||||
txn = txn.QueryInterface(Components.interfaces.nsPIEditorTransaction);
|
||||
desc = txn.txnDescription;
|
||||
} catch(e) {
|
||||
desc = "UnknownTxnType";
|
||||
}
|
||||
}
|
||||
dump(prefixStr + "+ " + desc + "\n");
|
||||
PrintTxnList(txnList.getChildListForItem(i), prefixStr + "| ");
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------ 3rd Party Transaction Test ------------------------
|
||||
|
||||
|
||||
function sampleJSTransaction()
|
||||
{
|
||||
this.wrappedJSObject = this;
|
||||
}
|
||||
|
||||
sampleJSTransaction.prototype = {
|
||||
|
||||
isTransient: false,
|
||||
mStrData: "[Sample-JS-Transaction-Content]",
|
||||
mObject: null,
|
||||
mContainer: null,
|
||||
mOffset: null,
|
||||
|
||||
doTransaction: function()
|
||||
{
|
||||
if (this.mContainer.nodeName != "#text")
|
||||
{
|
||||
// We're not in a text node, so create one and
|
||||
// we'll just insert it at (mContainer, mOffset).
|
||||
|
||||
this.mObject = this.mContainer.ownerDocument.createTextNode(this.mStrData);
|
||||
}
|
||||
|
||||
this.redoTransaction();
|
||||
},
|
||||
|
||||
undoTransaction: function()
|
||||
{
|
||||
if (!this.mObject)
|
||||
this.mContainer.deleteData(this.mOffset, this.mStrData.length);
|
||||
else
|
||||
this.mContainer.removeChild(this.mObject);
|
||||
},
|
||||
|
||||
redoTransaction: function()
|
||||
{
|
||||
if (!this.mObject)
|
||||
this.mContainer.insertData(this.mOffset, this.mStrData);
|
||||
else
|
||||
this.insert_node_at_point(this.mObject, this.mContainer, this.mOffset);
|
||||
},
|
||||
|
||||
merge: function(aTxn)
|
||||
{
|
||||
// We don't do any merging!
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
QueryInterface: function(theUID, theResult)
|
||||
{
|
||||
if (theUID == Components.interfaces.nsITransaction ||
|
||||
theUID == Components.interfaces.nsISupports)
|
||||
return this;
|
||||
|
||||
return nsnull;
|
||||
},
|
||||
|
||||
insert_node_at_point: function(node, container, offset)
|
||||
{
|
||||
var childList = container.childNodes;
|
||||
|
||||
if (childList.length == 0 || offset >= childList.length)
|
||||
container.appendChild(node);
|
||||
else
|
||||
container.insertBefore(node, childList.item(offset));
|
||||
}
|
||||
}
|
||||
|
||||
function ExecuteJSTransactionViaTxmgr()
|
||||
{
|
||||
try {
|
||||
var editor = GetCurrentEditor();
|
||||
var txmgr = editor.transactionManager;
|
||||
txmgr = txmgr.QueryInterface(Components.interfaces.nsITransactionManager);
|
||||
|
||||
var selection = editor.selection;
|
||||
var range = selection.getRangeAt(0);
|
||||
|
||||
var txn = new sampleJSTransaction();
|
||||
|
||||
txn.mContainer = range.startContainer;
|
||||
txn.mOffset = range.startOffset;
|
||||
|
||||
txmgr.doTransaction(txn);
|
||||
} catch (e) {
|
||||
dump("ExecuteJSTransactionViaTxmgr() failed!");
|
||||
}
|
||||
}
|
||||
|
||||
function ExecuteJSTransactionViaEditor()
|
||||
{
|
||||
try {
|
||||
var editor = GetCurrentEditor();
|
||||
|
||||
var selection = editor.selection;
|
||||
var range = selection.getRangeAt(0);
|
||||
|
||||
var txn = new sampleJSTransaction();
|
||||
|
||||
txn.mContainer = range.startContainer;
|
||||
txn.mOffset = range.startOffset;
|
||||
|
||||
editor.doTransaction(txn);
|
||||
} catch (e) {
|
||||
dump("ExecuteJSTransactionViaEditor() failed!");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -913,6 +913,10 @@
|
|||
oncommand="DumpUndoStack()"/>
|
||||
<menuitem label="&dumpRedoStack.label;"
|
||||
oncommand="DumpRedoStack()"/>
|
||||
<menuitem label="&executeJSTransactionViaTxmgr.label;"
|
||||
oncommand="ExecuteJSTransactionViaTxmgr()"/>
|
||||
<menuitem label="&executeJSTransactionViaEditor.label;"
|
||||
oncommand="ExecuteJSTransactionViaEditor()"/>
|
||||
<menuseparator />
|
||||
<menuitem label="&startLogCmd.label;"
|
||||
oncommand="EditorStartLog()"/>
|
||||
|
|
|
@ -482,6 +482,8 @@
|
|||
<!ENTITY runUnitTestsCmd.label "Run Unit Tests">
|
||||
<!ENTITY dumpUndoStack.label "Dump Undo Stack">
|
||||
<!ENTITY dumpRedoStack.label "Dump Redo Stack">
|
||||
<!ENTITY executeJSTransactionViaTxmgr.label "Execute JS Transaction Via Transaction Manager">
|
||||
<!ENTITY executeJSTransactionViaEditor.label "Execute JS Transaction Via Editor">
|
||||
<!ENTITY startLogCmd.label "Start Log">
|
||||
<!ENTITY stopLogCmd.label "Stop Log">
|
||||
<!ENTITY runLogCmd.label "Run Log">
|
||||
|
|
Загрузка…
Ссылка в новой задаче