зеркало из https://github.com/mozilla/gecko-dev.git
Bug 458381 followup: tests and a code fix for a problem the tests caught. r+sr=dbaron, a=beltzner
This commit is contained in:
Родитель
4e3f9ef480
Коммит
127f56f241
|
@ -3182,7 +3182,8 @@ CSSParserImpl::ParseNegatedSimpleSelector(PRInt32& aDataMask,
|
|||
// Given the current parsing rules, every selector in mNegations
|
||||
// contains only one simple selector (css3 definition) within it.
|
||||
// This could easily change in future versions of CSS, and the only
|
||||
// thing we need to change to support that is this parsing code.
|
||||
// thing we need to change to support that is this parsing code and the
|
||||
// serialization code for nsCSSSelector.
|
||||
nsCSSSelector *newSel = new nsCSSSelector();
|
||||
if (!newSel) {
|
||||
mScanner.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY);
|
||||
|
@ -3221,6 +3222,11 @@ CSSParserImpl::ParseNegatedSimpleSelector(PRInt32& aDataMask,
|
|||
return eSelectorParsingStatus_Error;
|
||||
}
|
||||
|
||||
NS_ASSERTION(newSel->mNameSpace == kNameSpaceID_Unknown ||
|
||||
(!newSel->mIDList && !newSel->mClassList &&
|
||||
!newSel->mPseudoClassList && !newSel->mAttrList),
|
||||
"Need to fix the serialization code to deal with this");
|
||||
|
||||
return eSelectorParsingStatus_Continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -504,47 +504,46 @@ void nsCSSSelector::ToStringInternal(nsAString& aString,
|
|||
PRBool wroteNamespace = PR_FALSE;
|
||||
if (!isPseudoElement || !mNext) {
|
||||
// append the namespace prefix if needed
|
||||
if (mNameSpace == kNameSpaceID_None) {
|
||||
// The only way to do this in CSS is to have an explicit namespace
|
||||
// of "none" specified in the sheet by having a '|' with nothing
|
||||
// before it.
|
||||
nsXMLNameSpaceMap *sheetNS = aSheet ? aSheet->GetNameSpaceMap() : nsnull;
|
||||
|
||||
// sheetNS is non-null if and only if we had an @namespace rule. If it's
|
||||
// null, that means that the only namespaces we could have are the
|
||||
// wildcard namespace (which can be implicit in this case) and the "none"
|
||||
// namespace, which then needs to be explicitly specified.
|
||||
if (!sheetNS) {
|
||||
NS_ASSERTION(mNameSpace == kNameSpaceID_Unknown ||
|
||||
mNameSpace == kNameSpaceID_None,
|
||||
"How did we get this namespace?");
|
||||
if (mNameSpace == kNameSpaceID_None) {
|
||||
aString.Append(PRUnichar('|'));
|
||||
wroteNamespace = PR_TRUE;
|
||||
}
|
||||
} else if (sheetNS->FindNameSpaceID(nsnull) == mNameSpace) {
|
||||
// We have the default namespace (possibly including the wildcard
|
||||
// namespace). Do nothing.
|
||||
NS_ASSERTION(mNameSpace == kNameSpaceID_Unknown ||
|
||||
CanBeNamespaced(aIsNegated),
|
||||
"How did we end up with this namespace?");
|
||||
} else if (mNameSpace != kNameSpaceID_Unknown) {
|
||||
NS_ASSERTION(CanBeNamespaced(aIsNegated),
|
||||
"How did we end up with this namespace?");
|
||||
nsIAtom *prefixAtom = sheetNS->FindPrefix(mNameSpace);
|
||||
NS_ASSERTION(prefixAtom, "how'd we get a non-default namespace "
|
||||
"without a prefix?");
|
||||
nsAutoString prefix;
|
||||
prefixAtom->ToString(prefix);
|
||||
aString.Append(prefix);
|
||||
aString.Append(PRUnichar('|'));
|
||||
wroteNamespace = PR_TRUE;
|
||||
} else {
|
||||
if (aSheet) {
|
||||
nsXMLNameSpaceMap *sheetNS = aSheet->GetNameSpaceMap();
|
||||
|
||||
// sheetNS is non-null if and only if we had an @namespace rule. If it's
|
||||
// null, that means that the only namespaces we could have are the
|
||||
// wildcard namespace (which can be implicit in this case) and the "none"
|
||||
// namespace, which we handled above. So no need to output anything when
|
||||
// sheetNS is null.
|
||||
if (sheetNS) {
|
||||
if (mNameSpace != kNameSpaceID_Unknown) {
|
||||
if (sheetNS->FindNameSpaceID(nsnull) != mNameSpace) {
|
||||
nsIAtom *prefixAtom = sheetNS->FindPrefix(mNameSpace);
|
||||
NS_ASSERTION(prefixAtom, "how'd we get a non-default namespace "
|
||||
"without a prefix?");
|
||||
nsAutoString prefix;
|
||||
prefixAtom->ToString(prefix);
|
||||
aString.Append(prefix);
|
||||
aString.Append(PRUnichar('|'));
|
||||
wroteNamespace = PR_TRUE;
|
||||
}
|
||||
// otherwise it must be the default namespace
|
||||
} else {
|
||||
// A selector for an element in any namespace.
|
||||
if (// Use explicit "*|" only when it's not implied
|
||||
sheetNS->FindNameSpaceID(nsnull) != kNameSpaceID_None &&
|
||||
// :not() is special in that the default namespace is
|
||||
// not implied for non-type selectors
|
||||
(!aIsNegated || (!mIDList && !mClassList &&
|
||||
!mPseudoClassList && !mAttrList))) {
|
||||
aString.AppendLiteral("*|");
|
||||
wroteNamespace = PR_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
// A selector for an element in any namespace, while the default
|
||||
// namespace is something else. :not() is special in that the default
|
||||
// namespace is not implied for non-type selectors, so if this is a
|
||||
// negated non-type selector we don't need to output an explicit wildcard
|
||||
// namespace here, since those default to a wildcard namespace.
|
||||
if (CanBeNamespaced(aIsNegated)) {
|
||||
aString.AppendLiteral("*|");
|
||||
wroteNamespace = PR_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -704,6 +703,13 @@ void nsCSSSelector::ToStringInternal(nsAString& aString,
|
|||
}
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsCSSSelector::CanBeNamespaced(PRBool aIsNegated) const
|
||||
{
|
||||
return !aIsNegated ||
|
||||
(!mIDList && !mClassList && !mPseudoClassList && !mAttrList);
|
||||
}
|
||||
|
||||
// -- nsCSSSelectorList -------------------------------
|
||||
|
||||
nsCSSSelectorList::nsCSSSelectorList(void)
|
||||
|
|
|
@ -176,6 +176,10 @@ private:
|
|||
void ToStringInternal(nsAString& aString, nsICSSStyleSheet* aSheet,
|
||||
PRBool aIsPseudoElem,
|
||||
PRBool aIsNegated) const;
|
||||
// Returns true if this selector can have a namespace specified (which
|
||||
// happens if and only if the default namespace would apply to this
|
||||
// selector).
|
||||
PRBool CanBeNamespaced(PRBool aIsNegated) const;
|
||||
|
||||
public:
|
||||
PRInt32 mNameSpace;
|
||||
|
|
|
@ -108,6 +108,7 @@ _TEST_FILES = test_acid3_test46.html \
|
|||
test_initial_storage.html \
|
||||
test_media_queries.html \
|
||||
test_media_queries_dynamic_xbl.html \
|
||||
test_namespace_rule.html \
|
||||
test_of_type_selectors.xhtml \
|
||||
test_parse_rule.html \
|
||||
test_property_database.html \
|
||||
|
|
|
@ -0,0 +1,407 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for CSS Namespace rules</title>
|
||||
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body onload="run()">
|
||||
<p id="display"><iframe id="iframe" src="data:application/xhtml+xml,<html%20xmlns='http://www.w3.org/1999/xhtml'><head/><body/></html>"></iframe></p>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var HTML_NS = "http://www.w3.org/1999/xhtml";
|
||||
var style_text;
|
||||
|
||||
function run() {
|
||||
var iframe = $("iframe");
|
||||
var ifwin = iframe.contentWindow;
|
||||
var ifdoc = iframe.contentDocument;
|
||||
var ifbody = ifdoc.getElementsByTagName("body")[0];
|
||||
|
||||
function setup_style_text() {
|
||||
var style_elem = ifdoc.createElement("style");
|
||||
style_elem.setAttribute("type", "text/css");
|
||||
ifdoc.getElementsByTagName("head")[0].appendChild(style_elem);
|
||||
var style_text = ifdoc.createCDATASection("");
|
||||
style_elem.appendChild(style_text);
|
||||
return style_text;
|
||||
}
|
||||
|
||||
style_text = setup_style_text();
|
||||
var gCounter = 0;
|
||||
|
||||
/*
|
||||
* namespaceRules: the @namespace rules to use
|
||||
* selector: the selector to test
|
||||
* body_contents: what to set the body's innerHTML to
|
||||
* match_fn: a function that, given the document object into which
|
||||
* body_contents has been inserted, produces an array of nodes that
|
||||
* should match selector
|
||||
* notmatch_fn: likewise, but for nodes that should not match
|
||||
*/
|
||||
function test_selector_in_html(namespaceRules, selector, body_contents,
|
||||
match_fn, notmatch_fn)
|
||||
{
|
||||
var zi = ++gCounter;
|
||||
if (typeof(body_contents) == "string") {
|
||||
ifbody.innerHTML = body_contents;
|
||||
} else {
|
||||
// It's a function.
|
||||
ifbody.innerHTML = "";
|
||||
body_contents(ifbody);
|
||||
}
|
||||
style_text.data =
|
||||
namespaceRules + " " + selector + "{ z-index: " + zi + " }";
|
||||
var should_match = match_fn(ifdoc);
|
||||
var should_not_match = notmatch_fn(ifdoc);
|
||||
if (should_match.length + should_not_match.length == 0) {
|
||||
ok(false, "nothing to check");
|
||||
}
|
||||
|
||||
for (var i = 0; i < should_match.length; ++i) {
|
||||
var e = should_match[i];
|
||||
is(ifwin.getComputedStyle(e, "").zIndex, zi,
|
||||
"element in " + body_contents + " matched " + selector);
|
||||
}
|
||||
for (var i = 0; i < should_not_match.length; ++i) {
|
||||
var e = should_not_match[i];
|
||||
is(ifwin.getComputedStyle(e, "").zIndex, "auto",
|
||||
"element in " + body_contents + " did not match " + selector);
|
||||
}
|
||||
|
||||
// Now, since we're here, may as well make sure serialization
|
||||
// works correctly. It need not produce the exact same text,
|
||||
// but it should produce a selector that matches the same
|
||||
// elements.
|
||||
zi = ++gCounter;
|
||||
var ruleList = style_text.parentNode.sheet.cssRules;
|
||||
var ser1 = ruleList[ruleList.length-1].selectorText;
|
||||
style_text.data =
|
||||
namespaceRules + " " + ser1 + "{ z-index: " + zi + " }";
|
||||
for (var i = 0; i < should_match.length; ++i) {
|
||||
var e = should_match[i];
|
||||
is(ifwin.getComputedStyle(e, "").zIndex, zi,
|
||||
"element in " + body_contents + " matched " + ser1 +
|
||||
" which is the reserialization of " + selector);
|
||||
}
|
||||
for (var i = 0; i < should_not_match.length; ++i) {
|
||||
var e = should_not_match[i];
|
||||
is(ifwin.getComputedStyle(e, "").zIndex, "auto",
|
||||
"element in " + body_contents + " did not match " + ser1 +
|
||||
" which is the reserialization of " + selector);
|
||||
}
|
||||
|
||||
// But when we serialize the serialized result, we should get
|
||||
// the same text.
|
||||
var ser2 = ruleList[ruleList.length-1].selectorText;
|
||||
is(ser2, ser1, "parse+serialize of selector \"" + selector +
|
||||
"\" is idempotent");
|
||||
|
||||
ifbody.innerHTML = "";
|
||||
style_text.data = "";
|
||||
}
|
||||
|
||||
// 2 tests from http://tc.labs.opera.com/css/namespaces/prefix-001.xml
|
||||
test_selector_in_html(
|
||||
'@namespace foo "x"; @namespace Foo "y";',
|
||||
'Foo|test',
|
||||
'<test xmlns="y"/>',
|
||||
function (doc) { return doc.getElementsByTagName("test"); },
|
||||
function (doc) { return []; }
|
||||
);
|
||||
|
||||
test_selector_in_html(
|
||||
'@namespace foo "x"; @namespace Foo "y";',
|
||||
'foo|test',
|
||||
'<test xmlns="y"/>',
|
||||
function (doc) { return []; },
|
||||
function (doc) { return doc.getElementsByTagName("test");}
|
||||
);
|
||||
|
||||
// 2 tests from http://tc.labs.opera.com/css/namespaces/prefix-002.xml
|
||||
test_selector_in_html(
|
||||
'@namespace foo "";',
|
||||
'test',
|
||||
'<test xmlns=""/>',
|
||||
function (doc) { return doc.getElementsByTagName("test");},
|
||||
function (doc) { return []; }
|
||||
);
|
||||
|
||||
test_selector_in_html(
|
||||
'@namespace foo "";',
|
||||
'foo|test',
|
||||
'<test xmlns=""/>',
|
||||
function (doc) { return doc.getElementsByTagName("test");},
|
||||
function (doc) { return []; }
|
||||
);
|
||||
|
||||
// 2 tests from http://tc.labs.opera.com/css/namespaces/prefix-003.xml
|
||||
test_selector_in_html(
|
||||
'@namespace foo "";',
|
||||
'test',
|
||||
'<foo xmlns=""><test/></foo>',
|
||||
function (doc) { return doc.getElementsByTagName("test");},
|
||||
function (doc) { return []; }
|
||||
);
|
||||
|
||||
test_selector_in_html(
|
||||
'@namespace foo "";',
|
||||
'foo|test',
|
||||
'<foo xmlns=""><test/></foo>',
|
||||
function (doc) { return doc.getElementsByTagName("test");},
|
||||
function (doc) { return []; }
|
||||
);
|
||||
|
||||
// 4 tests from http://tc.labs.opera.com/css/namespaces/prefix-004.xml
|
||||
test_selector_in_html(
|
||||
'@namespace ""; @namespace x "test";',
|
||||
'test[x]',
|
||||
'<foo xmlns=""><test x=""/></foo>',
|
||||
function (doc) { return doc.getElementsByTagName("test");},
|
||||
function (doc) { return []; }
|
||||
);
|
||||
|
||||
test_selector_in_html(
|
||||
'@namespace ""; @namespace x "test";',
|
||||
'*|test',
|
||||
'<foo xmlns=""><test x=""/></foo>',
|
||||
function (doc) { return doc.getElementsByTagName("test");},
|
||||
function (doc) { return []; }
|
||||
);
|
||||
|
||||
test_selector_in_html(
|
||||
'@namespace ""; @namespace x "test";',
|
||||
'*|test',
|
||||
'<test xmlns="test"/>',
|
||||
function (doc) { return doc.getElementsByTagName("test");},
|
||||
function (doc) { return []; }
|
||||
);
|
||||
|
||||
test_selector_in_html(
|
||||
'@namespace ""; @namespace x "test";',
|
||||
'test',
|
||||
'<test xmlns="test"/>',
|
||||
function (doc) { return []; },
|
||||
function (doc) { return doc.getElementsByTagName("test");}
|
||||
);
|
||||
|
||||
// 2 tests from http://tc.labs.opera.com/css/namespaces/prefix-005.xml
|
||||
test_selector_in_html(
|
||||
'@namespace x "test";',
|
||||
'test',
|
||||
'<test/>',
|
||||
function (doc) { return doc.getElementsByTagName("test");},
|
||||
function (doc) { return []; }
|
||||
);
|
||||
|
||||
test_selector_in_html(
|
||||
'@namespace x "test";',
|
||||
'test',
|
||||
'<test xmlns="test"/>',
|
||||
function (doc) { return doc.getElementsByTagName("test");},
|
||||
function (doc) { return []; }
|
||||
);
|
||||
|
||||
// Skipping the scope tests because they involve import, and we have no way
|
||||
// to know when the import load completes.
|
||||
|
||||
// 1 test from http://tc.labs.opera.com/css/namespaces/syntax-001.xml
|
||||
test_selector_in_html(
|
||||
'@NAmespace x "http://www.w3.org/1999/xhtml";',
|
||||
'x|test',
|
||||
'<test/>',
|
||||
function (doc) { return doc.getElementsByTagName("test");},
|
||||
function (doc) { return []; }
|
||||
);
|
||||
|
||||
// 1 test from http://tc.labs.opera.com/css/namespaces/syntax-002.xml
|
||||
test_selector_in_html(
|
||||
'@NAmespac\\65 x "http://www.w3.org/1999/xhtml";',
|
||||
'x|test',
|
||||
'<test/>',
|
||||
function (doc) { return doc.getElementsByTagName("test");},
|
||||
function (doc) { return []; }
|
||||
);
|
||||
|
||||
// 3 tests from http://tc.labs.opera.com/css/namespaces/syntax-003.xml
|
||||
test_selector_in_html(
|
||||
'@namespace url("test");',
|
||||
'*|test',
|
||||
'<test xmlns="test"/>',
|
||||
function (doc) { return doc.getElementsByTagName("test");},
|
||||
function (doc) { return []; }
|
||||
);
|
||||
|
||||
test_selector_in_html(
|
||||
'@namespace url("test");',
|
||||
'test',
|
||||
'<test xmlns="test"/>',
|
||||
function (doc) { return doc.getElementsByTagName("test");},
|
||||
function (doc) { return []; }
|
||||
);
|
||||
|
||||
test_selector_in_html(
|
||||
'@namespace url("test");',
|
||||
'test',
|
||||
'<test/>',
|
||||
function (doc) { return []; },
|
||||
function (doc) { return doc.getElementsByTagName("test");}
|
||||
);
|
||||
|
||||
// 3 tests from http://tc.labs.opera.com/css/namespaces/syntax-004.xml
|
||||
test_selector_in_html(
|
||||
'@namespace u\\00072l("test");',
|
||||
'*|test',
|
||||
'<test xmlns="test"/>',
|
||||
function (doc) { return doc.getElementsByTagName("test");},
|
||||
function (doc) { return []; }
|
||||
);
|
||||
|
||||
test_selector_in_html(
|
||||
'@namespace u\\00072l("test");',
|
||||
'test',
|
||||
'<test xmlns="test"/>',
|
||||
function (doc) { return doc.getElementsByTagName("test");},
|
||||
function (doc) { return []; }
|
||||
);
|
||||
|
||||
test_selector_in_html(
|
||||
'@namespace u\\00072l("test");',
|
||||
'test',
|
||||
'<test/>',
|
||||
function (doc) { return []; },
|
||||
function (doc) { return doc.getElementsByTagName("test");}
|
||||
);
|
||||
|
||||
// Skipping http://tc.labs.opera.com/css/namespaces/syntax-005.xml because it
|
||||
// involves import, and we have no way // to know when the import load completes.
|
||||
|
||||
// Skipping http://tc.labs.opera.com/css/namespaces/syntax-006.xml because it
|
||||
// involves import, and we have no way // to know when the import load completes.
|
||||
|
||||
// 2 tests from http://tc.labs.opera.com/css/namespaces/syntax-007.xml
|
||||
test_selector_in_html(
|
||||
'@charset "x"; @namespace url("test"); @namespace url("test2");',
|
||||
'*|test',
|
||||
'<test xmlns="test"/>',
|
||||
function (doc) { return doc.getElementsByTagName("test");},
|
||||
function (doc) { return []; }
|
||||
);
|
||||
|
||||
test_selector_in_html(
|
||||
'@charset "x"; @namespace url("test"); @namespace url("test2");',
|
||||
'test',
|
||||
'<test xmlns="test"/>',
|
||||
function (doc) { return []; },
|
||||
function (doc) { return doc.getElementsByTagName("test");}
|
||||
);
|
||||
|
||||
// 2 tests from http://tc.labs.opera.com/css/namespaces/syntax-008.xml
|
||||
test_selector_in_html(
|
||||
'@namespace \\72x url("test");',
|
||||
'rx|test',
|
||||
'<test xmlns="test"/>',
|
||||
function (doc) { return doc.getElementsByTagName("test");},
|
||||
function (doc) { return []; }
|
||||
);
|
||||
|
||||
test_selector_in_html(
|
||||
'@namespace \\72x url("test");',
|
||||
'test',
|
||||
'<test xmlns="test"/>',
|
||||
function (doc) { return doc.getElementsByTagName("test");},
|
||||
function (doc) { return []; }
|
||||
);
|
||||
|
||||
// And now some :not() tests
|
||||
test_selector_in_html(
|
||||
'@namespace url("test");',
|
||||
'*|*:not(test)',
|
||||
'<test xmlns="test"/>',
|
||||
function (doc) { return []; },
|
||||
function (doc) { return doc.getElementsByTagName("test");}
|
||||
);
|
||||
|
||||
test_selector_in_html(
|
||||
'@namespace url("test");',
|
||||
'*|*:not(test)',
|
||||
'<test xmlns="testing"/>',
|
||||
function (doc) { return doc.getElementsByTagName("test");},
|
||||
function (doc) { return []; }
|
||||
);
|
||||
|
||||
test_selector_in_html(
|
||||
'@namespace x url("test");',
|
||||
'*|*:not(x|test)',
|
||||
'<test xmlns="test"/>',
|
||||
function (doc) { return []; },
|
||||
function (doc) { return doc.getElementsByTagName("test");}
|
||||
);
|
||||
|
||||
test_selector_in_html(
|
||||
'@namespace x url("test");',
|
||||
'*|*:not(x|test)',
|
||||
'<test xmlns="testing"/>',
|
||||
function (doc) { return doc.getElementsByTagName("test");},
|
||||
function (doc) { return []; }
|
||||
);
|
||||
|
||||
test_selector_in_html(
|
||||
'@namespace url("test");',
|
||||
'*|*:not(*)',
|
||||
'<test xmlns="testing"/>',
|
||||
function (doc) { return doc.getElementsByTagName("test");},
|
||||
function (doc) { return []; }
|
||||
);
|
||||
|
||||
test_selector_in_html(
|
||||
'@namespace url("test");',
|
||||
'*|*:not(*)',
|
||||
'<test xmlns="test"/>',
|
||||
function (doc) { return []; },
|
||||
function (doc) { return doc.getElementsByTagName("test");}
|
||||
);
|
||||
|
||||
test_selector_in_html(
|
||||
'@namespace x url("test");',
|
||||
'*|*:not(x|*)',
|
||||
'<test xmlns="testing"/>',
|
||||
function (doc) { return doc.getElementsByTagName("test");},
|
||||
function (doc) { return []; }
|
||||
);
|
||||
|
||||
test_selector_in_html(
|
||||
'@namespace x url("test");',
|
||||
'*|*:not(x|*)',
|
||||
'<test xmlns="test"/>',
|
||||
function (doc) { return []; },
|
||||
function (doc) { return doc.getElementsByTagName("test");}
|
||||
);
|
||||
|
||||
test_selector_in_html(
|
||||
'@namespace url("test");',
|
||||
'*|*:not([foo])',
|
||||
'<test xmlns="testing" foo="bar"/>',
|
||||
function (doc) { return []; },
|
||||
function (doc) { return doc.getElementsByTagName("test");}
|
||||
);
|
||||
|
||||
test_selector_in_html(
|
||||
'@namespace url("test");',
|
||||
'*|*:not([foo])',
|
||||
'<test xmlns="test" foo="bar"/>',
|
||||
function (doc) { return []; },
|
||||
function (doc) { return doc.getElementsByTagName("test");}
|
||||
);
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
Загрузка…
Ссылка в новой задаче