зеркало из https://github.com/mozilla/pjs.git
fix for 48297: ome edit operations not scroling selection into view; r=fm
This commit is contained in:
Родитель
6848328c7f
Коммит
55e88dbb67
|
@ -786,6 +786,8 @@ nsEditor::nsEditor()
|
|||
, mEditorObservers(nsnull)
|
||||
, mDocDirtyState(-1)
|
||||
, mDocWeak(nsnull)
|
||||
, mAction(nsnull)
|
||||
, mDirection(eNone)
|
||||
{
|
||||
//initialize member variables here
|
||||
NS_INIT_REFCNT();
|
||||
|
@ -1096,8 +1098,6 @@ nsEditor::Undo(PRUint32 aCount)
|
|||
|
||||
nsAutoRules beginRulesSniffing(this, kOpUndo, nsIEditor::eNone);
|
||||
|
||||
BeginUpdateViewBatch();
|
||||
|
||||
if ((nsITransactionManager *)nsnull!=mTxnMgr.get())
|
||||
{
|
||||
PRUint32 i=0;
|
||||
|
@ -1113,7 +1113,6 @@ nsEditor::Undo(PRUint32 aCount)
|
|||
}
|
||||
}
|
||||
|
||||
EndUpdateViewBatch();
|
||||
NotifyEditorObservers();
|
||||
return result;
|
||||
}
|
||||
|
@ -1142,7 +1141,6 @@ nsEditor::Redo(PRUint32 aCount)
|
|||
nsresult result = NS_OK;
|
||||
|
||||
nsAutoRules beginRulesSniffing(this, kOpRedo, nsIEditor::eNone);
|
||||
BeginUpdateViewBatch();
|
||||
|
||||
if ((nsITransactionManager *)nsnull!=mTxnMgr.get())
|
||||
{
|
||||
|
@ -1159,7 +1157,6 @@ nsEditor::Redo(PRUint32 aCount)
|
|||
}
|
||||
}
|
||||
|
||||
EndUpdateViewBatch();
|
||||
NotifyEditorObservers();
|
||||
return result;
|
||||
}
|
||||
|
@ -1244,6 +1241,11 @@ nsEditor::EndPlaceHolderTransaction()
|
|||
{
|
||||
// time to turn off the batch
|
||||
EndUpdateViewBatch();
|
||||
// make sure selection is in view
|
||||
nsCOMPtr<nsISelectionController> selCon;
|
||||
if (NS_SUCCEEDED(GetSelectionController(getter_AddRefs(selCon))) && selCon)
|
||||
selCon->ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL, nsISelectionController::SELECTION_FOCUS_REGION);
|
||||
|
||||
if (mSelState)
|
||||
{
|
||||
// we saved the selection state, but never got to hand it to placeholder
|
||||
|
@ -2537,15 +2539,19 @@ nsEditor::GetRootElement(nsIDOMElement **aBodyElement)
|
|||
NS_IMETHODIMP
|
||||
nsEditor::StartOperation(PRInt32 opID, nsIEditor::EDirection aDirection)
|
||||
{
|
||||
mAction = opID;
|
||||
mDirection = aDirection;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
/** All editor operations which alter the doc should be followed
|
||||
* with a call to EndOperation, naming the action and direction */
|
||||
* with a call to EndOperation */
|
||||
NS_IMETHODIMP
|
||||
nsEditor::EndOperation(PRInt32 opID, nsIEditor::EDirection aDirection)
|
||||
nsEditor::EndOperation()
|
||||
{
|
||||
mAction = nsnull;
|
||||
mDirection = eNone;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -5248,7 +5254,7 @@ nsEditor::SetShouldTxnSetSelection(PRBool aShould)
|
|||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsEditor::DeleteSelectionImpl(EDirection aAction)
|
||||
nsEditor::DeleteSelectionImpl(nsIEditor::EDirection aAction)
|
||||
{
|
||||
nsresult res;
|
||||
|
||||
|
|
|
@ -480,8 +480,8 @@ public:
|
|||
NS_IMETHOD StartOperation(PRInt32 opID, nsIEditor::EDirection aDirection);
|
||||
|
||||
/** All editor operations which alter the doc should be followed
|
||||
* with a call to EndOperation, naming the action and direction */
|
||||
NS_IMETHOD EndOperation(PRInt32 opID, nsIEditor::EDirection aDirection);
|
||||
* with a call to EndOperation */
|
||||
NS_IMETHOD EndOperation();
|
||||
|
||||
/** return the string that represents text nodes in the content tree */
|
||||
static nsresult GetTextNodeTag(nsString& aOutString);
|
||||
|
@ -755,15 +755,17 @@ protected:
|
|||
nsSelectionState *mSavedSel; // cached selection for nsAutoSelectionReset
|
||||
PRBool mShouldTxnSetSelection; // turn off for conservative selection adjustment by txns
|
||||
nsCOMPtr<nsIDOMElement> mBodyElement; // cached body node
|
||||
//
|
||||
PRInt32 mAction; // the current editor action
|
||||
EDirection mDirection; // the current direction of editor action
|
||||
|
||||
// data necessary to build IME transactions
|
||||
//
|
||||
PRBool mInIMEMode; // are we inside an IME composition?
|
||||
nsIPrivateTextRangeList* mIMETextRangeList; // IME special selection ranges
|
||||
nsCOMPtr<nsIDOMCharacterData> mIMETextNode; // current IME text node
|
||||
PRUint32 mIMETextOffset; // offset in text node where IME comp string begins
|
||||
PRUint32 mIMEBufferLength; // current length of IME comp string
|
||||
|
||||
// various listeners
|
||||
nsVoidArray* mActionListeners; // listens to all low level actions on the doc
|
||||
nsVoidArray* mEditorObservers; // just notify once per high level change
|
||||
nsCOMPtr<nsISupportsArray> mDocStateListeners;// listen to overall doc state (dirty or not, just created, etc)
|
||||
|
@ -777,6 +779,7 @@ protected:
|
|||
friend PRBool NSCanUnload(nsISupports* serviceMgr);
|
||||
friend class nsAutoTxnsConserveSelection;
|
||||
friend class nsAutoSelectionReset;
|
||||
friend class nsAutoRules;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -87,14 +87,25 @@ class nsAutoRules
|
|||
public:
|
||||
|
||||
nsAutoRules(nsEditor *ed, PRInt32 action, nsIEditor::EDirection aDirection) :
|
||||
mEd(ed), mAction(action), mDirection(aDirection)
|
||||
{if (mEd) mEd->StartOperation(mAction, mDirection);}
|
||||
~nsAutoRules() {if (mEd) mEd->EndOperation(mAction, mDirection);}
|
||||
mEd(ed), mDoNothing(PR_FALSE)
|
||||
{
|
||||
if (mEd && !mEd->mAction) // mAction will already be set if this is nested call
|
||||
{
|
||||
mEd->StartOperation(action, aDirection);
|
||||
}
|
||||
else mDoNothing = PR_TRUE; // nested calls will end up here
|
||||
}
|
||||
~nsAutoRules()
|
||||
{
|
||||
if (mEd && !mDoNothing)
|
||||
{
|
||||
mEd->EndOperation();
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
nsEditor *mEd;
|
||||
PRInt32 mAction;
|
||||
nsIEditor::EDirection mDirection;
|
||||
PRBool mDoNothing;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -4503,7 +4503,7 @@ nsHTMLEditor::Undo(PRUint32 aCount)
|
|||
ForceCompositionEnd();
|
||||
nsresult result = NS_OK;
|
||||
|
||||
BeginUpdateViewBatch();
|
||||
nsAutoRules beginRulesSniffing(this, kOpUndo, nsIEditor::eNone);
|
||||
|
||||
nsTextRulesInfo ruleInfo(nsTextEditRules::kUndo);
|
||||
nsCOMPtr<nsIDOMSelection> selection;
|
||||
|
@ -4517,8 +4517,6 @@ nsHTMLEditor::Undo(PRUint32 aCount)
|
|||
result = mRules->DidDoAction(selection, &ruleInfo, result);
|
||||
}
|
||||
|
||||
EndUpdateViewBatch();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -4528,7 +4526,7 @@ nsHTMLEditor::Redo(PRUint32 aCount)
|
|||
{
|
||||
nsresult result = NS_OK;
|
||||
|
||||
BeginUpdateViewBatch();
|
||||
nsAutoRules beginRulesSniffing(this, kOpRedo, nsIEditor::eNone);
|
||||
|
||||
nsTextRulesInfo ruleInfo(nsTextEditRules::kRedo);
|
||||
nsCOMPtr<nsIDOMSelection> selection;
|
||||
|
@ -4542,8 +4540,6 @@ nsHTMLEditor::Redo(PRUint32 aCount)
|
|||
result = mRules->DidDoAction(selection, &ruleInfo, result);
|
||||
}
|
||||
|
||||
EndUpdateViewBatch();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -5906,23 +5902,27 @@ void nsHTMLEditor::ApplyStyleSheetToPresShellDocument(nsICSSStyleSheet* aSheet,
|
|||
NS_IMETHODIMP
|
||||
nsHTMLEditor::StartOperation(PRInt32 opID, nsIEditor::EDirection aDirection)
|
||||
{
|
||||
if (! ((opID==kOpInsertText) || (opID==kOpInsertIMEText)) )
|
||||
nsEditor::StartOperation(opID, aDirection); // will set mAction, mDirection
|
||||
if (! ((mAction==kOpInsertText) || (mAction==kOpInsertIMEText)) )
|
||||
ClearInlineStylesCache();
|
||||
if (mRules) return mRules->BeforeEdit(opID, aDirection);
|
||||
if (mRules) return mRules->BeforeEdit(mAction, mDirection);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
/** All editor operations which alter the doc should be followed
|
||||
* with a call to EndOperation, naming the action and direction */
|
||||
* with a call to EndOperation */
|
||||
NS_IMETHODIMP
|
||||
nsHTMLEditor::EndOperation(PRInt32 opID, nsIEditor::EDirection aDirection)
|
||||
nsHTMLEditor::EndOperation()
|
||||
{
|
||||
if (! ((opID==kOpInsertText) || (opID==kOpInsertIMEText)) )
|
||||
// post processing
|
||||
if (! ((mAction==kOpInsertText) || (mAction==kOpInsertIMEText) || (mAction==kOpIgnore)) )
|
||||
ClearInlineStylesCache();
|
||||
if (mRules) return mRules->AfterEdit(opID, aDirection);
|
||||
return NS_OK;
|
||||
}
|
||||
nsresult res = NS_OK;
|
||||
if (mRules) res = mRules->AfterEdit(mAction, mDirection);
|
||||
nsEditor::EndOperation(); // will clear mAction, mDirection
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
PRBool
|
||||
|
|
|
@ -288,8 +288,8 @@ public:
|
|||
NS_IMETHOD StartOperation(PRInt32 opID, nsIEditor::EDirection aDirection);
|
||||
|
||||
/** All editor operations which alter the doc should be followed
|
||||
* with a call to EndOperation, naming the action and direction */
|
||||
NS_IMETHOD EndOperation(PRInt32 opID, nsIEditor::EDirection aDirection);
|
||||
* with a call to EndOperation */
|
||||
NS_IMETHOD EndOperation();
|
||||
|
||||
/** returns PR_TRUE if aParentTag can contain a child of type aChildTag */
|
||||
virtual PRBool TagCanContainTag(const nsString &aParentTag, const nsString &aChildTag);
|
||||
|
@ -496,7 +496,7 @@ protected:
|
|||
|
||||
/* small utility routine to test the eEditorReadonly bit */
|
||||
PRBool IsModifiable();
|
||||
|
||||
|
||||
/* helpers for block transformations */
|
||||
nsresult MakeDefinitionItem(const nsString& aItemType);
|
||||
nsresult InsertBasicBlock(const nsString& aBlockType);
|
||||
|
|
|
@ -786,6 +786,8 @@ nsEditor::nsEditor()
|
|||
, mEditorObservers(nsnull)
|
||||
, mDocDirtyState(-1)
|
||||
, mDocWeak(nsnull)
|
||||
, mAction(nsnull)
|
||||
, mDirection(eNone)
|
||||
{
|
||||
//initialize member variables here
|
||||
NS_INIT_REFCNT();
|
||||
|
@ -1096,8 +1098,6 @@ nsEditor::Undo(PRUint32 aCount)
|
|||
|
||||
nsAutoRules beginRulesSniffing(this, kOpUndo, nsIEditor::eNone);
|
||||
|
||||
BeginUpdateViewBatch();
|
||||
|
||||
if ((nsITransactionManager *)nsnull!=mTxnMgr.get())
|
||||
{
|
||||
PRUint32 i=0;
|
||||
|
@ -1113,7 +1113,6 @@ nsEditor::Undo(PRUint32 aCount)
|
|||
}
|
||||
}
|
||||
|
||||
EndUpdateViewBatch();
|
||||
NotifyEditorObservers();
|
||||
return result;
|
||||
}
|
||||
|
@ -1142,7 +1141,6 @@ nsEditor::Redo(PRUint32 aCount)
|
|||
nsresult result = NS_OK;
|
||||
|
||||
nsAutoRules beginRulesSniffing(this, kOpRedo, nsIEditor::eNone);
|
||||
BeginUpdateViewBatch();
|
||||
|
||||
if ((nsITransactionManager *)nsnull!=mTxnMgr.get())
|
||||
{
|
||||
|
@ -1159,7 +1157,6 @@ nsEditor::Redo(PRUint32 aCount)
|
|||
}
|
||||
}
|
||||
|
||||
EndUpdateViewBatch();
|
||||
NotifyEditorObservers();
|
||||
return result;
|
||||
}
|
||||
|
@ -1244,6 +1241,11 @@ nsEditor::EndPlaceHolderTransaction()
|
|||
{
|
||||
// time to turn off the batch
|
||||
EndUpdateViewBatch();
|
||||
// make sure selection is in view
|
||||
nsCOMPtr<nsISelectionController> selCon;
|
||||
if (NS_SUCCEEDED(GetSelectionController(getter_AddRefs(selCon))) && selCon)
|
||||
selCon->ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL, nsISelectionController::SELECTION_FOCUS_REGION);
|
||||
|
||||
if (mSelState)
|
||||
{
|
||||
// we saved the selection state, but never got to hand it to placeholder
|
||||
|
@ -2537,15 +2539,19 @@ nsEditor::GetRootElement(nsIDOMElement **aBodyElement)
|
|||
NS_IMETHODIMP
|
||||
nsEditor::StartOperation(PRInt32 opID, nsIEditor::EDirection aDirection)
|
||||
{
|
||||
mAction = opID;
|
||||
mDirection = aDirection;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
/** All editor operations which alter the doc should be followed
|
||||
* with a call to EndOperation, naming the action and direction */
|
||||
* with a call to EndOperation */
|
||||
NS_IMETHODIMP
|
||||
nsEditor::EndOperation(PRInt32 opID, nsIEditor::EDirection aDirection)
|
||||
nsEditor::EndOperation()
|
||||
{
|
||||
mAction = nsnull;
|
||||
mDirection = eNone;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -5248,7 +5254,7 @@ nsEditor::SetShouldTxnSetSelection(PRBool aShould)
|
|||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsEditor::DeleteSelectionImpl(EDirection aAction)
|
||||
nsEditor::DeleteSelectionImpl(nsIEditor::EDirection aAction)
|
||||
{
|
||||
nsresult res;
|
||||
|
||||
|
|
|
@ -480,8 +480,8 @@ public:
|
|||
NS_IMETHOD StartOperation(PRInt32 opID, nsIEditor::EDirection aDirection);
|
||||
|
||||
/** All editor operations which alter the doc should be followed
|
||||
* with a call to EndOperation, naming the action and direction */
|
||||
NS_IMETHOD EndOperation(PRInt32 opID, nsIEditor::EDirection aDirection);
|
||||
* with a call to EndOperation */
|
||||
NS_IMETHOD EndOperation();
|
||||
|
||||
/** return the string that represents text nodes in the content tree */
|
||||
static nsresult GetTextNodeTag(nsString& aOutString);
|
||||
|
@ -755,15 +755,17 @@ protected:
|
|||
nsSelectionState *mSavedSel; // cached selection for nsAutoSelectionReset
|
||||
PRBool mShouldTxnSetSelection; // turn off for conservative selection adjustment by txns
|
||||
nsCOMPtr<nsIDOMElement> mBodyElement; // cached body node
|
||||
//
|
||||
PRInt32 mAction; // the current editor action
|
||||
EDirection mDirection; // the current direction of editor action
|
||||
|
||||
// data necessary to build IME transactions
|
||||
//
|
||||
PRBool mInIMEMode; // are we inside an IME composition?
|
||||
nsIPrivateTextRangeList* mIMETextRangeList; // IME special selection ranges
|
||||
nsCOMPtr<nsIDOMCharacterData> mIMETextNode; // current IME text node
|
||||
PRUint32 mIMETextOffset; // offset in text node where IME comp string begins
|
||||
PRUint32 mIMEBufferLength; // current length of IME comp string
|
||||
|
||||
// various listeners
|
||||
nsVoidArray* mActionListeners; // listens to all low level actions on the doc
|
||||
nsVoidArray* mEditorObservers; // just notify once per high level change
|
||||
nsCOMPtr<nsISupportsArray> mDocStateListeners;// listen to overall doc state (dirty or not, just created, etc)
|
||||
|
@ -777,6 +779,7 @@ protected:
|
|||
friend PRBool NSCanUnload(nsISupports* serviceMgr);
|
||||
friend class nsAutoTxnsConserveSelection;
|
||||
friend class nsAutoSelectionReset;
|
||||
friend class nsAutoRules;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -87,14 +87,25 @@ class nsAutoRules
|
|||
public:
|
||||
|
||||
nsAutoRules(nsEditor *ed, PRInt32 action, nsIEditor::EDirection aDirection) :
|
||||
mEd(ed), mAction(action), mDirection(aDirection)
|
||||
{if (mEd) mEd->StartOperation(mAction, mDirection);}
|
||||
~nsAutoRules() {if (mEd) mEd->EndOperation(mAction, mDirection);}
|
||||
mEd(ed), mDoNothing(PR_FALSE)
|
||||
{
|
||||
if (mEd && !mEd->mAction) // mAction will already be set if this is nested call
|
||||
{
|
||||
mEd->StartOperation(action, aDirection);
|
||||
}
|
||||
else mDoNothing = PR_TRUE; // nested calls will end up here
|
||||
}
|
||||
~nsAutoRules()
|
||||
{
|
||||
if (mEd && !mDoNothing)
|
||||
{
|
||||
mEd->EndOperation();
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
nsEditor *mEd;
|
||||
PRInt32 mAction;
|
||||
nsIEditor::EDirection mDirection;
|
||||
PRBool mDoNothing;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -4503,7 +4503,7 @@ nsHTMLEditor::Undo(PRUint32 aCount)
|
|||
ForceCompositionEnd();
|
||||
nsresult result = NS_OK;
|
||||
|
||||
BeginUpdateViewBatch();
|
||||
nsAutoRules beginRulesSniffing(this, kOpUndo, nsIEditor::eNone);
|
||||
|
||||
nsTextRulesInfo ruleInfo(nsTextEditRules::kUndo);
|
||||
nsCOMPtr<nsIDOMSelection> selection;
|
||||
|
@ -4517,8 +4517,6 @@ nsHTMLEditor::Undo(PRUint32 aCount)
|
|||
result = mRules->DidDoAction(selection, &ruleInfo, result);
|
||||
}
|
||||
|
||||
EndUpdateViewBatch();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -4528,7 +4526,7 @@ nsHTMLEditor::Redo(PRUint32 aCount)
|
|||
{
|
||||
nsresult result = NS_OK;
|
||||
|
||||
BeginUpdateViewBatch();
|
||||
nsAutoRules beginRulesSniffing(this, kOpRedo, nsIEditor::eNone);
|
||||
|
||||
nsTextRulesInfo ruleInfo(nsTextEditRules::kRedo);
|
||||
nsCOMPtr<nsIDOMSelection> selection;
|
||||
|
@ -4542,8 +4540,6 @@ nsHTMLEditor::Redo(PRUint32 aCount)
|
|||
result = mRules->DidDoAction(selection, &ruleInfo, result);
|
||||
}
|
||||
|
||||
EndUpdateViewBatch();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -5906,23 +5902,27 @@ void nsHTMLEditor::ApplyStyleSheetToPresShellDocument(nsICSSStyleSheet* aSheet,
|
|||
NS_IMETHODIMP
|
||||
nsHTMLEditor::StartOperation(PRInt32 opID, nsIEditor::EDirection aDirection)
|
||||
{
|
||||
if (! ((opID==kOpInsertText) || (opID==kOpInsertIMEText)) )
|
||||
nsEditor::StartOperation(opID, aDirection); // will set mAction, mDirection
|
||||
if (! ((mAction==kOpInsertText) || (mAction==kOpInsertIMEText)) )
|
||||
ClearInlineStylesCache();
|
||||
if (mRules) return mRules->BeforeEdit(opID, aDirection);
|
||||
if (mRules) return mRules->BeforeEdit(mAction, mDirection);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
/** All editor operations which alter the doc should be followed
|
||||
* with a call to EndOperation, naming the action and direction */
|
||||
* with a call to EndOperation */
|
||||
NS_IMETHODIMP
|
||||
nsHTMLEditor::EndOperation(PRInt32 opID, nsIEditor::EDirection aDirection)
|
||||
nsHTMLEditor::EndOperation()
|
||||
{
|
||||
if (! ((opID==kOpInsertText) || (opID==kOpInsertIMEText)) )
|
||||
// post processing
|
||||
if (! ((mAction==kOpInsertText) || (mAction==kOpInsertIMEText) || (mAction==kOpIgnore)) )
|
||||
ClearInlineStylesCache();
|
||||
if (mRules) return mRules->AfterEdit(opID, aDirection);
|
||||
return NS_OK;
|
||||
}
|
||||
nsresult res = NS_OK;
|
||||
if (mRules) res = mRules->AfterEdit(mAction, mDirection);
|
||||
nsEditor::EndOperation(); // will clear mAction, mDirection
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
PRBool
|
||||
|
|
|
@ -288,8 +288,8 @@ public:
|
|||
NS_IMETHOD StartOperation(PRInt32 opID, nsIEditor::EDirection aDirection);
|
||||
|
||||
/** All editor operations which alter the doc should be followed
|
||||
* with a call to EndOperation, naming the action and direction */
|
||||
NS_IMETHOD EndOperation(PRInt32 opID, nsIEditor::EDirection aDirection);
|
||||
* with a call to EndOperation */
|
||||
NS_IMETHOD EndOperation();
|
||||
|
||||
/** returns PR_TRUE if aParentTag can contain a child of type aChildTag */
|
||||
virtual PRBool TagCanContainTag(const nsString &aParentTag, const nsString &aChildTag);
|
||||
|
@ -496,7 +496,7 @@ protected:
|
|||
|
||||
/* small utility routine to test the eEditorReadonly bit */
|
||||
PRBool IsModifiable();
|
||||
|
||||
|
||||
/* helpers for block transformations */
|
||||
nsresult MakeDefinitionItem(const nsString& aItemType);
|
||||
nsresult InsertBasicBlock(const nsString& aBlockType);
|
||||
|
|
Загрузка…
Ссылка в новой задаче