mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 06:11:37 +00:00
Merge mozilla-central into cedar
This commit is contained in:
commit
f2fe50481f
@ -123,6 +123,10 @@ https://expired.example.com:443 privileged,cert=expired
|
||||
https://requestclientcert.example.com:443 privileged,clientauth=request
|
||||
https://requireclientcert.example.com:443 privileged,clientauth=require
|
||||
|
||||
# This is here so that we don't load the default live bookmark over
|
||||
# the network in every test suite.
|
||||
http://fxfeeds.mozilla.com:80
|
||||
|
||||
#
|
||||
# These are subdomains of <ält.example.org>.
|
||||
#
|
||||
|
@ -285,6 +285,8 @@ CONFIG_STATUS_DEPS := \
|
||||
$(TOPSRCDIR)/.mozconfig.mk \
|
||||
$(wildcard $(TOPSRCDIR)/nsprpub/configure) \
|
||||
$(wildcard $(TOPSRCDIR)/config/milestone.txt) \
|
||||
$(wildcard $(TOPSRCDIR)/js/src/config/milestone.txt) \
|
||||
$(wildcard $(TOPSRCDIR)/browser/config/version.txt) \
|
||||
$(wildcard $(addsuffix confvars.sh,$(wildcard $(TOPSRCDIR)/*/))) \
|
||||
$(NULL)
|
||||
|
||||
|
@ -4124,7 +4124,7 @@ nsDocument::LookupImageElement(const nsAString& aId)
|
||||
if (aId.IsEmpty())
|
||||
return nsnull;
|
||||
|
||||
nsIdentifierMapEntry *entry = mIdentifierMap.PutEntry(aId);
|
||||
nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(aId);
|
||||
return entry ? entry->GetImageIdElement() : nsnull;
|
||||
}
|
||||
|
||||
|
@ -854,6 +854,20 @@ nsFrameLoader::Show(PRInt32 marginWidth, PRInt32 marginHeight,
|
||||
|
||||
doc->SetDesignMode(NS_LITERAL_STRING("off"));
|
||||
doc->SetDesignMode(NS_LITERAL_STRING("on"));
|
||||
} else {
|
||||
// Re-initialie the presentation for contenteditable documents
|
||||
nsCOMPtr<nsIEditorDocShell> editorDocshell = do_QueryInterface(mDocShell);
|
||||
if (editorDocshell) {
|
||||
PRBool editable = PR_FALSE,
|
||||
hasEditingSession = PR_FALSE;
|
||||
editorDocshell->GetEditable(&editable);
|
||||
editorDocshell->GetHasEditingSession(&hasEditingSession);
|
||||
nsCOMPtr<nsIEditor> editor;
|
||||
editorDocshell->GetEditor(getter_AddRefs(editor));
|
||||
if (editable && hasEditingSession && editor) {
|
||||
editor->PostCreate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1450,18 +1450,6 @@ nsresult nsRange::CutContents(nsIDOMDocumentFragment** aFragment)
|
||||
}
|
||||
}
|
||||
|
||||
// XXX_kin: At this point we should be checking for the case
|
||||
// XXX_kin: where we have 2 adjacent text nodes left, each
|
||||
// XXX_kin: containing one of the range end points. The spec
|
||||
// XXX_kin: says the 2 nodes should be merged in that case,
|
||||
// XXX_kin: and to use Normalize() to do the merging, but
|
||||
// XXX_kin: calling Normalize() on the common parent to accomplish
|
||||
// XXX_kin: this might also normalize nodes that are outside the
|
||||
// XXX_kin: range but under the common parent. Need to verify
|
||||
// XXX_kin: with the range commitee members that this was the
|
||||
// XXX_kin: desired behavior. For now we don't merge anything!
|
||||
// XXX ajvincent Filed as https://bugzilla.mozilla.org/show_bug.cgi?id=401276
|
||||
|
||||
rv = CollapseRangeAfterDelete(this);
|
||||
if (NS_SUCCEEDED(rv) && aFragment) {
|
||||
NS_ADDREF(*aFragment = retval);
|
||||
|
@ -2320,7 +2320,6 @@ nsCanvasRenderingContext2D::SetFont(const nsAString& font)
|
||||
language,
|
||||
fontStyle->mFont.sizeAdjust,
|
||||
fontStyle->mFont.systemFont,
|
||||
fontStyle->mFont.familyNameQuirks,
|
||||
printerFont,
|
||||
fontStyle->mFont.featureSettings,
|
||||
fontStyle->mFont.languageOverride);
|
||||
|
@ -194,7 +194,6 @@ MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
|
||||
if (value && value->Type() == nsAttrValue::eString &&
|
||||
!value->IsEmptyString()) {
|
||||
font.mFamily.SetStringValue(value->GetStringValue(), eCSSUnit_Families);
|
||||
font.mFamilyFromHTML = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1231,7 +1231,7 @@ nsTextEditorState::PrepareEditor(const nsAString *aValue)
|
||||
nsCxPusher pusher;
|
||||
pusher.PushNull();
|
||||
|
||||
rv = newEditor->Init(domdoc, shell, GetRootNode(), mSelCon, editorFlags);
|
||||
rv = newEditor->Init(domdoc, GetRootNode(), mSelCon, editorFlags);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
|
@ -403,7 +403,6 @@ nsMathMLElement::MapMathMLAttributesInto(const nsMappedAttributes* aAttributes,
|
||||
aData->mFontData->mFamily.GetUnit() == eCSSUnit_Null) {
|
||||
aData->mFontData->mFamily.SetStringValue(value->GetStringValue(),
|
||||
eCSSUnit_Families);
|
||||
aData->mFontData->mFamilyFromHTML = PR_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10990,8 +10990,10 @@ NS_IMETHODIMP nsNavigator::GetGeolocation(nsIDOMGeoGeolocation **_retval)
|
||||
if (!mGeolocation)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (NS_FAILED(mGeolocation->Init(contentDOMWindow)))
|
||||
if (NS_FAILED(mGeolocation->Init(contentDOMWindow))) {
|
||||
mGeolocation = nsnull;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_ADDREF(*_retval = mGeolocation);
|
||||
return NS_OK;
|
||||
|
@ -68,8 +68,8 @@ public:
|
||||
const nsAString &aCountryCode,
|
||||
const nsAString &aPostalCode);
|
||||
|
||||
private:
|
||||
~nsGeoPositionAddress();
|
||||
private:
|
||||
const nsString mStreetNumber;
|
||||
const nsString mStreet;
|
||||
const nsString mPremises;
|
||||
@ -127,6 +127,10 @@ public:
|
||||
nsIDOMGeoPositionAddress *aAddress,
|
||||
DOMTimeStamp aTimestamp);
|
||||
|
||||
void SetAddress(nsIDOMGeoPositionAddress *address) {
|
||||
mAddress = address;
|
||||
}
|
||||
|
||||
private:
|
||||
~nsGeoPosition();
|
||||
long long mTimestamp;
|
||||
|
@ -461,16 +461,9 @@ nsGeolocationRequest::SendLocation(nsIDOMGeoPosition* aPosition)
|
||||
}
|
||||
|
||||
void
|
||||
nsGeolocationRequest::Update(nsIDOMGeoPosition* aPosition, PRBool isBetter)
|
||||
nsGeolocationRequest::Update(nsIDOMGeoPosition* aPosition)
|
||||
{
|
||||
// Only dispatch callbacks if this is the first position for this request, or
|
||||
// if the accuracy is as good or improving.
|
||||
//
|
||||
// This ensures that all listeners get at least one position callback, particularly
|
||||
// in the case when newly detected positions are all less accurate than the cached one.
|
||||
//
|
||||
// Fixes bug 596481
|
||||
if (mIsFirstUpdate || isBetter) {
|
||||
if (mIsFirstUpdate) {
|
||||
mIsFirstUpdate = PR_FALSE;
|
||||
nsCOMPtr<nsIRunnable> ev = new RequestSendLocationEvent(aPosition, this);
|
||||
NS_DispatchToMainThread(ev);
|
||||
@ -658,100 +651,13 @@ nsGeolocationService::Observe(nsISupports* aSubject,
|
||||
NS_IMETHODIMP
|
||||
nsGeolocationService::Update(nsIDOMGeoPosition *aSomewhere)
|
||||
{
|
||||
// here we have to determine this aSomewhere is a "better"
|
||||
// position than any previously recv'ed.
|
||||
|
||||
PRBool isBetter = IsBetterPosition(aSomewhere);
|
||||
if (isBetter) {
|
||||
SetCachedPosition(aSomewhere);
|
||||
}
|
||||
SetCachedPosition(aSomewhere);
|
||||
|
||||
for (PRUint32 i = 0; i< mGeolocators.Length(); i++)
|
||||
mGeolocators[i]->Update(aSomewhere, isBetter);
|
||||
mGeolocators[i]->Update(aSomewhere);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsGeolocationService::IsBetterPosition(nsIDOMGeoPosition *aSomewhere)
|
||||
{
|
||||
if (!aSomewhere)
|
||||
return PR_FALSE;
|
||||
|
||||
nsRefPtr<nsGeolocationService> geoService = nsGeolocationService::GetInstance();
|
||||
if (!geoService)
|
||||
return PR_FALSE;
|
||||
|
||||
nsCOMPtr<nsIDOMGeoPosition> lastPosition = geoService->GetCachedPosition();
|
||||
if (!lastPosition)
|
||||
return PR_TRUE;
|
||||
|
||||
nsresult rv;
|
||||
DOMTimeStamp oldTime;
|
||||
rv = lastPosition->GetTimestamp(&oldTime);
|
||||
NS_ENSURE_SUCCESS(rv, PR_FALSE);
|
||||
|
||||
nsCOMPtr<nsIDOMGeoPositionCoords> coords;
|
||||
lastPosition->GetCoords(getter_AddRefs(coords));
|
||||
if (!coords)
|
||||
return PR_FALSE;
|
||||
|
||||
double oldAccuracy;
|
||||
rv = coords->GetAccuracy(&oldAccuracy);
|
||||
NS_ENSURE_SUCCESS(rv, PR_FALSE);
|
||||
|
||||
double oldLat, oldLon;
|
||||
rv = coords->GetLongitude(&oldLon);
|
||||
NS_ENSURE_SUCCESS(rv, PR_FALSE);
|
||||
|
||||
rv = coords->GetLatitude(&oldLat);
|
||||
NS_ENSURE_SUCCESS(rv, PR_FALSE);
|
||||
|
||||
|
||||
DOMTimeStamp newTime;
|
||||
rv = aSomewhere->GetTimestamp(&newTime);
|
||||
NS_ENSURE_SUCCESS(rv, PR_FALSE);
|
||||
|
||||
aSomewhere->GetCoords(getter_AddRefs(coords));
|
||||
if (!coords)
|
||||
return PR_FALSE;
|
||||
|
||||
double newAccuracy;
|
||||
rv = coords->GetAccuracy(&newAccuracy);
|
||||
NS_ENSURE_SUCCESS(rv, PR_FALSE);
|
||||
|
||||
double newLat, newLon;
|
||||
rv = coords->GetLongitude(&newLon);
|
||||
NS_ENSURE_SUCCESS(rv, PR_FALSE);
|
||||
|
||||
rv = coords->GetLatitude(&newLat);
|
||||
NS_ENSURE_SUCCESS(rv, PR_FALSE);
|
||||
|
||||
// check to see if there has been a large movement
|
||||
// Use spherical law of cosines to calculate difference
|
||||
// Not quite as correct as the Haversine but simpler and cheaper
|
||||
double radsInDeg = 3.14159265 / 180.0;
|
||||
|
||||
double rNewLat = newLat * radsInDeg;
|
||||
double rNewLon = newLon * radsInDeg;
|
||||
double rOldLat = oldLat * radsInDeg;
|
||||
double rOldLon = oldLon * radsInDeg;
|
||||
|
||||
// WGS84 equatorial radius of earth = 6378137m
|
||||
double delta = acos( (sin(rNewLat) * sin(rOldLat)) + (cos(rNewLat) * cos(rOldLat) * cos(rOldLon - rNewLon)) ) * 6378137;
|
||||
|
||||
// The threshold is when the distance between the two positions exceeds the
|
||||
// worse (larger value) of the two accuracies.
|
||||
double max_accuracy = NS_MAX(oldAccuracy, newAccuracy);
|
||||
if (delta > max_accuracy)
|
||||
return PR_TRUE;
|
||||
|
||||
// check to see if the aSomewhere position is more accurate
|
||||
if (oldAccuracy >= newAccuracy)
|
||||
return PR_TRUE;
|
||||
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
nsGeolocationService::SetCachedPosition(nsIDOMGeoPosition* aPosition)
|
||||
{
|
||||
@ -999,19 +905,19 @@ nsGeolocation::RemoveRequest(nsGeolocationRequest* aRequest)
|
||||
}
|
||||
|
||||
void
|
||||
nsGeolocation::Update(nsIDOMGeoPosition *aSomewhere, PRBool isBetter)
|
||||
nsGeolocation::Update(nsIDOMGeoPosition *aSomewhere)
|
||||
{
|
||||
if (!WindowOwnerStillExists())
|
||||
return Shutdown();
|
||||
|
||||
for (PRUint32 i = 0; i< mPendingCallbacks.Length(); i++) {
|
||||
mPendingCallbacks[i]->Update(aSomewhere, isBetter);
|
||||
mPendingCallbacks[i]->Update(aSomewhere);
|
||||
}
|
||||
mPendingCallbacks.Clear();
|
||||
|
||||
// notify everyone that is watching
|
||||
for (PRUint32 i = 0; i< mWatchingCallbacks.Length(); i++) {
|
||||
mWatchingCallbacks[i]->Update(aSomewhere, isBetter);
|
||||
mWatchingCallbacks[i]->Update(aSomewhere);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -97,8 +97,7 @@ class nsGeolocationRequest
|
||||
void Shutdown();
|
||||
|
||||
// Called by the geolocation device to notify that a location has changed.
|
||||
// isBetter: the accuracy is as good or better than the previous position.
|
||||
void Update(nsIDOMGeoPosition* aPosition, PRBool isBetter);
|
||||
void Update(nsIDOMGeoPosition* aPosition);
|
||||
|
||||
void SendLocation(nsIDOMGeoPosition* location);
|
||||
void MarkCleared();
|
||||
@ -152,8 +151,6 @@ public:
|
||||
void AddLocator(nsGeolocation* locator);
|
||||
void RemoveLocator(nsGeolocation* locator);
|
||||
|
||||
PRBool IsBetterPosition(nsIDOMGeoPosition* aPosition);
|
||||
|
||||
void SetCachedPosition(nsIDOMGeoPosition* aPosition);
|
||||
nsIDOMGeoPosition* GetCachedPosition();
|
||||
|
||||
@ -208,8 +205,7 @@ public:
|
||||
nsresult Init(nsIDOMWindow* contentDom=nsnull);
|
||||
|
||||
// Called by the geolocation device to notify that a location has changed.
|
||||
// isBetter: the accuracy is as good or better than the previous position.
|
||||
void Update(nsIDOMGeoPosition* aPosition, PRBool isBetter);
|
||||
void Update(nsIDOMGeoPosition* aPosition);
|
||||
|
||||
// Returns true if any of the callbacks are repeating
|
||||
PRBool HasActiveCallbacks();
|
||||
|
@ -62,19 +62,23 @@ DIRS = android
|
||||
endif
|
||||
|
||||
CPPSRCS = \
|
||||
nsAccelerometer.cpp \
|
||||
$(NULL)
|
||||
nsAccelerometer.cpp \
|
||||
$(NULL)
|
||||
|
||||
# On Systems that have build in geolocation providers,
|
||||
# we really do not need these.
|
||||
ifneq (Android,$(OS_TARGET))
|
||||
EXTRA_COMPONENTS = \
|
||||
NetworkGeolocationProvider.js \
|
||||
NetworkGeolocationProvider.manifest \
|
||||
GPSDGeolocationProvider.js \
|
||||
GPSDGeolocationProvider.manifest \
|
||||
$(NULL)
|
||||
NetworkGeolocationProvider.js \
|
||||
NetworkGeolocationProvider.manifest \
|
||||
GPSDGeolocationProvider.js \
|
||||
GPSDGeolocationProvider.manifest \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
EXPORTS = \
|
||||
nsAccelerometer.h \
|
||||
$(NULL)
|
||||
nsAccelerometer.h \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/config.mk
|
||||
|
||||
|
@ -493,15 +493,8 @@ nsEditingSession::SetupEditorOnWindow(nsIDOMWindow *aWindow)
|
||||
rv = editor->AddDocumentStateListener(mStateMaintainer);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// XXXbz we really shouldn't need a presShell here!
|
||||
nsCOMPtr<nsIPresShell> presShell;
|
||||
rv = docShell->GetPresShell(getter_AddRefs(presShell));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsISelectionController> selCon = do_QueryInterface(presShell);
|
||||
rv = editor->Init(domDoc, presShell, nsnull /* root content */,
|
||||
selCon, mEditorFlags);
|
||||
rv = editor->Init(domDoc, nsnull /* root content */,
|
||||
nsnull, mEditorFlags);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsISelection> selection;
|
||||
|
@ -55,13 +55,7 @@ interface nsIEditActionListener;
|
||||
interface nsIInlineSpellChecker;
|
||||
interface nsITransferable;
|
||||
|
||||
%{C++
|
||||
class nsIPresShell;
|
||||
%}
|
||||
|
||||
[ptr] native nsIPresShellPtr(nsIPresShell);
|
||||
|
||||
[scriptable, uuid(972e54e1-dec3-4e3f-87ec-408a7dbcfd92)]
|
||||
[scriptable, uuid(78b0bde0-ab69-428b-ab30-fcc09eead499)]
|
||||
|
||||
interface nsIEditor : nsISupports
|
||||
{
|
||||
@ -81,19 +75,15 @@ interface nsIEditor : nsISupports
|
||||
/**
|
||||
* Init is to tell the implementation of nsIEditor to begin its services
|
||||
* @param aDoc The dom document interface being observed
|
||||
* @param aPresShell TEMP: The presentation shell displaying the document.
|
||||
* Once events can tell us from what pres shell
|
||||
* they originated, this will no longer be
|
||||
* necessary, and the editor will no longer be
|
||||
* linked to a single pres shell.
|
||||
* @param aRoot This is the root of the editable section of this
|
||||
* document. If it is null then we get root
|
||||
* from document body.
|
||||
* @param aSelCon this should be used to get the selection location
|
||||
* (will be null for HTML editors)
|
||||
* @param aFlags A bitmask of flags for specifying the behavior
|
||||
* of the editor.
|
||||
*/
|
||||
[noscript] void init(in nsIDOMDocument doc, in nsIPresShellPtr shell,
|
||||
[noscript] void init(in nsIDOMDocument doc,
|
||||
in nsIContent aRoot,
|
||||
in nsISelectionController aSelCon,
|
||||
in unsigned long aFlags);
|
||||
|
@ -44,6 +44,7 @@
|
||||
#include "nsISelectionPrivate.h"
|
||||
#include "nsISelectionController.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsIEditor.h"
|
||||
|
||||
// #define DEBUG_IMETXN
|
||||
|
||||
@ -77,7 +78,7 @@ NS_IMETHODIMP IMETextTxn::Init(nsIDOMCharacterData *aElement,
|
||||
PRUint32 aReplaceLength,
|
||||
nsIPrivateTextRangeList *aTextRangeList,
|
||||
const nsAString &aStringToInsert,
|
||||
nsWeakPtr aSelConWeak)
|
||||
nsIEditor *aEditor)
|
||||
{
|
||||
NS_ASSERTION(aElement, "illegal value- null ptr- aElement");
|
||||
NS_ASSERTION(aTextRangeList, "illegal value- null ptr - aTextRangeList");
|
||||
@ -86,7 +87,7 @@ NS_IMETHODIMP IMETextTxn::Init(nsIDOMCharacterData *aElement,
|
||||
mOffset = aOffset;
|
||||
mReplaceLength = aReplaceLength;
|
||||
mStringToInsert = aStringToInsert;
|
||||
mSelConWeak = aSelConWeak;
|
||||
mEditor = aEditor;
|
||||
mRangeList = do_QueryInterface(aTextRangeList);
|
||||
mFixed = PR_FALSE;
|
||||
return NS_OK;
|
||||
@ -99,7 +100,8 @@ NS_IMETHODIMP IMETextTxn::DoTransaction(void)
|
||||
printf("Do IME Text element = %p replace = %d len = %d\n", mElement.get(), mReplaceLength, mStringToInsert.Length());
|
||||
#endif
|
||||
|
||||
nsCOMPtr<nsISelectionController> selCon = do_QueryReferent(mSelConWeak);
|
||||
nsCOMPtr<nsISelectionController> selCon;
|
||||
mEditor->GetSelectionController(getter_AddRefs(selCon));
|
||||
NS_ENSURE_TRUE(selCon, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
// advance caret: This requires the presentation shell to get the selection.
|
||||
@ -122,7 +124,8 @@ NS_IMETHODIMP IMETextTxn::UndoTransaction(void)
|
||||
printf("Undo IME Text element = %p\n", mElement.get());
|
||||
#endif
|
||||
|
||||
nsCOMPtr<nsISelectionController> selCon = do_QueryReferent(mSelConWeak);
|
||||
nsCOMPtr<nsISelectionController> selCon;
|
||||
mEditor->GetSelectionController(getter_AddRefs(selCon));
|
||||
NS_ENSURE_TRUE(selCon, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
nsresult result = mElement->DeleteData(mOffset, mStringToInsert.Length());
|
||||
@ -263,7 +266,8 @@ NS_IMETHODIMP IMETextTxn::CollapseTextSelection(void)
|
||||
//
|
||||
// run through the text range list, if any
|
||||
//
|
||||
nsCOMPtr<nsISelectionController> selCon = do_QueryReferent(mSelConWeak);
|
||||
nsCOMPtr<nsISelectionController> selCon;
|
||||
mEditor->GetSelectionController(getter_AddRefs(selCon));
|
||||
NS_ENSURE_TRUE(selCon, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
PRUint16 textRangeListLength,selectionStart,selectionEnd,
|
||||
|
@ -51,6 +51,7 @@
|
||||
{0x9e, 0xa3, 0x0, 0x60, 0x8, 0x9f, 0xe5, 0x9b }}
|
||||
|
||||
|
||||
class nsIEditor;
|
||||
|
||||
|
||||
/**
|
||||
@ -73,7 +74,7 @@ public:
|
||||
PRUint32 aReplaceLength,
|
||||
nsIPrivateTextRangeList* aTextRangeList,
|
||||
const nsAString& aString,
|
||||
nsWeakPtr aSelCon);
|
||||
nsIEditor* aEditor);
|
||||
|
||||
IMETextTxn();
|
||||
|
||||
@ -111,8 +112,8 @@ protected:
|
||||
/** the range list **/
|
||||
nsCOMPtr<nsIPrivateTextRangeList> mRangeList;
|
||||
|
||||
/** the selection controller, which we'll need to get the selection */
|
||||
nsWeakPtr mSelConWeak; // use a weak reference
|
||||
/** the editor, which is used to get the selection controller */
|
||||
nsIEditor *mEditor;
|
||||
|
||||
PRBool mFixed;
|
||||
};
|
||||
|
@ -141,7 +141,6 @@ extern nsIParserService *sParserService;
|
||||
nsEditor::nsEditor()
|
||||
: mModCount(0)
|
||||
, mFlags(0)
|
||||
, mPresShellWeak(nsnull)
|
||||
, mUpdateCount(0)
|
||||
, mSpellcheckCheckboxState(eTriUnset)
|
||||
, mPlaceHolderTxn(nsnull)
|
||||
@ -159,6 +158,7 @@ nsEditor::nsEditor()
|
||||
, mIsIMEComposing(PR_FALSE)
|
||||
, mShouldTxnSetSelection(PR_TRUE)
|
||||
, mDidPreDestroy(PR_FALSE)
|
||||
, mDidPostCreate(PR_FALSE)
|
||||
, mDocDirtyState(-1)
|
||||
, mDocWeak(nsnull)
|
||||
, mPhonetic(nsnull)
|
||||
@ -224,14 +224,14 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsEditor, nsIEditor)
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsEditor::Init(nsIDOMDocument *aDoc, nsIPresShell* aPresShell, nsIContent *aRoot, nsISelectionController *aSelCon, PRUint32 aFlags)
|
||||
nsEditor::Init(nsIDOMDocument *aDoc, nsIContent *aRoot, nsISelectionController *aSelCon, PRUint32 aFlags)
|
||||
{
|
||||
NS_PRECONDITION(aDoc && aPresShell, "bad arg");
|
||||
if (!aDoc || !aPresShell)
|
||||
NS_PRECONDITION(aDoc, "bad arg");
|
||||
if (!aDoc)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
// First only set flags, but other stuff shouldn't be initialized now.
|
||||
// Don't move this call after initializing mDocWeak and mPresShellWeak.
|
||||
// Don't move this call after initializing mDocWeak.
|
||||
// SetFlags() can check whether it's called during initialization or not by
|
||||
// them. Note that SetFlags() will be called by PostCreate().
|
||||
#ifdef DEBUG
|
||||
@ -241,11 +241,19 @@ nsEditor::Init(nsIDOMDocument *aDoc, nsIPresShell* aPresShell, nsIContent *aRoot
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "SetFlags() failed");
|
||||
|
||||
mDocWeak = do_GetWeakReference(aDoc); // weak reference to doc
|
||||
mPresShellWeak = do_GetWeakReference(aPresShell); // weak reference to pres shell
|
||||
mSelConWeak = do_GetWeakReference(aSelCon); // weak reference to selectioncontroller
|
||||
|
||||
nsCOMPtr<nsIPresShell> ps = do_QueryReferent(mPresShellWeak);
|
||||
NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED);
|
||||
// HTML editors currently don't have their own selection controller,
|
||||
// so they'll pass null as aSelCon, and we'll get the selection controller
|
||||
// off of the presshell.
|
||||
nsCOMPtr<nsISelectionController> selCon;
|
||||
if (aSelCon) {
|
||||
mSelConWeak = do_GetWeakReference(aSelCon); // weak reference to selectioncontroller
|
||||
selCon = aSelCon;
|
||||
} else {
|
||||
nsCOMPtr<nsIPresShell> presShell;
|
||||
GetPresShell(getter_AddRefs(presShell));
|
||||
selCon = do_QueryInterface(presShell);
|
||||
}
|
||||
NS_ASSERTION(selCon, "Selection controller should be available at this point");
|
||||
|
||||
//set up root element if we are passed one.
|
||||
if (aRoot)
|
||||
@ -259,15 +267,17 @@ nsEditor::Init(nsIDOMDocument *aDoc, nsIPresShell* aPresShell, nsIContent *aRoot
|
||||
mIMEBufferLength = 0;
|
||||
|
||||
/* Show the caret */
|
||||
aSelCon->SetCaretReadOnly(PR_FALSE);
|
||||
aSelCon->SetDisplaySelection(nsISelectionController::SELECTION_ON);
|
||||
selCon->SetCaretReadOnly(PR_FALSE);
|
||||
selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON);
|
||||
|
||||
aSelCon->SetSelectionFlags(nsISelectionDisplay::DISPLAY_ALL);//we want to see all the selection reflected to user
|
||||
selCon->SetSelectionFlags(nsISelectionDisplay::DISPLAY_ALL);//we want to see all the selection reflected to user
|
||||
|
||||
NS_POSTCONDITION(mDocWeak && mPresShellWeak, "bad state");
|
||||
NS_POSTCONDITION(mDocWeak, "bad state");
|
||||
|
||||
// Make sure that the editor will be destroyed properly
|
||||
mDidPreDestroy = PR_FALSE;
|
||||
// Make sure that the ediotr will be created properly
|
||||
mDidPostCreate = PR_FALSE;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -284,31 +294,38 @@ nsEditor::PostCreate()
|
||||
nsresult rv = SetFlags(~mFlags);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Set up listeners
|
||||
rv = CreateEventListeners();
|
||||
if (NS_FAILED(rv))
|
||||
{
|
||||
RemoveEventListeners();
|
||||
// These operations only need to happen on the first PostCreate call
|
||||
if (!mDidPostCreate) {
|
||||
mDidPostCreate = PR_TRUE;
|
||||
|
||||
return rv;
|
||||
// Set up listeners
|
||||
rv = CreateEventListeners();
|
||||
if (NS_FAILED(rv))
|
||||
{
|
||||
RemoveEventListeners();
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = InstallEventListeners();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// nuke the modification count, so the doc appears unmodified
|
||||
// do this before we notify listeners
|
||||
ResetModificationCount();
|
||||
|
||||
// update the UI with our state
|
||||
NotifyDocumentListeners(eDocumentCreated);
|
||||
NotifyDocumentListeners(eDocumentStateChanged);
|
||||
}
|
||||
|
||||
rv = InstallEventListeners();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// nuke the modification count, so the doc appears unmodified
|
||||
// do this before we notify listeners
|
||||
ResetModificationCount();
|
||||
|
||||
// update the UI with our state
|
||||
NotifyDocumentListeners(eDocumentCreated);
|
||||
NotifyDocumentListeners(eDocumentStateChanged);
|
||||
|
||||
// update nsTextStateManager and caret if we have focus
|
||||
nsCOMPtr<nsIContent> focusedContent = GetFocusedContent();
|
||||
if (focusedContent) {
|
||||
nsCOMPtr<nsIPresShell> ps = do_QueryReferent(mPresShellWeak);
|
||||
nsCOMPtr<nsIPresShell> ps;
|
||||
GetPresShell(getter_AddRefs(ps));
|
||||
NS_ASSERTION(ps, "no pres shell even though we have focus");
|
||||
NS_ENSURE_TRUE(ps, NS_ERROR_UNEXPECTED);
|
||||
nsPresContext* pc = ps->GetPresContext();
|
||||
|
||||
nsIMEStateManager::OnTextStateBlur(pc, nsnull);
|
||||
@ -337,7 +354,7 @@ nsEditor::CreateEventListeners()
|
||||
nsresult
|
||||
nsEditor::InstallEventListeners()
|
||||
{
|
||||
NS_ENSURE_TRUE(mDocWeak && mPresShellWeak && mEventListener,
|
||||
NS_ENSURE_TRUE(mDocWeak && mEventListener,
|
||||
NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
// Initialize the event target.
|
||||
@ -464,7 +481,7 @@ nsEditor::SetFlags(PRUint32 aFlags)
|
||||
PRBool spellcheckerWasEnabled = CanEnableSpellCheck();
|
||||
mFlags = aFlags;
|
||||
|
||||
if (!mDocWeak || !mPresShellWeak) {
|
||||
if (!mDocWeak) {
|
||||
// If we're initializing, we shouldn't do anything now.
|
||||
// SetFlags() will be called by PostCreate(),
|
||||
// we should synchronize some stuff for the flags at that time.
|
||||
@ -524,10 +541,12 @@ nsEditor::GetPresShell(nsIPresShell **aPS)
|
||||
{
|
||||
NS_ENSURE_TRUE(aPS, NS_ERROR_NULL_POINTER);
|
||||
*aPS = nsnull; // init out param
|
||||
NS_PRECONDITION(mPresShellWeak, "bad state, null mPresShellWeak");
|
||||
nsCOMPtr<nsIPresShell> ps = do_QueryReferent(mPresShellWeak);
|
||||
NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED);
|
||||
NS_ADDREF(*aPS = ps);
|
||||
NS_PRECONDITION(mDocWeak, "bad state, null mDocWeak");
|
||||
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak);
|
||||
NS_ENSURE_TRUE(doc, NS_ERROR_NOT_INITIALIZED);
|
||||
*aPS = doc->GetShell();
|
||||
NS_ENSURE_TRUE(*aPS, NS_ERROR_NOT_INITIALIZED);
|
||||
NS_ADDREF(*aPS);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -553,8 +572,14 @@ nsEditor::GetSelectionController(nsISelectionController **aSel)
|
||||
{
|
||||
NS_ENSURE_TRUE(aSel, NS_ERROR_NULL_POINTER);
|
||||
*aSel = nsnull; // init out param
|
||||
NS_PRECONDITION(mSelConWeak, "bad state, null mSelConWeak");
|
||||
nsCOMPtr<nsISelectionController> selCon = do_QueryReferent(mSelConWeak);
|
||||
nsCOMPtr<nsISelectionController> selCon;
|
||||
if (mSelConWeak) {
|
||||
selCon = do_QueryReferent(mSelConWeak);
|
||||
} else {
|
||||
nsCOMPtr<nsIPresShell> presShell;
|
||||
GetPresShell(getter_AddRefs(presShell));
|
||||
selCon = do_QueryInterface(presShell);
|
||||
}
|
||||
NS_ENSURE_TRUE(selCon, NS_ERROR_NOT_INITIALIZED);
|
||||
NS_ADDREF(*aSel = selCon);
|
||||
return NS_OK;
|
||||
@ -574,7 +599,8 @@ nsEditor::GetSelection(nsISelection **aSelection)
|
||||
{
|
||||
NS_ENSURE_TRUE(aSelection, NS_ERROR_NULL_POINTER);
|
||||
*aSelection = nsnull;
|
||||
nsCOMPtr<nsISelectionController> selcon = do_QueryReferent(mSelConWeak);
|
||||
nsCOMPtr<nsISelectionController> selcon;
|
||||
GetSelectionController(getter_AddRefs(selcon));
|
||||
NS_ENSURE_TRUE(selcon, NS_ERROR_NOT_INITIALIZED);
|
||||
return selcon->GetSelection(nsISelectionController::SELECTION_NORMAL, aSelection); // does an addref
|
||||
}
|
||||
@ -1006,10 +1032,11 @@ nsEditor::GetDocumentIsEmpty(PRBool *aDocumentIsEmpty)
|
||||
// XXX: the rule system should tell us which node to select all on (ie, the root, or the body)
|
||||
NS_IMETHODIMP nsEditor::SelectAll()
|
||||
{
|
||||
if (!mDocWeak || !mPresShellWeak) { return NS_ERROR_NOT_INITIALIZED; }
|
||||
if (!mDocWeak) { return NS_ERROR_NOT_INITIALIZED; }
|
||||
ForceCompositionEnd();
|
||||
|
||||
nsCOMPtr<nsISelectionController> selCon = do_QueryReferent(mSelConWeak);
|
||||
nsCOMPtr<nsISelectionController> selCon;
|
||||
GetSelectionController(getter_AddRefs(selCon));
|
||||
NS_ENSURE_TRUE(selCon, NS_ERROR_NOT_INITIALIZED);
|
||||
nsCOMPtr<nsISelection> selection;
|
||||
nsresult result = selCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection));
|
||||
@ -1022,7 +1049,7 @@ NS_IMETHODIMP nsEditor::SelectAll()
|
||||
|
||||
NS_IMETHODIMP nsEditor::BeginningOfDocument()
|
||||
{
|
||||
if (!mDocWeak || !mPresShellWeak) { return NS_ERROR_NOT_INITIALIZED; }
|
||||
if (!mDocWeak) { return NS_ERROR_NOT_INITIALIZED; }
|
||||
|
||||
// get the selection
|
||||
nsCOMPtr<nsISelection> selection;
|
||||
@ -1067,7 +1094,7 @@ NS_IMETHODIMP nsEditor::BeginningOfDocument()
|
||||
NS_IMETHODIMP
|
||||
nsEditor::EndOfDocument()
|
||||
{
|
||||
if (!mDocWeak || !mPresShellWeak) { return NS_ERROR_NOT_INITIALIZED; }
|
||||
if (!mDocWeak) { return NS_ERROR_NOT_INITIALIZED; }
|
||||
nsresult res;
|
||||
|
||||
// get selection
|
||||
@ -1118,39 +1145,23 @@ nsEditor::GetDocumentModified(PRBool *outDocModified)
|
||||
NS_IMETHODIMP
|
||||
nsEditor::GetDocumentCharacterSet(nsACString &characterSet)
|
||||
{
|
||||
nsCOMPtr<nsIPresShell> presShell;
|
||||
|
||||
nsresult rv = GetPresShell(getter_AddRefs(presShell));
|
||||
if (NS_SUCCEEDED(rv))
|
||||
{
|
||||
nsIDocument *doc = presShell->GetDocument();
|
||||
if (doc) {
|
||||
characterSet = doc->GetDocumentCharacterSet();
|
||||
return NS_OK;
|
||||
}
|
||||
rv = NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
|
||||
return rv;
|
||||
nsresult rv = NS_OK;
|
||||
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak);
|
||||
NS_ENSURE_TRUE(doc, NS_ERROR_UNEXPECTED);
|
||||
|
||||
characterSet = doc->GetDocumentCharacterSet();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsEditor::SetDocumentCharacterSet(const nsACString& characterSet)
|
||||
{
|
||||
nsCOMPtr<nsIPresShell> presShell;
|
||||
nsresult rv = GetPresShell(getter_AddRefs(presShell));
|
||||
if (NS_SUCCEEDED(rv))
|
||||
{
|
||||
nsIDocument *doc = presShell->GetDocument();
|
||||
if (doc) {
|
||||
doc->SetDocumentCharacterSet(characterSet);
|
||||
return NS_OK;
|
||||
}
|
||||
rv = NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
nsresult rv = NS_OK;
|
||||
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak);
|
||||
NS_ENSURE_TRUE(doc, NS_ERROR_UNEXPECTED);
|
||||
|
||||
return rv;
|
||||
doc->SetDocumentCharacterSet(characterSet);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -2845,7 +2856,8 @@ nsEditor::SplitNodeImpl(nsIDOMNode * aExistingRightNode,
|
||||
}
|
||||
}
|
||||
// handle selection
|
||||
nsCOMPtr<nsIPresShell> ps = do_QueryReferent(mPresShellWeak);
|
||||
nsCOMPtr<nsIPresShell> ps;
|
||||
GetPresShell(getter_AddRefs(ps));
|
||||
if (ps)
|
||||
ps->FlushPendingNotifications(Flush_Frames);
|
||||
|
||||
@ -3973,7 +3985,8 @@ nsEditor::IsPreformatted(nsIDOMNode *aNode, PRBool *aResult)
|
||||
|
||||
NS_ENSURE_TRUE(aResult && content, NS_ERROR_NULL_POINTER);
|
||||
|
||||
nsCOMPtr<nsIPresShell> ps = do_QueryReferent(mPresShellWeak);
|
||||
nsCOMPtr<nsIPresShell> ps;
|
||||
GetPresShell(getter_AddRefs(ps));
|
||||
NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
// Look at the node (and its parent if it's not an element), and grab its style context
|
||||
@ -4622,7 +4635,7 @@ nsEditor::CreateTxnForIMEText(const nsAString& aStringToInsert,
|
||||
nsRefPtr<IMETextTxn> txn = new IMETextTxn();
|
||||
|
||||
nsresult rv = txn->Init(mIMETextNode, mIMETextOffset, mIMEBufferLength,
|
||||
mIMETextRangeList, aStringToInsert, mSelConWeak);
|
||||
mIMETextRangeList, aStringToInsert, this);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
{
|
||||
txn.forget(aTxn);
|
||||
@ -4674,7 +4687,8 @@ nsEditor::CreateTxnForDeleteSelection(nsIEditor::EDirection aAction,
|
||||
*aTxn = nsnull;
|
||||
|
||||
nsRefPtr<EditAggregateTxn> aggTxn;
|
||||
nsCOMPtr<nsISelectionController> selCon = do_QueryReferent(mSelConWeak);
|
||||
nsCOMPtr<nsISelectionController> selCon;
|
||||
GetSelectionController(getter_AddRefs(selCon));
|
||||
NS_ENSURE_TRUE(selCon, NS_ERROR_NOT_INITIALIZED);
|
||||
nsCOMPtr<nsISelection> selection;
|
||||
nsresult result = selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
|
||||
@ -4756,7 +4770,7 @@ nsEditor::CreateTxnForDeleteCharacter(nsIDOMCharacterData *aData,
|
||||
}
|
||||
} else {
|
||||
segOffset = aOffset - 1;
|
||||
if (segOffset > 1 &&
|
||||
if (segOffset > 0 &&
|
||||
NS_IS_LOW_SURROGATE(data[segOffset]) &&
|
||||
NS_IS_HIGH_SURROGATE(data[segOffset-1])) {
|
||||
++segLength;
|
||||
|
@ -725,7 +725,6 @@ protected:
|
||||
PRUint32 mModCount; // number of modifications (for undo/redo stack)
|
||||
PRUint32 mFlags; // behavior flags. See nsIPlaintextEditor.idl for the flags we use.
|
||||
|
||||
nsWeakPtr mPresShellWeak; // weak reference to the nsIPresShell
|
||||
nsWeakPtr mSelConWeak; // weak reference to the nsISelectionController
|
||||
PRInt32 mUpdateCount;
|
||||
nsIViewManager::UpdateViewBatch mBatch;
|
||||
@ -760,6 +759,7 @@ protected:
|
||||
|
||||
PRPackedBool mShouldTxnSetSelection; // turn off for conservative selection adjustment by txns
|
||||
PRPackedBool mDidPreDestroy; // whether PreDestroy has been called
|
||||
PRPackedBool mDidPostCreate; // whether PostCreate has been called
|
||||
// various listeners
|
||||
nsCOMArray<nsIEditActionListener> mActionListeners; // listens to all low level actions on the doc
|
||||
nsCOMArray<nsIEditorObserver> mEditorObservers; // just notify once per high level change
|
||||
|
@ -93,7 +93,7 @@ private:
|
||||
};
|
||||
|
||||
nsEditorEventListener::nsEditorEventListener() :
|
||||
mEditor(nsnull), mCaretDrawn(PR_FALSE), mCommitText(PR_FALSE),
|
||||
mEditor(nsnull), mCommitText(PR_FALSE),
|
||||
mInTransaction(PR_FALSE)
|
||||
{
|
||||
}
|
||||
@ -165,8 +165,9 @@ nsEditorEventListener::InstallToEditor()
|
||||
NS_EVENT_FLAG_BUBBLE, sysGroup);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = piTarget->AddEventListenerByIID(static_cast<nsIDOMMouseListener*>(this),
|
||||
NS_GET_IID(nsIDOMMouseListener));
|
||||
rv = elmP->AddEventListenerByIID(static_cast<nsIDOMMouseListener*>(this),
|
||||
NS_GET_IID(nsIDOMMouseListener),
|
||||
NS_EVENT_FLAG_CAPTURE);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Focus event doesn't bubble so adding the listener to capturing phase.
|
||||
@ -236,8 +237,9 @@ nsEditorEventListener::UninstallFromEditor()
|
||||
NS_LITERAL_STRING("drop"),
|
||||
NS_EVENT_FLAG_BUBBLE, sysGroup);
|
||||
|
||||
piTarget->RemoveEventListenerByIID(static_cast<nsIDOMMouseListener*>(this),
|
||||
NS_GET_IID(nsIDOMMouseListener));
|
||||
elmP->RemoveEventListenerByIID(static_cast<nsIDOMMouseListener*>(this),
|
||||
NS_GET_IID(nsIDOMMouseListener),
|
||||
NS_EVENT_FLAG_CAPTURE);
|
||||
|
||||
elmP->RemoveEventListenerByIID(static_cast<nsIDOMFocusListener*>(this),
|
||||
NS_GET_IID(nsIDOMFocusListener),
|
||||
@ -559,7 +561,6 @@ nsEditorEventListener::DragEnter(nsIDOMDragEvent* aDragEvent)
|
||||
mCaret->Init(presShell);
|
||||
mCaret->SetCaretReadOnly(PR_TRUE);
|
||||
}
|
||||
mCaretDrawn = PR_FALSE;
|
||||
}
|
||||
|
||||
presShell->SetCaret(mCaret);
|
||||
@ -598,52 +599,30 @@ nsEditorEventListener::DragOver(nsIDOMDragEvent* aDragEvent)
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// to avoid flicker, we could track the node and offset to see if we moved
|
||||
if (mCaretDrawn)
|
||||
if (mCaret)
|
||||
mCaret->EraseCaret();
|
||||
|
||||
//mCaret->SetCaretVisible(PR_TRUE); // make sure it's visible
|
||||
mCaret->DrawAtPosition(parent, offset);
|
||||
mCaretDrawn = PR_TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mCaret && mCaretDrawn)
|
||||
if (mCaret)
|
||||
{
|
||||
mCaret->EraseCaret();
|
||||
mCaretDrawn = PR_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsEditorEventListener::DragExit(nsIDOMDragEvent* aDragEvent)
|
||||
{
|
||||
if (mCaret && mCaretDrawn)
|
||||
{
|
||||
mCaret->EraseCaret();
|
||||
mCaretDrawn = PR_FALSE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPresShell> presShell = GetPresShell();
|
||||
if (presShell)
|
||||
presShell->RestoreCaret();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsEditorEventListener::Drop(nsIDOMDragEvent* aMouseEvent)
|
||||
void
|
||||
nsEditorEventListener::CleanupDragDropCaret()
|
||||
{
|
||||
if (mCaret)
|
||||
{
|
||||
if (mCaretDrawn)
|
||||
{
|
||||
mCaret->EraseCaret();
|
||||
mCaretDrawn = PR_FALSE;
|
||||
}
|
||||
mCaret->EraseCaret();
|
||||
mCaret->SetCaretVisible(PR_FALSE); // hide it, so that it turns off its timer
|
||||
|
||||
nsCOMPtr<nsIPresShell> presShell = GetPresShell();
|
||||
@ -651,7 +630,24 @@ nsEditorEventListener::Drop(nsIDOMDragEvent* aMouseEvent)
|
||||
{
|
||||
presShell->RestoreCaret();
|
||||
}
|
||||
|
||||
mCaret->Terminate();
|
||||
mCaret = nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsEditorEventListener::DragExit(nsIDOMDragEvent* aDragEvent)
|
||||
{
|
||||
CleanupDragDropCaret();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsEditorEventListener::Drop(nsIDOMDragEvent* aMouseEvent)
|
||||
{
|
||||
CleanupDragDropCaret();
|
||||
|
||||
nsCOMPtr<nsIDOMNSUIEvent> nsuiEvent = do_QueryInterface(aMouseEvent);
|
||||
if (nsuiEvent) {
|
||||
|
@ -105,12 +105,12 @@ protected:
|
||||
nsresult DragExit(nsIDOMDragEvent* aDragEvent);
|
||||
nsresult Drop(nsIDOMDragEvent* aDragEvent);
|
||||
nsresult DragGesture(nsIDOMDragEvent* aDragEvent);
|
||||
void CleanupDragDropCaret();
|
||||
already_AddRefed<nsIPresShell> GetPresShell();
|
||||
|
||||
protected:
|
||||
nsEditor* mEditor; // weak
|
||||
nsRefPtr<nsCaret> mCaret;
|
||||
PRPackedBool mCaretDrawn;
|
||||
PRPackedBool mCommitText;
|
||||
PRPackedBool mInTransaction;
|
||||
};
|
||||
|
@ -311,7 +311,8 @@ nsHTMLEditor::HideGrabber()
|
||||
NS_ENSURE_TRUE(mGrabber, NS_ERROR_NULL_POINTER);
|
||||
|
||||
// get the presshell's document observer interface.
|
||||
nsCOMPtr<nsIPresShell> ps = do_QueryReferent(mPresShellWeak);
|
||||
nsCOMPtr<nsIPresShell> ps;
|
||||
GetPresShell(getter_AddRefs(ps));
|
||||
// We allow the pres shell to be null; when it is, we presume there
|
||||
// are no document observers to notify, but we still want to
|
||||
// UnbindFromTree.
|
||||
@ -427,7 +428,8 @@ nsresult
|
||||
nsHTMLEditor::EndMoving()
|
||||
{
|
||||
if (mPositioningShadow) {
|
||||
nsCOMPtr<nsIPresShell> ps = do_QueryReferent(mPresShellWeak);
|
||||
nsCOMPtr<nsIPresShell> ps;
|
||||
GetPresShell(getter_AddRefs(ps));
|
||||
NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
nsCOMPtr<nsIDOMNode> parentNode;
|
||||
|
@ -156,7 +156,8 @@ nsHTMLEditor::CreateAnonymousElement(const nsAString & aTag, nsIDOMNode * aPare
|
||||
NS_ENSURE_TRUE(doc, NS_ERROR_NULL_POINTER);
|
||||
|
||||
// Get the pres shell
|
||||
nsCOMPtr<nsIPresShell> ps = do_QueryReferent(mPresShellWeak);
|
||||
nsCOMPtr<nsIPresShell> ps;
|
||||
GetPresShell(getter_AddRefs(ps));
|
||||
NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
// Create a new node through the element factory
|
||||
|
@ -204,9 +204,10 @@ nsHTMLEditor::~nsHTMLEditor()
|
||||
RemoveOverrideStyleSheet(mStyleSheetURLs[0]);
|
||||
}
|
||||
|
||||
if (mLinkHandler && mPresShellWeak)
|
||||
if (mLinkHandler && mDocWeak)
|
||||
{
|
||||
nsCOMPtr<nsIPresShell> ps = do_QueryReferent(mPresShellWeak);
|
||||
nsCOMPtr<nsIPresShell> ps;
|
||||
GetPresShell(getter_AddRefs(ps));
|
||||
|
||||
if (ps && ps->GetPresContext())
|
||||
{
|
||||
@ -295,12 +296,13 @@ NS_INTERFACE_MAP_END_INHERITING(nsPlaintextEditor)
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLEditor::Init(nsIDOMDocument *aDoc, nsIPresShell *aPresShell,
|
||||
nsIContent *aRoot, nsISelectionController *aSelCon,
|
||||
nsHTMLEditor::Init(nsIDOMDocument *aDoc,
|
||||
nsIContent *aRoot,
|
||||
nsISelectionController *aSelCon,
|
||||
PRUint32 aFlags)
|
||||
{
|
||||
NS_PRECONDITION(aDoc && aPresShell, "bad arg");
|
||||
NS_ENSURE_TRUE(aDoc && aPresShell, NS_ERROR_NULL_POINTER);
|
||||
NS_PRECONDITION(aDoc && !aSelCon, "bad arg");
|
||||
NS_ENSURE_TRUE(aDoc, NS_ERROR_NULL_POINTER);
|
||||
|
||||
nsresult result = NS_OK, rulesRes = NS_OK;
|
||||
|
||||
@ -317,7 +319,7 @@ nsHTMLEditor::Init(nsIDOMDocument *aDoc, nsIPresShell *aPresShell,
|
||||
nsAutoEditInitRulesTrigger rulesTrigger(static_cast<nsPlaintextEditor*>(this), rulesRes);
|
||||
|
||||
// Init the plaintext editor
|
||||
result = nsPlaintextEditor::Init(aDoc, aPresShell, aRoot, aSelCon, aFlags);
|
||||
result = nsPlaintextEditor::Init(aDoc, aRoot, nsnull, aFlags);
|
||||
if (NS_FAILED(result)) { return result; }
|
||||
|
||||
// Init mutation observer
|
||||
@ -337,7 +339,10 @@ nsHTMLEditor::Init(nsIDOMDocument *aDoc, nsIPresShell *aPresShell,
|
||||
mHTMLCSSUtils->Init(this);
|
||||
|
||||
// disable links
|
||||
nsPresContext *context = aPresShell->GetPresContext();
|
||||
nsCOMPtr<nsIPresShell> presShell;
|
||||
GetPresShell(getter_AddRefs(presShell));
|
||||
NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
|
||||
nsPresContext *context = presShell->GetPresContext();
|
||||
NS_ENSURE_TRUE(context, NS_ERROR_NULL_POINTER);
|
||||
if (!IsPlaintextEditor() && !IsInteractionAllowed()) {
|
||||
mLinkHandler = context->GetLinkHandler();
|
||||
@ -487,7 +492,7 @@ nsHTMLEditor::CreateEventListeners()
|
||||
nsresult
|
||||
nsHTMLEditor::InstallEventListeners()
|
||||
{
|
||||
NS_ENSURE_TRUE(mDocWeak && mPresShellWeak && mEventListener,
|
||||
NS_ENSURE_TRUE(mDocWeak && mEventListener,
|
||||
NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
// NOTE: nsHTMLEditor doesn't need to initialize mEventTarget here because
|
||||
@ -571,7 +576,7 @@ nsHTMLEditor::InitRules()
|
||||
NS_IMETHODIMP
|
||||
nsHTMLEditor::BeginningOfDocument()
|
||||
{
|
||||
if (!mDocWeak || !mPresShellWeak) { return NS_ERROR_NOT_INITIALIZED; }
|
||||
if (!mDocWeak) { return NS_ERROR_NOT_INITIALIZED; }
|
||||
|
||||
// get the selection
|
||||
nsCOMPtr<nsISelection> selection;
|
||||
@ -3543,8 +3548,9 @@ nsHTMLEditor::ReplaceStyleSheet(const nsAString& aURL)
|
||||
}
|
||||
|
||||
// Make sure the pres shell doesn't disappear during the load.
|
||||
NS_ENSURE_TRUE(mPresShellWeak, NS_ERROR_NOT_INITIALIZED);
|
||||
nsCOMPtr<nsIPresShell> ps = do_QueryReferent(mPresShellWeak);
|
||||
NS_ENSURE_TRUE(mDocWeak, NS_ERROR_NOT_INITIALIZED);
|
||||
nsCOMPtr<nsIPresShell> ps;
|
||||
GetPresShell(getter_AddRefs(ps));
|
||||
NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
nsCOMPtr<nsIURI> uaURI;
|
||||
@ -3588,7 +3594,8 @@ nsHTMLEditor::AddOverrideStyleSheet(const nsAString& aURL)
|
||||
return NS_OK;
|
||||
|
||||
// Make sure the pres shell doesn't disappear during the load.
|
||||
nsCOMPtr<nsIPresShell> ps = do_QueryReferent(mPresShellWeak);
|
||||
nsCOMPtr<nsIPresShell> ps;
|
||||
GetPresShell(getter_AddRefs(ps));
|
||||
NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
nsCOMPtr<nsIURI> uaURI;
|
||||
@ -3651,8 +3658,9 @@ nsHTMLEditor::RemoveOverrideStyleSheet(const nsAString &aURL)
|
||||
|
||||
NS_ENSURE_TRUE(sheet, NS_OK); /// Don't fail if sheet not found
|
||||
|
||||
NS_ENSURE_TRUE(mPresShellWeak, NS_ERROR_NOT_INITIALIZED);
|
||||
nsCOMPtr<nsIPresShell> ps = do_QueryReferent(mPresShellWeak);
|
||||
NS_ENSURE_TRUE(mDocWeak, NS_ERROR_NOT_INITIALIZED);
|
||||
nsCOMPtr<nsIPresShell> ps;
|
||||
GetPresShell(getter_AddRefs(ps));
|
||||
NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
ps->RemoveOverrideStyleSheet(sheet);
|
||||
@ -4248,7 +4256,8 @@ nsHTMLEditor::SelectAll()
|
||||
ForceCompositionEnd();
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsISelectionController> selCon = do_QueryReferent(mSelConWeak, &rv);
|
||||
nsCOMPtr<nsISelectionController> selCon;
|
||||
rv = GetSelectionController(getter_AddRefs(selCon));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsISelection> selection;
|
||||
@ -4273,7 +4282,8 @@ nsHTMLEditor::SelectAll()
|
||||
return selection->SelectAllChildren(mRootElement);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPresShell> ps = do_QueryReferent(mPresShellWeak);
|
||||
nsCOMPtr<nsIPresShell> ps;
|
||||
GetPresShell(getter_AddRefs(ps));
|
||||
nsIContent *rootContent = anchorContent->GetSelectionRootContent(ps);
|
||||
NS_ENSURE_TRUE(rootContent, NS_ERROR_UNEXPECTED);
|
||||
|
||||
@ -5680,8 +5690,9 @@ nsHTMLEditor::GetElementOrigin(nsIDOMElement * aElement, PRInt32 & aX, PRInt32 &
|
||||
aX = 0;
|
||||
aY = 0;
|
||||
|
||||
NS_ENSURE_TRUE(mPresShellWeak, NS_ERROR_NOT_INITIALIZED);
|
||||
nsCOMPtr<nsIPresShell> ps = do_QueryReferent(mPresShellWeak);
|
||||
NS_ENSURE_TRUE(mDocWeak, NS_ERROR_NOT_INITIALIZED);
|
||||
nsCOMPtr<nsIPresShell> ps;
|
||||
GetPresShell(getter_AddRefs(ps));
|
||||
NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(aElement);
|
||||
|
@ -329,7 +329,7 @@ public:
|
||||
nsresult EndUpdateViewBatch();
|
||||
|
||||
/** prepare the editor for use */
|
||||
NS_IMETHOD Init(nsIDOMDocument *aDoc, nsIPresShell *aPresShell, nsIContent *aRoot, nsISelectionController *aSelCon, PRUint32 aFlags);
|
||||
NS_IMETHOD Init(nsIDOMDocument *aDoc, nsIContent *aRoot, nsISelectionController *aSelCon, PRUint32 aFlags);
|
||||
NS_IMETHOD PreDestroy(PRBool aDestroyingFrames);
|
||||
|
||||
/** Internal, static version */
|
||||
|
@ -124,7 +124,8 @@ nsHTMLEditor::HideInlineTableEditingUI()
|
||||
RemoveMouseClickListener(mAddRowAfterButton);
|
||||
|
||||
// get the presshell's document observer interface.
|
||||
nsCOMPtr<nsIPresShell> ps = do_QueryReferent(mPresShellWeak);
|
||||
nsCOMPtr<nsIPresShell> ps;
|
||||
GetPresShell(getter_AddRefs(ps));
|
||||
// We allow the pres shell to be null; when it is, we presume there
|
||||
// are no document observers to notify, but we still want to
|
||||
// UnbindFromTree.
|
||||
|
@ -432,7 +432,8 @@ nsHTMLEditor::HideResizers(void)
|
||||
NS_ENSURE_TRUE(mResizedObject, NS_OK);
|
||||
|
||||
// get the presshell's document observer interface.
|
||||
nsCOMPtr<nsIPresShell> ps = do_QueryReferent(mPresShellWeak);
|
||||
nsCOMPtr<nsIPresShell> ps;
|
||||
GetPresShell(getter_AddRefs(ps));
|
||||
// We allow the pres shell to be null; when it is, we presume there
|
||||
// are no document observers to notify, but we still want to
|
||||
// UnbindFromTree.
|
||||
|
@ -2642,8 +2642,9 @@ nsHTMLEditor::GetCellIndexes(nsIDOMElement *aCell,
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_ENSURE_TRUE(mPresShellWeak, NS_ERROR_NOT_INITIALIZED);
|
||||
nsCOMPtr<nsIPresShell> ps = do_QueryReferent(mPresShellWeak);
|
||||
NS_ENSURE_TRUE(mDocWeak, NS_ERROR_NOT_INITIALIZED);
|
||||
nsCOMPtr<nsIPresShell> ps;
|
||||
GetPresShell(getter_AddRefs(ps));
|
||||
NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
nsCOMPtr<nsIContent> nodeAsContent( do_QueryInterface(aCell) );
|
||||
@ -2662,8 +2663,9 @@ nsHTMLEditor::GetTableLayoutObject(nsIDOMElement* aTable, nsITableLayout **table
|
||||
{
|
||||
*tableLayoutObject=nsnull;
|
||||
NS_ENSURE_TRUE(aTable, NS_ERROR_NOT_INITIALIZED);
|
||||
NS_ENSURE_TRUE(mPresShellWeak, NS_ERROR_NOT_INITIALIZED);
|
||||
nsCOMPtr<nsIPresShell> ps = do_QueryReferent(mPresShellWeak);
|
||||
NS_ENSURE_TRUE(mDocWeak, NS_ERROR_NOT_INITIALIZED);
|
||||
nsCOMPtr<nsIPresShell> ps;
|
||||
GetPresShell(getter_AddRefs(ps));
|
||||
NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
nsCOMPtr<nsIContent> nodeAsContent( do_QueryInterface(aTable) );
|
||||
|
@ -72,6 +72,7 @@ _TEST_FILES = \
|
||||
test_bug620906.html \
|
||||
test_bug622371.html \
|
||||
test_bug629845.html \
|
||||
test_bug640321.html \
|
||||
test_CF_HTML_clipboard.html \
|
||||
test_contenteditable_focus.html \
|
||||
test_contenteditable_text_input_handling.html \
|
||||
@ -92,6 +93,7 @@ _CHROME_TEST_FILES = \
|
||||
test_bug490879.xul \
|
||||
test_bug607584.xul \
|
||||
test_bug616590.xul \
|
||||
test_bug635636.html \
|
||||
green.png \
|
||||
$(NULL)
|
||||
|
||||
|
202
editor/libeditor/html/tests/browserscope/lib/richtext2/LICENSE
Normal file
202
editor/libeditor/html/tests/browserscope/lib/richtext2/LICENSE
Normal file
@ -0,0 +1,202 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
@ -0,0 +1,58 @@
|
||||
README FOR BROWSERSCOPE
|
||||
-----------------------
|
||||
|
||||
Hey there - thanks for downloading the code. This file has instructions
|
||||
for getting setup so that you can run the codebase locally.
|
||||
|
||||
This project is built on Google App Engine using the
|
||||
Django web application framework and written in Python.
|
||||
|
||||
To get started, you'll need to first download the App Engine SDK at:
|
||||
http://code.google.com/appengine/downloads.html
|
||||
|
||||
For local development, just startup the server:
|
||||
./pathto/google_appengine/dev_appserver.py --port=8080 browserscope
|
||||
|
||||
You should then be able to access the local application at:
|
||||
http://localhost:8080/
|
||||
|
||||
Note: the first time you hit the homepage it may take a little
|
||||
while - that's because it's trying to read out median times for all
|
||||
of the tests from a nonexistent datastore and write to memcache.
|
||||
Just be a lil patient.
|
||||
|
||||
You can run the unit tests at:
|
||||
http://localhost:8080/test
|
||||
|
||||
|
||||
CONTRIBUTING
|
||||
------------------
|
||||
|
||||
Most likely you are interested in adding new tests or creating
|
||||
a new test category. If you are interested in adding tests to an existing
|
||||
"category" you may want to get in touch with the maintainer for that
|
||||
branch of the tree. We are really looking forward to receiving your
|
||||
code in patch format. Currently the category maintainers are:
|
||||
Network: Steve Souders <souders@gmail.com>
|
||||
Reflow: Lindsey Simon <elsigh@gmail.com>
|
||||
Security: Adam Barth <adam@adambarth.com> and Collin Jackson <collin@collinjackson.com>
|
||||
|
||||
|
||||
To create a completely new test category:
|
||||
* Copy one of the existing directories in categories/
|
||||
* Edit your test_set.py, handlers.py
|
||||
* Add your files in templates/ and static/
|
||||
* Update urls.py and settings.CATEGORIES
|
||||
* Follow the examples of other tests re:
|
||||
* beaconing using/testdriver_base
|
||||
* your GetScoreAndDisplayValue method
|
||||
* your GetRowScoreAndDisplayValue method
|
||||
|
||||
References:
|
||||
* App Engine Docs - http://code.google.com/appengine/docs/python/overview.html
|
||||
* App Engine Group - http://groups.google.com/group/google-appengine
|
||||
* Python Docs - http://www.python.org/doc/
|
||||
* Django - http://www.djangoproject.com/
|
||||
|
||||
|
||||
|
@ -0,0 +1,23 @@
|
||||
The BrowserScope project provides a set of cross-browser HTML editor tests,
|
||||
which we import in our test suite in order to run them as part of our
|
||||
continuous integration system.
|
||||
|
||||
We pull tests occasionally from their Subversion repository using the pull
|
||||
script which can be found in this directory. We also record the revision ID
|
||||
which we've used in the current_revision file inside this directory.
|
||||
|
||||
Using the pull script is quite easy, just switch to this directory, and say:
|
||||
|
||||
sh update_from_upstream
|
||||
|
||||
There are tests which we're currently failing on, and there will probably be
|
||||
more of those in the future. We should maintain a list of the failing tests
|
||||
manually in currentStatus.js (which can also be found in this directory), to
|
||||
make sure that the suite passes entirely, with failing tests marked as todo
|
||||
items.
|
||||
|
||||
The current status of the test suite needs to be updated whenever an editor
|
||||
bug gets fixed, which makes us pass one of the tests. When that happens,
|
||||
you should set the UPDATE_TEST_RESULTS constant to true in test_richtext2.html,
|
||||
run the test suite, paste the result JSON string in a JSON beautifier (such
|
||||
as http://jsbeautifier.org/), and use the result to update currentStatus.js.
|
23821
editor/libeditor/html/tests/browserscope/lib/richtext2/currentStatus.js
Normal file
23821
editor/libeditor/html/tests/browserscope/lib/richtext2/currentStatus.js
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1 @@
|
||||
805
|
25
editor/libeditor/html/tests/browserscope/lib/richtext2/richtext2/common.py
Executable file
25
editor/libeditor/html/tests/browserscope/lib/richtext2/richtext2/common.py
Executable file
@ -0,0 +1,25 @@
|
||||
#!/usr/bin/python2.5
|
||||
#
|
||||
# Copyright 2010 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the 'License')
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Common constants"""
|
||||
|
||||
__author__ = 'rolandsteiner@google.com (Roland Steiner)'
|
||||
|
||||
CATEGORY = 'richtext2'
|
||||
|
||||
TEST_ID_PREFIX = 'RTE2'
|
||||
|
||||
CLASSES = ['Finalized', 'RFC', 'Proposed']
|
107
editor/libeditor/html/tests/browserscope/lib/richtext2/richtext2/handlers.py
Executable file
107
editor/libeditor/html/tests/browserscope/lib/richtext2/richtext2/handlers.py
Executable file
@ -0,0 +1,107 @@
|
||||
#!/usr/bin/python2.5
|
||||
#
|
||||
# Copyright 2010 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the 'License')
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Handlers for New Rich Text Tests"""
|
||||
|
||||
__author__ = 'rolandsteiner@google.com (Roland Steiner)'
|
||||
|
||||
from google.appengine.api import users
|
||||
from google.appengine.ext import db
|
||||
from google.appengine.api import memcache
|
||||
from google.appengine.ext import webapp
|
||||
from google.appengine.ext.webapp import template
|
||||
|
||||
import django
|
||||
from django import http
|
||||
from django import shortcuts
|
||||
|
||||
from django.template import add_to_builtins
|
||||
add_to_builtins('base.custom_filters')
|
||||
|
||||
# Shared stuff
|
||||
from categories import all_test_sets
|
||||
from base import decorators
|
||||
from base import util
|
||||
|
||||
# common to the RichText2 suite
|
||||
from categories.richtext2 import common
|
||||
|
||||
# tests
|
||||
from categories.richtext2.tests.apply import APPLY_TESTS
|
||||
from categories.richtext2.tests.applyCSS import APPLY_TESTS_CSS
|
||||
from categories.richtext2.tests.change import CHANGE_TESTS
|
||||
from categories.richtext2.tests.changeCSS import CHANGE_TESTS_CSS
|
||||
from categories.richtext2.tests.delete import DELETE_TESTS
|
||||
from categories.richtext2.tests.forwarddelete import FORWARDDELETE_TESTS
|
||||
from categories.richtext2.tests.insert import INSERT_TESTS
|
||||
from categories.richtext2.tests.selection import SELECTION_TESTS
|
||||
from categories.richtext2.tests.unapply import UNAPPLY_TESTS
|
||||
from categories.richtext2.tests.unapplyCSS import UNAPPLY_TESTS_CSS
|
||||
|
||||
from categories.richtext2.tests.querySupported import QUERYSUPPORTED_TESTS
|
||||
from categories.richtext2.tests.queryEnabled import QUERYENABLED_TESTS
|
||||
from categories.richtext2.tests.queryIndeterm import QUERYINDETERM_TESTS
|
||||
from categories.richtext2.tests.queryState import QUERYSTATE_TESTS, QUERYSTATE_TESTS_CSS
|
||||
from categories.richtext2.tests.queryValue import QUERYVALUE_TESTS, QUERYVALUE_TESTS_CSS
|
||||
|
||||
|
||||
def About(request):
|
||||
"""About page."""
|
||||
overview = """These tests cover browers' implementations of
|
||||
<a href="http://blog.whatwg.org/the-road-to-html-5-contenteditable">contenteditable</a>
|
||||
for basic rich text formatting commands. Most browser implementations do very
|
||||
well at editing the HTML which is generated by their own execCommands. But a
|
||||
big problem happens when developers try to make cross-browser web
|
||||
applications using contenteditable - most browsers are not able to correctly
|
||||
change formatting generated by other browsers. On top of that, most browsers
|
||||
allow users to to paste arbitrary HTML from other webpages into a
|
||||
contenteditable region, which is even harder for browsers to properly
|
||||
format. These tests check how well the execCommand, queryCommandState,
|
||||
and queryCommandValue functions work with different types of HTML."""
|
||||
return util.About(request, common.CATEGORY, category_title='Rich Text',
|
||||
overview=overview, show_hidden=False)
|
||||
|
||||
|
||||
def RunRichText2Tests(request):
|
||||
params = {
|
||||
'classes': common.CLASSES,
|
||||
'commonIDPrefix': common.TEST_ID_PREFIX,
|
||||
'strict': False,
|
||||
'suites': [
|
||||
SELECTION_TESTS,
|
||||
APPLY_TESTS,
|
||||
APPLY_TESTS_CSS,
|
||||
CHANGE_TESTS,
|
||||
CHANGE_TESTS_CSS,
|
||||
UNAPPLY_TESTS,
|
||||
UNAPPLY_TESTS_CSS,
|
||||
DELETE_TESTS,
|
||||
FORWARDDELETE_TESTS,
|
||||
INSERT_TESTS,
|
||||
|
||||
QUERYSUPPORTED_TESTS,
|
||||
QUERYENABLED_TESTS,
|
||||
QUERYINDETERM_TESTS,
|
||||
QUERYSTATE_TESTS,
|
||||
QUERYSTATE_TESTS_CSS,
|
||||
QUERYVALUE_TESTS,
|
||||
QUERYVALUE_TESTS_CSS
|
||||
]
|
||||
}
|
||||
return shortcuts.render_to_response('%s/templates/richtext2.html' % common.CATEGORY, params)
|
||||
|
||||
|
||||
|
@ -0,0 +1,116 @@
|
||||
.framed {
|
||||
vertical-align: top;
|
||||
margin: 8px;
|
||||
border: 1px solid black;
|
||||
}
|
||||
|
||||
.legend {
|
||||
padding: 12px;
|
||||
background-color: #f8f8ff;
|
||||
}
|
||||
|
||||
.legendHdr {
|
||||
font-size: large;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
table.legend {
|
||||
display: inline-table;
|
||||
}
|
||||
|
||||
.suite-thead {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.lo {
|
||||
background-color: #dddddd;
|
||||
}
|
||||
.hi {
|
||||
background-color: #eeeeee;
|
||||
}
|
||||
|
||||
.lo .grey {
|
||||
background-color: #dddddd;
|
||||
}
|
||||
.lo .na {
|
||||
background-color: #dddddd;
|
||||
}
|
||||
.lo .pass {
|
||||
background-color: #d4ffc0;
|
||||
}
|
||||
.lo .canary {
|
||||
background-color: #ffcccc;
|
||||
}
|
||||
.lo .fail {
|
||||
background-color: #ffcccc;
|
||||
}
|
||||
.lo .accept {
|
||||
background-color: #ffffc0;
|
||||
}
|
||||
.lo .exception {
|
||||
background-color: #f0d0f4;
|
||||
}
|
||||
.lo .unsupported {
|
||||
background-color: #f0d0f4;
|
||||
}
|
||||
|
||||
.hi .grey {
|
||||
background-color: #eeeeee;
|
||||
}
|
||||
.hi .na {
|
||||
background-color: #eeeeee;
|
||||
}
|
||||
.hi .pass {
|
||||
background-color: #e0ffdc;
|
||||
}
|
||||
.hi .canary {
|
||||
background-color: #ffd8d8;
|
||||
}
|
||||
.hi .fail {
|
||||
background-color: #ffd8d8;
|
||||
}
|
||||
.hi .accept {
|
||||
background-color: #ffffd8;
|
||||
}
|
||||
.hi .exception {
|
||||
background-color: #f4dcf8;
|
||||
}
|
||||
.hi .unsupported {
|
||||
background-color: #f4dcf8;
|
||||
}
|
||||
|
||||
|
||||
.sel {
|
||||
color: blue;
|
||||
}
|
||||
|
||||
.txt {
|
||||
padding: 1px;
|
||||
margin: 1px;
|
||||
border: 1px solid #b0b0b0;
|
||||
}
|
||||
|
||||
.idLabel {
|
||||
font-size: small;
|
||||
}
|
||||
|
||||
.fade {
|
||||
color: grey;
|
||||
}
|
||||
.accexp {
|
||||
color: #606070;
|
||||
}
|
||||
.comment {
|
||||
color: grey;
|
||||
}
|
||||
|
||||
.score {
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
.fatalerror {
|
||||
color: red;
|
||||
font-size: large;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
|
||||
<link rel="stylesheet" href="editable.css" type="text/css">
|
||||
</head>
|
||||
<body contentEditable="true">
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
|
||||
<link rel="stylesheet" href="editable.css" type="text/css">
|
||||
|
||||
<script>
|
||||
function setDesignMode() {
|
||||
window.document.designMode = "On";
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="setDesignMode()">
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
|
||||
<link rel="stylesheet" href="editable.css" type="text/css">
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,66 @@
|
||||
.b, myb {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.i, myi {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.s, mys {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
.u, myu {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.sub, mysub {
|
||||
vertical-align: sub;
|
||||
}
|
||||
|
||||
.sup, mysup {
|
||||
vertical-align: super;
|
||||
}
|
||||
|
||||
.jc, myjc {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.jf, myjf {
|
||||
text-align: justify;
|
||||
}
|
||||
|
||||
.jl, myjl {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.jr, myjr {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.red, myred {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.bcred, mybcred {
|
||||
background-color: red;
|
||||
}
|
||||
|
||||
.large, mylarge {
|
||||
font-size: large;
|
||||
}
|
||||
|
||||
.fs18px, myfs18px {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.courier, mycourier {
|
||||
font-family: courier;
|
||||
}
|
||||
|
||||
gen::before {
|
||||
content: "[BEFORE]";
|
||||
}
|
||||
gen::after {
|
||||
content: "[AFTER]";
|
||||
}
|
@ -0,0 +1,436 @@
|
||||
/**
|
||||
* @fileoverview
|
||||
* Canonicalization functions used in the RTE test suite.
|
||||
*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License')
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* @version 0.1
|
||||
* @author rolandsteiner@google.com
|
||||
*/
|
||||
|
||||
/**
|
||||
* Canonicalize HTML entities to their actual character
|
||||
*
|
||||
* @param str {String} the HTML string to be canonicalized
|
||||
* @return {String} the canonicalized string
|
||||
*/
|
||||
|
||||
function canonicalizeEntities(str) {
|
||||
// TODO(rolandsteiner): this function is very much not optimized, but that shouldn't
|
||||
// theoretically matter too much - look into it at some point.
|
||||
var match;
|
||||
while (match = str.match(/&#x([0-9A-F]+);/i)) {
|
||||
str = str.replace('&#x' + match[1] + ';', String.fromCharCode(parseInt(match[1], 16)));
|
||||
}
|
||||
while (match = str.match(/&#([0-9]+);/)) {
|
||||
str = str.replace('&#' + match[1] + ';', String.fromCharCode(Number(match[1])));
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Canonicalize the contents of the HTML 'style' attribute.
|
||||
* I.e. sorts the CSS attributes alphabetically and canonicalizes the values
|
||||
* CSS attributes where necessary.
|
||||
*
|
||||
* If this would return an empty string, return null instead to suppress the
|
||||
* whole 'style' attribute.
|
||||
*
|
||||
* Avoid tests that contain {, } or : within CSS values!
|
||||
*
|
||||
* Note that this function relies on the spaces of the input string already
|
||||
* having been normalized by canonicalizeSpaces!
|
||||
*
|
||||
* FIXME: does not canonicalize the contents of compound attributes
|
||||
* (e.g., 'border').
|
||||
*
|
||||
* @param str {String} contents of the 'style' attribute
|
||||
* @param emitFlags {Object} flags used for this output
|
||||
* @return {String/null} canonicalized string, null instead of the empty string
|
||||
*/
|
||||
function canonicalizeStyle(str, emitFlags) {
|
||||
// Remove any enclosing curly brackets
|
||||
str = str.replace(/ ?[\{\}] ?/g, '');
|
||||
|
||||
var attributes = str.split(';');
|
||||
var count = attributes.length;
|
||||
var resultArr = [];
|
||||
|
||||
for (var a = 0; a < count; ++a) {
|
||||
// Retrieve "name: value" pair
|
||||
// Note: may expectedly fail if the last pair was terminated with ';'
|
||||
var avPair = attributes[a].match(/ ?([^ :]+) ?: ?(.+)/);
|
||||
if (!avPair)
|
||||
continue;
|
||||
|
||||
var name = avPair[1];
|
||||
var value = avPair[2].replace(/ $/, ''); // Remove any trailing space.
|
||||
|
||||
switch (name) {
|
||||
case 'color':
|
||||
case 'background-color':
|
||||
case 'border-color':
|
||||
if (emitFlags.canonicalizeUnits) {
|
||||
resultArr.push(name + ': #' + new Color(value).toHexString());
|
||||
} else {
|
||||
resultArr.push(name + ': ' + value);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'font-family':
|
||||
if (emitFlags.canonicalizeUnits) {
|
||||
resultArr.push(name + ': ' + new FontName(value).toString());
|
||||
} else {
|
||||
resultArr.push(name + ': ' + value);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'font-size':
|
||||
if (emitFlags.canonicalizeUnits) {
|
||||
resultArr.push(name + ': ' + new FontSize(value).toString());
|
||||
} else {
|
||||
resultArr.push(name + ': ' + value);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
resultArr.push(name + ': ' + value);
|
||||
}
|
||||
}
|
||||
|
||||
// Sort by name, assuming no duplicate CSS attribute names.
|
||||
resultArr.sort();
|
||||
|
||||
return resultArr.join('; ') || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Canonicalize a single attribute value.
|
||||
*
|
||||
* Note that this function relies on the spaces of the input string already
|
||||
* having been normalized by canonicalizeSpaces!
|
||||
*
|
||||
* @param elemName {String} the name of the element
|
||||
* @param attrName {String} the name of the attribute
|
||||
* @param attrValue {String} the value of the attribute
|
||||
* @param emitFlags {Object} flags used for this output
|
||||
* @return {String/null} the canonicalized value, or null if the attribute should be skipped.
|
||||
*/
|
||||
function canonicalizeSingleAttribute(elemName, attrName, attrValue, emitFlags) {
|
||||
// We emit attributes as name="value", so change any contained apostrophes
|
||||
// to quote marks.
|
||||
attrValue = attrValue.replace(/\x22/, '\x27');
|
||||
|
||||
switch (attrName) {
|
||||
case 'class':
|
||||
return emitFlags.emitClass ? attrValue : null;
|
||||
|
||||
case 'id':
|
||||
if (!emitFlags.emitID) {
|
||||
return null;
|
||||
}
|
||||
if (attrValue && attrValue.substr(0, 7) == 'editor-') {
|
||||
return null;
|
||||
}
|
||||
return attrValue;
|
||||
|
||||
// Remove empty style attributes, canonicalize the contents otherwise,
|
||||
// provided the test cares for styles.
|
||||
case 'style':
|
||||
return (emitFlags.emitStyle && attrValue)
|
||||
? canonicalizeStyle(attrValue, emitFlags)
|
||||
: null;
|
||||
|
||||
// Never output onload handlers as they are set by the test environment.
|
||||
case 'onload':
|
||||
return null;
|
||||
|
||||
// Canonicalize colors.
|
||||
case 'bgcolor':
|
||||
case 'color':
|
||||
if (!attrValue) {
|
||||
return null;
|
||||
}
|
||||
return emitFlags.canonicalizeUnits ? new Color(attrValue).toString() : attrValue;
|
||||
|
||||
// Canonicalize font names.
|
||||
case 'face':
|
||||
return emitFlags.canonicalizeUnits ? new FontName(attrValue).toString() : attrValue;
|
||||
|
||||
// Canonicalize font sizes (leave other 'size' attributes as-is).
|
||||
case 'size':
|
||||
if (!attrValue) {
|
||||
return null;
|
||||
}
|
||||
switch (elemName) {
|
||||
case 'basefont':
|
||||
case 'font':
|
||||
return emitFlags.canonicalizeUnits ? new FontSize(attrValue).toString() : attrValue;
|
||||
}
|
||||
return attrValue;
|
||||
|
||||
// Remove spans with value 1. Retain spans with other values, even if
|
||||
// empty or with a value 0, since those indicate a flawed implementation.
|
||||
case 'colspan':
|
||||
case 'rowspan':
|
||||
case 'span':
|
||||
return (attrValue == '1' || attrValue === '') ? null : attrValue;
|
||||
|
||||
// Boolean attributes: presence equals true. If present, the value must be
|
||||
// the empty string or the attribute's canonical name.
|
||||
// (http://www.whatwg.org/specs/web-apps/current-work/#boolean-attributes)
|
||||
// Below we only normalize empty string to the canonical name for
|
||||
// comparison purposes. All other values are not touched and will therefore
|
||||
// in all likelihood result in a failed test (even if they may be accepted
|
||||
// by the UA).
|
||||
case 'async':
|
||||
case 'autofocus':
|
||||
case 'checked':
|
||||
case 'compact':
|
||||
case 'declare':
|
||||
case 'defer':
|
||||
case 'disabled':
|
||||
case 'formnovalidate':
|
||||
case 'frameborder':
|
||||
case 'ismap':
|
||||
case 'loop':
|
||||
case 'multiple':
|
||||
case 'nohref':
|
||||
case 'nosize':
|
||||
case 'noshade':
|
||||
case 'novalidate':
|
||||
case 'nowrap':
|
||||
case 'open':
|
||||
case 'readonly':
|
||||
case 'required':
|
||||
case 'reversed':
|
||||
case 'seamless':
|
||||
case 'selected':
|
||||
return attrValue ? attrValue : attrName;
|
||||
|
||||
default:
|
||||
return attrValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Canonicalize the contents of an element tag.
|
||||
*
|
||||
* I.e. sorts the attributes alphabetically and canonicalizes their
|
||||
* values where necessary. Also removes attributes we're not interested in.
|
||||
*
|
||||
* Note that this function relies on the spaces of the input string already
|
||||
* having been normalized by canonicalizeSpaces!
|
||||
*
|
||||
* @param str {String} the contens of the element tag, excluding < and >.
|
||||
* @param emitFlags {Object} flags used for this output
|
||||
* @return {String} the canonicalized contents.
|
||||
*/
|
||||
function canonicalizeElementTag(str, emitFlags) {
|
||||
// FIXME: lowercase only if emitFlags.lowercase is set
|
||||
str = str.toLowerCase();
|
||||
|
||||
var pos = str.search(' ');
|
||||
|
||||
// element name only
|
||||
if (pos == -1) {
|
||||
return str;
|
||||
}
|
||||
|
||||
var elemName = str.substr(0, pos);
|
||||
str = str.substr(pos + 1);
|
||||
|
||||
// Even if emitFlags.emitAttrs is not set, we must iterate over the
|
||||
// attributes to catch the special selection attribute and/or selection
|
||||
// markers. :(
|
||||
|
||||
// Iterate over attributes, add them to an array, canonicalize their
|
||||
// contents, and finally output the (remaining) attributes in sorted order.
|
||||
// Note: We can't do a simple split on space here, because the value of,
|
||||
// e.g., 'style' attributes may also contain spaces.
|
||||
var attrs = [];
|
||||
var selStartInTag = false;
|
||||
var selEndInTag = false;
|
||||
|
||||
while (str) {
|
||||
var attrName;
|
||||
var attrValue = '';
|
||||
|
||||
pos = str.search(/[ =]/);
|
||||
if (pos >= 0) {
|
||||
attrName = str.substr(0, pos);
|
||||
if (str.charAt(pos) == ' ') {
|
||||
++pos;
|
||||
}
|
||||
if (str.charAt(pos) == '=') {
|
||||
++pos;
|
||||
if (str.charAt(pos) == ' ') {
|
||||
++pos;
|
||||
}
|
||||
str = str.substr(pos);
|
||||
switch (str.charAt(0)) {
|
||||
case '"':
|
||||
case "'":
|
||||
pos = str.indexOf(str.charAt(0), 1);
|
||||
pos = (pos < 0) ? str.length : pos;
|
||||
attrValue = str.substring(1, pos);
|
||||
++pos;
|
||||
break;
|
||||
|
||||
default:
|
||||
pos = str.indexOf(' ', 0);
|
||||
pos = (pos < 0) ? str.length : pos;
|
||||
attrValue = (pos == -1) ? str : str.substr(0, pos);
|
||||
break;
|
||||
}
|
||||
attrValue = attrValue.replace(/^ /, '');
|
||||
attrValue = attrValue.replace(/ $/, '');
|
||||
}
|
||||
} else {
|
||||
attrName = str;
|
||||
}
|
||||
str = (pos == -1 || pos >= str.length) ? '' : str.substr(pos + 1);
|
||||
|
||||
// Remove special selection attributes.
|
||||
switch (attrName) {
|
||||
case ATTRNAME_SEL_START:
|
||||
selStartInTag = true;
|
||||
continue;
|
||||
|
||||
case ATTRNAME_SEL_END:
|
||||
selEndInTag = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (attrName) {
|
||||
case '':
|
||||
case 'onload':
|
||||
case 'xmlns':
|
||||
break;
|
||||
|
||||
default:
|
||||
if (!emitFlags.emitAttrs) {
|
||||
break;
|
||||
}
|
||||
// >>> fall through >>>
|
||||
|
||||
case 'contenteditable':
|
||||
attrValue = canonicalizeEntities(attrValue);
|
||||
attrValue = canonicalizeSingleAttribute(elemName, attrName, attrValue, emitFlags);
|
||||
if (attrValue !== null) {
|
||||
attrs.push(attrName + '="' + attrValue + '"');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var result = elemName;
|
||||
|
||||
// Sort alphabetically (on full string rather than just attribute value for
|
||||
// simplicity. Also, attribute names will differ when encountering the '=').
|
||||
if (attrs.length > 0) {
|
||||
attrs.sort();
|
||||
result += ' ' + attrs.join(' ');
|
||||
}
|
||||
|
||||
// Add intra-tag selection marker(s) or attribute(s), if any, at the end.
|
||||
if (selStartInTag && selEndInTag) {
|
||||
result += ' |';
|
||||
} else if (selStartInTag) {
|
||||
result += ' {';
|
||||
} else if (selEndInTag) {
|
||||
result += ' }';
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Canonicalize elements and attributes to facilitate comparison to the
|
||||
* expectation string: sort attributes, canonicalize values and remove chaff.
|
||||
*
|
||||
* Note that this function relies on the spaces of the input string already
|
||||
* having been normalized by canonicalizeSpaces!
|
||||
*
|
||||
* @param str {String} the HTML string to be canonicalized
|
||||
* @param emitFlags {Object} flags used for this output
|
||||
* @return {String} the canonicalized string
|
||||
*/
|
||||
function canonicalizeElementsAndAttributes(str, emitFlags) {
|
||||
var tagStart = str.indexOf('<');
|
||||
var tagEnd = 0;
|
||||
var result = '';
|
||||
|
||||
while (tagStart >= 0) {
|
||||
++tagStart;
|
||||
if (str.charAt(tagStart) == '/') {
|
||||
++tagStart;
|
||||
}
|
||||
result = result + canonicalizeEntities(str.substring(tagEnd, tagStart));
|
||||
tagEnd = str.indexOf('>', tagStart);
|
||||
if (tagEnd < 0) {
|
||||
tagEnd = str.length - 1;
|
||||
}
|
||||
if (str.charAt(tagEnd - 1) == '/') {
|
||||
--tagEnd;
|
||||
}
|
||||
var elemStr = str.substring(tagStart, tagEnd);
|
||||
elemStr = canonicalizeElementTag(elemStr, emitFlags);
|
||||
result = result + elemStr;
|
||||
tagStart = str.indexOf('<', tagEnd);
|
||||
}
|
||||
return result + canonicalizeEntities(str.substring(tagEnd));
|
||||
}
|
||||
|
||||
/**
|
||||
* Canonicalize an innerHTML string to uniform single whitespaces.
|
||||
*
|
||||
* FIXME: running this prevents testing for pre-formatted content
|
||||
* and the CSS 'white-space' attribute.
|
||||
*
|
||||
* @param str {String} the HTML string to be canonicalized
|
||||
* @return {String} the canonicalized string
|
||||
*/
|
||||
function canonicalizeSpaces(str) {
|
||||
// Collapse sequential whitespace.
|
||||
str = str.replace(/\s+/g, ' ');
|
||||
|
||||
// Remove spaces immediately inside angle brackets <, >, </ and />.
|
||||
// While doing this also canonicalize <.../> to <...>.
|
||||
str = str.replace(/\< ?/g, '<');
|
||||
str = str.replace(/\<\/ ?/g, '</');
|
||||
str = str.replace(/ ?\/?\>/g, '>');
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Canonicalize an innerHTML string to uniform single whitespaces.
|
||||
* Also remove comments to retain only embedded selection markers, and
|
||||
* remove </br> and </hr> if present.
|
||||
*
|
||||
* FIXME: running this prevents testing for pre-formatted content
|
||||
* and the CSS 'white-space' attribute.
|
||||
*
|
||||
* @param str {String} the HTML string to be canonicalized
|
||||
* @return {String} the canonicalized string
|
||||
*/
|
||||
function initialCanonicalizationOf(str) {
|
||||
str = canonicalizeSpaces(str);
|
||||
str = str.replace(/ ?<!-- ?/g, '');
|
||||
str = str.replace(/ ?--> ?/g, '');
|
||||
str = str.replace(/<\/[bh]r>/g, '');
|
||||
|
||||
return str;
|
||||
}
|
@ -0,0 +1,489 @@
|
||||
/**
|
||||
* @fileoverview
|
||||
* Comparison functions used in the RTE test suite.
|
||||
*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License')
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* @version 0.1
|
||||
* @author rolandsteiner@google.com
|
||||
*/
|
||||
|
||||
/**
|
||||
* constants used only in the compare functions.
|
||||
*/
|
||||
var RESULT_DIFF = 0; // actual result doesn't match expectation
|
||||
var RESULT_SEL = 1; // actual result matches expectation in HTML only
|
||||
var RESULT_EQUAL = 2; // actual result matches expectation in both HTML and selection
|
||||
|
||||
/**
|
||||
* Gets the test expectations as an array from the passed-in field.
|
||||
*
|
||||
* @param {Array|String} the test expectation(s) as string or array.
|
||||
* @return {Array} test expectations as an array.
|
||||
*/
|
||||
function getExpectationArray(expected) {
|
||||
if (expected === undefined) {
|
||||
return [];
|
||||
}
|
||||
if (expected === null) {
|
||||
return [null];
|
||||
}
|
||||
switch (typeof expected) {
|
||||
case 'string':
|
||||
case 'boolean':
|
||||
case 'number':
|
||||
return [expected];
|
||||
}
|
||||
// Assume it's already an array.
|
||||
return expected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare a test result to a single expectation string.
|
||||
*
|
||||
* FIXME: add support for optional elements/attributes.
|
||||
*
|
||||
* @param expected {String} the already canonicalized (with the exception of selection marks) expectation string
|
||||
* @param actual {String} the already canonicalized (with the exception of selection marks) actual result
|
||||
* @return {Integer} one of the RESULT_... return values
|
||||
* @see variables.js for return values
|
||||
*/
|
||||
function compareHTMLToSingleExpectation(expected, actual) {
|
||||
// If the test checks the selection, then the actual string must match the
|
||||
// expectation exactly.
|
||||
if (expected == actual) {
|
||||
return RESULT_EQUAL;
|
||||
}
|
||||
|
||||
// Remove selection markers and see if strings match then.
|
||||
expected = expected.replace(/ [{}\|]>/g, '>'); // intra-tag
|
||||
expected = expected.replace(/[\[\]\^{}\|]/g, ''); // outside tag
|
||||
actual = actual.replace(/ [{}\|]>/g, '>'); // intra-tag
|
||||
actual = actual.replace(/[\[\]\^{}\|]/g, ''); // outside tag
|
||||
|
||||
return (expected == actual) ? RESULT_SEL : RESULT_DIFF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare the current HTMLtest result to the expectation string(s).
|
||||
*
|
||||
* @param actual {String/Boolean} actual value
|
||||
* @param expected {String/Array} expectation(s)
|
||||
* @param emitFlags {Object} flags to use for canonicalization
|
||||
* @return {Integer} one of the RESULT_... return values
|
||||
* @see variables.js for return values
|
||||
*/
|
||||
function compareHTMLToExpectation(actual, expected, emitFlags) {
|
||||
// Find the most favorable result among the possible expectation strings.
|
||||
var expectedArr = getExpectationArray(expected);
|
||||
var count = expectedArr ? expectedArr.length : 0;
|
||||
var best = RESULT_DIFF;
|
||||
|
||||
for (var idx = 0; idx < count && best < RESULT_EQUAL; ++idx) {
|
||||
var expected = expectedArr[idx];
|
||||
expected = canonicalizeSpaces(expected);
|
||||
expected = canonicalizeElementsAndAttributes(expected, emitFlags);
|
||||
|
||||
var singleResult = compareHTMLToSingleExpectation(expected, actual);
|
||||
|
||||
best = Math.max(best, singleResult);
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare the current HTMLtest result to expected and acceptable results
|
||||
*
|
||||
* @param expected {String/Array} expected result(s)
|
||||
* @param accepted {String/Array} accepted result(s)
|
||||
* @param actual {String} actual result
|
||||
* @param emitFlags {Object} how to canonicalize the HTML strings
|
||||
* @param result {Object} [out] object recieving the result of the comparison.
|
||||
*/
|
||||
function compareHTMLTestResultTo(expected, accepted, actual, emitFlags, result) {
|
||||
actual = actual.replace(/[\x60\xb4]/g, '');
|
||||
actual = canonicalizeElementsAndAttributes(actual, emitFlags);
|
||||
|
||||
var bestExpected = compareHTMLToExpectation(actual, expected, emitFlags);
|
||||
|
||||
if (bestExpected == RESULT_EQUAL) {
|
||||
// Shortcut - it doesn't get any better
|
||||
result.valresult = VALRESULT_EQUAL;
|
||||
result.selresult = SELRESULT_EQUAL;
|
||||
return;
|
||||
}
|
||||
|
||||
var bestAccepted = compareHTMLToExpectation(actual, accepted, emitFlags);
|
||||
|
||||
switch (bestExpected) {
|
||||
case RESULT_SEL:
|
||||
switch (bestAccepted) {
|
||||
case RESULT_EQUAL:
|
||||
// The HTML was equal to the/an expected HTML result as well
|
||||
// (just not the selection there), therefore the difference
|
||||
// between expected and accepted can only lie in the selection.
|
||||
result.valresult = VALRESULT_EQUAL;
|
||||
result.selresult = SELRESULT_ACCEPT;
|
||||
return;
|
||||
|
||||
case RESULT_SEL:
|
||||
case RESULT_DIFF:
|
||||
// The acceptable expectations did not yield a better result
|
||||
// -> stay with the original (i.e., comparison to 'expected') result.
|
||||
result.valresult = VALRESULT_EQUAL;
|
||||
result.selresult = SELRESULT_DIFF;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case RESULT_DIFF:
|
||||
switch (bestAccepted) {
|
||||
case RESULT_EQUAL:
|
||||
result.valresult = VALRESULT_ACCEPT;
|
||||
result.selresult = SELRESULT_EQUAL;
|
||||
return;
|
||||
|
||||
case RESULT_SEL:
|
||||
result.valresult = VALRESULT_ACCEPT;
|
||||
result.selresult = SELRESULT_DIFF;
|
||||
return;
|
||||
|
||||
case RESULT_DIFF:
|
||||
result.valresult = VALRESULT_DIFF;
|
||||
result.selresult = SELRESULT_NA;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
throw INTERNAL_ERR + HTML_COMPARISON;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the canaries are unviolated.
|
||||
*
|
||||
* @param container {Object} the test container descriptor as object reference
|
||||
* @param result {Object} object reference that contains the result data
|
||||
* @return {Boolean} whether the canaries' HTML is OK (selection flagged, but not fatal)
|
||||
*/
|
||||
function verifyCanaries(container, result) {
|
||||
if (!container.canary) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var str = canonicalizeElementsAndAttributes(result.bodyInnerHTML, emitFlagsForCanary);
|
||||
|
||||
if (str.length < 2 * container.canary.length) {
|
||||
result.valresult = VALRESULT_CANARY;
|
||||
result.selresult = SELRESULT_NA;
|
||||
result.output = result.bodyOuterHTML;
|
||||
return false;
|
||||
}
|
||||
|
||||
var strBefore = str.substr(0, container.canary.length);
|
||||
var strAfter = str.substr(str.length - container.canary.length);
|
||||
|
||||
// Verify that the canary stretch doesn't contain any selection markers
|
||||
if (SELECTION_MARKERS.test(strBefore) || SELECTION_MARKERS.test(strAfter)) {
|
||||
str = str.replace(SELECTION_MARKERS, '');
|
||||
if (str.length < 2 * container.canary.length) {
|
||||
result.valresult = VALRESULT_CANARY;
|
||||
result.selresult = SELRESULT_NA;
|
||||
result.output = result.bodyOuterHTML;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Selection escaped contentEditable element, but HTML may still be ok.
|
||||
result.selresult = SELRESULT_CANARY;
|
||||
strBefore = str.substr(0, container.canary.length);
|
||||
strAfter = str.substr(str.length - container.canary.length);
|
||||
}
|
||||
|
||||
if (strBefore !== container.canary || strAfter !== container.canary) {
|
||||
result.valresult = VALRESULT_CANARY;
|
||||
result.selresult = SELRESULT_NA;
|
||||
result.output = result.bodyOuterHTML;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare the current HTMLtest result to the expectation string(s).
|
||||
* Sets the global result variables.
|
||||
*
|
||||
* @param suite {Object} the test suite as object reference
|
||||
* @param group {Object} group of tests within the suite the test belongs to
|
||||
* @param test {Object} the test as object reference
|
||||
* @param container {Object} the test container description
|
||||
* @param result {Object} [in/out] the result description, incl. HTML strings
|
||||
* @see variables.js for result values
|
||||
*/
|
||||
function compareHTMLTestResult(suite, group, test, container, result) {
|
||||
if (!verifyCanaries(container, result)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var emitFlags = {
|
||||
emitAttrs: getTestParameter(suite, group, test, PARAM_CHECK_ATTRIBUTES),
|
||||
emitStyle: getTestParameter(suite, group, test, PARAM_CHECK_STYLE),
|
||||
emitClass: getTestParameter(suite, group, test, PARAM_CHECK_CLASS),
|
||||
emitID: getTestParameter(suite, group, test, PARAM_CHECK_ID),
|
||||
lowercase: true,
|
||||
canonicalizeUnits: true
|
||||
};
|
||||
|
||||
// 2a.) Compare opening tag -
|
||||
// decide whether to compare vs. outer or inner HTML based on this.
|
||||
var openingTagEnd = result.outerHTML.indexOf('>') + 1;
|
||||
var openingTag = result.outerHTML.substr(0, openingTagEnd);
|
||||
|
||||
openingTag = canonicalizeElementsAndAttributes(openingTag, emitFlags);
|
||||
var tagCmp = compareHTMLToExpectation(openingTag, container.tagOpen, emitFlags);
|
||||
|
||||
if (tagCmp == RESULT_EQUAL) {
|
||||
result.output = result.innerHTML;
|
||||
compareHTMLTestResultTo(
|
||||
getTestParameter(suite, group, test, PARAM_EXPECTED),
|
||||
getTestParameter(suite, group, test, PARAM_ACCEPT),
|
||||
result.innerHTML,
|
||||
emitFlags,
|
||||
result)
|
||||
} else {
|
||||
result.output = result.outerHTML;
|
||||
compareHTMLTestResultTo(
|
||||
getContainerParameter(suite, group, test, container, PARAM_EXPECTED_OUTER),
|
||||
getContainerParameter(suite, group, test, container, PARAM_ACCEPT_OUTER),
|
||||
result.outerHTML,
|
||||
emitFlags,
|
||||
result)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a selection position indicator.
|
||||
*
|
||||
* @param node {DOMNode} the node where to insert the selection indicator
|
||||
* @param offs {Integer} the offset of the selection indicator
|
||||
* @param textInd {String} the indicator to use if the node is a text node
|
||||
* @param elemInd {String} the indicator to use if the node is an element node
|
||||
*/
|
||||
function insertSelectionIndicator(node, offs, textInd, elemInd) {
|
||||
switch (node.nodeType) {
|
||||
case DOM_NODE_TYPE_TEXT:
|
||||
// Insert selection marker for text node into text content.
|
||||
var text = node.data;
|
||||
node.data = text.substring(0, offs) + textInd + text.substring(offs);
|
||||
break;
|
||||
|
||||
case DOM_NODE_TYPE_ELEMENT:
|
||||
var child = node.firstChild;
|
||||
try {
|
||||
// node has other children: insert marker as comment node
|
||||
var comment = document.createComment(elemInd);
|
||||
while (child && offs) {
|
||||
--offs;
|
||||
child = child.nextSibling;
|
||||
}
|
||||
if (child) {
|
||||
node.insertBefore(comment, child);
|
||||
} else {
|
||||
node.appendChild(comment);
|
||||
}
|
||||
} catch (ex) {
|
||||
// can't append child comment -> insert as special attribute(s)
|
||||
switch (elemInd) {
|
||||
case '|':
|
||||
node.setAttribute(ATTRNAME_SEL_START, '1');
|
||||
node.setAttribute(ATTRNAME_SEL_END, '1');
|
||||
break;
|
||||
|
||||
case '{':
|
||||
node.setAttribute(ATTRNAME_SEL_START, '1');
|
||||
break;
|
||||
|
||||
case '}':
|
||||
node.setAttribute(ATTRNAME_SEL_END, '1');
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds quotes around all text nodes to show cases with non-normalized
|
||||
* text nodes. Those are not a bug, but may still be usefil in helping to
|
||||
* debug erroneous cases.
|
||||
*
|
||||
* @param node {DOMNode} root node from which to descend
|
||||
*/
|
||||
function encloseTextNodesWithQuotes(node) {
|
||||
switch (node.nodeType) {
|
||||
case DOM_NODE_TYPE_ELEMENT:
|
||||
for (var i = 0; i < node.childNodes.length; ++i) {
|
||||
encloseTextNodesWithQuotes(node.childNodes[i]);
|
||||
}
|
||||
break;
|
||||
|
||||
case DOM_NODE_TYPE_TEXT:
|
||||
node.data = '\x60' + node.data + '\xb4';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the result of a test run and do some preliminary canonicalization.
|
||||
*
|
||||
* @param container {Object} the container where to retrieve the result from as object reference
|
||||
* @param result {Object} object reference that contains the result data
|
||||
* @return {String} a preliminarily canonicalized innerHTML with selection markers
|
||||
*/
|
||||
function prepareHTMLTestResult(container, result) {
|
||||
// Start with empty strings in case any of the below throws.
|
||||
result.innerHTML = '';
|
||||
result.outerHTML = '';
|
||||
|
||||
// 1.) insert selection markers
|
||||
var selRange = createFromWindow(container.win);
|
||||
if (selRange) {
|
||||
// save values, since range object gets auto-modified
|
||||
var node1 = selRange.getAnchorNode();
|
||||
var offs1 = selRange.getAnchorOffset();
|
||||
var node2 = selRange.getFocusNode();
|
||||
var offs2 = selRange.getFocusOffset();
|
||||
|
||||
// add markers
|
||||
if (node1 && node1 == node2 && offs1 == offs2) {
|
||||
// collapsed selection
|
||||
insertSelectionIndicator(node1, offs1, '^', '|');
|
||||
} else {
|
||||
// Start point and end point are different
|
||||
if (node1) {
|
||||
insertSelectionIndicator(node1, offs1, '[', '{');
|
||||
}
|
||||
|
||||
if (node2) {
|
||||
if (node1 == node2 && offs1 < offs2) {
|
||||
// Anchor indicator was inserted under the same node, so we need
|
||||
// to shift the offset by 1
|
||||
++offs2;
|
||||
}
|
||||
insertSelectionIndicator(node2, offs2, ']', '}');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2.) insert markers for text node boundaries;
|
||||
encloseTextNodesWithQuotes(container.editor);
|
||||
|
||||
// 3.) retrieve inner and outer HTML
|
||||
result.innerHTML = initialCanonicalizationOf(container.editor.innerHTML);
|
||||
result.bodyInnerHTML = initialCanonicalizationOf(container.body.innerHTML);
|
||||
if (goog.userAgent.IE) {
|
||||
result.outerHTML = initialCanonicalizationOf(container.editor.outerHTML);
|
||||
result.bodyOuterHTML = initialCanonicalizationOf(container.body.outerHTML);
|
||||
result.outerHTML = result.outerHTML.replace(/^\s+/, '');
|
||||
result.outerHTML = result.outerHTML.replace(/\s+$/, '');
|
||||
result.bodyOuterHTML = result.bodyOuterHTML.replace(/^\s+/, '');
|
||||
result.bodyOuterHTML = result.bodyOuterHTML.replace(/\s+$/, '');
|
||||
} else {
|
||||
result.outerHTML = initialCanonicalizationOf(new XMLSerializer().serializeToString(container.editor));
|
||||
result.bodyOuterHTML = initialCanonicalizationOf(new XMLSerializer().serializeToString(container.body));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare a text test result to the expectation string(s).
|
||||
*
|
||||
* @param suite {Object} the test suite as object reference
|
||||
* @param group {Object} group of tests within the suite the test belongs to
|
||||
* @param test {Object} the test as object reference
|
||||
* @param actual {String/Boolean} actual value
|
||||
* @param expected {String/Array} expectation(s)
|
||||
* @return {Boolean} whether we found a match
|
||||
*/
|
||||
function compareTextTestResultWith(suite, group, test, actual, expected) {
|
||||
var expectedArr = getExpectationArray(expected);
|
||||
// Find the most favorable result among the possible expectation strings.
|
||||
var count = expectedArr.length;
|
||||
|
||||
// If the value matches the expectation exactly, then we're fine.
|
||||
for (var idx = 0; idx < count; ++idx) {
|
||||
if (actual === expectedArr[idx])
|
||||
return true;
|
||||
}
|
||||
|
||||
// Otherwise see if we should canonicalize specific value types.
|
||||
//
|
||||
// We only need to look at font name, color and size units if the originating
|
||||
// test was both a) queryCommandValue and b) querying a font name/color/size
|
||||
// specific criterion.
|
||||
//
|
||||
// TODO(rolandsteiner): This is ugly! Refactor!
|
||||
switch (getTestParameter(suite, group, test, PARAM_QUERYCOMMANDVALUE)) {
|
||||
case 'backcolor':
|
||||
case 'forecolor':
|
||||
case 'hilitecolor':
|
||||
for (var idx = 0; idx < count; ++idx) {
|
||||
if (new Color(actual).compare(new Color(expectedArr[idx])))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
case 'fontname':
|
||||
for (var idx = 0; idx < count; ++idx) {
|
||||
if (new FontName(actual).compare(new FontName(expectedArr[idx])))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
case 'fontsize':
|
||||
for (var idx = 0; idx < count; ++idx) {
|
||||
if (new FontSize(actual).compare(new FontSize(expectedArr[idx])))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare the passed-in text test result to the expectation string(s).
|
||||
* Sets the global result variables.
|
||||
*
|
||||
* @param suite {Object} the test suite as object reference
|
||||
* @param group {Object} group of tests within the suite the test belongs to
|
||||
* @param test {Object} the test as object reference
|
||||
* @param actual {String/Boolean} actual value
|
||||
* @return {Integer} a RESUTLHTML... result value
|
||||
* @see variables.js for result values
|
||||
*/
|
||||
function compareTextTestResult(suite, group, test, result) {
|
||||
var expected = getTestParameter(suite, group, test, PARAM_EXPECTED);
|
||||
if (compareTextTestResultWith(suite, group, test, result.output, expected)) {
|
||||
result.valresult = VALRESULT_EQUAL;
|
||||
return;
|
||||
}
|
||||
var accepted = getTestParameter(suite, group, test, PARAM_ACCEPT);
|
||||
if (accepted && compareTextTestResultWith(suite, group, test, result.output, accepted)) {
|
||||
result.valresult = VALRESULT_ACCEPT;
|
||||
return;
|
||||
}
|
||||
result.valresult = VALRESULT_DIFF;
|
||||
}
|
||||
|
@ -0,0 +1,456 @@
|
||||
/**
|
||||
* @fileoverview
|
||||
* Functions used to format the test result output.
|
||||
*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License')
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* @version 0.1
|
||||
* @author rolandsteiner@google.com
|
||||
*/
|
||||
|
||||
/**
|
||||
* Writes a fatal error to the output (replaces alert box)
|
||||
*
|
||||
* @param text {String} text to output
|
||||
*/
|
||||
function writeFatalError(text) {
|
||||
var errorsStart = document.getElementById('errors');
|
||||
var divider = document.getElementById('divider');
|
||||
if (!errorsStart) {
|
||||
errorsStart = document.createElement('hr');
|
||||
errorsStart.id = 'errors';
|
||||
divider.parentNode.insertBefore(errorsStart, divider);
|
||||
}
|
||||
var error = document.createElement('div');
|
||||
error.className = 'fatalerror';
|
||||
error.innerHTML = 'FATAL ERROR: ' + escapeOutput(text);
|
||||
errorsStart.parentNode.insertBefore(error, divider);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a unique ID for a given single test out of the suite ID and
|
||||
* test ID.
|
||||
*
|
||||
* @param suiteID {string} ID string of the suite
|
||||
* @param testID {string} ID string of the individual tests
|
||||
* @return {string} globally unique ID
|
||||
*/
|
||||
function generateOutputID(suiteID, testID) {
|
||||
return commonIDPrefix + '-' + suiteID + '_' + testID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to highlight the selection markers
|
||||
*
|
||||
* @param str {String} a HTML string containing selection markers
|
||||
* @return {String} the HTML string with highlighting tags around the markers
|
||||
*/
|
||||
function highlightSelectionMarkers(str) {
|
||||
str = str.replace(/\[/g, '<span class="sel">[</span>');
|
||||
str = str.replace(/\]/g, '<span class="sel">]</span>');
|
||||
str = str.replace(/\^/g, '<span class="sel">^</span>');
|
||||
str = str.replace(/{/g, '<span class="sel">{</span>');
|
||||
str = str.replace(/}/g, '<span class="sel">}</span>');
|
||||
str = str.replace(/\|/g, '<b class="sel">|</b>');
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to highlight the selection markers
|
||||
*
|
||||
* @param str {String} a HTML string containing selection markers
|
||||
* @return {String} the HTML string with highlighting tags around the markers
|
||||
*/
|
||||
function highlightSelectionMarkersAndTextNodes(str) {
|
||||
str = highlightSelectionMarkers(str);
|
||||
str = str.replace(/\x60/g, '<span class="txt">');
|
||||
str = str.replace(/\xb4/g, '</span>');
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to format output according to type
|
||||
*
|
||||
* @param value {String/Boolean} string or value to format
|
||||
* @return {String} HTML-formatted string
|
||||
*/
|
||||
function formatValueOrString(value) {
|
||||
if (value === undefined)
|
||||
return '<i>undefined</i>';
|
||||
if (value === null)
|
||||
return '<i>null</i>';
|
||||
|
||||
switch (typeof value) {
|
||||
case 'boolean':
|
||||
return '<i>' + value.toString() + '</i>';
|
||||
|
||||
case 'number':
|
||||
return value.toString();
|
||||
|
||||
case 'string':
|
||||
return "'" + escapeOutput(value) + "'";
|
||||
|
||||
default:
|
||||
return '<i>(' + escapeOutput(value.toString()) + ')</i>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to highlight text nodes
|
||||
*
|
||||
* @param suite {Object} the suite the test belongs to
|
||||
* @param group {Object} the group within the suite the test belongs to
|
||||
* @param test {Object} the test description as object reference
|
||||
* @param actual {String} a HTML string containing text nodes with markers
|
||||
* @return {String} string with highlighting tags around the text node parts
|
||||
*/
|
||||
function formatActualResult(suite, group, test, actual) {
|
||||
if (typeof actual != 'string')
|
||||
return formatValueOrString(actual);
|
||||
|
||||
actual = escapeOutput(actual);
|
||||
|
||||
// Fade attributes (or just style) if not actually tested for
|
||||
if (!getTestParameter(suite, group, test, PARAM_CHECK_ATTRIBUTES)) {
|
||||
actual = actual.replace(/([^ =]+)=\x22([^\x22]*)\x22/g, '<span class="fade">$1="$2"</span>');
|
||||
} else {
|
||||
// NOTE: convert 'class="..."' first, before adding other <span class="fade">...</span> !!!
|
||||
if (!getTestParameter(suite, group, test, PARAM_CHECK_CLASS)) {
|
||||
actual = actual.replace(/class=\x22([^\x22]*)\x22/g, '<span class="fade">class="$1"</span>');
|
||||
}
|
||||
if (!getTestParameter(suite, group, test, PARAM_CHECK_STYLE)) {
|
||||
actual = actual.replace(/style=\x22([^\x22]*)\x22/g, '<span class="fade">style="$1"</span>');
|
||||
}
|
||||
if (!getTestParameter(suite, group, test, PARAM_CHECK_ID)) {
|
||||
actual = actual.replace(/id=\x22([^\x22]*)\x22/g, '<span class="fade">id="$1"</span>');
|
||||
} else {
|
||||
// fade out contenteditable host element's 'editor-<xyz>' ID.
|
||||
actual = actual.replace(/id=\x22editor-([^\x22]*)\x22/g, '<span class="fade">id="editor-$1"</span>');
|
||||
}
|
||||
// grey out 'xmlns'
|
||||
actual = actual.replace(/xmlns=\x22([^\x22]*)\x22/g, '<span class="fade">xmlns="$1"</span>');
|
||||
// remove 'onload'
|
||||
actual = actual.replace(/onload=\x22[^\x22]*\x22 ?/g, '');
|
||||
}
|
||||
// Highlight selection markers and text nodes.
|
||||
actual = highlightSelectionMarkersAndTextNodes(actual);
|
||||
|
||||
return actual;
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape text content for use with .innerHTML.
|
||||
*
|
||||
* @param str {String} HTML text to displayed
|
||||
* @return {String} the escaped HTML
|
||||
*/
|
||||
function escapeOutput(str) {
|
||||
return str ? str.replace(/\</g, '<').replace(/\>/g, '>') : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills in a single output table cell
|
||||
*
|
||||
* @param id {String} ID of the table cell
|
||||
* @param val {String} inner HTML to set
|
||||
* @param ttl {String, optional} value of the 'title' attribute
|
||||
* @param cls {String, optional} class name for the cell
|
||||
*/
|
||||
function setTD(id, val, ttl, cls) {
|
||||
var td = document.getElementById(id);
|
||||
if (td) {
|
||||
td.innerHTML = val;
|
||||
if (ttl) {
|
||||
td.title = ttl;
|
||||
}
|
||||
if (cls) {
|
||||
td.className = cls;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the results of a single test suite
|
||||
*
|
||||
* @param suite {Object} test suite as object reference
|
||||
* @param clsID {String} test class ID ('Proposed', 'RFC', 'Final')
|
||||
* @param group {Object} the group of tests within the suite the test belongs to
|
||||
* @param testIdx {Object} the test as object reference
|
||||
*/
|
||||
function outputTestResults(suite, clsID, group, test) {
|
||||
var suiteID = suite.id;
|
||||
var cls = suite[clsID];
|
||||
var trID = generateOutputID(suiteID, test.id);
|
||||
var testResult = results[suiteID][clsID][test.id];
|
||||
var testValOut = VALOUTPUT[testResult.valresult];
|
||||
var testSelOut = SELOUTPUT[testResult.selresult];
|
||||
|
||||
var suiteChecksSelOnly = !suiteChecksHTMLOrText(suite);
|
||||
var testUsesHTML = !!getTestParameter(suite, group, test, PARAM_EXECCOMMAND) ||
|
||||
!!getTestParameter(suite, group, test, PARAM_FUNCTION);
|
||||
|
||||
// Set background color for test ID
|
||||
var td = document.getElementById(trID + IDOUT_TESTID);
|
||||
if (td) {
|
||||
td.className = (suiteChecksSelOnly && testResult.selresult != SELRESULT_NA) ? testSelOut.css : testValOut.css;
|
||||
}
|
||||
|
||||
// Fill in "Command" and "Value" cells
|
||||
var cmd;
|
||||
var cmdOutput = ' ';
|
||||
var valOutput = ' ';
|
||||
|
||||
if (cmd = getTestParameter(suite, group, test, PARAM_EXECCOMMAND)) {
|
||||
cmdOutput = escapeOutput(cmd);
|
||||
var val = getTestParameter(suite, group, test, PARAM_VALUE);
|
||||
if (val !== undefined) {
|
||||
valOutput = formatValueOrString(val);
|
||||
}
|
||||
} else if (cmd = getTestParameter(suite, group, test, PARAM_FUNCTION)) {
|
||||
cmdOutput = '<i>' + escapeOutput(cmd) + '</i>';
|
||||
} else if (cmd = getTestParameter(suite, group, test, PARAM_QUERYCOMMANDSUPPORTED)) {
|
||||
cmdOutput = '<i>queryCommandSupported</i>';
|
||||
valOutput = escapeOutput(cmd);
|
||||
} else if (cmd = getTestParameter(suite, group, test, PARAM_QUERYCOMMANDENABLED)) {
|
||||
cmdOutput = '<i>queryCommandEnabled</i>';
|
||||
valOutput = escapeOutput(cmd);
|
||||
} else if (cmd = getTestParameter(suite, group, test, PARAM_QUERYCOMMANDINDETERM)) {
|
||||
cmdOutput = '<i>queryCommandIndeterm</i>';
|
||||
valOutput = escapeOutput(cmd);
|
||||
} else if (cmd = getTestParameter(suite, group, test, PARAM_QUERYCOMMANDSTATE)) {
|
||||
cmdOutput = '<i>queryCommandState</i>';
|
||||
valOutput = escapeOutput(cmd);
|
||||
} else if (cmd = getTestParameter(suite, group, test, PARAM_QUERYCOMMANDVALUE)) {
|
||||
cmdOutput = '<i>queryCommandValue</i>';
|
||||
valOutput = escapeOutput(cmd);
|
||||
} else {
|
||||
cmdOutput = '<i>(none)</i>';
|
||||
}
|
||||
setTD(trID + IDOUT_COMMAND, cmdOutput);
|
||||
setTD(trID + IDOUT_VALUE, valOutput);
|
||||
|
||||
// Fill in "Attribute checked?" and "Style checked?" cells
|
||||
if (testUsesHTML) {
|
||||
var checkAttrs = getTestParameter(suite, group, test, PARAM_CHECK_ATTRIBUTES);
|
||||
var checkStyle = getTestParameter(suite, group, test, PARAM_CHECK_STYLE);
|
||||
|
||||
setTD(trID + IDOUT_CHECKATTRS,
|
||||
checkAttrs ? OUTSTR_YES : OUTSTR_NO,
|
||||
checkAttrs ? 'attributes must match' : 'attributes are ignored');
|
||||
|
||||
if (checkAttrs && checkStyle) {
|
||||
setTD(trID + IDOUT_CHECKSTYLE, OUTSTR_YES, 'style attribute contents must match');
|
||||
} else if (checkAttrs) {
|
||||
setTD(trID + IDOUT_CHECKSTYLE, OUTSTR_NO, 'style attribute contents is ignored');
|
||||
} else {
|
||||
setTD(trID + IDOUT_CHECKSTYLE, OUTSTR_NO, 'all attributes (incl. style) are ignored');
|
||||
}
|
||||
} else {
|
||||
setTD(trID + IDOUT_CHECKATTRS, OUTSTR_NA, 'attributes not applicable');
|
||||
setTD(trID + IDOUT_CHECKSTYLE, OUTSTR_NA, 'style not applicable');
|
||||
}
|
||||
|
||||
// Fill in test pad specification cell (initial HTML + selection markers)
|
||||
setTD(trID + IDOUT_PAD, highlightSelectionMarkers(escapeOutput(getTestParameter(suite, group, test, PARAM_PAD))));
|
||||
|
||||
// Fill in expected result(s) cell
|
||||
var expectedOutput = '';
|
||||
var expectedArr = getExpectationArray(getTestParameter(suite, group, test, PARAM_EXPECTED));
|
||||
for (var idx = 0; idx < expectedArr.length; ++idx) {
|
||||
if (expectedOutput) {
|
||||
expectedOutput += '\xA0\xA0\xA0<i>or</i><br>';
|
||||
}
|
||||
expectedOutput += testUsesHTML ? highlightSelectionMarkers(escapeOutput(expectedArr[idx]))
|
||||
: formatValueOrString(expectedArr[idx]);
|
||||
}
|
||||
var acceptedArr = getExpectationArray(getTestParameter(suite, group, test, PARAM_ACCEPT));
|
||||
for (var idx = 0; idx < acceptedArr.length; ++idx) {
|
||||
expectedOutput += '<span class="accexp">\xA0\xA0\xA0<i>or</i></span><br><span class="accexp">';
|
||||
expectedOutput += testUsesHTML ? highlightSelectionMarkers(escapeOutput(acceptedArr[idx]))
|
||||
: formatValueOrString(acceptedArr[idx]);
|
||||
expectedOutput += '</span>';
|
||||
}
|
||||
// TODO(rolandsteiner): THIS IS UGLY, relying on 'div' container being index 2,
|
||||
// AND not allowing other containers to have 'outer' results - change!!!
|
||||
var outerOutput = '';
|
||||
expectedArr = getExpectationArray(getContainerParameter(suite, group, test, containers[2], PARAM_EXPECTED_OUTER));
|
||||
for (var idx = 0; idx < expectedArr.length; ++idx) {
|
||||
if (outerOutput) {
|
||||
outerOutput += '\xA0\xA0\xA0<i>or</i><br>';
|
||||
}
|
||||
outerOutput += testUsesHTML ? highlightSelectionMarkers(escapeOutput(expectedArr[idx]))
|
||||
: formatValueOrString(expectedArr[idx]);
|
||||
}
|
||||
acceptedArr = getExpectationArray(getContainerParameter(suite, group, test, containers[2], PARAM_ACCEPT_OUTER));
|
||||
for (var idx = 0; idx < acceptedArr.length; ++idx) {
|
||||
if (outerOutput) {
|
||||
outerOutput += '<span class="accexp">\xA0\xA0\xA0<i>or</i></span><br>';
|
||||
}
|
||||
outerOutput += '<span class="accexp">';
|
||||
outerOutput += testUsesHTML ? highlightSelectionMarkers(escapeOutput(acceptedArr[idx]))
|
||||
: formatValueOrString(acceptedArr[idx]);
|
||||
outerOutput += '</span>';
|
||||
}
|
||||
if (outerOutput) {
|
||||
expectedOutput += '<hr>' + outerOutput;
|
||||
}
|
||||
setTD(trID + IDOUT_EXPECTED, expectedOutput);
|
||||
|
||||
// Iterate over the individual container results
|
||||
for (var cntIdx = 0; cntIdx < containers.length; ++cntIdx) {
|
||||
var cntID = containers[cntIdx].id;
|
||||
var cntTD = document.getElementById(trID + IDOUT_CONTAINER + cntID);
|
||||
var cntResult = testResult[cntID];
|
||||
var cntValOut = VALOUTPUT[cntResult.valresult];
|
||||
var cntSelOut = SELOUTPUT[cntResult.selresult];
|
||||
var cssVal = cntValOut.css;
|
||||
var cssSel = (!suiteChecksSelOnly || cntResult.selresult != SELRESULT_NA) ? cntSelOut.css : cssVal;
|
||||
var cssCnt = cssVal;
|
||||
|
||||
// Fill in result status cell ("PASS", "ACC.", "FAIL", "EXC.", etc.)
|
||||
setTD(trID + IDOUT_STATUSVAL + cntID, cntValOut.output, cntValOut.title, cssVal);
|
||||
|
||||
// Fill in selection status cell ("PASS", "ACC.", "FAIL", "N/A")
|
||||
setTD(trID + IDOUT_STATUSSEL + cntID, cntSelOut.output, cntSelOut.title, cssSel);
|
||||
|
||||
// Fill in actual result
|
||||
switch (cntResult.valresult) {
|
||||
case VALRESULT_SETUP_EXCEPTION:
|
||||
setTD(trID + IDOUT_ACTUAL + cntID,
|
||||
SETUP_EXCEPTION + '(mouseover)',
|
||||
escapeOutput(cntResult.output),
|
||||
cssVal);
|
||||
break;
|
||||
|
||||
case VALRESULT_EXECUTION_EXCEPTION:
|
||||
setTD(trID + IDOUT_ACTUAL + cntID,
|
||||
EXECUTION_EXCEPTION + '(mouseover)',
|
||||
escapeOutput(cntResult.output.toString()),
|
||||
cssVal);
|
||||
break;
|
||||
|
||||
case VALRESULT_VERIFICATION_EXCEPTION:
|
||||
setTD(trID + IDOUT_ACTUAL + cntID,
|
||||
VERIFICATION_EXCEPTION + '(mouseover)',
|
||||
escapeOutput(cntResult.output.toString()),
|
||||
cssVal);
|
||||
break;
|
||||
|
||||
case VALRESULT_UNSUPPORTED:
|
||||
setTD(trID + IDOUT_ACTUAL + cntID,
|
||||
escapeOutput(cntResult.output),
|
||||
'',
|
||||
cssVal);
|
||||
break;
|
||||
|
||||
case VALRESULT_CANARY:
|
||||
setTD(trID + IDOUT_ACTUAL + cntID,
|
||||
highlightSelectionMarkersAndTextNodes(escapeOutput(cntResult.output)),
|
||||
'',
|
||||
cssVal);
|
||||
break;
|
||||
|
||||
case VALRESULT_DIFF:
|
||||
case VALRESULT_ACCEPT:
|
||||
case VALRESULT_EQUAL:
|
||||
if (!testUsesHTML) {
|
||||
setTD(trID + IDOUT_ACTUAL + cntID,
|
||||
formatValueOrString(cntResult.output),
|
||||
'',
|
||||
cssVal);
|
||||
} else if (cntResult.selresult == SELRESULT_CANARY) {
|
||||
cssCnt = suiteChecksSelOnly ? cssSel : cssVal;
|
||||
setTD(trID + IDOUT_ACTUAL + cntID,
|
||||
highlightSelectionMarkersAndTextNodes(escapeOutput(cntResult.output)),
|
||||
'',
|
||||
cssCnt);
|
||||
} else {
|
||||
cssCnt = suiteChecksSelOnly ? cssSel : cssVal;
|
||||
setTD(trID + IDOUT_ACTUAL + cntID,
|
||||
formatActualResult(suite, group, test, cntResult.output),
|
||||
'',
|
||||
cssCnt);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
cssCnt = 'exception';
|
||||
setTD(trID + IDOUT_ACTUAL + cntID,
|
||||
INTERNAL_ERR + 'UNKNOWN RESULT VALUE',
|
||||
'',
|
||||
cssCnt);
|
||||
}
|
||||
|
||||
if (cntTD) {
|
||||
cntTD.className = cssCnt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the results of a single test suite
|
||||
*
|
||||
* @param {Object} suite as object reference
|
||||
*/
|
||||
function outputTestSuiteResults(suite) {
|
||||
var suiteID = suite.id;
|
||||
var span;
|
||||
|
||||
span = document.getElementById(suiteID + '-score');
|
||||
if (span) {
|
||||
span.innerHTML = results[suiteID].valscore + '/' + results[suiteID].count;
|
||||
}
|
||||
span = document.getElementById(suiteID + '-selscore');
|
||||
if (span) {
|
||||
span.innerHTML = results[suiteID].selscore + '/' + results[suiteID].count;
|
||||
}
|
||||
span = document.getElementById(suiteID + '-time');
|
||||
if (span) {
|
||||
span.innerHTML = results[suiteID].time;
|
||||
}
|
||||
span = document.getElementById(suiteID + '-progress');
|
||||
if (span) {
|
||||
span.style.color = 'green';
|
||||
}
|
||||
|
||||
for (var clsIdx = 0; clsIdx < testClassCount; ++clsIdx) {
|
||||
var clsID = testClassIDs[clsIdx];
|
||||
var cls = suite[clsID];
|
||||
if (!cls)
|
||||
continue;
|
||||
|
||||
span = document.getElementById(suiteID + '-' + clsID + '-score');
|
||||
if (span) {
|
||||
span.innerHTML = results[suiteID][clsID].valscore + '/' + results[suiteID][clsID].count;
|
||||
}
|
||||
span = document.getElementById(suiteID + '-' + clsID + '-selscore');
|
||||
if (span) {
|
||||
span.innerHTML = results[suiteID][clsID].selscore + '/' + results[suiteID][clsID].count;
|
||||
}
|
||||
|
||||
var groupCount = cls.length;
|
||||
|
||||
for (var groupIdx = 0; groupIdx < groupCount; ++groupIdx) {
|
||||
var group = cls[groupIdx];
|
||||
var testCount = group.tests.length;
|
||||
|
||||
for (var testIdx = 0; testIdx < testCount; ++testIdx) {
|
||||
var test = group.tests[testIdx];
|
||||
|
||||
outputTestResults(suite, clsID, group, test);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,269 @@
|
||||
/**
|
||||
* @fileoverview
|
||||
* Functions used to handle test and expectation strings.
|
||||
*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License')
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* @version 0.1
|
||||
* @author rolandsteiner@google.com
|
||||
*/
|
||||
|
||||
/**
|
||||
* Normalize text selection indicators and convert inter-element selection
|
||||
* indicators to comments.
|
||||
*
|
||||
* Note that this function relies on the spaces of the input string already
|
||||
* having been normalized by canonicalizeSpaces!
|
||||
*
|
||||
* @param pad {String} HTML string that includes selection marker characters
|
||||
* @return {String} the HTML string with the selection markers converted
|
||||
*/
|
||||
function convertSelectionIndicators(pad) {
|
||||
// Sanity check: Markers { } | only directly before or after an element,
|
||||
// or just before a closing > (i.e., not within a text node).
|
||||
// Note that intra-tag selection markers have already been converted to the
|
||||
// special selection attribute(s) above.
|
||||
if (/[^>][{}\|][^<>]/.test(pad) ||
|
||||
/^[{}\|][^<]/.test(pad) ||
|
||||
/[^>][{}\|]$/.test(pad) ||
|
||||
/^[{}\|]*$/.test(pad)) {
|
||||
throw SETUP_BAD_SELECTION_SPEC;
|
||||
}
|
||||
|
||||
// Convert intra-tag selection markers to special attributes.
|
||||
pad = pad.replace(/\{\>/g, ATTRNAME_SEL_START + '="1">');
|
||||
pad = pad.replace(/\}\>/g, ATTRNAME_SEL_END + '="1">');
|
||||
pad = pad.replace(/\|\>/g, ATTRNAME_SEL_START + '="1" ' +
|
||||
ATTRNAME_SEL_END + '="1">');
|
||||
|
||||
// Convert remaining {, }, | to comments with '[' and ']' data.
|
||||
pad = pad.replace('{', '<!--[-->');
|
||||
pad = pad.replace('}', '<!--]-->');
|
||||
pad = pad.replace('|', '<!--[--><!--]-->');
|
||||
|
||||
// Convert caret indicator ^ to empty selection indicator []
|
||||
// (this simplifies further processing).
|
||||
pad = pad.replace(/\^/, '[]');
|
||||
|
||||
return pad;
|
||||
}
|
||||
|
||||
/**
|
||||
* Derives one point of the selection from the indicators with the HTML tree:
|
||||
* '[' or ']' within a text or comment node, or the special selection
|
||||
* attributes within an element node.
|
||||
*
|
||||
* @param root {DOMNode} root node of the recursive search
|
||||
* @param marker {String} which marker to look for: '[' or ']'
|
||||
* @return {Object} a pair object: {node: {DOMNode}/null, offset: {Integer}}
|
||||
*/
|
||||
function deriveSelectionPoint(root, marker) {
|
||||
switch (root.nodeType) {
|
||||
case DOM_NODE_TYPE_ELEMENT:
|
||||
if (root.attributes) {
|
||||
// Note: getAttribute() is necessary for this to work on all browsers!
|
||||
if (marker == '[' && root.getAttribute(ATTRNAME_SEL_START)) {
|
||||
root.removeAttribute(ATTRNAME_SEL_START);
|
||||
return {node: root, offs: 0};
|
||||
}
|
||||
if (marker == ']' && root.getAttribute(ATTRNAME_SEL_END)) {
|
||||
root.removeAttribute(ATTRNAME_SEL_END);
|
||||
return {node: root, offs: 0};
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < root.childNodes.length; ++i) {
|
||||
var pair = deriveSelectionPoint(root.childNodes[i], marker);
|
||||
if (pair.node) {
|
||||
return pair;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case DOM_NODE_TYPE_TEXT:
|
||||
var pos = root.data.indexOf(marker);
|
||||
if (pos != -1) {
|
||||
// Remove selection marker from text.
|
||||
var nodeText = root.data;
|
||||
root.data = nodeText.substr(0, pos) + nodeText.substr(pos + 1);
|
||||
return {node: root, offs: pos };
|
||||
}
|
||||
break;
|
||||
|
||||
case DOM_NODE_TYPE_COMMENT:
|
||||
var pos = root.data.indexOf(marker);
|
||||
if (pos != -1) {
|
||||
// Remove comment node from parent.
|
||||
var helper = root.previousSibling;
|
||||
|
||||
for (pos = 0; helper; ++pos ) {
|
||||
helper = helper.previousSibling;
|
||||
}
|
||||
helper = root;
|
||||
root = root.parentNode;
|
||||
root.removeChild(helper);
|
||||
return {node: root, offs: pos };
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return {node: null, offs: 0 };
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the test HTML with the starting state specified in the test.
|
||||
*
|
||||
* The selection is specified "inline", using special characters:
|
||||
* ^ a collapsed text caret selection (same as [])
|
||||
* [ the selection start within a text node
|
||||
* ] the selection end within a text node
|
||||
* | collapsed selection between elements (same as {})
|
||||
* { selection starting with the following element
|
||||
* } selection ending with the preceding element
|
||||
* {, } and | can also be used within an element tag, just before the closing
|
||||
* angle bracket > to specify a selection [element, 0] where the element
|
||||
* doesn't otherwise have any children. Ex.: <hr {>foobarbaz<hr }>
|
||||
*
|
||||
* Explicit and implicit specification can also be mixed between the 2 points.
|
||||
*
|
||||
* A pad string must only contain at most ONE of the above that is suitable for
|
||||
* that start or end point, respectively, and must contain either both or none.
|
||||
*
|
||||
* @param suite {Object} suite that test originates in as object reference
|
||||
* @param group {Object} group of tests within the suite the test belongs to
|
||||
* @param test {Object} test to be run as object reference
|
||||
* @param container {Object} container descriptor as object reference
|
||||
*/
|
||||
function initContainer(suite, group, test, container) {
|
||||
var pad = getTestParameter(suite, group, test, PARAM_PAD);
|
||||
pad = canonicalizeSpaces(pad);
|
||||
pad = convertSelectionIndicators(pad);
|
||||
|
||||
if (container.editorID) {
|
||||
container.body.innerHTML = container.canary + container.tagOpen + pad + container.tagClose + container.canary;
|
||||
container.editor = container.doc.getElementById(container.editorID);
|
||||
} else {
|
||||
container.body.innerHTML = pad;
|
||||
container.editor = container.body;
|
||||
}
|
||||
|
||||
win = container.win;
|
||||
doc = container.doc;
|
||||
body = container.body;
|
||||
editor = container.editor;
|
||||
sel = null;
|
||||
|
||||
if (!editor) {
|
||||
throw SETUP_CONTAINER;
|
||||
}
|
||||
|
||||
if (getTestParameter(suite, group, test, PARAM_STYLE_WITH_CSS)) {
|
||||
try {
|
||||
container.doc.execCommand('styleWithCSS', false, true);
|
||||
} catch (ex) {
|
||||
// ignore exception if unsupported
|
||||
}
|
||||
}
|
||||
|
||||
var selAnchor = deriveSelectionPoint(editor, '[');
|
||||
var selFocus = deriveSelectionPoint(editor, ']');
|
||||
|
||||
// sanity check
|
||||
if (!selAnchor || !selFocus) {
|
||||
throw SETUP_SELECTION;
|
||||
}
|
||||
|
||||
if (!selAnchor.node || !selFocus.node) {
|
||||
if (selAnchor.node || selFocus.node) {
|
||||
// Broken test: only one selection point was specified
|
||||
throw SETUP_BAD_SELECTION_SPEC;
|
||||
}
|
||||
sel = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (selAnchor.node === selFocus.node) {
|
||||
if (selAnchor.offs > selFocus.offs) {
|
||||
// Both selection points are within the same node, the selection was
|
||||
// specified inline (thus the end indicator element or character was
|
||||
// removed), and the end point is before the start (reversed selection).
|
||||
// Start offset that was derived is now off by 1 and needs adjustment.
|
||||
--selAnchor.offs;
|
||||
}
|
||||
|
||||
if (selAnchor.offs === selFocus.offs) {
|
||||
createCaret(selAnchor.node, selAnchor.offs).select();
|
||||
try {
|
||||
sel = win.getSelection();
|
||||
} catch (ex) {
|
||||
sel = undefined;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
createFromNodes(selAnchor.node, selAnchor.offs, selFocus.node, selFocus.offs).select();
|
||||
|
||||
try {
|
||||
sel = win.getSelection();
|
||||
} catch (ex) {
|
||||
sel = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the editor element after a test is run.
|
||||
*
|
||||
* @param container {Object} container descriptor as object reference
|
||||
*/
|
||||
function resetContainer(container) {
|
||||
// Remove errant styles and attributes that may have been set on the <body>.
|
||||
container.body.removeAttribute('style');
|
||||
container.body.removeAttribute('color');
|
||||
container.body.removeAttribute('bgcolor');
|
||||
|
||||
try {
|
||||
container.doc.execCommand('styleWithCSS', false, false);
|
||||
} catch (ex) {
|
||||
// Ignore exception if unsupported.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the editor document.
|
||||
*/
|
||||
function initEditorDocs() {
|
||||
for (var c = 0; c < containers.length; ++c) {
|
||||
var container = containers[c];
|
||||
|
||||
container.iframe = document.getElementById('iframe-' + container.id);
|
||||
container.win = container.iframe.contentWindow;
|
||||
container.doc = container.win.document;
|
||||
container.body = container.doc.body;
|
||||
// container.editor is set per test (changes on embedded editor elements).
|
||||
|
||||
// Some browsers require a selection to go with their 'styleWithCSS'.
|
||||
try {
|
||||
container.win.getSelection().selectAllChildren(editor);
|
||||
} catch (ex) {
|
||||
// ignore exception if unsupported
|
||||
}
|
||||
// Default styleWithCSS to false.
|
||||
try {
|
||||
container.doc.execCommand('styleWithCSS', false, false);
|
||||
} catch (ex) {
|
||||
// ignore exception if unsupported
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
goog.require('goog.dom.Range');
|
||||
|
||||
window.createFromWindow = goog.dom.Range.createFromWindow;
|
||||
window.createFromNodes = goog.dom.Range.createFromNodes;
|
||||
window.createCaret = goog.dom.Range.createCaret;
|
6184
editor/libeditor/html/tests/browserscope/lib/richtext2/richtext2/static/js/range.js
Executable file
6184
editor/libeditor/html/tests/browserscope/lib/richtext2/richtext2/static/js/range.js
Executable file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,383 @@
|
||||
/**
|
||||
* @fileoverview
|
||||
* Main functions used in running the RTE test suite.
|
||||
*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License')
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* @version 0.1
|
||||
* @author rolandsteiner@google.com
|
||||
*/
|
||||
|
||||
/**
|
||||
* Info function: returns true if the suite (mainly) tests the result HTML/Text.
|
||||
*
|
||||
* @param suite {String} the test suite
|
||||
* @return {boolean} Whether the suite main focus is the output HTML/Text
|
||||
*/
|
||||
function suiteChecksHTMLOrText(suite) {
|
||||
return suite.id[0] != 'S';
|
||||
}
|
||||
|
||||
/**
|
||||
* Info function: returns true if the suite checks the result selection.
|
||||
*
|
||||
* @param suite {String} the test suite
|
||||
* @return {boolean} Whether the suite checks the selection
|
||||
*/
|
||||
function suiteChecksSelection(suite) {
|
||||
return suite.id[0] != 'Q';
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function returning the effective value of a test parameter.
|
||||
*
|
||||
* @param suite {Object} the test suite
|
||||
* @param group {Object} group of tests within the suite the test belongs to
|
||||
* @param test {Object} the test
|
||||
* @param param {String} the test parameter to be checked
|
||||
* @return {Any} the effective value of the parameter (can be undefined)
|
||||
*/
|
||||
function getTestParameter(suite, group, test, param) {
|
||||
var val = test[param];
|
||||
if (val === undefined) {
|
||||
val = group[param];
|
||||
}
|
||||
if (val === undefined) {
|
||||
val = suite[param];
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function returning the effective value of a container/test parameter.
|
||||
*
|
||||
* @param suite {Object} the test suite
|
||||
* @param group {Object} group of tests within the suite the test belongs to
|
||||
* @param test {Object} the test
|
||||
* @param container {Object} the container descriptor object
|
||||
* @param param {String} the test parameter to be checked
|
||||
* @return {Any} the effective value of the parameter (can be undefined)
|
||||
*/
|
||||
function getContainerParameter(suite, group, test, container, param) {
|
||||
var val = undefined;
|
||||
if (test[container.id]) {
|
||||
val = test[container.id][param];
|
||||
}
|
||||
if (val === undefined) {
|
||||
val = test[param];
|
||||
}
|
||||
if (val === undefined) {
|
||||
val = group[param];
|
||||
}
|
||||
if (val === undefined) {
|
||||
val = suite[param];
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the global variables before any tests are run.
|
||||
*/
|
||||
function initVariables() {
|
||||
results = {
|
||||
count: 0,
|
||||
valscore: 0,
|
||||
selscore: 0
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a single test - outputs and sets the result variables.
|
||||
*
|
||||
* @param suite {Object} suite that test originates in as object reference
|
||||
* @param group {Object} group of tests within the suite the test belongs to
|
||||
* @param test {Object} test to be run as object reference
|
||||
* @param container {Object} container descriptor as object reference
|
||||
* @see variables.js for RESULT... values
|
||||
*/
|
||||
function runSingleTest(suite, group, test, container) {
|
||||
var result = {
|
||||
valscore: 0,
|
||||
selscore: 0,
|
||||
valresult: VALRESULT_NOT_RUN,
|
||||
selresult: SELRESULT_NOT_RUN,
|
||||
output: ''
|
||||
};
|
||||
|
||||
// 1.) Populate the editor element with the initial test setup HTML.
|
||||
try {
|
||||
initContainer(suite, group, test, container);
|
||||
} catch(ex) {
|
||||
result.valresult = VALRESULT_SETUP_EXCEPTION;
|
||||
result.selresult = SELRESULT_NA;
|
||||
result.output = SETUP_EXCEPTION + ex.toString();
|
||||
return result;
|
||||
}
|
||||
|
||||
// 2.) Run the test command, general function or query function.
|
||||
var isHTMLTest = false;
|
||||
|
||||
try {
|
||||
var cmd = undefined;
|
||||
|
||||
if (cmd = getTestParameter(suite, group, test, PARAM_EXECCOMMAND)) {
|
||||
isHTMLTest = true;
|
||||
// Note: "getTestParameter(suite, group, test, PARAM_VALUE) || null"
|
||||
// doesn't work, since value might be the empty string, e.g., for 'insertText'!
|
||||
var value = getTestParameter(suite, group, test, PARAM_VALUE);
|
||||
if (value === undefined) {
|
||||
value = null;
|
||||
}
|
||||
container.doc.execCommand(cmd, false, value);
|
||||
} else if (cmd = getTestParameter(suite, group, test, PARAM_FUNCTION)) {
|
||||
isHTMLTest = true;
|
||||
eval(cmd);
|
||||
} else if (cmd = getTestParameter(suite, group, test, PARAM_QUERYCOMMANDSUPPORTED)) {
|
||||
result.output = container.doc.queryCommandSupported(cmd);
|
||||
} else if (cmd = getTestParameter(suite, group, test, PARAM_QUERYCOMMANDENABLED)) {
|
||||
result.output = container.doc.queryCommandEnabled(cmd);
|
||||
} else if (cmd = getTestParameter(suite, group, test, PARAM_QUERYCOMMANDINDETERM)) {
|
||||
result.output = container.doc.queryCommandIndeterm(cmd);
|
||||
} else if (cmd = getTestParameter(suite, group, test, PARAM_QUERYCOMMANDSTATE)) {
|
||||
result.output = container.doc.queryCommandState(cmd);
|
||||
} else if (cmd = getTestParameter(suite, group, test, PARAM_QUERYCOMMANDVALUE)) {
|
||||
result.output = container.doc.queryCommandValue(cmd);
|
||||
if (result.output === false) {
|
||||
// A return value of boolean 'false' for queryCommandValue means 'not supported'.
|
||||
result.valresult = VALRESULT_UNSUPPORTED;
|
||||
result.selresult = SELRESULT_NA;
|
||||
result.output = UNSUPPORTED;
|
||||
return result;
|
||||
}
|
||||
} else {
|
||||
result.valresult = VALRESULT_SETUP_EXCEPTION;
|
||||
result.selresult = SELRESULT_NA;
|
||||
result.output = SETUP_EXCEPTION + SETUP_NOCOMMAND;
|
||||
return result;
|
||||
}
|
||||
} catch (ex) {
|
||||
result.valresult = VALRESULT_EXECUTION_EXCEPTION;
|
||||
result.selresult = SELRESULT_NA;
|
||||
result.output = EXECUTION_EXCEPTION + ex.toString();
|
||||
return result;
|
||||
}
|
||||
|
||||
// 4.) Verify test result
|
||||
try {
|
||||
if (isHTMLTest) {
|
||||
// First, retrieve HTML from container
|
||||
prepareHTMLTestResult(container, result);
|
||||
|
||||
// Compare result to expectations
|
||||
compareHTMLTestResult(suite, group, test, container, result);
|
||||
|
||||
result.valscore = (result.valresult === VALRESULT_EQUAL) ? 1 : 0;
|
||||
result.selscore = (result.selresult === SELRESULT_EQUAL) ? 1 : 0;
|
||||
} else {
|
||||
compareTextTestResult(suite, group, test, result);
|
||||
|
||||
result.selresult = SELRESULT_NA;
|
||||
result.valscore = (result.valresult === VALRESULT_EQUAL) ? 1 : 0;
|
||||
}
|
||||
} catch (ex) {
|
||||
result.valresult = VALRESULT_VERIFICATION_EXCEPTION;
|
||||
result.selresult = SELRESULT_NA;
|
||||
result.output = VERIFICATION_EXCEPTION + ex.toString();
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the results dictionary for a given test suite.
|
||||
* (for all classes -> tests -> containers)
|
||||
*
|
||||
* @param {Object} suite as object reference
|
||||
*/
|
||||
function initTestSuiteResults(suite) {
|
||||
var suiteID = suite.id;
|
||||
|
||||
// Initialize results entries for this suite
|
||||
results[suiteID] = {
|
||||
count: 0,
|
||||
valscore: 0,
|
||||
selscore: 0,
|
||||
time: 0
|
||||
};
|
||||
var totalTestCount = 0;
|
||||
|
||||
for (var clsIdx = 0; clsIdx < testClassCount; ++clsIdx) {
|
||||
var clsID = testClassIDs[clsIdx];
|
||||
var cls = suite[clsID];
|
||||
if (!cls)
|
||||
continue;
|
||||
|
||||
results[suiteID][clsID] = {
|
||||
count: 0,
|
||||
valscore: 0,
|
||||
selscore: 0
|
||||
};
|
||||
var clsTestCount = 0;
|
||||
|
||||
var groupCount = cls.length;
|
||||
for (var groupIdx = 0; groupIdx < groupCount; ++groupIdx) {
|
||||
var group = cls[groupIdx];
|
||||
var testCount = group.tests.length;
|
||||
|
||||
clsTestCount += testCount;
|
||||
totalTestCount += testCount;
|
||||
|
||||
for (var testIdx = 0; testIdx < testCount; ++testIdx) {
|
||||
var test = group.tests[testIdx];
|
||||
|
||||
results[suiteID][clsID ][test.id] = {
|
||||
valscore: 0,
|
||||
selscore: 0,
|
||||
valresult: VALRESULT_NOT_RUN,
|
||||
selresult: SELRESULT_NOT_RUN
|
||||
};
|
||||
for (var cntIdx = 0; cntIdx < containers.length; ++cntIdx) {
|
||||
var cntID = containers[cntIdx].id;
|
||||
|
||||
results[suiteID][clsID][test.id][cntID] = {
|
||||
valscore: 0,
|
||||
selscore: 0,
|
||||
valresult: VALRESULT_NOT_RUN,
|
||||
selresult: SELRESULT_NOT_RUN,
|
||||
output: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
results[suiteID][clsID].count = clsTestCount;
|
||||
}
|
||||
results[suiteID].count = totalTestCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a single test suite (such as DELETE tests or INSERT tests).
|
||||
*
|
||||
* @param suite {Object} suite as object reference
|
||||
*/
|
||||
function runTestSuite(suite) {
|
||||
var suiteID = suite.id;
|
||||
var suiteStartTime = new Date().getTime();
|
||||
|
||||
initTestSuiteResults(suite);
|
||||
|
||||
for (var clsIdx = 0; clsIdx < testClassCount; ++clsIdx) {
|
||||
var clsID = testClassIDs[clsIdx];
|
||||
var cls = suite[clsID];
|
||||
if (!cls)
|
||||
continue;
|
||||
|
||||
var groupCount = cls.length;
|
||||
|
||||
for (var groupIdx = 0; groupIdx < groupCount; ++groupIdx) {
|
||||
var group = cls[groupIdx];
|
||||
var testCount = group.tests.length;
|
||||
|
||||
for (var testIdx = 0; testIdx < testCount; ++testIdx) {
|
||||
var test = group.tests[testIdx];
|
||||
|
||||
var valscore = 1;
|
||||
var selscore = 1;
|
||||
var valresult = VALRESULT_EQUAL;
|
||||
var selresult = SELRESULT_EQUAL;
|
||||
|
||||
for (var cntIdx = 0; cntIdx < containers.length; ++cntIdx) {
|
||||
var container = containers[cntIdx];
|
||||
var cntID = container.id;
|
||||
|
||||
var result = runSingleTest(suite, group, test, container);
|
||||
|
||||
results[suiteID][clsID][test.id][cntID] = result;
|
||||
|
||||
valscore = Math.min(valscore, result.valscore);
|
||||
selscore = Math.min(selscore, result.selscore);
|
||||
valresult = Math.min(valresult, result.valresult);
|
||||
selresult = Math.min(selresult, result.selresult);
|
||||
|
||||
resetContainer(container);
|
||||
}
|
||||
|
||||
results[suiteID][clsID][test.id].valscore = valscore;
|
||||
results[suiteID][clsID][test.id].selscore = selscore;
|
||||
results[suiteID][clsID][test.id].valresult = valresult;
|
||||
results[suiteID][clsID][test.id].selresult = selresult;
|
||||
|
||||
results[suiteID][clsID].valscore += valscore;
|
||||
results[suiteID][clsID].selscore += selscore;
|
||||
results[suiteID].valscore += valscore;
|
||||
results[suiteID].selscore += selscore;
|
||||
results.valscore += valscore;
|
||||
results.selscore += selscore;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
results[suiteID].time = new Date().getTime() - suiteStartTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a single test suite (such as DELETE tests or INSERT tests)
|
||||
* and updates the output HTML.
|
||||
*
|
||||
* @param {Object} suite as object reference
|
||||
*/
|
||||
function runAndOutputTestSuite(suite) {
|
||||
runTestSuite(suite);
|
||||
outputTestSuiteResults(suite);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the beacon with the test results.
|
||||
*/
|
||||
function fillResults() {
|
||||
// Result totals of the individual categories
|
||||
categoryTotals = [
|
||||
'selection=' + results['S'].selscore,
|
||||
'apply=' + results['A'].valscore,
|
||||
'applyCSS=' + results['AC'].valscore,
|
||||
'change=' + results['C'].valscore,
|
||||
'changeCSS=' + results['CC'].valscore,
|
||||
'unapply=' + results['U'].valscore,
|
||||
'unapplyCSS=' + results['UC'].valscore,
|
||||
'delete=' + results['D'].valscore,
|
||||
'forwarddelete=' + results['FD'].valscore,
|
||||
'insert=' + results['I'].valscore,
|
||||
'selectionResult=' + (results['A'].selscore +
|
||||
results['AC'].selscore +
|
||||
results['C'].selscore +
|
||||
results['CC'].selscore +
|
||||
results['U'].selscore +
|
||||
results['UC'].selscore +
|
||||
results['D'].selscore +
|
||||
results['FD'].selscore +
|
||||
results['I'].selscore),
|
||||
'querySupported=' + results['Q'].valscore,
|
||||
'queryEnabled=' + results['QE'].valscore,
|
||||
'queryIndeterm=' + results['QI'].valscore,
|
||||
'queryState=' + results['QS'].valscore,
|
||||
'queryStateCSS=' + results['QSC'].valscore,
|
||||
'queryValue=' + results['QV'].valscore,
|
||||
'queryValueCSS=' + results['QVC'].valscore
|
||||
];
|
||||
|
||||
// Beacon copies category results
|
||||
beacon = categoryTotals.slice(0);
|
||||
}
|
||||
|
@ -0,0 +1,416 @@
|
||||
/**
|
||||
* @fileoverview
|
||||
* Common constants and variables used in the RTE test suite.
|
||||
*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License')
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* @version 0.1
|
||||
* @author rolandsteiner@google.com
|
||||
*/
|
||||
|
||||
// All colors defined in CSS3.
|
||||
var colorChart = {
|
||||
'aliceblue': {red: 0xF0, green: 0xF8, blue: 0xFF},
|
||||
'antiquewhite': {red: 0xFA, green: 0xEB, blue: 0xD7},
|
||||
'aqua': {red: 0x00, green: 0xFF, blue: 0xFF},
|
||||
'aquamarine': {red: 0x7F, green: 0xFF, blue: 0xD4},
|
||||
'azure': {red: 0xF0, green: 0xFF, blue: 0xFF},
|
||||
'beige': {red: 0xF5, green: 0xF5, blue: 0xDC},
|
||||
'bisque': {red: 0xFF, green: 0xE4, blue: 0xC4},
|
||||
'black': {red: 0x00, green: 0x00, blue: 0x00},
|
||||
'blanchedalmond': {red: 0xFF, green: 0xEB, blue: 0xCD},
|
||||
'blue': {red: 0x00, green: 0x00, blue: 0xFF},
|
||||
'blueviolet': {red: 0x8A, green: 0x2B, blue: 0xE2},
|
||||
'brown': {red: 0xA5, green: 0x2A, blue: 0x2A},
|
||||
'burlywood': {red: 0xDE, green: 0xB8, blue: 0x87},
|
||||
'cadetblue': {red: 0x5F, green: 0x9E, blue: 0xA0},
|
||||
'chartreuse': {red: 0x7F, green: 0xFF, blue: 0x00},
|
||||
'chocolate': {red: 0xD2, green: 0x69, blue: 0x1E},
|
||||
'coral': {red: 0xFF, green: 0x7F, blue: 0x50},
|
||||
'cornflowerblue': {red: 0x64, green: 0x95, blue: 0xED},
|
||||
'cornsilk': {red: 0xFF, green: 0xF8, blue: 0xDC},
|
||||
'crimson': {red: 0xDC, green: 0x14, blue: 0x3C},
|
||||
'cyan': {red: 0x00, green: 0xFF, blue: 0xFF},
|
||||
'darkblue': {red: 0x00, green: 0x00, blue: 0x8B},
|
||||
'darkcyan': {red: 0x00, green: 0x8B, blue: 0x8B},
|
||||
'darkgoldenrod': {red: 0xB8, green: 0x86, blue: 0x0B},
|
||||
'darkgray': {red: 0xA9, green: 0xA9, blue: 0xA9},
|
||||
'darkgreen': {red: 0x00, green: 0x64, blue: 0x00},
|
||||
'darkgrey': {red: 0xA9, green: 0xA9, blue: 0xA9},
|
||||
'darkkhaki': {red: 0xBD, green: 0xB7, blue: 0x6B},
|
||||
'darkmagenta': {red: 0x8B, green: 0x00, blue: 0x8B},
|
||||
'darkolivegreen': {red: 0x55, green: 0x6B, blue: 0x2F},
|
||||
'darkorange': {red: 0xFF, green: 0x8C, blue: 0x00},
|
||||
'darkorchid': {red: 0x99, green: 0x32, blue: 0xCC},
|
||||
'darkred': {red: 0x8B, green: 0x00, blue: 0x00},
|
||||
'darksalmon': {red: 0xE9, green: 0x96, blue: 0x7A},
|
||||
'darkseagreen': {red: 0x8F, green: 0xBC, blue: 0x8F},
|
||||
'darkslateblue': {red: 0x48, green: 0x3D, blue: 0x8B},
|
||||
'darkslategray': {red: 0x2F, green: 0x4F, blue: 0x4F},
|
||||
'darkslategrey': {red: 0x2F, green: 0x4F, blue: 0x4F},
|
||||
'darkturquoise': {red: 0x00, green: 0xCE, blue: 0xD1},
|
||||
'darkviolet': {red: 0x94, green: 0x00, blue: 0xD3},
|
||||
'deeppink': {red: 0xFF, green: 0x14, blue: 0x93},
|
||||
'deepskyblue': {red: 0x00, green: 0xBF, blue: 0xFF},
|
||||
'dimgray': {red: 0x69, green: 0x69, blue: 0x69},
|
||||
'dimgrey': {red: 0x69, green: 0x69, blue: 0x69},
|
||||
'dodgerblue': {red: 0x1E, green: 0x90, blue: 0xFF},
|
||||
'firebrick': {red: 0xB2, green: 0x22, blue: 0x22},
|
||||
'floralwhite': {red: 0xFF, green: 0xFA, blue: 0xF0},
|
||||
'forestgreen': {red: 0x22, green: 0x8B, blue: 0x22},
|
||||
'fuchsia': {red: 0xFF, green: 0x00, blue: 0xFF},
|
||||
'gainsboro': {red: 0xDC, green: 0xDC, blue: 0xDC},
|
||||
'ghostwhite': {red: 0xF8, green: 0xF8, blue: 0xFF},
|
||||
'gold': {red: 0xFF, green: 0xD7, blue: 0x00},
|
||||
'goldenrod': {red: 0xDA, green: 0xA5, blue: 0x20},
|
||||
'gray': {red: 0x80, green: 0x80, blue: 0x80},
|
||||
'green': {red: 0x00, green: 0x80, blue: 0x00},
|
||||
'greenyellow': {red: 0xAD, green: 0xFF, blue: 0x2F},
|
||||
'grey': {red: 0x80, green: 0x80, blue: 0x80},
|
||||
'honeydew': {red: 0xF0, green: 0xFF, blue: 0xF0},
|
||||
'hotpink': {red: 0xFF, green: 0x69, blue: 0xB4},
|
||||
'indianred': {red: 0xCD, green: 0x5C, blue: 0x5C},
|
||||
'indigo': {red: 0x4B, green: 0x00, blue: 0x82},
|
||||
'ivory': {red: 0xFF, green: 0xFF, blue: 0xF0},
|
||||
'khaki': {red: 0xF0, green: 0xE6, blue: 0x8C},
|
||||
'lavender': {red: 0xE6, green: 0xE6, blue: 0xFA},
|
||||
'lavenderblush': {red: 0xFF, green: 0xF0, blue: 0xF5},
|
||||
'lawngreen': {red: 0x7C, green: 0xFC, blue: 0x00},
|
||||
'lemonchiffon': {red: 0xFF, green: 0xFA, blue: 0xCD},
|
||||
'lightblue': {red: 0xAD, green: 0xD8, blue: 0xE6},
|
||||
'lightcoral': {red: 0xF0, green: 0x80, blue: 0x80},
|
||||
'lightcyan': {red: 0xE0, green: 0xFF, blue: 0xFF},
|
||||
'lightgoldenrodyellow': {red: 0xFA, green: 0xFA, blue: 0xD2},
|
||||
'lightgray': {red: 0xD3, green: 0xD3, blue: 0xD3},
|
||||
'lightgreen': {red: 0x90, green: 0xEE, blue: 0x90},
|
||||
'lightgrey': {red: 0xD3, green: 0xD3, blue: 0xD3},
|
||||
'lightpink': {red: 0xFF, green: 0xB6, blue: 0xC1},
|
||||
'lightsalmon': {red: 0xFF, green: 0xA0, blue: 0x7A},
|
||||
'lightseagreen': {red: 0x20, green: 0xB2, blue: 0xAA},
|
||||
'lightskyblue': {red: 0x87, green: 0xCE, blue: 0xFA},
|
||||
'lightslategray': {red: 0x77, green: 0x88, blue: 0x99},
|
||||
'lightslategrey': {red: 0x77, green: 0x88, blue: 0x99},
|
||||
'lightsteelblue': {red: 0xB0, green: 0xC4, blue: 0xDE},
|
||||
'lightyellow': {red: 0xFF, green: 0xFF, blue: 0xE0},
|
||||
'lime': {red: 0x00, green: 0xFF, blue: 0x00},
|
||||
'limegreen': {red: 0x32, green: 0xCD, blue: 0x32},
|
||||
'linen': {red: 0xFA, green: 0xF0, blue: 0xE6},
|
||||
'magenta': {red: 0xFF, green: 0x00, blue: 0xFF},
|
||||
'maroon': {red: 0x80, green: 0x00, blue: 0x00},
|
||||
'mediumaquamarine': {red: 0x66, green: 0xCD, blue: 0xAA},
|
||||
'mediumblue': {red: 0x00, green: 0x00, blue: 0xCD},
|
||||
'mediumorchid': {red: 0xBA, green: 0x55, blue: 0xD3},
|
||||
'mediumpurple': {red: 0x93, green: 0x70, blue: 0xDB},
|
||||
'mediumseagreen': {red: 0x3C, green: 0xB3, blue: 0x71},
|
||||
'mediumslateblue': {red: 0x7B, green: 0x68, blue: 0xEE},
|
||||
'mediumspringgreen': {red: 0x00, green: 0xFA, blue: 0x9A},
|
||||
'mediumturquoise': {red: 0x48, green: 0xD1, blue: 0xCC},
|
||||
'mediumvioletred': {red: 0xC7, green: 0x15, blue: 0x85},
|
||||
'midnightblue': {red: 0x19, green: 0x19, blue: 0x70},
|
||||
'mintcream': {red: 0xF5, green: 0xFF, blue: 0xFA},
|
||||
'mistyrose': {red: 0xFF, green: 0xE4, blue: 0xE1},
|
||||
'moccasin': {red: 0xFF, green: 0xE4, blue: 0xB5},
|
||||
'navajowhite': {red: 0xFF, green: 0xDE, blue: 0xAD},
|
||||
'navy': {red: 0x00, green: 0x00, blue: 0x80},
|
||||
'oldlace': {red: 0xFD, green: 0xF5, blue: 0xE6},
|
||||
'olive': {red: 0x80, green: 0x80, blue: 0x00},
|
||||
'olivedrab': {red: 0x6B, green: 0x8E, blue: 0x23},
|
||||
'orange': {red: 0xFF, green: 0xA5, blue: 0x00},
|
||||
'orangered': {red: 0xFF, green: 0x45, blue: 0x00},
|
||||
'orchid': {red: 0xDA, green: 0x70, blue: 0xD6},
|
||||
'palegoldenrod': {red: 0xEE, green: 0xE8, blue: 0xAA},
|
||||
'palegreen': {red: 0x98, green: 0xFB, blue: 0x98},
|
||||
'paleturquoise': {red: 0xAF, green: 0xEE, blue: 0xEE},
|
||||
'palevioletred': {red: 0xDB, green: 0x70, blue: 0x93},
|
||||
'papayawhip': {red: 0xFF, green: 0xEF, blue: 0xD5},
|
||||
'peachpuff': {red: 0xFF, green: 0xDA, blue: 0xB9},
|
||||
'peru': {red: 0xCD, green: 0x85, blue: 0x3F},
|
||||
'pink': {red: 0xFF, green: 0xC0, blue: 0xCB},
|
||||
'plum': {red: 0xDD, green: 0xA0, blue: 0xDD},
|
||||
'powderblue': {red: 0xB0, green: 0xE0, blue: 0xE6},
|
||||
'purple': {red: 0x80, green: 0x00, blue: 0x80},
|
||||
'red': {red: 0xFF, green: 0x00, blue: 0x00},
|
||||
'rosybrown': {red: 0xBC, green: 0x8F, blue: 0x8F},
|
||||
'royalblue': {red: 0x41, green: 0x69, blue: 0xE1},
|
||||
'saddlebrown': {red: 0x8B, green: 0x45, blue: 0x13},
|
||||
'salmon': {red: 0xFA, green: 0x80, blue: 0x72},
|
||||
'sandybrown': {red: 0xF4, green: 0xA4, blue: 0x60},
|
||||
'seagreen': {red: 0x2E, green: 0x8B, blue: 0x57},
|
||||
'seashell': {red: 0xFF, green: 0xF5, blue: 0xEE},
|
||||
'sienna': {red: 0xA0, green: 0x52, blue: 0x2D},
|
||||
'silver': {red: 0xC0, green: 0xC0, blue: 0xC0},
|
||||
'skyblue': {red: 0x87, green: 0xCE, blue: 0xEB},
|
||||
'slateblue': {red: 0x6A, green: 0x5A, blue: 0xCD},
|
||||
'slategray': {red: 0x70, green: 0x80, blue: 0x90},
|
||||
'slategrey': {red: 0x70, green: 0x80, blue: 0x90},
|
||||
'snow': {red: 0xFF, green: 0xFA, blue: 0xFA},
|
||||
'springgreen': {red: 0x00, green: 0xFF, blue: 0x7F},
|
||||
'steelblue': {red: 0x46, green: 0x82, blue: 0xB4},
|
||||
'tan': {red: 0xD2, green: 0xB4, blue: 0x8C},
|
||||
'teal': {red: 0x00, green: 0x80, blue: 0x80},
|
||||
'thistle': {red: 0xD8, green: 0xBF, blue: 0xD8},
|
||||
'tomato': {red: 0xFF, green: 0x63, blue: 0x47},
|
||||
'turquoise': {red: 0x40, green: 0xE0, blue: 0xD0},
|
||||
'violet': {red: 0xEE, green: 0x82, blue: 0xEE},
|
||||
'wheat': {red: 0xF5, green: 0xDE, blue: 0xB3},
|
||||
'white': {red: 0xFF, green: 0xFF, blue: 0xFF},
|
||||
'whitesmoke': {red: 0xF5, green: 0xF5, blue: 0xF5},
|
||||
'yellow': {red: 0xFF, green: 0xFF, blue: 0x00},
|
||||
'yellowgreen': {red: 0x9A, green: 0xCD, blue: 0x32},
|
||||
|
||||
'transparent': {red: 0x00, green: 0x00, blue: 0x00, alpha: 0.0}
|
||||
};
|
||||
|
||||
/**
|
||||
* Color class allows cross-browser comparison of values, which can
|
||||
* be returned from queryCommandValue in several formats:
|
||||
* #ff00ff
|
||||
* #f0f
|
||||
* rgb(255, 0, 0)
|
||||
* rgb(100%, 0%, 28%) // disabled for the time being (see below)
|
||||
* rgba(127, 0, 64, 0.25)
|
||||
* rgba(50%, 0%, 10%, 0.65) // disabled for the time being (see below)
|
||||
* palegoldenrod
|
||||
* transparent
|
||||
*
|
||||
* @constructor
|
||||
* @param value {String} original value
|
||||
*/
|
||||
function Color(value) {
|
||||
this.compare = function(other) {
|
||||
if (!this.valid || !other.valid) {
|
||||
return false;
|
||||
}
|
||||
if (this.alpha != other.alpha) {
|
||||
return false;
|
||||
}
|
||||
if (this.alpha == 0.0) {
|
||||
// both are fully transparent -> ignore the specific color information
|
||||
return true;
|
||||
}
|
||||
// TODO(rolandsteiner): handle hsl/hsla values
|
||||
return this.red == other.red && this.green == other.green && this.blue == other.blue;
|
||||
}
|
||||
this.parse = function(value) {
|
||||
if (!value)
|
||||
return false;
|
||||
value = String(value).toLowerCase();
|
||||
var match;
|
||||
// '#' + 6 hex digits, e.g., #ff3300
|
||||
match = value.match(/#([0-9a-f]{6})/i);
|
||||
if (match) {
|
||||
this.red = parseInt(match[1].substring(0, 2), 16);
|
||||
this.green = parseInt(match[1].substring(2, 4), 16);
|
||||
this.blue = parseInt(match[1].substring(4, 6), 16);
|
||||
this.alpha = 1.0;
|
||||
return true;
|
||||
}
|
||||
// '#' + 3 hex digits, e.g., #f30
|
||||
match = value.match(/#([0-9a-f]{3})/i);
|
||||
if (match) {
|
||||
this.red = parseInt(match[1].substring(0, 1), 16) * 16;
|
||||
this.green = parseInt(match[1].substring(1, 2), 16) * 16;
|
||||
this.blue = parseInt(match[1].substring(2, 3), 16) * 16;
|
||||
this.alpha = 1.0;
|
||||
return true;
|
||||
}
|
||||
// a color name, e.g., springgreen
|
||||
match = colorChart[value];
|
||||
if (match) {
|
||||
this.red = match.red;
|
||||
this.green = match.green;
|
||||
this.blue = match.blue;
|
||||
this.alpha = (match.alpha === undefined) ? 1.0 : match.alpha;
|
||||
return true;
|
||||
}
|
||||
// rgb(r, g, b), e.g., rgb(128, 12, 217)
|
||||
match = value.match(/rgb\(([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/i);
|
||||
if (match) {
|
||||
this.red = Number(match[1]);
|
||||
this.green = Number(match[2]);
|
||||
this.blue = Number(match[3]);
|
||||
this.alpha = 1.0;
|
||||
return true;
|
||||
}
|
||||
// rgb(r%, g%, b%), e.g., rgb(100%, 0%, 50%)
|
||||
// Commented out for the time being, since it seems likely that the resulting
|
||||
// decimal values will create false negatives when compared with non-% values.
|
||||
//
|
||||
// => store as separate percent values and do exact matching when compared with % values
|
||||
// and fuzzy matching when compared with non-% values?
|
||||
//
|
||||
// match = value.match(/rgb\(([0-9]{0,3}(?:\.[0-9]+)?)%\s*,\s*([0-9]{0,3}(?:\.[0-9]+)?)%\s*,\s*([0-9]{0,3}(?:\.[0-9]+)?)%\s*\)/i);
|
||||
// if (match) {
|
||||
// this.red = Number(match[1]) * 255 / 100;
|
||||
// this.green = Number(match[2]) * 255 / 100;
|
||||
// this.blue = Number(match[3]) * 255 / 100;
|
||||
// this.alpha = 1.0;
|
||||
// return true;
|
||||
// }
|
||||
// rgba(r, g, b, a), e.g., rgb(128, 12, 217, 0.2)
|
||||
match = value.match(/rgba\(([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]?(?:\.[0-9]+)?)\s*\)/i);
|
||||
if (match) {
|
||||
this.red = Number(match[1]);
|
||||
this.green = Number(match[2]);
|
||||
this.blue = Number(match[3]);
|
||||
this.alpha = Number(match[4]);
|
||||
return true;
|
||||
}
|
||||
// rgba(r%, g%, b%, a), e.g., rgb(100%, 0%, 50%, 0.3)
|
||||
// Commented out for the time being (cf. rgb() matching above)
|
||||
// match = value.match(/rgba\(([0-9]{0,3}(?:\.[0-9]+)?)%\s*,\s*([0-9]{0,3}(?:\.[0-9]+)?)%\s*,\s*([0-9]{0,3}(?:\.[0-9]+)?)%,\s*([0-9]?(?:\.[0-9]+)?)\s*\)/i);
|
||||
// if (match) {
|
||||
// this.red = Number(match[1]) * 255 / 100;
|
||||
// this.green = Number(match[2]) * 255 / 100;
|
||||
// this.blue = Number(match[3]) * 255 / 100;
|
||||
// this.alpha = Number(match[4]);
|
||||
// return true;
|
||||
// }
|
||||
// TODO(rolandsteiner): handle "hsl(h, s, l)" and "hsla(h, s, l, a)" notation
|
||||
return false;
|
||||
}
|
||||
this.toString = function() {
|
||||
return this.valid ? this.red + ',' + this.green + ',' + this.blue : '(invalid)';
|
||||
}
|
||||
this.toHexString = function() {
|
||||
if (!this.valid)
|
||||
return '(invalid)';
|
||||
return ((this.red < 16) ? '0' : '') + this.red.toString(16) +
|
||||
((this.green < 16) ? '0' : '') + this.green.toString(16) +
|
||||
((this.blue < 16) ? '0' : '') + this.blue.toString(16);
|
||||
}
|
||||
this.valid = this.parse(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility class for converting font sizes to the size
|
||||
* attribute in a font tag. Currently only converts px because
|
||||
* only the sizes and px ever come from queryCommandValue.
|
||||
*
|
||||
* @constructor
|
||||
* @param value {String} original value
|
||||
*/
|
||||
function FontSize(value) {
|
||||
this.parse = function(str) {
|
||||
if (!str)
|
||||
this.valid = false;
|
||||
var match;
|
||||
if (match = String(str).match(/([0-9]+)px/)) {
|
||||
var px = Number(match[1]);
|
||||
if (px <= 0 || px > 47)
|
||||
return false;
|
||||
if (px <= 10) {
|
||||
this.size = '1';
|
||||
} else if (px <= 13) {
|
||||
this.size = '2';
|
||||
} else if (px <= 16) {
|
||||
this.size = '3';
|
||||
} else if (px <= 18) {
|
||||
this.size = '4';
|
||||
} else if (px <= 24) {
|
||||
this.size = '5';
|
||||
} else if (px <= 32) {
|
||||
this.size = '6';
|
||||
} else {
|
||||
this.size = '7';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (match = String(str).match(/([+-][0-9]+)/)) {
|
||||
this.size = match[1];
|
||||
return this.size >= 1 && this.size <= 7;
|
||||
}
|
||||
if (Number(str)) {
|
||||
this.size = String(Number(str));
|
||||
return this.size >= 1 && this.size <= 7;
|
||||
}
|
||||
switch (str) {
|
||||
case 'x-small':
|
||||
this.size = '1';
|
||||
return true;
|
||||
case 'small':
|
||||
this.size = '2';
|
||||
return true;
|
||||
case 'medium':
|
||||
this.size = '3';
|
||||
return true;
|
||||
case 'large':
|
||||
this.size = '4';
|
||||
return true;
|
||||
case 'x-large':
|
||||
this.size = '5';
|
||||
return true;
|
||||
case 'xx-large':
|
||||
this.size = '6';
|
||||
return true;
|
||||
case 'xxx-large':
|
||||
this.size = '7';
|
||||
return true;
|
||||
case '-webkit-xxx-large':
|
||||
this.size = '7';
|
||||
return true;
|
||||
case 'larger':
|
||||
this.size = '+1';
|
||||
return true;
|
||||
case 'smaller':
|
||||
this.size = '-1';
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
this.compare = function(other) {
|
||||
return this.valid && other.valid && this.size === other.size;
|
||||
}
|
||||
this.toString = function() {
|
||||
return this.valid ? this.size : '(invalid)';
|
||||
}
|
||||
this.valid = this.parse(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility class for converting & canonicalizing font names.
|
||||
*
|
||||
* @constructor
|
||||
* @param value {String} original value
|
||||
*/
|
||||
function FontName(value) {
|
||||
this.parse = function(str) {
|
||||
if (!str)
|
||||
return false;
|
||||
str = String(str).toLowerCase();
|
||||
switch (str) {
|
||||
case 'arial new':
|
||||
this.fontname = 'arial';
|
||||
return true;
|
||||
case 'courier new':
|
||||
this.fontname = 'courier';
|
||||
return true;
|
||||
case 'times new':
|
||||
case 'times roman':
|
||||
case 'times new roman':
|
||||
this.fontname = 'times';
|
||||
return true;
|
||||
}
|
||||
this.fontname = value;
|
||||
return true;
|
||||
}
|
||||
this.compare = function(other) {
|
||||
return this.valid && other.valid && this.fontname === other.fontname;
|
||||
}
|
||||
this.toString = function() {
|
||||
return this.valid ? this.fontname : '(invalid)';
|
||||
}
|
||||
this.valid = this.parse(value);
|
||||
}
|
@ -0,0 +1,227 @@
|
||||
/**
|
||||
* @fileoverview
|
||||
* Common constants and variables used in the RTE test suite.
|
||||
*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License')
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* @version 0.1
|
||||
* @author rolandsteiner@google.com
|
||||
*/
|
||||
|
||||
// Constant for indicating a test setup is unsupported or incorrect
|
||||
// (threw exception).
|
||||
var INTERNAL_ERR = 'INTERNAL ERROR: ';
|
||||
var SETUP_EXCEPTION = 'SETUP EXCEPTION: ';
|
||||
var EXECUTION_EXCEPTION = 'EXECUTION EXCEPTION: ';
|
||||
var VERIFICATION_EXCEPTION = 'VERIFICATION EXCEPTION: ';
|
||||
|
||||
var SETUP_CONTAINER = 'WHEN INITIALIZING TEST CONTAINER';
|
||||
var SETUP_BAD_SELECTION_SPEC = 'BAD SELECTION SPECIFICATION IN TEST OR EXPECTATION STRING';
|
||||
var SETUP_HTML = 'WHEN SETTING TEST HTML';
|
||||
var SETUP_SELECTION = 'WHEN SETTING SELECTION';
|
||||
var SETUP_NOCOMMAND = 'NO COMMAND, GENERAL FUNCTION OR QUERY FUNCTION GIVEN';
|
||||
var HTML_COMPARISON = 'WHEN COMPARING OUTPUT HTML';
|
||||
|
||||
// Exceptiona to be thrown on unsupported selection operations
|
||||
var SELMODIFY_UNSUPPORTED = 'UNSUPPORTED selection.modify()';
|
||||
var SELALLCHILDREN_UNSUPPORTED = 'UNSUPPORTED selection.selectAllChildren()';
|
||||
|
||||
// Output string for unsupported functions
|
||||
// (returning bool 'false' as opposed to throwing an exception)
|
||||
var UNSUPPORTED = '<i>false</i> (UNSUPPORTED)';
|
||||
|
||||
// HTML comparison result contants.
|
||||
var VALRESULT_NOT_RUN = 0; // test hasn't been run yet
|
||||
var VALRESULT_SETUP_EXCEPTION = 1;
|
||||
var VALRESULT_EXECUTION_EXCEPTION = 2;
|
||||
var VALRESULT_VERIFICATION_EXCEPTION = 3;
|
||||
var VALRESULT_UNSUPPORTED = 4;
|
||||
var VALRESULT_CANARY = 5; // HTML changes bled into the canary.
|
||||
var VALRESULT_DIFF = 6;
|
||||
var VALRESULT_ACCEPT = 7; // HTML technically correct, but not ideal.
|
||||
var VALRESULT_EQUAL = 8;
|
||||
|
||||
var VALOUTPUT = [ // IMPORTANT: this array MUST be coordinated with the values above!!
|
||||
{css: 'grey', output: '???', title: 'The test has not been run yet.'}, // VALRESULT_NOT_RUN
|
||||
{css: 'exception', output: 'EXC.', title: 'Exception was thrown during setup.'}, // VALRESULT_SETUP_EXCEPTION
|
||||
{css: 'exception', output: 'EXC.', title: 'Exception was thrown during execution.'}, // VALRESULT_EXECUTION_EXCEPTION
|
||||
{css: 'exception', output: 'EXC.', title: 'Exception was thrown during result verification.'}, // VALRESULT_VERIFICATION_EXCEPTION
|
||||
{css: 'unsupported', output: 'UNS.', title: 'Unsupported command or value'}, // VALRESULT_UNSUPPORTED
|
||||
{css: 'canary', output: 'CANARY', title: 'The command affected the contentEditable root element, or outside HTML.'}, // VALRESULT_CANARY
|
||||
{css: 'fail', output: 'FAIL', title: 'The result differs from the expectation(s).'}, // VALRESULT_DIFF
|
||||
{css: 'accept', output: 'ACC.', title: 'The result is technically correct, but sub-optimal.'}, // VALRESULT_ACCEPT
|
||||
{css: 'pass', output: 'PASS', title: 'The test result matches the expectation.'} // VALRESULT_EQUAL
|
||||
]
|
||||
|
||||
// Selection comparison result contants.
|
||||
var SELRESULT_NOT_RUN = 0; // test hasn't been run yet
|
||||
var SELRESULT_CANARY = 1; // selection escapes the contentEditable element
|
||||
var SELRESULT_DIFF = 2;
|
||||
var SELRESULT_NA = 3;
|
||||
var SELRESULT_ACCEPT = 4; // Selection is acceptable, but not ideal.
|
||||
var SELRESULT_EQUAL = 5;
|
||||
|
||||
var SELOUTPUT = [ // IMPORTANT: this array MUST be coordinated with the values above!!
|
||||
{css: 'grey', output: 'grey', title: 'The test has not been run yet.'}, // SELRESULT_NOT_RUN
|
||||
{css: 'canary', output: 'CANARY', title: 'The selection escaped the contentEditable boundary!'}, // SELRESULT_CANARY
|
||||
{css: 'fail', output: 'FAIL', title: 'The selection differs from the expectation(s).'}, // SELRESULT_DIFF
|
||||
{css: 'na', output: 'N/A', title: 'The correctness of the selection could not be verified.'}, // SELRESULT_NA
|
||||
{css: 'accept', output: 'ACC.', title: 'The selection is technically correct, but sub-optimal.'}, // SELRESULT_ACCEPT
|
||||
{css: 'pass', output: 'PASS', title: 'The selection matches the expectation.'} // SELRESULT_EQUAL
|
||||
];
|
||||
|
||||
// RegExp for selection markers
|
||||
var SELECTION_MARKERS = /[\[\]\{\}\|\^]/;
|
||||
|
||||
// Special attributes used to mark selections within elements that otherwise
|
||||
// have no children. Important: attribute name MUST be lower case!
|
||||
var ATTRNAME_SEL_START = 'bsselstart';
|
||||
var ATTRNAME_SEL_END = 'bsselend';
|
||||
|
||||
// DOM node type constants.
|
||||
var DOM_NODE_TYPE_ELEMENT = 1;
|
||||
var DOM_NODE_TYPE_TEXT = 3;
|
||||
var DOM_NODE_TYPE_COMMENT = 8;
|
||||
|
||||
// Test parameter names
|
||||
var PARAM_DESCRIPTION = 'desc';
|
||||
var PARAM_PAD = 'pad';
|
||||
var PARAM_EXECCOMMAND = 'command';
|
||||
var PARAM_FUNCTION = 'function';
|
||||
var PARAM_QUERYCOMMANDSUPPORTED = 'qcsupported';
|
||||
var PARAM_QUERYCOMMANDENABLED = 'qcenabled';
|
||||
var PARAM_QUERYCOMMANDINDETERM = 'qcindeterm';
|
||||
var PARAM_QUERYCOMMANDSTATE = 'qcstate';
|
||||
var PARAM_QUERYCOMMANDVALUE = 'qcvalue';
|
||||
var PARAM_VALUE = 'value';
|
||||
var PARAM_EXPECTED = 'expected';
|
||||
var PARAM_EXPECTED_OUTER = 'expOuter';
|
||||
var PARAM_ACCEPT = 'accept';
|
||||
var PARAM_ACCEPT_OUTER = 'accOuter';
|
||||
var PARAM_CHECK_ATTRIBUTES = 'checkAttrs';
|
||||
var PARAM_CHECK_STYLE = 'checkStyle';
|
||||
var PARAM_CHECK_CLASS = 'checkClass';
|
||||
var PARAM_CHECK_ID = 'checkID';
|
||||
var PARAM_STYLE_WITH_CSS = 'styleWithCSS';
|
||||
|
||||
// ID suffixes for the output columns
|
||||
var IDOUT_TR = '_:TR:'; // per container
|
||||
var IDOUT_TESTID = '_:tid'; // per test
|
||||
var IDOUT_COMMAND = '_:cmd'; // per test
|
||||
var IDOUT_VALUE = '_:val'; // per test
|
||||
var IDOUT_CHECKATTRS = '_:att'; // per test
|
||||
var IDOUT_CHECKSTYLE = '_:sty'; // per test
|
||||
var IDOUT_CONTAINER = '_:cnt:'; // per container
|
||||
var IDOUT_STATUSVAL = '_:sta:'; // per container
|
||||
var IDOUT_STATUSSEL = '_:sel:'; // per container
|
||||
var IDOUT_PAD = '_:pad'; // per test
|
||||
var IDOUT_EXPECTED = '_:exp'; // per test
|
||||
var IDOUT_ACTUAL = '_:act:'; // per container
|
||||
|
||||
// Output strings to use for yes/no/NA
|
||||
var OUTSTR_YES = '●';
|
||||
var OUTSTR_NO = '○';
|
||||
var OUTSTR_NA = '-';
|
||||
|
||||
// Tags at the start of HTML strings where they were taken from
|
||||
var HTMLTAG_BODY = 'B:';
|
||||
var HTMLTAG_OUTER = 'O:';
|
||||
var HTMLTAG_INNER = 'I:';
|
||||
|
||||
// What to use for the canary
|
||||
var CANARY = 'CAN<br>ARY';
|
||||
|
||||
// Containers for tests, and their associated DOM elements:
|
||||
// iframe, win, doc, body, elem
|
||||
var containers = [
|
||||
{ id: 'dM',
|
||||
iframe: null,
|
||||
win: null,
|
||||
doc: null,
|
||||
body: null,
|
||||
editor: null,
|
||||
tagOpen: '<body>',
|
||||
tagClose: '</body>',
|
||||
editorID: null,
|
||||
canary: '',
|
||||
},
|
||||
{ id: 'body',
|
||||
iframe: null,
|
||||
win: null,
|
||||
doc: null,
|
||||
body: null,
|
||||
editor: null,
|
||||
tagOpen: '<body contenteditable="true">',
|
||||
tagClose: '</body>',
|
||||
editorID: null,
|
||||
canary: ''
|
||||
},
|
||||
{ id: 'div',
|
||||
iframe: null,
|
||||
win: null,
|
||||
doc: null,
|
||||
body: null,
|
||||
editor: null,
|
||||
tagOpen: '<div contenteditable="true" id="editor-div">',
|
||||
tagClose: '</div>',
|
||||
editorID: 'editor-div',
|
||||
canary: CANARY
|
||||
}
|
||||
];
|
||||
|
||||
// Helper variables to use in test functions
|
||||
var win = null; // window object to use for test functions
|
||||
var doc = null; // document object to use for test functions
|
||||
var body = null; // The <body> element of the current document
|
||||
var editor = null; // The contentEditable element (i.e., the <body> or <div>)
|
||||
var sel = null; // The current selection after the pad is set up
|
||||
|
||||
// Canonicalization emit flags for various purposes
|
||||
var emitFlagsForCanary = {
|
||||
emitAttrs: true,
|
||||
emitStyle: true,
|
||||
emitClass: true,
|
||||
emitID: true,
|
||||
lowercase: true,
|
||||
canonicalizeUnits: true
|
||||
};
|
||||
var emitFlagsForOutput = {
|
||||
emitAttrs: true,
|
||||
emitStyle: true,
|
||||
emitClass: true,
|
||||
emitID: true,
|
||||
lowercase: false,
|
||||
canonicalizeUnits: false
|
||||
};
|
||||
|
||||
// Shades of output colors
|
||||
var colorShades = ['Lo', 'Hi'];
|
||||
|
||||
// Classes of tests
|
||||
var testClassIDs = ['Finalized', 'RFC', 'Proposed'];
|
||||
var testClassCount = testClassIDs.length;
|
||||
|
||||
// Dictionary storing the detailed test results.
|
||||
var results = {
|
||||
count: 0,
|
||||
score: 0
|
||||
};
|
||||
|
||||
// Results - populated by the fillResults() function.
|
||||
var beacon = [];
|
||||
|
||||
// "compatibility" between Python and JS for test quines
|
||||
var True = true;
|
||||
var False = false;
|
@ -0,0 +1,138 @@
|
||||
<!-- Legend -->
|
||||
<TABLE CLASS="legend framed">
|
||||
<THEAD>
|
||||
<TR><TH COLSPAN=3 CLASS="legendHdr">Result Description</TH></TR>
|
||||
<TR><TH>Status</TH><TH ALIGN="LEFT">Meaning</TH><TH ALIGN="LEFT">Explanation</TH><TH>Scoring</TH></TR>
|
||||
</THEAD>
|
||||
<TBODY>
|
||||
<TR CLASS="lo"><TD CLASS="pass" ALIGN="CENTER"> PASS </TD><TD CLASS="legend" ROWSPAN=2>Passed</TD><TD CLASS="legend" ROWSPAN=2>The result matches the expectation.</TD><TD ROWSPAN=2 ALIGN="CENTER" CLASS="pass">PASS (+1)</TD></TR>
|
||||
<TR CLASS="hi"><TD CLASS="pass" ALIGN="CENTER"> PASS </TD></TR>
|
||||
<TR CLASS="lo"><TD CLASS="accept" ALIGN="CENTER"> ACC. </TD><TD CLASS="legend" ROWSPAN=2>Acceptable</TD><TD CLASS="legend" ROWSPAN=2>The result is technically correct, but not ideal (too verbose, deprecated usage, etc.) - for informative purposes only.</TD><TD ROWSPAN=2 ALIGN="CENTER" CLASS="fail">FAIL (+0)</TD></TR>
|
||||
<TR CLASS="hi"><TD CLASS="accept" ALIGN="CENTER"> ACC. </TD></TR>
|
||||
<TR CLASS="lo"><TD CLASS="fail" ALIGN="CENTER"> FAIL </TD><TD CLASS="legend" ROWSPAN=2>Failure</TD><TD CLASS="legend" ROWSPAN=2>The result does not match any given expectation.</TD><TD ROWSPAN=2 ALIGN="CENTER" CLASS="fail">FAIL (+0)</TD></TR>
|
||||
<TR CLASS="hi"><TD CLASS="fail" ALIGN="CENTER"> FAIL </TD></TR>
|
||||
<TR CLASS="lo"><TD CLASS="canary" ALIGN="CENTER"> CANARY </TD><TD CLASS="legend" ROWSPAN=2>Canary</TD><TD CLASS="legend" ROWSPAN=2>The result changes HTML other than children of the contentEditable element.</TD><TD ROWSPAN=2 ALIGN="CENTER" CLASS="fail">FAIL (+0)</TD></TR>
|
||||
<TR CLASS="hi"><TD CLASS="canary" ALIGN="CENTER"> CANARY </TD></TR>
|
||||
<TR CLASS="lo"><TD CLASS="unsupported" ALIGN="CENTER"> UNS. </TD><TD CLASS="legend" ROWSPAN=2>Unsupported</TD><TD CLASS="legend" ROWSPAN=2>The specific function or value is unsupported (returned boolean 'false').</TD><TD ROWSPAN=2 ALIGN="CENTER" CLASS="fail">FAIL (+0)</TD></TR>
|
||||
<TR CLASS="hi"><TD CLASS="unsupported" ALIGN="CENTER"> UNS. </TD></TR>
|
||||
<TR CLASS="lo"><TD CLASS="exception" ALIGN="CENTER"> EXC. </TD><TD CLASS="legend" ROWSPAN=2>Exception</TD><TD CLASS="legend" ROWSPAN=2>An unexpected exception was thrown during the execution of the test.</TD><TD ROWSPAN=2 ALIGN="CENTER" CLASS="fail">FAIL (+0)</TD></TR>
|
||||
<TR CLASS="hi"><TD CLASS="exception" ALIGN="CENTER"> EXC. </TD></TR>
|
||||
<TR CLASS="lo"><TD CLASS="na" ALIGN="CENTER"> N/A </TD><TD CLASS="legend" ROWSPAN=2>Not Applicable</TD><TD CLASS="legend" ROWSPAN=2>The selection could not be tested, because the tested function failed to return a known result.</TD><TD ROWSPAN=2 ALIGN="CENTER" CLASS="fail">FAIL (+0)</TD></TR>
|
||||
<TR CLASS="hi"><TD CLASS="na" ALIGN="CENTER"> N/A </TD></TR>
|
||||
</TBODY>
|
||||
</TABLE>
|
||||
<TABLE CLASS="legend framed">
|
||||
<THEAD>
|
||||
<TR><TH COLSPAN=2 CLASS="legendHdr">Selection and Result Display</TH></TR>
|
||||
<TR><TH>Character</TH><TH ALIGN="LEFT">Explanation</TH></TR>
|
||||
</THEAD>
|
||||
<TBODY>
|
||||
<TR><TD CLASS="sel" ALIGN="CENTER">[</TD><TD>Start of selection - selection point is within a text node.</TD></TR>
|
||||
<TR><TD CLASS="sel" ALIGN="CENTER">]</TD><TD>End of selection - selection point is within a text node.</TD></TR>
|
||||
<TR><TD CLASS="sel" ALIGN="CENTER">^</TD><TD>Collapsed selection - selection point is within a text node.</TD></TR>
|
||||
<TR><TD COLSPAN=2> </TD></TR>
|
||||
<TR><TD CLASS="sel" ALIGN="CENTER">{</TD><TD>Start of selection - selection point is within an element node.</TD></TR>
|
||||
<TR><TD CLASS="sel" ALIGN="CENTER">}</TD><TD>End of selection - selection point is within an element node.</TD></TR>
|
||||
<TR><TD CLASS="sel" ALIGN="CENTER">|</TD><TD>Collapsed selection - selection point is within an element node.</TD></TR>
|
||||
<TR><TD COLSPAN=2> </TD></TR>
|
||||
<TR><TD ALIGN="CENTER"><SPAN CLASS="fade">foo</SPAN></TD><TD>Greyed text indicates parts of the output that are ignored for the purposes of checking the result.</TD></TR>
|
||||
<TR><TD ALIGN="CENTER"><SPAN CLASS="txt">foo</SPAN></TD><TD>Grey border indicates extent of text nodes in the result.</TD></TR>
|
||||
</TBODY>
|
||||
</TABLE>
|
||||
<!-- progress meter -->
|
||||
<HR ID="divider">
|
||||
<H1>Running Test Suites: {% for s in suites %}<A HREF="#{{ s.id }}" ID="{{ s.id }}-progress" STYLE="color: #eeeeee">{{ s.id }}</A> {% endfor %}<SPAN ID="done"> </SPAN></H1>
|
||||
<HR>
|
||||
<!-- main output -->
|
||||
{% for s in suites %}
|
||||
<H1 ID="{{ s.id }}"><A NAME="{{ s.id }}" HREF="#{{ s.id }}">{{ s.id }}</A> - {{ s.caption }}:
|
||||
<SPAN ID="{{ s.id }}-{% ifequal s.id.0 'S' %}sel{% endifequal %}score">?/?</SPAN>
|
||||
{% ifnotequal s.id.0 "Q" %}{% ifnotequal s.id.0 "S" %}
|
||||
(Selection: <SPAN ID="{{ s.id }}-selscore">?/?</SPAN>)
|
||||
{% endifnotequal %}{% endifnotequal %}
|
||||
(time: <SPAN ID="{{ s.id }}-time">?</SPAN> ms)
|
||||
</H1>
|
||||
{% if s.comment %}
|
||||
<DIV CLASS="comment">{{ s.comment|safe }}</DIV>
|
||||
{% endif %}
|
||||
{% for cls in classes %}{% for pk, pv in s.items %}{% ifequal pk cls %}
|
||||
<H2 ID="{{ s.id }}-{{ cls }}"><A NAME="{{ s.id }}-{{ cls }}" HREF="#{{ s.id }}-{{ cls }}">{{ cls }} Tests</A>:
|
||||
<SPAN ID="{{ s.id }}-{{ cls }}-{% ifequal s.id.0 'S' %}sel{% endifequal %}score">?/?</SPAN>
|
||||
{% ifnotequal s.id.0 "Q" %}{% ifnotequal s.id.0 "S" %}
|
||||
(Selection: <SPAN ID="{{ s.id }}-{{ cls }}-selscore">?/?</SPAN>)
|
||||
{% endifnotequal %}{% endifnotequal %}
|
||||
</H2>
|
||||
<TABLE WIDTH=100%>
|
||||
<THEAD>
|
||||
<TR>
|
||||
<TH TITLE="Unique ID of the test" ALIGN="LEFT">ID</TH>
|
||||
<TH TITLE="Command or function used in the test" ALIGN="LEFT">Command</TH>
|
||||
<TH TITLE="Value field for commands" ALIGN="LEFT">Value</TH>
|
||||
{% ifnotequal s.id.0 "S" %}{% ifnotequal s.id.0 "Q" %}{% comment %} Don't output attribute and style columns for selection and "queryCommand..." tests. {% endcomment %}
|
||||
<TH TITLE="check Atributes?">A</TH>
|
||||
<TH TITLE="check Style">S</TH>
|
||||
{% endifnotequal %}{% endifnotequal %}
|
||||
<TH TITLE="Testing HTML Element">Env.</TH>
|
||||
{% ifnotequal s.id.0 "S" %}{% comment %} Don't output HTML status column for selection tests. {% endcomment %}
|
||||
<TH TITLE="State of the test">Status</TH>
|
||||
{% endifnotequal %}
|
||||
{% ifnotequal s.id.0 "Q" %}{% comment %} Don't output selection result column for "queryCommand..." tests. {% endcomment %}
|
||||
<TH TITLE="State of the test regarding the selection">Selection</TH>
|
||||
{% endifnotequal %}
|
||||
<TH TITLE="Initial HTML and selection" ALIGN="LEFT">Initial</TH>
|
||||
<TH TITLE="Expected HTML and selection" ALIGN="LEFT">Expected</TH>
|
||||
<TH TITLE="Actual result HTML and selection" ALIGN="LEFT">Actual (lower case, canonicalized, selection marks)</TH>
|
||||
<TH TITLE="Short description of the test" ALIGN="LEFT">Description</TH>
|
||||
</TR>
|
||||
</THEAD>
|
||||
<TBODY>
|
||||
{% for g in pv %}{% for t in g.tests %}
|
||||
<TR ID="{{ commonIDPrefix }}-{{ s.id }}_{{ t.id }}_:TR:dM" CLASS="{% cycle 'lo' 'lo' 'lo' 'hi' 'hi' 'hi' as shade %}">
|
||||
<TD ROWSPAN=3 ID="{{ commonIDPrefix }}-{{ s.id }}_{{ t.id }}_:tid"><A CLASS="idLabel" NAME="{{ commonIDPrefix }}-{{ s.id }}_{{ t.id }}" HREF="#{{ commonIDPrefix }}-{{ s.id }}_{{ t.id }}">{{ commonIDPrefix }}-{{ s.id }}_{{ t.id }}</A></TD>
|
||||
<TD ROWSPAN=3 ID="{{ commonIDPrefix }}-{{ s.id }}_{{ t.id }}_:cmd"> </TD>
|
||||
<TD ROWSPAN=3 ID="{{ commonIDPrefix }}-{{ s.id }}_{{ t.id }}_:val"> </TD>
|
||||
{% ifnotequal s.id.0 "S" %}{% ifnotequal s.id.0 "Q" %}{% comment %} Don't output attribute and style columns for selection and "queryCommand..." tests. {% endcomment %}
|
||||
<TD ROWSPAN=3 ID="{{ commonIDPrefix }}-{{ s.id }}_{{ t.id }}_:att" ALIGN="CENTER"> </TD>
|
||||
<TD ROWSPAN=3 ID="{{ commonIDPrefix }}-{{ s.id }}_{{ t.id }}_:sty" ALIGN="CENTER"> </TD>
|
||||
{% endifnotequal %}{% endifnotequal %}
|
||||
<TD ID="{{ commonIDPrefix }}-{{ s.id }}_{{ t.id }}_:cnt:dM" TITLE="designMode="on"" ALIGN="CENTER">dM</TD>
|
||||
{% ifnotequal s.id.0 "S" %}
|
||||
<TD ID="{{ commonIDPrefix }}-{{ s.id }}_{{ t.id }}_:sta:dM" ALIGN="CENTER">NONE</TD>
|
||||
{% endifnotequal %}
|
||||
{% ifnotequal s.id.0 "Q" %}
|
||||
<TD ID="{{ commonIDPrefix }}-{{ s.id }}_{{ t.id }}_:sel:dM" ALIGN="CENTER">NONE</TD>
|
||||
{% endifnotequal %}
|
||||
<TD ROWSPAN=3 ID="{{ commonIDPrefix }}-{{ s.id }}_{{ t.id }}_:pad"> </TD>
|
||||
<TD ROWSPAN=3 ID="{{ commonIDPrefix }}-{{ s.id }}_{{ t.id }}_:exp"> </TD>
|
||||
<TD ID="{{ commonIDPrefix }}-{{ s.id }}_{{ t.id }}_:act:dM"><I>Processing...</I></TD>
|
||||
<TD ROWSPAN=3>{{ t.desc|default:" " }}</TD>
|
||||
</TR>
|
||||
<TR ID="{{ commonIDPrefix }}-{{ s.id }}_{{ t.id }}_:TR:body" CLASS="{% cycle shade %}">
|
||||
<TD ID="{{ commonIDPrefix }}-{{ s.id }}_{{ t.id }}_:cnt:body" TITLE="<body contentEditable="true">" ALIGN="CENTER">body</TD>
|
||||
{% ifnotequal s.id.0 "S" %}
|
||||
<TD ID="{{ commonIDPrefix }}-{{ s.id }}_{{ t.id }}_:sta:body" ALIGN="CENTER">NONE</TD>
|
||||
{% endifnotequal %}
|
||||
{% ifnotequal s.id.0 "Q" %}
|
||||
<TD ID="{{ commonIDPrefix }}-{{ s.id }}_{{ t.id }}_:sel:body" ALIGN="CENTER">NONE</TD>
|
||||
{% endifnotequal %}
|
||||
<TD ID="{{ commonIDPrefix }}-{{ s.id }}_{{ t.id }}_:act:body"><I>Processing...</I></TD>
|
||||
</TR>
|
||||
<TR ID="{{ commonIDPrefix }}-{{ s.id }}_{{ t.id }}_:TR:div" CLASS="{% cycle shade %}">
|
||||
<TD ID="{{ commonIDPrefix }}-{{ s.id }}_{{ t.id }}_:cnt:div" TITLE="<div contentEditable="true">" ALIGN="CENTER">div</TD>
|
||||
{% ifnotequal s.id.0 "S" %}
|
||||
<TD ID="{{ commonIDPrefix }}-{{ s.id }}_{{ t.id }}_:sta:div" ALIGN="CENTER">NONE</TD>
|
||||
{% endifnotequal %}
|
||||
{% ifnotequal s.id.0 "Q" %}
|
||||
<TD ID="{{ commonIDPrefix }}-{{ s.id }}_{{ t.id }}_:sel:div" ALIGN="CENTER">NONE</TD>
|
||||
{% endifnotequal %}
|
||||
<TD ID="{{ commonIDPrefix }}-{{ s.id }}_{{ t.id }}_:act:div"><I>Processing...</I></TD>
|
||||
</TR>
|
||||
{% endfor %}{% endfor %}
|
||||
</TBODY>
|
||||
</TABLE>
|
||||
{% endifequal %}{% endfor %}{% endfor %}
|
||||
{% endfor %}
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,107 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
|
||||
<title>New Rich Text Tests</title>
|
||||
|
||||
<link rel="stylesheet" href="static/common.css" type="text/css">
|
||||
<link rel="stylesheet" href="static/editable.css" type="text/css">
|
||||
|
||||
<!-- utility scripts -->
|
||||
<script src="static/js/variables.js"></script>
|
||||
|
||||
<script src="static/js/canonicalize.js"></script>
|
||||
<script src="static/js/compare.js"></script>
|
||||
<script src="static/js/output.js"></script>
|
||||
<script src="static/js/pad.js"></script>
|
||||
<script src="static/js/range.js"></script>
|
||||
<script src="static/js/units.js"></script>
|
||||
|
||||
<script src="static/js/run.js"></script>
|
||||
|
||||
<!-- new tests -->
|
||||
<script type="text/javascript">
|
||||
{% autoescape off %}
|
||||
|
||||
var commonIDPrefix = '{{ commonIDPrefix }}';
|
||||
{% for s in suites %}
|
||||
var {{ s.id }}_TESTS = {{ s }};
|
||||
{% endfor %}
|
||||
|
||||
/**
|
||||
* Stuff to do after all tests are run:
|
||||
* - write a nice "DONE!" at the end of the progress meter
|
||||
* - beacon the results
|
||||
* - remove the testing <iframe>s
|
||||
*/
|
||||
function finish() {
|
||||
var span = document.getElementById('done');
|
||||
if (span)
|
||||
span.innerHTML = ' ... DONE!';
|
||||
|
||||
fillResults();
|
||||
parent.sendScore(beacon, categoryTotals);
|
||||
|
||||
cleanUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Run every individual suite, with a a brief timeout in between
|
||||
* to allow for screen updates.
|
||||
*/
|
||||
{% for s in suites %}
|
||||
{% if not forloop.first %}
|
||||
setTimeout("runSuite{{ s.id }}()", 100);
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
function runSuite{{ s.id }}() {
|
||||
runAndOutputTestSuite({{ s.id }}_TESTS);
|
||||
{% endfor %}
|
||||
finish();
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs all tests in all suites.
|
||||
*/
|
||||
function doRunTests() {
|
||||
initVariables();
|
||||
initEditorDocs();
|
||||
|
||||
// Start with the first test suite
|
||||
runSuite{{ suites.0.id }}();
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs after allowing for some time to have everything loaded
|
||||
* (aka. horrible IE9 kludge)
|
||||
*/
|
||||
function runTests() {
|
||||
setTimeout("doRunTests()", 1500);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the <iframe>s after all tests are finished
|
||||
*/
|
||||
function cleanUp() {
|
||||
var e = document.getElementById('iframe-dM');
|
||||
e.parentNode.removeChild(e);
|
||||
e = document.getElementById('iframe-body');
|
||||
e.parentNode.removeChild(e);
|
||||
e = document.getElementById('iframe-div');
|
||||
e.parentNode.removeChild(e);
|
||||
}
|
||||
{% endautoescape %}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload="runTests()">
|
||||
{% include "richtext2/templates/output.html" %}
|
||||
<hr>
|
||||
<iframe name="iframe-dM" id="iframe-dM" src="static/editable-dM.html"></iframe>
|
||||
<iframe name="iframe-body" id="iframe-body" src="static/editable-body.html"></iframe>
|
||||
<iframe name="iframe-div" id="iframe-div" src="static/editable-div.html"></iframe>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,17 @@
|
||||
__all__ = [
|
||||
'apply',
|
||||
'applyCSS',
|
||||
'change',
|
||||
'changeCSS',
|
||||
'delete',
|
||||
'forwarddelete',
|
||||
'insert',
|
||||
'queryEnabled',
|
||||
'queryIndeterm',
|
||||
'queryState',
|
||||
'querySupported',
|
||||
'queryValue',
|
||||
'selection',
|
||||
'unapply',
|
||||
'unapplyCSS'
|
||||
]
|
364
editor/libeditor/html/tests/browserscope/lib/richtext2/richtext2/tests/apply.py
Executable file
364
editor/libeditor/html/tests/browserscope/lib/richtext2/richtext2/tests/apply.py
Executable file
@ -0,0 +1,364 @@
|
||||
|
||||
APPLY_TESTS = {
|
||||
'id': 'A',
|
||||
'caption': 'Apply Formatting Tests',
|
||||
'checkAttrs': True,
|
||||
'checkStyle': True,
|
||||
'styleWithCSS': False,
|
||||
|
||||
'Proposed': [
|
||||
{ 'desc': '',
|
||||
'command': '',
|
||||
'tests': [
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[HTML5] bold',
|
||||
'command': 'bold',
|
||||
'tests': [
|
||||
{ 'id': 'B_TEXT-1_SI',
|
||||
'rte1-id': 'a-bold-0',
|
||||
'desc': 'Bold selection',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': [ 'foo<b>[bar]</b>baz',
|
||||
'foo<strong>[bar]</strong>baz' ] },
|
||||
|
||||
{ 'id': 'B_TEXT-1_SIR',
|
||||
'desc': 'Bold reversed selection',
|
||||
'pad': 'foo]bar[baz',
|
||||
'expected': [ 'foo<b>[bar]</b>baz',
|
||||
'foo<strong>[bar]</strong>baz' ] },
|
||||
|
||||
{ 'id': 'B_I-1_SL',
|
||||
'desc': 'Bold selection, partially including italic',
|
||||
'pad': 'foo[bar<i>baz]qoz</i>quz',
|
||||
'expected': [ 'foo<b>[bar</b><i><b>baz]</b>qoz</i>quz',
|
||||
'foo<b>[bar<i>baz]</i></b><i>qoz</i>quz',
|
||||
'foo<strong>[bar</strong><i><strong>baz]</strong>qoz</i>quz',
|
||||
'foo<strong>[bar<i>baz]</i></strong><i>qoz</i>quz' ] }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[HTML5] italic',
|
||||
'command': 'italic',
|
||||
'tests': [
|
||||
{ 'id': 'I_TEXT-1_SI',
|
||||
'rte1-id': 'a-italic-0',
|
||||
'desc': 'Italicize selection',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': [ 'foo<i>[bar]</i>baz',
|
||||
'foo<em>[bar]</em>baz' ] }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[HTML5] underline',
|
||||
'command': 'underline',
|
||||
'tests': [
|
||||
{ 'id': 'U_TEXT-1_SI',
|
||||
'rte1-id': 'a-underline-0',
|
||||
'desc': 'Underline selection',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': 'foo<u>[bar]</u>baz' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[HTML5] strikethrough',
|
||||
'command': 'strikethrough',
|
||||
'tests': [
|
||||
{ 'id': 'S_TEXT-1_SI',
|
||||
'rte1-id': 'a-strikethrough-0',
|
||||
'desc': 'Strike-through selection',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': [ 'foo<s>[bar]</s>baz',
|
||||
'foo<strike>[bar]</strike>baz',
|
||||
'foo<del>[bar]</del>baz' ] }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[HTML5] subscript',
|
||||
'command': 'subscript',
|
||||
'tests': [
|
||||
{ 'id': 'SUB_TEXT-1_SI',
|
||||
'rte1-id': 'a-subscript-0',
|
||||
'desc': 'Change selection to subscript',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': 'foo<sub>[bar]</sub>baz' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[HTML5] superscript',
|
||||
'command': 'superscript',
|
||||
'tests': [
|
||||
{ 'id': 'SUP_TEXT-1_SI',
|
||||
'rte1-id': 'a-superscript-0',
|
||||
'desc': 'Change selection to superscript',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': 'foo<sup>[bar]</sup>baz' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[HTML5] createlink',
|
||||
'command': 'createlink',
|
||||
'tests': [
|
||||
{ 'id': 'CL:url_TEXT-1_SI',
|
||||
'rte1-id': 'a-createlink-0',
|
||||
'desc': 'create a link around the selection',
|
||||
'value': '#foo',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': 'foo<a href="#foo">[bar]</a>baz' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[HTML5] formatBlock',
|
||||
'command': 'formatblock',
|
||||
'tests': [
|
||||
{ 'id': 'FB:H1_TEXT-1_SI',
|
||||
'rte1-id': 'a-formatblock-0',
|
||||
'desc': 'format the selection into a block: use <h1>',
|
||||
'value': 'h1',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': '<h1>foo[bar]baz</h1>' },
|
||||
|
||||
{ 'id': 'FB:P_TEXT-1_SI',
|
||||
'desc': 'format the selection into a block: use <p>',
|
||||
'value': 'p',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': '<p>foo[bar]baz</p>' },
|
||||
|
||||
{ 'id': 'FB:PRE_TEXT-1_SI',
|
||||
'desc': 'format the selection into a block: use <pre>',
|
||||
'value': 'pre',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': '<pre>foo[bar]baz</pre>' },
|
||||
|
||||
{ 'id': 'FB:ADDRESS_TEXT-1_SI',
|
||||
'desc': 'format the selection into a block: use <address>',
|
||||
'value': 'address',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': '<address>foo[bar]baz</address>' },
|
||||
|
||||
{ 'id': 'FB:BQ_TEXT-1_SI',
|
||||
'desc': 'format the selection into a block: use <blockquote>',
|
||||
'value': 'blockquote',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': '<blockquote>foo[bar]baz</blockquote>' },
|
||||
|
||||
{ 'id': 'FB:BQ_BR.BR-1_SM',
|
||||
'desc': 'format a multi-line selection into a block: use <blockquote>',
|
||||
'command': 'formatblock',
|
||||
'value': 'blockquote',
|
||||
'pad': 'fo[o<br>bar<br>b]az',
|
||||
'expected': '<blockquote>fo[o<br>bar<br>b]az</blockquote>' }
|
||||
]
|
||||
},
|
||||
|
||||
|
||||
{ 'desc': '[MIDAS] backcolor',
|
||||
'command': 'backcolor',
|
||||
'tests': [
|
||||
{ 'id': 'BC:blue_TEXT-1_SI',
|
||||
'rte1-id': 'a-backcolor-0',
|
||||
'desc': 'Change background color (note: no non-CSS variant available)',
|
||||
'value': 'blue',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': [ 'foo<span style="background-color: blue">[bar]</span>baz',
|
||||
'foo<font style="background-color: blue">[bar]</font>baz' ] }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[MIDAS] forecolor',
|
||||
'command': 'forecolor',
|
||||
'tests': [
|
||||
{ 'id': 'FC:blue_TEXT-1_SI',
|
||||
'rte1-id': 'a-forecolor-0',
|
||||
'desc': 'Change the text color',
|
||||
'value': 'blue',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': 'foo<font color="blue">[bar]</font>baz' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[MIDAS] hilitecolor',
|
||||
'command': 'hilitecolor',
|
||||
'tests': [
|
||||
{ 'id': 'HC:blue_TEXT-1_SI',
|
||||
'rte1-id': 'a-hilitecolor-0',
|
||||
'desc': 'Change the hilite color',
|
||||
'value': 'blue',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': [ 'foo<span style="background-color: blue">[bar]</span>baz',
|
||||
'foo<font style="background-color: blue">[bar]</font>baz' ] }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[MIDAS] fontname',
|
||||
'command': 'fontname',
|
||||
'tests': [
|
||||
{ 'id': 'FN:a_TEXT-1_SI',
|
||||
'rte1-id': 'a-fontname-0',
|
||||
'desc': 'Change the font name',
|
||||
'value': 'arial',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': 'foo<font face="arial">[bar]</font>baz' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[MIDAS] fontsize',
|
||||
'command': 'fontsize',
|
||||
'tests': [
|
||||
{ 'id': 'FS:2_TEXT-1_SI',
|
||||
'rte1-id': 'a-fontsize-0',
|
||||
'desc': 'Change the font size to "2"',
|
||||
'value': '2',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': 'foo<font size="2">[bar]</font>baz' },
|
||||
|
||||
{ 'id': 'FS:18px_TEXT-1_SI',
|
||||
'desc': 'Change the font size to "18px"',
|
||||
'value': '18px',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': 'foo<font size="18px">[bar]</font>baz' },
|
||||
|
||||
{ 'id': 'FS:large_TEXT-1_SI',
|
||||
'desc': 'Change the font size to "large"',
|
||||
'value': 'large',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': 'foo<font size="large">[bar]</font>baz' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[MIDAS] increasefontsize',
|
||||
'command': 'increasefontsize',
|
||||
'tests': [
|
||||
{ 'id': 'INCFS:2_TEXT-1_SI',
|
||||
'desc': 'Decrease the font size (to small)',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': [ 'foo<font size="4">[bar]</font>baz',
|
||||
'foo<font size="+1">[bar]</font>baz',
|
||||
'foo<big>[bar]</big>baz' ] }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[MIDAS] decreasefontsize',
|
||||
'command': 'decreasefontsize',
|
||||
'tests': [
|
||||
{ 'id': 'DECFS:2_TEXT-1_SI',
|
||||
'rte1-id': 'a-decreasefontsize-0',
|
||||
'desc': 'Decrease the font size (to small)',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': [ 'foo<font size="2">[bar]</font>baz',
|
||||
'foo<font size="-1">[bar]</font>baz',
|
||||
'foo<small>[bar]</small>baz' ] }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[MIDAS] indent (note: accept the de-facto standard indent of 40px)',
|
||||
'command': 'indent',
|
||||
'tests': [
|
||||
{ 'id': 'IND_TEXT-1_SI',
|
||||
'rte1-id': 'a-indent-0',
|
||||
'desc': 'Indent the text (accept the de-facto standard of 40px indent)',
|
||||
'pad': 'foo[bar]baz',
|
||||
'checkAttrs': False,
|
||||
'expected': [ '<blockquote>foo[bar]baz</blockquote>',
|
||||
'<div style="margin-left: 40px">foo[bar]baz</div>' ],
|
||||
'div': {
|
||||
'accOuter': '<div contenteditable="true" style="margin-left: 40px">foo[bar]baz</div>' } }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[MIDAS] outdent (-> unapply tests)',
|
||||
'command': 'outdent',
|
||||
'tests': [
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[MIDAS] justifycenter',
|
||||
'command': 'justifycenter',
|
||||
'tests': [
|
||||
{ 'id': 'JC_TEXT-1_SC',
|
||||
'rte1-id': 'a-justifycenter-0',
|
||||
'desc': 'justify the text centrally',
|
||||
'pad': 'foo^bar',
|
||||
'expected': [ '<center>foo^bar</center>',
|
||||
'<p align="center">foo^bar</p>',
|
||||
'<p align="middle">foo^bar</p>',
|
||||
'<div align="center">foo^bar</div>',
|
||||
'<div align="middle">foo^bar</div>' ],
|
||||
'div': {
|
||||
'accOuter': [ '<div align="center" contenteditable="true">foo^bar</div>',
|
||||
'<div align="middle" contenteditable="true">foo^bar</div>' ] } }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[MIDAS] justifyfull',
|
||||
'command': 'justifyfull',
|
||||
'tests': [
|
||||
{ 'id': 'JF_TEXT-1_SC',
|
||||
'rte1-id': 'a-justifyfull-0',
|
||||
'desc': 'justify the text fully',
|
||||
'pad': 'foo^bar',
|
||||
'expected': [ '<p align="justify">foo^bar</p>',
|
||||
'<div align="justify">foo^bar</div>' ],
|
||||
'div': {
|
||||
'accOuter': '<div align="justify" contenteditable="true">foo^bar</div>' } }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[MIDAS] justifyleft',
|
||||
'command': 'justifyleft',
|
||||
'tests': [
|
||||
{ 'id': 'JL_TEXT-1_SC',
|
||||
'rte1-id': 'a-justifyleft-0',
|
||||
'desc': 'justify the text left',
|
||||
'pad': 'foo^bar',
|
||||
'expected': [ '<p align="left">foo^bar</p>',
|
||||
'<div align="left">foo^bar</div>' ],
|
||||
'div': {
|
||||
'accOuter': '<div align="left" contenteditable="true">foo^bar</div>' } }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[MIDAS] justifyright',
|
||||
'command': 'justifyright',
|
||||
'tests': [
|
||||
{ 'id': 'JR_TEXT-1_SC',
|
||||
'rte1-id': 'a-justifyright-0',
|
||||
'desc': 'justify the text right',
|
||||
'pad': 'foo^bar',
|
||||
'expected': [ '<p align="right">foo^bar</p>',
|
||||
'<div align="right">foo^bar</div>' ],
|
||||
'div': {
|
||||
'accOuter': '<div align="right" contenteditable="true">foo^bar</div>' } }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[MIDAS] heading',
|
||||
'command': 'heading',
|
||||
'tests': [
|
||||
{ 'id': 'H:H1_TEXT-1_SC',
|
||||
'desc': 'create a heading from the paragraph that contains the selection',
|
||||
'value': 'h1',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': '<h1>foo[bar]baz</h1>' }
|
||||
]
|
||||
},
|
||||
|
||||
|
||||
{ 'desc': '[Other] createbookmark',
|
||||
'command': 'createbookmark',
|
||||
'tests': [
|
||||
{ 'id': 'CB:name_TEXT-1_SI',
|
||||
'rte1-id': 'a-createbookmark-0',
|
||||
'desc': 'create a bookmark (named link) around selection',
|
||||
'value': 'created',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': 'foo<a name="created">[bar]</a>baz' }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,244 @@
|
||||
|
||||
APPLY_TESTS_CSS = {
|
||||
'id': 'AC',
|
||||
'caption': 'Apply Formatting Tests, using styleWithCSS',
|
||||
'checkAttrs': True,
|
||||
'checkStyle': True,
|
||||
'styleWithCSS': True,
|
||||
|
||||
'Proposed': [
|
||||
{ 'desc': '',
|
||||
'command': '',
|
||||
'tests': [
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[HTML5] bold',
|
||||
'command': 'bold',
|
||||
'tests': [
|
||||
{ 'id': 'B_TEXT-1_SI',
|
||||
'rte1-id': 'a-bold-1',
|
||||
'desc': 'Bold selection',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': 'foo<span style="font-weight: bold">[bar]</span>baz' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[HTML5] italic',
|
||||
'command': 'italic',
|
||||
'tests': [
|
||||
{ 'id': 'I_TEXT-1_SI',
|
||||
'rte1-id': 'a-italic-1',
|
||||
'desc': 'Italicize selection',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': 'foo<span style="font-style: italic">[bar]</span>baz' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[HTML5] underline',
|
||||
'command': 'underline',
|
||||
'tests': [
|
||||
{ 'id': 'U_TEXT-1_SI',
|
||||
'rte1-id': 'a-underline-1',
|
||||
'desc': 'Underline selection',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': 'foo<span style="text-decoration: underline">[bar]</span>baz' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[HTML5] strikethrough',
|
||||
'command': 'strikethrough',
|
||||
'tests': [
|
||||
{ 'id': 'S_TEXT-1_SI',
|
||||
'rte1-id': 'a-strikethrough-1',
|
||||
'desc': 'Strike-through selection',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': 'foo<span style="text-decoration: line-through">[bar]</span>baz' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[HTML5] subscript',
|
||||
'command': 'subscript',
|
||||
'tests': [
|
||||
{ 'id': 'SUB_TEXT-1_SI',
|
||||
'rte1-id': 'a-subscript-1',
|
||||
'desc': 'Change selection to subscript',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': 'foo<span style="vertical-align: sub">[bar]</span>baz' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[HTML5] superscript',
|
||||
'command': 'superscript',
|
||||
'tests': [
|
||||
{ 'id': 'SUP_TEXT-1_SI',
|
||||
'rte1-id': 'a-superscript-1',
|
||||
'desc': 'Change selection to superscript',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': 'foo<span style="vertical-align: super">[bar]</span>baz' }
|
||||
]
|
||||
},
|
||||
|
||||
|
||||
{ 'desc': '[MIDAS] backcolor',
|
||||
'command': 'backcolor',
|
||||
'tests': [
|
||||
{ 'id': 'BC:blue_TEXT-1_SI',
|
||||
'rte1-id': 'a-backcolor-1',
|
||||
'desc': 'Change background color',
|
||||
'value': 'blue',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': [ 'foo<span style="background-color: blue">[bar]</span>baz',
|
||||
'foo<font style="background-color: blue">[bar]</font>baz' ] }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[MIDAS] forecolor',
|
||||
'command': 'forecolor',
|
||||
'tests': [
|
||||
{ 'id': 'FC:blue_TEXT-1_SI',
|
||||
'rte1-id': 'a-forecolor-1',
|
||||
'desc': 'Change the text color',
|
||||
'value': 'blue',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': [ 'foo<span style="color: blue">[bar]</span>baz',
|
||||
'foo<font style="color: blue">[bar]</font>baz' ] }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[MIDAS] hilitecolor',
|
||||
'command': 'hilitecolor',
|
||||
'tests': [
|
||||
{ 'id': 'HC:blue_TEXT-1_SI',
|
||||
'rte1-id': 'a-hilitecolor-1',
|
||||
'desc': 'Change the hilite color',
|
||||
'value': 'blue',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': [ 'foo<span style="background-color: blue">[bar]</span>baz',
|
||||
'foo<font style="background-color: blue">[bar]</font>baz' ] }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[MIDAS] fontname',
|
||||
'command': 'fontname',
|
||||
'tests': [
|
||||
{ 'id': 'FN:a_TEXT-1_SI',
|
||||
'rte1-id': 'a-fontname-1',
|
||||
'desc': 'Change the font name',
|
||||
'value': 'arial',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': [ 'foo<span style="font-family: arial">[bar]</span>baz',
|
||||
'foo<font style="font-family: blue">[bar]</font>baz' ] }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[MIDAS] fontsize',
|
||||
'command': 'fontsize',
|
||||
'tests': [
|
||||
{ 'id': 'FS:2_TEXT-1_SI',
|
||||
'rte1-id': 'a-fontsize-1',
|
||||
'desc': 'Change the font size to "2"',
|
||||
'value': '2',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': [ 'foo<span style="font-size: small">[bar]</span>baz',
|
||||
'foo<font style="font-size: small">[bar]</font>baz' ] },
|
||||
|
||||
{ 'id': 'FS:18px_TEXT-1_SI',
|
||||
'desc': 'Change the font size to "18px"',
|
||||
'value': '18px',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': [ 'foo<span style="font-size: 18px">[bar]</span>baz',
|
||||
'foo<font style="font-size: 18px">[bar]</font>baz' ] },
|
||||
|
||||
{ 'id': 'FS:large_TEXT-1_SI',
|
||||
'desc': 'Change the font size to "large"',
|
||||
'value': 'large',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': [ 'foo<span style="font-size: large">[bar]</span>baz',
|
||||
'foo<font style="font-size: large">[bar]</font>baz' ] }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[MIDAS] indent',
|
||||
'command': 'indent',
|
||||
'tests': [
|
||||
{ 'id': 'IND_TEXT-1_SI',
|
||||
'rte1-id': 'a-indent-1',
|
||||
'desc': 'Indent the text (assume "standard" 40px)',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': [ '<div style="margin-left: 40px">foo[bar]baz</div>',
|
||||
'<div style="margin: 0 0 0 40px">foo[bar]baz</div>',
|
||||
'<blockquote style="margin-left: 40px">foo[bar]baz</blockquote>',
|
||||
'<blockquote style="margin: 0 0 0 40px">foo[bar]baz</blockquote>' ],
|
||||
'div': {
|
||||
'accOuter': [ '<div contenteditable="true" style="margin-left: 40px">foo[bar]baz</div>',
|
||||
'<div contenteditable="true" style="margin: 0 0 0 40px">foo[bar]baz</div>' ] } }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[MIDAS] outdent (-> unapply tests)',
|
||||
'command': 'outdent',
|
||||
'tests': [
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[MIDAS] justifycenter',
|
||||
'command': 'justifycenter',
|
||||
'tests': [
|
||||
{ 'id': 'JC_TEXT-1_SC',
|
||||
'rte1-id': 'a-justifycenter-1',
|
||||
'desc': 'justify the text centrally',
|
||||
'pad': 'foo^bar',
|
||||
'expected': [ '<p style="text-align: center">foo^bar</p>',
|
||||
'<div style="text-align: center">foo^bar</div>' ],
|
||||
'div': {
|
||||
'accOuter': '<div contenteditable="true" style="text-align: center">foo^bar</div>' } }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[MIDAS] justifyfull',
|
||||
'command': 'justifyfull',
|
||||
'tests': [
|
||||
{ 'id': 'JF_TEXT-1_SC',
|
||||
'rte1-id': 'a-justifyfull-1',
|
||||
'desc': 'justify the text fully',
|
||||
'pad': 'foo^bar',
|
||||
'expected': [ '<p style="text-align: justify">foo^bar</p>',
|
||||
'<div style="text-align: justify">foo^bar</div>' ],
|
||||
'div': {
|
||||
'accOuter': '<div contenteditable="true" style="text-align: justify">foo^bar</div>' } }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[MIDAS] justifyleft',
|
||||
'command': 'justifyleft',
|
||||
'tests': [
|
||||
{ 'id': 'JL_TEXT-1_SC',
|
||||
'rte1-id': 'a-justifyleft-1',
|
||||
'desc': 'justify the text left',
|
||||
'pad': 'foo^bar',
|
||||
'expected': [ '<p style="text-align: left">foo^bar</p>',
|
||||
'<div style="text-align: left">foo^bar</div>' ],
|
||||
'div': {
|
||||
'accOuter': '<div contenteditable="true" style="text-align: left">foo^bar</div>' } }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[MIDAS] justifyright',
|
||||
'command': 'justifyright',
|
||||
'tests': [
|
||||
{ 'id': 'JR_TEXT-1_SC',
|
||||
'rte1-id': 'a-justifyright-1',
|
||||
'desc': 'justify the text right',
|
||||
'pad': 'foo^bar',
|
||||
'expected': [ '<p style="text-align: right">foo^bar</p>',
|
||||
'<div style="text-align: right">foo^bar</div>' ],
|
||||
'div': {
|
||||
'accOuter': '<div contenteditable="true" style="text-align: right">foo^bar</div>' } }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
|
273
editor/libeditor/html/tests/browserscope/lib/richtext2/richtext2/tests/change.py
Executable file
273
editor/libeditor/html/tests/browserscope/lib/richtext2/richtext2/tests/change.py
Executable file
@ -0,0 +1,273 @@
|
||||
|
||||
CHANGE_TESTS = {
|
||||
'id': 'C',
|
||||
'caption': 'Change Existing Format to Different Format Tests',
|
||||
'checkAttrs': True,
|
||||
'checkStyle': True,
|
||||
'styleWithCSS': False,
|
||||
|
||||
'Proposed': [
|
||||
{ 'desc': '',
|
||||
'command': '',
|
||||
'tests': [
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[HTML5] italic',
|
||||
'command': 'italic',
|
||||
'tests': [
|
||||
{ 'id': 'I_I-1_SL',
|
||||
'desc': 'Italicize partially italicized text',
|
||||
'pad': 'foo[bar<i>baz]</i>qoz',
|
||||
'expected': 'foo<i>[barbaz]</i>qoz' },
|
||||
|
||||
{ 'id': 'I_B-I-1_SO',
|
||||
'desc': 'Italicize partially italicized text in bold context',
|
||||
'pad': '<b>foo[bar<i>baz</i>}</b>',
|
||||
'expected': '<b>foo<i>[barbaz]</i></b>' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[HTML5] underline',
|
||||
'command': 'underline',
|
||||
'tests': [
|
||||
{ 'id': 'U_U-1_SO',
|
||||
'desc': 'Underline partially underlined text',
|
||||
'pad': 'foo[bar<u>baz</u>qoz]quz',
|
||||
'expected': 'foo<u>[barbazqoz]</u>quz' },
|
||||
|
||||
{ 'id': 'U_U-1_SL',
|
||||
'desc': 'Underline partially underlined text',
|
||||
'pad': 'foo[bar<u>baz]qoz</u>quz',
|
||||
'expected': 'foo<u>[barbaz]qoz</u>quz' },
|
||||
|
||||
{ 'id': 'U_S-U-1_SO',
|
||||
'desc': 'Underline partially underlined text in striked context',
|
||||
'pad': '<s>foo[bar<u>baz</u>}</s>',
|
||||
'expected': '<s>foo<u>[barbaz]</u></s>' }
|
||||
]
|
||||
},
|
||||
|
||||
|
||||
{ 'desc': '[MIDAS] backcolor',
|
||||
'command': 'backcolor',
|
||||
'tests': [
|
||||
{ 'id': 'BC:842_FONTs:bc:fca-1_SW',
|
||||
'rte1-id': 'c-backcolor-0',
|
||||
'desc': 'Change background color to new color',
|
||||
'value': '#884422',
|
||||
'pad': '<font style="background-color: #ffccaa">[foobarbaz]</font>',
|
||||
'expected': [ '<font style="background-color: #884422">[foobarbaz]</font>',
|
||||
'<span style="background-color: #884422">[foobarbaz]</span>' ] },
|
||||
|
||||
{ 'id': 'BC:00f_SPANs:bc:f00-1_SW',
|
||||
'rte1-id': 'c-backcolor-2',
|
||||
'desc': 'Change background color to new color',
|
||||
'value': '#0000ff',
|
||||
'pad': '<span style="background-color: #ff0000">[foobarbaz]</span>',
|
||||
'expected': [ '<font style="background-color: #0000ff">[foobarbaz]</font>',
|
||||
'<span style="background-color: #0000ff">[foobarbaz]</span>' ] },
|
||||
|
||||
{ 'id': 'BC:ace_FONT.ass.s:bc:rgb-1_SW',
|
||||
'rte1-id': 'c-backcolor-1',
|
||||
'desc': 'Change background color in styled span to new color',
|
||||
'value': '#aaccee',
|
||||
'pad': '<span class="Apple-style-span" style="background-color: rgb(255, 0, 0)">[foobarbaz]</span>',
|
||||
'expected': [ '<font style="background-color: #aaccee">[foobarbaz]</font>',
|
||||
'<span style="background-color: #aaccee">[foobarbaz]</span>' ] }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[MIDAS] forecolor',
|
||||
'command': 'forecolor',
|
||||
'tests': [
|
||||
{ 'id': 'FC:g_FONTc:b-1_SW',
|
||||
'rte1-id': 'c-forecolor-0',
|
||||
'desc': 'Change the text color (without CSS)',
|
||||
'value': 'green',
|
||||
'pad': '<font color="blue">[foobarbaz]</font>',
|
||||
'expected': '<font color="green">[foobarbaz]</font>' },
|
||||
|
||||
{ 'id': 'FC:g_SPANs:c:g-1_SW',
|
||||
'rte1-id': 'c-forecolor-1',
|
||||
'desc': 'Change the text color from a styled span (without CSS)',
|
||||
'value': 'green',
|
||||
'pad': '<span style="color: blue">[foobarbaz]</span>',
|
||||
'expected': '<font color="green">[foobarbaz]</font>' },
|
||||
|
||||
{ 'id': 'FC:g_FONTc:b.s:c:r-1_SW',
|
||||
'rte1-id': 'c-forecolor-2',
|
||||
'desc': 'Change the text color from conflicting color and style (without CSS)',
|
||||
'value': 'green',
|
||||
'pad': '<font color="blue" style="color: red">[foobarbaz]</font>',
|
||||
'expected': '<font color="green">[foobarbaz]</font>' },
|
||||
|
||||
{ 'id': 'FC:g_FONTc:b.sz:6-1_SI',
|
||||
'desc': 'Change the font color in content with a different font size and font color',
|
||||
'value': 'green',
|
||||
'pad': '<font color="blue" size="6">foo[bar]baz</font>',
|
||||
'expected': [ '<font color="blue" size="6">foo<font color="green">[bar]</font>baz</font>',
|
||||
'<font size="6"><font color="blue">foo<font color="green">[bar]</font><font color="blue">baz</font></font>' ] }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[MIDAS] hilitecolor',
|
||||
'command': 'hilitecolor',
|
||||
'tests': [
|
||||
{ 'id': 'HC:g_FONTs:c:b-1_SW',
|
||||
'rte1-id': 'c-hilitecolor-0',
|
||||
'desc': 'Change the hilite color (without CSS)',
|
||||
'value': 'green',
|
||||
'pad': '<font style="background-color: blue">[foobarbaz]</font>',
|
||||
'expected': [ '<font style="background-color: green">[foobarbaz]</font>',
|
||||
'<span style="background-color: green">[foobarbaz]</span>' ] },
|
||||
|
||||
{ 'id': 'HC:g_SPANs:c:g-1_SW',
|
||||
'rte1-id': 'c-hilitecolor-2',
|
||||
'desc': 'Change the hilite color from a styled span (without CSS)',
|
||||
'value': 'green',
|
||||
'pad': '<span style="background-color: blue">[foobarbaz]</span>',
|
||||
'expected': '<span style="background-color: green">[foobarbaz]</span>' },
|
||||
|
||||
{ 'id': 'HC:g_SPAN.ass.s:c:rgb-1_SW',
|
||||
'rte1-id': 'c-hilitecolor-1',
|
||||
'desc': 'Change the hilite color from a styled span (without CSS)',
|
||||
'value': 'green',
|
||||
'pad': '<span class="Apple-style-span" style="background-color: rgb(255, 0, 0);">[foobarbaz]</span>',
|
||||
'expected': '<span style="background-color: green">[foobarbaz]</span>' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[MIDAS] fontname',
|
||||
'command': 'fontname',
|
||||
'tests': [
|
||||
{ 'id': 'FN:c_FONTf:a-1_SW',
|
||||
'rte1-id': 'c-fontname-0',
|
||||
'desc': 'Change existing font name to new font name (without CSS)',
|
||||
'value': 'courier',
|
||||
'pad': '<font face="arial">[foobarbaz]</font>',
|
||||
'expected': '<font face="courier">[foobarbaz]</font>' },
|
||||
|
||||
{ 'id': 'FN:c_SPANs:ff:a-1_SW',
|
||||
'rte1-id': 'c-fontname-1',
|
||||
'desc': 'Change existing font name from style to new font name (without CSS)',
|
||||
'value': 'courier',
|
||||
'pad': '<span style="font-family: arial">[foobarbaz]</span>',
|
||||
'expected': '<font face="courier">[foobarbaz]</font>' },
|
||||
|
||||
{ 'id': 'FN:c_FONTf:a.s:ff:v-1_SW',
|
||||
'rte1-id': 'c-fontname-2',
|
||||
'desc': 'Change existing font name with conflicting face and style to new font name (without CSS)',
|
||||
'value': 'courier',
|
||||
'pad': '<font face="arial" style="font-family: verdana">[foobarbaz]</font>',
|
||||
'expected': '<font face="courier">[foobarbaz]</font>' },
|
||||
|
||||
{ 'id': 'FN:c_FONTf:a-1_SI',
|
||||
'desc': 'Change existing font name to new font name, text partially selected',
|
||||
'value': 'courier',
|
||||
'pad': '<font face="arial">foo[bar]baz</font>',
|
||||
'expected': '<font face="arial">foo</font><font face="courier">[bar]</font><font face="arial">baz</font>',
|
||||
'accept': '<font face="arial">foo<font face="courier">[bar]</font>baz</font>' },
|
||||
|
||||
{ 'id': 'FN:c_FONTf:a-2_SL',
|
||||
'desc': 'Change existing font name to new font name, using CSS styling',
|
||||
'value': 'courier',
|
||||
'pad': 'foo[bar<font face="arial">baz]qoz</font>',
|
||||
'expected': 'foo<font face="courier">[barbaz]</font><font face="arial">qoz</font>' },
|
||||
|
||||
{ 'id': 'FN:c_FONTf:v-FONTf:a-1_SW',
|
||||
'rte1-id': 'c-fontname-3',
|
||||
'desc': 'Change existing font name in nested <font> tags to new font name (without CSS)',
|
||||
'value': 'courier',
|
||||
'pad': '<font face="verdana"><font face="arial">[foobarbaz]</font></font>',
|
||||
'expected': '<font face="courier">[foobarbaz]</font>',
|
||||
'accept': '<font face="verdana"><font face="courier">[foobarbaz]</font></font>' },
|
||||
|
||||
{ 'id': 'FN:c_SPANs:ff:v-FONTf:a-1_SW',
|
||||
'rte1-id': 'c-fontname-4',
|
||||
'desc': 'Change existing font name in nested mixed tags to new font name (without CSS)',
|
||||
'value': 'courier',
|
||||
'pad': '<span style="font-family: verdana"><font face="arial">[foobarbaz]</font></span>',
|
||||
'expected': '<font face="courier">[foobarbaz]</font>',
|
||||
'accept': '<span style="font-family: verdana"><font face="courier">[foobarbaz]</font></span>' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[MIDAS] fontsize',
|
||||
'command': 'fontsize',
|
||||
'tests': [
|
||||
{ 'id': 'FS:1_FONTsz:4-1_SW',
|
||||
'rte1-id': 'c-fontsize-0',
|
||||
'desc': 'Change existing font size to new size (without CSS)',
|
||||
'value': '1',
|
||||
'pad': '<font size="4">[foobarbaz]</font>',
|
||||
'expected': '<font size="1">[foobarbaz]</font>' },
|
||||
|
||||
{ 'id': 'FS:1_SPAN.ass.s:fs:large-1_SW',
|
||||
'rte1-id': 'c-fontsize-1',
|
||||
'desc': 'Change existing font size from styled span to new size (without CSS)',
|
||||
'value': '1',
|
||||
'pad': '<span class="Apple-style-span" style="font-size: large">[foobarbaz]</span>',
|
||||
'expected': '<font size="1">[foobarbaz]</font>' },
|
||||
|
||||
{ 'id': 'FS:5_FONTsz:1.s:fs:xs-1_SW',
|
||||
'rte1-id': 'c-fontsize-2',
|
||||
'desc': 'Change existing font size from tag with conflicting size and style to new size (without CSS)',
|
||||
'value': '5',
|
||||
'pad': '<font size="1" style="font-size:x-small">[foobarbaz]</font>',
|
||||
'expected': '<font size="5">[foobarbaz]</font>' },
|
||||
|
||||
{ 'id': 'FS:2_FONTc:b.sz:6-1_SI',
|
||||
'desc': 'Change the font size in content with a different font size and font color',
|
||||
'value': '2',
|
||||
'pad': '<font color="blue" size="6">foo[bar]baz</font>',
|
||||
'expected': [ '<font color="blue" size="6">foo<font size="2">[bar]</font>baz</font>',
|
||||
'<font color="blue"><font size="6">foo</font><font size="2">[bar]</font><font size="6">baz</font></font>' ] },
|
||||
|
||||
{ 'id': 'FS:larger_FONTsz:4',
|
||||
'desc': 'Change selection to use next larger font',
|
||||
'value': 'larger',
|
||||
'pad': '<font size="4">foo[bar]baz</font>',
|
||||
'expected': '<font size="4">foo<font size="larger">[bar]</font>baz</font>',
|
||||
'accept': '<font size="4">foo</font><font size="5">[bar]</font><font size="4">baz</font>' },
|
||||
|
||||
{ 'id': 'FS:smaller_FONTsz:4',
|
||||
'desc': 'Change selection to use next smaller font',
|
||||
'value': 'smaller',
|
||||
'pad': '<font size="4">foo[bar]baz</font>',
|
||||
'expected': '<font size="4">foo<font size="smaller">[bar]</font>baz</font>',
|
||||
'accept': '<font size="4">foo</font><font size="3">[bar]</font><font size="4">baz</font>' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[MIDAS] formatblock',
|
||||
'command': 'formatblock',
|
||||
'tests': [
|
||||
{ 'id': 'FB:h1_ADDRESS-1_SW',
|
||||
'desc': 'change block from <address> to <h1>',
|
||||
'value': 'h1',
|
||||
'pad': '<address>foo [bar] baz</address>',
|
||||
'expected': '<h1>foo [bar] baz</h1>' },
|
||||
|
||||
{ 'id': 'FB:h1_ADDRESS-FONTsz:4-1_SO',
|
||||
'desc': 'change block from <address> with partially formatted content to <h1>',
|
||||
'value': 'h1',
|
||||
'pad': '<address>foo [<font size="4">bar</font>] baz</address>',
|
||||
'expected': '<h1>foo [bar] baz</h1>' },
|
||||
|
||||
{ 'id': 'FB:h1_ADDRESS-FONTsz:4-1_SW',
|
||||
'desc': 'change block from <address> with partially formatted content to <h1>',
|
||||
'value': 'h1',
|
||||
'pad': '<address>foo <font size="4">[bar]</font> baz</address>',
|
||||
'expected': '<h1>foo [bar] baz</h1>' },
|
||||
|
||||
{ 'id': 'FB:h1_ADDRESS-FONT.ass.sz:4-1_SW',
|
||||
'desc': 'change block from <address> with partially formatted content to <h1>',
|
||||
'value': 'h1',
|
||||
'pad': '<address>foo <font class="Apple-style-span" size="4">[bar]</font> baz</address>',
|
||||
'expected': '<h1>foo [bar] baz</h1>' }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -0,0 +1,210 @@
|
||||
|
||||
CHANGE_TESTS_CSS = {
|
||||
'id': 'CC',
|
||||
'caption': 'Change Existing Format to Different Format Tests, using styleWithCSS',
|
||||
'checkAttrs': True,
|
||||
'checkStyle': True,
|
||||
'styleWithCSS': True,
|
||||
|
||||
'Proposed': [
|
||||
{ 'desc': '',
|
||||
'command': '',
|
||||
'tests': [
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[HTML5] italic',
|
||||
'command': 'italic',
|
||||
'tests': [
|
||||
{ 'id': 'I_I-1_SL',
|
||||
'desc': 'Italicize partially italicized text',
|
||||
'pad': 'foo[bar<i>baz]</i>qoz',
|
||||
'expected': 'foo<span style="font-style: italic">[barbaz]</span>qoz' },
|
||||
|
||||
{ 'id': 'I_B-1_SL',
|
||||
'desc': 'Italicize partially bolded text',
|
||||
'pad': 'foo[bar<b>baz]</b>qoz',
|
||||
'expected': 'foo<span style="font-style: italic">[bar<b>baz]</b></span>qoz',
|
||||
'accept': 'foo<span style="font-style: italic">[bar<b>baz</b>}</span>qoz' },
|
||||
|
||||
{ 'id': 'I_B-1_SW',
|
||||
'desc': 'Italicize bold text, ideally combining both',
|
||||
'pad': 'foobar<b>[baz]</b>qoz',
|
||||
'expected': 'foobar<span style="font-style: italic; font-weight: bold">[baz]</span>qoz',
|
||||
'accept': 'foobar<b><span style="font-style: italic">[baz]</span></b>qoz' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[MIDAS] backcolor',
|
||||
'command': 'backcolor',
|
||||
'tests': [
|
||||
{ 'id': 'BC:gray_SPANs:bc:b-1_SW',
|
||||
'desc': 'Change background color from blue to gray',
|
||||
'value': 'gray',
|
||||
'pad': '<span style="background-color: blue">[foobarbaz]</span>',
|
||||
'expected': '<span style="background-color: gray">[foobarbaz]</span>' },
|
||||
|
||||
{ 'id': 'BC:gray_SPANs:bc:b-1_SO',
|
||||
'desc': 'Change background color from blue to gray',
|
||||
'value': 'gray',
|
||||
'pad': '{<span style="background-color: blue">foobarbaz</span>}',
|
||||
'expected': [ '{<span style="background-color: gray">foobarbaz</span>}',
|
||||
'<span style="background-color: gray">[foobarbaz]</span>' ] },
|
||||
|
||||
{ 'id': 'BC:gray_SPANs:bc:b-1_SI',
|
||||
'desc': 'Change background color from blue to gray',
|
||||
'value': 'gray',
|
||||
'pad': '<span style="background-color: blue">foo[bar]baz</span>',
|
||||
'expected': '<span style="background-color: blue">foo</span><span style="background-color: gray">[bar]</span><span style="background-color: blue">baz</span>',
|
||||
'accept': '<span style="background-color: blue">foo<span style="background-color: gray">[bar]</span>baz</span>' },
|
||||
|
||||
{ 'id': 'BC:gray_P-SPANs:bc:b-1_SW',
|
||||
'desc': 'Change background color within a paragraph from blue to gray',
|
||||
'value': 'gray',
|
||||
'pad': '<p><span style="background-color: blue">[foobarbaz]</span></p>',
|
||||
'expected': [ '<p><span style="background-color: gray">[foobarbaz]</span></p>',
|
||||
'<p style="background-color: gray">[foobarbaz]</p>' ] },
|
||||
|
||||
{ 'id': 'BC:gray_P-SPANs:bc:b-2_SW',
|
||||
'desc': 'Change background color within a paragraph from blue to gray',
|
||||
'value': 'gray',
|
||||
'pad': '<p>foo<span style="background-color: blue">[bar]</span>baz</p>',
|
||||
'expected': '<p>foo<span style="background-color: gray">[bar]</span>baz</p>' },
|
||||
|
||||
{ 'id': 'BC:gray_P-SPANs:bc:b-3_SO',
|
||||
'desc': 'Change background color within a paragraph from blue to gray (selection encloses more than previous span)',
|
||||
'value': 'gray',
|
||||
'pad': '<p>[foo<span style="background-color: blue">barbaz</span>qoz]quz</p>',
|
||||
'expected': '<p><span style="background-color: gray">[foobarbazqoz]</span>quz</p>' },
|
||||
|
||||
{ 'id': 'BC:gray_P-SPANs:bc:b-3_SL',
|
||||
'desc': 'Change background color within a paragraph from blue to gray (previous span partially selected)',
|
||||
'value': 'gray',
|
||||
'pad': '<p>[foo<span style="background-color: blue">bar]baz</span>qozquz</p>',
|
||||
'expected': '<p><span style="background-color: gray">[foobar]</span><span style="background-color: blue">baz</span>qozquz</p>' },
|
||||
|
||||
{ 'id': 'BC:gray_SPANs:bc:b-2_SL',
|
||||
'desc': 'Change background color from blue to gray on partially covered span, selection extends left',
|
||||
'value': 'gray',
|
||||
'pad': 'foo [bar <span style="background-color: blue">baz] qoz</span> quz sic',
|
||||
'expected': 'foo <span style="background-color: gray">[bar baz]</span><span style="background-color: blue"> qoz</span> quz sic' },
|
||||
|
||||
{ 'id': 'BC:gray_SPANs:bc:b-2_SR',
|
||||
'desc': 'Change background color from blue to gray on partially covered span, selection extends right',
|
||||
'value': 'gray',
|
||||
'pad': 'foo bar <span style="background-color: blue">baz [qoz</span> quz] sic',
|
||||
'expected': 'foo bar <span style="background-color: blue">baz </span><span style="background-color: gray">[qoz quz]</span> sic' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[MIDAS] fontname',
|
||||
'command': 'fontname',
|
||||
'tests': [
|
||||
{ 'id': 'FN:c_SPANs:ff:a-1_SW',
|
||||
'desc': 'Change existing font name to new font name, using CSS styling',
|
||||
'value': 'courier',
|
||||
'pad': '<span style="font-family: arial">[foobarbaz]</span>',
|
||||
'expected': '<span style="font-family: courier">[foobarbaz]</span>' },
|
||||
|
||||
{ 'id': 'FN:c_FONTf:a-1_SW',
|
||||
'desc': 'Change existing font name to new font name, using CSS styling',
|
||||
'value': 'courier',
|
||||
'pad': '<font face="arial">[foobarbaz]</font>',
|
||||
'expected': [ '<font style="font-family: courier">[foobarbaz]</font>',
|
||||
'<span style="font-family: courier">[foobarbaz]</span>' ] },
|
||||
|
||||
{ 'id': 'FN:c_FONTf:a-1_SI',
|
||||
'desc': 'Change existing font name to new font name, using CSS styling',
|
||||
'value': 'courier',
|
||||
'pad': '<font face="arial">foo[bar]baz</font>',
|
||||
'expected': '<font face="arial">foo</font><span style="font-family: courier">[bar]</span><font face="arial">baz</font>' },
|
||||
|
||||
{ 'id': 'FN:a_FONTf:a-1_SI',
|
||||
'desc': 'Change existing font name to same font name, using CSS styling (should be noop)',
|
||||
'value': 'arial',
|
||||
'pad': '<font face="arial">foo[bar]baz</font>',
|
||||
'expected': '<font face="arial">foo[bar]baz</font>' },
|
||||
|
||||
{ 'id': 'FN:a_FONTf:a-1_SW',
|
||||
'desc': 'Change existing font name to same font name, using CSS styling (should be noop or perhaps change tag)',
|
||||
'value': 'arial',
|
||||
'pad': '<font face="arial">[foobarbaz]</font>',
|
||||
'expected': [ '<font face="arial">[foobarbaz]</font>',
|
||||
'<span style="font-family: arial">[foobarbaz]</span>' ] },
|
||||
|
||||
{ 'id': 'FN:a_FONTf:a-1_SO',
|
||||
'desc': 'Change existing font name to same font name, using CSS styling (should be noop or perhaps change tag)',
|
||||
'value': 'arial',
|
||||
'pad': '{<font face="arial">foobarbaz</font>}',
|
||||
'expected': [ '{<font face="arial">foobarbaz</font>}',
|
||||
'<font face="arial">[foobarbaz]</font>',
|
||||
'{<span style="font-family: arial">foobarbaz</span>}',
|
||||
'<span style="font-family: arial">[foobarbaz]</span>' ] },
|
||||
|
||||
{ 'id': 'FN:a_SPANs:ff:a-1_SI',
|
||||
'desc': 'Change existing font name to same font name, using CSS styling (should be noop)',
|
||||
'value': 'arial',
|
||||
'pad': '<span style="font-family: arial">[foobarbaz]</span>',
|
||||
'expected': '<span style="font-family: arial">[foobarbaz]</span>' },
|
||||
|
||||
{ 'id': 'FN:c_FONTf:a-2_SL',
|
||||
'desc': 'Change existing font name to new font name, using CSS styling',
|
||||
'value': 'courier',
|
||||
'pad': 'foo[bar<font face="arial">baz]qoz</font>',
|
||||
'expected': 'foo<span style="font-family: courier">[barbaz]</span><font face="arial">qoz</font>' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[MIDAS] fontsize',
|
||||
'command': 'fontsize',
|
||||
'tests': [
|
||||
{ 'id': 'FS:1_SPANs:fs:l-1_SW',
|
||||
'desc': 'Change existing font size to new size, using CSS styling',
|
||||
'value': '1',
|
||||
'pad': '<span style="font-size: large">[foobarbaz]</span>',
|
||||
'expected': '<span style="font-size: x-small">[foobarbaz]</span>' },
|
||||
|
||||
{ 'id': 'FS:large_SPANs:fs:l-1_SW',
|
||||
'desc': 'Change existing font size to same size (should be noop)',
|
||||
'value': 'large',
|
||||
'pad': '<span style="font-size: large">[foobarbaz]</span>',
|
||||
'expected': '<span style="font-size: large">[foobarbaz]</span>' },
|
||||
|
||||
{ 'id': 'FS:18px_SPANs:fs:l-1_SW',
|
||||
'desc': 'Change existing font size to equivalent px size (should be noop, or change unit)',
|
||||
'value': '18px',
|
||||
'pad': '<span style="font-size: large">[foobarbaz]</span>',
|
||||
'expected': [ '<span style="font-size: 18px">[foobarbaz]</span>',
|
||||
'<span style="font-size: large">[foobarbaz]</span>' ] },
|
||||
|
||||
{ 'id': 'FS:4_SPANs:fs:l-1_SW',
|
||||
'desc': 'Change existing font size to equivalent numeric size (should be noop)',
|
||||
'value': '4',
|
||||
'pad': '<span style="font-size: large">[foobarbaz]</span>',
|
||||
'expected': '<span style="font-size: large">[foobarbaz]</span>' },
|
||||
|
||||
{ 'id': 'FS:4_SPANs:fs:18px-1_SW',
|
||||
'desc': 'Change existing font size to equivalent numeric size (should be noop)',
|
||||
'value': '4',
|
||||
'pad': '<span style="font-size: 18px">[foobarbaz]</span>',
|
||||
'expected': '<span style="font-size: 18px">[foobarbaz]</span>' },
|
||||
|
||||
{ 'id': 'FS:larger_SPANs:fs:l-1_SI',
|
||||
'desc': 'Change selection to use next larger font',
|
||||
'value': 'larger',
|
||||
'pad': '<span style="font-size: large">foo[bar]baz</span>',
|
||||
'expected': [ '<span style="font-size: large">foo<span style="font-size: x-large">[bar]</span>baz</span>',
|
||||
'<span style="font-size: large">foo</span><span style="font-size: x-large">[bar]</span><span style="font-size: large">baz</span>' ],
|
||||
'accept': '<span style="font-size: large">foo<font size="larger">[bar]</font>baz</span>' },
|
||||
|
||||
{ 'id': 'FS:smaller_SPANs:fs:l-1_SI',
|
||||
'desc': 'Change selection to use next smaller font',
|
||||
'value': 'smaller',
|
||||
'pad': '<span style="font-size: large">foo[bar]baz</span>',
|
||||
'expected': [ '<span style="font-size: large">foo<span style="font-size: medium">[bar]</span>baz</span>',
|
||||
'<span style="font-size: large">foo</span><span style="font-size: medium">[bar]</span><span style="font-size: large">baz</span>' ],
|
||||
'accept': '<span style="font-size: large">foo<font size="smaller">[bar]</font>baz</span>' }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
330
editor/libeditor/html/tests/browserscope/lib/richtext2/richtext2/tests/delete.py
Executable file
330
editor/libeditor/html/tests/browserscope/lib/richtext2/richtext2/tests/delete.py
Executable file
@ -0,0 +1,330 @@
|
||||
|
||||
DELETE_TESTS = {
|
||||
'id': 'D',
|
||||
'caption': 'Delete Tests',
|
||||
'command': 'delete',
|
||||
'checkAttrs': True,
|
||||
'checkStyle': False,
|
||||
|
||||
'Proposed': [
|
||||
{ 'desc': '',
|
||||
'tests': [
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'delete single characters',
|
||||
'tests': [
|
||||
{ 'id': 'CHAR-1_SC',
|
||||
'desc': 'Delete 1 character',
|
||||
'pad': 'foo^barbaz',
|
||||
'expected': 'fo^barbaz' },
|
||||
|
||||
{ 'id': 'CHAR-2_SC',
|
||||
'desc': 'Delete 1 pre-composed character o with diaeresis',
|
||||
'pad': 'foö^barbaz',
|
||||
'expected': 'fo^barbaz' },
|
||||
|
||||
{ 'id': 'CHAR-3_SC',
|
||||
'desc': 'Delete 1 character with combining diaeresis above',
|
||||
'pad': 'foö^barbaz',
|
||||
'expected': 'fo^barbaz' },
|
||||
|
||||
{ 'id': 'CHAR-4_SC',
|
||||
'desc': 'Delete 1 character with combining diaeresis below',
|
||||
'pad': 'foo̤^barbaz',
|
||||
'expected': 'fo^barbaz' },
|
||||
|
||||
{ 'id': 'CHAR-5_SC',
|
||||
'desc': 'Delete 1 character with combining diaeresis above and below',
|
||||
'pad': 'foö̤^barbaz',
|
||||
'expected': 'fo^barbaz' },
|
||||
|
||||
{ 'id': 'CHAR-5_SI-1',
|
||||
'desc': 'Delete 1 character with combining diaeresis above and below, selection on diaeresis above',
|
||||
'pad': 'foo[̈]̤barbaz',
|
||||
'expected': 'fo^barbaz' },
|
||||
|
||||
{ 'id': 'CHAR-5_SI-2',
|
||||
'desc': 'Delete 1 character with combining diaeresis above and below, selection on diaeresis below',
|
||||
'pad': 'foö[̤]barbaz',
|
||||
'expected': 'fo^barbaz' },
|
||||
|
||||
{ 'id': 'CHAR-5_SR',
|
||||
'desc': 'Delete 1 character with combining diaeresis above and below, selection oblique on diaeresis and following text',
|
||||
'pad': 'foö[̤bar]baz',
|
||||
'expected': 'fo^baz' },
|
||||
|
||||
{ 'id': 'CHAR-6_SC',
|
||||
'desc': 'Delete 1 character with enclosing square',
|
||||
'pad': 'foo⃞^barbaz',
|
||||
'expected': 'fo^barbaz' },
|
||||
|
||||
{ 'id': 'CHAR-7_SC',
|
||||
'desc': 'Delete 1 character with combining long solidus overlay',
|
||||
'pad': 'foo̸^barbaz',
|
||||
'expected': 'fo^barbaz' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'delete text selection',
|
||||
'tests': [
|
||||
{ 'id': 'TEXT-1_SI',
|
||||
'desc': 'Delete text selection',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': 'foo^baz' },
|
||||
|
||||
{ 'id': 'B-1_SS',
|
||||
'desc': 'Delete at start of span',
|
||||
'pad': 'foo<b>^bar</b>baz',
|
||||
'expected': 'fo^<b>bar</b>baz' },
|
||||
|
||||
{ 'id': 'B-1_SA',
|
||||
'desc': 'Delete from position after span',
|
||||
'pad': 'foo<b>bar</b>^baz',
|
||||
'expected': 'foo<b>ba^</b>baz' },
|
||||
|
||||
{ 'id': 'B-1_SW',
|
||||
'desc': 'Delete selection that wraps the whole span content',
|
||||
'pad': 'foo<b>[bar]</b>baz',
|
||||
'expected': 'foo^baz' },
|
||||
|
||||
{ 'id': 'B-1_SO',
|
||||
'desc': 'Delete selection that wraps the whole span',
|
||||
'pad': 'foo[<b>bar</b>]baz',
|
||||
'expected': 'foo^baz' },
|
||||
|
||||
{ 'id': 'B-1_SL',
|
||||
'desc': 'Delete oblique selection that starts before span',
|
||||
'pad': 'foo[bar<b>baz]quoz</b>quuz',
|
||||
'expected': 'foo^<b>quoz</b>quuz' },
|
||||
|
||||
{ 'id': 'B-1_SR',
|
||||
'desc': 'Delete oblique selection that ends after span',
|
||||
'pad': 'foo<b>bar[baz</b>quoz]quuz',
|
||||
'expected': 'foo<b>bar^</b>quuz' },
|
||||
|
||||
{ 'id': 'B.I-1_SM',
|
||||
'desc': 'Delete oblique selection that starts and ends in different spans',
|
||||
'pad': 'foo<b>bar[baz</b><i>qoz]quuz</i>quuuz',
|
||||
'expected': 'foo<b>bar^</b><i>quuz</i>quuuz' },
|
||||
|
||||
{ 'id': 'GEN-1_SS',
|
||||
'desc': 'Delete at start of span with generated content',
|
||||
'pad': 'foo<gen>^bar</gen>baz',
|
||||
'expected': 'fo^<gen>bar</gen>baz' },
|
||||
|
||||
{ 'id': 'GEN-1_SA',
|
||||
'desc': 'Delete from position after span with generated content',
|
||||
'pad': 'foo<gen>bar</gen>^baz',
|
||||
'expected': 'foo<gen>ba^</gen>baz' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'delete paragraphs',
|
||||
'tests': [
|
||||
{ 'id': 'P2-1_SS2',
|
||||
'desc': 'Delete from collapsed selection at start of paragraph - should merge with previous',
|
||||
'pad': '<p>foobar</p><p>^bazqoz</p>',
|
||||
'expected': '<p>foobar^bazqoz</p>' },
|
||||
|
||||
{ 'id': 'P2-1_SI2',
|
||||
'desc': 'Delete non-collapsed selection at start of paragraph - should not merge with previous',
|
||||
'pad': '<p>foobar</p><p>[baz]qoz</p>',
|
||||
'expected': '<p>foobar</p><p>^qoz</p>' },
|
||||
|
||||
{ 'id': 'P2-1_SM',
|
||||
'desc': 'Delete non-collapsed selection spanning 2 paragraphs - should merge them',
|
||||
'pad': '<p>foo[bar</p><p>baz]qoz</p>',
|
||||
'expected': '<p>foo^qoz</p>' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'delete lists and list items',
|
||||
'tests': [
|
||||
{ 'id': 'OL-LI2-1_SO1',
|
||||
'desc': 'Delete fully wrapped list item',
|
||||
'pad': 'foo<ol>{<li>bar</li>}<li>baz</li></ol>qoz',
|
||||
'expected': ['foo<ol>|<li>baz</li></ol>qoz',
|
||||
'foo<ol><li>^baz</li></ol>qoz'] },
|
||||
|
||||
{ 'id': 'OL-LI2-1_SM',
|
||||
'desc': 'Delete oblique range between list items within same list',
|
||||
'pad': 'foo<ol><li>ba[r</li><li>b]az</li></ol>qoz',
|
||||
'expected': 'foo<ol><li>ba^az</li></ol>qoz' },
|
||||
|
||||
{ 'id': 'OL-LI-1_SW',
|
||||
'desc': 'Delete contents of last list item (list should remain)',
|
||||
'pad': 'foo<ol><li>[foo]</li></ol>qoz',
|
||||
'expected': ['foo<ol><li>|</li></ol>qoz',
|
||||
'foo<ol><li>^</li></ol>qoz'] },
|
||||
|
||||
{ 'id': 'OL-LI-1_SO',
|
||||
'desc': 'Delete last list item of list (should remove entire list)',
|
||||
'pad': 'foo<ol>{<li>foo</li>}</ol>qoz',
|
||||
'expected': 'foo^qoz' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'delete with strange selections',
|
||||
'tests': [
|
||||
{ 'id': 'HR.BR-1_SM',
|
||||
'desc': 'Delete selection that starts and ends within nodes that don\'t have children',
|
||||
'pad': 'foo<hr {>bar<br }>baz',
|
||||
'expected': 'foo<hr>|<br>baz' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'delete after table',
|
||||
'tests': [
|
||||
{ 'id': 'TABLE-1_SA',
|
||||
'desc': 'Delete from position immediately after table (should have no effect)',
|
||||
'pad': 'foo<table><tbody><tr><td>bar</td></tr></tbody></table>^baz',
|
||||
'expected': 'foo<table><tbody><tr><td>bar</td></tr></tbody></table>^baz' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'delete within table cells',
|
||||
'tests': [
|
||||
{ 'id': 'TD-1_SS',
|
||||
'desc': 'Delete from start of first cell (should have no effect)',
|
||||
'pad': 'foo<table><tbody><tr><td>^bar</td></tr></tbody></table>baz',
|
||||
'expected': 'foo<table><tbody><tr><td>^bar</td></tr></tbody></table>baz' },
|
||||
|
||||
{ 'id': 'TD2-1_SS2',
|
||||
'desc': 'Delete from start of inner cell (should have no effect)',
|
||||
'pad': 'foo<table><tbody><tr><td>bar</td><td>^baz</td></tr></tbody></table>quoz',
|
||||
'expected': 'foo<table><tbody><tr><td>bar</td><td>^baz</td></tr></tbody></table>quoz' },
|
||||
|
||||
{ 'id': 'TD2-1_SM',
|
||||
'desc': 'Delete with selection spanning 2 cells',
|
||||
'pad': 'foo<table><tbody><tr><td>ba[r</td><td>b]az</td></tr></tbody></table>quoz',
|
||||
'expected': 'foo<table><tbody><tr><td>ba^</td><td>az</td></tr></tbody></table>quoz' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'delete table rows',
|
||||
'tests': [
|
||||
{ 'id': 'TR3-1_SO1',
|
||||
'desc': 'Delete first table row',
|
||||
'pad': '<table><tbody>{<tr><td>A</td></tr>}<tr><td>B</td></tr><tr><td>C</td></tr></tbody></table>',
|
||||
'expected': ['<table><tbody>|<tr><td>B</td></tr><tr><td>C</td></tr></tbody></table>',
|
||||
'<table><tbody><tr><td>^B</td></tr><tr><td>C</td></tr></tbody></table>'] },
|
||||
|
||||
{ 'id': 'TR3-1_SO2',
|
||||
'desc': 'Delete middle table row',
|
||||
'pad': '<table><tbody><tr><td>A</td></tr>{<tr><td>B</td></tr>}<tr><td>C</td></tr></tbody></table>',
|
||||
'expected': ['<table><tbody><tr><td>A</td></tr>|<tr><td>C</td></tr></tbody></table>',
|
||||
'<table><tbody><tr><td>A</td></tr><tr><td>^C</td></tr></tbody></table>'] },
|
||||
|
||||
{ 'id': 'TR3-1_SO3',
|
||||
'desc': 'Delete last table row',
|
||||
'pad': '<table><tbody><tr><td>A</td></tr><tr><td>B</td></tr>{<tr><td>C</td></tr>}</tbody></table>',
|
||||
'expected': ['<table><tbody><tr><td>A</td></tr><tr><td>B</td></tr>|</tbody></table>',
|
||||
'<table><tbody><tr><td>A</td></tr><tr><td>B^</td></tr></tbody></table>'] },
|
||||
|
||||
{ 'id': 'TR2rs:2-1_SO1',
|
||||
'desc': 'Delete first table row where a cell has rowspan 2',
|
||||
'pad': '<table><tbody>{<tr><td>A</td><td rowspan=2>R</td></tr>}<tr><td>B</td></tr></tbody></table>',
|
||||
'expected': ['<table><tbody>|<tr><td>B</td><td>R</td></tr></tbody></table>',
|
||||
'<table><tbody><tr><td>^B</td><td>R</td></tr></tbody></table>'] },
|
||||
|
||||
{ 'id': 'TR2rs:2-1_SO2',
|
||||
'desc': 'Delete second table row where a cell has rowspan 2',
|
||||
'pad': '<table><tbody><tr><td>A</td><td rowspan=2>R</td></tr>{<tr><td>B</td></tr>}</tbody></table>',
|
||||
'expected': ['<table><tbody><tr><td>A</td><td>R</td></tr>|</tbody></table>',
|
||||
'<table><tbody><tr><td>A</td><td>R^</td></tr></tbody></table>'] },
|
||||
|
||||
{ 'id': 'TR3rs:3-1_SO1',
|
||||
'desc': 'Delete first table row where a cell has rowspan 3',
|
||||
'pad': '<table><tbody>{<tr><td>A</td><td rowspan=3>R</td></tr>}<tr><td>B</td></tr><tr><td>C</td></tr></tbody></table>',
|
||||
'expected': ['<table><tbody>|<tr><td>A</td><td rowspan="2">R</td></tr><tr><td>C</td></tr></tbody></table>',
|
||||
'<table><tbody><tr><td>^A</td><td rowspan="2">R</td></tr><tr><td>C</td></tr></tbody></table>'] },
|
||||
|
||||
{ 'id': 'TR3rs:3-1_SO2',
|
||||
'desc': 'Delete middle table row where a cell has rowspan 3',
|
||||
'pad': '<table><tbody><tr><td>A</td><td rowspan=3>R</td></tr>{<tr><td>B</td></tr>}<tr><td>C</td></tr></tbody></table>',
|
||||
'expected': ['<table><tbody><tr><td>B</td><td rowspan="2">R</td></tr>|<tr><td>C</td></tr></tbody></table>',
|
||||
'<table><tbody><tr><td>B</td><td rowspan="2">R</td></tr><tr><td>^C</td></tr></tbody></table>'] },
|
||||
|
||||
{ 'id': 'TR3rs:3-1_SO3',
|
||||
'desc': 'Delete last table row where a cell has rowspan 3',
|
||||
'pad': '<table><tbody><tr><td>A</td><td rowspan=3>R</td></tr><tr><td>B</td></tr>{<tr><td>C</td></tr>}</tbody></table>',
|
||||
'expected': ['<table><tbody><tr><td>A</td><td rowspan="2">R</td></tr><tr><td>B</td></tr>|</tbody></table>',
|
||||
'<table><tbody><tr><td>A</td><td rowspan="2">R</td></tr><tr><td>B^</td></tr></tbody></table>'] }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'delete with non-editable nested content',
|
||||
'tests': [
|
||||
{ 'id': 'DIV:ce:false-1_SO',
|
||||
'desc': 'Delete nested non-editable <div>',
|
||||
'pad': 'foo[bar<div contenteditable="false">NESTED</div>baz]qoz',
|
||||
'expected': 'foo^qoz' },
|
||||
|
||||
{ 'id': 'DIV:ce:false-1_SB',
|
||||
'desc': 'Delete from immediately after a nested non-editable <div> (should be no-op)',
|
||||
'pad': 'foobar<div contenteditable="false">NESTED</div>^bazqoz',
|
||||
'expected': 'foobar<div contenteditable="false">NESTED</div>^bazqoz' },
|
||||
|
||||
{ 'id': 'DIV:ce:false-1_SL',
|
||||
'desc': 'Delete nested non-editable <div> with oblique selection',
|
||||
'pad': 'foo[bar<div contenteditable="false">NES]TED</div>bazqoz',
|
||||
'expected': [ 'foo^<div contenteditable="false">NESTED</div>bazqoz',
|
||||
'foo<div contenteditable="false">[NES]TED</div>bazqoz' ] },
|
||||
|
||||
{ 'id': 'DIV:ce:false-1_SR',
|
||||
'desc': 'Delete nested non-editable <div> with oblique selection',
|
||||
'pad': 'foobar<div contenteditable="false">NES[TED</div>baz]qoz',
|
||||
'expected': [ 'foobar<div contenteditable="false">NESTED</div>^qoz',
|
||||
'foobar<div contenteditable="false">NES[TED]</div>qoz' ] },
|
||||
|
||||
{ 'id': 'DIV:ce:false-1_SI',
|
||||
'desc': 'Delete inside nested non-editable <div> (should be no-op)',
|
||||
'pad': 'foobar<div contenteditable="false">NE[ST]ED</div>bazqoz',
|
||||
'expected': 'foobar<div contenteditable="false">NE[ST]ED</div>bazqoz' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'Delete with display:inline-block',
|
||||
'checkStyle': True,
|
||||
'tests': [
|
||||
{ 'id': 'SPAN:d:ib-1_SC',
|
||||
'desc': 'Delete inside an inline-block <span>',
|
||||
'pad': 'foo<span style="display: inline-block">bar^baz</span>qoz',
|
||||
'expected': 'foo<span style="display: inline-block">ba^baz</span>qoz' },
|
||||
|
||||
{ 'id': 'SPAN:d:ib-1_SA',
|
||||
'desc': 'Delete from immediately after an inline-block <span>',
|
||||
'pad': 'foo<span style="display: inline-block">barbaz</span>^qoz',
|
||||
'expected': 'foo<span style="display: inline-block">barba^</span>qoz' },
|
||||
|
||||
{ 'id': 'SPAN:d:ib-2_SL',
|
||||
'desc': 'Delete with nested inline-block <span>, oblique selection',
|
||||
'pad': 'foo[DEL<span style="display: inline-block">ETE]bar</span>baz',
|
||||
'expected': 'foo^<span style="display: inline-block">bar</span>baz' },
|
||||
|
||||
{ 'id': 'SPAN:d:ib-3_SR',
|
||||
'desc': 'Delete with nested inline-block <span>, oblique selection',
|
||||
'pad': 'foo<span style="display: inline-block">bar[DEL</span>ETE]baz',
|
||||
'expected': 'foo<span style="display: inline-block">bar^</span>baz' },
|
||||
|
||||
{ 'id': 'SPAN:d:ib-4i_SI',
|
||||
'desc': 'Delete with nested inline-block <span>, oblique selection',
|
||||
'pad': 'foo<span style="display: inline-block">bar[DELETE]baz</span>qoz',
|
||||
'expected': 'foo<span style="display: inline-block">bar^baz</span>qoz' },
|
||||
|
||||
{ 'id': 'SPAN:d:ib-4l_SI',
|
||||
'desc': 'Delete with nested inline-block <span>, oblique selection',
|
||||
'pad': 'foo<span style="display: inline-block">[DELETE]barbaz</span>qoz',
|
||||
'expected': 'foo<span style="display: inline-block">^barbaz</span>qoz' },
|
||||
|
||||
{ 'id': 'SPAN:d:ib-4r_SI',
|
||||
'desc': 'Delete with nested inline-block <span>, oblique selection',
|
||||
'pad': 'foo<span style="display: inline-block">barbaz[DELETE]</span>qoz',
|
||||
'expected': 'foo<span style="display: inline-block">barbaz^</span>qoz' }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,315 @@
|
||||
|
||||
FORWARDDELETE_TESTS = {
|
||||
'id': 'FD',
|
||||
'caption': 'Forward-Delete Tests',
|
||||
'command': 'forwardDelete',
|
||||
'checkAttrs': True,
|
||||
'checkStyle': False,
|
||||
|
||||
'Proposed': [
|
||||
{ 'desc': '',
|
||||
'tests': [
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'forward-delete single characters',
|
||||
'tests': [
|
||||
{ 'id': 'CHAR-1_SC',
|
||||
'desc': 'Delete 1 character',
|
||||
'pad': 'foo^barbaz',
|
||||
'expected': 'foo^arbaz' },
|
||||
|
||||
{ 'id': 'CHAR-2_SC',
|
||||
'desc': 'Delete 1 pre-composed character o with diaeresis',
|
||||
'pad': 'fo^öbarbaz',
|
||||
'expected': 'fo^barbaz' },
|
||||
|
||||
{ 'id': 'CHAR-3_SC',
|
||||
'desc': 'Delete 1 character with combining diaeresis above',
|
||||
'pad': 'fo^öbarbaz',
|
||||
'expected': 'fo^barbaz' },
|
||||
|
||||
{ 'id': 'CHAR-4_SC',
|
||||
'desc': 'Delete 1 character with combining diaeresis below',
|
||||
'pad': 'fo^o̤barbaz',
|
||||
'expected': 'fo^barbaz' },
|
||||
|
||||
{ 'id': 'CHAR-5_SC',
|
||||
'desc': 'Delete 1 character with combining diaeresis above and below',
|
||||
'pad': 'fo^ö̤barbaz',
|
||||
'expected': 'fo^barbaz' },
|
||||
|
||||
{ 'id': 'CHAR-6_SC',
|
||||
'desc': 'Delete 1 character with enclosing square',
|
||||
'pad': 'fo^o⃞barbaz',
|
||||
'expected': 'fo^barbaz' },
|
||||
|
||||
{ 'id': 'CHAR-7_SC',
|
||||
'desc': 'Delete 1 character with combining long solidus overlay',
|
||||
'pad': 'fo^o̸barbaz',
|
||||
'expected': 'fo^barbaz' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'forward-delete text selections',
|
||||
'tests': [
|
||||
{ 'id': 'TEXT-1_SI',
|
||||
'desc': 'Delete text selection',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': 'foo^baz' },
|
||||
|
||||
{ 'id': 'B-1_SE',
|
||||
'desc': 'Forward-delete at end of span',
|
||||
'pad': 'foo<b>bar^</b>baz',
|
||||
'expected': 'foo<b>bar^</b>az' },
|
||||
|
||||
{ 'id': 'B-1_SB',
|
||||
'desc': 'Forward-delete from position before span',
|
||||
'pad': 'foo^<b>bar</b>baz',
|
||||
'expected': 'foo^<b>ar</b>baz' },
|
||||
|
||||
{ 'id': 'B-1_SW',
|
||||
'desc': 'Delete selection that wraps the whole span content',
|
||||
'pad': 'foo<b>[bar]</b>baz',
|
||||
'expected': 'foo^baz' },
|
||||
|
||||
{ 'id': 'B-1_SO',
|
||||
'desc': 'Delete selection that wraps the whole span',
|
||||
'pad': 'foo[<b>bar</b>]baz',
|
||||
'expected': 'foo^baz' },
|
||||
|
||||
{ 'id': 'B-1_SL',
|
||||
'desc': 'Delete oblique selection that starts before span',
|
||||
'pad': 'foo[bar<b>baz]quoz</b>quuz',
|
||||
'expected': 'foo^<b>quoz</b>quuz' },
|
||||
|
||||
{ 'id': 'B-1_SR',
|
||||
'desc': 'Delete oblique selection that ends after span',
|
||||
'pad': 'foo<b>bar[baz</b>quoz]quuz',
|
||||
'expected': 'foo<b>bar^</b>quuz' },
|
||||
|
||||
{ 'id': 'B.I-1_SM',
|
||||
'desc': 'Delete oblique selection that starts and ends in different spans',
|
||||
'pad': 'foo<b>bar[baz</b><i>qoz]quuz</i>quuuz',
|
||||
'expected': 'foo<b>bar^</b><i>quuz</i>quuuz' },
|
||||
|
||||
{ 'id': 'GEN-1_SE',
|
||||
'desc': 'Delete at end of span with generated content',
|
||||
'pad': 'foo<gen>bar^</gen>baz',
|
||||
'expected': 'foo<gen>bar^</gen>az' },
|
||||
|
||||
{ 'id': 'GEN-1_SB',
|
||||
'desc': 'Delete from position before span with generated content',
|
||||
'pad': 'foo^<gen>bar</gen>baz',
|
||||
'expected': 'foo^<gen>ar</gen>baz' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'forward-delete paragraphs',
|
||||
'tests': [
|
||||
{ 'id': 'P2-1_SE1',
|
||||
'desc': 'Delete from collapsed selection at end of paragraph - should merge with next',
|
||||
'pad': '<p>foobar^</p><p>bazqoz</p>',
|
||||
'expected': '<p>foobar^bazqoz</p>' },
|
||||
|
||||
{ 'id': 'P2-1_SI1',
|
||||
'desc': 'Delete non-collapsed selection at end of paragraph - should not merge with next',
|
||||
'pad': '<p>foo[bar]</p><p>bazqoz</p>',
|
||||
'expected': '<p>foo^</p><p>bazqoz</p>' },
|
||||
|
||||
{ 'id': 'P2-1_SM',
|
||||
'desc': 'Delete non-collapsed selection spanning 2 paragraphs - should merge them',
|
||||
'pad': '<p>foo[bar</p><p>baz]qoz</p>',
|
||||
'expected': '<p>foo^qoz</p>' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'forward-delete lists and list items',
|
||||
'tests': [
|
||||
{ 'id': 'OL-LI2-1_SO1',
|
||||
'desc': 'Delete fully wrapped list item',
|
||||
'pad': 'foo<ol>{<li>bar</li>}<li>baz</li></ol>qoz',
|
||||
'expected': ['foo<ol>|<li>baz</li></ol>qoz',
|
||||
'foo<ol><li>^baz</li></ol>qoz'] },
|
||||
|
||||
{ 'id': 'OL-LI2-1_SM',
|
||||
'desc': 'Delete oblique range between list items within same list',
|
||||
'pad': 'foo<ol><li>ba[r</li><li>b]az</li></ol>qoz',
|
||||
'expected': 'foo<ol><li>ba^az</li></ol>qoz' },
|
||||
|
||||
{ 'id': 'OL-LI-1_SW',
|
||||
'desc': 'Delete contents of last list item (list should remain)',
|
||||
'pad': 'foo<ol><li>[foo]</li></ol>qoz',
|
||||
'expected': ['foo<ol><li>|</li></ol>qoz',
|
||||
'foo<ol><li>^</li></ol>qoz'] },
|
||||
|
||||
{ 'id': 'OL-LI-1_SO',
|
||||
'desc': 'Delete last list item of list (should remove entire list)',
|
||||
'pad': 'foo<ol>{<li>foo</li>}</ol>qoz',
|
||||
'expected': 'foo^qoz' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'forward-delete with strange selections',
|
||||
'tests': [
|
||||
{ 'id': 'HR.BR-1_SM',
|
||||
'desc': 'Delete selection that starts and ends within nodes that don\'t have children',
|
||||
'pad': 'foo<hr {>bar<br }>baz',
|
||||
'expected': 'foo<hr>|<br>baz' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'forward-delete from immediately before a table',
|
||||
'tests': [
|
||||
{ 'id': 'TABLE-1_SB',
|
||||
'desc': 'Delete from position immediately before table (should have no effect)',
|
||||
'pad': 'foo^<table><tbody><tr><td>bar</td></tr></tbody></table>baz',
|
||||
'expected': 'foo^<table><tbody><tr><td>bar</td></tr></tbody></table>baz' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'forward-delete within table cells',
|
||||
'tests': [
|
||||
{ 'id': 'TD-1_SE',
|
||||
'desc': 'Delete from end of last cell (should have no effect)',
|
||||
'pad': 'foo<table><tbody><tr><td>bar^</td></tr></tbody></table>baz',
|
||||
'expected': 'foo<table><tbody><tr><td>bar^</td></tr></tbody></table>baz' },
|
||||
|
||||
{ 'id': 'TD2-1_SE1',
|
||||
'desc': 'Delete from end of inner cell (should have no effect)',
|
||||
'pad': 'foo<table><tbody><tr><td>bar^</td><td>baz</td></tr></tbody></table>quoz',
|
||||
'expected': 'foo<table><tbody><tr><td>bar^</td><td>baz</td></tr></tbody></table>quoz' },
|
||||
|
||||
{ 'id': 'TD2-1_SM',
|
||||
'desc': 'Delete with selection spanning 2 cells',
|
||||
'pad': 'foo<table><tbody><tr><td>ba[r</td><td>b]az</td></tr></tbody></table>quoz',
|
||||
'expected': 'foo<table><tbody><tr><td>ba^</td><td>az</td></tr></tbody></table>quoz' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'forward-delete table rows',
|
||||
'tests': [
|
||||
{ 'id': 'TR3-1_SO1',
|
||||
'desc': 'Delete first table row',
|
||||
'pad': '<table><tbody>{<tr><td>A</td></tr>}<tr><td>B</td></tr><tr><td>C</td></tr></tbody></table>',
|
||||
'expected': ['<table><tbody>|<tr><td>B</td></tr><tr><td>C</td></tr></tbody></table>',
|
||||
'<table><tbody><tr><td>^B</td></tr><tr><td>C</td></tr></tbody></table>'] },
|
||||
|
||||
{ 'id': 'TR3-1_SO2',
|
||||
'desc': 'Delete middle table row',
|
||||
'pad': '<table><tbody><tr><td>A</td></tr>{<tr><td>B</td></tr>}<tr><td>C</td></tr></tbody></table>',
|
||||
'expected': ['<table><tbody><tr><td>A</td></tr>|<tr><td>C</td></tr></tbody></table>',
|
||||
'<table><tbody><tr><td>A</td></tr><tr><td>^C</td></tr></tbody></table>'] },
|
||||
|
||||
{ 'id': 'TR3-1_SO3',
|
||||
'desc': 'Delete last table row',
|
||||
'pad': '<table><tbody><tr><td>A</td></tr><tr><td>B</td></tr>{<tr><td>C</td></tr>}</tbody></table>',
|
||||
'expected': ['<table><tbody><tr><td>A</td></tr><tr><td>B</td></tr>|</tbody></table>',
|
||||
'<table><tbody><tr><td>A</td></tr><tr><td>B^</td></tr></tbody></table>'] },
|
||||
|
||||
{ 'id': 'TR2rs:2-1_SO1',
|
||||
'desc': 'Delete first table row where a cell has rowspan 2',
|
||||
'pad': '<table><tbody>{<tr><td>A</td><td rowspan=2>R</td></tr>}<tr><td>B</td></tr></tbody></table>',
|
||||
'expected': ['<table><tbody>|<tr><td>B</td><td>R</td></tr></tbody></table>',
|
||||
'<table><tbody><tr><td>^B</td><td>R</td></tr></tbody></table>'] },
|
||||
|
||||
{ 'id': 'TR2rs:2-1_SO2',
|
||||
'desc': 'Delete second table row where a cell has rowspan 2',
|
||||
'pad': '<table><tbody><tr><td>A</td><td rowspan=2>R</td></tr>{<tr><td>B</td></tr>}</tbody></table>',
|
||||
'expected': ['<table><tbody><tr><td>A</td><td>R</td></tr>|</tbody></table>',
|
||||
'<table><tbody><tr><td>A</td><td>R^</td></tr></tbody></table>'] },
|
||||
|
||||
{ 'id': 'TR3rs:3-1_SO1',
|
||||
'desc': 'Delete first table row where a cell has rowspan 3',
|
||||
'pad': '<table><tbody>{<tr><td>A</td><td rowspan=3>R</td></tr>}<tr><td>B</td></tr><tr><td>C</td></tr></tbody></table>',
|
||||
'expected': ['<table><tbody>|<tr><td>A</td><td rowspan="2">R</td></tr><tr><td>C</td></tr></tbody></table>',
|
||||
'<table><tbody><tr><td>^A</td><td rowspan="2">R</td></tr><tr><td>C</td></tr></tbody></table>'] },
|
||||
|
||||
{ 'id': 'TR3rs:3-1_SO2',
|
||||
'desc': 'Delete middle table row where a cell has rowspan 3',
|
||||
'pad': '<table><tbody><tr><td>A</td><td rowspan=3>R</td></tr>{<tr><td>B</td></tr>}<tr><td>C</td></tr></tbody></table>',
|
||||
'expected': ['<table><tbody><tr><td>B</td><td rowspan="2">R</td></tr>|<tr><td>C</td></tr></tbody></table>',
|
||||
'<table><tbody><tr><td>B</td><td rowspan="2">R</td></tr><tr><td>^C</td></tr></tbody></table>'] },
|
||||
|
||||
{ 'id': 'TR3rs:3-1_SO3',
|
||||
'desc': 'Delete last table row where a cell has rowspan 3',
|
||||
'pad': '<table><tbody><tr><td>A</td><td rowspan=3>R</td></tr><tr><td>B</td></tr>{<tr><td>C</td></tr>}</tbody></table>',
|
||||
'expected': ['<table><tbody><tr><td>A</td><td rowspan="2">R</td></tr><tr><td>B</td></tr>|</tbody></table>',
|
||||
'<table><tbody><tr><td>A</td><td rowspan="2">R</td></tr><tr><td>B^</td></tr></tbody></table>'] }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'delete with non-editable nested content',
|
||||
'tests': [
|
||||
{ 'id': 'DIV:ce:false-1_SO',
|
||||
'desc': 'Delete nested non-editable <div>',
|
||||
'pad': 'foo[bar<div contenteditable="false">NESTED</div>baz]qoz',
|
||||
'expected': 'foo^qoz' },
|
||||
|
||||
{ 'id': 'DIV:ce:false-1_SB',
|
||||
'desc': 'Delete from immediately before a nested non-editable <div> (should be no-op)',
|
||||
'pad': 'foobar^<div contenteditable="false">NESTED</div>bazqoz',
|
||||
'expected': 'foobar^<div contenteditable="false">NESTED</div>bazqoz' },
|
||||
|
||||
{ 'id': 'DIV:ce:false-1_SL',
|
||||
'desc': 'Delete nested non-editable <div> with oblique selection',
|
||||
'pad': 'foo[bar<div contenteditable="false">NES]TED</div>bazqoz',
|
||||
'expected': [ 'foo^<div contenteditable="false">NESTED</div>bazqoz',
|
||||
'foo<div contenteditable="false">[NES]TED</div>bazqoz' ] },
|
||||
|
||||
{ 'id': 'DIV:ce:false-1_SR',
|
||||
'desc': 'Delete nested non-editable <div> with oblique selection',
|
||||
'pad': 'foobar<div contenteditable="false">NES[TED</div>baz]qoz',
|
||||
'expected': [ 'foobar<div contenteditable="false">NESTED</div>^qoz',
|
||||
'foobar<div contenteditable="false">NES[TED]</div>qoz' ] },
|
||||
|
||||
{ 'id': 'DIV:ce:false-1_SI',
|
||||
'desc': 'Delete inside nested non-editable <div> (should be no-op)',
|
||||
'pad': 'foobar<div contenteditable="false">NE[ST]ED</div>bazqoz',
|
||||
'expected': 'foobar<div contenteditable="false">NE[ST]ED</div>bazqoz' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'Delete with display:inline-block',
|
||||
'checkStyle': True,
|
||||
'tests': [
|
||||
{ 'id': 'SPAN:d:ib-1_SC',
|
||||
'desc': 'Delete inside an inline-block <span>',
|
||||
'pad': 'foo<span style="display: inline-block">bar^baz</span>qoz',
|
||||
'expected': 'foo<span style="display: inline-block">bar^az</span>qoz' },
|
||||
|
||||
{ 'id': 'SPAN:d:ib-1_SA',
|
||||
'desc': 'Delete from immediately before an inline-block <span>',
|
||||
'pad': 'foo^<span style="display: inline-block">barbaz</span>qoz',
|
||||
'expected': 'foo^<span style="display: inline-block">arbaz</span>qoz' },
|
||||
|
||||
{ 'id': 'SPAN:d:ib-2_SL',
|
||||
'desc': 'Delete with nested inline-block <span>, oblique selection',
|
||||
'pad': 'foo[DEL<span style="display: inline-block">ETE]bar</span>baz',
|
||||
'expected': 'foo^<span style="display: inline-block">bar</span>baz' },
|
||||
|
||||
{ 'id': 'SPAN:d:ib-3_SR',
|
||||
'desc': 'Delete with nested inline-block <span>, oblique selection',
|
||||
'pad': 'foo<span style="display: inline-block">bar[DEL</span>ETE]baz',
|
||||
'expected': 'foo<span style="display: inline-block">bar^</span>baz' },
|
||||
|
||||
{ 'id': 'SPAN:d:ib-4i_SI',
|
||||
'desc': 'Delete with nested inline-block <span>, oblique selection',
|
||||
'pad': 'foo<span style="display: inline-block">bar[DELETE]baz</span>qoz',
|
||||
'expected': 'foo<span style="display: inline-block">bar^baz</span>qoz' },
|
||||
|
||||
{ 'id': 'SPAN:d:ib-4l_SI',
|
||||
'desc': 'Delete with nested inline-block <span>, oblique selection',
|
||||
'pad': 'foo<span style="display: inline-block">[DELETE]barbaz</span>qoz',
|
||||
'expected': 'foo<span style="display: inline-block">^barbaz</span>qoz' },
|
||||
|
||||
{ 'id': 'SPAN:d:ib-4r_SI',
|
||||
'desc': 'Delete with nested inline-block <span>, oblique selection',
|
||||
'pad': 'foo<span style="display: inline-block">barbaz[DELETE]</span>qoz',
|
||||
'expected': 'foo<span style="display: inline-block">barbaz^</span>qoz' }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
285
editor/libeditor/html/tests/browserscope/lib/richtext2/richtext2/tests/insert.py
Executable file
285
editor/libeditor/html/tests/browserscope/lib/richtext2/richtext2/tests/insert.py
Executable file
@ -0,0 +1,285 @@
|
||||
|
||||
INSERT_TESTS = {
|
||||
'id': 'I',
|
||||
'caption': 'Insert Tests',
|
||||
'checkAttrs': False,
|
||||
'checkStyle': False,
|
||||
|
||||
'Proposed': [
|
||||
{ 'desc': '',
|
||||
'command': '',
|
||||
'tests': [
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'insert <hr>',
|
||||
'command': 'inserthorizontalrule',
|
||||
'tests': [
|
||||
{ 'id': 'IHR_TEXT-1_SC',
|
||||
'rte1-id': 'a-inserthorizontalrule-0',
|
||||
'desc': 'Insert <hr> into text',
|
||||
'pad': 'foo^bar',
|
||||
'expected': 'foo<hr>^bar',
|
||||
'accept': 'foo<hr>|bar' },
|
||||
|
||||
{ 'id': 'IHR_TEXT-1_SI',
|
||||
'desc': 'Insert <hr>, replacing selected text',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': 'foo<hr>^baz',
|
||||
'accept': 'foo<hr>|baz' },
|
||||
|
||||
{ 'id': 'IHR_DIV-B-1_SX',
|
||||
'desc': 'Insert <hr> between elements',
|
||||
'pad': '<div><b>foo</b>|<b>bar</b></div>',
|
||||
'expected': '<div><b>foo</b><hr>|<b>bar</b></div>' },
|
||||
|
||||
{ 'id': 'IHR_DIV-B-2_SO',
|
||||
'desc': 'Insert <hr>, replacing a fully wrapped element',
|
||||
'pad': '<div><b>foo</b>{<b>bar</b>}<b>baz</b></div>',
|
||||
'expected': '<div><b>foo</b><hr>|<b>baz</b></div>' },
|
||||
|
||||
{ 'id': 'IHR_B-1_SC',
|
||||
'desc': 'Insert <hr> into a span, splitting it',
|
||||
'pad': '<b>foo^bar</b>',
|
||||
'expected': '<b>foo</b><hr><b>^bar</b>' },
|
||||
|
||||
{ 'id': 'IHR_B-1_SS',
|
||||
'desc': 'Insert <hr> into a span at the start (should not create an empty span)',
|
||||
'pad': '<b>^foobar</b>',
|
||||
'expected': '<hr><b>^foobar</b>' },
|
||||
|
||||
{ 'id': 'IHR_B-1_SE',
|
||||
'desc': 'Insert <hr> into a span at the end',
|
||||
'pad': '<b>foobar^</b>',
|
||||
'expected': [ '<b>foobar</b><hr>|',
|
||||
'<b>foobar</b><hr><b>^</b>' ] },
|
||||
|
||||
{ 'id': 'IHR_B-2_SL',
|
||||
'desc': 'Insert <hr> with oblique selection starting outside of span',
|
||||
'pad': 'foo[bar<b>baz]qoz</b>',
|
||||
'expected': 'foo<hr>|<b>qoz</b>' },
|
||||
|
||||
{ 'id': 'IHR_B-2_SLR',
|
||||
'desc': 'Insert <hr> with oblique reversed selection starting outside of span',
|
||||
'pad': 'foo]bar<b>baz[qoz</b>',
|
||||
'expected': [ 'foo<hr>|<b>qoz</b>',
|
||||
'foo<hr><b>^qoz</b>' ] },
|
||||
|
||||
{ 'id': 'IHR_B-3_SR',
|
||||
'desc': 'Insert <hr> with oblique selection ending outside of span',
|
||||
'pad': '<b>foo[bar</b>baz]quoz',
|
||||
'expected': [ '<b>foo</b><hr>|quoz',
|
||||
'<b>foo</b><hr><b>^</b>quoz' ] },
|
||||
|
||||
{ 'id': 'IHR_B-3_SRR',
|
||||
'desc': 'Insert <hr> with oblique reversed selection starting outside of span',
|
||||
'pad': '<b>foo]bar</b>baz[quoz',
|
||||
'expected': '<b>foo</b><hr>|quoz' },
|
||||
|
||||
{ 'id': 'IHR_B-I-1_SM',
|
||||
'desc': 'Insert <hr> with oblique selection between different spans',
|
||||
'pad': '<b>foo[bar</b><i>baz]quoz</i>',
|
||||
'expected': [ '<b>foo</b><hr>|<i>quoz</i>',
|
||||
'<b>foo</b><hr><b>^</b><i>quoz</i>' ] },
|
||||
|
||||
{ 'id': 'IHR_B-I-1_SMR',
|
||||
'desc': 'Insert <hr> with reversed oblique selection between different spans',
|
||||
'pad': '<b>foo]bar</b><i>baz[quoz</i>',
|
||||
'expected': '<b>foo</b><hr><i>^quoz</i>' },
|
||||
|
||||
{ 'id': 'IHR_P-1_SC',
|
||||
'desc': 'Insert <hr> into a paragraph, splitting it',
|
||||
'pad': '<p>foo^bar</p>',
|
||||
'expected': [ '<p>foo</p><hr>|<p>bar</p>',
|
||||
'<p>foo</p><hr><p>^bar</p>' ] },
|
||||
|
||||
{ 'id': 'IHR_P-1_SS',
|
||||
'desc': 'Insert <hr> into a paragraph at the start (should not create an empty span)',
|
||||
'pad': '<p>^foobar</p>',
|
||||
'expected': [ '<hr>|<p>foobar</p>',
|
||||
'<hr><p>^foobar</p>' ] },
|
||||
|
||||
{ 'id': 'IHR_P-1_SE',
|
||||
'desc': 'Insert <hr> into a paragraph at the end (should not create an empty span)',
|
||||
'pad': '<p>foobar^</p>',
|
||||
'expected': '<p>foobar</p><hr>|' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'insert <p>',
|
||||
'command': 'insertparagraph',
|
||||
'tests': [
|
||||
{ 'id': 'IP_P-1_SC',
|
||||
'desc': 'Split paragraph',
|
||||
'pad': '<p>foo^bar</p>',
|
||||
'expected': '<p>foo</p><p>^bar</p>' },
|
||||
|
||||
{ 'id': 'IP_UL-LI-1_SC',
|
||||
'desc': 'Split list item',
|
||||
'pad': '<ul><li>foo^bar</li></ul>',
|
||||
'expected': '<ul><li>foo</li><li>^bar</li></ul>' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'insert text',
|
||||
'command': 'inserttext',
|
||||
'tests': [
|
||||
{ 'id': 'ITEXT:text_TEXT-1_SC',
|
||||
'desc': 'Insert text',
|
||||
'value': 'text',
|
||||
'pad': 'foo^bar',
|
||||
'expected': 'footext^bar' },
|
||||
|
||||
{ 'id': 'ITEXT:text_TEXT-1_SI',
|
||||
'desc': 'Insert text, replacing selected text',
|
||||
'value': 'text',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': 'footext^baz' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'insert <br>',
|
||||
'command': 'insertlinebreak',
|
||||
'tests': [
|
||||
{ 'id': 'IBR_TEXT-1_SC',
|
||||
'desc': 'Insert <br> into text',
|
||||
'pad': 'foo^bar',
|
||||
'expected': [ 'foo<br>|bar',
|
||||
'foo<br>^bar' ] },
|
||||
|
||||
{ 'id': 'IBR_TEXT-1_SI',
|
||||
'desc': 'Insert <br>, replacing selected text',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': [ 'foo<br>|baz',
|
||||
'foo<br>^baz' ] },
|
||||
|
||||
{ 'id': 'IBR_LI-1_SC',
|
||||
'desc': 'Insert <br> within list item',
|
||||
'pad': '<ul><li>foo^bar</li></ul>',
|
||||
'expected': '<ul><li>foo<br>^bar</li></ul>' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'insert <img>',
|
||||
'command': 'insertimage',
|
||||
'tests': [
|
||||
{ 'id': 'IIMG:url_TEXT-1_SC',
|
||||
'rte1-id': 'a-insertimage-0',
|
||||
'desc': 'Insert image with URL "http://goo.gl/bar.png"',
|
||||
'value': 'http://goo.gl/bar.png',
|
||||
'checkAttrs': True,
|
||||
'pad': 'foo^bar',
|
||||
'expected': [ 'foo<img src="http://goo.gl/bar.png">|bar',
|
||||
'foo<img src="http://goo.gl/bar.png">^bar' ] },
|
||||
|
||||
{ 'id': 'IIMG:url_IMG-1_SO',
|
||||
'desc': 'Change existing image to new URL, selection on <img>',
|
||||
'value': 'http://baz.com/quz.png',
|
||||
'checkAttrs': True,
|
||||
'pad': '<span>foo{<img src="http://goo.gl/bar.png">}bar</span>',
|
||||
'expected': [ '<span>foo<img src="http://baz.com/quz.png"/>|bar</span>',
|
||||
'<span>foo<img src="http://baz.com/quz.png"/>^bar</span>' ] },
|
||||
|
||||
{ 'id': 'IIMG:url_SPAN-IMG-1_SO',
|
||||
'desc': 'Change existing image to new URL, selection in text surrounding <img>',
|
||||
'value': 'http://baz.com/quz.png',
|
||||
'checkAttrs': True,
|
||||
'pad': 'foo[<img src="http://goo.gl/bar.png">]bar',
|
||||
'expected': [ 'foo<img src="http://baz.com/quz.png"/>|bar',
|
||||
'foo<img src="http://baz.com/quz.png"/>^bar' ] },
|
||||
|
||||
{ 'id': 'IIMG:._SPAN-IMG-1_SO',
|
||||
'desc': 'Remove existing image or URL, selection on <img>',
|
||||
'value': '',
|
||||
'checkAttrs': True,
|
||||
'pad': '<span>foo{<img src="http://goo.gl/bar.png">}bar</span>',
|
||||
'expected': [ '<span>foo^bar</span>',
|
||||
'<span>foo<img>|bar</span>',
|
||||
'<span>foo<img>^bar</span>',
|
||||
'<span>foo<img src="">|bar</span>',
|
||||
'<span>foo<img src="">^bar</span>' ] },
|
||||
|
||||
{ 'id': 'IIMG:._IMG-1_SO',
|
||||
'desc': 'Remove existing image or URL, selection in text surrounding <img>',
|
||||
'value': '',
|
||||
'checkAttrs': True,
|
||||
'pad': 'foo[<img src="http://goo.gl/bar.png">]bar',
|
||||
'expected': [ 'foo^bar',
|
||||
'foo<img>|bar',
|
||||
'foo<img>^bar',
|
||||
'foo<img src="">|bar',
|
||||
'foo<img src="">^bar' ] }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'insert <ol>',
|
||||
'command': 'insertorderedlist',
|
||||
'tests': [
|
||||
{ 'id': 'IOL_TEXT-1_SC',
|
||||
'rte1-id': 'a-insertorderedlist-0',
|
||||
'desc': 'Insert ordered list on collapsed selection',
|
||||
'pad': 'foo^bar',
|
||||
'expected': '<ol><li>foo^bar</li></ol>' },
|
||||
|
||||
{ 'id': 'IOL_TEXT-1_SI',
|
||||
'desc': 'Insert ordered list on selected text',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': '<ol><li>foo[bar]baz</li></ol>' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'insert <ul>',
|
||||
'command': 'insertunorderedlist',
|
||||
'tests': [
|
||||
{ 'id': 'IUL_TEXT-1_SC',
|
||||
'desc': 'Insert unordered list on collapsed selection',
|
||||
'pad': 'foo^bar',
|
||||
'expected': '<ul><li>foo^bar</li></ul>' },
|
||||
|
||||
{ 'id': 'IUL_TEXT-1_SI',
|
||||
'rte1-id': 'a-insertunorderedlist-0',
|
||||
'desc': 'Insert unordered list on selected text',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': '<ul><li>foo[bar]baz</li></ul>' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'insert arbitrary HTML',
|
||||
'command': 'inserthtml',
|
||||
'tests': [
|
||||
{ 'id': 'IHTML:BR_TEXT-1_SC',
|
||||
'rte1-id': 'a-inserthtml-0',
|
||||
'desc': 'InsertHTML: <br>',
|
||||
'value': '<br>',
|
||||
'pad': 'foo^barbaz',
|
||||
'expected': 'foo<br>^barbaz' },
|
||||
|
||||
{ 'id': 'IHTML:text_TEXT-1_SI',
|
||||
'desc': 'InsertHTML: "NEW"',
|
||||
'value': 'NEW',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': 'fooNEW^baz' },
|
||||
|
||||
{ 'id': 'IHTML:S_TEXT-1_SI',
|
||||
'desc': 'InsertHTML: "<span>NEW<span>"',
|
||||
'value': '<span>NEW</span>',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': 'foo<span>NEW</span>^baz' },
|
||||
|
||||
{ 'id': 'IHTML:H1.H2_TEXT-1_SI',
|
||||
'desc': 'InsertHTML: "<h1>NEW</h1><h2>HTML</h2>"',
|
||||
'value': '<h1>NEW</h1><h2>HTML</h2>',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': 'foo<h1>NEW</h1><h2>HTML</h2>^baz' },
|
||||
|
||||
{ 'id': 'IHTML:P-B_TEXT-1_SI',
|
||||
'desc': 'InsertHTML: "<p>NEW<b>HTML</b>!</p>"',
|
||||
'value': '<p>NEW<b>HTML</b>!</p>',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': 'foo<p>NEW<b>HTML</b>!</p>^baz' }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,215 @@
|
||||
|
||||
QUERYENABLED_TESTS = {
|
||||
'id': 'QE',
|
||||
'caption': 'queryCommandEnabled Tests',
|
||||
'pad': 'foo[bar]baz',
|
||||
'checkAttrs': False,
|
||||
'checkStyle': False,
|
||||
'styleWithCSS': False,
|
||||
'expected': True,
|
||||
|
||||
'Proposed': [
|
||||
{ 'desc': '',
|
||||
'tests': [
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'HTML5 commands',
|
||||
'tests': [
|
||||
{ 'id': 'SELECTALL_TEXT-1',
|
||||
'desc': 'check whether the "selectall" command is enabled',
|
||||
'qcenabled': 'selectall' },
|
||||
|
||||
{ 'id': 'UNSELECT_TEXT-1',
|
||||
'desc': 'check whether the "unselect" command is enabled',
|
||||
'qcenabled': 'unselect' },
|
||||
|
||||
{ 'id': 'UNDO_TEXT-1',
|
||||
'desc': 'check whether the "undo" command is enabled',
|
||||
'qcenabled': 'undo' },
|
||||
|
||||
{ 'id': 'REDO_TEXT-1',
|
||||
'desc': 'check whether the "redo" command is enabled',
|
||||
'qcenabled': 'redo' },
|
||||
|
||||
{ 'id': 'BOLD_TEXT-1',
|
||||
'desc': 'check whether the "bold" command is enabled',
|
||||
'qcenabled': 'bold' },
|
||||
|
||||
{ 'id': 'ITALIC_TEXT-1',
|
||||
'desc': 'check whether the "italic" command is enabled',
|
||||
'qcenabled': 'italic' },
|
||||
|
||||
{ 'id': 'UNDERLINE_TEXT-1',
|
||||
'desc': 'check whether the "underline" command is enabled',
|
||||
'qcenabled': 'underline' },
|
||||
|
||||
{ 'id': 'STRIKETHROUGH_TEXT-1',
|
||||
'desc': 'check whether the "strikethrough" command is enabled',
|
||||
'qcenabled': 'strikethrough' },
|
||||
|
||||
{ 'id': 'SUBSCRIPT_TEXT-1',
|
||||
'desc': 'check whether the "subscript" command is enabled',
|
||||
'qcenabled': 'subscript' },
|
||||
|
||||
{ 'id': 'SUPERSCRIPT_TEXT-1',
|
||||
'desc': 'check whether the "superscript" command is enabled',
|
||||
'qcenabled': 'superscript' },
|
||||
|
||||
{ 'id': 'FORMATBLOCK_TEXT-1',
|
||||
'desc': 'check whether the "formatblock" command is enabled',
|
||||
'qcenabled': 'formatblock' },
|
||||
|
||||
{ 'id': 'CREATELINK_TEXT-1',
|
||||
'desc': 'check whether the "createlink" command is enabled',
|
||||
'qcenabled': 'createlink' },
|
||||
|
||||
{ 'id': 'UNLINK_TEXT-1',
|
||||
'desc': 'check whether the "unlink" command is enabled',
|
||||
'qcenabled': 'unlink' },
|
||||
|
||||
{ 'id': 'INSERTHTML_TEXT-1',
|
||||
'desc': 'check whether the "inserthtml" command is enabled',
|
||||
'qcenabled': 'inserthtml' },
|
||||
|
||||
{ 'id': 'INSERTHORIZONTALRULE_TEXT-1',
|
||||
'desc': 'check whether the "inserthorizontalrule" command is enabled',
|
||||
'qcenabled': 'inserthorizontalrule' },
|
||||
|
||||
{ 'id': 'INSERTIMAGE_TEXT-1',
|
||||
'desc': 'check whether the "insertimage" command is enabled',
|
||||
'qcenabled': 'insertimage' },
|
||||
|
||||
{ 'id': 'INSERTLINEBREAK_TEXT-1',
|
||||
'desc': 'check whether the "insertlinebreak" command is enabled',
|
||||
'qcenabled': 'insertlinebreak' },
|
||||
|
||||
{ 'id': 'INSERTPARAGRAPH_TEXT-1',
|
||||
'desc': 'check whether the "insertparagraph" command is enabled',
|
||||
'qcenabled': 'insertparagraph' },
|
||||
|
||||
{ 'id': 'INSERTORDEREDLIST_TEXT-1',
|
||||
'desc': 'check whether the "insertorderedlist" command is enabled',
|
||||
'qcenabled': 'insertorderedlist' },
|
||||
|
||||
{ 'id': 'INSERTUNORDEREDLIST_TEXT-1',
|
||||
'desc': 'check whether the "insertunorderedlist" command is enabled',
|
||||
'qcenabled': 'insertunorderedlist' },
|
||||
|
||||
{ 'id': 'INSERTTEXT_TEXT-1',
|
||||
'desc': 'check whether the "inserttext" command is enabled',
|
||||
'qcenabled': 'inserttext' },
|
||||
|
||||
{ 'id': 'DELETE_TEXT-1',
|
||||
'desc': 'check whether the "delete" command is enabled',
|
||||
'qcenabled': 'delete' },
|
||||
|
||||
{ 'id': 'FORWARDDELETE_TEXT-1',
|
||||
'desc': 'check whether the "forwarddelete" command is enabled',
|
||||
'qcenabled': 'forwarddelete' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'MIDAS commands',
|
||||
'tests': [
|
||||
{ 'id': 'STYLEWITHCSS_TEXT-1',
|
||||
'desc': 'check whether the "styleWithCSS" command is enabled',
|
||||
'qcenabled': 'styleWithCSS' },
|
||||
|
||||
{ 'id': 'CONTENTREADONLY_TEXT-1',
|
||||
'desc': 'check whether the "contentreadonly" command is enabled',
|
||||
'qcenabled': 'contentreadonly' },
|
||||
|
||||
{ 'id': 'BACKCOLOR_TEXT-1',
|
||||
'desc': 'check whether the "backcolor" command is enabled',
|
||||
'qcenabled': 'backcolor' },
|
||||
|
||||
{ 'id': 'FORECOLOR_TEXT-1',
|
||||
'desc': 'check whether the "forecolor" command is enabled',
|
||||
'qcenabled': 'forecolor' },
|
||||
|
||||
{ 'id': 'HILITECOLOR_TEXT-1',
|
||||
'desc': 'check whether the "hilitecolor" command is enabled',
|
||||
'qcenabled': 'hilitecolor' },
|
||||
|
||||
{ 'id': 'FONTNAME_TEXT-1',
|
||||
'desc': 'check whether the "fontname" command is enabled',
|
||||
'qcenabled': 'fontname' },
|
||||
|
||||
{ 'id': 'FONTSIZE_TEXT-1',
|
||||
'desc': 'check whether the "fontsize" command is enabled',
|
||||
'qcenabled': 'fontsize' },
|
||||
|
||||
{ 'id': 'INCREASEFONTSIZE_TEXT-1',
|
||||
'desc': 'check whether the "increasefontsize" command is enabled',
|
||||
'qcenabled': 'increasefontsize' },
|
||||
|
||||
{ 'id': 'DECREASEFONTSIZE_TEXT-1',
|
||||
'desc': 'check whether the "decreasefontsize" command is enabled',
|
||||
'qcenabled': 'decreasefontsize' },
|
||||
|
||||
{ 'id': 'HEADING_TEXT-1',
|
||||
'desc': 'check whether the "heading" command is enabled',
|
||||
'qcenabled': 'heading' },
|
||||
|
||||
{ 'id': 'INDENT_TEXT-1',
|
||||
'desc': 'check whether the "indent" command is enabled',
|
||||
'qcenabled': 'indent' },
|
||||
|
||||
{ 'id': 'OUTDENT_TEXT-1',
|
||||
'desc': 'check whether the "outdent" command is enabled',
|
||||
'qcenabled': 'outdent' },
|
||||
|
||||
{ 'id': 'CREATEBOOKMARK_TEXT-1',
|
||||
'desc': 'check whether the "createbookmark" command is enabled',
|
||||
'qcenabled': 'createbookmark' },
|
||||
|
||||
{ 'id': 'UNBOOKMARK_TEXT-1',
|
||||
'desc': 'check whether the "unbookmark" command is enabled',
|
||||
'qcenabled': 'unbookmark' },
|
||||
|
||||
{ 'id': 'JUSTIFYCENTER_TEXT-1',
|
||||
'desc': 'check whether the "justifycenter" command is enabled',
|
||||
'qcenabled': 'justifycenter' },
|
||||
|
||||
{ 'id': 'JUSTIFYFULL_TEXT-1',
|
||||
'desc': 'check whether the "justifyfull" command is enabled',
|
||||
'qcenabled': 'justifyfull' },
|
||||
|
||||
{ 'id': 'JUSTIFYLEFT_TEXT-1',
|
||||
'desc': 'check whether the "justifyleft" command is enabled',
|
||||
'qcenabled': 'justifyleft' },
|
||||
|
||||
{ 'id': 'JUSTIFYRIGHT_TEXT-1',
|
||||
'desc': 'check whether the "justifyright" command is enabled',
|
||||
'qcenabled': 'justifyright' },
|
||||
|
||||
{ 'id': 'REMOVEFORMAT_TEXT-1',
|
||||
'desc': 'check whether the "removeformat" command is enabled',
|
||||
'qcenabled': 'removeformat' },
|
||||
|
||||
{ 'id': 'COPY_TEXT-1',
|
||||
'desc': 'check whether the "copy" command is enabled',
|
||||
'qcenabled': 'copy' },
|
||||
|
||||
{ 'id': 'CUT_TEXT-1',
|
||||
'desc': 'check whether the "cut" command is enabled',
|
||||
'qcenabled': 'cut' },
|
||||
|
||||
{ 'id': 'PASTE_TEXT-1',
|
||||
'desc': 'check whether the "paste" command is enabled',
|
||||
'qcenabled': 'paste' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'Other tests',
|
||||
'tests': [
|
||||
{ 'id': 'garbage-1_TEXT-1',
|
||||
'desc': 'check correct return value with garbage input',
|
||||
'qcenabled': '#!#@7',
|
||||
'expected': False }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -0,0 +1,214 @@
|
||||
|
||||
QUERYINDETERM_TESTS = {
|
||||
'id': 'QI',
|
||||
'caption': 'queryCommandIndeterm Tests',
|
||||
'pad': 'foo[bar]baz',
|
||||
'checkAttrs': False,
|
||||
'checkStyle': False,
|
||||
'styleWithCSS': False,
|
||||
'expected': False,
|
||||
|
||||
'Proposed': [
|
||||
{ 'desc': '',
|
||||
'tests': [
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'HTML5 commands',
|
||||
'tests': [
|
||||
{ 'id': 'SELECTALL_TEXT-1',
|
||||
'desc': 'check whether the "selectall" command is indeterminate',
|
||||
'qcindeterm': 'selectall' },
|
||||
|
||||
{ 'id': 'UNSELECT_TEXT-1',
|
||||
'desc': 'check whether the "unselect" command is indeterminate',
|
||||
'qcindeterm': 'unselect' },
|
||||
|
||||
{ 'id': 'UNDO_TEXT-1',
|
||||
'desc': 'check whether the "undo" command is indeterminate',
|
||||
'qcindeterm': 'undo' },
|
||||
|
||||
{ 'id': 'REDO_TEXT-1',
|
||||
'desc': 'check whether the "redo" command is indeterminate',
|
||||
'qcindeterm': 'redo' },
|
||||
|
||||
{ 'id': 'BOLD_TEXT-1',
|
||||
'desc': 'check whether the "bold" command is indeterminate',
|
||||
'qcindeterm': 'bold' },
|
||||
|
||||
{ 'id': 'ITALIC_TEXT-1',
|
||||
'desc': 'check whether the "italic" command is indeterminate',
|
||||
'qcindeterm': 'italic' },
|
||||
|
||||
{ 'id': 'UNDERLINE_TEXT-1',
|
||||
'desc': 'check whether the "underline" command is indeterminate',
|
||||
'qcindeterm': 'underline' },
|
||||
|
||||
{ 'id': 'STRIKETHROUGH_TEXT-1',
|
||||
'desc': 'check whether the "strikethrough" command is indeterminate',
|
||||
'qcindeterm': 'strikethrough' },
|
||||
|
||||
{ 'id': 'SUBSCRIPT_TEXT-1',
|
||||
'desc': 'check whether the "subscript" command is indeterminate',
|
||||
'qcindeterm': 'subscript' },
|
||||
|
||||
{ 'id': 'SUPERSCRIPT_TEXT-1',
|
||||
'desc': 'check whether the "superscript" command is indeterminate',
|
||||
'qcindeterm': 'superscript' },
|
||||
|
||||
{ 'id': 'FORMATBLOCK_TEXT-1',
|
||||
'desc': 'check whether the "formatblock" command is indeterminate',
|
||||
'qcindeterm': 'formatblock' },
|
||||
|
||||
{ 'id': 'CREATELINK_TEXT-1',
|
||||
'desc': 'check whether the "createlink" command is indeterminate',
|
||||
'qcindeterm': 'createlink' },
|
||||
|
||||
{ 'id': 'UNLINK_TEXT-1',
|
||||
'desc': 'check whether the "unlink" command is indeterminate',
|
||||
'qcindeterm': 'unlink' },
|
||||
|
||||
{ 'id': 'INSERTHTML_TEXT-1',
|
||||
'desc': 'check whether the "inserthtml" command is indeterminate',
|
||||
'qcindeterm': 'inserthtml' },
|
||||
|
||||
{ 'id': 'INSERTHORIZONTALRULE_TEXT-1',
|
||||
'desc': 'check whether the "inserthorizontalrule" command is indeterminate',
|
||||
'qcindeterm': 'inserthorizontalrule' },
|
||||
|
||||
{ 'id': 'INSERTIMAGE_TEXT-1',
|
||||
'desc': 'check whether the "insertimage" command is indeterminate',
|
||||
'qcindeterm': 'insertimage' },
|
||||
|
||||
{ 'id': 'INSERTLINEBREAK_TEXT-1',
|
||||
'desc': 'check whether the "insertlinebreak" command is indeterminate',
|
||||
'qcindeterm': 'insertlinebreak' },
|
||||
|
||||
{ 'id': 'INSERTPARAGRAPH_TEXT-1',
|
||||
'desc': 'check whether the "insertparagraph" command is indeterminate',
|
||||
'qcindeterm': 'insertparagraph' },
|
||||
|
||||
{ 'id': 'INSERTORDEREDLIST_TEXT-1',
|
||||
'desc': 'check whether the "insertorderedlist" command is indeterminate',
|
||||
'qcindeterm': 'insertorderedlist' },
|
||||
|
||||
{ 'id': 'INSERTUNORDEREDLIST_TEXT-1',
|
||||
'desc': 'check whether the "insertunorderedlist" command is indeterminate',
|
||||
'qcindeterm': 'insertunorderedlist' },
|
||||
|
||||
{ 'id': 'INSERTTEXT_TEXT-1',
|
||||
'desc': 'check whether the "inserttext" command is indeterminate',
|
||||
'qcindeterm': 'inserttext' },
|
||||
|
||||
{ 'id': 'DELETE_TEXT-1',
|
||||
'desc': 'check whether the "delete" command is indeterminate',
|
||||
'qcindeterm': 'delete' },
|
||||
|
||||
{ 'id': 'FORWARDDELETE_TEXT-1',
|
||||
'desc': 'check whether the "forwarddelete" command is indeterminate',
|
||||
'qcindeterm': 'forwarddelete' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'MIDAS commands',
|
||||
'tests': [
|
||||
{ 'id': 'STYLEWITHCSS_TEXT-1',
|
||||
'desc': 'check whether the "styleWithCSS" command is indeterminate',
|
||||
'qcindeterm': 'styleWithCSS' },
|
||||
|
||||
{ 'id': 'CONTENTREADONLY_TEXT-1',
|
||||
'desc': 'check whether the "contentreadonly" command is indeterminate',
|
||||
'qcindeterm': 'contentreadonly' },
|
||||
|
||||
{ 'id': 'BACKCOLOR_TEXT-1',
|
||||
'desc': 'check whether the "backcolor" command is indeterminate',
|
||||
'qcindeterm': 'backcolor' },
|
||||
|
||||
{ 'id': 'FORECOLOR_TEXT-1',
|
||||
'desc': 'check whether the "forecolor" command is indeterminate',
|
||||
'qcindeterm': 'forecolor' },
|
||||
|
||||
{ 'id': 'HILITECOLOR_TEXT-1',
|
||||
'desc': 'check whether the "hilitecolor" command is indeterminate',
|
||||
'qcindeterm': 'hilitecolor' },
|
||||
|
||||
{ 'id': 'FONTNAME_TEXT-1',
|
||||
'desc': 'check whether the "fontname" command is indeterminate',
|
||||
'qcindeterm': 'fontname' },
|
||||
|
||||
{ 'id': 'FONTSIZE_TEXT-1',
|
||||
'desc': 'check whether the "fontsize" command is indeterminate',
|
||||
'qcindeterm': 'fontsize' },
|
||||
|
||||
{ 'id': 'INCREASEFONTSIZE_TEXT-1',
|
||||
'desc': 'check whether the "increasefontsize" command is indeterminate',
|
||||
'qcindeterm': 'increasefontsize' },
|
||||
|
||||
{ 'id': 'DECREASEFONTSIZE_TEXT-1',
|
||||
'desc': 'check whether the "decreasefontsize" command is indeterminate',
|
||||
'qcindeterm': 'decreasefontsize' },
|
||||
|
||||
{ 'id': 'HEADING_TEXT-1',
|
||||
'desc': 'check whether the "heading" command is indeterminate',
|
||||
'qcindeterm': 'heading' },
|
||||
|
||||
{ 'id': 'INDENT_TEXT-1',
|
||||
'desc': 'check whether the "indent" command is indeterminate',
|
||||
'qcindeterm': 'indent' },
|
||||
|
||||
{ 'id': 'OUTDENT_TEXT-1',
|
||||
'desc': 'check whether the "outdent" command is indeterminate',
|
||||
'qcindeterm': 'outdent' },
|
||||
|
||||
{ 'id': 'CREATEBOOKMARK_TEXT-1',
|
||||
'desc': 'check whether the "createbookmark" command is indeterminate',
|
||||
'qcindeterm': 'createbookmark' },
|
||||
|
||||
{ 'id': 'UNBOOKMARK_TEXT-1',
|
||||
'desc': 'check whether the "unbookmark" command is indeterminate',
|
||||
'qcindeterm': 'unbookmark' },
|
||||
|
||||
{ 'id': 'JUSTIFYCENTER_TEXT-1',
|
||||
'desc': 'check whether the "justifycenter" command is indeterminate',
|
||||
'qcindeterm': 'justifycenter' },
|
||||
|
||||
{ 'id': 'JUSTIFYFULL_TEXT-1',
|
||||
'desc': 'check whether the "justifyfull" command is indeterminate',
|
||||
'qcindeterm': 'justifyfull' },
|
||||
|
||||
{ 'id': 'JUSTIFYLEFT_TEXT-1',
|
||||
'desc': 'check whether the "justifyleft" command is indeterminate',
|
||||
'qcindeterm': 'justifyleft' },
|
||||
|
||||
{ 'id': 'JUSTIFYRIGHT_TEXT-1',
|
||||
'desc': 'check whether the "justifyright" command is indeterminate',
|
||||
'qcindeterm': 'justifyright' },
|
||||
|
||||
{ 'id': 'REMOVEFORMAT_TEXT-1',
|
||||
'desc': 'check whether the "removeformat" command is indeterminate',
|
||||
'qcindeterm': 'removeformat' },
|
||||
|
||||
{ 'id': 'COPY_TEXT-1',
|
||||
'desc': 'check whether the "copy" command is indeterminate',
|
||||
'qcindeterm': 'copy' },
|
||||
|
||||
{ 'id': 'CUT_TEXT-1',
|
||||
'desc': 'check whether the "cut" command is indeterminate',
|
||||
'qcindeterm': 'cut' },
|
||||
|
||||
{ 'id': 'PASTE_TEXT-1',
|
||||
'desc': 'check whether the "paste" command is indeterminate',
|
||||
'qcindeterm': 'paste' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'Other tests',
|
||||
'tests': [
|
||||
{ 'id': 'garbage-1_TEXT-1',
|
||||
'desc': 'check correct return value with garbage input',
|
||||
'qcindeterm': '#!#@7' }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -0,0 +1,575 @@
|
||||
|
||||
QUERYSTATE_TESTS = {
|
||||
'id': 'QS',
|
||||
'caption': 'queryCommandState Tests',
|
||||
'checkAttrs': False,
|
||||
'checkStyle': False,
|
||||
'styleWithCSS': False,
|
||||
|
||||
'Proposed': [
|
||||
{ 'desc': '',
|
||||
'qcstate': '',
|
||||
'tests': [
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'query bold state',
|
||||
'qcstate': 'bold',
|
||||
'tests': [
|
||||
{ 'id': 'B_TEXT_SI',
|
||||
'rte1-id': 'q-bold-0',
|
||||
'desc': 'query the "bold" state',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': False },
|
||||
|
||||
{ 'id': 'B_B-1_SI',
|
||||
'rte1-id': 'q-bold-1',
|
||||
'desc': 'query the "bold" state',
|
||||
'pad': '<b>foo[bar]baz</b>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'B_STRONG-1_SI',
|
||||
'rte1-id': 'q-bold-2',
|
||||
'desc': 'query the "bold" state',
|
||||
'pad': '<strong>foo[bar]baz</strong>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'B_SPANs:fw:b-1_SI',
|
||||
'rte1-id': 'q-bold-3',
|
||||
'desc': 'query the "bold" state',
|
||||
'pad': '<span style="font-weight: bold">foo[bar]baz</span>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'B_SPANs:fw:n-1_SI',
|
||||
'desc': 'query the "bold" state',
|
||||
'pad': '<span style="font-weight: normal">foo[bar]baz</span>',
|
||||
'expected': False },
|
||||
|
||||
{ 'id': 'B_Bs:fw:n-1_SI',
|
||||
'rte1-id': 'q-bold-4',
|
||||
'desc': 'query the "bold" state',
|
||||
'pad': '<span style="font-weight: normal">foo[bar]baz</span>',
|
||||
'expected': False },
|
||||
|
||||
{ 'id': 'B_B-SPANs:fw:n-1_SI',
|
||||
'rte1-id': 'q-bold-5',
|
||||
'desc': 'query the "bold" state',
|
||||
'pad': '<b><span style="font-weight: normal">foo[bar]baz</span></b>',
|
||||
'expected': False },
|
||||
|
||||
{ 'id': 'B_SPAN.b-1-SI',
|
||||
'desc': 'query the "bold" state',
|
||||
'pad': '<span class="b">foo[bar]baz</span>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'B_MYB-1-SI',
|
||||
'desc': 'query the "bold" state',
|
||||
'pad': '<myb>foo[bar]baz</myb>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'B_B-I-1_SC',
|
||||
'desc': 'query the "bold" state, bold tag not immediate parent',
|
||||
'pad': '<b>foo<i>ba^r</i>baz</b>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'B_B-I-1_SL',
|
||||
'desc': 'query the "bold" state, selection partially in child element',
|
||||
'pad': '<b>fo[o<i>b]ar</i>baz</b>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'B_B-I-1_SR',
|
||||
'desc': 'query the "bold" state, selection partially in child element',
|
||||
'pad': '<b>foo<i>ba[r</i>b]az</b>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'B_STRONG-I-1_SC',
|
||||
'desc': 'query the "bold" state, bold tag not immediate parent',
|
||||
'pad': '<strong>foo<i>ba^r</i>baz</strong>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'B_B-I-U-1_SC',
|
||||
'desc': 'query the "bold" state, bold tag not immediate parent',
|
||||
'pad': '<b>foo<i>bar<u>b^az</u></i></strong>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'B_B-I-U-1_SM',
|
||||
'desc': 'query the "bold" state, bold tag not immediate parent',
|
||||
'pad': '<b>foo<i>ba[r<u>b]az</u></i></strong>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'B_TEXT-B-1_SO-1',
|
||||
'desc': 'query the "bold" state, selection wrapping the bold tag',
|
||||
'pad': 'foo[<b>bar</b>]baz',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'B_TEXT-B-1_SO-2',
|
||||
'desc': 'query the "bold" state, selection wrapping the bold tag',
|
||||
'pad': 'foo{<b>bar</b>}baz',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'B_TEXT-B-1_SL',
|
||||
'desc': 'query the "bold" state, selection containing non-bold text',
|
||||
'pad': 'fo[o<b>ba]r</b>baz',
|
||||
'expected': False },
|
||||
|
||||
{ 'id': 'B_TEXT-B-1_SR',
|
||||
'desc': 'query the "bold" state, selection containing non-bold text',
|
||||
'pad': 'foo<b>b[ar</b>b]az',
|
||||
'expected': False },
|
||||
|
||||
{ 'id': 'B_TEXT-B-1_SO-3',
|
||||
'desc': 'query the "bold" state, selection containing non-bold text',
|
||||
'pad': 'fo[o<b>bar</b>b]az',
|
||||
'expected': False },
|
||||
|
||||
{ 'id': 'B_B.TEXT.B-1_SM',
|
||||
'desc': 'query the "bold" state, selection including non-bold text',
|
||||
'pad': '<b>fo[o</b>bar<b>b]az</b>',
|
||||
'expected': False },
|
||||
|
||||
{ 'id': 'B_B.B.B-1_SM',
|
||||
'desc': 'query the "bold" state, selection mixed, but all bold',
|
||||
'pad': '<b>fo[o</b><b>bar</b><b>b]az</b>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'B_B.STRONG.B-1_SM',
|
||||
'desc': 'query the "bold" state, selection mixed, but all bold',
|
||||
'pad': '<b>fo[o</b><strong>bar</strong><b>b]az</b>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'B_SPAN.b.MYB.SPANs:fw:b-1_SM',
|
||||
'desc': 'query the "bold" state, selection mixed, but all bold',
|
||||
'pad': '<span class="b">fo[o</span><myb>bar</myb><span style="font-weight: bold">b]az</span>',
|
||||
'expected': True }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'query italic state',
|
||||
'qcstate': 'italic',
|
||||
'tests': [
|
||||
{ 'id': 'I_TEXT_SI',
|
||||
'rte1-id': 'q-italic-0',
|
||||
'desc': 'query the "italic" state',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': False },
|
||||
|
||||
{ 'id': 'I_I-1_SI',
|
||||
'rte1-id': 'q-italic-1',
|
||||
'desc': 'query the "italic" state',
|
||||
'pad': '<i>foo[bar]baz</i>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'I_EM-1_SI',
|
||||
'rte1-id': 'q-italic-2',
|
||||
'desc': 'query the "italic" state',
|
||||
'pad': '<em>foo[bar]baz</em>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'I_SPANs:fs:i-1_SI',
|
||||
'rte1-id': 'q-italic-3',
|
||||
'desc': 'query the "italic" state',
|
||||
'pad': '<span style="font-style: italic">foo[bar]baz</span>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'I_SPANs:fs:n-1_SI',
|
||||
'desc': 'query the "italic" state',
|
||||
'pad': '<span style="font-style: normal">foo[bar]baz</span>',
|
||||
'expected': False },
|
||||
|
||||
{ 'id': 'I_I-SPANs:fs:n-1_SI',
|
||||
'rte1-id': 'q-italic-4',
|
||||
'desc': 'query the "italic" state',
|
||||
'pad': '<i><span style="font-style: normal">foo[bar]baz</span></i>',
|
||||
'expected': False },
|
||||
|
||||
{ 'id': 'I_SPAN.i-1-SI',
|
||||
'desc': 'query the "italic" state',
|
||||
'pad': '<span class="i">foo[bar]baz</span>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'I_MYI-1-SI',
|
||||
'desc': 'query the "italic" state',
|
||||
'pad': '<myi>foo[bar]baz</myi>',
|
||||
'expected': True }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'query underline state',
|
||||
'qcstate': 'underline',
|
||||
'tests': [
|
||||
{ 'id': 'U_TEXT_SI',
|
||||
'rte1-id': 'q-underline-0',
|
||||
'desc': 'query the "underline" state',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': False },
|
||||
|
||||
{ 'id': 'U_U-1_SI',
|
||||
'rte1-id': 'q-underline-1',
|
||||
'desc': 'query the "underline" state',
|
||||
'pad': '<u>foo[bar]baz</u>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'U_Us:td:n-1_SI',
|
||||
'rte1-id': 'q-underline-4',
|
||||
'desc': 'query the "underline" state',
|
||||
'pad': '<u style="text-decoration: none">foo[bar]baz</u>',
|
||||
'expected': False },
|
||||
|
||||
{ 'id': 'U_Ah:url-1_SI',
|
||||
'rte1-id': 'q-underline-2',
|
||||
'desc': 'query the "underline" state',
|
||||
'pad': '<a href="http://www.goo.gl">foo[bar]baz</a>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'U_Ah:url.s:td:n-1_SI',
|
||||
'rte1-id': 'q-underline-5',
|
||||
'desc': 'query the "underline" state',
|
||||
'pad': '<a href="http://www.goo.gl" style="text-decoration: none">foo[bar]baz</a>',
|
||||
'expected': False },
|
||||
|
||||
{ 'id': 'U_SPANs:td:u-1_SI',
|
||||
'rte1-id': 'q-underline-3',
|
||||
'desc': 'query the "underline" state',
|
||||
'pad': '<span style="text-decoration: underline">foo[bar]baz</span>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'U_SPAN.u-1-SI',
|
||||
'desc': 'query the "underline" state',
|
||||
'pad': '<span class="u">foo[bar]baz</span>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'U_MYU-1-SI',
|
||||
'desc': 'query the "underline" state',
|
||||
'pad': '<myu>foo[bar]baz</myu>',
|
||||
'expected': True }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'query strike-through state',
|
||||
'qcstate': 'strikethrough',
|
||||
'tests': [
|
||||
{ 'id': 'S_TEXT_SI',
|
||||
'rte1-id': 'q-strikethrough-0',
|
||||
'desc': 'query the "strikethrough" state',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': False },
|
||||
|
||||
{ 'id': 'S_S-1_SI',
|
||||
'rte1-id': 'q-strikethrough-3',
|
||||
'desc': 'query the "strikethrough" state',
|
||||
'pad': '<s>foo[bar]baz</s>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'S_STRIKE-1_SI',
|
||||
'rte1-id': 'q-strikethrough-1',
|
||||
'desc': 'query the "strikethrough" state',
|
||||
'pad': '<strike>foo[bar]baz</strike>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'S_STRIKEs:td:n-1_SI',
|
||||
'rte1-id': 'q-strikethrough-2',
|
||||
'desc': 'query the "strikethrough" state',
|
||||
'pad': '<strike style="text-decoration: none">foo[bar]baz</strike>',
|
||||
'expected': False },
|
||||
|
||||
{ 'id': 'S_DEL-1_SI',
|
||||
'rte1-id': 'q-strikethrough-4',
|
||||
'desc': 'query the "strikethrough" state',
|
||||
'pad': '<del>foo[bar]baz</del>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'S_SPANs:td:lt-1_SI',
|
||||
'rte1-id': 'q-strikethrough-5',
|
||||
'desc': 'query the "strikethrough" state',
|
||||
'pad': '<span style="text-decoration: line-through">foo[bar]baz</span>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'S_SPAN.s-1-SI',
|
||||
'desc': 'query the "strikethrough" state',
|
||||
'pad': '<span class="s">foo[bar]baz</span>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'S_MYS-1-SI',
|
||||
'desc': 'query the "strikethrough" state',
|
||||
'pad': '<mys>foo[bar]baz</mys>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'S_S.STRIKE.DEL-1_SM',
|
||||
'desc': 'query the "strikethrough" state, selection mixed, but all struck',
|
||||
'pad': '<s>fo[o</s><strike>bar</strike><del>b]az</del>',
|
||||
'expected': True }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'query subscript state',
|
||||
'qcstate': 'subscript',
|
||||
'tests': [
|
||||
{ 'id': 'SUB_TEXT_SI',
|
||||
'rte1-id': 'q-subscript-0',
|
||||
'desc': 'query the "subscript" state',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': False },
|
||||
|
||||
{ 'id': 'SUB_SUB-1_SI',
|
||||
'rte1-id': 'q-subscript-1',
|
||||
'desc': 'query the "subscript" state',
|
||||
'pad': '<sub>foo[bar]baz</sub>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'SUB_SPAN.sub-1-SI',
|
||||
'desc': 'query the "subscript" state',
|
||||
'pad': '<span class="sub">foo[bar]baz</span>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'SUB_MYSUB-1-SI',
|
||||
'desc': 'query the "subscript" state',
|
||||
'pad': '<mysub>foo[bar]baz</mysub>',
|
||||
'expected': True }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'query superscript state',
|
||||
'qcstate': 'superscript',
|
||||
'tests': [
|
||||
{ 'id': 'SUP_TEXT_SI',
|
||||
'rte1-id': 'q-superscript-0',
|
||||
'desc': 'query the "superscript" state',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': False },
|
||||
|
||||
{ 'id': 'SUP_SUP-1_SI',
|
||||
'rte1-id': 'q-superscript-1',
|
||||
'desc': 'query the "superscript" state',
|
||||
'pad': '<sup>foo[bar]baz</sup>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'IOL_TEXT_SI',
|
||||
'desc': 'query the "insertorderedlist" state',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': False },
|
||||
|
||||
{ 'id': 'SUP_SPAN.sup-1-SI',
|
||||
'desc': 'query the "superscript" state',
|
||||
'pad': '<span class="sup">foo[bar]baz</span>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'SUP_MYSUP-1-SI',
|
||||
'desc': 'query the "superscript" state',
|
||||
'pad': '<mysup>foo[bar]baz</mysup>',
|
||||
'expected': True }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'query whether the selection is in an ordered list',
|
||||
'qcstate': 'insertorderedlist',
|
||||
'tests': [
|
||||
{ 'id': 'IOL_TEXT-1_SI',
|
||||
'rte1-id': 'q-insertorderedlist-0',
|
||||
'desc': 'query the "insertorderedlist" state',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': False },
|
||||
|
||||
{ 'id': 'IOL_OL-LI-1_SI',
|
||||
'rte1-id': 'q-insertorderedlist-1',
|
||||
'desc': 'query the "insertorderedlist" state',
|
||||
'pad': '<ol><li>foo[bar]baz</li></ol>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'IOL_UL_LI-1_SI',
|
||||
'rte1-id': 'q-insertorderedlist-2',
|
||||
'desc': 'query the "insertorderedlist" state',
|
||||
'pad': '<ul><li>foo[bar]baz</li></ul>',
|
||||
'expected': False }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'query whether the selection is in an unordered list',
|
||||
'qcstate': 'insertunorderedlist',
|
||||
'tests': [
|
||||
{ 'id': 'IUL_TEXT_SI',
|
||||
'rte1-id': 'q-insertunorderedlist-0',
|
||||
'desc': 'query the "insertunorderedlist" state',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': False },
|
||||
|
||||
{ 'id': 'IUL_OL-LI-1_SI',
|
||||
'rte1-id': 'q-insertunorderedlist-1',
|
||||
'desc': 'query the "insertunorderedlist" state',
|
||||
'pad': '<ol><li>foo[bar]baz</li></ol>',
|
||||
'expected': False },
|
||||
|
||||
{ 'id': 'IUL_UL-LI-1_SI',
|
||||
'rte1-id': 'q-insertunorderedlist-2',
|
||||
'desc': 'query the "insertunorderedlist" state',
|
||||
'pad': '<ul><li>foo[bar]baz</li></ul>',
|
||||
'expected': True }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'query whether the paragraph is centered',
|
||||
'qcstate': 'justifycenter',
|
||||
'tests': [
|
||||
{ 'id': 'JC_TEXT_SI',
|
||||
'rte1-id': 'q-justifycenter-0',
|
||||
'desc': 'query the "justifycenter" state',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': False },
|
||||
|
||||
{ 'id': 'JC_DIVa:c-1_SI',
|
||||
'rte1-id': 'q-justifycenter-1',
|
||||
'desc': 'query the "justifycenter" state',
|
||||
'pad': '<div align="center">foo[bar]baz</div>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'JC_Pa:c-1_SI',
|
||||
'rte1-id': 'q-justifycenter-2',
|
||||
'desc': 'query the "justifycenter" state',
|
||||
'pad': '<p align="center">foo[bar]baz</p>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'JC_SPANs:ta:c-1_SI',
|
||||
'rte1-id': 'q-justifycenter-3',
|
||||
'desc': 'query the "justifycenter" state',
|
||||
'pad': '<div style="text-align: center">foo[bar]baz</div>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'JC_SPAN.jc-1-SI',
|
||||
'desc': 'query the "justifycenter" state',
|
||||
'pad': '<span class="jc">foo[bar]baz</span>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'JC_MYJC-1-SI',
|
||||
'desc': 'query the "justifycenter" state',
|
||||
'pad': '<myjc>foo[bar]baz</myjc>',
|
||||
'expected': True }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'query whether the paragraph is justified',
|
||||
'qcstate': 'justifyfull',
|
||||
'tests': [
|
||||
{ 'id': 'JF_TEXT_SI',
|
||||
'rte1-id': 'q-justifyfull-0',
|
||||
'desc': 'query the "justifyfull" state',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': False },
|
||||
|
||||
{ 'id': 'JF_DIVa:j-1_SI',
|
||||
'rte1-id': 'q-justifyfull-1',
|
||||
'desc': 'query the "justifyfull" state',
|
||||
'pad': '<div align="justify">foo[bar]baz</div>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'JF_Pa:j-1_SI',
|
||||
'rte1-id': 'q-justifyfull-2',
|
||||
'desc': 'query the "justifyfull" state',
|
||||
'pad': '<p align="justify">foo[bar]baz</p>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'JF_SPANs:ta:j-1_SI',
|
||||
'rte1-id': 'q-justifyfull-3',
|
||||
'desc': 'query the "justifyfull" state',
|
||||
'pad': '<span style="text-align: justify">foo[bar]baz</span>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'JF_SPAN.jf-1-SI',
|
||||
'desc': 'query the "justifyfull" state',
|
||||
'pad': '<span class="jf">foo[bar]baz</span>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'JF_MYJF-1-SI',
|
||||
'desc': 'query the "justifyfull" state',
|
||||
'pad': '<myjf>foo[bar]baz</myjf>',
|
||||
'expected': True }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'query whether the paragraph is aligned left',
|
||||
'qcstate': 'justifyleft',
|
||||
'tests': [
|
||||
{ 'id': 'JL_TEXT_SI',
|
||||
'desc': 'query the "justifyleft" state',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': False },
|
||||
|
||||
{ 'id': 'JL_DIVa:l-1_SI',
|
||||
'rte1-id': 'q-justifyleft-0',
|
||||
'desc': 'query the "justifyleft" state',
|
||||
'pad': '<div align="left">foo[bar]baz</div>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'JL_Pa:l-1_SI',
|
||||
'rte1-id': 'q-justifyleft-1',
|
||||
'desc': 'query the "justifyleft" state',
|
||||
'pad': '<p align="left">foo[bar]baz</p>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'JL_SPANs:ta:l-1_SI',
|
||||
'rte1-id': 'q-justifyleft-2',
|
||||
'desc': 'query the "justifyleft" state',
|
||||
'pad': '<span style="text-align: left">foo[bar]baz</span>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'JL_SPAN.jl-1-SI',
|
||||
'desc': 'query the "justifyleft" state',
|
||||
'pad': '<span class="jl">foo[bar]baz</span>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'JL_MYJL-1-SI',
|
||||
'desc': 'query the "justifyleft" state',
|
||||
'pad': '<myjl>foo[bar]baz</myjl>',
|
||||
'expected': True }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'query whether the paragraph is aligned right',
|
||||
'qcstate': 'justifyright',
|
||||
'tests': [
|
||||
{ 'id': 'JR_TEXT_SI',
|
||||
'rte1-id': 'q-justifyright-0',
|
||||
'desc': 'query the "justifyright" state',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': False },
|
||||
|
||||
{ 'id': 'JR_DIVa:r-1_SI',
|
||||
'rte1-id': 'q-justifyright-1',
|
||||
'desc': 'query the "justifyright" state',
|
||||
'pad': '<div align="right">foo[bar]baz</div>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'JR_Pa:r-1_SI',
|
||||
'rte1-id': 'q-justifyright-2',
|
||||
'desc': 'query the "justifyright" state',
|
||||
'pad': '<p align="right">foo[bar]baz</p>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'JR_SPANs:ta:r-1_SI',
|
||||
'rte1-id': 'q-justifyright-3',
|
||||
'desc': 'query the "justifyright" state',
|
||||
'pad': '<span style="text-align: right">foo[bar]baz</span>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'JR_SPAN.jr-1-SI',
|
||||
'desc': 'query the "justifyright" state',
|
||||
'pad': '<span class="jr">foo[bar]baz</span>',
|
||||
'expected': True },
|
||||
|
||||
{ 'id': 'JR_MYJR-1-SI',
|
||||
'desc': 'query the "justifyright" state',
|
||||
'pad': '<myjr>foo[bar]baz</myjr>',
|
||||
'expected': True }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
QUERYSTATE_TESTS_CSS = {
|
||||
'id': 'QSC',
|
||||
'caption': 'queryCommandState Tests, using styleWithCSS',
|
||||
'checkAttrs': False,
|
||||
'checkStyle': False,
|
||||
'styleWithCSS': True,
|
||||
|
||||
'Proposed': QUERYSTATE_TESTS['Proposed']
|
||||
}
|
||||
|
@ -0,0 +1,226 @@
|
||||
|
||||
QUERYSUPPORTED_TESTS = {
|
||||
'id': 'Q',
|
||||
'caption': 'queryCommandSupported Tests',
|
||||
'pad': 'foo[bar]baz',
|
||||
'checkAttrs': False,
|
||||
'checkStyle': False,
|
||||
'styleWithCSS': False,
|
||||
'expected': True,
|
||||
|
||||
'Proposed': [
|
||||
{ 'desc': '',
|
||||
'tests': [
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'HTML5 commands',
|
||||
'tests': [
|
||||
{ 'id': 'SELECTALL_TEXT-1',
|
||||
'desc': 'check whether the "selectall" command is supported',
|
||||
'qcsupported': 'selectall' },
|
||||
|
||||
{ 'id': 'UNSELECT_TEXT-1',
|
||||
'desc': 'check whether the "unselect" command is supported',
|
||||
'qcsupported': 'unselect' },
|
||||
|
||||
{ 'id': 'UNDO_TEXT-1',
|
||||
'desc': 'check whether the "undo" command is supported',
|
||||
'qcsupported': 'undo' },
|
||||
|
||||
{ 'id': 'REDO_TEXT-1',
|
||||
'desc': 'check whether the "redo" command is supported',
|
||||
'qcsupported': 'redo' },
|
||||
|
||||
{ 'id': 'BOLD_TEXT-1',
|
||||
'desc': 'check whether the "bold" command is supported',
|
||||
'qcsupported': 'bold' },
|
||||
|
||||
{ 'id': 'BOLD_B',
|
||||
'desc': 'check whether the "bold" command is supported',
|
||||
'qcsupported': 'bold',
|
||||
'pad': '<b>foo[bar]baz</b>' },
|
||||
|
||||
{ 'id': 'ITALIC_TEXT-1',
|
||||
'desc': 'check whether the "italic" command is supported',
|
||||
'qcsupported': 'italic' },
|
||||
|
||||
{ 'id': 'ITALIC_I',
|
||||
'desc': 'check whether the "italic" command is supported',
|
||||
'qcsupported': 'italic',
|
||||
'pad': '<i>foo[bar]baz</i>' },
|
||||
|
||||
{ 'id': 'UNDERLINE_TEXT-1',
|
||||
'desc': 'check whether the "underline" command is supported',
|
||||
'qcsupported': 'underline' },
|
||||
|
||||
{ 'id': 'STRIKETHROUGH_TEXT-1',
|
||||
'desc': 'check whether the "strikethrough" command is supported',
|
||||
'qcsupported': 'strikethrough' },
|
||||
|
||||
{ 'id': 'SUBSCRIPT_TEXT-1',
|
||||
'desc': 'check whether the "subscript" command is supported',
|
||||
'qcsupported': 'subscript' },
|
||||
|
||||
{ 'id': 'SUPERSCRIPT_TEXT-1',
|
||||
'desc': 'check whether the "superscript" command is supported',
|
||||
'qcsupported': 'superscript' },
|
||||
|
||||
{ 'id': 'FORMATBLOCK_TEXT-1',
|
||||
'desc': 'check whether the "formatblock" command is supported',
|
||||
'qcsupported': 'formatblock' },
|
||||
|
||||
{ 'id': 'CREATELINK_TEXT-1',
|
||||
'desc': 'check whether the "createlink" command is supported',
|
||||
'qcsupported': 'createlink' },
|
||||
|
||||
{ 'id': 'UNLINK_TEXT-1',
|
||||
'desc': 'check whether the "unlink" command is supported',
|
||||
'qcsupported': 'unlink' },
|
||||
|
||||
{ 'id': 'INSERTHTML_TEXT-1',
|
||||
'desc': 'check whether the "inserthtml" command is supported',
|
||||
'qcsupported': 'inserthtml' },
|
||||
|
||||
{ 'id': 'INSERTHORIZONTALRULE_TEXT-1',
|
||||
'desc': 'check whether the "inserthorizontalrule" command is supported',
|
||||
'qcsupported': 'inserthorizontalrule' },
|
||||
|
||||
{ 'id': 'INSERTIMAGE_TEXT-1',
|
||||
'desc': 'check whether the "insertimage" command is supported',
|
||||
'qcsupported': 'insertimage' },
|
||||
|
||||
{ 'id': 'INSERTLINEBREAK_TEXT-1',
|
||||
'desc': 'check whether the "insertlinebreak" command is supported',
|
||||
'qcsupported': 'insertlinebreak' },
|
||||
|
||||
{ 'id': 'INSERTPARAGRAPH_TEXT-1',
|
||||
'desc': 'check whether the "insertparagraph" command is supported',
|
||||
'qcsupported': 'insertparagraph' },
|
||||
|
||||
{ 'id': 'INSERTORDEREDLIST_TEXT-1',
|
||||
'desc': 'check whether the "insertorderedlist" command is supported',
|
||||
'qcsupported': 'insertorderedlist' },
|
||||
|
||||
{ 'id': 'INSERTUNORDEREDLIST_TEXT-1',
|
||||
'desc': 'check whether the "insertunorderedlist" command is supported',
|
||||
'qcsupported': 'insertunorderedlist' },
|
||||
|
||||
{ 'id': 'INSERTTEXT_TEXT-1',
|
||||
'desc': 'check whether the "inserttext" command is supported',
|
||||
'qcsupported': 'inserttext' },
|
||||
|
||||
{ 'id': 'DELETE_TEXT-1',
|
||||
'desc': 'check whether the "delete" command is supported',
|
||||
'qcsupported': 'delete' },
|
||||
|
||||
{ 'id': 'FORWARDDELETE_TEXT-1',
|
||||
'desc': 'check whether the "forwarddelete" command is supported',
|
||||
'qcsupported': 'forwarddelete' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'MIDAS commands',
|
||||
'tests': [
|
||||
{ 'id': 'STYLEWITHCSS_TEXT-1',
|
||||
'desc': 'check whether the "styleWithCSS" command is supported',
|
||||
'qcsupported': 'styleWithCSS' },
|
||||
|
||||
{ 'id': 'CONTENTREADONLY_TEXT-1',
|
||||
'desc': 'check whether the "contentreadonly" command is supported',
|
||||
'qcsupported': 'contentreadonly' },
|
||||
|
||||
{ 'id': 'BACKCOLOR_TEXT-1',
|
||||
'desc': 'check whether the "backcolor" command is supported',
|
||||
'qcsupported': 'backcolor' },
|
||||
|
||||
{ 'id': 'FORECOLOR_TEXT-1',
|
||||
'desc': 'check whether the "forecolor" command is supported',
|
||||
'qcsupported': 'forecolor' },
|
||||
|
||||
{ 'id': 'HILITECOLOR_TEXT-1',
|
||||
'desc': 'check whether the "hilitecolor" command is supported',
|
||||
'qcsupported': 'hilitecolor' },
|
||||
|
||||
{ 'id': 'FONTNAME_TEXT-1',
|
||||
'desc': 'check whether the "fontname" command is supported',
|
||||
'qcsupported': 'fontname' },
|
||||
|
||||
{ 'id': 'FONTSIZE_TEXT-1',
|
||||
'desc': 'check whether the "fontsize" command is supported',
|
||||
'qcsupported': 'fontsize' },
|
||||
|
||||
{ 'id': 'INCREASEFONTSIZE_TEXT-1',
|
||||
'desc': 'check whether the "increasefontsize" command is supported',
|
||||
'qcsupported': 'increasefontsize' },
|
||||
|
||||
{ 'id': 'DECREASEFONTSIZE_TEXT-1',
|
||||
'desc': 'check whether the "decreasefontsize" command is supported',
|
||||
'qcsupported': 'decreasefontsize' },
|
||||
|
||||
{ 'id': 'HEADING_TEXT-1',
|
||||
'desc': 'check whether the "heading" command is supported',
|
||||
'qcsupported': 'heading' },
|
||||
|
||||
{ 'id': 'INDENT_TEXT-1',
|
||||
'desc': 'check whether the "indent" command is supported',
|
||||
'qcsupported': 'indent' },
|
||||
|
||||
{ 'id': 'OUTDENT_TEXT-1',
|
||||
'desc': 'check whether the "outdent" command is supported',
|
||||
'qcsupported': 'outdent' },
|
||||
|
||||
{ 'id': 'CREATEBOOKMARK_TEXT-1',
|
||||
'desc': 'check whether the "createbookmark" command is supported',
|
||||
'qcsupported': 'createbookmark' },
|
||||
|
||||
{ 'id': 'UNBOOKMARK_TEXT-1',
|
||||
'desc': 'check whether the "unbookmark" command is supported',
|
||||
'qcsupported': 'unbookmark' },
|
||||
|
||||
{ 'id': 'JUSTIFYCENTER_TEXT-1',
|
||||
'desc': 'check whether the "justifycenter" command is supported',
|
||||
'qcsupported': 'justifycenter' },
|
||||
|
||||
{ 'id': 'JUSTIFYFULL_TEXT-1',
|
||||
'desc': 'check whether the "justifyfull" command is supported',
|
||||
'qcsupported': 'justifyfull' },
|
||||
|
||||
{ 'id': 'JUSTIFYLEFT_TEXT-1',
|
||||
'desc': 'check whether the "justifyleft" command is supported',
|
||||
'qcsupported': 'justifyleft' },
|
||||
|
||||
{ 'id': 'JUSTIFYRIGHT_TEXT-1',
|
||||
'desc': 'check whether the "justifyright" command is supported',
|
||||
'qcsupported': 'justifyright' },
|
||||
|
||||
{ 'id': 'REMOVEFORMAT_TEXT-1',
|
||||
'desc': 'check whether the "removeformat" command is supported',
|
||||
'qcsupported': 'removeformat' },
|
||||
|
||||
{ 'id': 'COPY_TEXT-1',
|
||||
'desc': 'check whether the "copy" command is supported',
|
||||
'qcsupported': 'copy' },
|
||||
|
||||
{ 'id': 'CUT_TEXT-1',
|
||||
'desc': 'check whether the "cut" command is supported',
|
||||
'qcsupported': 'cut' },
|
||||
|
||||
{ 'id': 'PASTE_TEXT-1',
|
||||
'desc': 'check whether the "paste" command is supported',
|
||||
'qcsupported': 'paste' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'Other tests',
|
||||
'tests': [
|
||||
{ 'id': 'garbage-1_TEXT-1',
|
||||
'desc': 'check correct return value with garbage input',
|
||||
'qcsupported': '#!#@7',
|
||||
'expected': False }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,429 @@
|
||||
|
||||
QUERYVALUE_TESTS = {
|
||||
'id': 'QV',
|
||||
'caption': 'queryCommandValue Tests',
|
||||
'checkAttrs': False,
|
||||
'checkStyle': False,
|
||||
'styleWithCSS': False,
|
||||
|
||||
'Proposed': [
|
||||
{ 'desc': '',
|
||||
'tests': [
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[HTML5] query bold value',
|
||||
'qcvalue': 'bold',
|
||||
'tests': [
|
||||
{ 'id': 'B_TEXT_SI',
|
||||
'desc': 'query the "bold" value',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': 'false' },
|
||||
|
||||
{ 'id': 'B_B-1_SI',
|
||||
'desc': 'query the "bold" value',
|
||||
'pad': '<b>foo[bar]baz</b>',
|
||||
'expected': 'true' },
|
||||
|
||||
{ 'id': 'B_STRONG-1_SI',
|
||||
'desc': 'query the "bold" value',
|
||||
'pad': '<strong>foo[bar]baz</strong>',
|
||||
'expected': 'true' },
|
||||
|
||||
{ 'id': 'B_SPANs:fw:b-1_SI',
|
||||
'desc': 'query the "bold" value',
|
||||
'pad': '<span style="font-weight: bold">foo[bar]baz</span>',
|
||||
'expected': 'true' },
|
||||
|
||||
{ 'id': 'B_SPANs:fw:n-1_SI',
|
||||
'desc': 'query the "bold" value',
|
||||
'pad': '<span style="font-weight: normal">foo[bar]baz</span>',
|
||||
'expected': 'false' },
|
||||
|
||||
{ 'id': 'B_Bs:fw:n-1_SI',
|
||||
'desc': 'query the "bold" value',
|
||||
'pad': '<b><span style="font-weight: normal">foo[bar]baz</span></b>',
|
||||
'expected': 'false' },
|
||||
|
||||
{ 'id': 'B_SPAN.b-1_SI',
|
||||
'desc': 'query the "bold" value',
|
||||
'pad': '<span class="b">foo[bar]baz</span>',
|
||||
'expected': 'true' },
|
||||
|
||||
{ 'id': 'B_MYB-1-SI',
|
||||
'desc': 'query the "bold" value',
|
||||
'pad': '<myb>foo[bar]baz</myb>',
|
||||
'expected': 'true' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[HTML5] query italic value',
|
||||
'qcvalue': 'italic',
|
||||
'tests': [
|
||||
{ 'id': 'I_TEXT_SI',
|
||||
'desc': 'query the "bold" value',
|
||||
'pad': 'foo[bar]baz',
|
||||
'expected': 'false' },
|
||||
|
||||
{ 'id': 'I_I-1_SI',
|
||||
'desc': 'query the "bold" value',
|
||||
'pad': '<i>foo[bar]baz</i>',
|
||||
'expected': 'true' },
|
||||
|
||||
{ 'id': 'I_EM-1_SI',
|
||||
'desc': 'query the "bold" value',
|
||||
'pad': '<em>foo[bar]baz</em>',
|
||||
'expected': 'true' },
|
||||
|
||||
{ 'id': 'I_SPANs:fs:i-1_SI',
|
||||
'desc': 'query the "bold" value',
|
||||
'pad': '<span style="font-style: italic">foo[bar]baz</span>',
|
||||
'expected': 'true' },
|
||||
|
||||
{ 'id': 'I_SPANs:fs:n-1_SI',
|
||||
'desc': 'query the "bold" value',
|
||||
'pad': '<span style="font-style: normal">foo[bar]baz</span>',
|
||||
'expected': 'false' },
|
||||
|
||||
{ 'id': 'I_I-SPANs:fs:n-1_SI',
|
||||
'desc': 'query the "bold" value',
|
||||
'pad': '<i><span style="font-style: normal">foo[bar]baz</span></i>',
|
||||
'expected': 'false' },
|
||||
|
||||
{ 'id': 'I_SPAN.i-1_SI',
|
||||
'desc': 'query the "italic" value',
|
||||
'pad': '<span class="i">foo[bar]baz</span>',
|
||||
'expected': 'true' },
|
||||
|
||||
{ 'id': 'I_MYI-1-SI',
|
||||
'desc': 'query the "italic" value',
|
||||
'pad': '<myi>foo[bar]baz</myi>',
|
||||
'expected': 'true' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[HTML5] query block formatting value',
|
||||
'qcvalue': 'formatblock',
|
||||
'tests': [
|
||||
{ 'id': 'FB_TEXT-1_SC',
|
||||
'desc': 'query the "formatBlock" value',
|
||||
'pad': 'foobar^baz',
|
||||
'expected': '',
|
||||
'accept': 'normal' },
|
||||
|
||||
{ 'id': 'FB_H1-1_SC',
|
||||
'desc': 'query the "formatBlock" value',
|
||||
'pad': '<h1>foobar^baz</h1>',
|
||||
'expected': 'h1' },
|
||||
|
||||
{ 'id': 'FB_PRE-1_SC',
|
||||
'desc': 'query the "formatBlock" value',
|
||||
'pad': '<pre>foobar^baz</pre>',
|
||||
'expected': 'pre' },
|
||||
|
||||
{ 'id': 'FB_BQ-1_SC',
|
||||
'desc': 'query the "formatBlock" value',
|
||||
'pad': '<blockquote>foobar^baz</blockquote>',
|
||||
'expected': 'blockquote' },
|
||||
|
||||
{ 'id': 'FB_ADDRESS-1_SC',
|
||||
'desc': 'query the "formatBlock" value',
|
||||
'pad': '<address>foobar^baz</address>',
|
||||
'expected': 'address' },
|
||||
|
||||
{ 'id': 'FB_H1-H2-1_SC',
|
||||
'desc': 'query the "formatBlock" value',
|
||||
'pad': '<h1>foo<h2>ba^r</h2>baz</h1>',
|
||||
'expected': 'h2' },
|
||||
|
||||
{ 'id': 'FB_H1-H2-1_SL',
|
||||
'desc': 'query the "formatBlock" value on oblique selection (outermost formatting expected)',
|
||||
'pad': '<h1>fo[o<h2>ba]r</h2>baz</h1>',
|
||||
'expected': 'h1' },
|
||||
|
||||
{ 'id': 'FB_H1-H2-1_SR',
|
||||
'desc': 'query the "formatBlock" value on oblique selection (outermost formatting expected)',
|
||||
'pad': '<h1>foo<h2>b[ar</h2>ba]z</h1>',
|
||||
'expected': 'h1' },
|
||||
|
||||
{ 'id': 'FB_TEXT-ADDRESS-1_SL',
|
||||
'desc': 'query the "formatBlock" value on oblique selection (outermost formatting expected)',
|
||||
'pad': 'fo[o<ADDRESS>ba]r</ADDRESS>baz',
|
||||
'expected': '',
|
||||
'accept': 'normal' },
|
||||
|
||||
{ 'id': 'FB_TEXT-ADDRESS-1_SR',
|
||||
'desc': 'query the "formatBlock" value on oblique selection (outermost formatting expected)',
|
||||
'pad': 'foo<ADDRESS>b[ar</ADDRESS>ba]z',
|
||||
'expected': '',
|
||||
'accept': 'normal' },
|
||||
|
||||
{ 'id': 'FB_H1-H2.TEXT.H2-1_SM',
|
||||
'desc': 'query the "formatBlock" value on oblique selection (outermost formatting expected)',
|
||||
'pad': '<h1><h2>fo[o</h2>bar<h2>b]az</h2></h1>',
|
||||
'expected': 'h1' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[MIDAS] query heading type',
|
||||
'qcvalue': 'heading',
|
||||
'tests': [
|
||||
{ 'id': 'H_H1-1_SC',
|
||||
'desc': 'query the "heading" type',
|
||||
'pad': '<h1>foobar^baz</h1>',
|
||||
'expected': 'h1',
|
||||
'accept': '<h1>' },
|
||||
|
||||
{ 'id': 'H_H3-1_SC',
|
||||
'desc': 'query the "heading" type',
|
||||
'pad': '<h3>foobar^baz</h3>',
|
||||
'expected': 'h3',
|
||||
'accept': '<h3>' },
|
||||
|
||||
{ 'id': 'H_H1-H2-H3-H4-1_SC',
|
||||
'desc': 'query the "heading" type within nested heading tags',
|
||||
'pad': '<h1><h2><h3><h4>foobar^baz</h4></h3></h2></h1>',
|
||||
'expected': 'h4',
|
||||
'accept': '<h4>' },
|
||||
|
||||
{ 'id': 'H_P-1_SC',
|
||||
'desc': 'query the "heading" type outside of a heading',
|
||||
'pad': '<p>foobar^baz</p>',
|
||||
'expected': '' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[MIDAS] query font name',
|
||||
'qcvalue': 'fontname',
|
||||
'tests': [
|
||||
{ 'id': 'FN_FONTf:a-1_SI',
|
||||
'rte1-id': 'q-fontname-0',
|
||||
'desc': 'query the "fontname" value',
|
||||
'pad': '<font face="arial">foo[bar]baz</font>',
|
||||
'expected': 'arial' },
|
||||
|
||||
{ 'id': 'FN_SPANs:ff:a-1_SI',
|
||||
'rte1-id': 'q-fontname-1',
|
||||
'desc': 'query the "fontname" value',
|
||||
'pad': '<span style="font-family: arial">foo[bar]baz</span>',
|
||||
'expected': 'arial' },
|
||||
|
||||
{ 'id': 'FN_FONTf:a.s:ff:c-1_SI',
|
||||
'rte1-id': 'q-fontname-2',
|
||||
'desc': 'query the "fontname" value',
|
||||
'pad': '<font face="arial" style="font-family: courier">foo[bar]baz</font>',
|
||||
'expected': 'courier' },
|
||||
|
||||
{ 'id': 'FN_FONTf:a-FONTf:c-1_SI',
|
||||
'rte1-id': 'q-fontname-3',
|
||||
'desc': 'query the "fontname" value',
|
||||
'pad': '<font face="arial"><font face="courier">foo[bar]baz</font></font>',
|
||||
'expected': 'courier' },
|
||||
|
||||
{ 'id': 'FN_SPANs:ff:c-FONTf:a-1_SI',
|
||||
'rte1-id': 'q-fontname-4',
|
||||
'desc': 'query the "fontname" value',
|
||||
'pad': '<span style="font-family: courier"><font face="arial">foo[bar]baz</font></span>',
|
||||
'expected': 'arial' },
|
||||
|
||||
{ 'id': 'FN_SPAN.fs18px-1_SI',
|
||||
'desc': 'query the "fontname" value',
|
||||
'pad': '<span class="courier">foo[bar]baz</span>',
|
||||
'expected': 'courier' },
|
||||
|
||||
{ 'id': 'FN_MYCOURIER-1-SI',
|
||||
'desc': 'query the "fontname" value',
|
||||
'pad': '<mycourier>foo[bar]baz</mycourier>',
|
||||
'expected': 'courier' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[MIDAS] query font size',
|
||||
'qcvalue': 'fontsize',
|
||||
'tests': [
|
||||
{ 'id': 'FS_FONTsz:4-1_SI',
|
||||
'rte1-id': 'q-fontsize-0',
|
||||
'desc': 'query the "fontsize" value',
|
||||
'pad': '<font size=4>foo[bar]baz</font>',
|
||||
'expected': '18px' },
|
||||
|
||||
{ 'id': 'FS_FONTs:fs:l-1_SI',
|
||||
'desc': 'query the "fontsize" value',
|
||||
'pad': '<font style="font-size: large">foo[bar]baz</font>',
|
||||
'expected': '18px' },
|
||||
|
||||
{ 'id': 'FS_FONT.ass.s:fs:l-1_SI',
|
||||
'rte1-id': 'q-fontsize-1',
|
||||
'desc': 'query the "fontsize" value',
|
||||
'pad': '<font class="Apple-style-span" style="font-size: large">foo[bar]baz</font>',
|
||||
'expected': '18px' },
|
||||
|
||||
{ 'id': 'FS_FONTsz:1.s:fs:xl-1_SI',
|
||||
'rte1-id': 'q-fontsize-2',
|
||||
'desc': 'query the "fontsize" value',
|
||||
'pad': '<font size=1 style="font-size: x-large">foo[bar]baz</font>',
|
||||
'expected': '24px' },
|
||||
|
||||
{ 'id': 'FS_SPAN.large-1_SI',
|
||||
'desc': 'query the "fontsize" value',
|
||||
'pad': '<span class="large">foo[bar]baz</span>',
|
||||
'expected': 'large' },
|
||||
|
||||
{ 'id': 'FS_SPAN.fs18px-1_SI',
|
||||
'desc': 'query the "fontsize" value',
|
||||
'pad': '<span class="fs18px">foo[bar]baz</span>',
|
||||
'expected': '18px' },
|
||||
|
||||
{ 'id': 'FA_MYLARGE-1-SI',
|
||||
'desc': 'query the "fontsize" value',
|
||||
'pad': '<mylarge>foo[bar]baz</mylarge>',
|
||||
'expected': 'large' },
|
||||
|
||||
{ 'id': 'FA_MYFS18PX-1-SI',
|
||||
'desc': 'query the "fontsize" value',
|
||||
'pad': '<myfs18px>foo[bar]baz</myfs18px>',
|
||||
'expected': '18px' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[MIDAS] query background color',
|
||||
'qcvalue': 'backcolor',
|
||||
'tests': [
|
||||
{ 'id': 'BC_FONTs:bc:fca-1_SI',
|
||||
'rte1-id': 'q-backcolor-0',
|
||||
'desc': 'query the "backcolor" value',
|
||||
'pad': '<font style="background-color: #ffccaa">foo[bar]baz</font>',
|
||||
'expected': '#ffccaa' },
|
||||
|
||||
{ 'id': 'BC_SPANs:bc:abc-1_SI',
|
||||
'rte1-id': 'q-backcolor-2',
|
||||
'desc': 'query the "backcolor" value',
|
||||
'pad': '<span style="background-color: #aabbcc">foo[bar]baz</span>',
|
||||
'expected': '#aabbcc' },
|
||||
|
||||
{ 'id': 'BC_FONTs:bc:084-SPAN-1_SI',
|
||||
'desc': 'query the "backcolor" value, where the color was set on an ancestor',
|
||||
'pad': '<font style="background-color: #008844"><span>foo[bar]baz</span></font>',
|
||||
'expected': '#008844' },
|
||||
|
||||
{ 'id': 'BC_SPANs:bc:cde-SPAN-1_SI',
|
||||
'desc': 'query the "backcolor" value, where the color was set on an ancestor',
|
||||
'pad': '<span style="background-color: #ccddee"><span>foo[bar]baz</span></span>',
|
||||
'expected': '#ccddee' },
|
||||
|
||||
{ 'id': 'BC_SPAN.ass.s:bc:rgb-1_SI',
|
||||
'rte1-id': 'q-backcolor-1',
|
||||
'desc': 'query the "backcolor" value',
|
||||
'pad': '<span class="Apple-style-span" style="background-color: rgb(255, 0, 0)">foo[bar]baz</span>',
|
||||
'expected': '#ff0000' },
|
||||
|
||||
{ 'id': 'BC_SPAN.bcred-1_SI',
|
||||
'desc': 'query the "backcolor" value',
|
||||
'pad': '<span class="bcred">foo[bar]baz</span>',
|
||||
'expected': 'red' },
|
||||
|
||||
{ 'id': 'BC_MYBCRED-1-SI',
|
||||
'desc': 'query the "backcolor" value',
|
||||
'pad': '<mybcred>foo[bar]baz</mybcred>',
|
||||
'expected': 'red' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[MIDAS] query text color',
|
||||
'qcvalue': 'forecolor',
|
||||
'tests': [
|
||||
{ 'id': 'FC_FONTc:f00-1_SI',
|
||||
'rte1-id': 'q-forecolor-0',
|
||||
'desc': 'query the "forecolor" value',
|
||||
'pad': '<font color="#ff0000">foo[bar]baz</font>',
|
||||
'expected': '#ff0000' },
|
||||
|
||||
{ 'id': 'FC_SPANs:c:0f0-1_SI',
|
||||
'rte1-id': 'q-forecolor-1',
|
||||
'desc': 'query the "forecolor" value',
|
||||
'pad': '<span style="color: #00ff00">foo[bar]baz</span>',
|
||||
'expected': '#00ff00' },
|
||||
|
||||
{ 'id': 'FC_FONTc:333.s:c:999-1_SI',
|
||||
'rte1-id': 'q-forecolor-2',
|
||||
'desc': 'query the "forecolor" value',
|
||||
'pad': '<font color="#333333" style="color: #999999">foo[bar]baz</font>',
|
||||
'expected': '#999999' },
|
||||
|
||||
{ 'id': 'FC_FONTc:641-SPAN-1_SI',
|
||||
'desc': 'query the "forecolor" value, where the color was set on an ancestor',
|
||||
'pad': '<font color="#664411"><span>foo[bar]baz</span></font>',
|
||||
'expected': '#664411' },
|
||||
|
||||
{ 'id': 'FC_SPANs:c:d95-SPAN-1_SI',
|
||||
'desc': 'query the "forecolor" value, where the color was set on an ancestor',
|
||||
'pad': '<span style="color: #dd9955"><span>foo[bar]baz</span></span>',
|
||||
'expected': '#dd9955' },
|
||||
|
||||
{ 'id': 'FC_SPAN.red-1_SI',
|
||||
'desc': 'query the "forecolor" value',
|
||||
'pad': '<span class="red">foo[bar]baz</span>',
|
||||
'expected': 'red' },
|
||||
|
||||
{ 'id': 'FC_MYRED-1-SI',
|
||||
'desc': 'query the "forecolor" value',
|
||||
'pad': '<myred>foo[bar]baz</myred>',
|
||||
'expected': 'red' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': '[MIDAS] query hilight color (same as background color)',
|
||||
'qcvalue': 'hilitecolor',
|
||||
'tests': [
|
||||
{ 'id': 'HC_FONTs:bc:fc0-1_SI',
|
||||
'rte1-id': 'q-hilitecolor-0',
|
||||
'desc': 'query the "hilitecolor" value',
|
||||
'pad': '<font style="background-color: #ffcc00">foo[bar]baz</font>',
|
||||
'expected': '#ffcc00' },
|
||||
|
||||
{ 'id': 'HC_SPANs:bc:a0c-1_SI',
|
||||
'rte1-id': 'q-hilitecolor-2',
|
||||
'desc': 'query the "hilitecolor" value',
|
||||
'pad': '<span style="background-color: #aa00cc">foo[bar]baz</span>',
|
||||
'expected': '#aa00cc' },
|
||||
|
||||
{ 'id': 'HC_SPAN.ass.s:bc:rgb-1_SI',
|
||||
'rte1-id': 'q-hilitecolor-1',
|
||||
'desc': 'query the "hilitecolor" value',
|
||||
'pad': '<span class="Apple-style-span" style="background-color: rgb(255, 0, 0)">foo[bar]baz</span>',
|
||||
'expected': '#ff0000' },
|
||||
|
||||
{ 'id': 'HC_FONTs:bc:83e-SPAN-1_SI',
|
||||
'desc': 'query the "hilitecolor" value, where the color was set on an ancestor',
|
||||
'pad': '<font style="background-color: #8833ee"><span>foo[bar]baz</span></font>',
|
||||
'expected': '#8833ee' },
|
||||
|
||||
{ 'id': 'HC_SPANs:bc:b12-SPAN-1_SI',
|
||||
'desc': 'query the "hilitecolor" value, where the color was set on an ancestor',
|
||||
'pad': '<span style="background-color: #bb1122"><span>foo[bar]baz</span></span>',
|
||||
'expected': '#bb1122' },
|
||||
|
||||
{ 'id': 'HC_SPAN.bcred-1_SI',
|
||||
'desc': 'query the "hilitecolor" value',
|
||||
'pad': '<span class="bcred">foo[bar]baz</span>',
|
||||
'expected': 'red' },
|
||||
|
||||
{ 'id': 'HC_MYBCRED-1-SI',
|
||||
'desc': 'query the "hilitecolor" value',
|
||||
'pad': '<mybcred>foo[bar]baz</mybcred>',
|
||||
'expected': 'red' }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
QUERYVALUE_TESTS_CSS = {
|
||||
'id': 'QVC',
|
||||
'caption': 'queryCommandValue Tests, using styleWithCSS',
|
||||
'checkAttrs': False,
|
||||
'checkStyle': False,
|
||||
'styleWithCSS': True,
|
||||
|
||||
'Proposed': QUERYVALUE_TESTS['Proposed']
|
||||
}
|
||||
|
@ -0,0 +1,772 @@
|
||||
|
||||
SELECTION_TESTS = {
|
||||
'id': 'S',
|
||||
'caption': 'Selection Tests',
|
||||
'checkAttrs': True,
|
||||
'checkStyle': True,
|
||||
'styleWithCSS': False,
|
||||
|
||||
'Proposed': [
|
||||
{ 'desc': '',
|
||||
'command': '',
|
||||
'tests': [
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'selectall',
|
||||
'command': 'selectall',
|
||||
'tests': [
|
||||
{ 'id': 'SELALL_TEXT-1_SI',
|
||||
'desc': 'select all, text only',
|
||||
'pad': 'foo [bar] baz',
|
||||
'expected': [ '[foo bar baz]',
|
||||
'{foo bar baz}' ] },
|
||||
|
||||
{ 'id': 'SELALL_I-1_SI',
|
||||
'desc': 'select all, with outer tags',
|
||||
'pad': '<i>foo [bar] baz</i>',
|
||||
'expected': '{<i>foo bar baz</i>}' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'unselect',
|
||||
'command': 'unselect',
|
||||
'tests': [
|
||||
{ 'id': 'UNSEL_TEXT-1_SI',
|
||||
'desc': 'unselect',
|
||||
'pad': 'foo [bar] baz',
|
||||
'expected': 'foo bar baz' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'sel.modify (generic)',
|
||||
'tests': [
|
||||
{ 'id': 'SM:m.f.c_TEXT-1_SC-1',
|
||||
'desc': 'move caret 1 character forward',
|
||||
'function': 'sel.modify("move", "forward", "character");',
|
||||
'pad': 'foo b^ar baz',
|
||||
'expected': 'foo ba^r baz' },
|
||||
|
||||
{ 'id': 'SM:m.b.c_TEXT-1_SC-1',
|
||||
'desc': 'move caret 1 character backward',
|
||||
'function': 'sel.modify("move", "backward", "character");',
|
||||
'pad': 'foo b^ar baz',
|
||||
'expected': 'foo ^bar baz' },
|
||||
|
||||
{ 'id': 'SM:m.f.c_TEXT-1_SI-1',
|
||||
'desc': 'move caret forward (sollapse selection)',
|
||||
'function': 'sel.modify("move", "forward", "character");',
|
||||
'pad': 'foo [bar] baz',
|
||||
'expected': 'foo bar^ baz' },
|
||||
|
||||
{ 'id': 'SM:m.b.c_TEXT-1_SI-1',
|
||||
'desc': 'move caret backward (collapse selection)',
|
||||
'function': 'sel.modify("move", "backward", "character");',
|
||||
'pad': 'foo [bar] baz',
|
||||
'expected': 'foo ^bar baz' },
|
||||
|
||||
{ 'id': 'SM:m.f.w_TEXT-1_SC-1',
|
||||
'desc': 'move caret 1 word forward',
|
||||
'function': 'sel.modify("move", "forward", "word");',
|
||||
'pad': 'foo b^ar baz',
|
||||
'expected': 'foo bar^ baz' },
|
||||
|
||||
{ 'id': 'SM:m.f.w_TEXT-1_SC-2',
|
||||
'desc': 'move caret 1 word forward',
|
||||
'function': 'sel.modify("move", "forward", "word");',
|
||||
'pad': 'foo^ bar baz',
|
||||
'expected': 'foo bar^ baz' },
|
||||
|
||||
{ 'id': 'SM:m.f.w_TEXT-1_SI-1',
|
||||
'desc': 'move caret 1 word forward from non-collapsed selection',
|
||||
'function': 'sel.modify("move", "forward", "word");',
|
||||
'pad': 'foo [bar] baz',
|
||||
'expected': 'foo bar baz^' },
|
||||
|
||||
{ 'id': 'SM:m.b.w_TEXT-1_SC-1',
|
||||
'desc': 'move caret 1 word backward',
|
||||
'function': 'sel.modify("move", "backward", "word");',
|
||||
'pad': 'foo b^ar baz',
|
||||
'expected': 'foo ^bar baz' },
|
||||
|
||||
{ 'id': 'SM:m.b.w_TEXT-1_SC-3',
|
||||
'desc': 'move caret 1 word backward',
|
||||
'function': 'sel.modify("move", "backward", "word");',
|
||||
'pad': 'foo bar ^baz',
|
||||
'expected': 'foo ^bar baz' },
|
||||
|
||||
{ 'id': 'SM:m.b.w_TEXT-1_SI-1',
|
||||
'desc': 'move caret 1 word backward from non-collapsed selection',
|
||||
'function': 'sel.modify("move", "backward", "word");',
|
||||
'pad': 'foo [bar] baz',
|
||||
'expected': '^foo bar baz' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'sel.modify: move forward over combining diacritics, etc.',
|
||||
'tests': [
|
||||
{ 'id': 'SM:m.f.c_CHAR-2_SC-1',
|
||||
'desc': 'move 1 character forward over combined o with diaeresis',
|
||||
'function': 'sel.modify("move", "forward", "character");',
|
||||
'pad': 'fo^öbarbaz',
|
||||
'expected': 'foö^barbaz' },
|
||||
|
||||
{ 'id': 'SM:m.f.c_CHAR-3_SC-1',
|
||||
'desc': 'move 1 character forward over character with combining diaeresis above',
|
||||
'function': 'sel.modify("move", "forward", "character");',
|
||||
'pad': 'fo^öbarbaz',
|
||||
'expected': 'foö^barbaz' },
|
||||
|
||||
{ 'id': 'SM:m.f.c_CHAR-4_SC-1',
|
||||
'desc': 'move 1 character forward over character with combining diaeresis below',
|
||||
'function': 'sel.modify("move", "forward", "character");',
|
||||
'pad': 'fo^o̤barbaz',
|
||||
'expected': 'foo̤^barbaz' },
|
||||
|
||||
{ 'id': 'SM:m.f.c_CHAR-5_SC-1',
|
||||
'desc': 'move 1 character forward over character with combining diaeresis above and below',
|
||||
'function': 'sel.modify("move", "forward", "character");',
|
||||
'pad': 'fo^ö̤barbaz',
|
||||
'expected': 'foö̤^barbaz' },
|
||||
|
||||
{ 'id': 'SM:m.f.c_CHAR-5_SI-1',
|
||||
'desc': 'move 1 character forward over character with combining diaeresis above and below, selection on diaeresis above',
|
||||
'function': 'sel.modify("move", "forward", "character");',
|
||||
'pad': 'foo[̈]̤barbaz',
|
||||
'expected': 'foö̤^barbaz' },
|
||||
|
||||
{ 'id': 'SM:m.f.c_CHAR-5_SI-2',
|
||||
'desc': 'move 1 character forward over character with combining diaeresis above and below, selection on diaeresis below',
|
||||
'function': 'sel.modify("move", "forward", "character");',
|
||||
'pad': 'foö[̤]barbaz',
|
||||
'expected': 'foö̤^barbaz' },
|
||||
|
||||
{ 'id': 'SM:m.f.c_CHAR-5_SL',
|
||||
'desc': 'move 1 character forward over character with combining diaeresis above and below, selection oblique on diaeresis and preceding text',
|
||||
'function': 'sel.modify("move", "forward", "character");',
|
||||
'pad': 'fo[ö]̤barbaz',
|
||||
'expected': 'foö̤^barbaz' },
|
||||
|
||||
{ 'id': 'SM:m.f.c_CHAR-5_SR',
|
||||
'desc': 'move 1 character forward over character with combining diaeresis above and below, selection oblique on diaeresis and following text',
|
||||
'function': 'sel.modify("move", "forward", "character");',
|
||||
'pad': 'foö[̤bar]baz',
|
||||
'expected': 'foö̤bar^baz' },
|
||||
|
||||
{ 'id': 'SM:m.f.c_CHAR-6_SC-1',
|
||||
'desc': 'move 1 character forward over character with enclosing square',
|
||||
'function': 'sel.modify("move", "forward", "character");',
|
||||
'pad': 'fo^o⃞barbaz',
|
||||
'expected': 'foo⃞^barbaz' },
|
||||
|
||||
{ 'id': 'SM:m.f.c_CHAR-7_SC-1',
|
||||
'desc': 'move 1 character forward over character with combining long solidus overlay',
|
||||
'function': 'sel.modify("move", "forward", "character");',
|
||||
'pad': 'fo^o̸barbaz',
|
||||
'expected': 'foo̸^barbaz' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'sel.modify: move backward over combining diacritics, etc.',
|
||||
'tests': [
|
||||
{ 'id': 'SM:m.b.c_CHAR-2_SC-1',
|
||||
'desc': 'move 1 character backward over combined o with diaeresis',
|
||||
'function': 'sel.modify("move", "backward", "character");',
|
||||
'pad': 'foö^barbaz',
|
||||
'expected': 'fo^öbarbaz' },
|
||||
|
||||
{ 'id': 'SM:m.b.c_CHAR-3_SC-1',
|
||||
'desc': 'move 1 character backward over character with combining diaeresis above',
|
||||
'function': 'sel.modify("move", "backward", "character");',
|
||||
'pad': 'foö^barbaz',
|
||||
'expected': 'fo^öbarbaz' },
|
||||
|
||||
{ 'id': 'SM:m.b.c_CHAR-4_SC-1',
|
||||
'desc': 'move 1 character backward over character with combining diaeresis below',
|
||||
'function': 'sel.modify("move", "backward", "character");',
|
||||
'pad': 'foo̤^barbaz',
|
||||
'expected': 'fo^o̤barbaz' },
|
||||
|
||||
{ 'id': 'SM:m.b.c_CHAR-5_SC-1',
|
||||
'desc': 'move 1 character backward over character with combining diaeresis above and below',
|
||||
'function': 'sel.modify("move", "backward", "character");',
|
||||
'pad': 'foö̤^barbaz',
|
||||
'expected': 'fo^ö̤barbaz' },
|
||||
|
||||
{ 'id': 'SM:m.b.c_CHAR-5_SI-1',
|
||||
'desc': 'move 1 character backward over character with combining diaeresis above and below, selection on diaeresis above',
|
||||
'function': 'sel.modify("move", "backward", "character");',
|
||||
'pad': 'foo[̈]̤barbaz',
|
||||
'expected': 'fo^ö̤barbaz' },
|
||||
|
||||
{ 'id': 'SM:m.b.c_CHAR-5_SI-2',
|
||||
'desc': 'move 1 character backward over character with combining diaeresis above and below, selection on diaeresis below',
|
||||
'function': 'sel.modify("move", "backward", "character");',
|
||||
'pad': 'foö[̤]barbaz',
|
||||
'expected': 'fo^ö̤barbaz' },
|
||||
|
||||
{ 'id': 'SM:m.b.c_CHAR-5_SL',
|
||||
'desc': 'move 1 character backward over character with combining diaeresis above and below, selection oblique on diaeresis and preceding text',
|
||||
'function': 'sel.modify("move", "backward", "character");',
|
||||
'pad': 'fo[ö]̤barbaz',
|
||||
'expected': 'fo^ö̤barbaz' },
|
||||
|
||||
{ 'id': 'SM:m.b.c_CHAR-5_SR',
|
||||
'desc': 'move 1 character backward over character with combining diaeresis above and below, selection oblique on diaeresis and following text',
|
||||
'function': 'sel.modify("move", "backward", "character");',
|
||||
'pad': 'foö[̤bar]baz',
|
||||
'expected': 'fo^ö̤barbaz' },
|
||||
|
||||
{ 'id': 'SM:m.b.c_CHAR-6_SC-1',
|
||||
'desc': 'move 1 character backward over character with enclosing square',
|
||||
'function': 'sel.modify("move", "backward", "character");',
|
||||
'pad': 'foo⃞^barbaz',
|
||||
'expected': 'fo^o⃞barbaz' },
|
||||
|
||||
{ 'id': 'SM:m.b.c_CHAR-7_SC-1',
|
||||
'desc': 'move 1 character backward over character with combining long solidus overlay',
|
||||
'function': 'sel.modify("move", "backward", "character");',
|
||||
'pad': 'foo̸^barbaz',
|
||||
'expected': 'fo^o̸barbaz' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'sel.modify: move forward/backward/left/right in RTL text',
|
||||
'tests': [
|
||||
{ 'id': 'SM:m.f.c_Pdir:rtl-1_SC-1',
|
||||
'desc': 'move caret forward 1 character in right-to-left text',
|
||||
'function': 'sel.modify("move", "forward", "character");',
|
||||
'pad': '<p dir="rtl">foo b^ar baz</p>',
|
||||
'expected': '<p dir="rtl">foo ba^r baz</p>' },
|
||||
|
||||
{ 'id': 'SM:m.b.c_Pdir:rtl-1_SC-1',
|
||||
'desc': 'move caret backward 1 character in right-to-left text',
|
||||
'function': 'sel.modify("move", "backward", "character");',
|
||||
'pad': '<p dir="rtl">foo ba^r baz</p>',
|
||||
'expected': '<p dir="rtl">foo b^ar baz</p>' },
|
||||
|
||||
{ 'id': 'SM:m.r.c_Pdir:rtl-1_SC-1',
|
||||
'desc': 'move caret 1 character to the right in LTR text within RTL context',
|
||||
'function': 'sel.modify("move", "right", "character");',
|
||||
'pad': '<p dir="rtl">foo b^ar baz</p>',
|
||||
'expected': '<p dir="rtl">foo ba^r baz</p>' },
|
||||
|
||||
{ 'id': 'SM:m.l.c_Pdir:rtl-1_SC-1',
|
||||
'desc': 'move caret 1 character to the left in LTR text within RTL context',
|
||||
'function': 'sel.modify("move", "left", "character");',
|
||||
'pad': '<p dir="rtl">foo ba^r baz</p>',
|
||||
'expected': '<p dir="rtl">foo b^ar baz</p>' },
|
||||
|
||||
|
||||
{ 'id': 'SM:m.f.c_TEXT:ar-1_SC-1',
|
||||
'desc': 'move caret forward 1 character in Arabic text',
|
||||
'function': 'sel.modify("move", "forward", "character");',
|
||||
'pad': 'مرح^با العالم',
|
||||
'expected': 'مرحب^ا العالم' },
|
||||
|
||||
{ 'id': 'SM:m.b.c_TEXT:ar-1_SC-1',
|
||||
'desc': 'move caret backward 1 character in Arabic text',
|
||||
'function': 'sel.modify("move", "backward", "character");',
|
||||
'pad': 'مرح^با العالم',
|
||||
'expected': 'مر^حبا العالم' },
|
||||
|
||||
{ 'id': 'SM:m.f.c_TEXT:he-1_SC-1',
|
||||
'desc': 'move caret forward 1 character in Hebrew text',
|
||||
'function': 'sel.modify("move", "forward", "character");',
|
||||
'pad': 'של^ום עולם',
|
||||
'expected': 'שלו^ם עולם' },
|
||||
|
||||
{ 'id': 'SM:m.b.c_TEXT:he-1_SC-1',
|
||||
'desc': 'move caret backward 1 character in Hebrew text',
|
||||
'function': 'sel.modify("move", "backward", "character");',
|
||||
'pad': 'של^ום עולם',
|
||||
'expected': 'ש^לום עולם' },
|
||||
|
||||
|
||||
{ 'id': 'SM:m.f.c_BDOdir:rtl-1_SC-1',
|
||||
'desc': 'move caret forward 1 character inside <bdo>',
|
||||
'function': 'sel.modify("move", "forward", "character");',
|
||||
'pad': 'foo <bdo dir="rtl">b^ar</bdo> baz',
|
||||
'expected': 'foo <bdo dir="rtl">ba^r</bdo> baz' },
|
||||
|
||||
{ 'id': 'SM:m.b.c_BDOdir:rtl-1_SC-1',
|
||||
'desc': 'move caret backward 1 character inside <bdo>',
|
||||
'function': 'sel.modify("move", "backward", "character");',
|
||||
'pad': 'foo <bdo dir="rtl">ba^r</bdo> baz',
|
||||
'expected': 'foo <bdo dir="rtl">b^ar</bdo> baz' },
|
||||
|
||||
{ 'id': 'SM:m.r.c_BDOdir:rtl-1_SC-1',
|
||||
'desc': 'move caret 1 character to the right inside <bdo>',
|
||||
'function': 'sel.modify("move", "right", "character");',
|
||||
'pad': 'foo <bdo dir="rtl">ba^r</bdo> baz',
|
||||
'expected': 'foo <bdo dir="rtl">b^ar</bdo> baz' },
|
||||
|
||||
{ 'id': 'SM:m.l.c_BDOdir:rtl-1_SC-1',
|
||||
'desc': 'move caret 1 character to the left inside <bdo>',
|
||||
'function': 'sel.modify("move", "left", "character");',
|
||||
'pad': 'foo <bdo dir="rtl">b^ar</bdo> baz',
|
||||
'expected': 'foo <bdo dir="rtl">ba^r</bdo> baz' },
|
||||
|
||||
|
||||
{ 'id': 'SM:m.f.c_TEXTrle-1_SC-rtl-1',
|
||||
'desc': 'move caret forward in RTL text within RLE-PDF marks',
|
||||
'function': 'sel.modify("move", "forward", "character");',
|
||||
'pad': 'I said, "(RLE)‫car يعني سي^ارة‬(PDF)".',
|
||||
'expected': 'I said, "(RLE)‫car يعني سيا^رة‬(PDF)".' },
|
||||
|
||||
{ 'id': 'SM:m.b.c_TEXTrle-1_SC-rtl-1',
|
||||
'desc': 'move caret backward in RTL text within RLE-PDF marks',
|
||||
'function': 'sel.modify("move", "backward", "character");',
|
||||
'pad': 'I said, "(RLE)‫car يعني سي^ارة‬(PDF)".',
|
||||
'expected': 'I said, "(RLE)‫car يعني س^يارة‬(PDF)".' },
|
||||
|
||||
{ 'id': 'SM:m.r.c_TEXTrle-1_SC-rtl-1',
|
||||
'desc': 'move caret 1 character to the right in RTL text within RLE-PDF marks',
|
||||
'function': 'sel.modify("move", "right", "character");',
|
||||
'pad': 'I said, "(RLE)‫car يعني سي^ارة‬(PDF)".',
|
||||
'expected': 'I said, "(RLE)‫car يعني س^يارة‬(PDF)".' },
|
||||
|
||||
{ 'id': 'SM:m.l.c_TEXTrle-1_SC-rtl-1',
|
||||
'desc': 'move caret 1 character to the left in RTL text within RLE-PDF marks',
|
||||
'function': 'sel.modify("move", "left", "character");',
|
||||
'pad': 'I said, "(RLE)‫car يعني سي^ارة‬(PDF)".',
|
||||
'expected': 'I said, "(RLE)‫car يعني سيا^رة‬(PDF)".' },
|
||||
|
||||
{ 'id': 'SM:m.f.c_TEXTrle-1_SC-ltr-1',
|
||||
'desc': 'move caret forward in LTR text within RLE-PDF marks',
|
||||
'function': 'sel.modify("move", "forward", "character");',
|
||||
'pad': 'I said, "(RLE)‫c^ar يعني سيارة‬(PDF)".',
|
||||
'expected': 'I said, "(RLE)‫ca^r يعني سيارة‬(PDF)".' },
|
||||
|
||||
{ 'id': 'SM:m.b.c_TEXTrle-1_SC-ltr-1',
|
||||
'desc': 'move caret backward in LTR text within RLE-PDF marks',
|
||||
'function': 'sel.modify("move", "backward", "character");',
|
||||
'pad': 'I said, "(RLE)‫ca^r يعني سيارة‬(PDF)".',
|
||||
'expected': 'I said, "(RLE)‫c^ar يعني سيارة‬(PDF)".' },
|
||||
|
||||
{ 'id': 'SM:m.r.c_TEXTrle-1_SC-ltr-1',
|
||||
'desc': 'move caret 1 character to the right in LTR text within RLE-PDF marks',
|
||||
'function': 'sel.modify("move", "right", "character");',
|
||||
'pad': 'I said, "(RLE)‫c^ar يعني سيارة‬(PDF)".',
|
||||
'expected': 'I said, "(RLE)‫ca^r يعني سيارة‬(PDF)".' },
|
||||
|
||||
{ 'id': 'SM:m.l.c_TEXTrle-1_SC-ltr-1',
|
||||
'desc': 'move caret 1 character to the left in LTR text within RLE-PDF marks',
|
||||
'function': 'sel.modify("move", "left", "character");',
|
||||
'pad': 'I said, "(RLE)‫ca^r يعني سيارة‬(PDF)".',
|
||||
'expected': 'I said, "(RLE)‫c^ar يعني سيارة‬(PDF)".' },
|
||||
|
||||
|
||||
{ 'id': 'SM:m.f.c_TEXTrlo-1_SC-rtl-1',
|
||||
'desc': 'move caret forward in RTL text within RLO-PDF marks',
|
||||
'function': 'sel.modify("move", "forward", "character");',
|
||||
'pad': 'I said, "(RLO)‮car يعني سي^ارة‬(PDF)".',
|
||||
'expected': 'I said, "(RLO)‮car يعني سيا^رة‬(PDF)".' },
|
||||
|
||||
{ 'id': 'SM:m.b.c_TEXTrlo-1_SC-rtl-1',
|
||||
'desc': 'move caret backward in RTL text within RLO-PDF marks',
|
||||
'function': 'sel.modify("move", "backward", "character");',
|
||||
'pad': 'I said, "(RLO)‮car يعني سي^ارة‬(PDF)".',
|
||||
'expected': 'I said, "(RLO)‮car يعني س^يارة‬(PDF)".' },
|
||||
|
||||
{ 'id': 'SM:m.r.c_TEXTrlo-1_SC-rtl-1',
|
||||
'desc': 'move caret 1 character to the right in RTL text within RLO-PDF marks',
|
||||
'function': 'sel.modify("move", "right", "character");',
|
||||
'pad': 'I said, "(RLO)‮car يعني سي^ارة‬(PDF)".',
|
||||
'expected': 'I said, "(RLO)‮car يعني س^يارة‬(PDF)".' },
|
||||
|
||||
{ 'id': 'SM:m.l.c_TEXTrlo-1_SC-rtl-1',
|
||||
'desc': 'move caret 1 character to the left in RTL text within RLO-PDF marks',
|
||||
'function': 'sel.modify("move", "left", "character");',
|
||||
'pad': 'I said, "(RLO)‮car يعني سي^ارة‬(PDF)".',
|
||||
'expected': 'I said, "(RLO)‮car يعني سيا^رة‬(PDF)".' },
|
||||
|
||||
{ 'id': 'SM:m.f.c_TEXTrlo-1_SC-ltr-1',
|
||||
'desc': 'move caret forward in Latin text within RLO-PDF marks',
|
||||
'function': 'sel.modify("move", "forward", "character");',
|
||||
'pad': 'I said, "(RLO)‮c^ar يعني سيارة‬(PDF)".',
|
||||
'expected': 'I said, "(RLO)‮ca^r يعني سيارة‬(PDF)".' },
|
||||
|
||||
{ 'id': 'SM:m.b.c_TEXTrlo-1_SC-ltr-1',
|
||||
'desc': 'move caret backward in Latin text within RLO-PDF marks',
|
||||
'function': 'sel.modify("move", "backward", "character");',
|
||||
'pad': 'I said, "(RLO)‮ca^r يعني سيارة‬(PDF)".',
|
||||
'expected': 'I said, "(RLO)‮c^ar يعني سيارة‬(PDF)".' },
|
||||
|
||||
{ 'id': 'SM:m.r.c_TEXTrlo-1_SC-ltr-1',
|
||||
'desc': 'move caret 1 character to the right in Latin text within RLO-PDF marks',
|
||||
'function': 'sel.modify("move", "right", "character");',
|
||||
'pad': 'I said, "(RLO)‮ca^r يعني سيارة‬(PDF)".',
|
||||
'expected': 'I said, "(RLO)‮c^ar يعني سيارة‬(PDF)".' },
|
||||
|
||||
{ 'id': 'SM:m.l.c_TEXTrlo-1_SC-ltr-1',
|
||||
'desc': 'move caret 1 character to the left in Latin text within RLO-PDF marks',
|
||||
'function': 'sel.modify("move", "left", "character");',
|
||||
'pad': 'I said, "(RLO)‮c^ar يعني سيارة‬(PDF)".',
|
||||
'expected': 'I said, "(RLO)‮ca^r يعني سيارة‬(PDF)".' },
|
||||
|
||||
|
||||
{ 'id': 'SM:m.f.c_TEXTrlm-1_SC-1',
|
||||
'desc': 'move caret forward in RTL text within neutral characters followed by RLM',
|
||||
'function': 'sel.modify("move", "forward", "character");',
|
||||
'pad': 'I said, "يعني سيارة!^?!‏(RLM)".',
|
||||
'expected': 'I said, "يعني سيارة!?^!‏(RLM)".' },
|
||||
|
||||
{ 'id': 'SM:m.b.c_TEXTrlm-1_SC-1',
|
||||
'desc': 'move caret backward in RTL text within neutral characters followed by RLM',
|
||||
'function': 'sel.modify("move", "backward", "character");',
|
||||
'pad': 'I said, "يعني سيارة!?^!‏(RLM)".',
|
||||
'expected': 'I said, "يعني سيارة!^?!‏(RLM)".' },
|
||||
|
||||
{ 'id': 'SM:m.r.c_TEXTrlm-1_SC-1',
|
||||
'desc': 'move caret 1 character to the right in RTL text within neutral characters followed by RLM',
|
||||
'function': 'sel.modify("move", "right", "character");',
|
||||
'pad': 'I said, "يعني سيارة!?^!‏(RLM)".',
|
||||
'expected': 'I said, "يعني سيارة!^?!‏(RLM)".' },
|
||||
|
||||
{ 'id': 'SM:m.l.c_TEXTrlm-1_SC-1',
|
||||
'desc': 'move caret 1 character to the left in RTL text within neutral characters followed by RLM',
|
||||
'function': 'sel.modify("move", "left", "character");',
|
||||
'pad': 'I said, "يعني سيارة!^?!‏(RLM)".',
|
||||
'expected': 'I said, "يعني سيارة!?^!‏(RLM)".' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'sel.modify: move forward/backward over words in Japanese text',
|
||||
'tests': [
|
||||
{ 'id': 'SM:m.f.w_TEXT-jp_SC-1',
|
||||
'desc': 'move caret forward 1 word in Japanese text (adjective)',
|
||||
'function': 'sel.modify("move", "forward", "word");',
|
||||
'pad': '^面白い例文をテストしましょう。',
|
||||
'expected': '面白い^例文をテストしましょう。' },
|
||||
|
||||
{ 'id': 'SM:m.f.w_TEXT-jp_SC-2',
|
||||
'desc': 'move caret forward 1 word in Japanese text (in the middle of a word)',
|
||||
'function': 'sel.modify("move", "forward", "word");',
|
||||
'pad': '面^白い例文をテストしましょう。',
|
||||
'expected': '面白い^例文をテストしましょう。' },
|
||||
|
||||
{ 'id': 'SM:m.f.w_TEXT-jp_SC-3',
|
||||
'desc': 'move caret forward 1 word in Japanese text (noun)',
|
||||
'function': 'sel.modify("move", "forward", "word");',
|
||||
'pad': '面白い^例文をテストしましょう。',
|
||||
'expected': [ '面白い例文^をテストしましょう。',
|
||||
'面白い例文を^テストしましょう。' ] },
|
||||
|
||||
{ 'id': 'SM:m.f.w_TEXT-jp_SC-4',
|
||||
'desc': 'move caret forward 1 word in Japanese text (Katakana)',
|
||||
'function': 'sel.modify("move", "forward", "word");',
|
||||
'pad': '面白い例文を^テストしましょう。',
|
||||
'expected': '面白い例文をテスト^しましょう。' },
|
||||
|
||||
{ 'id': 'SM:m.f.w_TEXT-jp_SC-5',
|
||||
'desc': 'move caret forward 1 word in Japanese text (verb)',
|
||||
'function': 'sel.modify("move", "forward", "word");',
|
||||
'pad': '面白い例文をテスト^しましょう。',
|
||||
'expected': '面白い例文をテストしましょう^。' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'sel.modify: extend selection forward',
|
||||
'tests': [
|
||||
{ 'id': 'SM:e.f.c_TEXT-1_SC-1',
|
||||
'desc': 'extend selection 1 character forward',
|
||||
'function': 'sel.modify("extend", "forward", "character");',
|
||||
'pad': 'foo ^bar baz',
|
||||
'expected': 'foo [b]ar baz' },
|
||||
|
||||
{ 'id': 'SM:e.f.c_TEXT-1_SI-1',
|
||||
'desc': 'extend selection 1 character forward',
|
||||
'function': 'sel.modify("extend", "forward", "character");',
|
||||
'pad': 'foo [b]ar baz',
|
||||
'expected': 'foo [ba]r baz' },
|
||||
|
||||
{ 'id': 'SM:e.f.w_TEXT-1_SC-1',
|
||||
'desc': 'extend selection 1 word forward',
|
||||
'function': 'sel.modify("extend", "forward", "word");',
|
||||
'pad': 'foo ^bar baz',
|
||||
'expected': 'foo [bar] baz' },
|
||||
|
||||
{ 'id': 'SM:e.f.w_TEXT-1_SI-1',
|
||||
'desc': 'extend selection 1 word forward',
|
||||
'function': 'sel.modify("extend", "forward", "word");',
|
||||
'pad': 'foo [b]ar baz',
|
||||
'expected': 'foo [bar] baz' },
|
||||
|
||||
{ 'id': 'SM:e.f.w_TEXT-1_SI-2',
|
||||
'desc': 'extend selection 1 word forward',
|
||||
'function': 'sel.modify("extend", "forward", "word");',
|
||||
'pad': 'foo [bar] baz',
|
||||
'expected': 'foo [bar baz]' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'sel.modify: extend selection backward, shrinking it',
|
||||
'tests': [
|
||||
{ 'id': 'SM:e.b.c_TEXT-1_SI-2',
|
||||
'desc': 'extend selection 1 character backward',
|
||||
'function': 'sel.modify("extend", "backward", "character");',
|
||||
'pad': 'foo [bar] baz',
|
||||
'expected': 'foo [ba]r baz' },
|
||||
|
||||
{ 'id': 'SM:e.b.c_TEXT-1_SI-1',
|
||||
'desc': 'extend selection 1 character backward',
|
||||
'function': 'sel.modify("extend", "backward", "character");',
|
||||
'pad': 'foo [b]ar baz',
|
||||
'expected': 'foo ^bar baz' },
|
||||
|
||||
{ 'id': 'SM:e.b.w_TEXT-1_SI-3',
|
||||
'desc': 'extend selection 1 word backward',
|
||||
'function': 'sel.modify("extend", "backward", "word");',
|
||||
'pad': 'foo [bar baz]',
|
||||
'expected': 'foo [bar] baz' },
|
||||
|
||||
{ 'id': 'SM:e.b.w_TEXT-1_SI-2',
|
||||
'desc': 'extend selection 1 word backward',
|
||||
'function': 'sel.modify("extend", "backward", "word");',
|
||||
'pad': 'foo [bar] baz',
|
||||
'expected': 'foo ^bar baz' },
|
||||
|
||||
{ 'id': 'SM:e.b.w_TEXT-1_SI-4',
|
||||
'desc': 'extend selection 1 word backward',
|
||||
'function': 'sel.modify("extend", "backward", "word");',
|
||||
'pad': 'foo b[ar baz]',
|
||||
'expected': 'foo b[ar] baz' },
|
||||
|
||||
{ 'id': 'SM:e.b.w_TEXT-1_SI-5',
|
||||
'desc': 'extend selection 1 word backward',
|
||||
'function': 'sel.modify("extend", "backward", "word");',
|
||||
'pad': 'foo b[ar] baz',
|
||||
'expected': 'foo b^ar baz' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'sel.modify: extend selection backward, creating or extending a reverse selections',
|
||||
'tests': [
|
||||
{ 'id': 'SM:e.b.c_TEXT-1_SC-1',
|
||||
'desc': 'extend selection 1 character backward',
|
||||
'function': 'sel.modify("extend", "backward", "character");',
|
||||
'pad': 'foo b^ar baz',
|
||||
'expected': 'foo ]b[ar baz' },
|
||||
|
||||
{ 'id': 'SM:e.b.c_TEXT-1_SIR-1',
|
||||
'desc': 'extend selection 1 character backward',
|
||||
'function': 'sel.modify("extend", "backward", "character");',
|
||||
'pad': 'foo b]a[r baz',
|
||||
'expected': 'foo ]ba[r baz' },
|
||||
|
||||
{ 'id': 'SM:e.b.w_TEXT-1_SIR-1',
|
||||
'desc': 'extend selection 1 word backward',
|
||||
'function': 'sel.modify("extend", "backward", "word");',
|
||||
'pad': 'foo b]a[r baz',
|
||||
'expected': 'foo ]ba[r baz' },
|
||||
|
||||
{ 'id': 'SM:e.b.w_TEXT-1_SIR-2',
|
||||
'desc': 'extend selection 1 word backward',
|
||||
'function': 'sel.modify("extend", "backward", "word");',
|
||||
'pad': 'foo ]ba[r baz',
|
||||
'expected': ']foo ba[r baz' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'sel.modify: extend selection forward, shrinking a reverse selections',
|
||||
'tests': [
|
||||
{ 'id': 'SM:e.f.c_TEXT-1_SIR-1',
|
||||
'desc': 'extend selection 1 character forward',
|
||||
'function': 'sel.modify("extend", "forward", "character");',
|
||||
'pad': 'foo b]a[r baz',
|
||||
'expected': 'foo ba^r baz' },
|
||||
|
||||
{ 'id': 'SM:e.f.c_TEXT-1_SIR-2',
|
||||
'desc': 'extend selection 1 character forward',
|
||||
'function': 'sel.modify("extend", "forward", "character");',
|
||||
'pad': 'foo ]ba[r baz',
|
||||
'expected': 'foo b]a[r baz' },
|
||||
|
||||
{ 'id': 'SM:e.f.w_TEXT-1_SIR-1',
|
||||
'desc': 'extend selection 1 word forward',
|
||||
'function': 'sel.modify("extend", "forward", "word");',
|
||||
'pad': 'foo ]ba[r baz',
|
||||
'expected': 'foo ba^r baz' },
|
||||
|
||||
{ 'id': 'SM:e.f.w_TEXT-1_SIR-3',
|
||||
'desc': 'extend selection 1 word forward',
|
||||
'function': 'sel.modify("extend", "forward", "word");',
|
||||
'pad': ']foo ba[r baz',
|
||||
'expected': 'foo ]ba[r baz' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'sel.modify: extend selection forward to line boundary',
|
||||
'tests': [
|
||||
{ 'id': 'SM:e.f.lb_BR.BR-1_SC-1',
|
||||
'desc': 'extend selection forward to line boundary',
|
||||
'function': 'sel.modify("extend", "forward", "lineboundary");',
|
||||
'pad': 'fo^o<br>bar<br>baz',
|
||||
'expected': 'fo[o]<br>bar<br>baz' },
|
||||
|
||||
{ 'id': 'SM:e.f.lb_BR.BR-1_SI-1',
|
||||
'desc': 'extend selection forward to next line boundary',
|
||||
'function': 'sel.modify("extend", "forward", "lineboundary");',
|
||||
'pad': 'fo[o]<br>bar<br>baz',
|
||||
'expected': 'fo[o<br>bar]<br>baz' },
|
||||
|
||||
{ 'id': 'SM:e.f.lb_BR.BR-1_SM-1',
|
||||
'desc': 'extend selection forward to line boundary',
|
||||
'function': 'sel.modify("extend", "forward", "lineboundary");',
|
||||
'pad': 'fo[o<br>b]ar<br>baz',
|
||||
'expected': 'fo[o<br>bar]<br>baz' },
|
||||
|
||||
{ 'id': 'SM:e.f.lb_P.P.P-1_SC-1',
|
||||
'desc': 'extend selection forward to line boundary',
|
||||
'function': 'sel.modify("extend", "forward", "lineboundary");',
|
||||
'pad': '<p>fo^o</p><p>bar</p><p>baz</p>',
|
||||
'expected': '<p>fo[o]</p><p>bar</p><p>baz</p>' },
|
||||
|
||||
{ 'id': 'SM:e.f.lb_P.P.P-1_SI-1',
|
||||
'desc': 'extend selection forward to next line boundary',
|
||||
'function': 'sel.modify("extend", "forward", "lineboundary");',
|
||||
'pad': '<p>fo[o]</p><p>bar</p><p>baz</p>',
|
||||
'expected': '<p>fo[o</p><p>bar]</p><p>baz</p>' },
|
||||
|
||||
{ 'id': 'SM:e.f.lb_P.P.P-1_SM-1',
|
||||
'desc': 'extend selection forward to line boundary',
|
||||
'function': 'sel.modify("extend", "forward", "lineboundary");',
|
||||
'pad': '<p>fo[o</p><p>b]ar</p><p>baz</p>',
|
||||
'expected': '<p>fo[o</p><p>bar]</p><p>baz</p>' },
|
||||
|
||||
{ 'id': 'SM:e.f.lb_P.P.P-1_SMR-1',
|
||||
'desc': 'extend selection forward to line boundary',
|
||||
'function': 'sel.modify("extend", "forward", "lineboundary");',
|
||||
'pad': '<p>foo</p><p>b]a[r</p><p>baz</p>',
|
||||
'expected': '<p>foo</p><p>ba[r]</p><p>baz</p>' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'sel.modify: extend selection backward to line boundary',
|
||||
'tests': [
|
||||
{ 'id': 'SM:e.b.lb_BR.BR-1_SC-2',
|
||||
'desc': 'extend selection backward to line boundary',
|
||||
'function': 'sel.modify("extend", "backward", "lineboundary");',
|
||||
'pad': 'foo<br>bar<br>b^az',
|
||||
'expected': 'foo<br>bar<br>]b[az' },
|
||||
|
||||
{ 'id': 'SM:e.b.lb_BR.BR-1_SIR-2',
|
||||
'desc': 'extend selection backward to previous line boundary',
|
||||
'function': 'sel.modify("extend", "backward", "lineboundary");',
|
||||
'pad': 'foo<br>bar<br>]b[az',
|
||||
'expected': 'foo<br>]bar<br>b[az' },
|
||||
|
||||
{ 'id': 'SM:e.b.lb_BR.BR-1_SMR-2',
|
||||
'desc': 'extend selection backward to line boundary',
|
||||
'function': 'sel.modify("extend", "backward", "lineboundary");',
|
||||
'pad': 'foo<br>ba]r<br>b[az',
|
||||
'expected': 'foo<br>]bar<br>b[az' },
|
||||
|
||||
{ 'id': 'SM:e.b.lb_P.P.P-1_SC-2',
|
||||
'desc': 'extend selection backward to line boundary',
|
||||
'function': 'sel.modify("extend", "backward", "lineboundary");',
|
||||
'pad': '<p>foo</p><p>bar</p><p>b^az</p>',
|
||||
'expected': '<p>foo</p><p>bar</p><p>]b[az</p>' },
|
||||
|
||||
{ 'id': 'SM:e.b.lb_P.P.P-1_SIR-2',
|
||||
'desc': 'extend selection backward to previous line boundary',
|
||||
'function': 'sel.modify("extend", "backward", "lineboundary");',
|
||||
'pad': '<p>foo</p><p>bar</p><p>]b[az</p>',
|
||||
'expected': '<p>foo</p><p>]bar</p><p>b[az</p>' },
|
||||
|
||||
{ 'id': 'SM:e.b.lb_P.P.P-1_SMR-2',
|
||||
'desc': 'extend selection backward to line boundary',
|
||||
'function': 'sel.modify("extend", "backward", "lineboundary");',
|
||||
'pad': '<p>foo</p><p>ba]r</p><p>b[az</p>',
|
||||
'expected': '<p>foo</p><p>]bar</p><p>b[az</p>' },
|
||||
|
||||
{ 'id': 'SM:e.b.lb_P.P.P-1_SM-2',
|
||||
'desc': 'extend selection backward to line boundary',
|
||||
'function': 'sel.modify("extend", "backward", "lineboundary");',
|
||||
'pad': '<p>foo</p><p>b[a]r</p><p>baz</p>',
|
||||
'expected': '<p>foo</p><p>]b[ar</p><p>baz</p>' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'sel.modify: extend selection forward to next line (NOTE: use identical text in every line!)',
|
||||
'tests': [
|
||||
{ 'id': 'SM:e.f.l_BR.BR-2_SC-1',
|
||||
'desc': 'extend selection forward to next line',
|
||||
'function': 'sel.modify("extend", "forward", "line");',
|
||||
'pad': 'fo^o<br>foo<br>foo',
|
||||
'expected': 'fo[o<br>fo]o<br>foo' },
|
||||
|
||||
{ 'id': 'SM:e.f.l_BR.BR-2_SI-1',
|
||||
'desc': 'extend selection forward to next line',
|
||||
'function': 'sel.modify("extend", "forward", "line");',
|
||||
'pad': 'fo[o]<br>foo<br>foo',
|
||||
'expected': 'fo[o<br>foo]<br>foo' },
|
||||
|
||||
{ 'id': 'SM:e.f.l_BR.BR-2_SM-1',
|
||||
'desc': 'extend selection forward to next line',
|
||||
'function': 'sel.modify("extend", "forward", "line");',
|
||||
'pad': 'fo[o<br>f]oo<br>foo',
|
||||
'expected': 'fo[o<br>foo<br>f]oo' },
|
||||
|
||||
{ 'id': 'SM:e.f.l_P.P-1_SC-1',
|
||||
'desc': 'extend selection forward to next line over paragraph boundaries',
|
||||
'function': 'sel.modify("extend", "forward", "line");',
|
||||
'pad': '<p>foo^bar</p><p>foobar</p>',
|
||||
'expected': '<p>foo[bar</p><p>foo]bar</p>' },
|
||||
|
||||
{ 'id': 'SM:e.f.l_P.P-1_SMR-1',
|
||||
'desc': 'extend selection forward to next line over paragraph boundaries',
|
||||
'function': 'sel.modify("extend", "forward", "line");',
|
||||
'pad': '<p>fo]obar</p><p>foob[ar</p>',
|
||||
'expected': '<p>foobar</p><p>fo]ob[ar</p>' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'sel.modify: extend selection backward to previous line (NOTE: use identical text in every line!)',
|
||||
'tests': [
|
||||
{ 'id': 'SM:e.b.l_BR.BR-2_SC-2',
|
||||
'desc': 'extend selection backward to previous line',
|
||||
'function': 'sel.modify("extend", "backward", "line");',
|
||||
'pad': 'foo<br>foo<br>f^oo',
|
||||
'expected': 'foo<br>f]oo<br>f[oo' },
|
||||
|
||||
{ 'id': 'SM:e.b.l_BR.BR-2_SIR-2',
|
||||
'desc': 'extend selection backward to previous line',
|
||||
'function': 'sel.modify("extend", "backward", "line");',
|
||||
'pad': 'foo<br>foo<br>]f[oo',
|
||||
'expected': 'foo<br>]foo<br>f[oo' },
|
||||
|
||||
{ 'id': 'SM:e.b.l_BR.BR-2_SMR-2',
|
||||
'desc': 'extend selection backward to previous line',
|
||||
'function': 'sel.modify("extend", "backward", "line");',
|
||||
'pad': 'foo<br>fo]o<br>f[oo',
|
||||
'expected': 'fo]o<br>foo<br>f[oo' },
|
||||
|
||||
{ 'id': 'SM:e.b.l_P.P-1_SC-2',
|
||||
'desc': 'extend selection backward to next line over paragraph boundaries',
|
||||
'function': 'sel.modify("extend", "backward", "line");',
|
||||
'pad': '<p>foobar</p><p>foo^bar</p>',
|
||||
'expected': '<p>foo]bar</p><p>foo[bar</p>' },
|
||||
|
||||
{ 'id': 'SM:e.b.l_P.P-1_SM-1',
|
||||
'desc': 'extend selection backward to next line over paragraph boundaries',
|
||||
'function': 'sel.modify("extend", "backward", "line");',
|
||||
'pad': '<p>fo[obar</p><p>foob]ar</p>',
|
||||
'expected': '<p>fo[ob]ar</p><p>foobar</p>' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'sel.selectAllChildren(<element>)',
|
||||
'function': 'sel.selectAllChildren(doc.getElementById("div"));',
|
||||
'tests': [
|
||||
{ 'id': 'SAC:div_DIV-1_SC-1',
|
||||
'desc': 'selectAllChildren(<div>)',
|
||||
'pad': 'foo<div id="div">bar <span>ba^z</span></div>qoz',
|
||||
'expected': [ 'foo<div id="div">[bar <span>baz</span>}</div>qoz',
|
||||
'foo<div id="div">{bar <span>baz</span>}</div>qoz' ] },
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -0,0 +1,462 @@
|
||||
|
||||
UNAPPLY_TESTS = {
|
||||
'id': 'U',
|
||||
'caption': 'Unapply Existing Formatting Tests',
|
||||
'checkAttrs': True,
|
||||
'checkStyle': True,
|
||||
'styleWithCSS': False,
|
||||
'expected': 'foo[bar]baz',
|
||||
|
||||
'RFC': [
|
||||
{ 'desc': '',
|
||||
'command': '',
|
||||
'tests': [
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'remove link',
|
||||
'command': 'unlink',
|
||||
'tests': [
|
||||
{ 'id': 'UNLINK_A-1_SO',
|
||||
'desc': 'unlink wrapped <a> element',
|
||||
'pad': 'foo[<a>bar</a>]baz' },
|
||||
|
||||
{ 'id': 'UNLINK_A-1_SW',
|
||||
'desc': 'unlink <a> element where the selection wraps the full content',
|
||||
'pad': 'foo<a>[bar]</a>baz' },
|
||||
|
||||
{ 'id': 'UNLINK_An:a.h:id-1_SO',
|
||||
'desc': 'unlink wrapped <a> element that has a name and href attribute',
|
||||
'pad': 'foo[<a name="A" href="#UNLINK:An:a.h:id-1_SO">bar</a>]baz' },
|
||||
|
||||
{ 'id': 'UNLINK_A-2_SO',
|
||||
'desc': 'unlink contained <a> element',
|
||||
'pad': 'foo[b<a>a</a>r]baz' },
|
||||
|
||||
{ 'id': 'UNLINK_A2-1_SO',
|
||||
'desc': 'unlink 2 contained <a> elements',
|
||||
'pad': 'foo[<a>b</a>a<a>r</a>]baz' }
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
'Proposed': [
|
||||
{ 'desc': '',
|
||||
'command': '',
|
||||
'tests': [
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'remove bold',
|
||||
'command': 'bold',
|
||||
'tests': [
|
||||
{ 'id': 'B_B-1_SW',
|
||||
'rte1-id': 'u-bold-0',
|
||||
'desc': 'Selection within tags; remove <b> tags',
|
||||
'pad': 'foo<b>[bar]</b>baz' },
|
||||
|
||||
{ 'id': 'B_B-1_SO',
|
||||
'desc': 'Selection outside of tags; remove <b> tags',
|
||||
'pad': 'foo[<b>bar</b>]baz' },
|
||||
|
||||
{ 'id': 'B_B-1_SL',
|
||||
'desc': 'Selection oblique left; remove <b> tags',
|
||||
'pad': 'foo[<b>bar]</b>baz' },
|
||||
|
||||
{ 'id': 'B_B-1_SR',
|
||||
'desc': 'Selection oblique right; remove <b> tags',
|
||||
'pad': 'foo<b>[bar</b>]baz' },
|
||||
|
||||
{ 'id': 'B_STRONG-1_SW',
|
||||
'rte1-id': 'u-bold-1',
|
||||
'desc': 'Selection within tags; remove <strong> tags',
|
||||
'pad': 'foo<strong>[bar]</strong>baz' },
|
||||
|
||||
{ 'id': 'B_STRONG-1_SO',
|
||||
'desc': 'Selection outside of tags; remove <strong> tags',
|
||||
'pad': 'foo[<strong>bar</strong>]baz' },
|
||||
|
||||
{ 'id': 'B_STRONG-1_SL',
|
||||
'desc': 'Selection oblique left; remove <strong> tags',
|
||||
'pad': 'foo[<strong>bar]</strong>baz' },
|
||||
|
||||
{ 'id': 'B_STRONG-1_SR',
|
||||
'desc': 'Selection oblique right; remove <strong> tags',
|
||||
'pad': 'foo<strong>[bar</strong>]baz' },
|
||||
|
||||
{ 'id': 'B_SPANs:fw:b-1_SW',
|
||||
'rte1-id': 'u-bold-2',
|
||||
'desc': 'Selection within tags; remove "font-weight: bold"',
|
||||
'pad': 'foo<span style="font-weight: bold">[bar]</span>baz' },
|
||||
|
||||
{ 'id': 'B_SPANs:fw:b-1_SO',
|
||||
'desc': 'Selection outside of tags; remove "font-weight: bold"',
|
||||
'pad': 'foo[<span style="font-weight: bold">bar</span>]baz' },
|
||||
|
||||
{ 'id': 'B_SPANs:fw:b-1_SL',
|
||||
'desc': 'Selection oblique left; remove "font-weight: bold"',
|
||||
'pad': 'foo[<span style="font-weight: bold">bar]</span>baz' },
|
||||
|
||||
{ 'id': 'B_SPANs:fw:b-1_SR',
|
||||
'desc': 'Selection oblique right; remove "font-weight: bold"',
|
||||
'pad': 'foo<span style="font-weight: bold">[bar</span>]baz' },
|
||||
|
||||
{ 'id': 'B_B-P3-1_SO12',
|
||||
'desc': 'Unbolding multiple paragraphs in inside bolded content with content-model violation',
|
||||
'pad': '<b>{<p>foo</p><p>bar</p>}<p>baz</p></b>',
|
||||
'expected': [ '<p>[foo</p><p>bar]</p><p><b>baz</b></p>',
|
||||
'<p>[foo</p><p>bar]</p><b><p>baz</p></b>' ] },
|
||||
|
||||
{ 'id': 'B_B-P-I..P-1_SO-I',
|
||||
'desc': 'Unbolding italicized content inside bolded content with content-model violation',
|
||||
'pad': '<b><p>foo[<i>bar</i>]</p><p>baz</p></b>',
|
||||
'expected': [ '<p><b>foo</b><i>[bar]</i></p><p><b>baz</b></p>',
|
||||
'<b><p>foo</p></b><p><i>[bar]</i></p><b><p>baz</p></b>' ] },
|
||||
|
||||
{ 'id': 'B_B-2_SL',
|
||||
'desc': 'Remove partially covered bold, selection extends left',
|
||||
'pad': 'foo [bar <b>baz] qoz</b> quz sic',
|
||||
'expected': 'foo [bar baz]<b> qoz</b> quz sic' },
|
||||
|
||||
{ 'id': 'B_B-2_SR',
|
||||
'desc': 'Remove partially covered bold, selection extends right',
|
||||
'pad': 'foo bar <b>baz [qoz</b> quz] sic',
|
||||
'expected': 'foo bar <b>baz </b>[qoz quz] sic' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'remove italic',
|
||||
'command': 'italic',
|
||||
'tests': [
|
||||
{ 'id': 'I_I-1_SW',
|
||||
'rte1-id': 'u-italic-0',
|
||||
'desc': 'Selection within tags; remove <i> tags',
|
||||
'pad': 'foo<i>[bar]</i>baz' },
|
||||
|
||||
{ 'id': 'I_I-1_SO',
|
||||
'desc': 'Selection outside of tags; remove <i> tags',
|
||||
'pad': 'foo[<i>bar</i>]baz' },
|
||||
|
||||
{ 'id': 'I_I-1_SL',
|
||||
'desc': 'Selection oblique left; remove <i> tags',
|
||||
'pad': 'foo[<i>bar]</i>baz' },
|
||||
|
||||
{ 'id': 'I_I-1_SR',
|
||||
'desc': 'Selection oblique right; remove <i> tags',
|
||||
'pad': 'foo<i>[bar</i>]baz' },
|
||||
|
||||
{ 'id': 'I_EM-1_SW',
|
||||
'rte1-id': 'u-italic-1',
|
||||
'desc': 'Selection within tags; remove <em> tags',
|
||||
'pad': 'foo<em>[bar]</em>baz' },
|
||||
|
||||
{ 'id': 'I_EM-1_SO',
|
||||
'desc': 'Selection outside of tags; remove <em> tags',
|
||||
'pad': 'foo[<em>bar</em>]baz' },
|
||||
|
||||
{ 'id': 'I_EM-1_SL',
|
||||
'desc': 'Selection oblique left; remove <em> tags',
|
||||
'pad': 'foo[<em>bar]</em>baz' },
|
||||
|
||||
{ 'id': 'I_EM-1_SR',
|
||||
'desc': 'Selection oblique right; remove <em> tags',
|
||||
'pad': 'foo<em>[bar</em>]baz' },
|
||||
|
||||
{ 'id': 'I_SPANs:fs:i-1_SW',
|
||||
'rte1-id': 'u-italic-2',
|
||||
'desc': 'Selection within tags; remove "font-style: italic"',
|
||||
'pad': 'foo<span style="font-style: italic">[bar]</span>baz' },
|
||||
|
||||
{ 'id': 'I_SPANs:fs:i-1_SO',
|
||||
'desc': 'Selection outside of tags; Italicize "font-style: italic"',
|
||||
'pad': 'foo[<span style="font-style: italic">bar</span>]baz' },
|
||||
|
||||
{ 'id': 'I_SPANs:fs:i-1_SL',
|
||||
'desc': 'Selection oblique left; Italicize "font-style: italic"',
|
||||
'pad': 'foo[<span style="font-style: italic">bar]</span>baz' },
|
||||
|
||||
{ 'id': 'I_SPANs:fs:i-1_SR',
|
||||
'desc': 'Selection oblique right; Italicize "font-style: italic"',
|
||||
'pad': 'foo<span style="font-style: italic">[bar</span>]baz' },
|
||||
|
||||
{ 'id': 'I_I-P3-1_SO2',
|
||||
'desc': 'Unitalicize content with content-model violation',
|
||||
'pad': '<i><p>foo</p>{<p>bar</p>}<p>baz</p></i>',
|
||||
'expected': [ '<p><i>foo</i></p><p>[bar]</p><p><i>baz</i></p>',
|
||||
'<i><p>foo</p></i><p>[bar]</p><i><p>baz</p></i>' ] }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'remove underline',
|
||||
'command': 'underline',
|
||||
'tests': [
|
||||
{ 'id': 'U_U-1_SW',
|
||||
'rte1-id': 'u-underline-0',
|
||||
'desc': 'Selection within tags; remove <u> tags',
|
||||
'pad': 'foo<u>[bar]</u>baz' },
|
||||
|
||||
{ 'id': 'U_U-1_SO',
|
||||
'desc': 'Selection outside of tags; remove <u> tags',
|
||||
'pad': 'foo[<u>bar</u>]baz' },
|
||||
|
||||
{ 'id': 'U_U-1_SL',
|
||||
'desc': 'Selection oblique left; remove <u> tags',
|
||||
'pad': 'foo[<u>bar]</u>baz' },
|
||||
|
||||
{ 'id': 'U_U-1_SR',
|
||||
'desc': 'Selection oblique right; remove <u> tags',
|
||||
'pad': 'foo<u>[bar</u>]baz' },
|
||||
|
||||
{ 'id': 'U_SPANs:td:u-1_SW',
|
||||
'rte1-id': 'u-underline-1',
|
||||
'desc': 'Selection within tags; remove "text-decoration: underline"',
|
||||
'pad': 'foo<span style="text-decoration: underline">[bar]</span>baz' },
|
||||
|
||||
{ 'id': 'U_SPANs:td:u-1_SO',
|
||||
'desc': 'Selection outside of tags; remove "text-decoration: underline"',
|
||||
'pad': 'foo[<span style="text-decoration: underline">bar</span>]baz' },
|
||||
|
||||
{ 'id': 'U_SPANs:td:u-1_SL',
|
||||
'desc': 'Selection oblique left; remove "text-decoration: underline"',
|
||||
'pad': 'foo[<span style="text-decoration: underline">bar]</span>baz' },
|
||||
|
||||
{ 'id': 'U_SPANs:td:u-1_SR',
|
||||
'desc': 'Selection oblique right; remove "text-decoration: underline"',
|
||||
'pad': 'foo<span style="text-decoration: underline">[bar</span>]baz' },
|
||||
|
||||
{ 'id': 'U_U-S-1_SO',
|
||||
'desc': 'Removing underline from underlined content with striked content',
|
||||
'pad': '<u>foo[bar<s>baz</s>quoz]</u>',
|
||||
'expected': '<u>foo</u>[bar<s>baz</s>quoz]' },
|
||||
|
||||
{ 'id': 'U_U-S-2_SI',
|
||||
'desc': 'Removing underline from striked content inside underlined content',
|
||||
'pad': '<u><s>foo[bar]baz</s>quoz</u>',
|
||||
'expected': '<s><u>foo</u>[bar]<u>baz</u>quoz</s>' },
|
||||
|
||||
{ 'id': 'U_U-P3-1_SO',
|
||||
'desc': 'Removing underline from underlined content with content-model violation',
|
||||
'pad': '<u><p>foo</p>{<p>bar</p>}<p>baz</p></u>',
|
||||
'expected': [ '<p><u>foo</u></p><p>[bar]</p><p><u>baz</u></p>',
|
||||
'<u><p>foo</p></u><p>[bar]</p><u><p>baz</p></u>' ] }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'remove strike through',
|
||||
'command': 'strikethrough',
|
||||
'tests': [
|
||||
{ 'id': 'S_S-1_SW',
|
||||
'rte1-id': 'u-strikethrough-1',
|
||||
'desc': 'Selection within tags; remove <s> tags',
|
||||
'pad': 'foo<s>[bar]</s>baz' },
|
||||
|
||||
{ 'id': 'S_S-1_SO',
|
||||
'desc': 'Selection outside of tags; remove <s> tags',
|
||||
'pad': 'foo[<s>bar</s>]baz' },
|
||||
|
||||
{ 'id': 'S_S-1_SL',
|
||||
'desc': 'Selection oblique left; remove <s> tags',
|
||||
'pad': 'foo[<s>bar]</s>baz' },
|
||||
|
||||
{ 'id': 'S_S-1_SR',
|
||||
'desc': 'Selection oblique right; remove <s> tags',
|
||||
'pad': 'foo<s>[bar</s>]baz' },
|
||||
|
||||
{ 'id': 'S_STRIKE-1_SW',
|
||||
'rte1-id': 'u-strikethrough-0',
|
||||
'desc': 'Selection within tags; remove <strike> tags',
|
||||
'pad': 'foo<strike>[bar]</strike>baz' },
|
||||
|
||||
{ 'id': 'S_STRIKE-1_SO',
|
||||
'desc': 'Selection outside of tags; remove <strike> tags',
|
||||
'pad': 'foo[<strike>bar</strike>]baz' },
|
||||
|
||||
{ 'id': 'S_STRIKE-1_SL',
|
||||
'desc': 'Selection oblique left; remove <strike> tags',
|
||||
'pad': 'foo[<strike>bar]</strike>baz' },
|
||||
|
||||
{ 'id': 'S_STRIKE-2_SR',
|
||||
'desc': 'Selection oblique right; remove <strike> tags',
|
||||
'pad': 'foo<strike>[bar</strike>]baz' },
|
||||
|
||||
{ 'id': 'S_DEL-1_SW',
|
||||
'rte1-id': 'u-strikethrough-2',
|
||||
'desc': 'Selection within tags; remove <del> tags',
|
||||
'pad': 'foo<del>[bar]</del>baz' },
|
||||
|
||||
{ 'id': 'S_SPANs:td:lt-1_SW',
|
||||
'rte1-id': 'u-strikethrough-3',
|
||||
'desc': 'Selection within tags; remove "text-decoration:line-through"',
|
||||
'pad': 'foo<span style="text-decoration:line-through">[bar]</span>baz' },
|
||||
|
||||
{ 'id': 'S_SPANs:td:lt-1_SO',
|
||||
'desc': 'Selection outside of tags; Italicize "text-decoration:line-through"',
|
||||
'pad': 'foo[<span style="text-decoration:line-through">bar</span>]baz' },
|
||||
|
||||
{ 'id': 'S_SPANs:td:lt-1_SL',
|
||||
'desc': 'Selection oblique left; Italicize "text-decoration:line-through"',
|
||||
'pad': 'foo[<span style="text-decoration:line-through">bar]</span>baz' },
|
||||
|
||||
{ 'id': 'S_SPANs:td:lt-1_SR',
|
||||
'desc': 'Selection oblique right; Italicize "text-decoration:line-through"',
|
||||
'pad': 'foo<span style="text-decoration:line-through">[bar</span>]baz' },
|
||||
|
||||
{ 'id': 'S_S-U-1_SI',
|
||||
'desc': 'Removing underline from underlined content inside striked content',
|
||||
'pad': '<s><u>foo[bar]baz</u>quoz</s>',
|
||||
'expected': '<s><u>foo</u></s><u>[bar]</u><s><u>baz</u>quoz</s>' },
|
||||
|
||||
{ 'id': 'S_U-S-1_SI',
|
||||
'desc': 'Removing underline from striked content inside underlined content',
|
||||
'pad': '<u><s>foo[bar]baz</s>quoz</u>',
|
||||
'expected': '<u><s>foo</s>[bar]<s>baz</s>quoz</u>' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'remove subscript',
|
||||
'command': 'subscript',
|
||||
'tests': [
|
||||
{ 'id': 'SUB_SUB-1_SW',
|
||||
'rte1-id': 'u-subscript-0',
|
||||
'desc': 'remove subscript',
|
||||
'pad': 'foo<sub>[bar]</sub>baz' },
|
||||
|
||||
{ 'id': 'SUB_SPANs:va:sub-1_SW',
|
||||
'rte1-id': 'u-subscript-1',
|
||||
'desc': 'remove subscript',
|
||||
'pad': 'foo<span style="vertical-align: sub">[bar]</span>baz' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'remove superscript',
|
||||
'command': 'superscript',
|
||||
'tests': [
|
||||
{ 'id': 'SUP_SUP-1_SW',
|
||||
'rte1-id': 'u-superscript-0',
|
||||
'desc': 'remove superscript',
|
||||
'pad': 'foo<sup>[bar]</sup>baz' },
|
||||
|
||||
{ 'id': 'SUP_SPANs:va:super-1_SW',
|
||||
'rte1-id': 'u-superscript-1',
|
||||
'desc': 'remove superscript',
|
||||
'pad': 'foo<span style="vertical-align: super">[bar]</span>baz' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'remove links',
|
||||
'command': 'unlink',
|
||||
'tests': [
|
||||
{ 'id': 'UNLINK_Ahref:url-1_SW',
|
||||
'rte1-id': 'u-unlink-0',
|
||||
'desc': 'unlink an <a> element with href attribute where all children are selected',
|
||||
'pad': 'foo<a href="http://www.goo.gl">[bar]</a>baz' },
|
||||
|
||||
{ 'id': 'UNLINK_A-1_SC',
|
||||
'desc': 'unlink an <a> element that contains the collapsed selection',
|
||||
'pad': 'foo<a>ba^r</a>baz',
|
||||
'expected': 'fooba^rbaz' },
|
||||
|
||||
{ 'id': 'UNLINK_A-1_SI',
|
||||
'desc': 'unlink an <a> element that contains the whole selection',
|
||||
'pad': 'foo<a>b[a]r</a>baz',
|
||||
'expected': 'foob[a]rbaz' },
|
||||
|
||||
{ 'id': 'UNLINK_A-2_SL',
|
||||
'desc': 'unlink a partially contained <a> element',
|
||||
'pad': 'foo[ba<a>r]ba</a>z' },
|
||||
|
||||
{ 'id': 'UNLINK_A-3_SR',
|
||||
'desc': 'unlink a partially contained <a> element',
|
||||
'pad': 'fo<a>o[ba</a>r]baz' },
|
||||
|
||||
{ 'id': 'UNLINK_As:d:b.fw:b-1_SW',
|
||||
'desc': 'unlink, preserving styles',
|
||||
'pad': 'foo<a href="#" style="display: block; font-weight: bold">[bar]</a>baz',
|
||||
'expected': 'foo<span style="display: block; font-weight: bold">[bar]</span>baz' },
|
||||
|
||||
{ 'id': 'UNLINK_A-IMG-1_SO',
|
||||
'desc': 'unlink a linked image at the start of the content',
|
||||
'pad': '{<a href="#"><img src="pic.jpg" align="right" height="140" width="200"></a>abc]',
|
||||
'expected': '{<img src="pic.jpg" align="right" height="140" width="200">abc]' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'outdent',
|
||||
'command': 'outdent',
|
||||
'tests': [
|
||||
{ 'id': 'OUTDENT_BQ-1_SW',
|
||||
'rte1-id': 'u-outdent-0',
|
||||
'desc': 'outdent (remove) a <blockquote>',
|
||||
'pad': 'foo<blockquote>[bar]</blockquote>baz',
|
||||
'expected': [ 'foo<p>[bar]</p>baz',
|
||||
'foo<div>[bar]</div>baz' ],
|
||||
'accept': 'foo<br>[bar]<br>baz' },
|
||||
|
||||
{ 'id': 'OUTDENT_BQ.wibq.s:m:00040.b:n.p:0-1_SW',
|
||||
'rte1-id': 'u-outdent-1',
|
||||
'desc': 'outdent (remove) a styled <blockquote>',
|
||||
'pad': 'foo<blockquote class="webkit-indent-blockquote" style="margin: 0 0 0 40px; border: none; padding: 0px">[bar]</blockquote>baz',
|
||||
'expected': [ 'foo<p>[bar]</p>baz',
|
||||
'foo<div>[bar]</div>baz' ],
|
||||
'accept': 'foo<br>[bar]<br>baz' },
|
||||
|
||||
{ 'id': 'OUTDENT_OL-LI-1_SW',
|
||||
'rte1-id': 'u-outdent-3',
|
||||
'desc': 'outdent (remove) an ordered list',
|
||||
'pad': 'foo<ol><li>[bar]</li></ol>baz',
|
||||
'expected': [ 'foo<p>[bar]</p>baz',
|
||||
'foo<div>[bar]</div>baz' ],
|
||||
'accept': 'foo<br>[bar]<br>baz' },
|
||||
|
||||
{ 'id': 'OUTDENT_UL-LI-1_SW',
|
||||
'rte1-id': 'u-outdent-2',
|
||||
'desc': 'outdent (remove) an unordered list',
|
||||
'pad': 'foo<ul><li>[bar]</li></ul>baz',
|
||||
'expected': [ 'foo<p>[bar]</p>baz',
|
||||
'foo<div>[bar]</div>baz' ],
|
||||
'accept': 'foo<br>[bar]<br>baz' },
|
||||
|
||||
{ 'id': 'OUTDENT_DIV-1_SW',
|
||||
'rte1-id': 'u-outdent-4',
|
||||
'desc': 'outdent (remove) a styled <div> with margin',
|
||||
'pad': 'foo<div style="margin-left: 40px;">[bar]</div>baz',
|
||||
'expected': [ 'foo<p>[bar]</p>baz',
|
||||
'foo<div>[bar]</div>baz' ],
|
||||
'accept': 'foo<br>[bar]<br>baz' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'remove all formatting',
|
||||
'command': 'removeformat',
|
||||
'tests': [
|
||||
{ 'id': 'REMOVEFORMAT_B-1_SW',
|
||||
'rte1-id': 'u-removeformat-0',
|
||||
'desc': 'remove a <b> tag using "removeformat"',
|
||||
'pad': 'foo<b>[bar]</b>baz' },
|
||||
|
||||
{ 'id': 'REMOVEFORMAT_Ahref:url-1_SW',
|
||||
'rte1-id': 'u-removeformat-0',
|
||||
'desc': 'remove a link using "removeformat"',
|
||||
'pad': 'foo<a href="http://www.goo.gl">[bar]</a>baz' },
|
||||
|
||||
{ 'id': 'REMOVEFORMAT_TABLE-TBODY-TR-TD-1_SW',
|
||||
'rte1-id': 'u-removeformat-2',
|
||||
'desc': 'remove a table using "removeformat"',
|
||||
'pad': 'foo<table><tbody><tr><td>[bar]</td></tr></tbody></table>baz',
|
||||
'expected': [ 'foo<p>[bar]</p>baz',
|
||||
'foo<div>[bar]</div>baz' ],
|
||||
'accept': 'foo<br>[bar]<br>baz' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'remove bookmark',
|
||||
'command': 'unbookmark',
|
||||
'tests': [
|
||||
{ 'id': 'UNBOOKMARK_An:name-1_SW',
|
||||
'rte1-id': 'u-unbookmark-0',
|
||||
'desc': 'unlink a bookmark (a named <a> element) where all children are selected',
|
||||
'pad': 'foo<a name="bookmark">[bar]</a>baz' }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,226 @@
|
||||
|
||||
UNAPPLY_TESTS_CSS = {
|
||||
'id': 'UC',
|
||||
'caption': 'Unapply Existing Formatting Tests, using styleWithCSS',
|
||||
'checkAttrs': True,
|
||||
'checkStyle': True,
|
||||
'styleWithCSS': True,
|
||||
'expected': 'foo[bar]baz',
|
||||
|
||||
'Proposed': [
|
||||
{ 'desc': '',
|
||||
'id': '',
|
||||
'command': '',
|
||||
'tests': [
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'remove bold',
|
||||
'command': 'bold',
|
||||
'tests': [
|
||||
{ 'id': 'B_B-1_SW',
|
||||
'desc': 'Selection within tags; remove <b> tags',
|
||||
'pad': 'foo<b>[bar]</b>baz' },
|
||||
|
||||
{ 'id': 'B_B-1_SO',
|
||||
'desc': 'Selection outside of tags; remove <b> tags',
|
||||
'pad': 'foo[<b>bar</b>]baz' },
|
||||
|
||||
{ 'id': 'B_B-1_SL',
|
||||
'desc': 'Selection oblique left; remove <b> tags',
|
||||
'pad': 'foo[<b>bar]</b>baz' },
|
||||
|
||||
{ 'id': 'B_B-1_SR',
|
||||
'desc': 'Selection oblique right; remove <b> tags',
|
||||
'pad': 'foo<b>[bar</b>]baz' },
|
||||
|
||||
{ 'id': 'B_STRONG-1_SW',
|
||||
'desc': 'Selection within tags; remove <strong> tags',
|
||||
'pad': 'foo<strong>[bar]</strong>baz' },
|
||||
|
||||
{ 'id': 'B_STRONG-1_SO',
|
||||
'desc': 'Selection outside of tags; remove <strong> tags',
|
||||
'pad': 'foo[<strong>bar</strong>]baz' },
|
||||
|
||||
{ 'id': 'B_STRONG-1_SL',
|
||||
'desc': 'Selection oblique left; remove <strong> tags',
|
||||
'pad': 'foo[<strong>bar]</strong>baz' },
|
||||
|
||||
{ 'id': 'B_STRONG-1_SR',
|
||||
'desc': 'Selection oblique right; remove <strong> tags',
|
||||
'pad': 'foo<strong>[bar</strong>]baz' },
|
||||
|
||||
{ 'id': 'B_SPANs:fw:b-1_SW',
|
||||
'desc': 'Selection within tags; remove "font-weight: bold"',
|
||||
'pad': 'foo<span style="font-weight: bold">[bar]</span>baz' },
|
||||
|
||||
{ 'id': 'B_SPANs:fw:b-1_SO',
|
||||
'desc': 'Selection outside of tags; remove "font-weight: bold"',
|
||||
'pad': 'foo[<span style="font-weight: bold">bar</span>]baz' },
|
||||
|
||||
{ 'id': 'B_SPANs:fw:b-1_SL',
|
||||
'desc': 'Selection oblique left; remove "font-weight: bold"',
|
||||
'pad': 'foo[<span style="font-weight: bold">bar]</span>baz' },
|
||||
|
||||
{ 'id': 'B_SPANs:fw:b-1_SR',
|
||||
'desc': 'Selection oblique right; remove "font-weight: bold"',
|
||||
'pad': 'foo<span style="font-weight: bold">[bar</span>]baz' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'remove italic',
|
||||
'command': 'italic',
|
||||
'tests': [
|
||||
{ 'id': 'I_I-1_SW',
|
||||
'desc': 'Selection within tags; remove <i> tags',
|
||||
'pad': 'foo<i>[bar]</i>baz' },
|
||||
|
||||
{ 'id': 'I_I-1_SO',
|
||||
'desc': 'Selection outside of tags; remove <i> tags',
|
||||
'pad': 'foo[<i>bar</i>]baz' },
|
||||
|
||||
{ 'id': 'I_I-1_SL',
|
||||
'desc': 'Selection oblique left; remove <i> tags',
|
||||
'pad': 'foo[<i>bar]</i>baz' },
|
||||
|
||||
{ 'id': 'I_I-1_SR',
|
||||
'desc': 'Selection oblique right; remove <i> tags',
|
||||
'pad': 'foo<i>[bar</i>]baz' },
|
||||
|
||||
{ 'id': 'I_EM-1_SW',
|
||||
'desc': 'Selection within tags; remove <em> tags',
|
||||
'pad': 'foo<em>[bar]</em>baz' },
|
||||
|
||||
{ 'id': 'I_EM-1_SO',
|
||||
'desc': 'Selection outside of tags; remove <em> tags',
|
||||
'pad': 'foo[<em>bar</em>]baz' },
|
||||
|
||||
{ 'id': 'I_EM-1_SL',
|
||||
'desc': 'Selection oblique left; remove <em> tags',
|
||||
'pad': 'foo[<em>bar]</em>baz' },
|
||||
|
||||
{ 'id': 'I_EM-1_SR',
|
||||
'desc': 'Selection oblique right; remove <em> tags',
|
||||
'pad': 'foo<em>[bar</em>]baz' },
|
||||
|
||||
{ 'id': 'I_SPANs:fs:i-1_SW',
|
||||
'desc': 'Selection within tags; remove "font-style: italic"',
|
||||
'pad': 'foo<span style="font-style: italic">[bar]</span>baz' },
|
||||
|
||||
{ 'id': 'I_SPANs:fs:i-1_SO',
|
||||
'desc': 'Selection outside of tags; Italicize "font-style: italic"',
|
||||
'pad': 'foo[<span style="font-style: italic">bar</span>]baz' },
|
||||
|
||||
{ 'id': 'I_SPANs:fs:i-1_SL',
|
||||
'desc': 'Selection oblique left; Italicize "font-style: italic"',
|
||||
'pad': 'foo[<span style="font-style: italic">bar]</span>baz' },
|
||||
|
||||
{ 'id': 'I_SPANs:fs:i-1_SR',
|
||||
'desc': 'Selection oblique right; Italicize "font-style: italic"',
|
||||
'pad': 'foo<span style="font-style: italic">[bar</span>]baz' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'remove underline',
|
||||
'command': 'underline',
|
||||
'tests': [
|
||||
{ 'id': 'U_U-1_SW',
|
||||
'desc': 'Selection within tags; remove <u> tags',
|
||||
'pad': 'foo<u>[bar]</u>baz' },
|
||||
|
||||
{ 'id': 'U_U-1_SO',
|
||||
'desc': 'Selection outside of tags; remove <u> tags',
|
||||
'pad': 'foo[<u>bar</u>]baz' },
|
||||
|
||||
{ 'id': 'U_U-1_SL',
|
||||
'desc': 'Selection oblique left; remove <u> tags',
|
||||
'pad': 'foo[<u>bar]</u>baz' },
|
||||
|
||||
{ 'id': 'U_U-1_SR',
|
||||
'desc': 'Selection oblique right; remove <u> tags',
|
||||
'pad': 'foo<u>[bar</u>]baz' },
|
||||
|
||||
{ 'id': 'U_SPANs:td:u-1_SW',
|
||||
'desc': 'Selection within tags; remove "text-decoration: underline"',
|
||||
'pad': 'foo<span style="text-decoration: underline">[bar]</span>baz' },
|
||||
|
||||
{ 'id': 'U_SPANs:td:u-1_SO',
|
||||
'desc': 'Selection outside of tags; remove "text-decoration: underline"',
|
||||
'pad': 'foo[<span style="text-decoration: underline">bar</span>]baz' },
|
||||
|
||||
{ 'id': 'U_SPANs:td:u-1_SL',
|
||||
'desc': 'Selection oblique left; remove "text-decoration: underline"',
|
||||
'pad': 'foo[<span style="text-decoration: underline">bar]</span>baz' },
|
||||
|
||||
{ 'id': 'U_SPANs:td:u-1_SR',
|
||||
'desc': 'Selection oblique right; remove "text-decoration: underline"',
|
||||
'pad': 'foo<span style="text-decoration: underline">[bar</span>]baz' }
|
||||
]
|
||||
},
|
||||
|
||||
{ 'desc': 'remove strike-through',
|
||||
'command': 'strikethrough',
|
||||
'tests': [
|
||||
{ 'id': 'S_S-1_SW',
|
||||
'desc': 'Selection within tags; remove <s> tags',
|
||||
'pad': 'foo<s>[bar]</s>baz' },
|
||||
|
||||
{ 'id': 'S_S-1_SO',
|
||||
'desc': 'Selection outside of tags; remove <s> tags',
|
||||
'pad': 'foo[<s>bar</s>]baz' },
|
||||
|
||||
{ 'id': 'S_S-1_SL',
|
||||
'desc': 'Selection oblique left; remove <s> tags',
|
||||
'pad': 'foo[<s>bar]</s>baz' },
|
||||
|
||||
{ 'id': 'S_S-1_SR',
|
||||
'desc': 'Selection oblique right; remove <s> tags',
|
||||
'pad': 'foo<s>[bar</s>]baz' },
|
||||
|
||||
{ 'id': 'S_STRIKE-1_SW',
|
||||
'desc': 'Selection within tags; remove <strike> tags',
|
||||
'pad': 'foo<strike>[bar]</strike>baz' },
|
||||
|
||||
{ 'id': 'S_STRIKE-1_SO',
|
||||
'desc': 'Selection outside of tags; remove <strike> tags',
|
||||
'pad': 'foo[<strike>bar</strike>]baz' },
|
||||
|
||||
{ 'id': 'S_STRIKE-1_SL',
|
||||
'desc': 'Selection oblique left; remove <strike> tags',
|
||||
'pad': 'foo[<strike>bar]</strike>baz' },
|
||||
|
||||
{ 'id': 'S_STRIKE-1_SR',
|
||||
'desc': 'Selection oblique right; remove <strike> tags',
|
||||
'pad': 'foo<strike>[bar</strike>]baz' },
|
||||
|
||||
{ 'id': 'S_SPANs:td:lt-1_SW',
|
||||
'desc': 'Selection within tags; remove "text-decoration:line-through"',
|
||||
'pad': 'foo<span style="text-decoration:line-through">[bar]</span>baz' },
|
||||
|
||||
{ 'id': 'S_SPANs:td:lt-1_SO',
|
||||
'desc': 'Selection outside of tags; Italicize "text-decoration:line-through"',
|
||||
'pad': 'foo[<span style="text-decoration:line-through">bar</span>]baz' },
|
||||
|
||||
{ 'id': 'S_SPANs:td:lt-1_SL',
|
||||
'desc': 'Selection oblique left; Italicize "text-decoration:line-through"',
|
||||
'pad': 'foo[<span style="text-decoration:line-through">bar]</span>baz' },
|
||||
|
||||
{ 'id': 'S_SPANs:td:lt-1_SR',
|
||||
'desc': 'Selection oblique right; Italicize "text-decoration:line-through"',
|
||||
'pad': 'foo<span style="text-decoration:line-through">[bar</span>]baz' },
|
||||
|
||||
{ 'id': 'S_SPANc:s-1_SW',
|
||||
'desc': 'Unapply "strike-through" on interited CSS style',
|
||||
'checkClass': True,
|
||||
'pad': 'foo<span class="s">[bar]</span>baz' },
|
||||
|
||||
{ 'id': 'S_SPANc:s-2_SI',
|
||||
'desc': 'Unapply "strike-through" on interited CSS style',
|
||||
'pad': '<span class="s">foo[bar]baz</span>',
|
||||
'checkClass': True,
|
||||
'expected': '<span class="s">foo</span>[bar]<span class="s">baz</span>' }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -0,0 +1,103 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
|
||||
<title>Rich Text 2 Unit Test Example</title>
|
||||
|
||||
<!-- utility scripts -->
|
||||
<script type="text/javascript" src="static/js/variables.js"></script>
|
||||
<script type="text/javascript" src="static/js/canonicalize.js"></script>
|
||||
<script type="text/javascript" src="static/js/compare.js"></script>
|
||||
<script type="text/javascript" src="static/js/pad.js"></script>
|
||||
<script type="text/javascript" src="static/js/range.js"></script>
|
||||
<script type="text/javascript" src="static/js/units.js"></script>
|
||||
<script type="text/javascript" src="static/js/run.js"></script>
|
||||
<!-- you do not need static/js/output.js -->
|
||||
|
||||
<!--
|
||||
Tests - note that those have the extensions .py,
|
||||
but can be used as JS files directly.
|
||||
-->
|
||||
<script type="text/javascript" src="tests/selection.py"></script>
|
||||
<script type="text/javascript" src="tests/apply.py"></script>
|
||||
<script type="text/javascript" src="tests/applyCSS.py"></script>
|
||||
<script type="text/javascript" src="tests/change.py"></script>
|
||||
<script type="text/javascript" src="tests/changeCSS.py"></script>
|
||||
<script type="text/javascript" src="tests/unapply.py"></script>
|
||||
<script type="text/javascript" src="tests/unapplyCSS.py"></script>
|
||||
<script type="text/javascript" src="tests/delete.py"></script>
|
||||
<script type="text/javascript" src="tests/forwarddelete.py"></script>
|
||||
<script type="text/javascript" src="tests/insert.py"></script>
|
||||
<script type="text/javascript" src="tests/querySupported.py"></script>
|
||||
<script type="text/javascript" src="tests/queryEnabled.py"></script>
|
||||
<script type="text/javascript" src="tests/queryIndeterm.py"></script>
|
||||
<script type="text/javascript" src="tests/queryState.py"></script>
|
||||
<script type="text/javascript" src="tests/queryValue.py"></script>
|
||||
|
||||
<!-- Do something -->
|
||||
<script type="text/javascript">
|
||||
function runTest() {
|
||||
initVariables();
|
||||
initEditorDocs();
|
||||
|
||||
runTestSuite(UNAPPLY_TESTS);
|
||||
|
||||
// Below alert is just a simple demonstration on how to access the test results.
|
||||
// Note that we only ran UNAPPLY tests above, so we have only results from that test set.
|
||||
//
|
||||
// The 'results' structure is as follows:
|
||||
//
|
||||
// results structure containing all results
|
||||
// [<suite ID>] structure containing the results for the given suite *)
|
||||
// .count number of tests in the given suite
|
||||
// .valscore sum of all test value results (HTML or query value)
|
||||
// .selscore sum of all selection results (HTML tests only)
|
||||
// [<class ID>] structure containing the results for the given class **)
|
||||
// .count number of tests in the given suite
|
||||
// .valscore sum of all test value results (HTML or query value)
|
||||
// .selscore sum of all selection results (HTML tests only)
|
||||
// [<test ID>] structure containing the reults for a given test ***)
|
||||
// .valscore value score (0 or 1), minimum over all containers
|
||||
// .selscore selection score (0 or 1), minimum over all containers (HTML tests only)
|
||||
// .valresult worst test value result (integer, see variables.js)
|
||||
// .selresult worst selection result (integer, see variables.js)
|
||||
// [<cont. ID>] structure containing the results of the test for a given container ****)
|
||||
// .valscore value score (0 or 1)
|
||||
// .selscore selection score (0 or 1)
|
||||
// .valresult value result (integer, see variables.js)
|
||||
// .selresult selection result (integer, see variables.js)
|
||||
// .output output string (mainly for use by the online version)
|
||||
// .innerHTML inner HTML of the testing container (<div> or <body>) after the test
|
||||
// .outerHTML outer HTML of the testing container (<div> or <body>) after the test
|
||||
// .bodyInnerHTML inner HTML of the <body> after the test
|
||||
// .bodyOuterHTML outer HTML of the <body> after the test
|
||||
//
|
||||
// *) <suite ID>: a 1-3 character ID, e.g. UNAPPLY_TESTS.id, or 'U' (both referring the same suite)
|
||||
// **) <class ID>: one of 'Proposed', 'RFC' or 'Finalized'
|
||||
// ***) <test ID>: the ID of the test, without the leading 'RTE2-<suite ID>_' part
|
||||
// ****) <container ID>: one of 'div' (test within a <div contenteditable="true">)
|
||||
// 'dM' (test with designMode = 'on')
|
||||
// 'body' (test within a <body contenteditable="true">)
|
||||
|
||||
alert("Result of 'Apply' tests:\nOut of " +
|
||||
results[UNAPPLY_TESTS.id].count + " tests\n" +
|
||||
results[UNAPPLY_TESTS.id].valscore + " had correct HTML, and\n" +
|
||||
results[UNAPPLY_TESTS.id].selscore + " had a correct result selection\n(in all testing containers)." +
|
||||
"\n\n" +
|
||||
"Test RTE2-U_B_B-1_SW results with a contenteditable <body>:\n" +
|
||||
results['U']['Proposed']['B_B-1_SW']['body'].valscore + " points for the value result, and\n" +
|
||||
results['U']['Proposed']['B_B-1_SW']['body'].selscore + " points for the selection" +
|
||||
""
|
||||
);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload="runTest()">
|
||||
<iframe name="iframe-dM" id="iframe-dM" src="static/editable-dM.html"></iframe>
|
||||
<iframe name="iframe-body" id="iframe-body" src="static/editable-body.html"></iframe>
|
||||
<iframe name="iframe-div" id="iframe-div" src="static/editable-div.html"></iframe>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,19 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -x
|
||||
|
||||
if test -d richtext2; then
|
||||
rm -drf richtext2;
|
||||
fi
|
||||
|
||||
svn checkout http://browserscope.googlecode.com/svn/trunk/categories/richtext2 richtext2 | tail -1 | sed 's/[^0-9]//g' > current_revision
|
||||
|
||||
find richtext2 -type d -name .svn -exec rm -drf \{\} \; 2> /dev/null
|
||||
|
||||
# Remove test_set.py and other similarly named files because they confuse our mochitest runner
|
||||
find richtext2 =type f -name test_\* -exec rm -rf \{\} \; 2> /dev/null
|
||||
|
||||
hg add current_revision richtext2
|
||||
|
||||
hg stat .
|
||||
|
263
editor/libeditor/html/tests/browserscope/test_richtext2.html
Normal file
263
editor/libeditor/html/tests/browserscope/test_richtext2.html
Normal file
@ -0,0 +1,263 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<!--
|
||||
BrowserScope richtext2 category tests
|
||||
|
||||
This test is originally based on the unit test example available as part of the
|
||||
RichText2 suite:
|
||||
http://code.google.com/p/browserscope/source/browse/trunk/categories/richtext2/unittestexample.html
|
||||
-->
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
|
||||
<title>BrowserScope Richtext2 Tests</title>
|
||||
<script type="application/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
|
||||
<!-- utility scripts -->
|
||||
<script type="text/javascript" src="lib/richtext2/richtext2/static/js/variables.js"></script>
|
||||
<script type="text/javascript" src="lib/richtext2/richtext2/static/js/canonicalize.js"></script>
|
||||
<script type="text/javascript" src="lib/richtext2/richtext2/static/js/compare.js"></script>
|
||||
<script type="text/javascript" src="lib/richtext2/richtext2/static/js/pad.js"></script>
|
||||
<script type="text/javascript" src="lib/richtext2/richtext2/static/js/range.js"></script>
|
||||
<script type="text/javascript" src="lib/richtext2/richtext2/static/js/units.js"></script>
|
||||
<script type="text/javascript" src="lib/richtext2/richtext2/static/js/run.js"></script>
|
||||
<!-- you do not need static/js/output.js -->
|
||||
|
||||
<!--
|
||||
Tests - note that those have the extensions .py,
|
||||
but can be used as JS files directly.
|
||||
-->
|
||||
<script type="text/javascript" src="lib/richtext2/richtext2/tests/selection.py"></script>
|
||||
<script type="text/javascript" src="lib/richtext2/richtext2/tests/apply.py"></script>
|
||||
<script type="text/javascript" src="lib/richtext2/richtext2/tests/applyCSS.py"></script>
|
||||
<script type="text/javascript" src="lib/richtext2/richtext2/tests/change.py"></script>
|
||||
<script type="text/javascript" src="lib/richtext2/richtext2/tests/changeCSS.py"></script>
|
||||
<script type="text/javascript" src="lib/richtext2/richtext2/tests/unapply.py"></script>
|
||||
<script type="text/javascript" src="lib/richtext2/richtext2/tests/unapplyCSS.py"></script>
|
||||
<script type="text/javascript" src="lib/richtext2/richtext2/tests/delete.py"></script>
|
||||
<script type="text/javascript" src="lib/richtext2/richtext2/tests/forwarddelete.py"></script>
|
||||
<script type="text/javascript" src="lib/richtext2/richtext2/tests/insert.py"></script>
|
||||
<script type="text/javascript" src="lib/richtext2/richtext2/tests/querySupported.py"></script>
|
||||
<script type="text/javascript" src="lib/richtext2/richtext2/tests/queryEnabled.py"></script>
|
||||
<script type="text/javascript" src="lib/richtext2/richtext2/tests/queryIndeterm.py"></script>
|
||||
<script type="text/javascript" src="lib/richtext2/richtext2/tests/queryState.py"></script>
|
||||
<script type="text/javascript" src="lib/richtext2/richtext2/tests/queryValue.py"></script>
|
||||
|
||||
<script type="text/javascript" src="lib/richtext2/currentStatus.js"></script>
|
||||
|
||||
<!-- Do something -->
|
||||
<script type="text/javascript">
|
||||
// Set this constant to true in order to get the current status of the test suite.
|
||||
// This is useful for updating the currentStatus.js file when an editor bug is fixed.
|
||||
const UPDATE_TEST_RESULTS = false;
|
||||
|
||||
function runTest() {
|
||||
initVariables();
|
||||
initEditorDocs();
|
||||
|
||||
const tests = [
|
||||
SELECTION_TESTS,
|
||||
APPLY_TESTS,
|
||||
APPLY_TESTS_CSS,
|
||||
CHANGE_TESTS,
|
||||
CHANGE_TESTS_CSS,
|
||||
UNAPPLY_TESTS,
|
||||
UNAPPLY_TESTS_CSS,
|
||||
DELETE_TESTS,
|
||||
FORWARDDELETE_TESTS,
|
||||
INSERT_TESTS,
|
||||
QUERYSUPPORTED_TESTS,
|
||||
QUERYENABLED_TESTS,
|
||||
QUERYINDETERM_TESTS,
|
||||
QUERYSTATE_TESTS,
|
||||
QUERYVALUE_TESTS,
|
||||
];
|
||||
|
||||
for (var i = 0; i < tests.length; ++i) {
|
||||
runTestSuite(tests[i]);
|
||||
}
|
||||
|
||||
// Below alert is just a simple demonstration on how to access the test results.
|
||||
// Note that we only ran UNAPPLY tests above, so we have only results from that test set.
|
||||
//
|
||||
// The 'results' structure is as follows:
|
||||
//
|
||||
// results structure containing all results
|
||||
// [<suite ID>] structure containing the results for the given suite *)
|
||||
// .count number of tests in the given suite
|
||||
// .valscore sum of all test value results (HTML or query value)
|
||||
// .selscore sum of all selection results (HTML tests only)
|
||||
// [<class ID>] structure containing the results for the given class **)
|
||||
// .count number of tests in the given suite
|
||||
// .valscore sum of all test value results (HTML or query value)
|
||||
// .selscore sum of all selection results (HTML tests only)
|
||||
// [<test ID>] structure containing the reults for a given test ***)
|
||||
// .valscore value score (0 or 1), minimum over all containers
|
||||
// .selscore selection score (0 or 1), minimum over all containers (HTML tests only)
|
||||
// .valresult worst test value result (integer, see variables.js)
|
||||
// .selresult worst selection result (integer, see variables.js)
|
||||
// [<cont. ID>] structure containing the results of the test for a given container ****)
|
||||
// .valscore value score (0 or 1)
|
||||
// .selscore selection score (0 or 1)
|
||||
// .valresult value result (integer, see variables.js)
|
||||
// .selresult selection result (integer, see variables.js)
|
||||
// .output output string (mainly for use by the online version)
|
||||
// .innerHTML inner HTML of the testing container (<div> or <body>) after the test
|
||||
// .outerHTML outer HTML of the testing container (<div> or <body>) after the test
|
||||
// .bodyInnerHTML inner HTML of the <body> after the test
|
||||
// .bodyOuterHTML outer HTML of the <body> after the test
|
||||
//
|
||||
// *) <suite ID>: a 1-3 character ID, e.g. UNAPPLY_TESTS.id, or 'U' (both referring the same suite)
|
||||
// **) <class ID>: one of 'Proposed', 'RFC' or 'Finalized'
|
||||
// ***) <test ID>: the ID of the test, without the leading 'RTE2-<suite ID>_' part
|
||||
// ****) <container ID>: one of 'div' (test within a <div contenteditable="true">)
|
||||
// 'dM' (test with designMode = 'on')
|
||||
// 'body' (test within a <body contenteditable="true">)
|
||||
|
||||
if (UPDATE_TEST_RESULTS) {
|
||||
var testResults = {};
|
||||
for (var i = 0; i < tests.length; ++i) {
|
||||
var category = tests[i];
|
||||
testResults[category.id] = {};
|
||||
for (var group in results[category.id]) {
|
||||
switch (group) {
|
||||
// Skip the known properties
|
||||
case "count":
|
||||
case "valscore":
|
||||
case "selscore":
|
||||
case "time":
|
||||
break;
|
||||
default:
|
||||
testResults[category.id][group] = {};
|
||||
for (var test_id in results[category.id][group]) {
|
||||
switch (test_id) {
|
||||
// Skip the known properties
|
||||
case "count":
|
||||
case "valscore":
|
||||
case "selscore":
|
||||
break;
|
||||
default:
|
||||
testResults[category.id][group][test_id] = {};
|
||||
for (var structure in results[category.id][group][test_id]) {
|
||||
switch (structure) {
|
||||
// Only look at each test structure
|
||||
case "dM":
|
||||
case "body":
|
||||
case "div":
|
||||
var row = results[category.id][group][test_id][structure];
|
||||
testResults[category.id][group][test_id][structure] = row;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var resultContainer = document.getElementById("results");
|
||||
resultContainer.style.display = "";
|
||||
resultContainer.textContent = JSON.stringify(testResults);
|
||||
} else {
|
||||
for (var i = 0; i < tests.length; ++i) {
|
||||
var category = tests[i];
|
||||
for (var group in results[category.id]) {
|
||||
switch (group) {
|
||||
// Skip the known properties
|
||||
case "count":
|
||||
case "valscore":
|
||||
case "selscore":
|
||||
case "time":
|
||||
break;
|
||||
default:
|
||||
for (var test_id in results[category.id][group]) {
|
||||
switch (test_id) {
|
||||
// Skip the known properties
|
||||
case "count":
|
||||
case "valscore":
|
||||
case "selscore":
|
||||
break;
|
||||
default:
|
||||
for (var structure in results[category.id][group][test_id]) {
|
||||
switch (structure) {
|
||||
// Only look at each test structure
|
||||
case "dM":
|
||||
case "body":
|
||||
case "div":
|
||||
var row = results[category.id][group][test_id][structure];
|
||||
var expected = TEST_RESULTS[category.id][group][test_id][structure];
|
||||
var testName = "[" + [category.id, group, test_id, structure].join(", ") + "]";
|
||||
// There are three possible cases here:
|
||||
// a) If row.valscore == 1 and expected.valscore == 1, then the test has passed successfully.
|
||||
// b) If row.valscore == 1 and expected.valscore == 0, a previously failing test has started to pass.
|
||||
// In this case, the respective currentStatus.js entry should be modified.
|
||||
// c) If row.valscore == 0 && expected.valscore == 0, then the test is known to fail.
|
||||
// d) If row.valscore == 0 && expected.valscore == 1, then we've found a regression, which should be fixed.
|
||||
// The same logic goes for selscore too.
|
||||
if (row.valscore == 1 && expected.valscore == 1) {
|
||||
// successful
|
||||
is(row.valscore, expected.valscore, testName + " passed successfully");
|
||||
} else if (row.valscore == 1 && expected.valscore == 0) {
|
||||
// unexpected pass
|
||||
todo_is(row.valscore, 1, testName + " used to fail, but it just started passing");
|
||||
// debugging information
|
||||
is(row.output, expected.output, "HTML test result comparison");
|
||||
} else if (row.valscore == 0 && expected.valscore == 0) {
|
||||
// known failure
|
||||
todo_is(row.valscore, 1, testName + " is known to fail");
|
||||
} else if (row.valscore == 0 && expected.valscore == 1) {
|
||||
// regression
|
||||
is(row.valscore, expected.valscore, testName + " has regressed");
|
||||
// debugging information
|
||||
is(row.output, expected.output, "HTML test result comparison");
|
||||
} else {
|
||||
// sanity check: this shouldn't happen!
|
||||
ok(false, "Unexpected result: row = " + row.toSource() + ", expected: " + expected.toSource());
|
||||
}
|
||||
if (row.selscore == 1 && expected.selscore == 1) {
|
||||
// successful
|
||||
is(row.selscore, expected.selscore, testName + " passed successfully");
|
||||
} else if (row.selscore == 1 && expected.selscore == 0) {
|
||||
// unexpected pass
|
||||
todo_is(row.selscore, 1, testName + " used to fail, but it just started passing");
|
||||
// debugging information
|
||||
is(row.output, expected.output, "HTML test result comparison");
|
||||
} else if (row.selscore == 0 && expected.selscore == 0) {
|
||||
// known failure
|
||||
todo_is(row.selscore, 1, testName + " is known to fail");
|
||||
} else if (row.selscore == 0 && expected.selscore == 1) {
|
||||
// regression
|
||||
is(row.selscore, expected.selscore, testName + " has regressed");
|
||||
// debugging information
|
||||
is(row.output, expected.output, "HTML test result comparison");
|
||||
} else {
|
||||
// sanity check: this shouldn't happen!
|
||||
ok(false, "Unexpected result: row = " + row.toSource() + ", expected: " + expected.toSource());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
// Running all of the tests can take a long time, try to account for it
|
||||
SimpleTest.requestLongerTimeout(5);
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload="runTest()">
|
||||
<iframe name="iframe-dM" id="iframe-dM" src="lib/richtext2/richtext2/static/editable-dM.html"></iframe>
|
||||
<iframe name="iframe-body" id="iframe-body" src="lib/richtext2/richtext2/static/editable-body.html"></iframe>
|
||||
<iframe name="iframe-div" id="iframe-div" src="lib/richtext2/richtext2/static/editable-div.html"></iframe>
|
||||
<pre id="results" style="display: none"></pre>
|
||||
</body>
|
||||
</html>
|
65
editor/libeditor/html/tests/test_bug635636.html
Normal file
65
editor/libeditor/html/tests/test_bug635636.html
Normal file
@ -0,0 +1,65 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=635636
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 635636</title>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=635636">Mozilla Bug 635636</a>
|
||||
<p id="display"></p>
|
||||
<div id="content">
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 635636 **/
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addLoadEvent(function() {
|
||||
var w, d;
|
||||
|
||||
function b1()
|
||||
{
|
||||
w = window.open('data:application/xhtml+xml,<html xmlns="http://www.w3.org/1999/xhtml"><div>1</div></html>');
|
||||
SimpleTest.waitForFocus(b2, w);
|
||||
}
|
||||
|
||||
function b2()
|
||||
{
|
||||
w.document.designMode = 'on';
|
||||
w.location = "data:text/plain,2";
|
||||
d = w.document.getElementsByTagName("div")[0];
|
||||
const Ci = Components.interfaces;
|
||||
var mainWindow = w.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIDocShellTreeItem)
|
||||
.rootTreeItem
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindow);
|
||||
var browser = mainWindow.gBrowser.selectedBrowser;
|
||||
browser.addEventListener("pageshow", function() {
|
||||
setTimeout(b3, 0);
|
||||
}, false);
|
||||
}
|
||||
|
||||
function b3()
|
||||
{
|
||||
d.parentNode.removeChild(d);
|
||||
ok(true, "Should not crash");
|
||||
// Not needed for the crash
|
||||
w.close();
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
b1();
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
193
editor/libeditor/html/tests/test_bug640321.html
Normal file
193
editor/libeditor/html/tests/test_bug640321.html
Normal file
@ -0,0 +1,193 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=640321
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 640321</title>
|
||||
<script type="application/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=640321">Mozilla Bug 640321</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" contenteditable style="text-align: center">
|
||||
<img src="green.png">
|
||||
</div>
|
||||
<div id="clickaway" style="width: 10px; height: 10px"></div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 640321 **/
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SimpleTest.waitForFocus(function() {
|
||||
var img = document.querySelector("img");
|
||||
|
||||
function cancel(e) { e.stopPropagation(); }
|
||||
var content = document.getElementById("content");
|
||||
content.addEventListener("mousedown", cancel, false);
|
||||
content.addEventListener("mousemove", cancel, false);
|
||||
content.addEventListener("mouseup", cancel, false);
|
||||
|
||||
/**
|
||||
* This function is a generic resizer test.
|
||||
* We have 8 resizers that we'd like to test, and each can be moved in 8 different directions.
|
||||
* In specifying baseX, W can be considered to be the width of the image, and for baseY, H
|
||||
* can be considered to be the height of the image. deltaX and deltaY are regular pixel values
|
||||
* which can be positive or negative.
|
||||
*/
|
||||
const W = 1;
|
||||
const H = 1;
|
||||
function testResizer(baseX, baseY, deltaX, deltaY, expectedDeltaX, expectedDeltaY) {
|
||||
ok(true, "testResizer(" + [baseX, baseY, deltaX, deltaY, expectedDeltaX, expectedDeltaY].join(", ") + ")");
|
||||
|
||||
// Reset the dimensions of the image
|
||||
img.style.width = "100px";
|
||||
img.style.height = "100px";
|
||||
var rect = img.getBoundingClientRect();
|
||||
is(rect.width, 100, "Sanity check the length");
|
||||
is(rect.height, 100, "Sanity check the height");
|
||||
|
||||
// Click on the image to show the resizers
|
||||
synthesizeMouseAtCenter(img, {});
|
||||
|
||||
// Determine which resizer we're dealing with
|
||||
var basePosX = rect.width * baseX;
|
||||
var basePosY = rect.height * baseY;
|
||||
|
||||
// Click on the correct resizer
|
||||
synthesizeMouse(img, basePosX, basePosY, {type: "mousedown"});
|
||||
// Drag it delta pixels to the right and bottom (or maybe left and top!)
|
||||
synthesizeMouse(img, basePosX + deltaX, basePosY + deltaY, {type: "mousemove"});
|
||||
// Release the mouse button
|
||||
synthesizeMouse(img, basePosX + deltaX, basePosY + deltaY, {type: "mouseup"});
|
||||
// Move the mouse delta more pixels to the same direction to make sure that the
|
||||
// resize operation has stopped.
|
||||
synthesizeMouse(img, basePosX + deltaX * 2, basePosY + deltaY * 2, {type: "mousemove"});
|
||||
// Click outside of the image to hide the resizers
|
||||
synthesizeMouseAtCenter(document.getElementById("clickaway"), {});
|
||||
|
||||
// Get the new dimensions for the image
|
||||
var newRect = img.getBoundingClientRect();
|
||||
is(newRect.width, rect.width + expectedDeltaX, "The width should be increased by " + expectedDeltaX + " pixels");
|
||||
is(newRect.height, rect.height + expectedDeltaY, "The height should be increased by " + expectedDeltaY + "pixels");
|
||||
}
|
||||
|
||||
function runTests(preserveRatio) {
|
||||
// Account for changes in the resizing behavior when we're trying to preserve
|
||||
// the aspect ration.
|
||||
// ignoredGrowth means we don't change the size of a dimension because otherwise
|
||||
// the aspect ratio would change undesirably.
|
||||
// needlessGrowth means that we change the size of a dimension perpendecular to
|
||||
// the mouse movement axis in order to preserve the aspect ratio.
|
||||
// reversedGrowth means that we change the size of a dimension in the opposite
|
||||
// direction to the mouse movement in order to maintain the aspect ratio.
|
||||
const ignoredGrowth = preserveRatio ? 0 : 1;
|
||||
const needlessGrowth = preserveRatio ? 1 : 0;
|
||||
const reversedGrowth = preserveRatio ? -1 : 1;
|
||||
|
||||
SpecialPowers.setBoolPref("editor.resizing.preserve_ratio", preserveRatio);
|
||||
|
||||
// top resizer
|
||||
testResizer(W/2, 0, -10, -10, 0, 10);
|
||||
testResizer(W/2, 0, -10, 0, 0, 0);
|
||||
testResizer(W/2, 0, -10, 10, 0, -10);
|
||||
testResizer(W/2, 0, 0, -10, 0, 10);
|
||||
testResizer(W/2, 0, 0, 0, 0, 0);
|
||||
testResizer(W/2, 0, 0, 10, 0, -10);
|
||||
testResizer(W/2, 0, 10, -10, 0, 10);
|
||||
testResizer(W/2, 0, 10, 0, 0, 0);
|
||||
testResizer(W/2, 0, 10, 10, 0, -10);
|
||||
|
||||
// top right resizer
|
||||
testResizer( W, 0, -10, -10, -10 * reversedGrowth, 10);
|
||||
testResizer( W, 0, -10, 0, -10 * ignoredGrowth, 0);
|
||||
testResizer( W, 0, -10, 10, -10, -10);
|
||||
testResizer( W, 0, 0, -10, 10 * needlessGrowth, 10);
|
||||
testResizer( W, 0, 0, 0, 0, 0);
|
||||
testResizer( W, 0, 0, 10, 0, -10 * ignoredGrowth);
|
||||
testResizer( W, 0, 10, -10, 10, 10);
|
||||
testResizer( W, 0, 10, 0, 10, 10 * needlessGrowth);
|
||||
testResizer( W, 0, 10, 10, 10, -10 * reversedGrowth);
|
||||
|
||||
// right resizer
|
||||
testResizer( W, H/2, -10, -10, -10, 0);
|
||||
testResizer( W, H/2, -10, 0, -10, 0);
|
||||
testResizer( W, H/2, -10, 10, -10, 0);
|
||||
testResizer( W, H/2, 0, -10, 0, 0);
|
||||
testResizer( W, H/2, 0, 0, 0, 0);
|
||||
testResizer( W, H/2, 0, 10, 0, 0);
|
||||
testResizer( W, H/2, 10, -10, 10, 0);
|
||||
testResizer( W, H/2, 10, 0, 10, 0);
|
||||
testResizer( W, H/2, 10, 10, 10, 0);
|
||||
|
||||
// bottom right resizer
|
||||
testResizer( W, H, -10, -10, -10, -10);
|
||||
testResizer( W, H, -10, 0, -10 * ignoredGrowth, 0);
|
||||
testResizer( W, H, -10, 10, -10 * reversedGrowth, 10);
|
||||
testResizer( W, H, 0, -10, 0, -10 * ignoredGrowth);
|
||||
testResizer( W, H, 0, 0, 0, 0);
|
||||
testResizer( W, H, 0, 10, 10 * needlessGrowth, 10);
|
||||
testResizer( W, H, 10, -10, 10, -10 * reversedGrowth);
|
||||
testResizer( W, H, 10, 0, 10, 10 * needlessGrowth);
|
||||
testResizer( W, H, 10, 10, 10, 10);
|
||||
|
||||
// bottom resizer
|
||||
testResizer(W/2, H, -10, -10, 0, -10);
|
||||
testResizer(W/2, H, -10, 0, 0, 0);
|
||||
testResizer(W/2, H, -10, 10, 0, 10);
|
||||
testResizer(W/2, H, 0, -10, 0, -10);
|
||||
testResizer(W/2, H, 0, 0, 0, 0);
|
||||
testResizer(W/2, H, 0, 10, 0, 10);
|
||||
testResizer(W/2, H, 10, -10, 0, -10);
|
||||
testResizer(W/2, H, 10, 0, 0, 0);
|
||||
testResizer(W/2, H, 10, 10, 0, 10);
|
||||
|
||||
// bottom left resizer
|
||||
testResizer( 0, H, -10, -10, 10, -10 * reversedGrowth);
|
||||
testResizer( 0, H, -10, 0, 10, 10 * needlessGrowth);
|
||||
testResizer( 0, H, -10, 10, 10, 10);
|
||||
testResizer( 0, H, 0, -10, 0, -10 * ignoredGrowth);
|
||||
testResizer( 0, H, 0, 0, 0, 0);
|
||||
testResizer( 0, H, 0, 10, 10 * needlessGrowth, 10);
|
||||
testResizer( 0, H, 10, -10, -10, -10);
|
||||
testResizer( 0, H, 10, 0, -10 * ignoredGrowth, 0);
|
||||
testResizer( 0, H, 10, 10, -10 * reversedGrowth, 10);
|
||||
|
||||
// left resizer
|
||||
testResizer( 0, H/2, -10, -10, 10, 0);
|
||||
testResizer( 0, H/2, -10, 0, 10, 0);
|
||||
testResizer( 0, H/2, -10, 10, 10, 0);
|
||||
testResizer( 0, H/2, 0, -10, 0, 0);
|
||||
testResizer( 0, H/2, 0, 0, 0, 0);
|
||||
testResizer( 0, H/2, 0, 10, 0, 0);
|
||||
testResizer( 0, H/2, 10, -10, -10, 0);
|
||||
testResizer( 0, H/2, 10, 0, -10, 0);
|
||||
testResizer( 0, H/2, 10, 10, -10, 0);
|
||||
|
||||
// top left resizer
|
||||
testResizer( 0, 0, -10, -10, 10, 10);
|
||||
testResizer( 0, 0, -10, 0, 10, 10 * needlessGrowth);
|
||||
testResizer( 0, 0, -10, 10, 10, -10 * reversedGrowth);
|
||||
testResizer( 0, 0, 0, -10, 10 * needlessGrowth, 10);
|
||||
testResizer( 0, 0, 0, 0, 0, 0);
|
||||
testResizer( 0, 0, 0, 10, 0, -10 * ignoredGrowth);
|
||||
testResizer( 0, 0, 10, -10, -10 * reversedGrowth, 10);
|
||||
testResizer( 0, 0, 10, 0, -10 * ignoredGrowth, 0);
|
||||
testResizer( 0, 0, 10, 10, -10, -10);
|
||||
|
||||
SpecialPowers.clearUserPref("editor.resizing.preserve_ratio");
|
||||
}
|
||||
|
||||
runTests(false);
|
||||
runTests(true);
|
||||
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -139,12 +139,14 @@ NS_INTERFACE_MAP_END_INHERITING(nsEditor)
|
||||
|
||||
|
||||
NS_IMETHODIMP nsPlaintextEditor::Init(nsIDOMDocument *aDoc,
|
||||
nsIPresShell *aPresShell, nsIContent *aRoot, nsISelectionController *aSelCon, PRUint32 aFlags)
|
||||
nsIContent *aRoot,
|
||||
nsISelectionController *aSelCon,
|
||||
PRUint32 aFlags)
|
||||
{
|
||||
NS_TIME_FUNCTION;
|
||||
|
||||
NS_PRECONDITION(aDoc && aPresShell, "bad arg");
|
||||
NS_ENSURE_TRUE(aDoc && aPresShell, NS_ERROR_NULL_POINTER);
|
||||
NS_PRECONDITION(aDoc, "bad arg");
|
||||
NS_ENSURE_TRUE(aDoc, NS_ERROR_NULL_POINTER);
|
||||
|
||||
nsresult res = NS_OK, rulesRes = NS_OK;
|
||||
|
||||
@ -154,7 +156,7 @@ NS_IMETHODIMP nsPlaintextEditor::Init(nsIDOMDocument *aDoc,
|
||||
nsAutoEditInitRulesTrigger rulesTrigger(this, rulesRes);
|
||||
|
||||
// Init the base editor
|
||||
res = nsEditor::Init(aDoc, aPresShell, aRoot, aSelCon, aFlags);
|
||||
res = nsEditor::Init(aDoc, aRoot, aSelCon, aFlags);
|
||||
}
|
||||
|
||||
// check the "single line editor newline handling"
|
||||
@ -671,7 +673,8 @@ nsPlaintextEditor::ExtendSelectionForDelete(nsISelection *aSelection,
|
||||
|| (*aAction == ePrevious && bCollapsed)
|
||||
|| *aAction == eToBeginningOfLine || *aAction == eToEndOfLine)
|
||||
{
|
||||
nsCOMPtr<nsISelectionController> selCont (do_QueryReferent(mSelConWeak));
|
||||
nsCOMPtr<nsISelectionController> selCont;
|
||||
GetSelectionController(getter_AddRefs(selCont));
|
||||
NS_ENSURE_TRUE(selCont, NS_ERROR_NO_INTERFACE);
|
||||
|
||||
switch (*aAction)
|
||||
@ -956,7 +959,8 @@ nsPlaintextEditor::UpdateIMEComposition(const nsAString& aCompositionString,
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPresShell> ps = do_QueryReferent(mPresShellWeak);
|
||||
nsCOMPtr<nsIPresShell> ps;
|
||||
GetPresShell(getter_AddRefs(ps));
|
||||
NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
nsCOMPtr<nsISelection> selection;
|
||||
@ -1285,7 +1289,8 @@ nsPlaintextEditor::FireClipboardEvent(PRInt32 aType)
|
||||
if (aType == NS_PASTE)
|
||||
ForceCompositionEnd();
|
||||
|
||||
nsCOMPtr<nsIPresShell> presShell = do_QueryReferent(mPresShellWeak);
|
||||
nsCOMPtr<nsIPresShell> presShell;
|
||||
GetPresShell(getter_AddRefs(presShell));
|
||||
NS_ENSURE_TRUE(presShell, PR_FALSE);
|
||||
|
||||
nsCOMPtr<nsISelection> selection;
|
||||
@ -1336,17 +1341,14 @@ nsPlaintextEditor::GetAndInitDocEncoder(const nsAString& aFormatType,
|
||||
const nsACString& aCharset,
|
||||
nsIDocumentEncoder** encoder)
|
||||
{
|
||||
nsCOMPtr<nsIPresShell> presShell;
|
||||
nsresult rv = GetPresShell(getter_AddRefs(presShell));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
nsCAutoString formatType(NS_DOC_ENCODER_CONTRACTID_BASE);
|
||||
formatType.AppendWithConversion(aFormatType);
|
||||
nsCOMPtr<nsIDocumentEncoder> docEncoder (do_CreateInstance(formatType.get(), &rv));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsIDocument *doc = presShell->GetDocument();
|
||||
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak);
|
||||
nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(doc);
|
||||
NS_ASSERTION(domDoc, "Need a document");
|
||||
|
||||
|
@ -97,7 +97,7 @@ public:
|
||||
PRBool aSuppressTransaction);
|
||||
|
||||
/** prepare the editor for use */
|
||||
NS_IMETHOD Init(nsIDOMDocument *aDoc, nsIPresShell *aPresShell, nsIContent *aRoot, nsISelectionController *aSelCon, PRUint32 aFlags);
|
||||
NS_IMETHOD Init(nsIDOMDocument *aDoc, nsIContent *aRoot, nsISelectionController *aSelCon, PRUint32 aFlags);
|
||||
|
||||
NS_IMETHOD GetDocumentIsEmpty(PRBool *aDocumentIsEmpty);
|
||||
NS_IMETHOD GetIsDocumentEditable(PRBool *aIsDocumentEditable);
|
||||
|
@ -59,6 +59,8 @@ _TEST_FILES = \
|
||||
test_bug604532.html \
|
||||
test_bug625452.html \
|
||||
test_bug629172.html \
|
||||
test_bug638596.html \
|
||||
test_bug641466.html \
|
||||
$(NULL)
|
||||
|
||||
# disables the key handling test on gtk2 because gtk2 overrides some key events
|
||||
|
38
editor/libeditor/text/tests/test_bug638596.html
Normal file
38
editor/libeditor/text/tests/test_bug638596.html
Normal file
@ -0,0 +1,38 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=638596
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 638596</title>
|
||||
<script type="application/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=638596">Mozilla Bug 638596</a>
|
||||
<p id="display"></p>
|
||||
<div id="content">
|
||||
<input type="password" style="font-size: 0">
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 638596 **/
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SimpleTest.waitForFocus(function() {
|
||||
var i = document.querySelector("input");
|
||||
i.focus();
|
||||
synthesizeKey("t", {});
|
||||
synthesizeKey("e", {});
|
||||
synthesizeKey("s", {});
|
||||
synthesizeKey("t", {});
|
||||
is(i.value, "test", "The correct value should be stored in the field");
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
47
editor/libeditor/text/tests/test_bug641466.html
Normal file
47
editor/libeditor/text/tests/test_bug641466.html
Normal file
@ -0,0 +1,47 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=641466
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 641466</title>
|
||||
<script type="application/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=641466">Mozilla Bug 641466</a>
|
||||
<p id="display"></p>
|
||||
<div id="content">
|
||||
<input value="𐑑𐑧𐑕𐑑">
|
||||
<textarea>𐑑𐑧𐑕𐑑</textarea>
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 641466 **/
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SimpleTest.waitForFocus(function() {
|
||||
function doTest(element) {
|
||||
element.focus();
|
||||
element.selectionStart = 4;
|
||||
element.selectionEnd = 4;
|
||||
synthesizeKey("VK_BACKSPACE", {});
|
||||
synthesizeKey("VK_BACKSPACE", {});
|
||||
synthesizeKey("VK_BACKSPACE", {});
|
||||
synthesizeKey("VK_BACKSPACE", {});
|
||||
|
||||
ok(element.value, "", "4 backspaces should delete all of the characters in the " + element.localName);
|
||||
}
|
||||
|
||||
doTest(document.querySelector("input"));
|
||||
doTest(document.querySelector("textarea"));
|
||||
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -571,7 +571,7 @@ public class GeckoAppShell
|
||||
|
||||
Location loc = lm.getLastKnownLocation(provider);
|
||||
if (loc != null)
|
||||
sendEventToGecko(new GeckoEvent(loc));
|
||||
sendEventToGecko(new GeckoEvent(loc, null));
|
||||
lm.requestLocationUpdates(provider, 100, (float).5, GeckoApp.surfaceView, Looper.getMainLooper());
|
||||
} else {
|
||||
lm.removeUpdates(GeckoApp.surfaceView);
|
||||
|
@ -67,7 +67,6 @@ public class GeckoEvent {
|
||||
public static final int ACTIVITY_PAUSING = 9;
|
||||
public static final int ACTIVITY_SHUTDOWN = 10;
|
||||
public static final int LOAD_URI = 11;
|
||||
|
||||
public static final int SURFACE_CREATED = 12;
|
||||
public static final int SURFACE_DESTROYED = 13;
|
||||
public static final int GECKO_EVENT_SYNC = 14;
|
||||
@ -105,6 +104,7 @@ public class GeckoEvent {
|
||||
public int mRangeType, mRangeStyles;
|
||||
public int mRangeForeColor, mRangeBackColor;
|
||||
public Location mLocation;
|
||||
public Address mAddress;
|
||||
|
||||
public int mNativeWindow;
|
||||
|
||||
@ -145,9 +145,10 @@ public class GeckoEvent {
|
||||
mZ = s.values[2] / SensorManager.GRAVITY_EARTH;
|
||||
}
|
||||
|
||||
public GeckoEvent(Location l) {
|
||||
public GeckoEvent(Location l, Address a) {
|
||||
mType = LOCATION_EVENT;
|
||||
mLocation = l;
|
||||
mAddress = a;
|
||||
}
|
||||
|
||||
public GeckoEvent(int imeAction, int offset, int count) {
|
||||
|
@ -413,10 +413,46 @@ class GeckoSurfaceView
|
||||
GeckoAppShell.sendEventToGecko(new GeckoEvent(event));
|
||||
}
|
||||
|
||||
private class GeocoderTask extends AsyncTask<Location, Void, Void> {
|
||||
protected Void doInBackground(Location... location) {
|
||||
try {
|
||||
List<Address> addresses = mGeocoder.getFromLocation(location[0].getLatitude(),
|
||||
location[0].getLongitude(), 1);
|
||||
// grab the first address. in the future,
|
||||
// may want to expose multiple, or filter
|
||||
// for best.
|
||||
mLastGeoAddress = addresses.get(0);
|
||||
} catch (Exception e) {
|
||||
Log.w("GeckoSurfaceView", "GeocoderTask "+e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// geolocation
|
||||
public void onLocationChanged(Location location)
|
||||
{
|
||||
GeckoAppShell.sendEventToGecko(new GeckoEvent(location));
|
||||
if (mGeocoder == null)
|
||||
mGeocoder = new Geocoder(getContext());
|
||||
|
||||
if (mLastGeoAddress == null) {
|
||||
new GeocoderTask().execute(location);
|
||||
}
|
||||
else {
|
||||
float[] results = new float[1];
|
||||
Location.distanceBetween(location.getLatitude(),
|
||||
location.getLongitude(),
|
||||
mLastGeoAddress.getLatitude(),
|
||||
mLastGeoAddress.getLongitude(),
|
||||
results);
|
||||
// pfm value. don't want to slam the
|
||||
// geocoder with very similar values, so
|
||||
// only call after about 100m
|
||||
if (results[0] > 100)
|
||||
new GeocoderTask().execute(location);
|
||||
}
|
||||
|
||||
GeckoAppShell.sendEventToGecko(new GeckoEvent(location, mLastGeoAddress));
|
||||
}
|
||||
|
||||
public void onProviderDisabled(String provider)
|
||||
@ -592,6 +628,9 @@ class GeckoSurfaceView
|
||||
ByteBuffer mSoftwareBuffer;
|
||||
Bitmap mSoftwareBitmap;
|
||||
|
||||
Geocoder mGeocoder;
|
||||
Address mLastGeoAddress;
|
||||
|
||||
final SynchronousQueue<ByteBuffer> mSyncBuf = new SynchronousQueue<ByteBuffer>();
|
||||
}
|
||||
|
||||
|
@ -52,7 +52,6 @@ nsFont::nsFont(const char* aName, PRUint8 aStyle, PRUint8 aVariant,
|
||||
style = aStyle;
|
||||
systemFont = PR_FALSE;
|
||||
variant = aVariant;
|
||||
familyNameQuirks = PR_FALSE;
|
||||
weight = aWeight;
|
||||
stretch = aStretch;
|
||||
decorations = aDecoration;
|
||||
@ -76,7 +75,6 @@ nsFont::nsFont(const nsString& aName, PRUint8 aStyle, PRUint8 aVariant,
|
||||
style = aStyle;
|
||||
systemFont = PR_FALSE;
|
||||
variant = aVariant;
|
||||
familyNameQuirks = PR_FALSE;
|
||||
weight = aWeight;
|
||||
stretch = aStretch;
|
||||
decorations = aDecoration;
|
||||
@ -96,7 +94,6 @@ nsFont::nsFont(const nsFont& aOther)
|
||||
style = aOther.style;
|
||||
systemFont = aOther.systemFont;
|
||||
variant = aOther.variant;
|
||||
familyNameQuirks = aOther.familyNameQuirks;
|
||||
weight = aOther.weight;
|
||||
stretch = aOther.stretch;
|
||||
decorations = aOther.decorations;
|
||||
@ -118,7 +115,6 @@ PRBool nsFont::BaseEquals(const nsFont& aOther) const
|
||||
{
|
||||
if ((style == aOther.style) &&
|
||||
(systemFont == aOther.systemFont) &&
|
||||
(familyNameQuirks == aOther.familyNameQuirks) &&
|
||||
(weight == aOther.weight) &&
|
||||
(stretch == aOther.stretch) &&
|
||||
(size == aOther.size) &&
|
||||
@ -147,7 +143,6 @@ nsFont& nsFont::operator=(const nsFont& aOther)
|
||||
style = aOther.style;
|
||||
systemFont = aOther.systemFont;
|
||||
variant = aOther.variant;
|
||||
familyNameQuirks = aOther.familyNameQuirks;
|
||||
weight = aOther.weight;
|
||||
stretch = aOther.stretch;
|
||||
decorations = aOther.decorations;
|
||||
|
@ -78,10 +78,6 @@ struct NS_GFX nsFont {
|
||||
// The variant of the font (normal, small-caps)
|
||||
PRUint8 variant;
|
||||
|
||||
// True if the character set quirks (for treatment of "Symbol",
|
||||
// "Wingdings", etc.) should be applied.
|
||||
PRUint8 familyNameQuirks;
|
||||
|
||||
// The weight of the font; see gfxFontConstants.h.
|
||||
PRUint16 weight;
|
||||
|
||||
|
@ -826,7 +826,6 @@ nsThebesDeviceContext::GetSystemFont(nsSystemFontID aID, nsFont *aFont) const
|
||||
aFont->style = fontStyle.style;
|
||||
aFont->systemFont = fontStyle.systemFont;
|
||||
aFont->variant = NS_FONT_VARIANT_NORMAL;
|
||||
aFont->familyNameQuirks = fontStyle.familyNameQuirks;
|
||||
aFont->weight = fontStyle.weight;
|
||||
aFont->stretch = fontStyle.stretch;
|
||||
aFont->decorations = NS_FONT_DECORATION_NONE;
|
||||
|
@ -82,7 +82,6 @@ nsThebesFontMetrics::Init(const nsFont& aFont, nsIAtom* aLanguage,
|
||||
mFontStyle = new gfxFontStyle(aFont.style, aFont.weight, aFont.stretch,
|
||||
size, aLanguage,
|
||||
aFont.sizeAdjust, aFont.systemFont,
|
||||
aFont.familyNameQuirks,
|
||||
printerFont,
|
||||
aFont.featureSettings,
|
||||
aFont.languageOverride);
|
||||
|
@ -117,19 +117,6 @@ gfxAlphaBoxBlur::Init(const gfxRect& aRect,
|
||||
return mContext;
|
||||
}
|
||||
|
||||
void
|
||||
gfxAlphaBoxBlur::PremultiplyAlpha(gfxFloat alpha)
|
||||
{
|
||||
if (!mImageSurface)
|
||||
return;
|
||||
|
||||
unsigned char* data = mImageSurface->Data();
|
||||
PRInt32 length = mImageSurface->GetDataSize();
|
||||
|
||||
for (PRInt32 i=0; i<length; ++i)
|
||||
data[i] = static_cast<unsigned char>(data[i] * alpha);
|
||||
}
|
||||
|
||||
/**
|
||||
* Box blur involves looking at one pixel, and setting its value to the average
|
||||
* of its neighbouring pixels.
|
||||
|
@ -103,11 +103,6 @@ public:
|
||||
return mContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Premultiplies the image by the given alpha.
|
||||
*/
|
||||
void PremultiplyAlpha(gfxFloat alpha);
|
||||
|
||||
/**
|
||||
* Does the actual blurring/spreading and mask applying. Users of this
|
||||
* object must have drawn whatever they want to be blurred onto the internal
|
||||
|
@ -2860,7 +2860,7 @@ gfxFontStyle::ParseFontLanguageOverride(const nsString& aLangTag)
|
||||
|
||||
gfxFontStyle::gfxFontStyle() :
|
||||
style(FONT_STYLE_NORMAL), systemFont(PR_TRUE), printerFont(PR_FALSE),
|
||||
familyNameQuirks(PR_FALSE), weight(FONT_WEIGHT_NORMAL),
|
||||
weight(FONT_WEIGHT_NORMAL),
|
||||
stretch(NS_FONT_STRETCH_NORMAL), size(DEFAULT_PIXEL_FONT_SIZE),
|
||||
sizeAdjust(0.0f),
|
||||
language(gfxAtoms::x_western),
|
||||
@ -2871,12 +2871,11 @@ gfxFontStyle::gfxFontStyle() :
|
||||
gfxFontStyle::gfxFontStyle(PRUint8 aStyle, PRUint16 aWeight, PRInt16 aStretch,
|
||||
gfxFloat aSize, nsIAtom *aLanguage,
|
||||
float aSizeAdjust, PRPackedBool aSystemFont,
|
||||
PRPackedBool aFamilyNameQuirks,
|
||||
PRPackedBool aPrinterFont,
|
||||
const nsString& aFeatureSettings,
|
||||
const nsString& aLanguageOverride):
|
||||
style(aStyle), systemFont(aSystemFont), printerFont(aPrinterFont),
|
||||
familyNameQuirks(aFamilyNameQuirks), weight(aWeight), stretch(aStretch),
|
||||
weight(aWeight), stretch(aStretch),
|
||||
size(aSize), sizeAdjust(aSizeAdjust),
|
||||
language(aLanguage),
|
||||
languageOverride(ParseFontLanguageOverride(aLanguageOverride))
|
||||
@ -2904,7 +2903,7 @@ gfxFontStyle::gfxFontStyle(PRUint8 aStyle, PRUint16 aWeight, PRInt16 aStretch,
|
||||
|
||||
gfxFontStyle::gfxFontStyle(const gfxFontStyle& aStyle) :
|
||||
style(aStyle.style), systemFont(aStyle.systemFont), printerFont(aStyle.printerFont),
|
||||
familyNameQuirks(aStyle.familyNameQuirks), weight(aStyle.weight),
|
||||
weight(aStyle.weight),
|
||||
stretch(aStyle.stretch), size(aStyle.size),
|
||||
sizeAdjust(aStyle.sizeAdjust),
|
||||
language(aStyle.language),
|
||||
|
@ -111,7 +111,6 @@ struct THEBES_API gfxFontStyle {
|
||||
gfxFontStyle(PRUint8 aStyle, PRUint16 aWeight, PRInt16 aStretch,
|
||||
gfxFloat aSize, nsIAtom *aLanguage,
|
||||
float aSizeAdjust, PRPackedBool aSystemFont,
|
||||
PRPackedBool aFamilyNameQuirks,
|
||||
PRPackedBool aPrinterFont,
|
||||
const nsString& aFeatureSettings,
|
||||
const nsString& aLanguageOverride);
|
||||
@ -128,10 +127,6 @@ struct THEBES_API gfxFontStyle {
|
||||
// Say that this font is used for print or print preview.
|
||||
PRPackedBool printerFont : 1;
|
||||
|
||||
// True if the character set quirks (for treatment of "Symbol",
|
||||
// "Wingdings", etc.) should be applied.
|
||||
PRPackedBool familyNameQuirks : 1;
|
||||
|
||||
// The weight of the font: 100, 200, ... 900.
|
||||
PRUint16 weight;
|
||||
|
||||
@ -177,8 +172,8 @@ struct THEBES_API gfxFontStyle {
|
||||
}
|
||||
|
||||
PLDHashNumber Hash() const {
|
||||
return ((style + (systemFont << 7) + (familyNameQuirks << 8) +
|
||||
(weight << 9)) + PRUint32(size*1000) + PRUint32(sizeAdjust*1000)) ^
|
||||
return ((style + (systemFont << 7) +
|
||||
(weight << 8)) + PRUint32(size*1000) + PRUint32(sizeAdjust*1000)) ^
|
||||
nsISupportsHashKey::HashKey(language);
|
||||
}
|
||||
|
||||
@ -189,7 +184,6 @@ struct THEBES_API gfxFontStyle {
|
||||
(style == other.style) &&
|
||||
(systemFont == other.systemFont) &&
|
||||
(printerFont == other.printerFont) &&
|
||||
(familyNameQuirks == other.familyNameQuirks) &&
|
||||
(weight == other.weight) &&
|
||||
(stretch == other.stretch) &&
|
||||
(language == other.language) &&
|
||||
|
@ -2346,7 +2346,7 @@ gfxFcFont::GetOrMakeFont(FcPattern *aRequestedPattern, FcPattern *aFontPattern)
|
||||
// FIXME: Pass a real stretch based on renderPattern!
|
||||
gfxFontStyle fontStyle(style, weight, NS_FONT_STRETCH_NORMAL,
|
||||
size, language, 0.0,
|
||||
PR_TRUE, PR_FALSE, PR_FALSE,
|
||||
PR_TRUE, PR_FALSE,
|
||||
NS_LITERAL_STRING(""),
|
||||
NS_LITERAL_STRING(""));
|
||||
|
||||
|
@ -3434,7 +3434,7 @@ nsCSSFrameConstructor::ConstructTextFrame(const FrameConstructionData* aData,
|
||||
/* static */
|
||||
const nsCSSFrameConstructor::FrameConstructionData*
|
||||
nsCSSFrameConstructor::FindDataByInt(PRInt32 aInt,
|
||||
nsIContent* aContent,
|
||||
Element* aElement,
|
||||
nsStyleContext* aStyleContext,
|
||||
const FrameConstructionDataByInt* aDataPtr,
|
||||
PRUint32 aDataLength)
|
||||
@ -3446,7 +3446,7 @@ nsCSSFrameConstructor::FindDataByInt(PRInt32 aInt,
|
||||
if (curData->mInt == aInt) {
|
||||
const FrameConstructionData* data = &curData->mData;
|
||||
if (data->mBits & FCDATA_FUNC_IS_DATA_GETTER) {
|
||||
return data->mFunc.mDataGetter(aContent, aStyleContext);
|
||||
return data->mFunc.mDataGetter(aElement, aStyleContext);
|
||||
}
|
||||
|
||||
return data;
|
||||
@ -3459,7 +3459,7 @@ nsCSSFrameConstructor::FindDataByInt(PRInt32 aInt,
|
||||
/* static */
|
||||
const nsCSSFrameConstructor::FrameConstructionData*
|
||||
nsCSSFrameConstructor::FindDataByTag(nsIAtom* aTag,
|
||||
nsIContent* aContent,
|
||||
Element* aElement,
|
||||
nsStyleContext* aStyleContext,
|
||||
const FrameConstructionDataByTag* aDataPtr,
|
||||
PRUint32 aDataLength)
|
||||
@ -3471,7 +3471,7 @@ nsCSSFrameConstructor::FindDataByTag(nsIAtom* aTag,
|
||||
if (*curData->mTag == aTag) {
|
||||
const FrameConstructionData* data = &curData->mData;
|
||||
if (data->mBits & FCDATA_FUNC_IS_DATA_GETTER) {
|
||||
return data->mFunc.mDataGetter(aContent, aStyleContext);
|
||||
return data->mFunc.mDataGetter(aElement, aStyleContext);
|
||||
}
|
||||
|
||||
return data;
|
||||
@ -3497,7 +3497,7 @@ nsCSSFrameConstructor::FindDataByTag(nsIAtom* aTag,
|
||||
|
||||
/* static */
|
||||
const nsCSSFrameConstructor::FrameConstructionData*
|
||||
nsCSSFrameConstructor::FindHTMLData(nsIContent* aContent,
|
||||
nsCSSFrameConstructor::FindHTMLData(Element* aElement,
|
||||
nsIAtom* aTag,
|
||||
PRInt32 aNameSpaceID,
|
||||
nsIFrame* aParentFrame,
|
||||
@ -3520,9 +3520,8 @@ nsCSSFrameConstructor::FindHTMLData(nsIContent* aContent,
|
||||
(aParentFrame->GetType() != nsGkAtoms::fieldSetFrame &&
|
||||
aParentFrame->GetStyleContext()->GetPseudo() !=
|
||||
nsCSSAnonBoxes::fieldsetContent) ||
|
||||
!aContent->GetParent() ||
|
||||
!aContent->GetParent()->IsHTML() ||
|
||||
aContent->GetParent()->Tag() != nsGkAtoms::fieldset ||
|
||||
!aElement->GetParent() ||
|
||||
!aElement->GetParent()->IsHTML(nsGkAtoms::fieldset) ||
|
||||
aStyleContext->GetStyleDisplay()->IsFloating() ||
|
||||
aStyleContext->GetStyleDisplay()->IsAbsolutelyPositioned())) {
|
||||
// <legend> is only special inside fieldset, check both the frame tree
|
||||
@ -3565,16 +3564,16 @@ nsCSSFrameConstructor::FindHTMLData(nsIContent* aContent,
|
||||
SIMPLE_TAG_CREATE(isindex, NS_NewIsIndexFrame)
|
||||
};
|
||||
|
||||
return FindDataByTag(aTag, aContent, aStyleContext, sHTMLData,
|
||||
return FindDataByTag(aTag, aElement, aStyleContext, sHTMLData,
|
||||
NS_ARRAY_LENGTH(sHTMLData));
|
||||
}
|
||||
|
||||
/* static */
|
||||
const nsCSSFrameConstructor::FrameConstructionData*
|
||||
nsCSSFrameConstructor::FindImgData(nsIContent* aContent,
|
||||
nsCSSFrameConstructor::FindImgData(Element* aElement,
|
||||
nsStyleContext* aStyleContext)
|
||||
{
|
||||
if (!nsImageFrame::ShouldCreateImageFrameFor(aContent, aStyleContext)) {
|
||||
if (!nsImageFrame::ShouldCreateImageFrameFor(aElement, aStyleContext)) {
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
@ -3584,10 +3583,10 @@ nsCSSFrameConstructor::FindImgData(nsIContent* aContent,
|
||||
|
||||
/* static */
|
||||
const nsCSSFrameConstructor::FrameConstructionData*
|
||||
nsCSSFrameConstructor::FindImgControlData(nsIContent* aContent,
|
||||
nsCSSFrameConstructor::FindImgControlData(Element* aElement,
|
||||
nsStyleContext* aStyleContext)
|
||||
{
|
||||
if (!nsImageFrame::ShouldCreateImageFrameFor(aContent, aStyleContext)) {
|
||||
if (!nsImageFrame::ShouldCreateImageFrameFor(aElement, aStyleContext)) {
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
@ -3598,7 +3597,7 @@ nsCSSFrameConstructor::FindImgControlData(nsIContent* aContent,
|
||||
|
||||
/* static */
|
||||
const nsCSSFrameConstructor::FrameConstructionData*
|
||||
nsCSSFrameConstructor::FindInputData(nsIContent* aContent,
|
||||
nsCSSFrameConstructor::FindInputData(Element* aElement,
|
||||
nsStyleContext* aStyleContext)
|
||||
{
|
||||
static const FrameConstructionDataByInt sInputData[] = {
|
||||
@ -3623,28 +3622,28 @@ nsCSSFrameConstructor::FindInputData(nsIContent* aContent,
|
||||
// display (in practice, none).
|
||||
};
|
||||
|
||||
nsCOMPtr<nsIFormControl> control = do_QueryInterface(aContent);
|
||||
nsCOMPtr<nsIFormControl> control = do_QueryInterface(aElement);
|
||||
NS_ASSERTION(control, "input doesn't implement nsIFormControl?");
|
||||
|
||||
return FindDataByInt(control->GetType(), aContent, aStyleContext,
|
||||
return FindDataByInt(control->GetType(), aElement, aStyleContext,
|
||||
sInputData, NS_ARRAY_LENGTH(sInputData));
|
||||
}
|
||||
|
||||
/* static */
|
||||
const nsCSSFrameConstructor::FrameConstructionData*
|
||||
nsCSSFrameConstructor::FindObjectData(nsIContent* aContent,
|
||||
nsCSSFrameConstructor::FindObjectData(Element* aElement,
|
||||
nsStyleContext* aStyleContext)
|
||||
{
|
||||
// GetDisplayedType isn't necessarily nsIObjectLoadingContent::TYPE_NULL for
|
||||
// cases when the object is broken/suppressed/etc (e.g. a broken image), but
|
||||
// we want to treat those cases as TYPE_NULL
|
||||
PRUint32 type;
|
||||
if (aContent->IntrinsicState().HasAtLeastOneOfStates(NS_EVENT_STATE_BROKEN |
|
||||
if (aElement->IntrinsicState().HasAtLeastOneOfStates(NS_EVENT_STATE_BROKEN |
|
||||
NS_EVENT_STATE_USERDISABLED |
|
||||
NS_EVENT_STATE_SUPPRESSED)) {
|
||||
type = nsIObjectLoadingContent::TYPE_NULL;
|
||||
} else {
|
||||
nsCOMPtr<nsIObjectLoadingContent> objContent(do_QueryInterface(aContent));
|
||||
nsCOMPtr<nsIObjectLoadingContent> objContent(do_QueryInterface(aElement));
|
||||
NS_ASSERTION(objContent,
|
||||
"applet, embed and object must implement "
|
||||
"nsIObjectLoadingContent!");
|
||||
@ -3664,7 +3663,7 @@ nsCSSFrameConstructor::FindObjectData(nsIContent* aContent,
|
||||
// Nothing for TYPE_NULL so we'll construct frames by display there
|
||||
};
|
||||
|
||||
return FindDataByInt((PRInt32)type, aContent, aStyleContext,
|
||||
return FindDataByInt((PRInt32)type, aElement, aStyleContext,
|
||||
sObjectData, NS_ARRAY_LENGTH(sObjectData));
|
||||
}
|
||||
|
||||
@ -4008,7 +4007,7 @@ nsIFrame* NS_NewGridBoxFrame(nsIPresShell* aPresShell,
|
||||
|
||||
/* static */
|
||||
const nsCSSFrameConstructor::FrameConstructionData*
|
||||
nsCSSFrameConstructor::FindXULTagData(nsIContent* aContent,
|
||||
nsCSSFrameConstructor::FindXULTagData(Element* aElement,
|
||||
nsIAtom* aTag,
|
||||
PRInt32 aNameSpaceID,
|
||||
nsStyleContext* aStyleContext)
|
||||
@ -4056,17 +4055,17 @@ nsCSSFrameConstructor::FindXULTagData(nsIContent* aContent,
|
||||
SIMPLE_XUL_CREATE(scrollbarbutton, NS_NewScrollbarButtonFrame)
|
||||
};
|
||||
|
||||
return FindDataByTag(aTag, aContent, aStyleContext, sXULTagData,
|
||||
return FindDataByTag(aTag, aElement, aStyleContext, sXULTagData,
|
||||
NS_ARRAY_LENGTH(sXULTagData));
|
||||
}
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
/* static */
|
||||
const nsCSSFrameConstructor::FrameConstructionData*
|
||||
nsCSSFrameConstructor::FindPopupGroupData(nsIContent* aContent,
|
||||
nsCSSFrameConstructor::FindPopupGroupData(Element* aElement,
|
||||
nsStyleContext* /* unused */)
|
||||
{
|
||||
if (!aContent->IsRootOfNativeAnonymousSubtree()) {
|
||||
if (!aElement->IsRootOfNativeAnonymousSubtree()) {
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
@ -4081,10 +4080,10 @@ nsCSSFrameConstructor::sXULTextBoxData = SIMPLE_XUL_FCDATA(NS_NewTextBoxFrame);
|
||||
|
||||
/* static */
|
||||
const nsCSSFrameConstructor::FrameConstructionData*
|
||||
nsCSSFrameConstructor::FindXULLabelData(nsIContent* aContent,
|
||||
nsCSSFrameConstructor::FindXULLabelData(Element* aElement,
|
||||
nsStyleContext* /* unused */)
|
||||
{
|
||||
if (aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::value)) {
|
||||
if (aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::value)) {
|
||||
return &sXULTextBoxData;
|
||||
}
|
||||
|
||||
@ -4104,10 +4103,10 @@ NS_NewXULDescriptionFrame(nsIPresShell* aPresShell, nsStyleContext *aContext)
|
||||
|
||||
/* static */
|
||||
const nsCSSFrameConstructor::FrameConstructionData*
|
||||
nsCSSFrameConstructor::FindXULDescriptionData(nsIContent* aContent,
|
||||
nsCSSFrameConstructor::FindXULDescriptionData(Element* aElement,
|
||||
nsStyleContext* /* unused */)
|
||||
{
|
||||
if (aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::value)) {
|
||||
if (aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::value)) {
|
||||
return &sXULTextBoxData;
|
||||
}
|
||||
|
||||
@ -4119,7 +4118,7 @@ nsCSSFrameConstructor::FindXULDescriptionData(nsIContent* aContent,
|
||||
#ifdef XP_MACOSX
|
||||
/* static */
|
||||
const nsCSSFrameConstructor::FrameConstructionData*
|
||||
nsCSSFrameConstructor::FindXULMenubarData(nsIContent* aContent,
|
||||
nsCSSFrameConstructor::FindXULMenubarData(Element* aElement,
|
||||
nsStyleContext* aStyleContext)
|
||||
{
|
||||
nsCOMPtr<nsISupports> container =
|
||||
@ -4150,7 +4149,7 @@ nsCSSFrameConstructor::FindXULMenubarData(nsIContent* aContent,
|
||||
|
||||
/* static */
|
||||
const nsCSSFrameConstructor::FrameConstructionData*
|
||||
nsCSSFrameConstructor::FindXULListBoxBodyData(nsIContent* aContent,
|
||||
nsCSSFrameConstructor::FindXULListBoxBodyData(Element* aElement,
|
||||
nsStyleContext* aStyleContext)
|
||||
{
|
||||
if (aStyleContext->GetStyleDisplay()->mDisplay !=
|
||||
@ -4165,7 +4164,7 @@ nsCSSFrameConstructor::FindXULListBoxBodyData(nsIContent* aContent,
|
||||
|
||||
/* static */
|
||||
const nsCSSFrameConstructor::FrameConstructionData*
|
||||
nsCSSFrameConstructor::FindXULListItemData(nsIContent* aContent,
|
||||
nsCSSFrameConstructor::FindXULListItemData(Element* aElement,
|
||||
nsStyleContext* aStyleContext)
|
||||
{
|
||||
if (aStyleContext->GetStyleDisplay()->mDisplay !=
|
||||
@ -4183,7 +4182,7 @@ nsCSSFrameConstructor::FindXULListItemData(nsIContent* aContent,
|
||||
/* static */
|
||||
const nsCSSFrameConstructor::FrameConstructionData*
|
||||
nsCSSFrameConstructor::FindXULDisplayData(const nsStyleDisplay* aDisplay,
|
||||
nsIContent* aContent,
|
||||
Element* aElement,
|
||||
nsStyleContext* aStyleContext)
|
||||
{
|
||||
static const FrameConstructionDataByInt sXULDisplayData[] = {
|
||||
@ -4207,7 +4206,7 @@ nsCSSFrameConstructor::FindXULDisplayData(const nsStyleDisplay* aDisplay,
|
||||
};
|
||||
|
||||
// Processing by display here:
|
||||
return FindDataByInt(aDisplay->mDisplay, aContent, aStyleContext,
|
||||
return FindDataByInt(aDisplay->mDisplay, aElement, aStyleContext,
|
||||
sXULDisplayData, NS_ARRAY_LENGTH(sXULDisplayData));
|
||||
}
|
||||
|
||||
@ -4327,7 +4326,7 @@ nsCSSFrameConstructor::BuildScrollFrame(nsFrameConstructorState& aState,
|
||||
|
||||
const nsCSSFrameConstructor::FrameConstructionData*
|
||||
nsCSSFrameConstructor::FindDisplayData(const nsStyleDisplay* aDisplay,
|
||||
nsIContent* aContent,
|
||||
Element* aElement,
|
||||
nsStyleContext* aStyleContext)
|
||||
{
|
||||
PR_STATIC_ASSERT(eParentTypeCount < (1 << (32 - FCDATA_PARENT_TYPE_OFFSET)));
|
||||
@ -4346,10 +4345,9 @@ nsCSSFrameConstructor::FindDisplayData(const nsStyleDisplay* aDisplay,
|
||||
// XXXbz is this the right place to do this? If this code moves,
|
||||
// make this function static.
|
||||
PRBool propagatedScrollToViewport = PR_FALSE;
|
||||
if (aContent->NodeInfo()->Equals(nsGkAtoms::body) &&
|
||||
aContent->IsHTML()) {
|
||||
if (aElement->IsHTML(nsGkAtoms::body)) {
|
||||
propagatedScrollToViewport =
|
||||
PropagateScrollToViewport() == aContent;
|
||||
PropagateScrollToViewport() == aElement;
|
||||
}
|
||||
|
||||
NS_ASSERTION(!propagatedScrollToViewport ||
|
||||
@ -4369,7 +4367,7 @@ nsCSSFrameConstructor::FindDisplayData(const nsStyleDisplay* aDisplay,
|
||||
// anonymous stuff.
|
||||
if (mPresShell->GetPresContext()->IsPaginated() &&
|
||||
aDisplay->IsBlockOutside() &&
|
||||
!aContent->IsInNativeAnonymousSubtree()) {
|
||||
!aElement->IsInNativeAnonymousSubtree()) {
|
||||
static const FrameConstructionData sForcedNonScrollableBlockData =
|
||||
FULL_CTOR_FCDATA(FCDATA_FORCED_NON_SCROLLABLE_BLOCK,
|
||||
&nsCSSFrameConstructor::ConstructNonScrollableBlock);
|
||||
@ -4444,7 +4442,7 @@ nsCSSFrameConstructor::FindDisplayData(const nsStyleDisplay* aDisplay,
|
||||
&nsCSSFrameConstructor::ConstructTableCell) }
|
||||
};
|
||||
|
||||
return FindDataByInt(aDisplay->mDisplay, aContent, aStyleContext,
|
||||
return FindDataByInt(aDisplay->mDisplay, aElement, aStyleContext,
|
||||
sDisplayData, NS_ARRAY_LENGTH(sDisplayData));
|
||||
}
|
||||
|
||||
@ -4654,7 +4652,7 @@ nsCSSFrameConstructor::FlushAccumulatedBlock(nsFrameConstructorState& aState,
|
||||
|
||||
/* static */
|
||||
const nsCSSFrameConstructor::FrameConstructionData*
|
||||
nsCSSFrameConstructor::FindMathMLData(nsIContent* aContent,
|
||||
nsCSSFrameConstructor::FindMathMLData(Element* aElement,
|
||||
nsIAtom* aTag,
|
||||
PRInt32 aNameSpaceID,
|
||||
nsStyleContext* aStyleContext)
|
||||
@ -4715,7 +4713,7 @@ nsCSSFrameConstructor::FindMathMLData(nsIContent* aContent,
|
||||
SIMPLE_MATHML_CREATE(semantics_, NS_NewMathMLsemanticsFrame)
|
||||
};
|
||||
|
||||
return FindDataByTag(aTag, aContent, aStyleContext, sMathMLData,
|
||||
return FindDataByTag(aTag, aElement, aStyleContext, sMathMLData,
|
||||
NS_ARRAY_LENGTH(sMathMLData));
|
||||
}
|
||||
#endif // MOZ_MATHML
|
||||
@ -4731,7 +4729,7 @@ nsCSSFrameConstructor::FindMathMLData(nsIContent* aContent,
|
||||
|
||||
/* static */
|
||||
const nsCSSFrameConstructor::FrameConstructionData*
|
||||
nsCSSFrameConstructor::FindSVGData(nsIContent* aContent,
|
||||
nsCSSFrameConstructor::FindSVGData(Element* aElement,
|
||||
nsIAtom* aTag,
|
||||
PRInt32 aNameSpaceID,
|
||||
nsIFrame* aParentFrame,
|
||||
@ -4789,7 +4787,7 @@ nsCSSFrameConstructor::FindSVGData(nsIContent* aContent,
|
||||
}
|
||||
|
||||
// We don't need frames for animation elements
|
||||
if (aContent->IsNodeOfType(nsINode::eANIMATION)) {
|
||||
if (aElement->IsNodeOfType(nsINode::eANIMATION)) {
|
||||
return &sSuppressData;
|
||||
}
|
||||
|
||||
@ -4807,7 +4805,7 @@ nsCSSFrameConstructor::FindSVGData(nsIContent* aContent,
|
||||
return &sOuterSVGData;
|
||||
}
|
||||
|
||||
if (!nsSVGFeatures::PassesConditionalProcessingTests(aContent)) {
|
||||
if (!nsSVGFeatures::PassesConditionalProcessingTests(aElement)) {
|
||||
// Elements with failing conditional processing attributes never get
|
||||
// rendered. Note that this is not where we select which frame in a
|
||||
// <switch> to render! That happens in nsSVGSwitchFrame::PaintSVG.
|
||||
@ -4892,7 +4890,7 @@ nsCSSFrameConstructor::FindSVGData(nsIContent* aContent,
|
||||
};
|
||||
|
||||
const FrameConstructionData* data =
|
||||
FindDataByTag(aTag, aContent, aStyleContext, sSVGData,
|
||||
FindDataByTag(aTag, aElement, aStyleContext, sSVGData,
|
||||
NS_ARRAY_LENGTH(sSVGData));
|
||||
|
||||
if (!data) {
|
||||
@ -5091,6 +5089,10 @@ nsCSSFrameConstructor::AddFrameConstructionItemsInternal(nsFrameConstructorState
|
||||
PRUint32 aFlags,
|
||||
FrameConstructionItemList& aItems)
|
||||
{
|
||||
NS_PRECONDITION(aContent->IsNodeOfType(nsINode::eTEXT) ||
|
||||
aContent->IsElement(),
|
||||
"Shouldn't get anything else here!");
|
||||
|
||||
// The following code allows the user to specify the base tag
|
||||
// of an element using XBL. XUL and HTML objects (like boxes, menus, etc.)
|
||||
// can then be extended arbitrarily.
|
||||
@ -5144,7 +5146,7 @@ nsCSSFrameConstructor::AddFrameConstructionItemsInternal(nsFrameConstructorState
|
||||
return;
|
||||
}
|
||||
|
||||
PRBool isText = aContent->IsNodeOfType(nsINode::eTEXT);
|
||||
PRBool isText = !aContent->IsElement();
|
||||
|
||||
// never create frames for non-option/optgroup kids of <select> and
|
||||
// non-option kids of <optgroup> inside a <select>.
|
||||
@ -5181,46 +5183,48 @@ nsCSSFrameConstructor::AddFrameConstructionItemsInternal(nsFrameConstructorState
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
Element* element = aContent->AsElement();
|
||||
|
||||
// Don't create frames for non-SVG element children of SVG elements.
|
||||
if (aNameSpaceID != kNameSpaceID_SVG &&
|
||||
aParentFrame &&
|
||||
aParentFrame->IsFrameOfType(nsIFrame::eSVG) &&
|
||||
!aParentFrame->IsFrameOfType(nsIFrame::eSVGForeignObject)
|
||||
) {
|
||||
SetAsUndisplayedContent(aState.mFrameManager, aContent, styleContext,
|
||||
SetAsUndisplayedContent(aState.mFrameManager, element, styleContext,
|
||||
isGeneratedContent);
|
||||
return;
|
||||
}
|
||||
|
||||
data = FindHTMLData(aContent, aTag, aNameSpaceID, aParentFrame,
|
||||
data = FindHTMLData(element, aTag, aNameSpaceID, aParentFrame,
|
||||
styleContext);
|
||||
if (!data) {
|
||||
data = FindXULTagData(aContent, aTag, aNameSpaceID, styleContext);
|
||||
data = FindXULTagData(element, aTag, aNameSpaceID, styleContext);
|
||||
}
|
||||
#ifdef MOZ_MATHML
|
||||
if (!data) {
|
||||
data = FindMathMLData(aContent, aTag, aNameSpaceID, styleContext);
|
||||
data = FindMathMLData(element, aTag, aNameSpaceID, styleContext);
|
||||
}
|
||||
#endif
|
||||
if (!data) {
|
||||
data = FindSVGData(aContent, aTag, aNameSpaceID, aParentFrame,
|
||||
data = FindSVGData(element, aTag, aNameSpaceID, aParentFrame,
|
||||
styleContext);
|
||||
}
|
||||
|
||||
// Now check for XUL display types
|
||||
if (!data) {
|
||||
data = FindXULDisplayData(display, aContent, styleContext);
|
||||
data = FindXULDisplayData(display, element, styleContext);
|
||||
}
|
||||
|
||||
// And general display types
|
||||
if (!data) {
|
||||
data = FindDisplayData(display, aContent, styleContext);
|
||||
data = FindDisplayData(display, element, styleContext);
|
||||
}
|
||||
|
||||
NS_ASSERTION(data, "Should have frame construction data now");
|
||||
|
||||
if (data->mBits & FCDATA_SUPPRESS_FRAME) {
|
||||
SetAsUndisplayedContent(aState.mFrameManager, aContent, styleContext,
|
||||
SetAsUndisplayedContent(aState.mFrameManager, element, styleContext,
|
||||
isGeneratedContent);
|
||||
return;
|
||||
}
|
||||
@ -5231,7 +5235,7 @@ nsCSSFrameConstructor::AddFrameConstructionItemsInternal(nsFrameConstructorState
|
||||
aParentFrame->GetType() != nsGkAtoms::menuFrame)) {
|
||||
if (!aState.mPopupItems.containingBlock &&
|
||||
!aState.mHavePendingPopupgroup) {
|
||||
SetAsUndisplayedContent(aState.mFrameManager, aContent, styleContext,
|
||||
SetAsUndisplayedContent(aState.mFrameManager, element, styleContext,
|
||||
isGeneratedContent);
|
||||
return;
|
||||
}
|
||||
@ -8879,8 +8883,7 @@ nsCSSFrameConstructor::GetInsertionPoint(nsIFrame* aParentFrame,
|
||||
// have to look at insertionElement here...
|
||||
if (aMultiple && !*aMultiple) {
|
||||
nsIContent* content = insertionElement ? insertionElement : container;
|
||||
if (content->IsHTML() &&
|
||||
content->Tag() == nsGkAtoms::fieldset) {
|
||||
if (content->IsHTML(nsGkAtoms::fieldset)) {
|
||||
*aMultiple = PR_TRUE;
|
||||
}
|
||||
}
|
||||
@ -10942,7 +10945,7 @@ nsCSSFrameConstructor::BuildInlineChildItems(nsFrameConstructorState& aState,
|
||||
for (ChildIterator::Init(parentContent, &iter, &last);
|
||||
iter != last;
|
||||
++iter) {
|
||||
// Manually check for comments/PIs, since we do't have a frame to pass to
|
||||
// Manually check for comments/PIs, since we don't have a frame to pass to
|
||||
// AddFrameConstructionItems. We know our parent is a non-replaced inline,
|
||||
// so there is no need to do the NeedFrameFor check.
|
||||
nsIContent* content = *iter;
|
||||
|
@ -623,7 +623,7 @@ private:
|
||||
*/
|
||||
struct FrameConstructionData;
|
||||
typedef const FrameConstructionData*
|
||||
(* FrameConstructionDataGetter)(nsIContent*, nsStyleContext*);
|
||||
(* FrameConstructionDataGetter)(Element*, nsStyleContext*);
|
||||
|
||||
/* A constructor function that's used for complicated construction tasks.
|
||||
This is expected to create the new frame, initialize it, add whatever
|
||||
@ -787,7 +787,7 @@ private:
|
||||
match or if the matching integer has a FrameConstructionDataGetter that
|
||||
returns null. */
|
||||
static const FrameConstructionData*
|
||||
FindDataByInt(PRInt32 aInt, nsIContent* aContent,
|
||||
FindDataByInt(PRInt32 aInt, Element* aElement,
|
||||
nsStyleContext* aStyleContext,
|
||||
const FrameConstructionDataByInt* aDataPtr,
|
||||
PRUint32 aDataLength);
|
||||
@ -798,7 +798,7 @@ private:
|
||||
match or if the matching tag has a FrameConstructionDataGetter that
|
||||
returns null. */
|
||||
static const FrameConstructionData*
|
||||
FindDataByTag(nsIAtom* aTag, nsIContent* aContent,
|
||||
FindDataByTag(nsIAtom* aTag, Element* aElement,
|
||||
nsStyleContext* aStyleContext,
|
||||
const FrameConstructionDataByTag* aDataPtr,
|
||||
PRUint32 aDataLength);
|
||||
@ -1194,24 +1194,24 @@ private:
|
||||
nsStyleContext* aMainStyleContext,
|
||||
FrameConstructionItemList& aItems);
|
||||
|
||||
// Function to find FrameConstructionData for aContent. Will return
|
||||
// null if aContent is not HTML.
|
||||
// Function to find FrameConstructionData for aElement. Will return
|
||||
// null if aElement is not HTML.
|
||||
// aParentFrame might be null. If it is, that means it was an
|
||||
// inline frame.
|
||||
static const FrameConstructionData* FindHTMLData(nsIContent* aContent,
|
||||
static const FrameConstructionData* FindHTMLData(Element* aContent,
|
||||
nsIAtom* aTag,
|
||||
PRInt32 aNameSpaceID,
|
||||
nsIFrame* aParentFrame,
|
||||
nsStyleContext* aStyleContext);
|
||||
// HTML data-finding helper functions
|
||||
static const FrameConstructionData*
|
||||
FindImgData(nsIContent* aContent, nsStyleContext* aStyleContext);
|
||||
FindImgData(Element* aElement, nsStyleContext* aStyleContext);
|
||||
static const FrameConstructionData*
|
||||
FindImgControlData(nsIContent* aContent, nsStyleContext* aStyleContext);
|
||||
FindImgControlData(Element* aElement, nsStyleContext* aStyleContext);
|
||||
static const FrameConstructionData*
|
||||
FindInputData(nsIContent* aContent, nsStyleContext* aStyleContext);
|
||||
FindInputData(Element* aElement, nsStyleContext* aStyleContext);
|
||||
static const FrameConstructionData*
|
||||
FindObjectData(nsIContent* aContent, nsStyleContext* aStyleContext);
|
||||
FindObjectData(Element* aElement, nsStyleContext* aStyleContext);
|
||||
|
||||
/* Construct a frame from the given FrameConstructionItem. This function
|
||||
will handle adding the frame to frame lists, processing children, setting
|
||||
@ -1289,7 +1289,7 @@ private:
|
||||
|
||||
// Function to find FrameConstructionData for aContent. Will return
|
||||
// null if aContent is not MathML.
|
||||
static const FrameConstructionData* FindMathMLData(nsIContent* aContent,
|
||||
static const FrameConstructionData* FindMathMLData(Element* aElement,
|
||||
nsIAtom* aTag,
|
||||
PRInt32 aNameSpaceID,
|
||||
nsStyleContext* aStyleContext);
|
||||
@ -1297,28 +1297,28 @@ private:
|
||||
|
||||
// Function to find FrameConstructionData for aContent. Will return
|
||||
// null if aContent is not XUL.
|
||||
static const FrameConstructionData* FindXULTagData(nsIContent* aContent,
|
||||
static const FrameConstructionData* FindXULTagData(Element* aElement,
|
||||
nsIAtom* aTag,
|
||||
PRInt32 aNameSpaceID,
|
||||
nsStyleContext* aStyleContext);
|
||||
// XUL data-finding helper functions and structures
|
||||
#ifdef MOZ_XUL
|
||||
static const FrameConstructionData*
|
||||
FindPopupGroupData(nsIContent* aContent, nsStyleContext* aStyleContext);
|
||||
FindPopupGroupData(Element* aElement, nsStyleContext* aStyleContext);
|
||||
// sXULTextBoxData used for both labels and descriptions
|
||||
static const FrameConstructionData sXULTextBoxData;
|
||||
static const FrameConstructionData*
|
||||
FindXULLabelData(nsIContent* aContent, nsStyleContext* aStyleContext);
|
||||
FindXULLabelData(Element* aElement, nsStyleContext* aStyleContext);
|
||||
static const FrameConstructionData*
|
||||
FindXULDescriptionData(nsIContent* aContent, nsStyleContext* aStyleContext);
|
||||
FindXULDescriptionData(Element* aElement, nsStyleContext* aStyleContext);
|
||||
#ifdef XP_MACOSX
|
||||
static const FrameConstructionData*
|
||||
FindXULMenubarData(nsIContent* aContent, nsStyleContext* aStyleContext);
|
||||
FindXULMenubarData(Element* aElement, nsStyleContext* aStyleContext);
|
||||
#endif /* XP_MACOSX */
|
||||
static const FrameConstructionData*
|
||||
FindXULListBoxBodyData(nsIContent* aContent, nsStyleContext* aStyleContext);
|
||||
FindXULListBoxBodyData(Element* aElement, nsStyleContext* aStyleContext);
|
||||
static const FrameConstructionData*
|
||||
FindXULListItemData(nsIContent* aContent, nsStyleContext* aStyleContext);
|
||||
FindXULListItemData(Element* aElement, nsStyleContext* aStyleContext);
|
||||
#endif /* MOZ_XUL */
|
||||
|
||||
// Function to find FrameConstructionData for aContent using one of the XUL
|
||||
@ -1328,12 +1328,12 @@ private:
|
||||
// constructed by tag.
|
||||
static const FrameConstructionData*
|
||||
FindXULDisplayData(const nsStyleDisplay* aDisplay,
|
||||
nsIContent* aContent,
|
||||
Element* aElement,
|
||||
nsStyleContext* aStyleContext);
|
||||
|
||||
// SVG - rods
|
||||
#ifdef MOZ_SVG
|
||||
static const FrameConstructionData* FindSVGData(nsIContent* aContent,
|
||||
static const FrameConstructionData* FindSVGData(Element* aElement,
|
||||
nsIAtom* aTag,
|
||||
PRInt32 aNameSpaceID,
|
||||
nsIFrame* aParentFrame,
|
||||
@ -1350,7 +1350,7 @@ private:
|
||||
/* Not static because it does PropagateScrollToViewport. If this
|
||||
changes, make this static */
|
||||
const FrameConstructionData*
|
||||
FindDisplayData(const nsStyleDisplay* aDisplay, nsIContent* aContent,
|
||||
FindDisplayData(const nsStyleDisplay* aDisplay, Element* aElement,
|
||||
nsStyleContext* aStyleContext);
|
||||
|
||||
/**
|
||||
|
@ -2074,14 +2074,17 @@ nsCSSRendering::PaintGradient(nsPresContext* aPresContext,
|
||||
// multiplying by stopScale.
|
||||
double stopScale;
|
||||
double stopDelta = lastStop - firstStop;
|
||||
if (stopDelta < 1e-6 || lineLength < 1e-6 ||
|
||||
(aGradient->mShape != NS_STYLE_GRADIENT_SHAPE_LINEAR &&
|
||||
(radiusX < 1e-6 || radiusY < 1e-6))) {
|
||||
PRBool zeroRadius = aGradient->mShape != NS_STYLE_GRADIENT_SHAPE_LINEAR &&
|
||||
(radiusX < 1e-6 || radiusY < 1e-6);
|
||||
if (stopDelta < 1e-6 || lineLength < 1e-6 || zeroRadius) {
|
||||
// Stops are all at the same place. Map all stops to 0.0.
|
||||
// For radial gradients we need to fill with the last stop color,
|
||||
// so just set both radii to 0.
|
||||
// For repeating radial gradients, or for any radial gradients with
|
||||
// a zero radius, we need to fill with the last stop color, so just set
|
||||
// both radii to 0.
|
||||
stopScale = 0.0;
|
||||
radiusX = radiusY = 0.0;
|
||||
if (aGradient->mRepeating || zeroRadius) {
|
||||
radiusX = radiusY = 0.0;
|
||||
}
|
||||
lastStop = firstStop;
|
||||
} else {
|
||||
stopScale = 1.0/stopDelta;
|
||||
@ -2115,6 +2118,11 @@ nsCSSRendering::PaintGradient(nsPresContext* aPresContext,
|
||||
// So our radii are based on radiusX.
|
||||
double innerRadius = radiusX*firstStop;
|
||||
double outerRadius = radiusX*lastStop;
|
||||
if (stopScale == 0.0) {
|
||||
// Stops are all at the same place. See above (except we now have
|
||||
// the inside vs. outside of an ellipse).
|
||||
outerRadius = innerRadius + 1;
|
||||
}
|
||||
gradientPattern = new gfxPattern(lineStart.x, lineStart.y, innerRadius,
|
||||
lineStart.x, lineStart.y, outerRadius);
|
||||
if (gradientPattern && radiusX != radiusY) {
|
||||
@ -2135,12 +2143,11 @@ nsCSSRendering::PaintGradient(nsPresContext* aPresContext,
|
||||
|
||||
// Now set normalized color stops in pattern.
|
||||
if (stopScale == 0.0) {
|
||||
// Non-repeating linear gradient with all stops in same place -> just add
|
||||
// Non-repeating gradient with all stops in same place -> just add
|
||||
// first stop and last stop, both at position 0.
|
||||
// Repeating or radial gradient with all stops in the same place -> just
|
||||
// paint the last stop color.
|
||||
if (!aGradient->mRepeating &&
|
||||
aGradient->mShape == NS_STYLE_GRADIENT_SHAPE_LINEAR) {
|
||||
// Repeating gradient with all stops in the same place, or radial
|
||||
// gradient with radius of 0 -> just paint the last stop color.
|
||||
if (!aGradient->mRepeating && !zeroRadius) {
|
||||
gradientPattern->AddColorStop(0.0, stops[0].mColor);
|
||||
}
|
||||
gradientPattern->AddColorStop(0.0, stops[stops.Length() - 1].mColor);
|
||||
|
@ -60,23 +60,31 @@ using mozilla::TimeStamp;
|
||||
|
||||
// Compute the interval to use for the refresh driver timer, in
|
||||
// milliseconds
|
||||
static PRInt32
|
||||
GetRefreshTimerInterval(bool aThrottled)
|
||||
PRInt32
|
||||
nsRefreshDriver::GetRefreshTimerInterval() const
|
||||
{
|
||||
const char* prefName =
|
||||
aThrottled ? "layout.throttled_frame_rate" : "layout.frame_rate";
|
||||
mThrottled ? "layout.throttled_frame_rate" : "layout.frame_rate";
|
||||
PRInt32 rate = nsContentUtils::GetIntPref(prefName, -1);
|
||||
if (rate <= 0) {
|
||||
// TODO: get the rate from the platform
|
||||
rate = aThrottled ? DEFAULT_THROTTLED_FRAME_RATE : DEFAULT_FRAME_RATE;
|
||||
rate = mThrottled ? DEFAULT_THROTTLED_FRAME_RATE : DEFAULT_FRAME_RATE;
|
||||
}
|
||||
NS_ASSERTION(rate > 0, "Must have positive rate here");
|
||||
return NSToIntRound(1000.0/rate);
|
||||
PRInt32 interval = NSToIntRound(1000.0/rate);
|
||||
if (mThrottled) {
|
||||
interval = NS_MAX(interval, mLastTimerInterval * 2);
|
||||
}
|
||||
mLastTimerInterval = interval;
|
||||
return interval;
|
||||
}
|
||||
|
||||
static PRInt32
|
||||
GetRefreshTimerType()
|
||||
PRInt32
|
||||
nsRefreshDriver::GetRefreshTimerType() const
|
||||
{
|
||||
if (mThrottled) {
|
||||
return nsITimer::TYPE_ONE_SHOT;
|
||||
}
|
||||
PRBool precise =
|
||||
nsContentUtils::GetBoolPref("layout.frame_rate.precise", PR_FALSE);
|
||||
return precise ? (PRInt32)nsITimer::TYPE_REPEATING_PRECISE
|
||||
@ -150,7 +158,7 @@ nsRefreshDriver::EnsureTimerStarted()
|
||||
}
|
||||
|
||||
nsresult rv = mTimer->InitWithCallback(this,
|
||||
GetRefreshTimerInterval(mThrottled),
|
||||
GetRefreshTimerInterval(),
|
||||
GetRefreshTimerType());
|
||||
if (NS_FAILED(rv)) {
|
||||
mTimer = nsnull;
|
||||
@ -330,6 +338,16 @@ nsRefreshDriver::Notify(nsITimer * /* unused */)
|
||||
}
|
||||
}
|
||||
|
||||
if (mThrottled) {
|
||||
// Stop the timer now and restart it here. Stopping is ok because either
|
||||
// it's already one-shot, and it just fired, and all we need to do is null
|
||||
// it out, or it's repeating and we need to reset it to be one-shot. Note
|
||||
// that the EnsureTimerStarted() call here is ok because EnsureTimerStarted
|
||||
// makes sure to not start the timer if it shouldn't be started.
|
||||
StopTimer();
|
||||
EnsureTimerStarted();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -358,10 +376,10 @@ nsRefreshDriver::SetThrottled(bool aThrottled)
|
||||
if (aThrottled != mThrottled) {
|
||||
mThrottled = aThrottled;
|
||||
if (mTimer) {
|
||||
// Stopping and restarting the timer would update our most recent refresh
|
||||
// time, which isn't quite right. Luckily, we can just reschedule the
|
||||
// timer.
|
||||
mTimer->SetDelay(GetRefreshTimerInterval(mThrottled));
|
||||
// We want to switch our timer type here, so just stop and
|
||||
// restart the timer.
|
||||
StopTimer();
|
||||
EnsureTimerStarted();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -218,6 +218,9 @@ private:
|
||||
// Trigger a refresh immediately, if haven't been disconnected or frozen.
|
||||
void DoRefresh();
|
||||
|
||||
PRInt32 GetRefreshTimerInterval() const;
|
||||
PRInt32 GetRefreshTimerType() const;
|
||||
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
mozilla::TimeStamp mMostRecentRefresh; // only valid when mTimer non-null
|
||||
PRInt64 mMostRecentRefreshEpochTime; // same thing as mMostRecentRefresh,
|
||||
@ -237,6 +240,10 @@ private:
|
||||
nsTArray<nsIDocument*> mBeforePaintTargets;
|
||||
// nsTArray on purpose, because we want to be able to swap.
|
||||
nsTArray<nsIDocument*> mAnimationFrameListenerDocs;
|
||||
|
||||
// This is the last interval we used for our timer. May be 0 if we
|
||||
// haven't computed a timer interval yet.
|
||||
mutable PRInt32 mLastTimerInterval;
|
||||
};
|
||||
|
||||
#endif /* !defined(nsRefreshDriver_h_) */
|
||||
|
20
layout/generic/crashtests/621841-1.html
Normal file
20
layout/generic/crashtests/621841-1.html
Normal file
@ -0,0 +1,20 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
|
||||
function boom()
|
||||
{
|
||||
var frame = document.getElementById("f");
|
||||
var frameDoc = frame.contentDocument;
|
||||
frameDoc.getElementById("g").style.background = "yellow";
|
||||
frame.style.cssFloat = "right";
|
||||
document.documentElement.offsetHeight;
|
||||
frameDoc.documentElement.style.color = "green";
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload="boom();"><iframe id="f" src="data:text/html,<!DOCTYPE html><frameset><frame id=g></frameset>"></iframe></body>
|
||||
</html>
|
@ -352,3 +352,4 @@ load 603510-1.html
|
||||
load 604314-1.html
|
||||
load 604843.html
|
||||
load 605340.html
|
||||
load 621841-1.html
|
||||
|
@ -5498,6 +5498,17 @@ nsIFrame::PeekOffset(nsPeekOffsetStruct* aPos)
|
||||
|
||||
break;
|
||||
}
|
||||
case eSelectWordNoSpace:
|
||||
// eSelectWordNoSpace means that we should not be eating any whitespace when
|
||||
// moving to the adjacent word. This means that we should set aPos->
|
||||
// mWordMovementType to eEndWord if we're moving forwards, and to eStartWord
|
||||
// if we're moving backwards.
|
||||
if (aPos->mDirection == eDirPrevious) {
|
||||
aPos->mWordMovementType = eStartWord;
|
||||
} else {
|
||||
aPos->mWordMovementType = eEndWord;
|
||||
}
|
||||
// Intentionally fall through the eSelectWord case.
|
||||
case eSelectWord:
|
||||
{
|
||||
// wordSelectEatSpace means "are we looking for a boundary between whitespace
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user