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

Bug 837494 - re-implement contentStyle* using the new nsIDOMWindowUtils methods #839

Merged
merged 1 commit into from
Apr 10, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 105 additions & 0 deletions doc/module-source/sdk/content/mod.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->

The `mod` module provides functions to modify a page content.

<api name="attachTo">
@function
Function applies given `modification` to a given `window`.

For example, the following code applies a style to a content window, adding
a border to all divs in page:

var attachTo = require("sdk/content/mod").attachTo;
var Style = require("sdk/stylesheet/style").Style;

var style = Style({
source: "div { border: 4px solid gray }"
});

// assuming window points to the content page we want to modify
attachTo(style, window);

@param modification {object}
The modification we want to apply to the target.

@param window {nsIDOMWindow}
The window to be modified.
</api>

<api name="detachFrom">
@function
Function removes attached `modification` from a given `window`.
If `window` is not specified, `modification` is removed from all the windows
it's being attached to.

For example, the following code applies and removes a style to a content
window, adding a border to all divs in page:

var { attachTo, detachFrom } = require("sdk/content/mod");
var Style = require("sdk/stylesheet/style").Style;

var style = Style({
source: "div { border: 4px solid gray }"
});

// assuming window points to the content page we want to modify
attachTo(style, window);
// ...
detachFrom(style, window);

@param modification {object}
The modification we want to remove from the target

@param window {nsIDOMWindow}
The window to be modified.
If `window` is not provided `modification` is removed from all targets it's
being attached to.
</api>

<api name="getTargetWindow">
@function
Function takes `target`, value representing content (page) and returns
`nsIDOMWindow` for that content.
If `target` does not represents valid content `null` is returned.
For example target can be a content window itself in which case it's will be
returned back.

@param target {object}
The object for which we want to obtain the window represented or contained.
If a `nsIDOMWindow` is given, it works as an identify function, returns
`target` itself.
@returns {nsIDOMWindow|null}
The window represented or contained by the `target`, if any. Returns `null`
otherwise.
</api>

<api name="attach">
@function
Function applies given `modification` to a given `target` representing a
content to be modified.

@param modification {object}
The modification we want to apply to the target

@param target {object}
Target is a value that representing content to be modified. It is valid only
when `getTargetWindow(target)` returns nsIDOMWindow of content it represents.
</api>

<api name="detach">
@function
Function removes attached `modification`. If `target` is specified
`modification` is removed from that `target` only, otherwise `modification` is
removed from all the targets it's being attached to.

@param modification {object}
The modification we want to remove from the target

@param target {object}
Target is a value that representing content to be modified. It is valid only
when `getTargetWindow(target)` returns `nsIDOMWindow` of content it represents.
If `target` is not provided `modification` is removed from all targets it's
being attached to.
</api>
53 changes: 53 additions & 0 deletions doc/module-source/sdk/stylesheet/style.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->

Module provides `Style` function that can be used to construct content style
modification via stylesheet files or CSS rules.

<api name="Style">
@class
<api name="Style">
@constructor
The Style constructor creates an object that represents style modifications
via stylesheet file(s) or/and CSS rules. Stylesheet file URL(s) are verified
to be local to an add-on, while CSS rules are virified to be a string or
array of strings.

The style created can be applied to a content by calling `attach`,
and removed using `detach`. Those functions are part of [content/mod](modules/sdk/content/mod.html) module.
@param options {object}
Options for the style. All these options are optional. Although if you
don't supply any stylesheet or CSS rules, your style won't be very useful.

@prop uri {string,array}
A string, or an array of strings, that represents local URI to stylesheet.
@prop source {string,array}
A string, or an array of strings, that contains CSS rules. Those rules
are applied after the rules in the stylesheet specified with `uri` options,
if provided.
@prop [type="author"] {string}
The type of the sheet. It accepts the following values: `"agent"`, `"user"`
and `"author"`.
If not provided, the default value is `"author"`.
</api>

<api name="source">
@property {string}
An array of strings that contains the CSS rule(s) specified in the constructor's
option; `null` if no `source` option was given to the constructor.
This property is read-only.
</api>
<api name="uri">
@property {string}
An array of strings that contains the stylesheet local URI(s) specified in the
constructor's option; `null` if no `uri` option was given to the
constructor.
This property is read-only.
</api>
<api name="type">
@property {string}
The type of the sheet. If no type is provided in constructor's option,
it returns the default value, `"author"`. This property is read-only.
</api>
</api>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would also mention in docs that style can be applied to a content by calling attach(style, window) or removed using
detach(style, window) and would refer to content/mod docs for more details.

41 changes: 41 additions & 0 deletions doc/module-source/sdk/stylesheet/utils.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->

Module provides helper functions for working with stylesheets.

<api name="loadSheet">
@function
Synchronously loads a style sheet from `uri` and adds it to the list of
additional style sheets of the document.
The sheets added takes effect immediately, and only on the document of the
`window` given.
@param window {nsIDOMWindow}
@param uri {string, nsIURI}
@param [type="author"] {string}
The type of the sheet. It accepts the following values: `"agent"`, `"user"`
and `"author"`.
If not provided, the default value is `"author"`.
</api>

<api name="removeSheet">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't remember if it was me who suggested it in first place but I think it's better to have load/unload or add/remove Sheet

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was made to be consistent with the platform's name. I think they're actually good and they express exactly what they did. Why you think is no good with them?

@function
Remove the document style sheet at `sheetURI` from the list of additional
style sheets of the document. The removal takes effect immediately.
@param window {nsIDOMWindow}
@param uri {string, nsIURI}
@param [type="author"] {string}
The type of the sheet. It accepts the following values: `"agent"`, `"user"`
and `"author"`.
If not provided, the default value is `"author"`.
</api>

<api name="isTypeValid">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think isValidSheetType makes more sense this name is too generic specially because type is generic by it's own.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked with native language speaker (aka, @jsantell) about if noun should be before or after the the "valid" part, and he said that isTypeValid sounds more correct than isValidType (that was the original name).

About the too generic name: we have tons of generic name, but I always though that the module worked as context (see for instance add or once).
If you think isTypeValid is too generic, then what about the other generic name we have in the code base? Should we change them too?
If we should be more specific here, why we shouldn't more specific also in the other modules? What is the discriminant?

@function
Verifies that the `type` given is a valid stylesheet's type.
The values considered valid are: `"agent"`, `"user"` and `"author"`.
@param type {string}
The type of the sheet.
@returns {boolean}
`true` if the `type` given is valid, otherwise `false`.
</api>
60 changes: 60 additions & 0 deletions lib/sdk/content/mod.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";

module.metadata = {
"stability": "experimental"
};

const { Ci } = require("chrome");
const method = require("method/core");
const { add, remove, iterator } = require("../lang/weak-set");

let getTargetWindow = method("getTargetWindow");

getTargetWindow.define(function (target) {
if (target instanceof Ci.nsIDOMWindow)
return target;
if (target instanceof Ci.nsIDOMDocument)
return target.defaultView || null;

return null;
});

exports.getTargetWindow = getTargetWindow;

let attachTo = method("attachTo");
exports.attachTo = attachTo;

let detachFrom = method("detatchFrom");
exports.detachFrom = detachFrom;

function attach(modification, target) {
let window = getTargetWindow(target);

attachTo(modification, window);

// modification are stored per content; `window` reference can still be the
// same even if the content is changed, therefore `document` is used instead.
add(modification, window.document);
}
exports.attach = attach;

function detach(modification, target) {
if (target) {
let window = getTargetWindow(target);
detachFrom(modification, window);
remove(modification, window.document);
}
else {
let documents = iterator(modification);
for (let document of documents) {
detachFrom(modification, document.defaultView);
remove(modification, document);
}
}
}
exports.detach = detach;
56 changes: 56 additions & 0 deletions lib/sdk/lang/weak-set.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
"use strict";

const { Cu } = require("chrome");

function makeGetterFor(Type) {
let cache = new WeakMap();

return function getFor(target) {
if (!cache.has(target))
cache.set(target, new Type());

return cache.get(target);
}
}

let getLookupFor = makeGetterFor(WeakMap);
let getRefsFor = makeGetterFor(Set);

function add(target, value) {
if (has(target, value))
return;

getLookupFor(target).set(value, true);
getRefsFor(target).add(Cu.getWeakReference(value));
}
exports.add = add;

function remove(target, value) {
getLookupFor(target).delete(value);
}
exports.remove = remove;

function has(target, value) {
return getLookupFor(target).has(value);
}
exports.has = has;

function clear(target) {
getLookupFor(target).clear();
getRefsFor(target).clear();
}
exports.clear = clear;

function iterator(target) {
let refs = getRefsFor(target);

for (let ref of refs) {
let value = ref.get();

if (has(target, value))
yield value;
else
refs.delete(ref);
}
}
exports.iterator = iterator;
Loading