Skip to content
This repository has been archived by the owner on Feb 26, 2022. It is now read-only.

Commit

Permalink
Bug 870677 - Adding './' as shortcut for 'data' folder in existing AP
Browse files Browse the repository at this point in the history
- Added shortcut and test cases
  • Loading branch information
ZER0 committed Jul 16, 2014
1 parent 8778d45 commit 21edd11
Show file tree
Hide file tree
Showing 29 changed files with 481 additions and 207 deletions.
79 changes: 24 additions & 55 deletions lib/sdk/content/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,81 +9,50 @@ module.metadata = {
};

const { EventEmitter } = require('../deprecated/events');
const { validateOptions } = require('../deprecated/api-utils');
const { isValidURI, URL } = require('../url');
const { isValidURI, isLocalURL, URL } = require('../url');
const file = require('../io/file');
const { contract } = require('../util/contract');
const { isString, instanceOf } = require('../lang/type');
const { isString, isNil, instanceOf } = require('../lang/type');
const { validateOptions,
string, array, object, either, required } = require('../deprecated/api-utils');

const LOCAL_URI_SCHEMES = ['resource', 'data'];
const isJSONable = (value) => {
try {
JSON.parse(JSON.stringify(value));
} catch (e) {
return false;
}
return true;
};

// Returns `null` if `value` is `null` or `undefined`, otherwise `value`.
function ensureNull(value) value == null ? null : value
const isValidScriptFile = (value) =>
(isString(value) || instanceOf(value, URL)) && isLocalURL(value);

// map of property validations
const valid = {
contentURL: {
map: function(url) !url ? ensureNull(url) : url.toString(),
is: ['undefined', 'null', 'string'],
ok: function (url) {
if (url === null)
return true;
return isValidURI(url);
},
is: either(string, object),
ok: url => isNil(url) || isLocalURL(url) || isValidURI(url),
msg: 'The `contentURL` option must be a valid URL.'
},
contentScriptFile: {
is: ['undefined', 'null', 'string', 'array', 'object'],
map: ensureNull,
ok: function(value) {
if (value === null)
return true;

value = [].concat(value);

// Make sure every item is a string or an
// URL instance, and also a local file URL.
return value.every(function (item) {

if (!isString(item) && !(item instanceof URL))
return false;

try {
return ~LOCAL_URI_SCHEMES.indexOf(URL(item).scheme);
}
catch(e) {
return false;
}
});

},
is: either(string, object, array),
ok: value => isNil(value) || [].concat(value).every(isValidScriptFile),
msg: 'The `contentScriptFile` option must be a local URL or an array of URLs.'
},
contentScript: {
is: ['undefined', 'null', 'string', 'array'],
map: ensureNull,
ok: function(value) {
return !Array.isArray(value) || value.every(
function(item) { return typeof item === 'string' }
);
},
is: either(string, array),
ok: value => isNil(value) || [].concat(value).every(isString),
msg: 'The `contentScript` option must be a string or an array of strings.'
},
contentScriptWhen: {
is: ['string'],
ok: function(value) { return ~['start', 'ready', 'end'].indexOf(value) },
map: function(value) {
return value || 'end';
},
is: required(string),
map: value => value || 'end',
ok: value => ~['start', 'ready', 'end'].indexOf(value),
msg: 'The `contentScriptWhen` option must be either "start", "ready" or "end".'
},
contentScriptOptions: {
ok: function(value) {
if ( value === undefined ) { return true; }
try { JSON.parse( JSON.stringify( value ) ); } catch(e) { return false; }
return true;
},
map: function(value) 'undefined' === getTypeOf(value) ? null : value,
ok: value => isNil(value) || isJSONable(value),
msg: 'The contentScriptOptions should be a jsonable value.'
}
};
Expand Down
12 changes: 8 additions & 4 deletions lib/sdk/content/sandbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const { merge } = require('../util/object');
const { getTabForContentWindow } = require('../tabs/utils');
const { getInnerId } = require('../window/utils');
const { PlainTextConsole } = require('../console/plain-text');

const { data } = require('../self');
// WeakMap of sandboxes so we can access private values
const sandboxes = new WeakMap();

Expand Down Expand Up @@ -247,9 +247,12 @@ const WorkerSandbox = Class({
// The order of `contentScriptFile` and `contentScript` evaluation is
// intentional, so programs can load libraries like jQuery from script URLs
// and use them in scripts.
let contentScriptFile = ('contentScriptFile' in worker) ? worker.contentScriptFile
let contentScriptFile = ('contentScriptFile' in worker)
? worker.contentScriptFile
: null,
contentScript = ('contentScript' in worker) ? worker.contentScript : null;
contentScript = ('contentScript' in worker)
? worker.contentScript
: null;

if (contentScriptFile)
importScripts.apply(null, [this].concat(contentScriptFile));
Expand Down Expand Up @@ -285,7 +288,8 @@ exports.WorkerSandbox = WorkerSandbox;
function importScripts (workerSandbox, ...urls) {
let { worker, sandbox } = modelFor(workerSandbox);
for (let i in urls) {
let contentScriptFile = urls[i];
let contentScriptFile = data.url(urls[i]);

try {
let uri = URL(contentScriptFile);
if (uri.scheme === 'resource')
Expand Down
9 changes: 5 additions & 4 deletions lib/sdk/content/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@ module.metadata = {
};

let { merge } = require('../util/object');
let assetsURI = require('../self').data.url();
let { data } = require('../self');
let assetsURI = data.url();
let isArray = Array.isArray;
let method = require('../../method/core');

function isAddonContent({ contentURL }) {
return typeof(contentURL) === 'string' && contentURL.indexOf(assetsURI) === 0;
}
const isAddonContent = ({ contentURL }) =>
contentURL && data.url(contentURL).startsWith(assetsURI);

exports.isAddonContent = isAddonContent;

function hasContentScript({ contentScript, contentScriptFile }) {
Expand Down
30 changes: 6 additions & 24 deletions lib/sdk/context-menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const { EventTarget } = require("./event/target");
const { emit } = require('./event/core');
const { when } = require('./system/unload');
const selection = require('./selection');
const { contract: loaderContract } = require('./content/loader');

// All user items we add have this class.
const ITEM_CLASS = "addon-context-menu-item";
Expand Down Expand Up @@ -257,15 +258,15 @@ function populateCallbackNodeData(node) {
}

data.selectionText = selection.text;

data.srcURL = node.src || null;
data.value = node.value || null;

while (!data.linkURL && node) {
data.linkURL = node.href || null;
node = node.parentNode;
}

return data;
}

Expand Down Expand Up @@ -298,30 +299,11 @@ let baseItemRules = {
msg: "The 'context' option must be a Context object or an array of " +
"Context objects."
},
contentScript: {
is: ["string", "array", "undefined"],
ok: function (v) {
return !Array.isArray(v) ||
v.every(function (s) typeof(s) === "string");
}
},
contentScriptFile: {
is: ["string", "array", "undefined"],
ok: function (v) {
if (!v)
return true;
let arr = Array.isArray(v) ? v : [v];
return arr.every(function (s) {
return getTypeOf(s) === "string" &&
getScheme(s) === 'resource';
});
},
msg: "The 'contentScriptFile' option must be a local file URL or " +
"an array of local file URLs."
},
onMessage: {
is: ["function", "undefined"]
}
},
contentScript: loaderContract.rules.contentScript,
contentScriptFile: loaderContract.rules.contentScriptFile
};

let labelledItemRules = mix(baseItemRules, {
Expand Down
3 changes: 3 additions & 0 deletions lib/sdk/deprecated/api-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,9 @@ exports.boolean = boolean;
let object = { is: ['object', 'undefined', 'null'] };
exports.object = object;

let array = { is: ['array', 'undefined', 'null'] };
exports.array = array;

let isTruthyType = type => !(type === 'undefined' || type === 'null');
let findTypes = v => { while (!isArray(v) && v.is) v = v.is; return v };

Expand Down
10 changes: 7 additions & 3 deletions lib/sdk/notifications.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ const { Cc, Ci, Cr } = require("chrome");
const apiUtils = require("./deprecated/api-utils");
const errors = require("./deprecated/errors");
const { isString, isUndefined, instanceOf } = require('./lang/type');
const { URL } = require('./url');
const { URL, isLocalURL } = require('./url');
const { data } = require('./self');

const NOTIFICATION_DIRECTIONS = ["auto", "ltr", "rtl"];

Expand All @@ -39,15 +40,18 @@ exports.notify = function notifications_notify(options) {
}
};
function notifyWithOpts(notifyFn) {
notifyFn(valOpts.iconURL, valOpts.title, valOpts.text, !!clickObserver,
let { iconURL } = valOpts;
iconURL = iconURL && isLocalURL(iconURL) ? data.url(iconURL) : iconURL;

notifyFn(iconURL, valOpts.title, valOpts.text, !!clickObserver,
valOpts.data, clickObserver, valOpts.tag, valOpts.dir, valOpts.lang);
}
try {
notifyWithOpts(notify);
}
catch (err) {
if (err instanceof Ci.nsIException && err.result == Cr.NS_ERROR_FILE_NOT_FOUND) {
console.warn("The notification icon named by " + valOpts.iconURL +
console.warn("The notification icon named by " + iconURL +
" does not exist. A default icon will be used instead.");
delete valOpts.iconURL;
notifyWithOpts(notify);
Expand Down
17 changes: 14 additions & 3 deletions lib/sdk/page-worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const { contract: loaderContract } = require('./content/loader');
const { has } = require('./util/array');
const { Rules } = require('./util/rules');
const { merge } = require('./util/object');
const { data } = require('./self');

const views = WeakMap();
const workers = WeakMap();
Expand Down Expand Up @@ -92,10 +93,13 @@ const Page = Class({
setup: function Page(options) {
let page = this;
options = pageContract(options);

let uri = options.contentURL;

let view = makeFrame(window.document, {
nodeName: 'iframe',
type: 'content',
uri: options.contentURL,
uri: uri ? data.url(uri) : '',
allowJavascript: options.allow.script,
allowPlugins: true,
allowAuth: true
Expand Down Expand Up @@ -124,12 +128,19 @@ const Page = Class({
let allowJavascript = pageContract({ allow: value }).allow.script;
return allowJavascript ? enableScript(this) : disableScript(this);
},
get contentURL() { return viewFor(this).getAttribute('src'); },
get contentURL() { return viewFor(this).getAttribute("data-src") },
set contentURL(value) {
if (!isValidURL(this, value)) return;
let view = viewFor(this);
let contentURL = pageContract({ contentURL: value }).contentURL;
view.setAttribute('src', contentURL);

// page-worker doesn't have a model like other APIs, so to be consitent
// with the behavior "what you set is what you get", we need to store
// the original `contentURL` given.
// Even if XUL elements doesn't support `dataset`, properties, to
// indicate that is a custom attribute the syntax "data-*" is used.
view.setAttribute('data-src', contentURL);
view.setAttribute('src', data.url(contentURL));
},
dispose: function () {
if (isDisposed(this)) return;
Expand Down
4 changes: 2 additions & 2 deletions lib/sdk/panel.js
Original file line number Diff line number Diff line change
Expand Up @@ -307,13 +307,13 @@ on(hides, "data", ({target}) => emit(panelFor(target), "hide"));
on(ready, "data", ({target}) => {
let panel = panelFor(target);
let window = domPanel.getContentDocument(target).defaultView;

workerFor(panel).attach(window);
});

on(start, "data", ({target}) => {
let panel = panelFor(target);
let window = domPanel.getContentDocument(target).defaultView;

attach(styleFor(panel), window);
});
7 changes: 6 additions & 1 deletion lib/sdk/panel/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ const { getMostRecentBrowserWindow, getOwnerBrowserWindow,
const { create: createFrame, swapFrameLoaders } = require("../frame/utils");
const { window: addonWindow } = require("../addon/window");
const { isNil } = require("../lang/type");
const { data } = require('../self');

const events = require("../system/events");


Expand Down Expand Up @@ -402,7 +404,10 @@ exports.getContentFrame = getContentFrame;
function getContentDocument(panel) getContentFrame(panel).contentDocument
exports.getContentDocument = getContentDocument;

function setURL(panel, url) getContentFrame(panel).setAttribute("src", url)
function setURL(panel, url) {
getContentFrame(panel).setAttribute("src", url ? data.url(url) : url);
}

exports.setURL = setURL;

function allowContextMenu(panel, allow) {
Expand Down
2 changes: 1 addition & 1 deletion lib/sdk/self.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const permissions = metadata.permissions || {};
const isPacked = rootURI && rootURI.indexOf("jar:") === 0;

const uri = (path="") =>
path.contains(":") ? path : addonDataURI + path;
path.contains(":") ? path : addonDataURI + path.replace(/^\.\//, "/");


// Some XPCOM APIs require valid URIs as an argument for certain operations
Expand Down
18 changes: 4 additions & 14 deletions lib/sdk/stylesheet/style.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,14 @@ module.metadata = {

const { Cc, Ci } = require("chrome");
const { Class } = require("../core/heritage");
const { ns } = require("../core/namespace");
const { URL } = require('../url');
const { URL, isLocalURL } = require('../url');
const events = require("../system/events");
const { loadSheet, removeSheet, isTypeValid } = require("./utils");
const { isString } = require("../lang/type");
const { attachTo, detachFrom, getTargetWindow } = require("../content/mod");
const { data } = require('../self');

const { freeze, create } = Object;
const LOCAL_URI_SCHEMES = ['resource', 'data'];

function isLocalURL(item) {
try {
return LOCAL_URI_SCHEMES.indexOf(URL(item).scheme) > -1;
}
catch(e) {}

return false;
}

function Style({ source, uri, type }) {
source = source == null ? null : freeze([].concat(source));
Expand Down Expand Up @@ -54,7 +44,7 @@ exports.Style = Style;
attachTo.define(Style, function (style, window) {
if (style.uri) {
for (let uri of style.uri)
loadSheet(window, uri, style.type);
loadSheet(window, data.url(uri), style.type);
}

if (style.source) {
Expand All @@ -69,7 +59,7 @@ attachTo.define(Style, function (style, window) {
detachFrom.define(Style, function (style, window) {
if (style.uri)
for (let uri of style.uri)
removeSheet(window, uri);
removeSheet(window, data.url(uri));

if (style.source) {
let uri = "data:text/css;charset=utf-8,";
Expand Down
Loading

0 comments on commit 21edd11

Please sign in to comment.