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

Commit

Permalink
Merge pull request #826 from ZER0/panel-align/732294
Browse files Browse the repository at this point in the history
fix Bug 732294 - Panel constructor lacks a way to set position of panel other than "centered" r=@Gozala
  • Loading branch information
ZER0 committed Apr 16, 2013
2 parents 944219c + dbd07b3 commit a2e18bc
Show file tree
Hide file tree
Showing 11 changed files with 247 additions and 46 deletions.
84 changes: 83 additions & 1 deletion doc/module-source/sdk/panel.md
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,73 @@ Creates a panel.
The width of the panel in pixels. Optional.
@prop [height] {number}
The height of the panel in pixels. Optional.
@prop [focus] {boolean}
@prop [position] {object}
The position of the panel.
Ignored if the panel is opened by a widget.

You can set as value an object that has one or more of the following
properites: `top`, `right`, `bottom` and `left`. Their values are expressed
in pixels. Any other properties will be ignored.

The default alignment is centered, so for example panel can be displayed in
the center of the bottom corner by leaving off vertical axis:

// Show the panel to the centered horizontally and aligned to the bottom
// of the content area
require("sdk/panel").Panel({
position: {
bottom: 0
}
}).show();

// Show the panel to the centered vertically and aligned to the left o
// the content area
require("sdk/panel").Panel({
position: {
left: 0
}
}).show();

// Centered panel, default behavior
require("sdk/panel").Panel({}).show();

In the same way of their CSS counterpart, setting both `top` and `bottom`,
or `left` and `right`, will results in calculated the `height` and `width`:

// Show the panel centered horizontally, that is distant 40px
// from the top and 100px from the bottom.
require("sdk/panel").Panel({
position: {
top: 40,
bottom: 100
}
}).show();

Set implicitly `height` in this example, will makes the panel ignore the
`bottom` property, as the CSS homonym properties does:

// Show the panel centered horizontally, that is distant 40px from the top
// and has 400px as height
require("sdk/panel").Panel({
position: {
top: 40,
bottom: 100,
},
height: 400
}).show();

// This is equivalent to:

require("panel").Panel({
position {
top: 40
},
height: 400
}).show();

The same principle is applied for `width`, `left` and `right`.

@prop [focus=true] {boolean}
Set to `false` to prevent taking the focus away when the panel is shown.
Only turn this off if necessary, to prevent accessibility issue.
Optional, default to `true`.
Expand Down Expand Up @@ -575,6 +641,22 @@ The message to send. Must be stringifiable to JSON.
<api name="show">
@method
Displays the panel.

If the `options` argument is given, it will be shallow merged with the options
provided in the constructor: the `options` passed in the `show` method takes
the precedence.
It's useful for temporary changes, without touching the default values.

@param options {object}
Showing options for the panel, with the following keys:
@prop [width] {number}
The width of the panel in pixels. Optional.
@prop [height] {number}
The height of the panel in pixels. Optional.
@prop [position] {object}
The position of the panel. Optional. See [Panel's options](./modules/sdk/panel.html#Panel%28options%29) for further details.
@prop [focus=true] {boolean}
Set to `false` to prevent taking the focus away when the panel is shown.
</api>

<api name="hide">
Expand Down
20 changes: 14 additions & 6 deletions lib/sdk/deprecated/api-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ exports.validateOptions = function validateOptions(options, requirements) {
optsVal = req.map(optsVal);
}
catch (err) {
if (err instanceof RequirementError)
throw err;

mapThrew = true;
}
}
Expand All @@ -108,12 +111,12 @@ exports.validateOptions = function validateOptions(options, requirements) {
}
});
if (req.is.indexOf(getTypeOf(optsVal)) < 0)
throw requirementError(key, req);
throw new RequirementError(key, req);
}
if (req.ok && !req.ok(optsVal))
throw requirementError(key, req);
throw new RequirementError(key, req);

if (keyInOpts || (req.map && !mapThrew))
if (keyInOpts || (req.map && !mapThrew && optsVal !== undefined))
validatedOptions[key] = optsVal;
}

Expand Down Expand Up @@ -145,14 +148,19 @@ let getTypeOf = exports.getTypeOf = function getTypeOf(val) {
return typ;
}

// Returns a new Error with a nice message.
function requirementError(key, requirement) {
function RequirementError(key, requirement) {
Error.call(this);

this.name = "RequirementError";

let msg = requirement.msg;
if (!msg) {
msg = 'The option "' + key + '" ';
msg += requirement.is ?
"must be one of the following types: " + requirement.is.join(", ") :
"is invalid.";
}
return new Error(msg);

this.message = msg;
}
RequirementError.prototype = Object.create(Error.prototype);
15 changes: 15 additions & 0 deletions lib/sdk/lang/type.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,21 @@ function isNull(value) {
}
exports.isNull = isNull;

/**
* Returns `true` if value is `null` or `undefined`.
* It's equivalent to `== null`, but resolve the ambiguity of the writer
* intention, makes clear that he's clearly checking both `null` and `undefined`
* values, and it's not a typo for `=== null`.
*/
function isNil(value) {
return value === null || value === undefined;
}
exports.isNil = isNil;

function isBoolean(value) {
return typeof value === "boolean";
}
exports.isBoolean = isBoolean;
/**
* Returns `true` if value is a string.
* @examples
Expand Down
51 changes: 40 additions & 11 deletions lib/sdk/panel.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ const domPanel = require("./panel/utils");
const { events } = require("./panel/events");
const systemEvents = require("./system/events");
const { filter, pipe } = require("./event/utils");
const { getNodeView } = require("./view/core");
const { getNodeView, getActiveView } = require("./view/core");
const { isNil, isObject } = require("./lang/type");

if (isPrivateBrowsingSupported && isWindowPBSupported)
throw Error('The panel module cannot be used with per-window private browsing at the moment, see Bug 816257');
Expand Down Expand Up @@ -65,11 +66,26 @@ function getAttachEventType(model) {
let number = { is: ['number', 'undefined', 'null'] };
let boolean = { is: ['boolean', 'undefined', 'null'] };

let panelContract = contract(merge({
let rectContract = contract({
top: number,
right: number,
bottom: number,
left: number
});

let rect = {
is: ['object', 'undefined', 'null'],
map: function(v) isNil(v) || !isObject(v) ? v : rectContract(v)
}

let displayContract = contract({
width: number,
height: number,
focus: boolean,
}, loaderContract.rules));
position: rect
});

let panelContract = contract(merge({}, displayContract.rules, loaderContract.rules));


function isDisposed(panel) !views.has(panel);
Expand All @@ -80,12 +96,12 @@ let views = new WeakMap();
let workers = new WeakMap();

function viewFor(panel) views.get(panel)
exports.viewFor = viewFor;

function modelFor(panel) models.get(panel)
function panelFor(view) panels.get(view)
function workerFor(panel) workers.get(panel)

getActiveView.define(Panel, viewFor);

// Utility function takes `panel` instance and makes sure it will be
// automatically hidden as soon as other panel is shown.
let setupAutoHide = new function() {
Expand Down Expand Up @@ -124,9 +140,10 @@ const Panel = Class({
extends: WorkerHost(workerFor),
setup: function setup(options) {
let model = merge({
width: 320,
height: 240,
defaultWidth: 320,
defaultHeight: 240,
focus: true,
position: Object.freeze({}),
}, panelContract(options));
models.set(this, model);

Expand Down Expand Up @@ -172,6 +189,9 @@ const Panel = Class({
/* Public API: Panel.focus */
get focus() modelFor(this).focus,

/* Public API: Panel.position */
get position() modelFor(this).position,

get contentURL() modelFor(this).contentURL,
set contentURL(value) {
let model = modelFor(this);
Expand All @@ -183,13 +203,22 @@ const Panel = Class({
get isShowing() !isDisposed(this) && domPanel.isOpen(viewFor(this)),

/* Public API: Panel.show */
show: function show(anchor) {
show: function show(options, anchor) {
let model = modelFor(this);
let view = viewFor(this);
let anchorView = getNodeView(anchor);

options = merge({
position: model.position,
width: model.width,
height: model.height,
defaultWidth: model.defaultWidth,
defaultHeight: model.defaultHeight,
focus: model.focus
}, displayContract(options));

if (!isDisposed(this))
domPanel.show(view, model.width, model.height, model.focus, anchorView);
domPanel.show(view, options, anchorView);

return this;
},
Expand All @@ -207,8 +236,8 @@ const Panel = Class({
let model = modelFor(this);
let view = viewFor(this);
let change = panelContract({
width: width || model.width,
height: height || model.height
width: width || model.width || model.defaultWidth,
height: height || model.height || model.defaultHeight
});

model.width = change.width
Expand Down
Loading

0 comments on commit a2e18bc

Please sign in to comment.