<?xml version="1.0"?> <?xml-stylesheet href="chrome://global/skin" type="text/css"?> <window title="Browser Drop Tests" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/> <script> <![CDATA[ Components.utils.import("resource://testing-common/ContentTask.jsm"); function dropOnRemoteBrowserAsync(browser, data, shouldExpectStateChange) { ContentTask.setTestScope(window); // Need this so is/isnot/ok are available inside the contenttask return ContentTask.spawn(browser, {data, shouldExpectStateChange}, function*({data, shouldExpectStateChange}) { let { interfaces: Ci, utils: Cu } = Components; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); if (!content.document.documentElement) { // Wait until the testing document gets loaded. yield new Promise(resolve => { let onload = function() { content.window.removeEventListener("load", onload); resolve(); }; content.window.addEventListener("load", onload); }); } let dataTransfer = new content.DataTransfer(); for (let i = 0; i < data.length; i++) { let types = data[i]; for (let j = 0; j < types.length; j++) { dataTransfer.mozSetDataAt(types[j].type, types[j].data, i); } } let event = content.document.createEvent("DragEvent"); event.initDragEvent("drop", true, true, content, 0, 0, 0, 0, 0, false, false, false, false, 0, null, dataTransfer); content.document.body.dispatchEvent(event); let links = []; try { links = Services.droppedLinkHandler.dropLinks(event, true); } catch (ex) { if (shouldExpectStateChange) { ok(false, "Should not have gotten an exception from the dropped link handler, but got: " + ex); Cu.reportError(ex); } } return links; }); } function* expectLink(browser, expectedLinks, data, testid, onbody=false) { let lastLinks = []; let lastLinksPromise = new Promise(resolve => { browser.droppedLinkHandler = function(event, links) { info(`droppedLinkHandler called, received links ${JSON.stringify(links)}`); if (expectedLinks.length == 0) { ok(false, `droppedLinkHandler called for ${JSON.stringify(links)} which we didn't expect.`); } lastLinks = links; resolve(links); }; }); function dropOnBrowserSync() { let dropEl = onbody ? browser.contentDocument.body : browser; synthesizeDrop(dropEl, dropEl, data, "", dropEl.ownerDocument.defaultView); } let links; if (browser.isRemoteBrowser) { let remoteLinks = yield dropOnRemoteBrowserAsync(browser, data, expectedLinks.length != 0); is(remoteLinks.length, expectedLinks.length, testid + " remote links length"); for (let i = 0, length = remoteLinks.length; i < length; i++) { is(remoteLinks[i].url, expectedLinks[i].url, testid + "[" + i + "] remote link"); is(remoteLinks[i].name, expectedLinks[i].name, testid + "[" + i + "] remote name"); } if (expectedLinks.length == 0) { // There is no way to check if nothing happens asynchronously. return; } links = yield lastLinksPromise; } else { dropOnBrowserSync(); links = lastLinks; } is(links.length, expectedLinks.length, testid + " links length"); for (let i = 0, length = links.length; i < length; i++) { is(links[i].url, expectedLinks[i].url, testid + "[" + i + "] link"); is(links[i].name, expectedLinks[i].name, testid + "[" + i + "] name"); } }; function* dropLinksOnBrowser(browser, type) { // Dropping single text/plain item with single link should open single // page. yield* expectLink(browser, [ { url: "http://www.mozilla.org/", name: "http://www.mozilla.org/" } ], [ [ { type: "text/plain", data: "http://www.mozilla.org/" } ] ], "text/plain drop on browser " + type); // Dropping single text/plain item with multiple links should open // multiple pages. yield* expectLink(browser, [ { url: "http://www.mozilla.org/", name: "http://www.mozilla.org/" }, { url: "http://www.example.com/", name: "http://www.example.com/" } ], [ [ { type: "text/plain", data: "http://www.mozilla.org/\nhttp://www.example.com/" } ] ], "text/plain with 2 URLs drop on browser " + type); // Dropping sinlge unsupported type item should not open anything. yield* expectLink(browser, [], [ [ { type: "text/link", data: "http://www.mozilla.org/" } ] ], "text/link drop on browser " + type); // Dropping single text/uri-list item with single link should open single // page. yield* expectLink(browser, [ { url: "http://www.example.com/", name: "http://www.example.com/" } ], [ [ { type: "text/uri-list", data: "http://www.example.com/" } ] ], "text/uri-list drop on browser " + type); // Dropping single text/uri-list item with multiple links should open // multiple pages. yield* expectLink(browser, [ { url: "http://www.example.com/", name: "http://www.example.com/" }, { url: "http://www.mozilla.org/", name: "http://www.mozilla.org/" }], [ [ { type: "text/uri-list", data: "http://www.example.com/\nhttp://www.mozilla.org/" } ] ], "text/uri-list with 2 URLs drop on browser " + type); // Name in text/x-moz-url should be handled. yield* expectLink(browser, [ { url: "http://www.example.com/", name: "Example.com" } ], [ [ { type: "text/x-moz-url", data: "http://www.example.com/\nExample.com" } ] ], "text/x-moz-url drop on browser " + type); yield* expectLink(browser, [ { url: "http://www.mozilla.org/", name: "Mozilla.org" }, { url: "http://www.example.com/", name: "Example.com" } ], [ [ { type: "text/x-moz-url", data: "http://www.mozilla.org/\nMozilla.org\nhttp://www.example.com/\nExample.com" } ] ], "text/x-moz-url with 2 URLs drop on browser " + type); // Dropping single item with multiple types should open single page. yield* expectLink(browser, [ { url: "http://www.example.org/", name: "Example.com" } ], [ [ { type: "text/plain", data: "http://www.mozilla.org/" }, { type: "text/x-moz-url", data: "http://www.example.org/\nExample.com" } ] ], "text/plain and text/x-moz-url drop on browser " + type); // Dropping javascript or data: URLs should fail: yield* expectLink(browser, [], [ [ { type: "text/plain", data: "javascript:'bad'" } ] ], "text/plain javascript url drop on browser " + type); yield* expectLink(browser, [], [ [ { type: "text/plain", data: "jAvascript:'also bad'" } ] ], "text/plain mixed-case javascript url drop on browser " + type); yield* expectLink(browser, [], [ [ { type: "text/plain", data: "data:text/html,bad" } ] ], "text/plain data url drop on browser " + type); // Dropping a chrome url should fail as we don't have a source node set, // defaulting to a source of file:/// yield* expectLink(browser, [], [ [ { type: "text/x-moz-url", data: "chrome://browser/content/browser.xul" } ] ], "text/x-moz-url chrome url drop on browser " + type); if (browser.type == "content") { yield ContentTask.spawn(browser, null, function() { content.window.stopMode = true; }); // stopPropagation should not prevent the browser link handling from occuring yield* expectLink(browser, [ { url: "http://www.mozilla.org/", name: "http://www.mozilla.org/" } ], [ [ { type: "text/uri-list", data: "http://www.mozilla.org/" } ] ], "text/x-moz-url drop on browser with stopPropagation drop event", true); yield ContentTask.spawn(browser, null, function() { content.window.cancelMode = true; }); // Canceling the event, however, should prevent the link from being handled. yield* expectLink(browser, [], [ [ { type: "text/uri-list", data: "http://www.mozilla.org/" } ] ], "text/x-moz-url drop on browser with cancelled drop event", true); } } function info(msg) { window.opener.wrappedJSObject.SimpleTest.info(msg); } function is(l, r, n) { window.opener.wrappedJSObject.SimpleTest.is(l,r,n); } function ok(v, n) { window.opener.wrappedJSObject.SimpleTest.ok(v,n); } ]]> </script> <browser id="chromechild" src="about:blank"/> <browser id="contentchild" type="content" width="100" height="100" src="data:text/html,<html draggable='true'><body draggable='true' style='width: 100px; height: 100px;' ondragover='event.preventDefault()' ondrop='if (window.stopMode) event.stopPropagation(); if (window.cancelMode) event.preventDefault();'></body></html>"/> <browser id="remote-contentchild" type="content" width="100" height="100" remote="true" src="data:text/html,<html draggable='true'><body draggable='true' style='width: 100px; height: 100px;' ondragover='event.preventDefault()' ondrop='if (window.stopMode) event.stopPropagation(); if (window.cancelMode) event.preventDefault();'></body></html>"/> </window>