mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-09 16:57:36 +00:00
Merge m-c to s-c
This commit is contained in:
commit
492a680813
2
CLOBBER
2
CLOBBER
@ -17,4 +17,4 @@
|
|||||||
#
|
#
|
||||||
# Modifying this file will now automatically clobber the buildbot machines \o/
|
# Modifying this file will now automatically clobber the buildbot machines \o/
|
||||||
#
|
#
|
||||||
Bug 879831 needed to clobber for the removal of jsprobes.cpp
|
Bug 877859 Valgrind header location updates for FxOS Valgrind
|
||||||
|
@ -20,8 +20,6 @@ GARBAGE += $(MIDL_GENERATED_FILES)
|
|||||||
|
|
||||||
FORCE_SHARED_LIB = 1
|
FORCE_SHARED_LIB = 1
|
||||||
|
|
||||||
SRCS_IN_OBJDIR = 1
|
|
||||||
|
|
||||||
# Please keep this list in sync with the moz.build file until the rest of this
|
# Please keep this list in sync with the moz.build file until the rest of this
|
||||||
# Makefile is ported over.
|
# Makefile is ported over.
|
||||||
MIDL_INTERFACES = \
|
MIDL_INTERFACES = \
|
||||||
|
@ -18,8 +18,6 @@ GARBAGE += $(MIDL_GENERATED_FILES) done_gen dlldata.c
|
|||||||
|
|
||||||
FORCE_SHARED_LIB = 1
|
FORCE_SHARED_LIB = 1
|
||||||
|
|
||||||
SRCS_IN_OBJDIR = 1
|
|
||||||
|
|
||||||
CSRCS = \
|
CSRCS = \
|
||||||
dlldata.c \
|
dlldata.c \
|
||||||
ISimpleDOMNode_p.c \
|
ISimpleDOMNode_p.c \
|
||||||
|
@ -2112,6 +2112,14 @@ HyperTextAccessible::ScrollSubstringToPoint(int32_t aStartIndex,
|
|||||||
ENameValueFlag
|
ENameValueFlag
|
||||||
HyperTextAccessible::NativeName(nsString& aName)
|
HyperTextAccessible::NativeName(nsString& aName)
|
||||||
{
|
{
|
||||||
|
// Check @alt attribute for invalid img elements.
|
||||||
|
bool hasImgAlt = false;
|
||||||
|
if (mContent->IsHTML(nsGkAtoms::img)) {
|
||||||
|
hasImgAlt = mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::alt, aName);
|
||||||
|
if (!aName.IsEmpty())
|
||||||
|
return eNameOK;
|
||||||
|
}
|
||||||
|
|
||||||
ENameValueFlag nameFlag = AccessibleWrap::NativeName(aName);
|
ENameValueFlag nameFlag = AccessibleWrap::NativeName(aName);
|
||||||
if (!aName.IsEmpty())
|
if (!aName.IsEmpty())
|
||||||
return nameFlag;
|
return nameFlag;
|
||||||
@ -2123,7 +2131,7 @@ HyperTextAccessible::NativeName(nsString& aName)
|
|||||||
mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::title, aName))
|
mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::title, aName))
|
||||||
aName.CompressWhitespace();
|
aName.CompressWhitespace();
|
||||||
|
|
||||||
return eNameOK;
|
return hasImgAlt ? eNoNameOnPurpose : eNameOK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -468,6 +468,10 @@ var Output = {
|
|||||||
Utils.win.navigator.vibrate(aDetails.pattern);
|
Utils.win.navigator.vibrate(aDetails.pattern);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
Braille: function Braille(aDetails, aBrowser) {
|
||||||
|
Logger.debug('Braille output: ' + aDetails.text);
|
||||||
|
},
|
||||||
|
|
||||||
_adjustBounds: function(aJsonBounds, aBrowser) {
|
_adjustBounds: function(aJsonBounds, aBrowser) {
|
||||||
let bounds = new Rect(aJsonBounds.left, aJsonBounds.top,
|
let bounds = new Rect(aJsonBounds.left, aJsonBounds.top,
|
||||||
aJsonBounds.right - aJsonBounds.left,
|
aJsonBounds.right - aJsonBounds.left,
|
||||||
|
@ -16,11 +16,11 @@ ACCESSFU_FILES := \
|
|||||||
EventManager.jsm \
|
EventManager.jsm \
|
||||||
jar.mn \
|
jar.mn \
|
||||||
Makefile.in \
|
Makefile.in \
|
||||||
|
OutputGenerator.jsm \
|
||||||
Presentation.jsm \
|
Presentation.jsm \
|
||||||
TouchAdapter.jsm \
|
TouchAdapter.jsm \
|
||||||
TraversalRules.jsm \
|
TraversalRules.jsm \
|
||||||
Utils.jsm \
|
Utils.jsm \
|
||||||
UtteranceGenerator.jsm \
|
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
ACCESSFU_DEST = $(FINAL_TARGET)/modules/accessibility
|
ACCESSFU_DEST = $(FINAL_TARGET)/modules/accessibility
|
||||||
|
@ -14,9 +14,14 @@ const INCLUDE_NAME = 0x02;
|
|||||||
const INCLUDE_CUSTOM = 0x04;
|
const INCLUDE_CUSTOM = 0x04;
|
||||||
const NAME_FROM_SUBTREE_RULE = 0x08;
|
const NAME_FROM_SUBTREE_RULE = 0x08;
|
||||||
|
|
||||||
const UTTERANCE_DESC_FIRST = 0;
|
const OUTPUT_DESC_FIRST = 0;
|
||||||
|
const OUTPUT_DESC_LAST = 1;
|
||||||
|
|
||||||
Cu.import('resource://gre/modules/accessibility/Utils.jsm');
|
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||||
|
XPCOMUtils.defineLazyModuleGetter(this, 'Utils',
|
||||||
|
'resource://gre/modules/accessibility/Utils.jsm');
|
||||||
|
XPCOMUtils.defineLazyModuleGetter(this, 'PrefCache',
|
||||||
|
'resource://gre/modules/accessibility/Utils.jsm');
|
||||||
|
|
||||||
let gUtteranceOrder = new PrefCache('accessibility.accessfu.utterance');
|
let gUtteranceOrder = new PrefCache('accessibility.accessfu.utterance');
|
||||||
|
|
||||||
@ -24,44 +29,12 @@ var gStringBundle = Cc['@mozilla.org/intl/stringbundle;1'].
|
|||||||
getService(Ci.nsIStringBundleService).
|
getService(Ci.nsIStringBundleService).
|
||||||
createBundle('chrome://global/locale/AccessFu.properties');
|
createBundle('chrome://global/locale/AccessFu.properties');
|
||||||
|
|
||||||
this.EXPORTED_SYMBOLS = ['UtteranceGenerator'];
|
this.EXPORTED_SYMBOLS = ['UtteranceGenerator', 'BrailleGenerator'];
|
||||||
|
|
||||||
|
this.OutputGenerator = {
|
||||||
/**
|
|
||||||
* Generates speech utterances from objects, actions and state changes.
|
|
||||||
* An utterance is an array of strings.
|
|
||||||
*
|
|
||||||
* It should not be assumed that flattening an utterance array would create a
|
|
||||||
* gramatically correct sentence. For example, {@link genForObject} might
|
|
||||||
* return: ['graphic', 'Welcome to my home page'].
|
|
||||||
* Each string element in an utterance should be gramatically correct in itself.
|
|
||||||
* Another example from {@link genForObject}: ['list item 2 of 5', 'Alabama'].
|
|
||||||
*
|
|
||||||
* An utterance is ordered from the least to the most important. Speaking the
|
|
||||||
* last string usually makes sense, but speaking the first often won't.
|
|
||||||
* For example {@link genForAction} might return ['button', 'clicked'] for a
|
|
||||||
* clicked event. Speaking only 'clicked' makes sense. Speaking 'button' does
|
|
||||||
* not.
|
|
||||||
*/
|
|
||||||
this.UtteranceGenerator = {
|
|
||||||
gActionMap: {
|
|
||||||
jump: 'jumpAction',
|
|
||||||
press: 'pressAction',
|
|
||||||
check: 'checkAction',
|
|
||||||
uncheck: 'uncheckAction',
|
|
||||||
select: 'selectAction',
|
|
||||||
open: 'openAction',
|
|
||||||
close: 'closeAction',
|
|
||||||
switch: 'switchAction',
|
|
||||||
click: 'clickAction',
|
|
||||||
collapse: 'collapseAction',
|
|
||||||
expand: 'expandAction',
|
|
||||||
activate: 'activateAction',
|
|
||||||
cycle: 'cycleAction'
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates an utterance for a PivotContext.
|
* Generates output for a PivotContext.
|
||||||
* @param {PivotContext} aContext object that generates and caches
|
* @param {PivotContext} aContext object that generates and caches
|
||||||
* context information for a given accessible and its relationship with
|
* context information for a given accessible and its relationship with
|
||||||
* another accessible.
|
* another accessible.
|
||||||
@ -70,43 +43,44 @@ this.UtteranceGenerator = {
|
|||||||
* starting from the accessible's ancestry or accessible's subtree.
|
* starting from the accessible's ancestry or accessible's subtree.
|
||||||
*/
|
*/
|
||||||
genForContext: function genForContext(aContext) {
|
genForContext: function genForContext(aContext) {
|
||||||
let utterance = [];
|
let output = [];
|
||||||
let addUtterance = function addUtterance(aAccessible) {
|
let self = this;
|
||||||
utterance.push.apply(utterance,
|
let addOutput = function addOutput(aAccessible) {
|
||||||
UtteranceGenerator.genForObject(aAccessible));
|
output.push.apply(output, self.genForObject(aAccessible));
|
||||||
};
|
};
|
||||||
let ignoreSubtree = function ignoreSubtree(aAccessible) {
|
let ignoreSubtree = function ignoreSubtree(aAccessible) {
|
||||||
let roleString = Utils.AccRetrieval.getStringRole(aAccessible.role);
|
let roleString = Utils.AccRetrieval.getStringRole(aAccessible.role);
|
||||||
let nameRule = UtteranceGenerator.roleRuleMap[roleString] || 0;
|
let nameRule = self.roleRuleMap[roleString] || 0;
|
||||||
// Ignore subtree if the name is explicit and the role's name rule is the
|
// Ignore subtree if the name is explicit and the role's name rule is the
|
||||||
// NAME_FROM_SUBTREE_RULE.
|
// NAME_FROM_SUBTREE_RULE.
|
||||||
return (nameRule & NAME_FROM_SUBTREE_RULE) &&
|
return (nameRule & NAME_FROM_SUBTREE_RULE) &&
|
||||||
(Utils.getAttributes(aAccessible)['explicit-name'] === 'true');
|
(Utils.getAttributes(aAccessible)['explicit-name'] === 'true');
|
||||||
};
|
};
|
||||||
let utteranceOrder = gUtteranceOrder.value || UTTERANCE_DESC_FIRST;
|
let outputOrder = typeof gUtteranceOrder.value == 'number' ?
|
||||||
|
gUtteranceOrder.value : this.defaultOutputOrder;
|
||||||
|
let contextStart = this._getContextStart(aContext);
|
||||||
|
|
||||||
if (utteranceOrder === UTTERANCE_DESC_FIRST) {
|
if (outputOrder === OUTPUT_DESC_FIRST) {
|
||||||
aContext.newAncestry.forEach(addUtterance);
|
contextStart.forEach(addOutput);
|
||||||
addUtterance(aContext.accessible);
|
addOutput(aContext.accessible);
|
||||||
[addUtterance(node) for
|
[addOutput(node) for
|
||||||
(node of aContext.subtreeGenerator(true, ignoreSubtree))];
|
(node of aContext.subtreeGenerator(true, ignoreSubtree))];
|
||||||
} else {
|
} else {
|
||||||
[addUtterance(node) for
|
[addOutput(node) for
|
||||||
(node of aContext.subtreeGenerator(false, ignoreSubtree))];
|
(node of aContext.subtreeGenerator(false, ignoreSubtree))];
|
||||||
addUtterance(aContext.accessible);
|
addOutput(aContext.accessible);
|
||||||
aContext.newAncestry.reverse().forEach(addUtterance);
|
contextStart.reverse().forEach(addOutput);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean up the white space.
|
// Clean up the white space.
|
||||||
let trimmed;
|
let trimmed;
|
||||||
utterance = [trimmed for (word of utterance) if (trimmed = word.trim())];
|
output = [trimmed for (word of output) if (trimmed = word.trim())];
|
||||||
|
return output;
|
||||||
return utterance;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates an utterance for an object.
|
* Generates output for an object.
|
||||||
* @param {nsIAccessible} aAccessible accessible object to generate utterance
|
* @param {nsIAccessible} aAccessible accessible object to generate utterance
|
||||||
* for.
|
* for.
|
||||||
* @return {Array} Two string array. The first string describes the object
|
* @return {Array} Two string array. The first string describes the object
|
||||||
@ -116,9 +90,8 @@ this.UtteranceGenerator = {
|
|||||||
*/
|
*/
|
||||||
genForObject: function genForObject(aAccessible) {
|
genForObject: function genForObject(aAccessible) {
|
||||||
let roleString = Utils.AccRetrieval.getStringRole(aAccessible.role);
|
let roleString = Utils.AccRetrieval.getStringRole(aAccessible.role);
|
||||||
|
let func = this.objectOutputFunctions[roleString.replace(' ', '')] ||
|
||||||
let func = this.objectUtteranceFunctions[roleString] ||
|
this.objectOutputFunctions.defaultFunc;
|
||||||
this.objectUtteranceFunctions.defaultFunc;
|
|
||||||
|
|
||||||
let flags = this.roleRuleMap[roleString] || 0;
|
let flags = this.roleRuleMap[roleString] || 0;
|
||||||
|
|
||||||
@ -134,68 +107,61 @@ this.UtteranceGenerator = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates an utterance for an action performed.
|
* Generates output for an action performed.
|
||||||
* TODO: May become more verbose in the future.
|
|
||||||
* @param {nsIAccessible} aAccessible accessible object that the action was
|
* @param {nsIAccessible} aAccessible accessible object that the action was
|
||||||
* invoked in.
|
* invoked in.
|
||||||
* @param {string} aActionName the name of the action, one of the keys in
|
* @param {string} aActionName the name of the action, one of the keys in
|
||||||
* {@link gActionMap}.
|
* {@link gActionMap}.
|
||||||
* @return {Array} A one string array with the action.
|
* @return {Array} A one string array with the action.
|
||||||
*/
|
*/
|
||||||
genForAction: function genForAction(aObject, aActionName) {
|
genForAction: function genForAction(aObject, aActionName) {},
|
||||||
return [gStringBundle.GetStringFromName(this.gActionMap[aActionName])];
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates an utterance for an announcement. Basically attempts to localize
|
* Generates output for an announcement. Basically attempts to localize
|
||||||
* the announcement string.
|
* the announcement string.
|
||||||
* @param {string} aAnnouncement unlocalized announcement.
|
* @param {string} aAnnouncement unlocalized announcement.
|
||||||
* @return {Array} A one string array with the announcement.
|
* @return {Array} A one string array with the announcement.
|
||||||
*/
|
*/
|
||||||
genForAnnouncement: function genForAnnouncement(aAnnouncement) {
|
genForAnnouncement: function genForAnnouncement(aAnnouncement) {},
|
||||||
try {
|
|
||||||
return [gStringBundle.GetStringFromName(aAnnouncement)];
|
|
||||||
} catch (x) {
|
|
||||||
return [aAnnouncement];
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates an utterance for a tab state change.
|
* Generates output for a tab state change.
|
||||||
* @param {nsIAccessible} aAccessible accessible object of the tab's attached
|
* @param {nsIAccessible} aAccessible accessible object of the tab's attached
|
||||||
* document.
|
* document.
|
||||||
* @param {string} aTabState the tab state name, see
|
* @param {string} aTabState the tab state name, see
|
||||||
* {@link Presenter.tabStateChanged}.
|
* {@link Presenter.tabStateChanged}.
|
||||||
* @return {Array} The tab state utterace.
|
* @return {Array} The tab state utterace.
|
||||||
*/
|
*/
|
||||||
genForTabStateChange: function genForTabStateChange(aObject, aTabState) {
|
genForTabStateChange: function genForTabStateChange(aObject, aTabState) {},
|
||||||
switch (aTabState) {
|
|
||||||
case 'newtab':
|
|
||||||
return [gStringBundle.GetStringFromName('tabNew')];
|
|
||||||
case 'loading':
|
|
||||||
return [gStringBundle.GetStringFromName('tabLoading')];
|
|
||||||
case 'loaded':
|
|
||||||
return [aObject.name || '',
|
|
||||||
gStringBundle.GetStringFromName('tabLoaded')];
|
|
||||||
case 'loadstopped':
|
|
||||||
return [gStringBundle.GetStringFromName('tabLoadStopped')];
|
|
||||||
case 'reload':
|
|
||||||
return [gStringBundle.GetStringFromName('tabReload')];
|
|
||||||
default:
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates an utterance for announcing entering and leaving editing mode.
|
* Generates output for announcing entering and leaving editing mode.
|
||||||
* @param {aIsEditing} boolean true if we are in editing mode
|
* @param {aIsEditing} boolean true if we are in editing mode
|
||||||
* @return {Array} The mode utterance
|
* @return {Array} The mode utterance
|
||||||
*/
|
*/
|
||||||
genForEditingMode: function genForEditingMode(aIsEditing) {
|
genForEditingMode: function genForEditingMode(aIsEditing) {},
|
||||||
return [gStringBundle.GetStringFromName(
|
|
||||||
aIsEditing ? 'editingMode' : 'navigationMode')];
|
_getContextStart: function getContextStart(aContext) {},
|
||||||
|
|
||||||
|
_addName: function _addName(aOutput, aAccessible, aFlags) {
|
||||||
|
let name;
|
||||||
|
if (Utils.getAttributes(aAccessible)['explicit-name'] === 'true' ||
|
||||||
|
(aFlags & INCLUDE_NAME)) {
|
||||||
|
name = aAccessible.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name) {
|
||||||
|
let outputOrder = typeof gUtteranceOrder.value == 'number' ?
|
||||||
|
gUtteranceOrder.value : this.defaultOutputOrder;
|
||||||
|
aOutput[outputOrder === OUTPUT_DESC_FIRST ?
|
||||||
|
'push' : 'unshift'](name);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_getLocalizedRole: function _getLocalizedRole(aRoleStr) {},
|
||||||
|
|
||||||
|
_getLocalizedStates: function _getLocalizedStates(aStates) {},
|
||||||
|
|
||||||
roleRuleMap: {
|
roleRuleMap: {
|
||||||
'menubar': INCLUDE_DESC,
|
'menubar': INCLUDE_DESC,
|
||||||
'scrollbar': INCLUDE_DESC,
|
'scrollbar': INCLUDE_DESC,
|
||||||
@ -268,35 +234,119 @@ this.UtteranceGenerator = {
|
|||||||
'listbox': INCLUDE_DESC,
|
'listbox': INCLUDE_DESC,
|
||||||
'definitionlist': INCLUDE_DESC | INCLUDE_NAME},
|
'definitionlist': INCLUDE_DESC | INCLUDE_NAME},
|
||||||
|
|
||||||
objectUtteranceFunctions: {
|
objectOutputFunctions: {
|
||||||
defaultFunc: function defaultFunc(aAccessible, aRoleStr, aStates, aFlags) {
|
_generateBaseOutput: function _generateBaseOutput(aAccessible, aRoleStr, aStates, aFlags) {
|
||||||
let utterance = [];
|
let output = [];
|
||||||
|
|
||||||
if (aFlags & INCLUDE_DESC) {
|
if (aFlags & INCLUDE_DESC) {
|
||||||
let desc = this._getLocalizedStates(aStates);
|
let desc = this._getLocalizedStates(aStates);
|
||||||
let roleStr = this._getLocalizedRole(aRoleStr);
|
let roleStr = this._getLocalizedRole(aRoleStr);
|
||||||
if (roleStr)
|
if (roleStr)
|
||||||
desc.push(roleStr);
|
desc.push(roleStr);
|
||||||
utterance.push(desc.join(' '));
|
output.push(desc.join(' '));
|
||||||
}
|
}
|
||||||
|
|
||||||
this._addName(utterance, aAccessible, aFlags);
|
this._addName(output, aAccessible, aFlags);
|
||||||
|
|
||||||
return utterance;
|
return output;
|
||||||
},
|
},
|
||||||
|
|
||||||
entry: function entry(aAccessible, aRoleStr, aStates, aFlags) {
|
entry: function entry(aAccessible, aRoleStr, aStates, aFlags) {
|
||||||
let utterance = [];
|
let output = [];
|
||||||
let desc = this._getLocalizedStates(aStates);
|
let desc = this._getLocalizedStates(aStates);
|
||||||
desc.push(this._getLocalizedRole(
|
desc.push(this._getLocalizedRole(
|
||||||
(aStates.ext & Ci.nsIAccessibleStates.EXT_STATE_MULTI_LINE) ?
|
(aStates.ext & Ci.nsIAccessibleStates.EXT_STATE_MULTI_LINE) ?
|
||||||
'textarea' : 'entry'));
|
'textarea' : 'entry'));
|
||||||
|
|
||||||
utterance.push(desc.join(' '));
|
output.push(desc.join(' '));
|
||||||
|
|
||||||
this._addName(utterance, aAccessible, aFlags);
|
this._addName(output, aAccessible, aFlags);
|
||||||
|
|
||||||
return utterance;
|
return output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates speech utterances from objects, actions and state changes.
|
||||||
|
* An utterance is an array of strings.
|
||||||
|
*
|
||||||
|
* It should not be assumed that flattening an utterance array would create a
|
||||||
|
* gramatically correct sentence. For example, {@link genForObject} might
|
||||||
|
* return: ['graphic', 'Welcome to my home page'].
|
||||||
|
* Each string element in an utterance should be gramatically correct in itself.
|
||||||
|
* Another example from {@link genForObject}: ['list item 2 of 5', 'Alabama'].
|
||||||
|
*
|
||||||
|
* An utterance is ordered from the least to the most important. Speaking the
|
||||||
|
* last string usually makes sense, but speaking the first often won't.
|
||||||
|
* For example {@link genForAction} might return ['button', 'clicked'] for a
|
||||||
|
* clicked event. Speaking only 'clicked' makes sense. Speaking 'button' does
|
||||||
|
* not.
|
||||||
|
*/
|
||||||
|
this.UtteranceGenerator = {
|
||||||
|
__proto__: OutputGenerator,
|
||||||
|
|
||||||
|
defaultOutputOrder: OUTPUT_DESC_FIRST,
|
||||||
|
|
||||||
|
gActionMap: {
|
||||||
|
jump: 'jumpAction',
|
||||||
|
press: 'pressAction',
|
||||||
|
check: 'checkAction',
|
||||||
|
uncheck: 'uncheckAction',
|
||||||
|
select: 'selectAction',
|
||||||
|
open: 'openAction',
|
||||||
|
close: 'closeAction',
|
||||||
|
switch: 'switchAction',
|
||||||
|
click: 'clickAction',
|
||||||
|
collapse: 'collapseAction',
|
||||||
|
expand: 'expandAction',
|
||||||
|
activate: 'activateAction',
|
||||||
|
cycle: 'cycleAction'
|
||||||
|
},
|
||||||
|
|
||||||
|
//TODO: May become more verbose in the future.
|
||||||
|
genForAction: function genForAction(aObject, aActionName) {
|
||||||
|
return [gStringBundle.GetStringFromName(this.gActionMap[aActionName])];
|
||||||
|
},
|
||||||
|
|
||||||
|
genForAnnouncement: function genForAnnouncement(aAnnouncement) {
|
||||||
|
try {
|
||||||
|
return [gStringBundle.GetStringFromName(aAnnouncement)];
|
||||||
|
} catch (x) {
|
||||||
|
return [aAnnouncement];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
genForTabStateChange: function genForTabStateChange(aObject, aTabState) {
|
||||||
|
switch (aTabState) {
|
||||||
|
case 'newtab':
|
||||||
|
return [gStringBundle.GetStringFromName('tabNew')];
|
||||||
|
case 'loading':
|
||||||
|
return [gStringBundle.GetStringFromName('tabLoading')];
|
||||||
|
case 'loaded':
|
||||||
|
return [aObject.name || '',
|
||||||
|
gStringBundle.GetStringFromName('tabLoaded')];
|
||||||
|
case 'loadstopped':
|
||||||
|
return [gStringBundle.GetStringFromName('tabLoadStopped')];
|
||||||
|
case 'reload':
|
||||||
|
return [gStringBundle.GetStringFromName('tabReload')];
|
||||||
|
default:
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
genForEditingMode: function genForEditingMode(aIsEditing) {
|
||||||
|
return [gStringBundle.GetStringFromName(
|
||||||
|
aIsEditing ? 'editingMode' : 'navigationMode')];
|
||||||
|
},
|
||||||
|
|
||||||
|
objectOutputFunctions: {
|
||||||
|
defaultFunc: function defaultFunc(aAccessible, aRoleStr, aStates, aFlags) {
|
||||||
|
return OutputGenerator.objectOutputFunctions._generateBaseOutput.apply(this, arguments);
|
||||||
|
},
|
||||||
|
|
||||||
|
entry: function entry(aAccessible, aRoleStr, aStates, aFlags) {
|
||||||
|
return OutputGenerator.objectOutputFunctions.entry.apply(this, arguments);
|
||||||
},
|
},
|
||||||
|
|
||||||
heading: function heading(aAccessible, aRoleStr, aStates, aFlags) {
|
heading: function heading(aAccessible, aRoleStr, aStates, aFlags) {
|
||||||
@ -338,25 +388,15 @@ this.UtteranceGenerator = {
|
|||||||
application: function application(aAccessible, aRoleStr, aStates, aFlags) {
|
application: function application(aAccessible, aRoleStr, aStates, aFlags) {
|
||||||
// Don't utter location of applications, it gets tiring.
|
// Don't utter location of applications, it gets tiring.
|
||||||
if (aAccessible.name != aAccessible.DOMNode.location)
|
if (aAccessible.name != aAccessible.DOMNode.location)
|
||||||
return this.objectUtteranceFunctions.defaultFunc.apply(this,
|
return this.objectOutputFunctions.defaultFunc.apply(this,
|
||||||
[aAccessible, aRoleStr, aStates, aFlags]);
|
[aAccessible, aRoleStr, aStates, aFlags]);
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_addName: function _addName(utterance, aAccessible, aFlags) {
|
_getContextStart: function _getContextStart(aContext) {
|
||||||
let name;
|
return aContext.newAncestry;
|
||||||
if (Utils.getAttributes(aAccessible)['explicit-name'] === 'true' ||
|
|
||||||
(aFlags & INCLUDE_NAME)) {
|
|
||||||
name = aAccessible.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name) {
|
|
||||||
let utteranceOrder = gUtteranceOrder.value || UTTERANCE_DESC_FIRST;
|
|
||||||
utterance[utteranceOrder === UTTERANCE_DESC_FIRST ?
|
|
||||||
'push' : 'unshift'](name);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_getLocalizedRole: function _getLocalizedRole(aRoleStr) {
|
_getLocalizedRole: function _getLocalizedRole(aRoleStr) {
|
||||||
@ -419,3 +459,118 @@ this.UtteranceGenerator = {
|
|||||||
return utterance;
|
return utterance;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
this.BrailleGenerator = {
|
||||||
|
__proto__: OutputGenerator,
|
||||||
|
|
||||||
|
defaultOutputOrder: OUTPUT_DESC_LAST,
|
||||||
|
|
||||||
|
objectOutputFunctions: {
|
||||||
|
defaultFunc: function defaultFunc(aAccessible, aRoleStr, aStates, aFlags) {
|
||||||
|
let braille = OutputGenerator.objectOutputFunctions._generateBaseOutput.apply(this, arguments);
|
||||||
|
|
||||||
|
if (aAccessible.indexInParent === 1 &&
|
||||||
|
aAccessible.parent.role == Ci.nsIAccessibleRole.ROLE_LISTITEM &&
|
||||||
|
aAccessible.previousSibling.role == Ci.nsIAccessibleRole.ROLE_STATICTEXT) {
|
||||||
|
if (aAccessible.parent.parent && aAccessible.parent.parent.DOMNode &&
|
||||||
|
aAccessible.parent.parent.DOMNode.nodeName == 'UL') {
|
||||||
|
braille.unshift('*');
|
||||||
|
} else {
|
||||||
|
braille.unshift(aAccessible.previousSibling.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return braille;
|
||||||
|
},
|
||||||
|
|
||||||
|
listitem: function listitem(aAccessible, aRoleStr, aStates, aFlags) {
|
||||||
|
let braille = [];
|
||||||
|
|
||||||
|
this._addName(braille, aAccessible, aFlags);
|
||||||
|
|
||||||
|
return braille;
|
||||||
|
},
|
||||||
|
|
||||||
|
statictext: function statictext(aAccessible, aRoleStr, aStates, aFlags) {
|
||||||
|
// Since we customize the list bullet's output, we add the static
|
||||||
|
// text from the first node in each listitem, so skip it here.
|
||||||
|
if (aAccessible.parent.role == Ci.nsIAccessibleRole.ROLE_LISTITEM) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.objectOutputFunctions._useStateNotRole.apply(this, arguments);
|
||||||
|
},
|
||||||
|
|
||||||
|
_useStateNotRole: function _useStateNotRole(aAccessible, aRoleStr, aStates, aFlags) {
|
||||||
|
let braille = [];
|
||||||
|
|
||||||
|
let desc = this._getLocalizedStates(aStates);
|
||||||
|
braille.push(desc.join(' '));
|
||||||
|
|
||||||
|
this._addName(braille, aAccessible, aFlags);
|
||||||
|
|
||||||
|
return braille;
|
||||||
|
},
|
||||||
|
|
||||||
|
checkbutton: function checkbutton(aAccessible, aRoleStr, aStates, aFlags) {
|
||||||
|
return this.objectOutputFunctions._useStateNotRole.apply(this, arguments);
|
||||||
|
},
|
||||||
|
|
||||||
|
radiobutton: function radiobutton(aAccessible, aRoleStr, aStates, aFlags) {
|
||||||
|
return this.objectOutputFunctions._useStateNotRole.apply(this, arguments);
|
||||||
|
},
|
||||||
|
|
||||||
|
togglebutton: function radiobutton(aAccessible, aRoleStr, aStates, aFlags) {
|
||||||
|
return this.objectOutputFunctions._useStateNotRole.apply(this, arguments);
|
||||||
|
},
|
||||||
|
|
||||||
|
entry: function entry(aAccessible, aRoleStr, aStates, aFlags) {
|
||||||
|
return OutputGenerator.objectOutputFunctions.entry.apply(this, arguments);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_getContextStart: function _getContextStart(aContext) {
|
||||||
|
if (aContext.accessible.parent.role == Ci.nsIAccessibleRole.ROLE_LINK) {
|
||||||
|
return [aContext.accessible.parent];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
},
|
||||||
|
|
||||||
|
_getLocalizedRole: function _getLocalizedRole(aRoleStr) {
|
||||||
|
try {
|
||||||
|
return gStringBundle.GetStringFromName(aRoleStr.replace(' ', '') + 'Abbr');
|
||||||
|
} catch (x) {
|
||||||
|
try {
|
||||||
|
return gStringBundle.GetStringFromName(aRoleStr.replace(' ', ''));
|
||||||
|
} catch (y) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_getLocalizedStates: function _getLocalizedStates(aStates) {
|
||||||
|
let stateBraille = [];
|
||||||
|
|
||||||
|
let getCheckedState = function getCheckedState() {
|
||||||
|
let resultMarker = [];
|
||||||
|
let state = aStates.base;
|
||||||
|
let fill = !!(state & Ci.nsIAccessibleStates.STATE_CHECKED) ||
|
||||||
|
!!(state & Ci.nsIAccessibleStates.STATE_PRESSED);
|
||||||
|
|
||||||
|
resultMarker.push('(');
|
||||||
|
resultMarker.push(fill ? 'x' : ' ');
|
||||||
|
resultMarker.push(')');
|
||||||
|
|
||||||
|
return resultMarker.join('');
|
||||||
|
};
|
||||||
|
|
||||||
|
if (aStates.base & Ci.nsIAccessibleStates.STATE_CHECKABLE) {
|
||||||
|
stateBraille.push(getCheckedState());
|
||||||
|
}
|
||||||
|
|
||||||
|
return stateBraille;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
@ -9,8 +9,17 @@ const Ci = Components.interfaces;
|
|||||||
const Cu = Components.utils;
|
const Cu = Components.utils;
|
||||||
const Cr = Components.results;
|
const Cr = Components.results;
|
||||||
|
|
||||||
Cu.import('resource://gre/modules/accessibility/Utils.jsm');
|
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||||
Cu.import('resource://gre/modules/accessibility/UtteranceGenerator.jsm');
|
XPCOMUtils.defineLazyModuleGetter(this, 'Utils',
|
||||||
|
'resource://gre/modules/accessibility/Utils.jsm');
|
||||||
|
XPCOMUtils.defineLazyModuleGetter(this, 'Logger',
|
||||||
|
'resource://gre/modules/accessibility/Utils.jsm');
|
||||||
|
XPCOMUtils.defineLazyModuleGetter(this, 'PivotContext',
|
||||||
|
'resource://gre/modules/accessibility/Utils.jsm');
|
||||||
|
XPCOMUtils.defineLazyModuleGetter(this, 'UtteranceGenerator',
|
||||||
|
'resource://gre/modules/accessibility/OutputGenerator.jsm');
|
||||||
|
XPCOMUtils.defineLazyModuleGetter(this, 'BrailleGenerator',
|
||||||
|
'resource://gre/modules/accessibility/OutputGenerator.jsm');
|
||||||
|
|
||||||
this.EXPORTED_SYMBOLS = ['Presentation'];
|
this.EXPORTED_SYMBOLS = ['Presentation'];
|
||||||
|
|
||||||
@ -219,6 +228,15 @@ AndroidPresenter.prototype = {
|
|||||||
|
|
||||||
let state = Utils.getStates(aContext.accessible)[0];
|
let state = Utils.getStates(aContext.accessible)[0];
|
||||||
|
|
||||||
|
let brailleText = '';
|
||||||
|
if (Utils.AndroidSdkVersion >= 16) {
|
||||||
|
if (!this._braillePresenter) {
|
||||||
|
this._braillePresenter = new BraillePresenter();
|
||||||
|
}
|
||||||
|
brailleText = this._braillePresenter.pivotChanged(aContext, aReason).
|
||||||
|
details.text;
|
||||||
|
}
|
||||||
|
|
||||||
androidEvents.push({eventType: (isExploreByTouch) ?
|
androidEvents.push({eventType: (isExploreByTouch) ?
|
||||||
this.ANDROID_VIEW_HOVER_ENTER : focusEventType,
|
this.ANDROID_VIEW_HOVER_ENTER : focusEventType,
|
||||||
text: UtteranceGenerator.genForContext(aContext),
|
text: UtteranceGenerator.genForContext(aContext),
|
||||||
@ -227,7 +245,8 @@ AndroidPresenter.prototype = {
|
|||||||
checkable: !!(state &
|
checkable: !!(state &
|
||||||
Ci.nsIAccessibleStates.STATE_CHECKABLE),
|
Ci.nsIAccessibleStates.STATE_CHECKABLE),
|
||||||
checked: !!(state &
|
checked: !!(state &
|
||||||
Ci.nsIAccessibleStates.STATE_CHECKED)});
|
Ci.nsIAccessibleStates.STATE_CHECKED),
|
||||||
|
brailleText: brailleText});
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -367,6 +386,29 @@ HapticPresenter.prototype = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A braille presenter
|
||||||
|
*/
|
||||||
|
|
||||||
|
this.BraillePresenter = function BraillePresenter() {};
|
||||||
|
|
||||||
|
BraillePresenter.prototype = {
|
||||||
|
__proto__: Presenter.prototype,
|
||||||
|
|
||||||
|
type: 'Braille',
|
||||||
|
|
||||||
|
pivotChanged: function BraillePresenter_pivotChanged(aContext, aReason) {
|
||||||
|
if (!aContext.accessible) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
let text = BrailleGenerator.genForContext(aContext);
|
||||||
|
|
||||||
|
return { type: this.type, details: {text: text.join(' ')} };
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
this.Presentation = {
|
this.Presentation = {
|
||||||
get presenters() {
|
get presenters() {
|
||||||
delete this.presenters;
|
delete this.presenters;
|
||||||
|
@ -14,6 +14,8 @@ this.EXPORTED_SYMBOLS = ['TraversalRules'];
|
|||||||
Cu.import('resource://gre/modules/accessibility/Utils.jsm');
|
Cu.import('resource://gre/modules/accessibility/Utils.jsm');
|
||||||
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||||
|
|
||||||
|
let gSkipEmptyImages = new PrefCache('accessibility.accessfu.skip_empty_images');
|
||||||
|
|
||||||
function BaseTraversalRule(aRoles, aMatchFunc) {
|
function BaseTraversalRule(aRoles, aMatchFunc) {
|
||||||
this._matchRoles = aRoles;
|
this._matchRoles = aRoles;
|
||||||
this._matchFunc = aMatchFunc;
|
this._matchFunc = aMatchFunc;
|
||||||
@ -103,6 +105,8 @@ this.TraversalRules = {
|
|||||||
|
|
||||||
return Ci.nsIAccessibleTraversalRule.FILTER_MATCH;
|
return Ci.nsIAccessibleTraversalRule.FILTER_MATCH;
|
||||||
}
|
}
|
||||||
|
case Ci.nsIAccessibleRole.ROLE_GRAPHIC:
|
||||||
|
return TraversalRules._shouldSkipImage(aAccessible);
|
||||||
default:
|
default:
|
||||||
// Ignore the subtree, if there is one. So that we don't land on
|
// Ignore the subtree, if there is one. So that we don't land on
|
||||||
// the same content that was already presented by its parent.
|
// the same content that was already presented by its parent.
|
||||||
@ -168,7 +172,10 @@ this.TraversalRules = {
|
|||||||
Ci.nsIAccessibleRole.ROLE_CHECK_MENU_ITEM]),
|
Ci.nsIAccessibleRole.ROLE_CHECK_MENU_ITEM]),
|
||||||
|
|
||||||
Graphic: new BaseTraversalRule(
|
Graphic: new BaseTraversalRule(
|
||||||
[Ci.nsIAccessibleRole.ROLE_GRAPHIC]),
|
[Ci.nsIAccessibleRole.ROLE_GRAPHIC],
|
||||||
|
function Graphic_match(aAccessible) {
|
||||||
|
return TraversalRules._shouldSkipImage(aAccessible);
|
||||||
|
}),
|
||||||
|
|
||||||
Heading: new BaseTraversalRule(
|
Heading: new BaseTraversalRule(
|
||||||
[Ci.nsIAccessibleRole.ROLE_HEADING]),
|
[Ci.nsIAccessibleRole.ROLE_HEADING]),
|
||||||
@ -211,5 +218,12 @@ this.TraversalRules = {
|
|||||||
|
|
||||||
Checkbox: new BaseTraversalRule(
|
Checkbox: new BaseTraversalRule(
|
||||||
[Ci.nsIAccessibleRole.ROLE_CHECKBUTTON,
|
[Ci.nsIAccessibleRole.ROLE_CHECKBUTTON,
|
||||||
Ci.nsIAccessibleRole.ROLE_CHECK_MENU_ITEM])
|
Ci.nsIAccessibleRole.ROLE_CHECK_MENU_ITEM]),
|
||||||
|
|
||||||
|
_shouldSkipImage: function _shouldSkipImage(aAccessible) {
|
||||||
|
if (gSkipEmptyImages.value && aAccessible.name === '') {
|
||||||
|
return Ci.nsIAccessibleTraversalRule.FILTER_IGNORE;
|
||||||
|
}
|
||||||
|
return Ci.nsIAccessibleTraversalRule.FILTER_MATCH;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
@ -16,6 +16,8 @@ XPCOMUtils.defineLazyModuleGetter(this, 'Utils',
|
|||||||
'resource://gre/modules/accessibility/Utils.jsm');
|
'resource://gre/modules/accessibility/Utils.jsm');
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, 'EventManager',
|
XPCOMUtils.defineLazyModuleGetter(this, 'EventManager',
|
||||||
'resource://gre/modules/accessibility/EventManager.jsm');
|
'resource://gre/modules/accessibility/EventManager.jsm');
|
||||||
|
XPCOMUtils.defineLazyModuleGetter(this, 'ObjectWrapper',
|
||||||
|
'resource://gre/modules/ObjectWrapper.jsm');
|
||||||
|
|
||||||
Logger.debug('content-script.js');
|
Logger.debug('content-script.js');
|
||||||
|
|
||||||
@ -182,6 +184,21 @@ function scroll(aMessage) {
|
|||||||
while (acc) {
|
while (acc) {
|
||||||
let elem = acc.DOMNode;
|
let elem = acc.DOMNode;
|
||||||
|
|
||||||
|
// This is inspired by IndieUI events. Once they are
|
||||||
|
// implemented, it should be easy to transition to them.
|
||||||
|
// https://dvcs.w3.org/hg/IndieUI/raw-file/tip/src/indie-ui-events.html#scrollrequest
|
||||||
|
let uiactions = elem.getAttribute ? elem.getAttribute('uiactions') : '';
|
||||||
|
if (uiactions && uiactions.split(' ').indexOf('scroll') >= 0) {
|
||||||
|
let evt = elem.ownerDocument.createEvent('CustomEvent');
|
||||||
|
let details = horiz ? { deltaX: page * elem.clientWidth } :
|
||||||
|
{ deltaY: page * elem.clientHeight };
|
||||||
|
evt.initCustomEvent(
|
||||||
|
'scrollrequest', true, true,
|
||||||
|
ObjectWrapper.wrap(details, elem.ownerDocument.defaultView));
|
||||||
|
if (!elem.dispatchEvent(evt))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// We will do window scrolling next.
|
// We will do window scrolling next.
|
||||||
if (elem == content.document)
|
if (elem == content.document)
|
||||||
break;
|
break;
|
||||||
@ -202,25 +219,6 @@ function scroll(aMessage) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let controllers = acc.
|
|
||||||
getRelationByType(
|
|
||||||
Ci.nsIAccessibleRelation.RELATION_CONTROLLED_BY);
|
|
||||||
for (let i = 0; controllers.targetsCount > i; i++) {
|
|
||||||
let controller = controllers.getTarget(i);
|
|
||||||
// If the section has a controlling slider, it should be considered
|
|
||||||
// the page-turner.
|
|
||||||
if (controller.role == Ci.nsIAccessibleRole.ROLE_SLIDER) {
|
|
||||||
// Sliders are controlled with ctrl+right/left. I just decided :)
|
|
||||||
let evt = content.document.createEvent('KeyboardEvent');
|
|
||||||
evt.initKeyEvent(
|
|
||||||
'keypress', true, true, null,
|
|
||||||
true, false, false, false,
|
|
||||||
(page > 0) ? evt.DOM_VK_RIGHT : evt.DOM_VK_LEFT, 0);
|
|
||||||
controller.DOMNode.dispatchEvent(evt);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
acc = acc.parent;
|
acc = acc.parent;
|
||||||
}
|
}
|
||||||
|
@ -13,10 +13,11 @@ include $(DEPTH)/config/autoconf.mk
|
|||||||
|
|
||||||
MOCHITEST_A11Y_FILES =\
|
MOCHITEST_A11Y_FILES =\
|
||||||
jsatcommon.js \
|
jsatcommon.js \
|
||||||
utterance.js \
|
output.js \
|
||||||
test_alive.html \
|
test_alive.html \
|
||||||
test_explicit_names.html \
|
test_explicit_names.html \
|
||||||
test_utterance_order.html \
|
test_utterance_order.html \
|
||||||
|
test_braille.html \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
include $(topsrcdir)/config/rules.mk
|
include $(topsrcdir)/config/rules.mk
|
||||||
|
80
accessible/tests/mochitest/jsat/output.js
Normal file
80
accessible/tests/mochitest/jsat/output.js
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
const Cu = Components.utils;
|
||||||
|
const PREF_UTTERANCE_ORDER = "accessibility.accessfu.utterance";
|
||||||
|
|
||||||
|
Cu.import('resource://gre/modules/accessibility/Utils.jsm');
|
||||||
|
Cu.import("resource://gre/modules/accessibility/OutputGenerator.jsm", this);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test context output generation.
|
||||||
|
*
|
||||||
|
* @param expected {Array} expected output.
|
||||||
|
* @param aAccOrElmOrID identifier to get an accessible to test.
|
||||||
|
* @param aOldAccOrElmOrID optional identifier to get an accessible relative to
|
||||||
|
* the |aAccOrElmOrID|.
|
||||||
|
* @param aGenerator the output generator to use when generating accessible
|
||||||
|
* output
|
||||||
|
*
|
||||||
|
* Note: if |aOldAccOrElmOrID| is not provided, the |aAccOrElmOrID| must be
|
||||||
|
* scoped to the "root" element in markup.
|
||||||
|
*/
|
||||||
|
function testContextOutput(expected, aAccOrElmOrID, aOldAccOrElmOrID, aGenerator) {
|
||||||
|
aOldAccOrElmOrID = aOldAccOrElmOrID || "root";
|
||||||
|
var accessible = getAccessible(aAccOrElmOrID);
|
||||||
|
var oldAccessible = getAccessible(aOldAccOrElmOrID);
|
||||||
|
var context = new PivotContext(accessible, oldAccessible);
|
||||||
|
var output = aGenerator.genForContext(context);
|
||||||
|
isDeeply(output, expected,
|
||||||
|
"Context output is correct for " + aAccOrElmOrID);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test object output generated array that includes names.
|
||||||
|
* Note: test ignores outputs without the name.
|
||||||
|
*
|
||||||
|
* @param aAccOrElmOrID identifier to get an accessible to test.
|
||||||
|
* @param aGenerator the output generator to use when generating accessible
|
||||||
|
* output
|
||||||
|
*/
|
||||||
|
function testObjectOutput(aAccOrElmOrID, aGenerator) {
|
||||||
|
var accessible = getAccessible(aAccOrElmOrID);
|
||||||
|
var output = aGenerator.genForObject(accessible);
|
||||||
|
var outputOrder;
|
||||||
|
try {
|
||||||
|
outputOrder = SpecialPowers.getIntPref(PREF_UTTERANCE_ORDER);
|
||||||
|
} catch (ex) {
|
||||||
|
// PREF_UTTERANCE_ORDER not set.
|
||||||
|
outputOrder = 0;
|
||||||
|
}
|
||||||
|
var expectedNameIndex = outputOrder === 0 ? output.length - 1 : 0;
|
||||||
|
var nameIndex = output.indexOf(accessible.name);
|
||||||
|
|
||||||
|
if (nameIndex > -1) {
|
||||||
|
ok(output.indexOf(accessible.name) === expectedNameIndex,
|
||||||
|
"Object output is correct for " + aAccOrElmOrID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test object and context output for an accessible.
|
||||||
|
*
|
||||||
|
* @param expected {Array} expected output.
|
||||||
|
* @param aAccOrElmOrID identifier to get an accessible to test.
|
||||||
|
* @param aOldAccOrElmOrID optional identifier to get an accessible relative to
|
||||||
|
* the |aAccOrElmOrID|.
|
||||||
|
* @param aOutputKind the type of output
|
||||||
|
*/
|
||||||
|
function testOutput(expected, aAccOrElmOrID, aOldAccOrElmOrID, aOutputKind) {
|
||||||
|
var generator;
|
||||||
|
if (aOutputKind === 1) {
|
||||||
|
generator = UtteranceGenerator;
|
||||||
|
} else {
|
||||||
|
generator = BrailleGenerator;
|
||||||
|
}
|
||||||
|
testContextOutput(expected, aAccOrElmOrID, aOldAccOrElmOrID, generator);
|
||||||
|
// Just need to test object output for individual
|
||||||
|
// accOrElmOrID.
|
||||||
|
if (aOldAccOrElmOrID) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
testObjectOutput(aAccOrElmOrID, generator);
|
||||||
|
}
|
114
accessible/tests/mochitest/jsat/test_braille.html
Normal file
114
accessible/tests/mochitest/jsat/test_braille.html
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<!--
|
||||||
|
https://bugzilla.mozilla.org/show_bug.cgi?id=876475
|
||||||
|
-->
|
||||||
|
<head>
|
||||||
|
<title>[AccessFu] braille generation test</title>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<link rel="stylesheet" type="text/css"
|
||||||
|
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
|
||||||
|
<script type="application/javascript"
|
||||||
|
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
<script type="application/javascript"
|
||||||
|
src="../common.js"></script>
|
||||||
|
<script type="application/javascript"
|
||||||
|
src="./output.js"></script>
|
||||||
|
<script type="application/javascript">
|
||||||
|
|
||||||
|
function doTest() {
|
||||||
|
// Test the following accOrElmOrID (with optional old accOrElmOrID).
|
||||||
|
// Note: each accOrElmOrID entry maps to a unique object braille
|
||||||
|
// generator function within the BrailleGenerator.
|
||||||
|
var tests = [{
|
||||||
|
accOrElmOrID: "link",
|
||||||
|
expected: [["lnk", "Link"], ["Link", "lnk"]]
|
||||||
|
},{
|
||||||
|
accOrElmOrID: "button",
|
||||||
|
expected: [["btn", "I am a button"], ["I am a button", "btn"]]
|
||||||
|
},{
|
||||||
|
accOrElmOrID: "password_input",
|
||||||
|
expected: [["passwdtxt", "Secret Password"], ["Secret Password", "passwdtxt"]]
|
||||||
|
},{
|
||||||
|
accOrElmOrID: "checkbox_unchecked",
|
||||||
|
expected: [["( )", "checkboxtext"], ["checkboxtext", "( )"]]
|
||||||
|
},{
|
||||||
|
accOrElmOrID: "checkbox_checked",
|
||||||
|
expected: [["(x)", "some more checkbox text"], ["some more checkbox text", "(x)"]]
|
||||||
|
},{
|
||||||
|
accOrElmOrID: "radio_unselected",
|
||||||
|
expected: [["( )", "any old radio button"], ["any old radio button", "( )"]]
|
||||||
|
},{
|
||||||
|
accOrElmOrID: "radio_selected",
|
||||||
|
expected: [["(x)", "a unique radio button"], ["a unique radio button", "(x)"]]
|
||||||
|
},{
|
||||||
|
accOrElmOrID: "togglebutton_notpressed",
|
||||||
|
expected: [["( )", "I ain't pressed"], ["I ain't pressed", "( )"]]
|
||||||
|
},{
|
||||||
|
accOrElmOrID: "togglebutton_pressed",
|
||||||
|
expected: [["(x)", "I am pressed!"], ["I am pressed!", "(x)"]]
|
||||||
|
},{
|
||||||
|
accOrElmOrID: "ul_li_one",
|
||||||
|
expected: [["*", "ul item 1"], ["*", "ul item 1"]]
|
||||||
|
},{
|
||||||
|
accOrElmOrID: "ol_li_one",
|
||||||
|
expected: [["1.", "ol item 1"], ["1.", "ol item 1"]]
|
||||||
|
},{
|
||||||
|
accOrElmOrID: "textarea",
|
||||||
|
expected: [["txtarea", "Here lies treasure."], ["Here lies treasure.", "txtarea"]]
|
||||||
|
}];
|
||||||
|
|
||||||
|
// Test all possible braille order preference values.
|
||||||
|
tests.forEach(function run(test) {
|
||||||
|
var brailleOrderValues = [0, 1];
|
||||||
|
brailleOrderValues.forEach(
|
||||||
|
function testBrailleOrder(brailleOrder) {
|
||||||
|
SpecialPowers.setIntPref(PREF_UTTERANCE_ORDER, brailleOrder);
|
||||||
|
var expected = test.expected[brailleOrder];
|
||||||
|
testOutput(expected, test.accOrElmOrID, test.oldAccOrElmOrID, 2);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// If there was an original utterance order preference, revert to it.
|
||||||
|
SpecialPowers.clearUserPref(PREF_UTTERANCE_ORDER);
|
||||||
|
SimpleTest.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
addA11yLoadEvent(doTest);
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="root">
|
||||||
|
<p id="display"></p>
|
||||||
|
<div id="content" style="display: none"></div>
|
||||||
|
<pre id="test"></pre>
|
||||||
|
<a href="example.com" id="link">Link</a>
|
||||||
|
<button id="button">I am a button</button>
|
||||||
|
<label for="password_input">Secret Password</label><input id="password_input" type="password"></input>
|
||||||
|
<label for="checkbox_unchecked">checkboxtext</label><input id="checkbox_unchecked" type="checkbox"></input>
|
||||||
|
<label for="checkbox_checked">some more checkbox text</label><input id="checkbox_checked" type="checkbox" checked></input>
|
||||||
|
<label for="radio_unselected">any old radio button</label><input id="radio_unselected" type="radio"></input>
|
||||||
|
<label for="radio_selected">a unique radio button</label><input id="radio_selected" type="radio" checked></input>
|
||||||
|
<div id="togglebutton_notpressed" aria-pressed="false" role="button" tabindex="-1">I ain't pressed</div>
|
||||||
|
<div id="togglebutton_pressed" aria-pressed="true" role="button" tabindex="-1">I am pressed!</div>
|
||||||
|
<ol id="ordered_list">
|
||||||
|
<li id="ol_li_one">ol item 1</li>
|
||||||
|
<li id="ol_li_two">ol item 2</li>
|
||||||
|
<li id="ol_li_three">ol item 3</li>
|
||||||
|
<li id="ol_li_three">ol item 4</li>
|
||||||
|
</ol>
|
||||||
|
<ul id="unordered_list">
|
||||||
|
<li id="ul_li_one">ul item 1</li>
|
||||||
|
<li id="ul_li_two">ul item 2</li>
|
||||||
|
<li id="ul_li_three">ul item 3</li>
|
||||||
|
<li id="ul_li_three">ul item 4</li>
|
||||||
|
</ul>
|
||||||
|
<textarea id="textarea" cols="80" rows="5">
|
||||||
|
Here lies treasure.
|
||||||
|
</textarea>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -9,7 +9,7 @@
|
|||||||
<script type="application/javascript"
|
<script type="application/javascript"
|
||||||
src="../common.js"></script>
|
src="../common.js"></script>
|
||||||
<script type="application/javascript"
|
<script type="application/javascript"
|
||||||
src="utterance.js"></script>
|
src="output.js"></script>
|
||||||
<script type="application/javascript">
|
<script type="application/javascript">
|
||||||
|
|
||||||
function doTest() {
|
function doTest() {
|
||||||
@ -87,11 +87,14 @@
|
|||||||
"Plums"]
|
"Plums"]
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
SpecialPowers.setIntPref(PREF_UTTERANCE_ORDER, 0);
|
||||||
|
|
||||||
// Test various explicit names vs the utterance generated from subtrees.
|
// Test various explicit names vs the utterance generated from subtrees.
|
||||||
tests.forEach(function run(test) {
|
tests.forEach(function run(test) {
|
||||||
testUtterance(test.expected, test.accOrElmOrID, test.oldAccOrElmOrID);
|
testOutput(test.expected, test.accOrElmOrID, test.oldAccOrElmOrID, 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
SpecialPowers.clearUserPref(PREF_UTTERANCE_ORDER);
|
||||||
SimpleTest.finish();
|
SimpleTest.finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,4 +166,4 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -13,7 +13,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=753984
|
|||||||
<script type="application/javascript"
|
<script type="application/javascript"
|
||||||
src="../common.js"></script>
|
src="../common.js"></script>
|
||||||
<script type="application/javascript"
|
<script type="application/javascript"
|
||||||
src="./utterance.js"></script>
|
src="./output.js"></script>
|
||||||
<script type="application/javascript">
|
<script type="application/javascript">
|
||||||
|
|
||||||
function doTest() {
|
function doTest() {
|
||||||
@ -120,7 +120,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=753984
|
|||||||
function testUtteranceOrder(utteranceOrder) {
|
function testUtteranceOrder(utteranceOrder) {
|
||||||
SpecialPowers.setIntPref(PREF_UTTERANCE_ORDER, utteranceOrder);
|
SpecialPowers.setIntPref(PREF_UTTERANCE_ORDER, utteranceOrder);
|
||||||
var expected = test.expected[utteranceOrder];
|
var expected = test.expected[utteranceOrder];
|
||||||
testUtterance(expected, test.accOrElmOrID, test.oldAccOrElmOrID);
|
testOutput(expected, test.accOrElmOrID, test.oldAccOrElmOrID, 1);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -1,70 +0,0 @@
|
|||||||
const Cu = Components.utils;
|
|
||||||
const PREF_UTTERANCE_ORDER = "accessibility.accessfu.utterance";
|
|
||||||
|
|
||||||
Cu.import('resource://gre/modules/accessibility/Utils.jsm');
|
|
||||||
Cu.import("resource://gre/modules/accessibility/UtteranceGenerator.jsm",
|
|
||||||
this);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test context utterance generation.
|
|
||||||
*
|
|
||||||
* @param expected {Array} expected utterance.
|
|
||||||
* @param aAccOrElmOrID identifier to get an accessible to test.
|
|
||||||
* @param aOldAccOrElmOrID optional identifier to get an accessible relative to
|
|
||||||
* the |aAccOrElmOrID|.
|
|
||||||
*
|
|
||||||
* Note: if |aOldAccOrElmOrID| is not provided, the |aAccOrElmOrID| must be
|
|
||||||
* scoped to the "root" element in markup.
|
|
||||||
*/
|
|
||||||
function testContextUtterance(expected, aAccOrElmOrID, aOldAccOrElmOrID) {
|
|
||||||
aOldAccOrElmOrID = aOldAccOrElmOrID || "root";
|
|
||||||
var accessible = getAccessible(aAccOrElmOrID);
|
|
||||||
var oldAccessible = getAccessible(aOldAccOrElmOrID);
|
|
||||||
var context = new PivotContext(accessible, oldAccessible);
|
|
||||||
var utterance = UtteranceGenerator.genForContext(context);
|
|
||||||
isDeeply(utterance, expected,
|
|
||||||
"Context utterance is correct for " + aAccOrElmOrID);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test object utterance generated array that includes names.
|
|
||||||
* Note: test ignores utterances without the name.
|
|
||||||
*
|
|
||||||
* @param aAccOrElmOrID identifier to get an accessible to test.
|
|
||||||
*/
|
|
||||||
function testObjectUtterance(aAccOrElmOrID) {
|
|
||||||
var accessible = getAccessible(aAccOrElmOrID);
|
|
||||||
var utterance = UtteranceGenerator.genForObject(accessible);
|
|
||||||
var utteranceOrder;
|
|
||||||
try {
|
|
||||||
utteranceOrder = SpecialPowers.getIntPref(PREF_UTTERANCE_ORDER);
|
|
||||||
} catch (ex) {
|
|
||||||
// PREF_UTTERANCE_ORDER not set.
|
|
||||||
utteranceOrder = 0;
|
|
||||||
}
|
|
||||||
var expectedNameIndex = utteranceOrder === 0 ? utterance.length - 1 : 0;
|
|
||||||
var nameIndex = utterance.indexOf(accessible.name);
|
|
||||||
|
|
||||||
if (nameIndex > -1) {
|
|
||||||
ok(utterance.indexOf(accessible.name) === expectedNameIndex,
|
|
||||||
"Object utterance is correct for " + aAccOrElmOrID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test object and context utterance for an accessible.
|
|
||||||
*
|
|
||||||
* @param expected {Array} expected utterance.
|
|
||||||
* @param aAccOrElmOrID identifier to get an accessible to test.
|
|
||||||
* @param aOldAccOrElmOrID optional identifier to get an accessible relative to
|
|
||||||
* the |aAccOrElmOrID|.
|
|
||||||
*/
|
|
||||||
function testUtterance(expected, aAccOrElmOrID, aOldAccOrElmOrID) {
|
|
||||||
testContextUtterance(expected, aAccOrElmOrID, aOldAccOrElmOrID);
|
|
||||||
// Just need to test object utterance for individual
|
|
||||||
// accOrElmOrID.
|
|
||||||
if (aOldAccOrElmOrID) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
testObjectUtterance(aAccOrElmOrID);
|
|
||||||
}
|
|
@ -208,6 +208,7 @@
|
|||||||
|
|
||||||
// Test equation image
|
// Test equation image
|
||||||
testName("img_eq", "x^2 + y^2 + z^2")
|
testName("img_eq", "x^2 + y^2 + z^2")
|
||||||
|
testName("input_img_eq", "x^2 + y^2 + z^2")
|
||||||
testName("txt_eq", "x^2 + y^2 + z^2")
|
testName("txt_eq", "x^2 + y^2 + z^2")
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
@ -606,6 +607,7 @@
|
|||||||
|
|
||||||
<p>Image:
|
<p>Image:
|
||||||
<img id="img_eq" role="math" src="foo" alt="x^2 + y^2 + z^2">
|
<img id="img_eq" role="math" src="foo" alt="x^2 + y^2 + z^2">
|
||||||
|
<input type="image" id="input_img_eq" src="foo" alt="x^2 + y^2 + z^2">
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>Text:
|
<p>Text:
|
||||||
|
@ -34,6 +34,7 @@ MOCHITEST_A11Y_FILES =\
|
|||||||
test_groupbox.xul \
|
test_groupbox.xul \
|
||||||
test_iframe.html \
|
test_iframe.html \
|
||||||
test_img.html \
|
test_img.html \
|
||||||
|
test_invalid_img.xhtml \
|
||||||
test_invalidationlist.html \
|
test_invalidationlist.html \
|
||||||
test_list.html \
|
test_list.html \
|
||||||
test_map.html \
|
test_map.html \
|
||||||
|
50
accessible/tests/mochitest/tree/test_invalid_img.xhtml
Normal file
50
accessible/tests/mochitest/tree/test_invalid_img.xhtml
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
<head>
|
||||||
|
<title>invalid html img</title>
|
||||||
|
|
||||||
|
<link rel="stylesheet" type="text/css"
|
||||||
|
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
|
||||||
|
|
||||||
|
<script type="application/javascript"
|
||||||
|
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
|
||||||
|
<script type="application/javascript"
|
||||||
|
src="../common.js"></script>
|
||||||
|
<script type="application/javascript"
|
||||||
|
src="../role.js"></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
<![CDATA[
|
||||||
|
function doTest()
|
||||||
|
{
|
||||||
|
document.getElementsByTagName("img")[0].firstChild.data = "2";
|
||||||
|
|
||||||
|
var accTree = {
|
||||||
|
role: ROLE_TEXT_CONTAINER,
|
||||||
|
children: [ { role: ROLE_TEXT_LEAF } ]
|
||||||
|
};
|
||||||
|
testAccessibleTree("the_img", accTree);
|
||||||
|
SimpleTest.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
addA11yLoadEvent(doTest);
|
||||||
|
]]>
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<a target="_blank"
|
||||||
|
title="use HyperTextAccessible for invalid img"
|
||||||
|
href="https://bugzilla.mozilla.org/show_bug.cgi?id=852129">
|
||||||
|
Mozilla Bug 852129
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<p id="display"></p>
|
||||||
|
<div id="content" style="display: none"></div>
|
||||||
|
<pre id="test">
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<img id="the_img">1</img>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -1150,3 +1150,7 @@ function closeBrowserWindow(window, callback) {
|
|||||||
}, false);
|
}, false);
|
||||||
window.close();
|
window.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test disabled on Linux because of bug 882867
|
||||||
|
if (require("sdk/system/runtime").OS == "Linux")
|
||||||
|
module.exports = {};
|
||||||
|
@ -51,7 +51,6 @@ STL_FLAGS=
|
|||||||
LIBS += $(JEMALLOC_LIBS)
|
LIBS += $(JEMALLOC_LIBS)
|
||||||
|
|
||||||
LIBS += \
|
LIBS += \
|
||||||
$(EXTRA_DSO_LIBS) \
|
|
||||||
$(XPCOM_STANDALONE_GLUE_LDOPTS) \
|
$(XPCOM_STANDALONE_GLUE_LDOPTS) \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
|
@ -377,23 +377,32 @@ pref("dom.ipc.processCount", 100000);
|
|||||||
|
|
||||||
pref("dom.ipc.browser_frames.oop_by_default", false);
|
pref("dom.ipc.browser_frames.oop_by_default", false);
|
||||||
|
|
||||||
// Temporary permission hack for WebSMS
|
// WebSMS
|
||||||
pref("dom.sms.enabled", true);
|
pref("dom.sms.enabled", true);
|
||||||
pref("dom.sms.strict7BitEncoding", false); // Disabled by default.
|
pref("dom.sms.strict7BitEncoding", false); // Disabled by default.
|
||||||
pref("dom.sms.requestStatusReport", true); // Enabled by default.
|
pref("dom.sms.requestStatusReport", true); // Enabled by default.
|
||||||
|
|
||||||
// Temporary permission hack for WebContacts
|
// WebContacts
|
||||||
pref("dom.mozContacts.enabled", true);
|
pref("dom.mozContacts.enabled", true);
|
||||||
pref("dom.navigator-property.disable.mozContacts", false);
|
pref("dom.navigator-property.disable.mozContacts", false);
|
||||||
pref("dom.global-constructor.disable.mozContact", false);
|
pref("dom.global-constructor.disable.mozContact", false);
|
||||||
|
|
||||||
|
// Shortnumber matching needed for e.g. Brazil:
|
||||||
|
// 01187654321 can be found with 87654321
|
||||||
|
pref("dom.phonenumber.substringmatching.BR", 8);
|
||||||
|
pref("dom.phonenumber.substringmatching.CO", 10);
|
||||||
|
pref("dom.phonenumber.substringmatching.VE", 7);
|
||||||
|
|
||||||
// WebAlarms
|
// WebAlarms
|
||||||
pref("dom.mozAlarms.enabled", true);
|
pref("dom.mozAlarms.enabled", true);
|
||||||
|
|
||||||
// SimplePush
|
// SimplePush
|
||||||
pref("services.push.enabled", true);
|
pref("services.push.enabled", true);
|
||||||
|
// Is the network connection allowed to be up?
|
||||||
|
// This preference should be used in UX to enable/disable push.
|
||||||
|
pref("services.push.connection.enabled", true);
|
||||||
// serverURL to be assigned by services team
|
// serverURL to be assigned by services team
|
||||||
pref("services.push.serverURL", "");
|
pref("services.push.serverURL", "wss://push.services.mozilla.com/");
|
||||||
pref("services.push.userAgentID", "");
|
pref("services.push.userAgentID", "");
|
||||||
// Exponential back-off start is 5 seconds like in HTTP/1.1.
|
// Exponential back-off start is 5 seconds like in HTTP/1.1.
|
||||||
// Maximum back-off is pingInterval.
|
// Maximum back-off is pingInterval.
|
||||||
@ -635,6 +644,8 @@ pref("dom.disable_window_open_dialog_feature", true);
|
|||||||
|
|
||||||
// Screen reader support
|
// Screen reader support
|
||||||
pref("accessibility.accessfu.activate", 2);
|
pref("accessibility.accessfu.activate", 2);
|
||||||
|
// Whether to skip images with empty alt text
|
||||||
|
pref("accessibility.accessfu.skip_empty_images", true);
|
||||||
|
|
||||||
// Enable hit-target fluffing
|
// Enable hit-target fluffing
|
||||||
pref("ui.touch.radius.enabled", false);
|
pref("ui.touch.radius.enabled", false);
|
||||||
|
@ -174,6 +174,11 @@ SettingsListener.observe('language.current', 'en-US', function(value) {
|
|||||||
function(value) {
|
function(value) {
|
||||||
Services.prefs.setBoolPref('ril.cellbroadcast.disabled', value);
|
Services.prefs.setBoolPref('ril.cellbroadcast.disabled', value);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
SettingsListener.observe('ril.radio.disabled', false,
|
||||||
|
function(value) {
|
||||||
|
Services.prefs.setBoolPref('ril.radio.disabled', value);
|
||||||
|
});
|
||||||
})();
|
})();
|
||||||
|
|
||||||
//=================== DeviceInfo ====================
|
//=================== DeviceInfo ====================
|
||||||
|
@ -379,8 +379,27 @@ var shell = {
|
|||||||
case evt.DOM_VK_F1: // headset button
|
case evt.DOM_VK_F1: // headset button
|
||||||
type = 'headset-button';
|
type = 'headset-button';
|
||||||
break;
|
break;
|
||||||
default: // Anything else is a real key
|
}
|
||||||
return; // Don't filter it at all; let it propagate to Gaia
|
|
||||||
|
let mediaKeys = {
|
||||||
|
'MediaNextTrack': 'media-next-track-button',
|
||||||
|
'MediaPreviousTrack': 'media-previous-track-button',
|
||||||
|
'MediaPause': 'media-pause-button',
|
||||||
|
'MediaPlay': 'media-play-button',
|
||||||
|
'MediaPlayPause': 'media-play-pause-button',
|
||||||
|
'MediaStop': 'media-stop-button',
|
||||||
|
'MediaRewind': 'media-rewind-button',
|
||||||
|
'FastFwd': 'media-fast-forward-button'
|
||||||
|
};
|
||||||
|
|
||||||
|
let isMediaKey = false;
|
||||||
|
if (mediaKeys[evt.key]) {
|
||||||
|
isMediaKey = true;
|
||||||
|
type = mediaKeys[evt.key];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!type) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we didn't return, then the key event represents a hardware key
|
// If we didn't return, then the key event represents a hardware key
|
||||||
@ -408,6 +427,12 @@ var shell = {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isMediaKey) {
|
||||||
|
this.lastHardwareButtonEventType = type;
|
||||||
|
gSystemMessenger.broadcastMessage('media-button', type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// On my device, the physical hardware buttons (sleep and volume)
|
// On my device, the physical hardware buttons (sleep and volume)
|
||||||
// send multiple events (press press release release), but the
|
// send multiple events (press press release release), but the
|
||||||
// soft home button just sends one. This hack is to manually
|
// soft home button just sends one. This hack is to manually
|
||||||
|
@ -9,7 +9,7 @@ VPATH = @srcdir@
|
|||||||
|
|
||||||
include $(DEPTH)/config/autoconf.mk
|
include $(DEPTH)/config/autoconf.mk
|
||||||
|
|
||||||
EXTRA_PP_COMPONENTS = \
|
DISABLED_EXTRA_PP_COMPONENTS = \
|
||||||
ActivitiesGlue.js \
|
ActivitiesGlue.js \
|
||||||
AlertsService.js \
|
AlertsService.js \
|
||||||
B2GAboutRedirector.js \
|
B2GAboutRedirector.js \
|
||||||
@ -36,7 +36,7 @@ EXTRA_JS_MODULES = \
|
|||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
ifdef MOZ_UPDATER
|
ifdef MOZ_UPDATER
|
||||||
EXTRA_PP_COMPONENTS += UpdatePrompt.js
|
DISABLED_EXTRA_PP_COMPONENTS += UpdatePrompt.js
|
||||||
endif
|
endif
|
||||||
|
|
||||||
include $(topsrcdir)/config/rules.mk
|
include $(topsrcdir)/config/rules.mk
|
||||||
|
@ -12,3 +12,26 @@ XPIDL_SOURCES += [
|
|||||||
|
|
||||||
MODULE = 'B2GComponents'
|
MODULE = 'B2GComponents'
|
||||||
|
|
||||||
|
EXTRA_PP_COMPONENTS += [
|
||||||
|
'ActivitiesGlue.js',
|
||||||
|
'AlertsService.js',
|
||||||
|
'B2GAboutRedirector.js',
|
||||||
|
'B2GComponents.manifest',
|
||||||
|
'ContentHandler.js',
|
||||||
|
'ContentPermissionPrompt.js',
|
||||||
|
'DirectoryProvider.js',
|
||||||
|
'FilePicker.js',
|
||||||
|
'MailtoProtocolHandler.js',
|
||||||
|
'MozKeyboard.js',
|
||||||
|
'PaymentGlue.js',
|
||||||
|
'ProcessGlobal.js',
|
||||||
|
'RecoveryService.js',
|
||||||
|
'SmsProtocolHandler.js',
|
||||||
|
'TelProtocolHandler.js',
|
||||||
|
'YoutubeProtocolHandler.js',
|
||||||
|
]
|
||||||
|
|
||||||
|
if CONFIG['MOZ_UPDATER']:
|
||||||
|
EXTRA_PP_COMPONENTS += [
|
||||||
|
'UpdatePrompt.js',
|
||||||
|
]
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"revision": "a7f713158285156858dcf774ce51782ac01c938c",
|
"revision": "393b5209f9bc300017f2e037b1d0beeda4da7519",
|
||||||
"repo_path": "/integration/gaia-central"
|
"repo_path": "/integration/gaia-central"
|
||||||
}
|
}
|
||||||
|
36
b2g/config/inari/config.json
Normal file
36
b2g/config/inari/config.json
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
{
|
||||||
|
"config_version": 2,
|
||||||
|
"tooltool_manifest": "releng-inari.tt",
|
||||||
|
"mock_target": "mozilla-centos6-i386",
|
||||||
|
"mock_packages": ["ccache", "make", "bison", "flex", "gcc", "g++", "mpfr", "zlib-devel", "ncurses-devel", "zip", "autoconf213", "glibc-static", "perl-Digest-SHA", "wget", "alsa-lib", "atk", "cairo", "dbus-glib", "fontconfig", "freetype", "glib2", "gtk2", "libXRender", "libXt", "pango", "mozilla-python27-mercurial", "openssh-clients", "nss-devel", "java-1.6.0-openjdk-devel", "git"],
|
||||||
|
"mock_files": [["/home/cltbld/.ssh", "/home/mock_mozilla/.ssh"]],
|
||||||
|
"build_targets": [],
|
||||||
|
"upload_files": [
|
||||||
|
"{objdir}/dist/b2g-*.crashreporter-symbols.zip",
|
||||||
|
"{objdir}/dist/b2g-*.tar.gz",
|
||||||
|
"{workdir}/sources.xml"
|
||||||
|
],
|
||||||
|
"zip_files": [
|
||||||
|
["{workdir}/out/target/product/inari/*.img", "out/target/product/inari/"],
|
||||||
|
["{workdir}/boot.img", "out/target/product/inari/"],
|
||||||
|
"{workdir}/flash.sh",
|
||||||
|
"{workdir}/load-config.sh",
|
||||||
|
"{workdir}/.config",
|
||||||
|
"{workdir}/sources.xml"
|
||||||
|
],
|
||||||
|
"env": {
|
||||||
|
"VARIANT": "user",
|
||||||
|
"MOZILLA_OFFICIAL": "1",
|
||||||
|
"B2GUPDATER": "1"
|
||||||
|
},
|
||||||
|
"b2g_manifest": "inari.xml",
|
||||||
|
"b2g_manifest_branch": "master",
|
||||||
|
"additional_source_tarballs": ["backup-inari.tar.xz"],
|
||||||
|
"gecko_l10n_root": "http://hg.mozilla.org/l10n-central",
|
||||||
|
"gaia": {
|
||||||
|
"l10n": {
|
||||||
|
"vcs": "hgtool",
|
||||||
|
"root": "http://hg.mozilla.org/gaia-l10n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
b2g/config/inari/releng-inari.tt
Normal file
20
b2g/config/inari/releng-inari.tt
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"size": 4249600,
|
||||||
|
"digest": "9f2150350e6fb2e8fe8744f47c02799865de16f8539844374188c2b421d8a044c213af57c8fe9dc7ad2038150687b50eba251dc782fa606674a86d8acc9e3dad",
|
||||||
|
"algorithm": "sha512",
|
||||||
|
"filename": "boot.img"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size": 33335060,
|
||||||
|
"digest": "aa60b13458fabcb60c671e80db4dfc0cda3090fc5df27215cec3fb01f9cf2ac4403c93be99d1816a1f2d903febd4b027f7193a5fcec1aacf18ebb419ee9f32d7",
|
||||||
|
"algorithm": "sha512",
|
||||||
|
"filename": "backup-inari.tar.xz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size": 1570553,
|
||||||
|
"digest": "ea03de74df73b05e939c314cd15c54aac7b5488a407b7cc4f5f263f3049a1f69642c567dd35c43d0bc3f0d599d0385a26ab2dd947a6b18f9044e4918b382eea7",
|
||||||
|
"algorithm": "sha512",
|
||||||
|
"filename": "Adreno200-AU_LINUX_ANDROID_ICS_CHOCO_CS.04.00.03.06.001.zip"
|
||||||
|
}
|
||||||
|
]
|
@ -54,7 +54,6 @@ DEFINES += -DXPCOM_GLUE
|
|||||||
STL_FLAGS=
|
STL_FLAGS=
|
||||||
|
|
||||||
LIBS += \
|
LIBS += \
|
||||||
$(EXTRA_DSO_LIBS) \
|
|
||||||
$(XPCOM_STANDALONE_GLUE_LDOPTS) \
|
$(XPCOM_STANDALONE_GLUE_LDOPTS) \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1370548649000">
|
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1370990544000">
|
||||||
<emItems>
|
<emItems>
|
||||||
<emItem blockID="i350" id="sqlmoz@facebook.com">
|
<emItem blockID="i350" id="sqlmoz@facebook.com">
|
||||||
<versionRange minVersion="0" maxVersion="*" severity="3">
|
<versionRange minVersion="0" maxVersion="*" severity="3">
|
||||||
@ -222,6 +222,10 @@
|
|||||||
<versionRange minVersion="0" maxVersion="*" severity="3">
|
<versionRange minVersion="0" maxVersion="*" severity="3">
|
||||||
</versionRange>
|
</versionRange>
|
||||||
</emItem>
|
</emItem>
|
||||||
|
<emItem blockID="i364" id="{FE1DEEEA-DB6D-44b8-83F0-34FC0F9D1052}">
|
||||||
|
<versionRange minVersion="0" maxVersion="*" severity="1">
|
||||||
|
</versionRange>
|
||||||
|
</emItem>
|
||||||
<emItem blockID="i59" id="ghostviewer@youtube2.com">
|
<emItem blockID="i59" id="ghostviewer@youtube2.com">
|
||||||
<versionRange minVersion="0" maxVersion="*">
|
<versionRange minVersion="0" maxVersion="*">
|
||||||
</versionRange>
|
</versionRange>
|
||||||
@ -253,6 +257,10 @@
|
|||||||
<versionRange minVersion="0" maxVersion="*" severity="3">
|
<versionRange minVersion="0" maxVersion="*" severity="3">
|
||||||
</versionRange>
|
</versionRange>
|
||||||
</emItem>
|
</emItem>
|
||||||
|
<emItem blockID="i370" id="happylyrics@hpyproductions.net">
|
||||||
|
<versionRange minVersion="0" maxVersion="*" severity="1">
|
||||||
|
</versionRange>
|
||||||
|
</emItem>
|
||||||
<emItem blockID="i22" id="ShopperReports@ShopperReports.com">
|
<emItem blockID="i22" id="ShopperReports@ShopperReports.com">
|
||||||
<versionRange minVersion="3.1.22.0" maxVersion="3.1.22.0">
|
<versionRange minVersion="3.1.22.0" maxVersion="3.1.22.0">
|
||||||
</versionRange>
|
</versionRange>
|
||||||
@ -803,7 +811,7 @@
|
|||||||
</versionRange>
|
</versionRange>
|
||||||
</pluginItem>
|
</pluginItem>
|
||||||
<pluginItem blockID="p248">
|
<pluginItem blockID="p248">
|
||||||
<match name="filename" exp="Scorch\.plugin" /> <versionRange minVersion="0" maxVersion="6.2.0" severity="1"></versionRange>
|
<match name="filename" exp="Scorch\.plugin" /> <versionRange minVersion="0" maxVersion="6.2.0b88" severity="1"></versionRange>
|
||||||
</pluginItem>
|
</pluginItem>
|
||||||
<pluginItem blockID="p250">
|
<pluginItem blockID="p250">
|
||||||
<match name="filename" exp="npFoxitReaderPlugin\.dll" /> <versionRange minVersion="0" maxVersion="2.2.1.530" severity="0" vulnerabilitystatus="2"></versionRange>
|
<match name="filename" exp="npFoxitReaderPlugin\.dll" /> <versionRange minVersion="0" maxVersion="2.2.1.530" severity="0" vulnerabilitystatus="2"></versionRange>
|
||||||
@ -930,6 +938,9 @@
|
|||||||
</targetApplication>
|
</targetApplication>
|
||||||
</versionRange>
|
</versionRange>
|
||||||
</pluginItem>
|
</pluginItem>
|
||||||
|
<pluginItem blockID="p366">
|
||||||
|
<match name="filename" exp="Scorch\.plugin" /> <versionRange minVersion="6.2.0" maxVersion="6.2.0" severity="1"></versionRange>
|
||||||
|
</pluginItem>
|
||||||
</pluginItems>
|
</pluginItems>
|
||||||
|
|
||||||
<gfxItems>
|
<gfxItems>
|
||||||
|
@ -3612,6 +3612,7 @@ function mimeTypeIsTextBased(aMimeType)
|
|||||||
aMimeType.endsWith("+xml") ||
|
aMimeType.endsWith("+xml") ||
|
||||||
aMimeType == "application/x-javascript" ||
|
aMimeType == "application/x-javascript" ||
|
||||||
aMimeType == "application/javascript" ||
|
aMimeType == "application/javascript" ||
|
||||||
|
aMimeType == "application/json" ||
|
||||||
aMimeType == "application/xml" ||
|
aMimeType == "application/xml" ||
|
||||||
aMimeType == "mozilla.application/cached-xul";
|
aMimeType == "mozilla.application/cached-xul";
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,6 @@ function sendNotifyRequest(name) {
|
|||||||
|
|
||||||
service.healthReporter.onInit().then(function onInit() {
|
service.healthReporter.onInit().then(function onInit() {
|
||||||
is(policy.ensureNotifyResponse(new Date()), false, "User has not responded to policy.");
|
is(policy.ensureNotifyResponse(new Date()), false, "User has not responded to policy.");
|
||||||
is(policy.notifyState, policy.STATE_NOTIFY_WAIT, "Policy is waiting for notification response.");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return policy;
|
return policy;
|
||||||
@ -53,15 +52,17 @@ function waitForNotificationClose(notification, cb) {
|
|||||||
observer.observe(parent, {childList: true});
|
observer.observe(parent, {childList: true});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let dumpAppender, rootLogger;
|
||||||
|
|
||||||
function test() {
|
function test() {
|
||||||
waitForExplicitFinish();
|
waitForExplicitFinish();
|
||||||
|
|
||||||
let ns = {};
|
let ns = {};
|
||||||
Components.utils.import("resource://services-common/log4moz.js", ns);
|
Components.utils.import("resource://services-common/log4moz.js", ns);
|
||||||
let rootLogger = ns.Log4Moz.repository.rootLogger;
|
rootLogger = ns.Log4Moz.repository.rootLogger;
|
||||||
let appender = new ns.Log4Moz.DumpAppender();
|
dumpAppender = new ns.Log4Moz.DumpAppender();
|
||||||
appender.level = ns.Log4Moz.Level.All;
|
dumpAppender.level = ns.Log4Moz.Level.All;
|
||||||
rootLogger.addAppender(appender);
|
rootLogger.addAppender(dumpAppender);
|
||||||
|
|
||||||
let notification = document.getElementById("global-notificationbox");
|
let notification = document.getElementById("global-notificationbox");
|
||||||
let policy;
|
let policy;
|
||||||
@ -126,6 +127,9 @@ function test_multiple_windows() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dump("Finishing multiple window test.\n");
|
dump("Finishing multiple window test.\n");
|
||||||
|
rootLogger.removeAppender(dumpAppender);
|
||||||
|
delete dumpAppender;
|
||||||
|
delete rootLogger;
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ function runAltLeftClickTest() {
|
|||||||
function runShiftLeftClickTest() {
|
function runShiftLeftClickTest() {
|
||||||
let listener = new WindowListener(getBrowserURL(), function(aWindow) {
|
let listener = new WindowListener(getBrowserURL(), function(aWindow) {
|
||||||
Services.wm.removeListener(listener);
|
Services.wm.removeListener(listener);
|
||||||
addPageShowListener(aWindow.gBrowser, function() {
|
addPageShowListener(aWindow.gBrowser.selectedBrowser, function() {
|
||||||
info("URL should be loaded in a new window");
|
info("URL should be loaded in a new window");
|
||||||
is(gURLBar.value, "", "Urlbar reverted to original value");
|
is(gURLBar.value, "", "Urlbar reverted to original value");
|
||||||
is(gFocusManager.focusedElement, null, "There should be no focused element");
|
is(gFocusManager.focusedElement, null, "There should be no focused element");
|
||||||
@ -43,7 +43,7 @@ function runShiftLeftClickTest() {
|
|||||||
|
|
||||||
aWindow.close();
|
aWindow.close();
|
||||||
runNextTest();
|
runNextTest();
|
||||||
});
|
}, "http://example.com/");
|
||||||
});
|
});
|
||||||
Services.wm.addListener(listener);
|
Services.wm.addListener(listener);
|
||||||
|
|
||||||
@ -61,7 +61,7 @@ function runNextTest() {
|
|||||||
info("Running test: " + test.desc);
|
info("Running test: " + test.desc);
|
||||||
// Tab will be blank if test.startValue is null
|
// Tab will be blank if test.startValue is null
|
||||||
let tab = gBrowser.selectedTab = gBrowser.addTab(test.startValue);
|
let tab = gBrowser.selectedTab = gBrowser.addTab(test.startValue);
|
||||||
addPageShowListener(gBrowser, function() {
|
addPageShowListener(gBrowser.selectedBrowser, function() {
|
||||||
triggerCommand(test.click, test.event);
|
triggerCommand(test.click, test.event);
|
||||||
test.check(tab);
|
test.check(tab);
|
||||||
|
|
||||||
@ -163,10 +163,13 @@ function checkNewTab(aTab) {
|
|||||||
isnot(gBrowser.selectedTab, aTab, "New URL was loaded in a new tab");
|
isnot(gBrowser.selectedTab, aTab, "New URL was loaded in a new tab");
|
||||||
}
|
}
|
||||||
|
|
||||||
function addPageShowListener(aBrowser, aFunc) {
|
function addPageShowListener(browser, cb, expectedURL) {
|
||||||
aBrowser.selectedBrowser.addEventListener("pageshow", function loadListener() {
|
browser.addEventListener("pageshow", function pageShowListener() {
|
||||||
aBrowser.selectedBrowser.removeEventListener("pageshow", loadListener, false);
|
info("pageshow: " + browser.currentURI.spec);
|
||||||
aFunc();
|
if (expectedURL && browser.currentURI.spec != expectedURL)
|
||||||
|
return; // ignore pageshows for non-expected URLs
|
||||||
|
browser.removeEventListener("pageshow", pageShowListener, false);
|
||||||
|
cb();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ function test() {
|
|||||||
gURLBar.value = "firefox health report";
|
gURLBar.value = "firefox health report";
|
||||||
gURLBar.handleCommand();
|
gURLBar.handleCommand();
|
||||||
|
|
||||||
executeSoon(function afterSearch() {
|
executeSoon(() => executeSoon(() => {
|
||||||
gBrowser.removeTab(tab);
|
gBrowser.removeTab(tab);
|
||||||
|
|
||||||
m.getValues().then(function onData(data) {
|
m.getValues().then(function onData(data) {
|
||||||
@ -58,7 +58,7 @@ function test() {
|
|||||||
is(newCount, oldCount + 1, "Exactly one search has been recorded.");
|
is(newCount, oldCount + 1, "Exactly one search has been recorded.");
|
||||||
finish();
|
finish();
|
||||||
});
|
});
|
||||||
});
|
}));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -712,10 +712,10 @@ function runTest(testNum) {
|
|||||||
var full_screen_element = subwindow.document.getElementById("test-dom-full-screen");
|
var full_screen_element = subwindow.document.getElementById("test-dom-full-screen");
|
||||||
var openDomFullScreen = function() {
|
var openDomFullScreen = function() {
|
||||||
subwindow.removeEventListener("mozfullscreenchange", openDomFullScreen, false);
|
subwindow.removeEventListener("mozfullscreenchange", openDomFullScreen, false);
|
||||||
SpecialPowers.clearUserPref("full-screen-api.allow-trusted-requests-only");
|
|
||||||
openContextMenuFor(dom_full_screen, true); // Invoke context menu for next test.
|
openContextMenuFor(dom_full_screen, true); // Invoke context menu for next test.
|
||||||
}
|
}
|
||||||
subwindow.addEventListener("mozfullscreenchange", openDomFullScreen, false);
|
subwindow.addEventListener("mozfullscreenchange", openDomFullScreen, false);
|
||||||
|
SpecialPowers.setBoolPref("full-screen-api.approval-required", false);
|
||||||
SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", false);
|
SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", false);
|
||||||
full_screen_element.mozRequestFullScreen();
|
full_screen_element.mozRequestFullScreen();
|
||||||
break;
|
break;
|
||||||
@ -741,11 +741,11 @@ function runTest(testNum) {
|
|||||||
var full_screen_element = subwindow.document.getElementById("test-dom-full-screen");
|
var full_screen_element = subwindow.document.getElementById("test-dom-full-screen");
|
||||||
var openPagemenu = function() {
|
var openPagemenu = function() {
|
||||||
subwindow.removeEventListener("mozfullscreenchange", openPagemenu, false);
|
subwindow.removeEventListener("mozfullscreenchange", openPagemenu, false);
|
||||||
|
SpecialPowers.clearUserPref("full-screen-api.approval-required");
|
||||||
SpecialPowers.clearUserPref("full-screen-api.allow-trusted-requests-only");
|
SpecialPowers.clearUserPref("full-screen-api.allow-trusted-requests-only");
|
||||||
openContextMenuFor(pagemenu, true); // Invoke context menu for next test.
|
openContextMenuFor(pagemenu, true); // Invoke context menu for next test.
|
||||||
}
|
}
|
||||||
subwindow.addEventListener("mozfullscreenchange", openPagemenu, false);
|
subwindow.addEventListener("mozfullscreenchange", openPagemenu, false);
|
||||||
SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", false);
|
|
||||||
subwindow.document.mozCancelFullScreen();
|
subwindow.document.mozCancelFullScreen();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ DISABLED_EXTRA_COMPONENTS = \
|
|||||||
BrowserComponents.manifest \
|
BrowserComponents.manifest \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
EXTRA_PP_COMPONENTS = \
|
DISABLED_EXTRA_PP_COMPONENTS = \
|
||||||
nsBrowserContentHandler.js \
|
nsBrowserContentHandler.js \
|
||||||
nsBrowserGlue.js \
|
nsBrowserGlue.js \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
@ -25,7 +25,7 @@ DISABLED_EXTRA_COMPONENTS = \
|
|||||||
WebContentConverter.js \
|
WebContentConverter.js \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
EXTRA_PP_COMPONENTS = \
|
DISABLED_EXTRA_PP_COMPONENTS = \
|
||||||
FeedWriter.js \
|
FeedWriter.js \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
|
@ -15,3 +15,7 @@ EXTRA_COMPONENTS += [
|
|||||||
'FeedConverter.js',
|
'FeedConverter.js',
|
||||||
'WebContentConverter.js',
|
'WebContentConverter.js',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
EXTRA_PP_COMPONENTS += [
|
||||||
|
'FeedWriter.js',
|
||||||
|
]
|
||||||
|
@ -19,7 +19,7 @@ DISABLED_EXTRA_COMPONENTS = \
|
|||||||
FirefoxProfileMigrator.js \
|
FirefoxProfileMigrator.js \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
EXTRA_PP_COMPONENTS = \
|
DISABLED_EXTRA_PP_COMPONENTS = \
|
||||||
ChromeProfileMigrator.js \
|
ChromeProfileMigrator.js \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
@ -27,19 +27,19 @@ ifeq ($(OS_ARCH),WINNT)
|
|||||||
DISABLED_EXTRA_COMPONENTS += IEProfileMigrator.js \
|
DISABLED_EXTRA_COMPONENTS += IEProfileMigrator.js \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
EXTRA_PP_COMPONENTS += SafariProfileMigrator.js \
|
DISABLED_EXTRA_PP_COMPONENTS += SafariProfileMigrator.js \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
DEFINES += -DHAS_IE_MIGRATOR -DHAS_SAFARI_MIGRATOR
|
DEFINES += -DHAS_IE_MIGRATOR -DHAS_SAFARI_MIGRATOR
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
|
ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
|
||||||
EXTRA_PP_COMPONENTS += SafariProfileMigrator.js \
|
DISABLED_EXTRA_PP_COMPONENTS += SafariProfileMigrator.js \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
DEFINES += -DHAS_SAFARI_MIGRATOR
|
DEFINES += -DHAS_SAFARI_MIGRATOR
|
||||||
endif
|
endif
|
||||||
|
|
||||||
EXTRA_PP_COMPONENTS += \
|
DISABLED_EXTRA_PP_COMPONENTS += \
|
||||||
BrowserProfileMigrators.manifest \
|
BrowserProfileMigrators.manifest \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
|
@ -20,3 +20,18 @@ if CONFIG['OS_ARCH'] == 'WINNT':
|
|||||||
EXTRA_COMPONENTS += [
|
EXTRA_COMPONENTS += [
|
||||||
'IEProfileMigrator.js',
|
'IEProfileMigrator.js',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
EXTRA_PP_COMPONENTS += [
|
||||||
|
'BrowserProfileMigrators.manifest',
|
||||||
|
'ChromeProfileMigrator.js',
|
||||||
|
]
|
||||||
|
|
||||||
|
if CONFIG['OS_ARCH'] == 'WINNT':
|
||||||
|
EXTRA_PP_COMPONENTS += [
|
||||||
|
'SafariProfileMigrator.js',
|
||||||
|
]
|
||||||
|
|
||||||
|
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
||||||
|
EXTRA_PP_COMPONENTS += [
|
||||||
|
'SafariProfileMigrator.js',
|
||||||
|
]
|
||||||
|
@ -39,3 +39,7 @@ MODULE = 'browsercomps'
|
|||||||
EXTRA_COMPONENTS += [
|
EXTRA_COMPONENTS += [
|
||||||
'BrowserComponents.manifest',
|
'BrowserComponents.manifest',
|
||||||
]
|
]
|
||||||
|
EXTRA_PP_COMPONENTS += [
|
||||||
|
'nsBrowserContentHandler.js',
|
||||||
|
'nsBrowserGlue.js',
|
||||||
|
]
|
||||||
|
@ -317,6 +317,23 @@ BrowserGlue.prototype = {
|
|||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
case "browser-search-engine-modified":
|
||||||
|
if (data != "engine-default" && data != "engine-current") {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Enforce that the search service's defaultEngine is always equal to
|
||||||
|
// its currentEngine. The search service will notify us any time either
|
||||||
|
// of them are changed (either by directly setting the relevant prefs,
|
||||||
|
// i.e. if add-ons try to change this directly, or if the
|
||||||
|
// nsIBrowserSearchService setters are called).
|
||||||
|
let ss = Services.search;
|
||||||
|
if (ss.currentEngine.name == ss.defaultEngine.name)
|
||||||
|
return;
|
||||||
|
if (data == "engine-current")
|
||||||
|
ss.defaultEngine = ss.currentEngine;
|
||||||
|
else
|
||||||
|
ss.currentEngine = ss.defaultEngine;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -351,6 +368,7 @@ BrowserGlue.prototype = {
|
|||||||
#ifdef MOZ_SERVICES_HEALTHREPORT
|
#ifdef MOZ_SERVICES_HEALTHREPORT
|
||||||
os.addObserver(this, "keyword-search", false);
|
os.addObserver(this, "keyword-search", false);
|
||||||
#endif
|
#endif
|
||||||
|
os.addObserver(this, "browser-search-engine-modified", false);
|
||||||
},
|
},
|
||||||
|
|
||||||
// cleanup (called on application shutdown)
|
// cleanup (called on application shutdown)
|
||||||
@ -384,6 +402,7 @@ BrowserGlue.prototype = {
|
|||||||
#ifdef MOZ_SERVICES_HEALTHREPORT
|
#ifdef MOZ_SERVICES_HEALTHREPORT
|
||||||
os.removeObserver(this, "keyword-search");
|
os.removeObserver(this, "keyword-search");
|
||||||
#endif
|
#endif
|
||||||
|
os.removeObserver(this, "browser-search-engine-modified");
|
||||||
},
|
},
|
||||||
|
|
||||||
_onAppDefaults: function BG__onAppDefaults() {
|
_onAppDefaults: function BG__onAppDefaults() {
|
||||||
|
@ -71,7 +71,7 @@
|
|||||||
</hbox>
|
</hbox>
|
||||||
|
|
||||||
<!-- Tracking -->
|
<!-- Tracking -->
|
||||||
<groupbox id="trackingGroup" data-category="panePrivacy" hidden="true">
|
<groupbox id="trackingGroup" data-category="panePrivacy" hidden="true" align="start">
|
||||||
<caption label="&tracking.label;"/>
|
<caption label="&tracking.label;"/>
|
||||||
<radiogroup id="doNotTrackSelection" orient="vertical"
|
<radiogroup id="doNotTrackSelection" orient="vertical"
|
||||||
preference="privacy.donottrackheader.value"
|
preference="privacy.donottrackheader.value"
|
||||||
|
@ -82,7 +82,7 @@
|
|||||||
<script type="application/javascript" src="chrome://browser/content/preferences/privacy.js"/>
|
<script type="application/javascript" src="chrome://browser/content/preferences/privacy.js"/>
|
||||||
|
|
||||||
<!-- Tracking -->
|
<!-- Tracking -->
|
||||||
<groupbox id="trackingGroup">
|
<groupbox id="trackingGroup" align="start">
|
||||||
<caption label="&tracking.label;"/>
|
<caption label="&tracking.label;"/>
|
||||||
<radiogroup id="doNotTrackSelection" orient="vertical"
|
<radiogroup id="doNotTrackSelection" orient="vertical"
|
||||||
preference="privacy.donottrackheader.value"
|
preference="privacy.donottrackheader.value"
|
||||||
|
@ -488,17 +488,22 @@
|
|||||||
<handlers>
|
<handlers>
|
||||||
<handler event="command"><![CDATA[
|
<handler event="command"><![CDATA[
|
||||||
const target = event.originalTarget;
|
const target = event.originalTarget;
|
||||||
if (target.classList.contains("addengine-item")) {
|
if (target.engine) {
|
||||||
|
this.currentEngine = target.engine;
|
||||||
|
} else if (target.classList.contains("addengine-item")) {
|
||||||
var searchService =
|
var searchService =
|
||||||
Components.classes["@mozilla.org/browser/search-service;1"]
|
Components.classes["@mozilla.org/browser/search-service;1"]
|
||||||
.getService(Components.interfaces.nsIBrowserSearchService);
|
.getService(Components.interfaces.nsIBrowserSearchService);
|
||||||
// We only detect OpenSearch files
|
// We only detect OpenSearch files
|
||||||
var type = Components.interfaces.nsISearchEngine.DATA_XML;
|
var type = Components.interfaces.nsISearchEngine.DATA_XML;
|
||||||
|
// Select the installed engine if the installation succeeds
|
||||||
|
var installCallback = {
|
||||||
|
onSuccess: engine => this.currentEngine = engine
|
||||||
|
}
|
||||||
searchService.addEngine(target.getAttribute("uri"), type,
|
searchService.addEngine(target.getAttribute("uri"), type,
|
||||||
target.getAttribute("src"), false);
|
target.getAttribute("src"), false,
|
||||||
|
installCallback);
|
||||||
}
|
}
|
||||||
else if (target.engine)
|
|
||||||
this.currentEngine = target.engine;
|
|
||||||
else
|
else
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -30,8 +30,7 @@ function test() {
|
|||||||
case "engine-added":
|
case "engine-added":
|
||||||
var engine = ss.getEngineByName("Bug 426329");
|
var engine = ss.getEngineByName("Bug 426329");
|
||||||
ok(engine, "Engine was added.");
|
ok(engine, "Engine was added.");
|
||||||
//XXX Bug 493051
|
ss.currentEngine = engine;
|
||||||
//ss.currentEngine = engine;
|
|
||||||
break;
|
break;
|
||||||
case "engine-current":
|
case "engine-current":
|
||||||
ok(ss.currentEngine.name == "Bug 426329", "currentEngine set");
|
ok(ss.currentEngine.name == "Bug 426329", "currentEngine set");
|
||||||
|
@ -16,8 +16,7 @@ function test() {
|
|||||||
case "engine-added":
|
case "engine-added":
|
||||||
var engine = ss.getEngineByName(ENGINE_NAME);
|
var engine = ss.getEngineByName(ENGINE_NAME);
|
||||||
ok(engine, "Engine was added.");
|
ok(engine, "Engine was added.");
|
||||||
//XXX Bug 493051
|
ss.currentEngine = engine;
|
||||||
//ss.currentEngine = engine;
|
|
||||||
break;
|
break;
|
||||||
case "engine-current":
|
case "engine-current":
|
||||||
is(ss.currentEngine.name, ENGINE_NAME, "currentEngine set");
|
is(ss.currentEngine.name, ENGINE_NAME, "currentEngine set");
|
||||||
|
@ -66,7 +66,7 @@ function test() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
EventUtils.synthesizeKey("VK_RETURN", {});
|
EventUtils.synthesizeKey("VK_RETURN", {});
|
||||||
executeSoon(afterSearch);
|
executeSoon(() => executeSoon(afterSearch));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -42,20 +42,18 @@ function test() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function addEngine(aCallback) {
|
function addEngine(aCallback) {
|
||||||
function observer(aSub, aTopic, aData) {
|
let installCallback = {
|
||||||
switch (aData) {
|
onSuccess: function (engine) {
|
||||||
case "engine-current":
|
Services.search.currentEngine = engine;
|
||||||
ok(Services.search.currentEngine.name == "Bug 426329",
|
aCallback();
|
||||||
"currentEngine set");
|
},
|
||||||
aCallback();
|
onError: function (errorCode) {
|
||||||
break;
|
ok(false, "failed to install engine: " + errorCode);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
Services.search.addEngine(engineURL + "426329.xml",
|
||||||
Services.obs.addObserver(observer, "browser-search-engine-modified", false);
|
Ci.nsISearchEngine.DATA_XML,
|
||||||
Services.search.addEngine(
|
"data:image/x-icon,%00", false, installCallback);
|
||||||
engineURL + "426329.xml", Ci.nsISearchEngine.DATA_XML,
|
|
||||||
"data:image/x-icon,%00", false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function testOnWindow(aIsPrivate, aCallback) {
|
function testOnWindow(aIsPrivate, aCallback) {
|
||||||
|
@ -494,23 +494,16 @@ let SessionStoreInternal = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
_initWindow: function ssi_initWindow(aWindow) {
|
_initWindow: function ssi_initWindow(aWindow) {
|
||||||
if (!aWindow || this._loadState == STATE_RUNNING) {
|
if (aWindow) {
|
||||||
// make sure that all browser windows which try to initialize
|
this.onLoad(aWindow);
|
||||||
// SessionStore are really tracked by it
|
} else if (this._loadState == STATE_STOPPED) {
|
||||||
if (aWindow && (!aWindow.__SSi || !this._windows[aWindow.__SSi]))
|
|
||||||
this.onLoad(aWindow);
|
|
||||||
// If init is being called with a null window, it's possible that we
|
// If init is being called with a null window, it's possible that we
|
||||||
// just want to tell sessionstore that a session is live (as is the case
|
// just want to tell sessionstore that a session is live (as is the case
|
||||||
// with starting Firefox with -private, for example; see bug 568816),
|
// with starting Firefox with -private, for example; see bug 568816),
|
||||||
// so we should mark the load state as running to make sure that
|
// so we should mark the load state as running to make sure that
|
||||||
// things like setBrowserState calls will succeed in restoring the session.
|
// things like setBrowserState calls will succeed in restoring the session.
|
||||||
if (!aWindow && this._loadState == STATE_STOPPED)
|
this._loadState = STATE_RUNNING;
|
||||||
this._loadState = STATE_RUNNING;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// As this is called at delayedStartup, restoration must be initiated here
|
|
||||||
this.onLoad(aWindow);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -747,7 +740,7 @@ let SessionStoreInternal = {
|
|||||||
this._deferredInitialState._firstTabs = true;
|
this._deferredInitialState._firstTabs = true;
|
||||||
this._restoreCount = this._deferredInitialState.windows ?
|
this._restoreCount = this._deferredInitialState.windows ?
|
||||||
this._deferredInitialState.windows.length : 0;
|
this._deferredInitialState.windows.length : 0;
|
||||||
this.restoreWindow(aWindow, this._deferredInitialState, true);
|
this.restoreWindow(aWindow, this._deferredInitialState, false);
|
||||||
this._deferredInitialState = null;
|
this._deferredInitialState = null;
|
||||||
}
|
}
|
||||||
else if (this._restoreLastWindow && aWindow.toolbar.visible &&
|
else if (this._restoreLastWindow && aWindow.toolbar.visible &&
|
||||||
|
@ -1920,6 +1920,7 @@ let GroupItems = {
|
|||||||
minGroupHeight: 110,
|
minGroupHeight: 110,
|
||||||
minGroupWidth: 125,
|
minGroupWidth: 125,
|
||||||
_lastActiveList: null,
|
_lastActiveList: null,
|
||||||
|
_lastGroupToUpdateTabBar: null,
|
||||||
|
|
||||||
// ----------
|
// ----------
|
||||||
// Function: toString
|
// Function: toString
|
||||||
@ -2285,6 +2286,10 @@ let GroupItems = {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this._lastActiveList.remove(groupItem);
|
this._lastActiveList.remove(groupItem);
|
||||||
|
|
||||||
|
if (this._lastGroupToUpdateTabBar == groupItem)
|
||||||
|
this._lastGroupToUpdateTabBar = null;
|
||||||
|
|
||||||
UI.updateTabButton();
|
UI.updateTabButton();
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -2418,8 +2423,13 @@ let GroupItems = {
|
|||||||
|
|
||||||
Utils.assert(this._activeGroupItem, "There must be something to show in the tab bar!");
|
Utils.assert(this._activeGroupItem, "There must be something to show in the tab bar!");
|
||||||
|
|
||||||
|
// Update list of visible tabs only once after switching to another group.
|
||||||
|
if (this._activeGroupItem == this._lastGroupToUpdateTabBar)
|
||||||
|
return;
|
||||||
|
|
||||||
let tabItems = this._activeGroupItem._children;
|
let tabItems = this._activeGroupItem._children;
|
||||||
gBrowser.showOnlyTheseTabs(tabItems.map(function(item) item.tab));
|
gBrowser.showOnlyTheseTabs(tabItems.map(function(item) item.tab));
|
||||||
|
this._lastGroupToUpdateTabBar = this._activeGroupItem;
|
||||||
},
|
},
|
||||||
|
|
||||||
// ----------
|
// ----------
|
||||||
@ -2537,7 +2547,7 @@ let GroupItems = {
|
|||||||
if (tab._tabViewTabItem.parent && tab._tabViewTabItem.parent.id == groupItemId)
|
if (tab._tabViewTabItem.parent && tab._tabViewTabItem.parent.id == groupItemId)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
let shouldUpdateTabBar = false;
|
let shouldHideTab = false;
|
||||||
let shouldShowTabView = false;
|
let shouldShowTabView = false;
|
||||||
let groupItem;
|
let groupItem;
|
||||||
|
|
||||||
@ -2545,12 +2555,12 @@ let GroupItems = {
|
|||||||
if (tab.selected) {
|
if (tab.selected) {
|
||||||
if (gBrowser.visibleTabs.length > 1) {
|
if (gBrowser.visibleTabs.length > 1) {
|
||||||
gBrowser._blurTab(tab);
|
gBrowser._blurTab(tab);
|
||||||
shouldUpdateTabBar = true;
|
shouldHideTab = true;
|
||||||
} else {
|
} else {
|
||||||
shouldShowTabView = true;
|
shouldShowTabView = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
shouldUpdateTabBar = true
|
shouldHideTab = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove tab item from a groupItem
|
// remove tab item from a groupItem
|
||||||
@ -2573,8 +2583,8 @@ let GroupItems = {
|
|||||||
new GroupItem([ tab._tabViewTabItem ], { bounds: box, immediately: true });
|
new GroupItem([ tab._tabViewTabItem ], { bounds: box, immediately: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shouldUpdateTabBar)
|
if (shouldHideTab)
|
||||||
this._updateTabBar();
|
gBrowser.hideTab(tab);
|
||||||
else if (shouldShowTabView)
|
else if (shouldShowTabView)
|
||||||
UI.showTabView();
|
UI.showTabView();
|
||||||
},
|
},
|
||||||
|
@ -99,47 +99,14 @@ function test() {
|
|||||||
}, aWindow);
|
}, aWindow);
|
||||||
}
|
}
|
||||||
|
|
||||||
// [624102] check state after return from private browsing
|
function testOnWindow(aCallback) {
|
||||||
let testPrivateBrowsing = function (aWindow) {
|
let win = OpenBrowserWindow({private: false});
|
||||||
aWindow.gBrowser.loadOneTab('http://mochi.test:8888/#1', {inBackground: true});
|
|
||||||
aWindow.gBrowser.loadOneTab('http://mochi.test:8888/#2', {inBackground: true});
|
|
||||||
|
|
||||||
let cw = getContentWindow(aWindow);
|
|
||||||
let box = new cw.Rect(20, 20, 250, 200);
|
|
||||||
let groupItem = new cw.GroupItem([], {bounds: box, immediately: true});
|
|
||||||
cw.UI.setActive(groupItem);
|
|
||||||
|
|
||||||
aWindow.gBrowser.selectedTab = aWindow.gBrowser.loadOneTab('http://mochi.test:8888/#3', {inBackground: true});
|
|
||||||
aWindow.gBrowser.loadOneTab('http://mochi.test:8888/#4', {inBackground: true});
|
|
||||||
|
|
||||||
afterAllTabsLoaded(function () {
|
|
||||||
assertNumberOfVisibleTabs(aWindow, 2);
|
|
||||||
|
|
||||||
enterAndLeavePrivateBrowsing(function () {
|
|
||||||
assertNumberOfVisibleTabs(aWindow, 2);
|
|
||||||
aWindow.gBrowser.selectedTab = aWindow.gBrowser.tabs[0];
|
|
||||||
closeGroupItem(cw.GroupItems.groupItems[1], function() {
|
|
||||||
next(aWindow);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}, aWindow);
|
|
||||||
}
|
|
||||||
|
|
||||||
function testOnWindow(aIsPrivate, aCallback) {
|
|
||||||
let win = OpenBrowserWindow({private: aIsPrivate});
|
|
||||||
win.addEventListener("load", function onLoad() {
|
win.addEventListener("load", function onLoad() {
|
||||||
win.removeEventListener("load", onLoad, false);
|
win.removeEventListener("load", onLoad, false);
|
||||||
executeSoon(function() { aCallback(win) });
|
executeSoon(function() { aCallback(win) });
|
||||||
}, false);
|
}, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
function enterAndLeavePrivateBrowsing(callback) {
|
|
||||||
testOnWindow(true, function (aWindow) {
|
|
||||||
aWindow.close();
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
waitForExplicitFinish();
|
waitForExplicitFinish();
|
||||||
|
|
||||||
// Tests for #624265
|
// Tests for #624265
|
||||||
@ -149,10 +116,7 @@ function test() {
|
|||||||
tests.push(testDuplicateTab);
|
tests.push(testDuplicateTab);
|
||||||
tests.push(testBackForwardDuplicateTab);
|
tests.push(testBackForwardDuplicateTab);
|
||||||
|
|
||||||
// Tests for #624102
|
testOnWindow(function(aWindow) {
|
||||||
tests.push(testPrivateBrowsing);
|
|
||||||
|
|
||||||
testOnWindow(false, function(aWindow) {
|
|
||||||
loadTabView(function() {
|
loadTabView(function() {
|
||||||
next(aWindow);
|
next(aWindow);
|
||||||
}, aWindow);
|
}, aWindow);
|
||||||
@ -163,4 +127,4 @@ function loadTabView(callback, aWindow) {
|
|||||||
showTabView(function () {
|
showTabView(function () {
|
||||||
hideTabView(callback, aWindow);
|
hideTabView(callback, aWindow);
|
||||||
}, aWindow);
|
}, aWindow);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
ac_add_options --enable-debug
|
ac_add_options --enable-debug
|
||||||
ac_add_options --enable-trace-malloc
|
ac_add_options --enable-trace-malloc
|
||||||
ac_add_options --enable-signmar
|
ac_add_options --enable-signmar
|
||||||
ENABLE_MARIONETTE=1
|
|
||||||
|
|
||||||
. $topsrcdir/build/unix/mozconfig.linux32
|
. $topsrcdir/build/unix/mozconfig.linux32
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
ac_add_options --enable-debug
|
ac_add_options --enable-debug
|
||||||
ac_add_options --enable-trace-malloc
|
ac_add_options --enable-trace-malloc
|
||||||
ac_add_options --enable-signmar
|
ac_add_options --enable-signmar
|
||||||
ENABLE_MARIONETTE=1
|
|
||||||
|
|
||||||
. $topsrcdir/build/unix/mozconfig.linux
|
. $topsrcdir/build/unix/mozconfig.linux
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@ ac_add_options --enable-debug
|
|||||||
ac_add_options --enable-trace-malloc
|
ac_add_options --enable-trace-malloc
|
||||||
ac_add_options --enable-accessibility
|
ac_add_options --enable-accessibility
|
||||||
ac_add_options --enable-signmar
|
ac_add_options --enable-signmar
|
||||||
ENABLE_MARIONETTE=1
|
|
||||||
|
|
||||||
# Needed to enable breakpad in application.ini
|
# Needed to enable breakpad in application.ini
|
||||||
export MOZILLA_OFFICIAL=1
|
export MOZILLA_OFFICIAL=1
|
||||||
|
@ -5,8 +5,6 @@ ac_add_options --enable-trace-malloc
|
|||||||
ac_add_options --enable-signmar
|
ac_add_options --enable-signmar
|
||||||
ac_add_options --enable-metro
|
ac_add_options --enable-metro
|
||||||
|
|
||||||
ENABLE_MARIONETTE=1
|
|
||||||
|
|
||||||
# Needed to enable breakpad in application.ini
|
# Needed to enable breakpad in application.ini
|
||||||
export MOZILLA_OFFICIAL=1
|
export MOZILLA_OFFICIAL=1
|
||||||
|
|
||||||
|
@ -7,7 +7,6 @@ ac_add_options --enable-debug
|
|||||||
ac_add_options --enable-trace-malloc
|
ac_add_options --enable-trace-malloc
|
||||||
ac_add_options --enable-signmar
|
ac_add_options --enable-signmar
|
||||||
ac_add_options --enable-metro
|
ac_add_options --enable-metro
|
||||||
ENABLE_MARIONETTE=1
|
|
||||||
|
|
||||||
# Needed to enable breakpad in application.ini
|
# Needed to enable breakpad in application.ini
|
||||||
export MOZILLA_OFFICIAL=1
|
export MOZILLA_OFFICIAL=1
|
||||||
|
@ -24,6 +24,7 @@ Cu.import("resource:///modules/devtools/LayoutHelpers.jsm");
|
|||||||
Cu.import("resource:///modules/devtools/BreadcrumbsWidget.jsm");
|
Cu.import("resource:///modules/devtools/BreadcrumbsWidget.jsm");
|
||||||
Cu.import("resource:///modules/devtools/SideMenuWidget.jsm");
|
Cu.import("resource:///modules/devtools/SideMenuWidget.jsm");
|
||||||
Cu.import("resource:///modules/devtools/VariablesView.jsm");
|
Cu.import("resource:///modules/devtools/VariablesView.jsm");
|
||||||
|
Cu.import("resource:///modules/devtools/VariablesViewController.jsm");
|
||||||
Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
|
Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
|
||||||
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "Parser",
|
XPCOMUtils.defineLazyModuleGetter(this, "Parser",
|
||||||
@ -73,6 +74,24 @@ let DebuggerController = {
|
|||||||
DebuggerView.initialize(() => {
|
DebuggerView.initialize(() => {
|
||||||
DebuggerView._isInitialized = true;
|
DebuggerView._isInitialized = true;
|
||||||
|
|
||||||
|
VariablesViewController.attach(DebuggerView.Variables, {
|
||||||
|
getGripClient: aObject => {
|
||||||
|
return this.activeThread.pauseGrip(aObject);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Relay events from the VariablesView.
|
||||||
|
DebuggerView.Variables.on("fetched", (aEvent, aType) => {
|
||||||
|
switch (aType) {
|
||||||
|
case "variables":
|
||||||
|
window.dispatchEvent(document, "Debugger:FetchedVariables");
|
||||||
|
break;
|
||||||
|
case "properties":
|
||||||
|
window.dispatchEvent(document, "Debugger:FetchedProperties");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Chrome debugging needs to initiate the connection by itself.
|
// Chrome debugging needs to initiate the connection by itself.
|
||||||
if (window._isChromeDebugger) {
|
if (window._isChromeDebugger) {
|
||||||
this.connect().then(deferred.resolve);
|
this.connect().then(deferred.resolve);
|
||||||
@ -403,6 +422,7 @@ ThreadState.prototype = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Keeps the stack frame list up-to-date, using the thread client's
|
* Keeps the stack frame list up-to-date, using the thread client's
|
||||||
* stack frame cache.
|
* stack frame cache.
|
||||||
@ -413,9 +433,6 @@ function StackFrames() {
|
|||||||
this._onFrames = this._onFrames.bind(this);
|
this._onFrames = this._onFrames.bind(this);
|
||||||
this._onFramesCleared = this._onFramesCleared.bind(this);
|
this._onFramesCleared = this._onFramesCleared.bind(this);
|
||||||
this._afterFramesCleared = this._afterFramesCleared.bind(this);
|
this._afterFramesCleared = this._afterFramesCleared.bind(this);
|
||||||
this._fetchScopeVariables = this._fetchScopeVariables.bind(this);
|
|
||||||
this._fetchVarProperties = this._fetchVarProperties.bind(this);
|
|
||||||
this._addVarExpander = this._addVarExpander.bind(this);
|
|
||||||
this.evaluate = this.evaluate.bind(this);
|
this.evaluate = this.evaluate.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -588,7 +605,12 @@ StackFrames.prototype = {
|
|||||||
DebuggerView.StackFrames.empty();
|
DebuggerView.StackFrames.empty();
|
||||||
|
|
||||||
for (let frame of this.activeThread.cachedFrames) {
|
for (let frame of this.activeThread.cachedFrames) {
|
||||||
this._addFrame(frame);
|
let depth = frame.depth;
|
||||||
|
let { url, line } = frame.where;
|
||||||
|
let frameLocation = NetworkHelper.convertToUnicode(unescape(url));
|
||||||
|
let frameTitle = StackFrameUtils.getFrameTitle(frame);
|
||||||
|
|
||||||
|
DebuggerView.StackFrames.addFrame(frameTitle, frameLocation, line, depth);
|
||||||
}
|
}
|
||||||
if (this.currentFrame == null) {
|
if (this.currentFrame == null) {
|
||||||
DebuggerView.StackFrames.selectedDepth = 0;
|
DebuggerView.StackFrames.selectedDepth = 0;
|
||||||
@ -661,6 +683,7 @@ StackFrames.prototype = {
|
|||||||
// Clear existing scopes and create each one dynamically.
|
// Clear existing scopes and create each one dynamically.
|
||||||
DebuggerView.Variables.empty();
|
DebuggerView.Variables.empty();
|
||||||
|
|
||||||
|
|
||||||
// If watch expressions evaluation results are available, create a scope
|
// If watch expressions evaluation results are available, create a scope
|
||||||
// to contain all the values.
|
// to contain all the values.
|
||||||
if (this.syncedWatchExpressions && watchExpressionsEvaluation) {
|
if (this.syncedWatchExpressions && watchExpressionsEvaluation) {
|
||||||
@ -684,18 +707,20 @@ StackFrames.prototype = {
|
|||||||
// Create a scope to contain all the inspected variables.
|
// Create a scope to contain all the inspected variables.
|
||||||
let label = StackFrameUtils.getScopeLabel(environment);
|
let label = StackFrameUtils.getScopeLabel(environment);
|
||||||
let scope = DebuggerView.Variables.addScope(label);
|
let scope = DebuggerView.Variables.addScope(label);
|
||||||
|
let innermost = environment == frame.environment;
|
||||||
|
|
||||||
// Handle additions to the innermost scope.
|
// Handle special additions to the innermost scope.
|
||||||
if (environment == frame.environment) {
|
if (innermost) {
|
||||||
this._insertScopeFrameReferences(scope, frame);
|
this._insertScopeFrameReferences(scope, frame);
|
||||||
this._addScopeExpander(scope, environment);
|
|
||||||
// Always expand the innermost scope by default.
|
|
||||||
scope.expand();
|
|
||||||
}
|
}
|
||||||
// Lazily add nodes for every other environment scope.
|
|
||||||
else {
|
DebuggerView.Variables.controller.addExpander(scope, environment);
|
||||||
this._addScopeExpander(scope, environment);
|
|
||||||
this.autoScopeExpand && scope.expand();
|
// The innermost scope is always automatically expanded, because it
|
||||||
|
// contains the variables in the current stack frame which are likely to
|
||||||
|
// be inspected.
|
||||||
|
if (innermost || this.autoScopeExpand) {
|
||||||
|
scope.expand();
|
||||||
}
|
}
|
||||||
} while ((environment = environment.parent));
|
} while ((environment = environment.parent));
|
||||||
|
|
||||||
@ -704,49 +729,6 @@ StackFrames.prototype = {
|
|||||||
DebuggerView.Variables.commitHierarchy();
|
DebuggerView.Variables.commitHierarchy();
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds an 'onexpand' callback for a scope, lazily handling
|
|
||||||
* the addition of new variables.
|
|
||||||
*
|
|
||||||
* @param Scope aScope
|
|
||||||
* The scope where the variables will be placed into.
|
|
||||||
* @param object aEnv
|
|
||||||
* The scope's environment.
|
|
||||||
*/
|
|
||||||
_addScopeExpander: function(aScope, aEnv) {
|
|
||||||
aScope._sourceEnvironment = aEnv;
|
|
||||||
|
|
||||||
// It's a good idea to be prepared in case of an expansion.
|
|
||||||
aScope.addEventListener("mouseover", this._fetchScopeVariables, false);
|
|
||||||
// Make sure that variables are always available on expansion.
|
|
||||||
aScope.onexpand = this._fetchScopeVariables;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds an 'onexpand' callback for a variable, lazily handling
|
|
||||||
* the addition of new properties.
|
|
||||||
*
|
|
||||||
* @param Variable aVar
|
|
||||||
* The variable where the properties will be placed into.
|
|
||||||
* @param any aGrip
|
|
||||||
* The grip of the variable.
|
|
||||||
*/
|
|
||||||
_addVarExpander: function(aVar, aGrip) {
|
|
||||||
// No need for expansion for primitive values.
|
|
||||||
if (VariablesView.isPrimitive({ value: aGrip })) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
aVar._sourceGrip = aGrip;
|
|
||||||
|
|
||||||
// Some variables are likely to contain a very large number of properties.
|
|
||||||
// It's a good idea to be prepared in case of an expansion.
|
|
||||||
if (aVar.name == "window" || aVar.name == "this") {
|
|
||||||
aVar.addEventListener("mouseover", this._fetchVarProperties, false);
|
|
||||||
}
|
|
||||||
// Make sure that properties are always available on expansion.
|
|
||||||
aVar.onexpand = this._fetchVarProperties;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the watch expressions evaluation results to a scope in the view.
|
* Adds the watch expressions evaluation results to a scope in the view.
|
||||||
*
|
*
|
||||||
@ -770,8 +752,8 @@ StackFrames.prototype = {
|
|||||||
for (let i = 0; i < totalExpressions; i++) {
|
for (let i = 0; i < totalExpressions; i++) {
|
||||||
let name = DebuggerView.WatchExpressions.getExpression(i);
|
let name = DebuggerView.WatchExpressions.getExpression(i);
|
||||||
let expVal = ownProperties[i].value;
|
let expVal = ownProperties[i].value;
|
||||||
let expRef = aScope.addVar(name, ownProperties[i]);
|
let expRef = aScope.addItem(name, ownProperties[i]);
|
||||||
this._addVarExpander(expRef, expVal);
|
DebuggerView.Variables.controller.addExpander(expRef, expVal);
|
||||||
|
|
||||||
// Revert some of the custom watch expressions scope presentation flags.
|
// Revert some of the custom watch expressions scope presentation flags.
|
||||||
expRef.switch = null;
|
expRef.switch = null;
|
||||||
@ -786,51 +768,6 @@ StackFrames.prototype = {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds variables to a scope in the view. Triggered when a scope is
|
|
||||||
* expanded or is hovered. It does not expand the scope.
|
|
||||||
*
|
|
||||||
* @param Scope aScope
|
|
||||||
* The scope where the variables will be placed into.
|
|
||||||
*/
|
|
||||||
_fetchScopeVariables: function(aScope) {
|
|
||||||
// Fetch the variables only once.
|
|
||||||
if (aScope._fetched) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
aScope._fetched = true;
|
|
||||||
let env = aScope._sourceEnvironment;
|
|
||||||
|
|
||||||
switch (env.type) {
|
|
||||||
case "with":
|
|
||||||
case "object":
|
|
||||||
// Add nodes for every variable in scope.
|
|
||||||
this.activeThread.pauseGrip(env.object).getPrototypeAndProperties((aResponse) => {
|
|
||||||
let { ownProperties, safeGetterValues } = aResponse;
|
|
||||||
this._mergeSafeGetterValues(ownProperties, safeGetterValues);
|
|
||||||
this._insertScopeVariables(ownProperties, aScope);
|
|
||||||
|
|
||||||
// Signal that variables have been fetched.
|
|
||||||
window.dispatchEvent(document, "Debugger:FetchedVariables");
|
|
||||||
DebuggerView.Variables.commitHierarchy();
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
case "block":
|
|
||||||
case "function":
|
|
||||||
// Add nodes for every argument and every other variable in scope.
|
|
||||||
this._insertScopeArguments(env.bindings.arguments, aScope);
|
|
||||||
this._insertScopeVariables(env.bindings.variables, aScope);
|
|
||||||
|
|
||||||
// No need to signal that variables have been fetched, since
|
|
||||||
// the scope arguments and variables are already attached to the
|
|
||||||
// environment bindings, so pausing the active thread is unnecessary.
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
Cu.reportError("Unknown Debugger.Environment type: " + env.type);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add nodes for special frame references in the innermost scope.
|
* Add nodes for special frame references in the innermost scope.
|
||||||
*
|
*
|
||||||
@ -842,154 +779,21 @@ StackFrames.prototype = {
|
|||||||
_insertScopeFrameReferences: function(aScope, aFrame) {
|
_insertScopeFrameReferences: function(aScope, aFrame) {
|
||||||
// Add any thrown exception.
|
// Add any thrown exception.
|
||||||
if (this.currentException) {
|
if (this.currentException) {
|
||||||
let excRef = aScope.addVar("<exception>", { value: this.currentException });
|
let excRef = aScope.addItem("<exception>", { value: this.currentException });
|
||||||
this._addVarExpander(excRef, this.currentException);
|
DebuggerView.Variables.controller.addExpander(excRef, this.currentException);
|
||||||
}
|
}
|
||||||
// Add any returned value.
|
// Add any returned value.
|
||||||
if (this.currentReturnedValue) {
|
if (this.currentReturnedValue) {
|
||||||
let retRef = aScope.addVar("<return>", { value: this.currentReturnedValue });
|
let retRef = aScope.addItem("<return>", { value: this.currentReturnedValue });
|
||||||
this._addVarExpander(retRef, this.currentReturnedValue);
|
DebuggerView.Variables.controller.addExpander(retRef, this.currentReturnedValue);
|
||||||
}
|
}
|
||||||
// Add "this".
|
// Add "this".
|
||||||
if (aFrame.this) {
|
if (aFrame.this) {
|
||||||
let thisRef = aScope.addVar("this", { value: aFrame.this });
|
let thisRef = aScope.addItem("this", { value: aFrame.this });
|
||||||
this._addVarExpander(thisRef, aFrame.this);
|
DebuggerView.Variables.controller.addExpander(thisRef, aFrame.this);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* Add nodes for every argument in scope.
|
|
||||||
*
|
|
||||||
* @param object aArguments
|
|
||||||
* The map of names to arguments, as specified in the protocol.
|
|
||||||
* @param Scope aScope
|
|
||||||
* The scope where the nodes will be placed into.
|
|
||||||
*/
|
|
||||||
_insertScopeArguments: function(aArguments, aScope) {
|
|
||||||
if (!aArguments) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (let argument of aArguments) {
|
|
||||||
let name = Object.getOwnPropertyNames(argument)[0];
|
|
||||||
let argRef = aScope.addVar(name, argument[name]);
|
|
||||||
let argVal = argument[name].value;
|
|
||||||
this._addVarExpander(argRef, argVal);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add nodes for every variable in scope.
|
|
||||||
*
|
|
||||||
* @param object aVariables
|
|
||||||
* The map of names to variables, as specified in the protocol.
|
|
||||||
* @param Scope aScope
|
|
||||||
* The scope where the nodes will be placed into.
|
|
||||||
*/
|
|
||||||
_insertScopeVariables: function(aVariables, aScope) {
|
|
||||||
if (!aVariables) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let variableNames = Object.keys(aVariables);
|
|
||||||
|
|
||||||
// Sort all of the variables before adding them, if preferred.
|
|
||||||
if (Prefs.variablesSortingEnabled) {
|
|
||||||
variableNames.sort();
|
|
||||||
}
|
|
||||||
// Add the variables to the specified scope.
|
|
||||||
for (let name of variableNames) {
|
|
||||||
let varRef = aScope.addVar(name, aVariables[name]);
|
|
||||||
let varVal = aVariables[name].value;
|
|
||||||
this._addVarExpander(varRef, varVal);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds properties to a variable in the view. Triggered when a variable is
|
|
||||||
* expanded or certain variables are hovered. It does not expand the variable.
|
|
||||||
*
|
|
||||||
* @param Variable aVar
|
|
||||||
* The variable where the properties will be placed into.
|
|
||||||
*/
|
|
||||||
_fetchVarProperties: function(aVar) {
|
|
||||||
// Fetch the properties only once.
|
|
||||||
if (aVar._fetched) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
aVar._fetched = true;
|
|
||||||
let grip = aVar._sourceGrip;
|
|
||||||
|
|
||||||
this.activeThread.pauseGrip(grip).getPrototypeAndProperties((aResponse) => {
|
|
||||||
let { ownProperties, prototype, safeGetterValues } = aResponse;
|
|
||||||
let sortable = VariablesView.NON_SORTABLE_CLASSES.indexOf(grip.class) == -1;
|
|
||||||
|
|
||||||
this._mergeSafeGetterValues(ownProperties, safeGetterValues);
|
|
||||||
|
|
||||||
// Add all the variable properties.
|
|
||||||
if (ownProperties) {
|
|
||||||
aVar.addProperties(ownProperties, {
|
|
||||||
// Not all variables need to force sorted properties.
|
|
||||||
sorted: sortable,
|
|
||||||
// Expansion handlers must be set after the properties are added.
|
|
||||||
callback: this._addVarExpander
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the variable's __proto__.
|
|
||||||
if (prototype && prototype.type != "null") {
|
|
||||||
aVar.addProperty("__proto__", { value: prototype });
|
|
||||||
// Expansion handlers must be set after the properties are added.
|
|
||||||
this._addVarExpander(aVar.get("__proto__"), prototype);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mark the variable as having retrieved all its properties.
|
|
||||||
aVar._retrieved = true;
|
|
||||||
|
|
||||||
// Signal that properties have been fetched.
|
|
||||||
window.dispatchEvent(document, "Debugger:FetchedProperties");
|
|
||||||
DebuggerView.Variables.commitHierarchy();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Merge the safe getter values descriptors into the "own properties" object
|
|
||||||
* that comes from a "prototypeAndProperties" response packet. This is needed
|
|
||||||
* for Variables View.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @param object aOwnProperties
|
|
||||||
* The |ownProperties| object that will get the new safe getter values.
|
|
||||||
* @param object aSafeGetterValues
|
|
||||||
* The |safeGetterValues| object.
|
|
||||||
*/
|
|
||||||
_mergeSafeGetterValues: function(aOwnProperties, aSafeGetterValues) {
|
|
||||||
// Merge the safe getter values into one object such that we can use it
|
|
||||||
// in VariablesView.
|
|
||||||
for (let name of Object.keys(aSafeGetterValues)) {
|
|
||||||
if (name in aOwnProperties) {
|
|
||||||
aOwnProperties[name].getterValue = aSafeGetterValues[name].getterValue;
|
|
||||||
aOwnProperties[name].getterPrototypeLevel =
|
|
||||||
aSafeGetterValues[name].getterPrototypeLevel;
|
|
||||||
} else {
|
|
||||||
aOwnProperties[name] = aSafeGetterValues[name];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds the specified stack frame to the list.
|
|
||||||
*
|
|
||||||
* @param object aFrame
|
|
||||||
* The new frame to add.
|
|
||||||
*/
|
|
||||||
_addFrame: function(aFrame) {
|
|
||||||
let depth = aFrame.depth;
|
|
||||||
let { url, line } = aFrame.where;
|
|
||||||
let frameLocation = NetworkHelper.convertToUnicode(unescape(url));
|
|
||||||
let frameTitle = StackFrameUtils.getFrameTitle(aFrame);
|
|
||||||
|
|
||||||
DebuggerView.StackFrames.addFrame(frameTitle, frameLocation, line, depth);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads more stack frames from the debugger server cache.
|
* Loads more stack frames from the debugger server cache.
|
||||||
*/
|
*/
|
||||||
|
@ -24,9 +24,9 @@ function testNonEnumProperties() {
|
|||||||
Services.tm.currentThread.dispatch({ run: function() {
|
Services.tm.currentThread.dispatch({ run: function() {
|
||||||
|
|
||||||
let testScope = gDebugger.DebuggerView.Variables.addScope("test-scope");
|
let testScope = gDebugger.DebuggerView.Variables.addScope("test-scope");
|
||||||
let testVar = testScope.addVar("foo");
|
let testVar = testScope.addItem("foo");
|
||||||
|
|
||||||
testVar.addProperties({
|
testVar.addItems({
|
||||||
foo: {
|
foo: {
|
||||||
value: "bar",
|
value: "bar",
|
||||||
enumerable: true
|
enumerable: true
|
||||||
|
@ -24,8 +24,8 @@ function testSimpleCall() {
|
|||||||
Services.tm.currentThread.dispatch({ run: function() {
|
Services.tm.currentThread.dispatch({ run: function() {
|
||||||
|
|
||||||
let testScope = gDebugger.DebuggerView.Variables.addScope("test-scope");
|
let testScope = gDebugger.DebuggerView.Variables.addScope("test-scope");
|
||||||
let testVar = testScope.addVar("something");
|
let testVar = testScope.addItem("something");
|
||||||
let duplVar = testScope.addVar("something");
|
let duplVar = testScope.addItem("something");
|
||||||
|
|
||||||
info("Scope id: " + testScope.target.id);
|
info("Scope id: " + testScope.target.id);
|
||||||
info("Scope name: " + testScope.target.name);
|
info("Scope name: " + testScope.target.name);
|
||||||
@ -61,8 +61,8 @@ function testSimpleCall() {
|
|||||||
"Any new variable should have a details container with no child nodes.");
|
"Any new variable should have a details container with no child nodes.");
|
||||||
|
|
||||||
|
|
||||||
let properties = testVar.addProperties({ "child": { "value": { "type": "object",
|
let properties = testVar.addItems({ "child": { "value": { "type": "object",
|
||||||
"class": "Object" } } });
|
"class": "Object" } } });
|
||||||
|
|
||||||
|
|
||||||
ok(!testVar.expanded,
|
ok(!testVar.expanded,
|
||||||
|
@ -24,9 +24,9 @@ function testSimpleCall() {
|
|||||||
Services.tm.currentThread.dispatch({ run: function() {
|
Services.tm.currentThread.dispatch({ run: function() {
|
||||||
|
|
||||||
let testScope = gDebugger.DebuggerView.Variables.addScope("test");
|
let testScope = gDebugger.DebuggerView.Variables.addScope("test");
|
||||||
let testVar = testScope.addVar("something");
|
let testVar = testScope.addItem("something");
|
||||||
|
|
||||||
let properties = testVar.addProperties({
|
let properties = testVar.addItems({
|
||||||
"child": {
|
"child": {
|
||||||
"value": {
|
"value": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
@ -43,7 +43,7 @@ function testSimpleCall() {
|
|||||||
"The added detail property should be accessible from the variable.");
|
"The added detail property should be accessible from the variable.");
|
||||||
|
|
||||||
|
|
||||||
let properties2 = testVar.get("child").addProperties({
|
let properties2 = testVar.get("child").addItems({
|
||||||
"grandchild": {
|
"grandchild": {
|
||||||
"value": {
|
"value": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
@ -24,7 +24,7 @@ function testSimpleCall() {
|
|||||||
Services.tm.currentThread.dispatch({ run: function() {
|
Services.tm.currentThread.dispatch({ run: function() {
|
||||||
|
|
||||||
let testScope = gDebugger.DebuggerView.Variables.addScope("test");
|
let testScope = gDebugger.DebuggerView.Variables.addScope("test");
|
||||||
let testVar = testScope.addVar("something");
|
let testVar = testScope.addItem("something");
|
||||||
|
|
||||||
testVar.setGrip(1.618);
|
testVar.setGrip(1.618);
|
||||||
|
|
||||||
@ -44,32 +44,32 @@ function testSimpleCall() {
|
|||||||
"The information for the variable wasn't set correctly.");
|
"The information for the variable wasn't set correctly.");
|
||||||
|
|
||||||
|
|
||||||
testVar.addProperties({ "helloWorld": { "value": "hello world", "enumerable": true } });
|
testVar.addItems({ "helloWorld": { "value": "hello world", "enumerable": true } });
|
||||||
|
|
||||||
is(testVar.target.querySelector(".variables-view-element-details").childNodes.length, 1,
|
is(testVar.target.querySelector(".variables-view-element-details").childNodes.length, 1,
|
||||||
"A new detail node should have been added in the variable tree.");
|
"A new detail node should have been added in the variable tree.");
|
||||||
|
|
||||||
|
|
||||||
testVar.addProperties({ "helloWorld": { "value": "hello jupiter", "enumerable": true } });
|
testVar.addItems({ "helloWorld": { "value": "hello jupiter", "enumerable": true } });
|
||||||
|
|
||||||
is(testVar.target.querySelector(".variables-view-element-details").childNodes.length, 1,
|
is(testVar.target.querySelector(".variables-view-element-details").childNodes.length, 1,
|
||||||
"Shouldn't be able to duplicate nodes added in the variable tree.");
|
"Shouldn't be able to duplicate nodes added in the variable tree.");
|
||||||
|
|
||||||
|
|
||||||
testVar.addProperties({ "someProp0": { "value": "random string", "enumerable": true },
|
testVar.addItems({ "someProp0": { "value": "random string", "enumerable": true },
|
||||||
"someProp1": { "value": "another string", "enumerable": true } });
|
"someProp1": { "value": "another string", "enumerable": true } });
|
||||||
|
|
||||||
is(testVar.target.querySelector(".variables-view-element-details").childNodes.length, 3,
|
is(testVar.target.querySelector(".variables-view-element-details").childNodes.length, 3,
|
||||||
"Two new detail nodes should have been added in the variable tree.");
|
"Two new detail nodes should have been added in the variable tree.");
|
||||||
|
|
||||||
|
|
||||||
testVar.addProperties({ "someProp2": { "value": { "type": "null" }, "enumerable": true },
|
testVar.addItems({ "someProp2": { "value": { "type": "null" }, "enumerable": true },
|
||||||
"someProp3": { "value": { "type": "undefined" }, "enumerable": true },
|
"someProp3": { "value": { "type": "undefined" }, "enumerable": true },
|
||||||
"someProp4": {
|
"someProp4": {
|
||||||
"value": { "type": "object", "class": "Object" },
|
"value": { "type": "object", "class": "Object" },
|
||||||
"enumerable": true
|
"enumerable": true
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
is(testVar.target.querySelector(".variables-view-element-details").childNodes.length, 6,
|
is(testVar.target.querySelector(".variables-view-element-details").childNodes.length, 6,
|
||||||
"Three new detail nodes should have been added in the variable tree.");
|
"Three new detail nodes should have been added in the variable tree.");
|
||||||
|
@ -26,14 +26,14 @@ function testSimpleCall() {
|
|||||||
let globalScope = gDebugger.DebuggerView.Variables.addScope("Test-Global");
|
let globalScope = gDebugger.DebuggerView.Variables.addScope("Test-Global");
|
||||||
let localScope = gDebugger.DebuggerView.Variables.addScope("Test-Local");
|
let localScope = gDebugger.DebuggerView.Variables.addScope("Test-Local");
|
||||||
|
|
||||||
let windowVar = globalScope.addVar("window");
|
let windowVar = globalScope.addItem("window");
|
||||||
let documentVar = globalScope.addVar("document");
|
let documentVar = globalScope.addItem("document");
|
||||||
let localVar0 = localScope.addVar("localVariable");
|
let localVar0 = localScope.addItem("localVariable");
|
||||||
let localVar1 = localScope.addVar("localVar1");
|
let localVar1 = localScope.addItem("localVar1");
|
||||||
let localVar2 = localScope.addVar("localVar2");
|
let localVar2 = localScope.addItem("localVar2");
|
||||||
let localVar3 = localScope.addVar("localVar3");
|
let localVar3 = localScope.addItem("localVar3");
|
||||||
let localVar4 = localScope.addVar("localVar4");
|
let localVar4 = localScope.addItem("localVar4");
|
||||||
let localVar5 = localScope.addVar("localVar5");
|
let localVar5 = localScope.addItem("localVar5");
|
||||||
|
|
||||||
localVar0.setGrip(42);
|
localVar0.setGrip(42);
|
||||||
localVar1.setGrip(true);
|
localVar1.setGrip(true);
|
||||||
@ -43,36 +43,36 @@ function testSimpleCall() {
|
|||||||
localVar4.setGrip({ "type": "null" });
|
localVar4.setGrip({ "type": "null" });
|
||||||
localVar5.setGrip({ "type": "object", "class": "Object" });
|
localVar5.setGrip({ "type": "object", "class": "Object" });
|
||||||
|
|
||||||
localVar5.addProperties({ "someProp0": { "value": 42, "enumerable": true },
|
localVar5.addItems({ "someProp0": { "value": 42, "enumerable": true },
|
||||||
"someProp1": { "value": true , "enumerable": true},
|
"someProp1": { "value": true , "enumerable": true},
|
||||||
"someProp2": { "value": "nasu", "enumerable": true},
|
"someProp2": { "value": "nasu", "enumerable": true},
|
||||||
"someProp3": { "value": { "type": "undefined" }, "enumerable": true},
|
"someProp3": { "value": { "type": "undefined" }, "enumerable": true},
|
||||||
"someProp4": { "value": { "type": "null" }, "enumerable": true },
|
"someProp4": { "value": { "type": "null" }, "enumerable": true },
|
||||||
"someProp5": {
|
"someProp5": {
|
||||||
"value": { "type": "object", "class": "Object" },
|
"value": { "type": "object", "class": "Object" },
|
||||||
"enumerable": true
|
"enumerable": true
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
localVar5.get("someProp5").addProperties({ "someProp0": { "value": 42, "enumerable": true },
|
localVar5.get("someProp5").addItems({ "someProp0": { "value": 42, "enumerable": true },
|
||||||
"someProp1": { "value": true, "enumerable": true },
|
"someProp1": { "value": true, "enumerable": true },
|
||||||
"someProp2": { "value": "nasu", "enumerable": true },
|
"someProp2": { "value": "nasu", "enumerable": true },
|
||||||
"someProp3": { "value": { "type": "undefined" }, "enumerable": true },
|
"someProp3": { "value": { "type": "undefined" }, "enumerable": true },
|
||||||
"someProp4": { "value": { "type": "null" }, "enumerable": true },
|
"someProp4": { "value": { "type": "null" }, "enumerable": true },
|
||||||
"someAccessor": { "get": { "type": "object", "class": "Function" },
|
"someAccessor": { "get": { "type": "object", "class": "Function" },
|
||||||
"set": { "type": "undefined" },
|
"set": { "type": "undefined" }, "enumerable": true }
|
||||||
"enumerable": true } });
|
});
|
||||||
|
|
||||||
windowVar.setGrip({ "type": "object", "class": "Window" });
|
windowVar.setGrip({ "type": "object", "class": "Window" });
|
||||||
windowVar.addProperties({ "helloWorld": { "value": "hello world" } });
|
windowVar.addItems({ "helloWorld": { "value": "hello world" } });
|
||||||
|
|
||||||
documentVar.setGrip({ "type": "object", "class": "HTMLDocument" });
|
documentVar.setGrip({ "type": "object", "class": "HTMLDocument" });
|
||||||
documentVar.addProperties({ "onload": { "value": { "type": "null" } },
|
documentVar.addItems({ "onload": { "value": { "type": "null" } },
|
||||||
"onunload": { "value": { "type": "null" } },
|
"onunload": { "value": { "type": "null" } },
|
||||||
"onfocus": { "value": { "type": "null" } },
|
"onfocus": { "value": { "type": "null" } },
|
||||||
"onblur": { "value": { "type": "null" } },
|
"onblur": { "value": { "type": "null" } },
|
||||||
"onclick": { "value": { "type": "null" } },
|
"onclick": { "value": { "type": "null" } },
|
||||||
"onkeypress": { "value": { "type": "null" } } });
|
"onkeypress": { "value": { "type": "null" } } });
|
||||||
|
|
||||||
|
|
||||||
ok(windowVar, "The windowVar hasn't been created correctly.");
|
ok(windowVar, "The windowVar hasn't been created correctly.");
|
||||||
|
@ -75,11 +75,11 @@ function testVariablesView()
|
|||||||
testIntegrity(arr, obj);
|
testIntegrity(arr, obj);
|
||||||
|
|
||||||
let fooScope = gVariablesView.addScope("foo");
|
let fooScope = gVariablesView.addScope("foo");
|
||||||
let anonymousVar = fooScope.addVar();
|
let anonymousVar = fooScope.addItem();
|
||||||
|
|
||||||
let anonymousScope = gVariablesView.addScope();
|
let anonymousScope = gVariablesView.addScope();
|
||||||
let barVar = anonymousScope.addVar("bar");
|
let barVar = anonymousScope.addItem("bar");
|
||||||
let bazProperty = barVar.addProperty("baz");
|
let bazProperty = barVar.addItem("baz");
|
||||||
|
|
||||||
testAnonymousHeaders(fooScope, anonymousVar, anonymousScope, barVar, bazProperty);
|
testAnonymousHeaders(fooScope, anonymousVar, anonymousScope, barVar, bazProperty);
|
||||||
testPropertyInheritance(fooScope, anonymousVar, anonymousScope, barVar, bazProperty);
|
testPropertyInheritance(fooScope, anonymousVar, anonymousScope, barVar, bazProperty);
|
||||||
|
@ -110,8 +110,9 @@ function testVariablesFiltering()
|
|||||||
is(gSearchBox.value, "*",
|
is(gSearchBox.value, "*",
|
||||||
"Searchbox value is incorrect after 3 backspaces");
|
"Searchbox value is incorrect after 3 backspaces");
|
||||||
|
|
||||||
is(innerScope.querySelectorAll(".variables-view-variable:not([non-match])").length, 3,
|
// variable count includes `__proto__` for object scopes
|
||||||
"There should be 3 variables displayed in the inner scope");
|
is(innerScope.querySelectorAll(".variables-view-variable:not([non-match])").length, 4,
|
||||||
|
"There should be 4 variables displayed in the inner scope");
|
||||||
isnot(mathScope.querySelectorAll(".variables-view-variable:not([non-match])").length, 0,
|
isnot(mathScope.querySelectorAll(".variables-view-variable:not([non-match])").length, 0,
|
||||||
"There should be some variables displayed in the math scope");
|
"There should be some variables displayed in the math scope");
|
||||||
isnot(testScope.querySelectorAll(".variables-view-variable:not([non-match])").length, 0,
|
isnot(testScope.querySelectorAll(".variables-view-variable:not([non-match])").length, 0,
|
||||||
@ -140,8 +141,9 @@ function testVariablesFiltering()
|
|||||||
is(gSearchBox.value, "",
|
is(gSearchBox.value, "",
|
||||||
"Searchbox value is incorrect after 1 backspace");
|
"Searchbox value is incorrect after 1 backspace");
|
||||||
|
|
||||||
is(innerScope.querySelectorAll(".variables-view-variable:not([non-match])").length, 3,
|
// variable count includes `__proto__` for object scopes
|
||||||
"There should be 3 variables displayed in the inner scope");
|
is(innerScope.querySelectorAll(".variables-view-variable:not([non-match])").length, 4,
|
||||||
|
"There should be 4 variables displayed in the inner scope");
|
||||||
isnot(mathScope.querySelectorAll(".variables-view-variable:not([non-match])").length, 0,
|
isnot(mathScope.querySelectorAll(".variables-view-variable:not([non-match])").length, 0,
|
||||||
"There should be some variables displayed in the math scope");
|
"There should be some variables displayed in the math scope");
|
||||||
isnot(testScope.querySelectorAll(".variables-view-variable:not([non-match])").length, 0,
|
isnot(testScope.querySelectorAll(".variables-view-variable:not([non-match])").length, 0,
|
||||||
|
@ -158,7 +158,7 @@ Tools.jsprofiler = {
|
|||||||
icon: "chrome://browser/skin/devtools/tool-profiler.png",
|
icon: "chrome://browser/skin/devtools/tool-profiler.png",
|
||||||
url: "chrome://browser/content/devtools/profiler.xul",
|
url: "chrome://browser/content/devtools/profiler.xul",
|
||||||
label: l10n("profiler.label", profilerStrings),
|
label: l10n("profiler.label", profilerStrings),
|
||||||
tooltip: l10n("profiler.tooltip", profilerStrings),
|
tooltip: l10n("profiler.tooltip2", profilerStrings),
|
||||||
|
|
||||||
isTargetSupported: function (target) {
|
isTargetSupported: function (target) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -1446,7 +1446,7 @@ NetworkDetailsView.prototype = {
|
|||||||
headersScope.expanded = true;
|
headersScope.expanded = true;
|
||||||
|
|
||||||
for (let header of aResponse.headers) {
|
for (let header of aResponse.headers) {
|
||||||
let headerVar = headersScope.addVar(header.name, { null: true }, true);
|
let headerVar = headersScope.addItem(header.name, { null: true }, true);
|
||||||
gNetwork.getString(header.value).then((aString) => headerVar.setGrip(aString));
|
gNetwork.getString(header.value).then((aString) => headerVar.setGrip(aString));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -1489,7 +1489,7 @@ NetworkDetailsView.prototype = {
|
|||||||
cookiesScope.expanded = true;
|
cookiesScope.expanded = true;
|
||||||
|
|
||||||
for (let cookie of aResponse.cookies) {
|
for (let cookie of aResponse.cookies) {
|
||||||
let cookieVar = cookiesScope.addVar(cookie.name, { null: true }, true);
|
let cookieVar = cookiesScope.addItem(cookie.name, { null: true }, true);
|
||||||
gNetwork.getString(cookie.value).then((aString) => cookieVar.setGrip(aString));
|
gNetwork.getString(cookie.value).then((aString) => cookieVar.setGrip(aString));
|
||||||
|
|
||||||
// By default the cookie name and value are shown. If this is the only
|
// By default the cookie name and value are shown. If this is the only
|
||||||
@ -1591,7 +1591,7 @@ NetworkDetailsView.prototype = {
|
|||||||
paramsScope.expanded = true;
|
paramsScope.expanded = true;
|
||||||
|
|
||||||
for (let param of paramsArray) {
|
for (let param of paramsArray) {
|
||||||
let headerVar = paramsScope.addVar(param.name, { null: true }, true);
|
let headerVar = paramsScope.addItem(param.name, { null: true }, true);
|
||||||
headerVar.setGrip(param.value);
|
headerVar.setGrip(param.value);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -1634,7 +1634,7 @@ NetworkDetailsView.prototype = {
|
|||||||
: L10N.getStr("jsonScopeName");
|
: L10N.getStr("jsonScopeName");
|
||||||
|
|
||||||
let jsonScope = this._json.addScope(jsonScopeName);
|
let jsonScope = this._json.addScope(jsonScopeName);
|
||||||
jsonScope.addVar().populate(jsonObject, { expanded: true });
|
jsonScope.addItem().populate(jsonObject, { expanded: true });
|
||||||
jsonScope.expanded = true;
|
jsonScope.expanded = true;
|
||||||
}
|
}
|
||||||
// Malformed JSON.
|
// Malformed JSON.
|
||||||
|
@ -10,6 +10,8 @@ Cu.import("resource:///modules/devtools/gDevTools.jsm");
|
|||||||
Cu.import("resource:///modules/devtools/ProfilerController.jsm");
|
Cu.import("resource:///modules/devtools/ProfilerController.jsm");
|
||||||
Cu.import("resource:///modules/devtools/ProfilerHelpers.jsm");
|
Cu.import("resource:///modules/devtools/ProfilerHelpers.jsm");
|
||||||
Cu.import("resource:///modules/devtools/shared/event-emitter.js");
|
Cu.import("resource:///modules/devtools/shared/event-emitter.js");
|
||||||
|
Cu.import("resource:///modules/devtools/SideMenuWidget.jsm");
|
||||||
|
Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
|
||||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||||
Cu.import("resource://gre/modules/devtools/Console.jsm");
|
Cu.import("resource://gre/modules/devtools/Console.jsm");
|
||||||
|
|
||||||
@ -24,6 +26,10 @@ XPCOMUtils.defineLazyModuleGetter(this, "DebuggerServer",
|
|||||||
XPCOMUtils.defineLazyModuleGetter(this, "Services",
|
XPCOMUtils.defineLazyModuleGetter(this, "Services",
|
||||||
"resource://gre/modules/Services.jsm");
|
"resource://gre/modules/Services.jsm");
|
||||||
|
|
||||||
|
const PROFILE_IDLE = 0;
|
||||||
|
const PROFILE_RUNNING = 1;
|
||||||
|
const PROFILE_COMPLETED = 2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An instance of a profile UI. Profile UI consists of
|
* An instance of a profile UI. Profile UI consists of
|
||||||
* an iframe with Cleopatra loaded in it and some
|
* an iframe with Cleopatra loaded in it and some
|
||||||
@ -159,18 +165,6 @@ ProfileUI.prototype = {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* Update profile's label in the sidebar.
|
|
||||||
*
|
|
||||||
* @param string text
|
|
||||||
* New text for the label.
|
|
||||||
*/
|
|
||||||
updateLabel: function PUI_udpateLabel(text) {
|
|
||||||
let doc = this.panel.document;
|
|
||||||
let label = doc.querySelector("li#profile-" + this.uid + "> h1");
|
|
||||||
label.textContent = text;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start profiling and, once started, notify the underlying page
|
* Start profiling and, once started, notify the underlying page
|
||||||
* so that it could update the UI. Also, once started, we add a
|
* so that it could update the UI. Also, once started, we add a
|
||||||
@ -192,7 +186,7 @@ ProfileUI.prototype = {
|
|||||||
startFn = startFn || this.panel.startProfiling.bind(this.panel);
|
startFn = startFn || this.panel.startProfiling.bind(this.panel);
|
||||||
startFn(this.name, () => {
|
startFn(this.name, () => {
|
||||||
this.isStarted = true;
|
this.isStarted = true;
|
||||||
this.updateLabel(this.name + " *");
|
this.panel.sidebar.setProfileState(this, PROFILE_RUNNING);
|
||||||
this.panel.broadcast(this.uid, {task: "onStarted"}); // Do we really need this?
|
this.panel.broadcast(this.uid, {task: "onStarted"}); // Do we really need this?
|
||||||
this.emit("started");
|
this.emit("started");
|
||||||
});
|
});
|
||||||
@ -219,7 +213,7 @@ ProfileUI.prototype = {
|
|||||||
stopFn(this.name, () => {
|
stopFn(this.name, () => {
|
||||||
this.isStarted = false;
|
this.isStarted = false;
|
||||||
this.isFinished = true;
|
this.isFinished = true;
|
||||||
this.updateLabel(this.name);
|
this.panel.sidebar.setProfileState(this, PROFILE_COMPLETED);
|
||||||
this.panel.broadcast(this.uid, {task: "onStopped"});
|
this.panel.broadcast(this.uid, {task: "onStopped"});
|
||||||
this.emit("stopped");
|
this.emit("stopped");
|
||||||
});
|
});
|
||||||
@ -274,6 +268,39 @@ ProfileUI.prototype = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function SidebarView(el) {
|
||||||
|
EventEmitter.decorate(this);
|
||||||
|
this.node = new SideMenuWidget(el);
|
||||||
|
}
|
||||||
|
|
||||||
|
ViewHelpers.create({ constructor: SidebarView, proto: MenuContainer.prototype }, {
|
||||||
|
getItemByProfile: function (profile) {
|
||||||
|
return this.orderedItems.filter((item) => item.attachment.uid === profile.uid)[0];
|
||||||
|
},
|
||||||
|
|
||||||
|
setProfileState: function (profile, state) {
|
||||||
|
let item = this.getItemByProfile(profile);
|
||||||
|
let label = item.target.querySelector(".profiler-sidebar-item > span");
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
case PROFILE_IDLE:
|
||||||
|
label.textContent = L10N.getStr("profiler.stateIdle");
|
||||||
|
break;
|
||||||
|
case PROFILE_RUNNING:
|
||||||
|
label.textContent = L10N.getStr("profiler.stateRunning");
|
||||||
|
break;
|
||||||
|
case PROFILE_COMPLETED:
|
||||||
|
label.textContent = L10N.getStr("profiler.stateCompleted");
|
||||||
|
break;
|
||||||
|
default: // Wrong state, do nothing.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
item.attachment.state = state;
|
||||||
|
this.emit("stateChanged", item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Profiler panel. It is responsible for creating and managing
|
* Profiler panel. It is responsible for creating and managing
|
||||||
* different profile instances (see ProfileUI).
|
* different profile instances (see ProfileUI).
|
||||||
@ -320,6 +347,7 @@ ProfilerPanel.prototype = {
|
|||||||
target: null,
|
target: null,
|
||||||
controller: null,
|
controller: null,
|
||||||
profiles: null,
|
profiles: null,
|
||||||
|
sidebar: null,
|
||||||
|
|
||||||
_uid: null,
|
_uid: null,
|
||||||
_activeUid: null,
|
_activeUid: null,
|
||||||
@ -332,7 +360,14 @@ ProfilerPanel.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
set activeProfile(profile) {
|
set activeProfile(profile) {
|
||||||
|
if (this._activeUid === profile.uid)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (this.activeProfile)
|
||||||
|
this.activeProfile.hide();
|
||||||
|
|
||||||
this._activeUid = profile.uid;
|
this._activeUid = profile.uid;
|
||||||
|
profile.show();
|
||||||
},
|
},
|
||||||
|
|
||||||
get browserWindow() {
|
get browserWindow() {
|
||||||
@ -357,42 +392,59 @@ ProfilerPanel.prototype = {
|
|||||||
* @return Promise
|
* @return Promise
|
||||||
*/
|
*/
|
||||||
open: function PP_open() {
|
open: function PP_open() {
|
||||||
let promise;
|
|
||||||
|
|
||||||
// Local profiling needs to make the target remote.
|
// Local profiling needs to make the target remote.
|
||||||
if (!this.target.isRemote) {
|
let target = this.target;
|
||||||
promise = this.target.makeRemote();
|
let promise = !target.isRemote ? target.makeRemote() : Promise.resolve(target);
|
||||||
} else {
|
|
||||||
promise = Promise.resolve(this.target);
|
|
||||||
}
|
|
||||||
|
|
||||||
return promise
|
return promise
|
||||||
.then(function(target) {
|
.then((target) => {
|
||||||
let deferred = Promise.defer();
|
let deferred = Promise.defer();
|
||||||
this.controller = new ProfilerController(this.target);
|
|
||||||
|
|
||||||
this.controller.connect(function onConnect() {
|
this.controller = new ProfilerController(this.target);
|
||||||
|
this.sidebar = new SidebarView(this.document.querySelector("#profiles-list"));
|
||||||
|
this.sidebar.node.addEventListener("select", (ev) => {
|
||||||
|
if (!ev.detail)
|
||||||
|
return;
|
||||||
|
|
||||||
|
let profile = this.profiles.get(ev.detail.attachment.uid);
|
||||||
|
this.activeProfile = profile;
|
||||||
|
|
||||||
|
if (profile.isReady) {
|
||||||
|
profile.flushMessages();
|
||||||
|
return void this.emit("profileSwitched", profile.uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
profile.once("ready", () => {
|
||||||
|
profile.flushMessages();
|
||||||
|
this.emit("profileSwitched", profile.uid);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
this.controller.connect(() => {
|
||||||
let create = this.document.getElementById("profiler-create");
|
let create = this.document.getElementById("profiler-create");
|
||||||
create.addEventListener("click", function (ev) {
|
create.addEventListener("click", () => this.createProfile(), false);
|
||||||
this.createProfile()
|
|
||||||
}.bind(this), false);
|
|
||||||
create.removeAttribute("disabled");
|
create.removeAttribute("disabled");
|
||||||
|
|
||||||
let profile = this.createProfile();
|
let profile = this.createProfile();
|
||||||
this.switchToProfile(profile, function () {
|
let onSwitch = (_, uid) => {
|
||||||
|
if (profile.uid !== uid)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.off("profileSwitched", onSwitch);
|
||||||
this.isReady = true;
|
this.isReady = true;
|
||||||
this.emit("ready");
|
this.emit("ready");
|
||||||
|
|
||||||
deferred.resolve(this);
|
deferred.resolve(this);
|
||||||
}.bind(this))
|
};
|
||||||
}.bind(this));
|
|
||||||
|
this.on("profileSwitched", onSwitch);
|
||||||
|
this.sidebar.selectedItem = this.sidebar.getItemByProfile(profile);
|
||||||
|
});
|
||||||
|
|
||||||
return deferred.promise;
|
return deferred.promise;
|
||||||
}.bind(this))
|
})
|
||||||
.then(null, function onError(reason) {
|
.then(null, (reason) =>
|
||||||
Cu.reportError("ProfilerPanel open failed. " +
|
Cu.reportError("ProfilePanel open failed: " + reason.message));
|
||||||
reason.error + ": " + reason.message);
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -427,22 +479,17 @@ ProfilerPanel.prototype = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let list = this.document.getElementById("profiles-list");
|
let box = this.document.createElement("vbox");
|
||||||
let item = this.document.createElement("li");
|
box.className = "profiler-sidebar-item";
|
||||||
let wrap = this.document.createElement("h1");
|
box.id = "profile-" + uid;
|
||||||
name = name || L10N.getFormatStr("profiler.profileName", [uid]);
|
let h3 = this.document.createElement("h3");
|
||||||
|
h3.textContent = name;
|
||||||
|
let span = this.document.createElement("span");
|
||||||
|
span.textContent = L10N.getStr("profiler.stateIdle");
|
||||||
|
box.appendChild(h3);
|
||||||
|
box.appendChild(span);
|
||||||
|
|
||||||
item.setAttribute("id", "profile-" + uid);
|
this.sidebar.push(box, { attachment: { uid: uid, name: name, state: PROFILE_IDLE } });
|
||||||
item.setAttribute("data-uid", uid);
|
|
||||||
item.addEventListener("click", function (ev) {
|
|
||||||
this.switchToProfile(this.profiles.get(uid));
|
|
||||||
}.bind(this), false);
|
|
||||||
|
|
||||||
wrap.className = "profile-name";
|
|
||||||
wrap.textContent = name;
|
|
||||||
|
|
||||||
item.appendChild(wrap);
|
|
||||||
list.appendChild(item);
|
|
||||||
|
|
||||||
let profile = new ProfileUI(uid, name, this);
|
let profile = new ProfileUI(uid, name, this);
|
||||||
this.profiles.set(uid, profile);
|
this.profiles.set(uid, profile);
|
||||||
@ -451,47 +498,6 @@ ProfilerPanel.prototype = {
|
|||||||
return profile;
|
return profile;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* Switches to a different profile by making its instance an
|
|
||||||
* active one.
|
|
||||||
*
|
|
||||||
* @param ProfileUI profile
|
|
||||||
* A profile instance to switch to.
|
|
||||||
* @param function onLoad
|
|
||||||
* A function to call when profile instance is ready.
|
|
||||||
* If the instance is already loaded, onLoad will be
|
|
||||||
* called synchronously.
|
|
||||||
*/
|
|
||||||
switchToProfile: function PP_switchToProfile(profile, onLoad=function() {}) {
|
|
||||||
let doc = this.document;
|
|
||||||
|
|
||||||
if (this.activeProfile) {
|
|
||||||
this.activeProfile.hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
let active = doc.querySelector("#profiles-list > li.splitview-active");
|
|
||||||
if (active) {
|
|
||||||
active.className = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
doc.getElementById("profile-" + profile.uid).className = "splitview-active";
|
|
||||||
profile.show();
|
|
||||||
this.activeProfile = profile;
|
|
||||||
|
|
||||||
if (profile.isReady) {
|
|
||||||
profile.flushMessages();
|
|
||||||
this.emit("profileSwitched", profile.uid);
|
|
||||||
onLoad();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
profile.once("ready", () => {
|
|
||||||
profile.flushMessages();
|
|
||||||
this.emit("profileSwitched", profile.uid);
|
|
||||||
onLoad();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start collecting profile data.
|
* Start collecting profile data.
|
||||||
*
|
*
|
||||||
|
@ -83,7 +83,15 @@ gcli.addCommand({
|
|||||||
throw gcli.lookup("profilerAlreadyFinished");
|
throw gcli.lookup("profilerAlreadyFinished");
|
||||||
}
|
}
|
||||||
|
|
||||||
panel.switchToProfile(profile, function () profile.start());
|
let item = panel.sidebar.getItemByProfile(profile);
|
||||||
|
|
||||||
|
if (panel.sidebar.selectedItem === item) {
|
||||||
|
profile.start();
|
||||||
|
} else {
|
||||||
|
panel.on("profileSwitched", () => profile.start());
|
||||||
|
panel.sidebar.selectedItem = item;
|
||||||
|
}
|
||||||
|
|
||||||
return gcli.lookup("profilerStarting2");
|
return gcli.lookup("profilerStarting2");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,7 +132,15 @@ gcli.addCommand({
|
|||||||
throw gcli.lookup("profilerNotStarted2");
|
throw gcli.lookup("profilerNotStarted2");
|
||||||
}
|
}
|
||||||
|
|
||||||
panel.switchToProfile(profile, function () profile.stop());
|
let item = panel.sidebar.getItemByProfile(profile);
|
||||||
|
|
||||||
|
if (panel.sidebar.selectedItem === item) {
|
||||||
|
profile.stop();
|
||||||
|
} else {
|
||||||
|
panel.on("profileSwitched", () => profile.stop());
|
||||||
|
panel.sidebar.selectedItem = item;
|
||||||
|
}
|
||||||
|
|
||||||
return gcli.lookup("profilerStopping2");
|
return gcli.lookup("profilerStopping2");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,7 +209,7 @@ gcli.addCommand({
|
|||||||
throw gcli.lookup("profilerNotFound");
|
throw gcli.lookup("profilerNotFound");
|
||||||
}
|
}
|
||||||
|
|
||||||
panel.switchToProfile(profile);
|
panel.sidebar.selectedItem = panel.sidebar.getItemByProfile(profile);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
|
|
||||||
<?xml-stylesheet href="chrome://global/skin/global.css"?>
|
<?xml-stylesheet href="chrome://global/skin/global.css"?>
|
||||||
<?xml-stylesheet href="chrome://browser/skin/devtools/common.css"?>
|
<?xml-stylesheet href="chrome://browser/skin/devtools/common.css"?>
|
||||||
<?xml-stylesheet href="chrome://browser/skin/devtools/splitview.css"?>
|
<?xml-stylesheet href="chrome://browser/skin/devtools/widgets.css"?>
|
||||||
<?xml-stylesheet href="chrome://browser/skin/devtools/profiler.css"?>
|
<?xml-stylesheet href="chrome://browser/skin/devtools/profiler.css"?>
|
||||||
<?xml-stylesheet href="chrome://browser/content/devtools/splitview.css"?>
|
<?xml-stylesheet href="chrome://browser/content/devtools/widgets.css"?>
|
||||||
|
|
||||||
<!DOCTYPE window [
|
<!DOCTYPE window [
|
||||||
<!ENTITY % profilerDTD SYSTEM "chrome://browser/locale/devtools/profiler.dtd">
|
<!ENTITY % profilerDTD SYSTEM "chrome://browser/locale/devtools/profiler.dtd">
|
||||||
@ -16,37 +16,31 @@
|
|||||||
]>
|
]>
|
||||||
|
|
||||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||||
<box flex="1" id="profiler-chrome" class="splitview-root">
|
<box flex="1" id="profiler-chrome" class="devtools-responsive-container">
|
||||||
<box class="splitview-controller" width="180px">
|
<vbox class="profiler-sidebar">
|
||||||
<box class="splitview-main"></box>
|
<toolbar class="devtools-toolbar">
|
||||||
|
<toolbarbutton id="profiler-create"
|
||||||
|
class="devtools-toolbarbutton"
|
||||||
|
label="&profilerNew.label;"
|
||||||
|
disabled="true"/>
|
||||||
|
</toolbar>
|
||||||
|
|
||||||
<box class="splitview-nav-container">
|
<vbox id="profiles-list" flex="1">
|
||||||
<ol class="splitview-nav" id="profiles-list">
|
</vbox>
|
||||||
<!-- Example:
|
</vbox>
|
||||||
<li class="splitview-active" id="profile-1" data-uid="1">
|
|
||||||
<h1 class="profile-name">Profile 1</h1>
|
|
||||||
</li>
|
|
||||||
-->
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
<spacer flex="1"/>
|
<splitter class="devtools-side-splitter"/>
|
||||||
|
|
||||||
<toolbar class="devtools-toolbar" mode="full">
|
<vbox flex="1">
|
||||||
<toolbarbutton id="profiler-create"
|
<toolbar class="devtools-toolbar">
|
||||||
class="devtools-toolbarbutton"
|
</toolbar>
|
||||||
label="&profilerNew.label;"
|
|
||||||
disabled="true"/>
|
|
||||||
</toolbar>
|
|
||||||
</box> <!-- splitview-nav-container -->
|
|
||||||
</box> <!-- splitview-controller -->
|
|
||||||
|
|
||||||
<box flex="1">
|
|
||||||
<vbox flex="1" id="profiler-report">
|
<vbox flex="1" id="profiler-report">
|
||||||
<!-- Example:
|
<!-- Example:
|
||||||
<iframe id="profiler-cleo-1"
|
<iframe id="profiler-cleo-1"
|
||||||
src="devtools/cleopatra.html" flex="1"></iframe>
|
src="devtools/cleopatra.html" flex="1"></iframe>
|
||||||
-->
|
-->
|
||||||
</vbox>
|
</vbox>
|
||||||
</box>
|
</vbox>
|
||||||
</box>
|
</box>
|
||||||
</window>
|
</window>
|
||||||
|
@ -26,13 +26,6 @@ function test() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCleoControls(doc) {
|
|
||||||
return [
|
|
||||||
doc.querySelector("#startWrapper button"),
|
|
||||||
doc.querySelector("#profilerMessage")
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
function startProfiling() {
|
function startProfiling() {
|
||||||
gPanel.profiles.get(gPanel.activeProfile.uid).once("started", function () {
|
gPanel.profiles.get(gPanel.activeProfile.uid).once("started", function () {
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
@ -40,36 +33,27 @@ function startProfiling() {
|
|||||||
gPanel.profiles.get(2).once("started", function () setTimeout(stopProfiling, 50));
|
gPanel.profiles.get(2).once("started", function () setTimeout(stopProfiling, 50));
|
||||||
}, 50);
|
}, 50);
|
||||||
});
|
});
|
||||||
|
|
||||||
sendFromProfile(gPanel.activeProfile.uid, "start");
|
sendFromProfile(gPanel.activeProfile.uid, "start");
|
||||||
}
|
}
|
||||||
|
|
||||||
function stopProfiling() {
|
function stopProfiling() {
|
||||||
let [win, doc] = getProfileInternals(gUid);
|
is(getSidebarItem(1).attachment.state, PROFILE_RUNNING);
|
||||||
let [btn, msg] = getCleoControls(doc);
|
is(getSidebarItem(2).attachment.state, PROFILE_RUNNING);
|
||||||
|
|
||||||
is(gPanel.document.querySelector("li#profile-1 > h1").textContent,
|
|
||||||
"Profile 1 *", "Profile 1 has a star next to it.");
|
|
||||||
is(gPanel.document.querySelector("li#profile-2 > h1").textContent,
|
|
||||||
"Profile 2 *", "Profile 2 has a star next to it.");
|
|
||||||
|
|
||||||
gPanel.profiles.get(gPanel.activeProfile.uid).once("stopped", function () {
|
gPanel.profiles.get(gPanel.activeProfile.uid).once("stopped", function () {
|
||||||
is(gPanel.document.querySelector("li#profile-1 > h1").textContent,
|
is(getSidebarItem(1).attachment.state, PROFILE_COMPLETED);
|
||||||
"Profile 1", "Profile 1 doesn't have a star next to it anymore.");
|
|
||||||
|
|
||||||
sendFromProfile(2, "stop");
|
sendFromProfile(2, "stop");
|
||||||
gPanel.profiles.get(2).once("stopped", confirmAndFinish);
|
gPanel.profiles.get(2).once("stopped", confirmAndFinish);
|
||||||
});
|
});
|
||||||
|
|
||||||
sendFromProfile(gPanel.activeProfile.uid, "stop");
|
sendFromProfile(gPanel.activeProfile.uid, "stop");
|
||||||
}
|
}
|
||||||
|
|
||||||
function confirmAndFinish(ev, data) {
|
function confirmAndFinish(ev, data) {
|
||||||
let [win, doc] = getProfileInternals(gUid);
|
is(getSidebarItem(1).attachment.state, PROFILE_COMPLETED);
|
||||||
let [btn, msg] = getCleoControls(doc);
|
is(getSidebarItem(2).attachment.state, PROFILE_COMPLETED);
|
||||||
|
|
||||||
is(gPanel.document.querySelector("li#profile-1 > h1").textContent,
|
|
||||||
"Profile 1", "Profile 1 doesn't have a star next to it.");
|
|
||||||
is(gPanel.document.querySelector("li#profile-2 > h1").textContent,
|
|
||||||
"Profile 2", "Profile 2 doesn't have a star next to it.");
|
|
||||||
|
|
||||||
tearDown(gTab, function onTearDown() {
|
tearDown(gTab, function onTearDown() {
|
||||||
gPanel = null;
|
gPanel = null;
|
||||||
|
@ -48,17 +48,15 @@ function testConsoleProfile(hud) {
|
|||||||
|
|
||||||
function checkProfiles(toolbox) {
|
function checkProfiles(toolbox) {
|
||||||
let panel = toolbox.getPanel("jsprofiler");
|
let panel = toolbox.getPanel("jsprofiler");
|
||||||
let getTitle = (uid) =>
|
|
||||||
panel.document.querySelector("li#profile-" + uid + " > h1").textContent;
|
|
||||||
|
|
||||||
is(getTitle(1), "Profile 1", "Profile 1 doesn't have a star next to it.");
|
is(getSidebarItem(1, panel).attachment.state, PROFILE_IDLE);
|
||||||
is(getTitle(2), "Profile 2 *", "Profile 2 doesn't have a star next to it.");
|
is(getSidebarItem(2, panel).attachment.state, PROFILE_RUNNING);
|
||||||
is(getTitle(3), "Profile 3", "Profile 3 doesn't have a star next to it.");
|
is(getSidebarItem(3, panel).attachment.state, PROFILE_COMPLETED);
|
||||||
|
|
||||||
// Make sure we can still stop profiles via the UI.
|
// Make sure we can still stop profiles via the UI.
|
||||||
|
|
||||||
gPanel.profiles.get(2).once("stopped", () => {
|
gPanel.profiles.get(2).once("stopped", () => {
|
||||||
is(getTitle(2), "Profile 2", "Profile 2 doesn't have a star next to it.");
|
is(getSidebarItem(2, panel).attachment.state, PROFILE_COMPLETED);
|
||||||
tearDown(gTab, () => gTab = gPanel = null);
|
tearDown(gTab, () => gTab = gPanel = null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -17,18 +17,20 @@ function test() {
|
|||||||
openProfiler(tab, (toolbox) => {
|
openProfiler(tab, (toolbox) => {
|
||||||
gToolbox = toolbox;
|
gToolbox = toolbox;
|
||||||
loadUrl(PAGE, tab, () => {
|
loadUrl(PAGE, tab, () => {
|
||||||
gPanel.on("profileCreated", runTests);
|
gPanel.sidebar.on("stateChanged", (_, item) => {
|
||||||
|
if (item.attachment.state !== PROFILE_COMPLETED)
|
||||||
|
return;
|
||||||
|
|
||||||
|
runTests();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function runTests() {
|
function runTests() {
|
||||||
let getTitle = (uid) =>
|
is(getSidebarItem(1).attachment.state, PROFILE_IDLE);
|
||||||
gPanel.document.querySelector("li#profile-" + uid + " > h1").textContent;
|
is(getSidebarItem(2).attachment.state, PROFILE_COMPLETED);
|
||||||
|
|
||||||
is(getTitle(1), "Profile 1", "Profile 1 doesn't have a star next to it.");
|
|
||||||
is(getTitle(2), "Profile 2", "Profile 2 doesn't have a star next to it.");
|
|
||||||
|
|
||||||
gPanel.once("parsed", () => {
|
gPanel.once("parsed", () => {
|
||||||
function assertSampleAndFinish() {
|
function assertSampleAndFinish() {
|
||||||
@ -49,5 +51,6 @@ function runTests() {
|
|||||||
assertSampleAndFinish();
|
assertSampleAndFinish();
|
||||||
});
|
});
|
||||||
|
|
||||||
gPanel.switchToProfile(gPanel.profiles.get(2));
|
let profile = gPanel.profiles.get(2);
|
||||||
|
gPanel.sidebar.selectedItem = gPanel.sidebar.getItemByProfile(profile);
|
||||||
}
|
}
|
@ -18,15 +18,13 @@ function test() {
|
|||||||
|
|
||||||
function runTests(toolbox) {
|
function runTests(toolbox) {
|
||||||
let panel = toolbox.getPanel("jsprofiler");
|
let panel = toolbox.getPanel("jsprofiler");
|
||||||
let getTitle = (uid) =>
|
|
||||||
panel.document.querySelector("li#profile-" + uid + " > h1").textContent;
|
|
||||||
|
|
||||||
panel.profiles.get(1).once("started", () => {
|
panel.profiles.get(1).once("started", () => {
|
||||||
is(getTitle(1), "Profile 1 *", "Profile 1 has a start next to it.");
|
is(getSidebarItem(1, panel).attachment.state, PROFILE_RUNNING);
|
||||||
|
|
||||||
openConsole(gTab, (hud) => {
|
openConsole(gTab, (hud) => {
|
||||||
panel.profiles.get(1).once("stopped", () => {
|
panel.profiles.get(1).once("stopped", () => {
|
||||||
is(getTitle(1), "Profile 1", "Profile 1 doesn't have a star next to it.");
|
is(getSidebarItem(1, panel).attachment.state, PROFILE_COMPLETED);
|
||||||
tearDown(gTab, () => gTab = gPanel = null);
|
tearDown(gTab, () => gTab = gPanel = null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -46,18 +46,18 @@ function testConsoleProfile(hud) {
|
|||||||
|
|
||||||
function checkProfiles(toolbox) {
|
function checkProfiles(toolbox) {
|
||||||
let panel = toolbox.getPanel("jsprofiler");
|
let panel = toolbox.getPanel("jsprofiler");
|
||||||
let getTitle = (uid) =>
|
|
||||||
panel.document.querySelector("li#profile-" + uid + " > h1").textContent;
|
|
||||||
|
|
||||||
is(getTitle(1), "Profile 1", "Profile 1 doesn't have a star next to it.");
|
is(getSidebarItem(1, panel).attachment.state, PROFILE_IDLE);
|
||||||
is(getTitle(2), "Second", "Second doesn't have a star next to it.");
|
is(getSidebarItem(2, panel).attachment.name, "Second");
|
||||||
is(getTitle(3), "Third *", "Third does have a star next to it.");
|
is(getSidebarItem(2, panel).attachment.state, PROFILE_COMPLETED);
|
||||||
|
is(getSidebarItem(3, panel).attachment.name, "Third");
|
||||||
|
is(getSidebarItem(3, panel).attachment.state, PROFILE_RUNNING);
|
||||||
|
|
||||||
// Make sure we can still stop profiles via the queue pop.
|
// Make sure we can still stop profiles via the queue pop.
|
||||||
|
|
||||||
gPanel.profiles.get(3).once("stopped", () => {
|
gPanel.profiles.get(3).once("stopped", () => {
|
||||||
openProfiler(gTab, () => {
|
openProfiler(gTab, () => {
|
||||||
is(getTitle(3), "Third", "Third doesn't have a star next to it.");
|
is(getSidebarItem(3, panel).attachment.state, PROFILE_COMPLETED);
|
||||||
tearDown(gTab, () => gTab = gPanel = null);
|
tearDown(gTab, () => gTab = gPanel = null);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -48,8 +48,11 @@ function onNamedProfileCreated(name, uid) {
|
|||||||
is(gPanel.profiles.size, 3, "There are three profiles now");
|
is(gPanel.profiles.size, 3, "There are three profiles now");
|
||||||
is(gPanel.getProfileByUID(uid).name, "Custom Profile", "Name is correct");
|
is(gPanel.getProfileByUID(uid).name, "Custom Profile", "Name is correct");
|
||||||
|
|
||||||
let label = gPanel.document.querySelector("li#profile-" + uid + "> h1");
|
let profile = gPanel.profiles.get(uid);
|
||||||
is(label.textContent, "Custom Profile", "Name is correct on the label");
|
let data = gPanel.sidebar.getItemByProfile(profile).attachment;
|
||||||
|
|
||||||
|
is(data.uid, uid, "UID is correct");
|
||||||
|
is(data.name, "Custom Profile", "Name is correct on the label");
|
||||||
|
|
||||||
let btn = gPanel.document.getElementById("profile-" + uid);
|
let btn = gPanel.document.getElementById("profile-" + uid);
|
||||||
ok(btn, "Profile item has been added to the sidebar");
|
ok(btn, "Profile item has been added to the sidebar");
|
||||||
|
@ -2,8 +2,12 @@
|
|||||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
let temp = {};
|
let temp = {};
|
||||||
|
|
||||||
const PROFILER_ENABLED = "devtools.profiler.enabled";
|
const PROFILER_ENABLED = "devtools.profiler.enabled";
|
||||||
const REMOTE_ENABLED = "devtools.debugger.remote-enabled";
|
const REMOTE_ENABLED = "devtools.debugger.remote-enabled";
|
||||||
|
const PROFILE_IDLE = 0;
|
||||||
|
const PROFILE_RUNNING = 1;
|
||||||
|
const PROFILE_COMPLETED = 2;
|
||||||
|
|
||||||
Cu.import("resource:///modules/devtools/gDevTools.jsm", temp);
|
Cu.import("resource:///modules/devtools/gDevTools.jsm", temp);
|
||||||
let gDevTools = temp.gDevTools;
|
let gDevTools = temp.gDevTools;
|
||||||
@ -36,6 +40,11 @@ function getProfileInternals(uid) {
|
|||||||
return [win, doc];
|
return [win, doc];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getSidebarItem(uid, panel=gPanel) {
|
||||||
|
let profile = panel.profiles.get(uid);
|
||||||
|
return panel.sidebar.getItemByProfile(profile);
|
||||||
|
}
|
||||||
|
|
||||||
function sendFromProfile(uid, msg) {
|
function sendFromProfile(uid, msg) {
|
||||||
let [win, doc] = getProfileInternals(uid);
|
let [win, doc] = getProfileInternals(uid);
|
||||||
win.parent.postMessage({ uid: uid, status: msg }, "*");
|
win.parent.postMessage({ uid: uid, status: msg }, "*");
|
||||||
|
@ -20,6 +20,8 @@ const SEARCH_ACTION_MAX_DELAY = 300; // ms
|
|||||||
Cu.import("resource://gre/modules/Services.jsm");
|
Cu.import("resource://gre/modules/Services.jsm");
|
||||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||||
Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
|
Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
|
||||||
|
Cu.import("resource:///modules/devtools/shared/event-emitter.js");
|
||||||
|
Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js");
|
||||||
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "NetworkHelper",
|
XPCOMUtils.defineLazyModuleGetter(this, "NetworkHelper",
|
||||||
"resource://gre/modules/devtools/NetworkHelper.jsm");
|
"resource://gre/modules/devtools/NetworkHelper.jsm");
|
||||||
@ -74,6 +76,8 @@ this.VariablesView = function VariablesView(aParentNode, aFlags = {}) {
|
|||||||
for (let name in aFlags) {
|
for (let name in aFlags) {
|
||||||
this[name] = aFlags[name];
|
this[name] = aFlags[name];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EventEmitter.decorate(this);
|
||||||
};
|
};
|
||||||
|
|
||||||
VariablesView.prototype = {
|
VariablesView.prototype = {
|
||||||
@ -86,7 +90,7 @@ VariablesView.prototype = {
|
|||||||
*/
|
*/
|
||||||
set rawObject(aObject) {
|
set rawObject(aObject) {
|
||||||
this.empty();
|
this.empty();
|
||||||
this.addScope().addVar().populate(aObject);
|
this.addScope().addItem().populate(aObject);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -180,6 +184,11 @@ VariablesView.prototype = {
|
|||||||
}, aTimeout);
|
}, aTimeout);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The controller for this VariablesView, if it has one.
|
||||||
|
*/
|
||||||
|
controller: null,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The amount of time (in milliseconds) it takes to empty this view lazily.
|
* The amount of time (in milliseconds) it takes to empty this view lazily.
|
||||||
*/
|
*/
|
||||||
@ -587,7 +596,8 @@ VariablesView.prototype = {
|
|||||||
*/
|
*/
|
||||||
getScopeForNode: function(aNode) {
|
getScopeForNode: function(aNode) {
|
||||||
let item = this._itemsByElement.get(aNode);
|
let item = this._itemsByElement.get(aNode);
|
||||||
if (item && !(item instanceof Variable) && !(item instanceof Property)) {
|
// Match only Scopes, not Variables or Properties.
|
||||||
|
if (item && !(item instanceof Variable)) {
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@ -790,9 +800,8 @@ VariablesView.prototype = {
|
|||||||
|
|
||||||
case e.DOM_VK_RETURN:
|
case e.DOM_VK_RETURN:
|
||||||
case e.DOM_VK_ENTER:
|
case e.DOM_VK_ENTER:
|
||||||
// Start editing the value or name of the variable or property.
|
// Start editing the value or name of the Variable or Property.
|
||||||
if (item instanceof Variable ||
|
if (item instanceof Variable) {
|
||||||
item instanceof Property) {
|
|
||||||
if (e.metaKey || e.altKey || e.shiftKey) {
|
if (e.metaKey || e.altKey || e.shiftKey) {
|
||||||
item._activateNameInput();
|
item._activateNameInput();
|
||||||
} else {
|
} else {
|
||||||
@ -803,9 +812,8 @@ VariablesView.prototype = {
|
|||||||
|
|
||||||
case e.DOM_VK_DELETE:
|
case e.DOM_VK_DELETE:
|
||||||
case e.DOM_VK_BACK_SPACE:
|
case e.DOM_VK_BACK_SPACE:
|
||||||
// Delete the variable or property if allowed.
|
// Delete the Variable or Property if allowed.
|
||||||
if (item instanceof Variable ||
|
if (item instanceof Variable) {
|
||||||
item instanceof Property) {
|
|
||||||
item._onDelete(e);
|
item._onDelete(e);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@ -902,6 +910,7 @@ VariablesView.NON_SORTABLE_CLASSES = [
|
|||||||
"Array",
|
"Array",
|
||||||
"Int8Array",
|
"Int8Array",
|
||||||
"Uint8Array",
|
"Uint8Array",
|
||||||
|
"Uint8ClampedArray",
|
||||||
"Int16Array",
|
"Int16Array",
|
||||||
"Uint16Array",
|
"Uint16Array",
|
||||||
"Int32Array",
|
"Int32Array",
|
||||||
@ -910,6 +919,16 @@ VariablesView.NON_SORTABLE_CLASSES = [
|
|||||||
"Float64Array"
|
"Float64Array"
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether an object's properties should be sorted based on its class.
|
||||||
|
*
|
||||||
|
* @param string aClassName
|
||||||
|
* The class of the object.
|
||||||
|
*/
|
||||||
|
VariablesView.isSortable = function(aClassName) {
|
||||||
|
return VariablesView.NON_SORTABLE_CLASSES.indexOf(aClassName) == -1;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates the string evaluated when performing simple value changes.
|
* Generates the string evaluated when performing simple value changes.
|
||||||
*
|
*
|
||||||
@ -917,11 +936,13 @@ VariablesView.NON_SORTABLE_CLASSES = [
|
|||||||
* The current variable or property.
|
* The current variable or property.
|
||||||
* @param string aCurrentString
|
* @param string aCurrentString
|
||||||
* The trimmed user inputted string.
|
* The trimmed user inputted string.
|
||||||
|
* @param string aPrefix [optional]
|
||||||
|
* Prefix for the symbolic name.
|
||||||
* @return string
|
* @return string
|
||||||
* The string to be evaluated.
|
* The string to be evaluated.
|
||||||
*/
|
*/
|
||||||
VariablesView.simpleValueEvalMacro = function(aItem, aCurrentString) {
|
VariablesView.simpleValueEvalMacro = function(aItem, aCurrentString, aPrefix = "") {
|
||||||
return aItem._symbolicName + "=" + aCurrentString;
|
return aPrefix + aItem._symbolicName + "=" + aCurrentString;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -932,12 +953,14 @@ VariablesView.simpleValueEvalMacro = function(aItem, aCurrentString) {
|
|||||||
* The current getter or setter property.
|
* The current getter or setter property.
|
||||||
* @param string aCurrentString
|
* @param string aCurrentString
|
||||||
* The trimmed user inputted string.
|
* The trimmed user inputted string.
|
||||||
|
* @param string aPrefix [optional]
|
||||||
|
* Prefix for the symbolic name.
|
||||||
* @return string
|
* @return string
|
||||||
* The string to be evaluated.
|
* The string to be evaluated.
|
||||||
*/
|
*/
|
||||||
VariablesView.overrideValueEvalMacro = function(aItem, aCurrentString) {
|
VariablesView.overrideValueEvalMacro = function(aItem, aCurrentString, aPrefix = "") {
|
||||||
let property = "\"" + aItem._nameString + "\"";
|
let property = "\"" + aItem._nameString + "\"";
|
||||||
let parent = aItem.ownerView._symbolicName || "this";
|
let parent = aPrefix + aItem.ownerView._symbolicName || "this";
|
||||||
|
|
||||||
return "Object.defineProperty(" + parent + "," + property + "," +
|
return "Object.defineProperty(" + parent + "," + property + "," +
|
||||||
"{ value: " + aCurrentString +
|
"{ value: " + aCurrentString +
|
||||||
@ -954,15 +977,17 @@ VariablesView.overrideValueEvalMacro = function(aItem, aCurrentString) {
|
|||||||
* The current getter or setter property.
|
* The current getter or setter property.
|
||||||
* @param string aCurrentString
|
* @param string aCurrentString
|
||||||
* The trimmed user inputted string.
|
* The trimmed user inputted string.
|
||||||
|
* @param string aPrefix [optional]
|
||||||
|
* Prefix for the symbolic name.
|
||||||
* @return string
|
* @return string
|
||||||
* The string to be evaluated.
|
* The string to be evaluated.
|
||||||
*/
|
*/
|
||||||
VariablesView.getterOrSetterEvalMacro = function(aItem, aCurrentString) {
|
VariablesView.getterOrSetterEvalMacro = function(aItem, aCurrentString, aPrefix = "") {
|
||||||
let type = aItem._nameString;
|
let type = aItem._nameString;
|
||||||
let propertyObject = aItem.ownerView;
|
let propertyObject = aItem.ownerView;
|
||||||
let parentObject = propertyObject.ownerView;
|
let parentObject = propertyObject.ownerView;
|
||||||
let property = "\"" + propertyObject._nameString + "\"";
|
let property = "\"" + propertyObject._nameString + "\"";
|
||||||
let parent = parentObject._symbolicName || "this";
|
let parent = aPrefix + parentObject._symbolicName || "this";
|
||||||
|
|
||||||
switch (aCurrentString) {
|
switch (aCurrentString) {
|
||||||
case "":
|
case "":
|
||||||
@ -976,7 +1001,7 @@ VariablesView.getterOrSetterEvalMacro = function(aItem, aCurrentString) {
|
|||||||
if ((type == "set" && propertyObject.getter.type == "undefined") ||
|
if ((type == "set" && propertyObject.getter.type == "undefined") ||
|
||||||
(type == "get" && propertyObject.setter.type == "undefined")) {
|
(type == "get" && propertyObject.setter.type == "undefined")) {
|
||||||
// Make sure the right getter/setter to value override macro is applied to the target object.
|
// Make sure the right getter/setter to value override macro is applied to the target object.
|
||||||
return propertyObject.evaluationMacro(propertyObject, "undefined");
|
return propertyObject.evaluationMacro(propertyObject, "undefined", aPrefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct and return the getter/setter removal evaluation string.
|
// Construct and return the getter/setter removal evaluation string.
|
||||||
@ -995,16 +1020,16 @@ VariablesView.getterOrSetterEvalMacro = function(aItem, aCurrentString) {
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
// Wrap statements inside a function declaration if not already wrapped.
|
// Wrap statements inside a function declaration if not already wrapped.
|
||||||
if (aCurrentString.indexOf("function") != 0) {
|
if (!aCurrentString.startsWith("function")) {
|
||||||
let header = "function(" + (type == "set" ? "value" : "") + ")";
|
let header = "function(" + (type == "set" ? "value" : "") + ")";
|
||||||
let body = "";
|
let body = "";
|
||||||
// If there's a return statement explicitly written, always use the
|
// If there's a return statement explicitly written, always use the
|
||||||
// standard function definition syntax
|
// standard function definition syntax
|
||||||
if (aCurrentString.indexOf("return ") != -1) {
|
if (aCurrentString.contains("return ")) {
|
||||||
body = "{" + aCurrentString + "}";
|
body = "{" + aCurrentString + "}";
|
||||||
}
|
}
|
||||||
// If block syntax is used, use the whole string as the function body.
|
// If block syntax is used, use the whole string as the function body.
|
||||||
else if (aCurrentString.indexOf("{") == 0) {
|
else if (aCurrentString.startsWith("{")) {
|
||||||
body = aCurrentString;
|
body = aCurrentString;
|
||||||
}
|
}
|
||||||
// Prefer an expression closure.
|
// Prefer an expression closure.
|
||||||
@ -1042,6 +1067,7 @@ VariablesView.getterOrSetterDeleteCallback = function(aItem) {
|
|||||||
return true; // Don't hide the element.
|
return true; // Don't hide the element.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Scope is an object holding Variable instances.
|
* A Scope is an object holding Variable instances.
|
||||||
* Iterable via "for (let [name, variable] in instance) { }".
|
* Iterable via "for (let [name, variable] in instance) { }".
|
||||||
@ -1083,12 +1109,31 @@ function Scope(aView, aName, aFlags = {}) {
|
|||||||
|
|
||||||
Scope.prototype = {
|
Scope.prototype = {
|
||||||
/**
|
/**
|
||||||
* Adds a variable to contain any inspected properties.
|
* Whether this Scope should be prefetched when it is remoted.
|
||||||
|
*/
|
||||||
|
shouldPrefetch: true,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new Variable that is a child of this Scope.
|
||||||
*
|
*
|
||||||
* @param string aName
|
* @param string aName
|
||||||
* The variable's name.
|
* The name of the new Property.
|
||||||
* @param object aDescriptor
|
* @param object aDescriptor
|
||||||
* Specifies the value and/or type & class of the variable,
|
* The variable's descriptor.
|
||||||
|
* @return Variable
|
||||||
|
* The newly created child Variable.
|
||||||
|
*/
|
||||||
|
_createChild: function(aName, aDescriptor) {
|
||||||
|
return new Variable(this, aName, aDescriptor);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a child to contain any inspected properties.
|
||||||
|
*
|
||||||
|
* @param string aName
|
||||||
|
* The child's name.
|
||||||
|
* @param object aDescriptor
|
||||||
|
* Specifies the value and/or type & class of the child,
|
||||||
* or 'get' & 'set' accessor properties. If the type is implicit,
|
* or 'get' & 'set' accessor properties. If the type is implicit,
|
||||||
* it will be inferred from the value.
|
* it will be inferred from the value.
|
||||||
* e.g. - { value: 42 }
|
* e.g. - { value: 42 }
|
||||||
@ -1104,17 +1149,56 @@ Scope.prototype = {
|
|||||||
* @return Variable
|
* @return Variable
|
||||||
* The newly created Variable instance, null if it already exists.
|
* The newly created Variable instance, null if it already exists.
|
||||||
*/
|
*/
|
||||||
addVar: function(aName = "", aDescriptor = {}, aRelaxed = false) {
|
addItem: function(aName = "", aDescriptor = {}, aRelaxed = false) {
|
||||||
if (this._store.has(aName) && !aRelaxed) {
|
if (this._store.has(aName) && !aRelaxed) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
let variable = new Variable(this, aName, aDescriptor);
|
let child = this._createChild(aName, aDescriptor);
|
||||||
this._store.set(aName, variable);
|
this._store.set(aName, child);
|
||||||
this._variablesView._itemsByElement.set(variable._target, variable);
|
this._variablesView._itemsByElement.set(child._target, child);
|
||||||
this._variablesView._currHierarchy.set(variable._absoluteName, variable);
|
this._variablesView._currHierarchy.set(child._absoluteName, child);
|
||||||
variable.header = !!aName;
|
child.header = !!aName;
|
||||||
return variable;
|
return child;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds items for this variable.
|
||||||
|
*
|
||||||
|
* @param object aItems
|
||||||
|
* An object containing some { name: descriptor } data properties,
|
||||||
|
* specifying the value and/or type & class of the variable,
|
||||||
|
* or 'get' & 'set' accessor properties. If the type is implicit,
|
||||||
|
* it will be inferred from the value.
|
||||||
|
* e.g. - { someProp0: { value: 42 },
|
||||||
|
* someProp1: { value: true },
|
||||||
|
* someProp2: { value: "nasu" },
|
||||||
|
* someProp3: { value: { type: "undefined" } },
|
||||||
|
* someProp4: { value: { type: "null" } },
|
||||||
|
* someProp5: { value: { type: "object", class: "Object" } },
|
||||||
|
* someProp6: { get: { type: "object", class: "Function" },
|
||||||
|
* set: { type: "undefined" } } }
|
||||||
|
* @param object aOptions [optional]
|
||||||
|
* Additional options for adding the properties. Supported options:
|
||||||
|
* - sorted: true to sort all the properties before adding them
|
||||||
|
* - callback: function invoked after each item is added
|
||||||
|
*/
|
||||||
|
addItems: function(aItems, aOptions = {}) {
|
||||||
|
let names = Object.keys(aItems);
|
||||||
|
|
||||||
|
// Sort all of the properties before adding them, if preferred.
|
||||||
|
if (aOptions.sorted) {
|
||||||
|
names.sort();
|
||||||
|
}
|
||||||
|
// Add the properties to the current scope.
|
||||||
|
for (let name of names) {
|
||||||
|
let descriptor = aItems[name];
|
||||||
|
let item = this.addItem(name, descriptor);
|
||||||
|
|
||||||
|
if (aOptions.callback) {
|
||||||
|
aOptions.callback(item, descriptor.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1179,11 +1263,13 @@ Scope.prototype = {
|
|||||||
if (this.isChildOf(aParent)) {
|
if (this.isChildOf(aParent)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (this.ownerView instanceof Scope ||
|
|
||||||
this.ownerView instanceof Variable ||
|
// Recurse to parent if it is a Scope, Variable, or Property.
|
||||||
this.ownerView instanceof Property) {
|
if (this.ownerView instanceof Scope) {
|
||||||
return this.ownerView.isDescendantOf(aParent);
|
return this.ownerView.isDescendantOf(aParent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1405,10 +1491,9 @@ Scope.prototype = {
|
|||||||
}
|
}
|
||||||
// Check if all parent objects are expanded.
|
// Check if all parent objects are expanded.
|
||||||
let item = this;
|
let item = this;
|
||||||
while ((item = item.ownerView) && /* Parent object exists. */
|
|
||||||
(item instanceof Scope ||
|
// Recurse while parent is a Scope, Variable, or Property
|
||||||
item instanceof Variable ||
|
while ((item = item.ownerView) && item instanceof Scope) {
|
||||||
item instanceof Property)) {
|
|
||||||
if (!item._isExpanded) {
|
if (!item._isExpanded) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1722,14 +1807,11 @@ Scope.prototype = {
|
|||||||
variable._wasToggled = true;
|
variable._wasToggled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the variable is contained in another scope (variable or property),
|
// If the variable is contained in another Scope, Variable, or Property,
|
||||||
// the parent may not be a match, thus hidden. It should be visible
|
// the parent may not be a match, thus hidden. It should be visible
|
||||||
// ("expand upwards").
|
// ("expand upwards").
|
||||||
|
|
||||||
while ((variable = variable.ownerView) && /* Parent object exists. */
|
while ((variable = variable.ownerView) && /* Parent object exists. */
|
||||||
(variable instanceof Scope ||
|
variable instanceof Scope) {
|
||||||
variable instanceof Variable ||
|
|
||||||
variable instanceof Property)) {
|
|
||||||
|
|
||||||
// Show and expand the parent, as it is certainly accessible.
|
// Show and expand the parent, as it is certainly accessible.
|
||||||
variable._matched = true;
|
variable._matched = true;
|
||||||
@ -1971,79 +2053,24 @@ function Variable(aScope, aName, aDescriptor) {
|
|||||||
|
|
||||||
ViewHelpers.create({ constructor: Variable, proto: Scope.prototype }, {
|
ViewHelpers.create({ constructor: Variable, proto: Scope.prototype }, {
|
||||||
/**
|
/**
|
||||||
* Adds a property for this variable.
|
* Whether this Scope should be prefetched when it is remoted.
|
||||||
*
|
|
||||||
* @param string aName
|
|
||||||
* The property's name.
|
|
||||||
* @param object aDescriptor
|
|
||||||
* Specifies the value and/or type & class of the property,
|
|
||||||
* or 'get' & 'set' accessor properties. If the type is implicit,
|
|
||||||
* it will be inferred from the value.
|
|
||||||
* e.g. - { value: 42 }
|
|
||||||
* - { value: true }
|
|
||||||
* - { value: "nasu" }
|
|
||||||
* - { value: { type: "undefined" } }
|
|
||||||
* - { value: { type: "null" } }
|
|
||||||
* - { value: { type: "object", class: "Object" } }
|
|
||||||
* - { get: { type: "object", class: "Function" },
|
|
||||||
* set: { type: "undefined" } }
|
|
||||||
* - { get: { type "object", class: "Function" },
|
|
||||||
* getterValue: "foo", getterPrototypeLevel: 2 }
|
|
||||||
* @param boolean aRelaxed
|
|
||||||
* True if name duplicates should be allowed.
|
|
||||||
* @return Property
|
|
||||||
* The newly created Property instance, null if it already exists.
|
|
||||||
*/
|
*/
|
||||||
addProperty: function(aName = "", aDescriptor = {}, aRelaxed = false) {
|
get shouldPrefetch(){
|
||||||
if (this._store.has(aName) && !aRelaxed) {
|
return this.name == "window" || this.name == "this";
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
let property = new Property(this, aName, aDescriptor);
|
|
||||||
this._store.set(aName, property);
|
|
||||||
this._variablesView._itemsByElement.set(property._target, property);
|
|
||||||
this._variablesView._currHierarchy.set(property._absoluteName, property);
|
|
||||||
property.header = !!aName;
|
|
||||||
return property;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds properties for this variable.
|
* Create a new Property that is a child of Variable.
|
||||||
*
|
*
|
||||||
* @param object aProperties
|
* @param string aName
|
||||||
* An object containing some { name: descriptor } data properties,
|
* The name of the new Property.
|
||||||
* specifying the value and/or type & class of the variable,
|
* @param object aDescriptor
|
||||||
* or 'get' & 'set' accessor properties. If the type is implicit,
|
* The property's descriptor.
|
||||||
* it will be inferred from the value.
|
* @return Property
|
||||||
* e.g. - { someProp0: { value: 42 },
|
* The newly created child Property.
|
||||||
* someProp1: { value: true },
|
|
||||||
* someProp2: { value: "nasu" },
|
|
||||||
* someProp3: { value: { type: "undefined" } },
|
|
||||||
* someProp4: { value: { type: "null" } },
|
|
||||||
* someProp5: { value: { type: "object", class: "Object" } },
|
|
||||||
* someProp6: { get: { type: "object", class: "Function" },
|
|
||||||
* set: { type: "undefined" } } }
|
|
||||||
* @param object aOptions [optional]
|
|
||||||
* Additional options for adding the properties. Supported options:
|
|
||||||
* - sorted: true to sort all the properties before adding them
|
|
||||||
* - callback: function invoked after each property is added
|
|
||||||
*/
|
*/
|
||||||
addProperties: function(aProperties, aOptions = {}) {
|
_createChild: function(aName, aDescriptor) {
|
||||||
let propertyNames = Object.keys(aProperties);
|
return new Property(this, aName, aDescriptor);
|
||||||
|
|
||||||
// Sort all of the properties before adding them, if preferred.
|
|
||||||
if (aOptions.sorted) {
|
|
||||||
propertyNames.sort();
|
|
||||||
}
|
|
||||||
// Add the properties to the current scope.
|
|
||||||
for (let name of propertyNames) {
|
|
||||||
let descriptor = aProperties[name];
|
|
||||||
let property = this.addProperty(name, descriptor);
|
|
||||||
|
|
||||||
if (aOptions.callback) {
|
|
||||||
aOptions.callback(property, descriptor.value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2122,7 +2149,7 @@ ViewHelpers.create({ constructor: Variable, proto: Scope.prototype }, {
|
|||||||
let descriptor = Object.create(aDescriptor);
|
let descriptor = Object.create(aDescriptor);
|
||||||
descriptor.value = VariablesView.getGrip(aValue);
|
descriptor.value = VariablesView.getGrip(aValue);
|
||||||
|
|
||||||
let propertyItem = this.addProperty(aName, descriptor);
|
let propertyItem = this.addItem(aName, descriptor);
|
||||||
propertyItem._sourceValue = aValue;
|
propertyItem._sourceValue = aValue;
|
||||||
|
|
||||||
// Add an 'onexpand' callback for the property, lazily handling
|
// Add an 'onexpand' callback for the property, lazily handling
|
||||||
@ -2149,7 +2176,7 @@ ViewHelpers.create({ constructor: Variable, proto: Scope.prototype }, {
|
|||||||
descriptor.get = VariablesView.getGrip(aDescriptor.get);
|
descriptor.get = VariablesView.getGrip(aDescriptor.get);
|
||||||
descriptor.set = VariablesView.getGrip(aDescriptor.set);
|
descriptor.set = VariablesView.getGrip(aDescriptor.set);
|
||||||
|
|
||||||
return this.addProperty(aName, descriptor);
|
return this.addItem(aName, descriptor);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2311,8 +2338,8 @@ ViewHelpers.create({ constructor: Variable, proto: Scope.prototype }, {
|
|||||||
this.evaluationMacro = null;
|
this.evaluationMacro = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
let getter = this.addProperty("get", { value: descriptor.get });
|
let getter = this.addItem("get", { value: descriptor.get });
|
||||||
let setter = this.addProperty("set", { value: descriptor.set });
|
let setter = this.addItem("set", { value: descriptor.set });
|
||||||
getter.evaluationMacro = VariablesView.getterOrSetterEvalMacro;
|
getter.evaluationMacro = VariablesView.getterOrSetterEvalMacro;
|
||||||
setter.evaluationMacro = VariablesView.getterOrSetterEvalMacro;
|
setter.evaluationMacro = VariablesView.getterOrSetterEvalMacro;
|
||||||
|
|
||||||
@ -2852,9 +2879,8 @@ VariablesView.prototype.commitHierarchy = function() {
|
|||||||
if (prevVariable) {
|
if (prevVariable) {
|
||||||
expanded = prevVariable._isExpanded;
|
expanded = prevVariable._isExpanded;
|
||||||
|
|
||||||
// Only analyze variables and properties for displayed value changes.
|
// Only analyze Variables and Properties for displayed value changes.
|
||||||
if (currVariable instanceof Variable ||
|
if (currVariable instanceof Variable) {
|
||||||
currVariable instanceof Property) {
|
|
||||||
changed = prevVariable._valueString != currVariable._valueString;
|
changed = prevVariable._valueString != currVariable._valueString;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2974,6 +3000,16 @@ VariablesView.isFalsy = function(aDescriptor) {
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the value is an instance of Variable or Property.
|
||||||
|
*
|
||||||
|
* @param any aValue
|
||||||
|
* The value to test.
|
||||||
|
*/
|
||||||
|
VariablesView.isVariable = function(aValue) {
|
||||||
|
return aValue instanceof Variable;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a standard grip for a value.
|
* Returns a standard grip for a value.
|
||||||
*
|
*
|
||||||
|
350
browser/devtools/shared/widgets/VariablesViewController.jsm
Normal file
350
browser/devtools/shared/widgets/VariablesViewController.jsm
Normal file
@ -0,0 +1,350 @@
|
|||||||
|
/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||||
|
/* 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";
|
||||||
|
|
||||||
|
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||||
|
|
||||||
|
Cu.import("resource://gre/modules/Services.jsm");
|
||||||
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||||
|
Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js");
|
||||||
|
Cu.import("resource:///modules/devtools/VariablesView.jsm");
|
||||||
|
Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
|
||||||
|
Cu.import("resource://gre/modules/devtools/WebConsoleUtils.jsm");
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyGetter(this, "VARIABLES_SORTING_ENABLED", () =>
|
||||||
|
Services.prefs.getBoolPref("devtools.debugger.ui.variables-sorting-enabled")
|
||||||
|
);
|
||||||
|
|
||||||
|
const MAX_LONG_STRING_LENGTH = 200000;
|
||||||
|
|
||||||
|
this.EXPORTED_SYMBOLS = ["VariablesViewController"];
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controller for a VariablesView that handles interfacing with the debugger
|
||||||
|
* protocol. Is able to populate scopes and variables via the protocol as well
|
||||||
|
* as manage actor lifespans.
|
||||||
|
*
|
||||||
|
* @param VariablesView aView
|
||||||
|
* The view to attach to.
|
||||||
|
* @param object aOptions
|
||||||
|
* Options for configuring the controller. Supported options:
|
||||||
|
* - getGripClient: callback for creating an object grip client
|
||||||
|
* - getLongStringClient: callback for creating a long string grip client
|
||||||
|
* - releaseActor: callback for releasing an actor when it's no longer needed
|
||||||
|
* - overrideValueEvalMacro: callback for creating an overriding eval macro
|
||||||
|
* - getterOrSetterEvalMacro: callback for creating a getter/setter eval macro
|
||||||
|
* - simpleValueEvalMacro: callback for creating a simple value eval macro
|
||||||
|
*/
|
||||||
|
function VariablesViewController(aView, aOptions) {
|
||||||
|
this.addExpander = this.addExpander.bind(this);
|
||||||
|
|
||||||
|
this._getGripClient = aOptions.getGripClient;
|
||||||
|
this._getLongStringClient = aOptions.getLongStringClient;
|
||||||
|
this._releaseActor = aOptions.releaseActor;
|
||||||
|
|
||||||
|
if (aOptions.overrideValueEvalMacro) {
|
||||||
|
this._overrideValueEvalMacro = aOptions.overrideValueEvalMacro;
|
||||||
|
}
|
||||||
|
if (aOptions.getterOrSetterEvalMacro) {
|
||||||
|
this._getterOrSetterEvalMacro = aOptions.getterOrSetterEvalMacro;
|
||||||
|
}
|
||||||
|
if (aOptions.simpleValueEvalMacro) {
|
||||||
|
this._simpleValueEvalMacro = aOptions.simpleValueEvalMacro;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._actors = new Set();
|
||||||
|
this.view = aView;
|
||||||
|
this.view.controller = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
VariablesViewController.prototype = {
|
||||||
|
/**
|
||||||
|
* The default getter/setter evaluation macro.
|
||||||
|
*/
|
||||||
|
_getterOrSetterEvalMacro: VariablesView.getterOrSetterEvalMacro,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default override value evaluation macro.
|
||||||
|
*/
|
||||||
|
_overrideValueEvalMacro: VariablesView.overrideValueEvalMacro,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default simple value evaluation macro.
|
||||||
|
*/
|
||||||
|
_simpleValueEvalMacro: VariablesView.simpleValueEvalMacro,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populate a long string into a target using a grip.
|
||||||
|
*
|
||||||
|
* @param Variable aTarget
|
||||||
|
* The target Variable/Property to put the retrieved string into.
|
||||||
|
* @param LongStringActor aGrip
|
||||||
|
* The long string grip that use to retrieve the full string.
|
||||||
|
* @return Promise
|
||||||
|
* The promise that will be resolved when the string is retrieved.
|
||||||
|
*/
|
||||||
|
_populateFromLongString: function(aTarget, aGrip){
|
||||||
|
let deferred = Promise.defer();
|
||||||
|
|
||||||
|
let from = aGrip.initial.length;
|
||||||
|
let to = Math.min(aGrip.length, MAX_LONG_STRING_LENGTH);
|
||||||
|
|
||||||
|
this._getLongStringClient(aGrip).substring(from, to, aResponse => {
|
||||||
|
// Stop tracking the actor because it's no longer needed.
|
||||||
|
this.releaseActor(aGrip);
|
||||||
|
|
||||||
|
// Replace the preview with the full string and make it non-expandable.
|
||||||
|
aTarget.onexpand = null;
|
||||||
|
aTarget.setGrip(aGrip.initial + aResponse.substring);
|
||||||
|
aTarget.hideArrow();
|
||||||
|
|
||||||
|
// Mark the string as having retrieved.
|
||||||
|
aTarget._retrieved = true;
|
||||||
|
deferred.resolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
return deferred.promise;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds properties to a Scope, Variable, or Property in the view. Triggered
|
||||||
|
* when a scope is expanded or certain variables are hovered.
|
||||||
|
*
|
||||||
|
* @param Scope aTarget
|
||||||
|
* The Scope where the properties will be placed into.
|
||||||
|
* @param object aGrip
|
||||||
|
* The grip to use to populate the target.
|
||||||
|
*/
|
||||||
|
_populateFromObject: function(aTarget, aGrip) {
|
||||||
|
let deferred = Promise.defer();
|
||||||
|
|
||||||
|
this._getGripClient(aGrip).getPrototypeAndProperties(aResponse => {
|
||||||
|
let { ownProperties, prototype, safeGetterValues } = aResponse;
|
||||||
|
let sortable = VariablesView.isSortable(aGrip.class);
|
||||||
|
|
||||||
|
// Merge the safe getter values into one object such that we can use it
|
||||||
|
// in VariablesView.
|
||||||
|
for (let name of Object.keys(safeGetterValues)) {
|
||||||
|
if (name in ownProperties) {
|
||||||
|
ownProperties[name].getterValue = safeGetterValues[name].getterValue;
|
||||||
|
ownProperties[name].getterPrototypeLevel = safeGetterValues[name]
|
||||||
|
.getterPrototypeLevel;
|
||||||
|
} else {
|
||||||
|
ownProperties[name] = safeGetterValues[name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add all the variable properties.
|
||||||
|
if (ownProperties) {
|
||||||
|
aTarget.addItems(ownProperties, {
|
||||||
|
// Not all variables need to force sorted properties.
|
||||||
|
sorted: sortable,
|
||||||
|
// Expansion handlers must be set after the properties are added.
|
||||||
|
callback: this.addExpander
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the variable's __proto__.
|
||||||
|
if (prototype && prototype.type != "null") {
|
||||||
|
let proto = aTarget.addItem("__proto__", { value: prototype });
|
||||||
|
// Expansion handlers must be set after the properties are added.
|
||||||
|
this.addExpander(proto, prototype);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark the variable as having retrieved all its properties.
|
||||||
|
aTarget._retrieved = true;
|
||||||
|
this.view.commitHierarchy();
|
||||||
|
deferred.resolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
return deferred.promise;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an 'onexpand' callback for a variable, lazily handling
|
||||||
|
* the addition of new properties.
|
||||||
|
*
|
||||||
|
* @param Variable aVar
|
||||||
|
* The variable where the properties will be placed into.
|
||||||
|
* @param any aSource
|
||||||
|
* The source to use to populate the target.
|
||||||
|
*/
|
||||||
|
addExpander: function(aTarget, aSource) {
|
||||||
|
// Attach evaluation macros as necessary.
|
||||||
|
if (aTarget.getter || aTarget.setter) {
|
||||||
|
aTarget.evaluationMacro = this._overrideValueEvalMacro;
|
||||||
|
|
||||||
|
let getter = aTarget.get("get");
|
||||||
|
if (getter) {
|
||||||
|
getter.evaluationMacro = this._getterOrSetterEvalMacro;
|
||||||
|
}
|
||||||
|
|
||||||
|
let setter = aTarget.get("set");
|
||||||
|
if (setter) {
|
||||||
|
setter.evaluationMacro = this._getterOrSetterEvalMacro;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
aTarget.evaluationMacro = this._simpleValueEvalMacro;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the source is primitive then an expander is not needed.
|
||||||
|
if (VariablesView.isPrimitive({ value: aSource })) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the source is a long string then show the arrow.
|
||||||
|
if (WebConsoleUtils.isActorGrip(aSource) && aSource.type == "longString") {
|
||||||
|
aTarget.showArrow();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure that properties are always available on expansion.
|
||||||
|
aTarget.onexpand = () => this.expand(aTarget, aSource);
|
||||||
|
|
||||||
|
// Some variables are likely to contain a very large number of properties.
|
||||||
|
// It's a good idea to be prepared in case of an expansion.
|
||||||
|
if (aTarget.shouldPrefetch) {
|
||||||
|
aTarget.addEventListener("mouseover", aTarget.onexpand, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register all the actors that this controller now depends on.
|
||||||
|
for (let grip of [aTarget.value, aTarget.getter, aTarget.setter]) {
|
||||||
|
if (WebConsoleUtils.isActorGrip(grip)) {
|
||||||
|
this._actors.add(grip.actor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds properties to a Scope, Variable, or Property in the view. Triggered
|
||||||
|
* when a scope is expanded or certain variables are hovered.
|
||||||
|
*
|
||||||
|
* @param Scope aTarget
|
||||||
|
* The Scope to be expanded.
|
||||||
|
* @param object aSource
|
||||||
|
* The source to use to populate the target.
|
||||||
|
* @return Promise
|
||||||
|
* The promise that is resolved once the target has been expanded.
|
||||||
|
*/
|
||||||
|
expand: function(aTarget, aSource) {
|
||||||
|
// Fetch the variables only once.
|
||||||
|
if (aTarget._fetched) {
|
||||||
|
return aTarget._fetched;
|
||||||
|
}
|
||||||
|
|
||||||
|
let deferred = Promise.defer();
|
||||||
|
aTarget._fetched = deferred.promise;
|
||||||
|
|
||||||
|
if (!aSource) {
|
||||||
|
throw new Error("No actor grip was given for the variable.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the target a Variable or Property then we're fetching properties
|
||||||
|
if (VariablesView.isVariable(aTarget)) {
|
||||||
|
this._populateFromObject(aTarget, aSource).then(() => {
|
||||||
|
deferred.resolve();
|
||||||
|
// Signal that properties have been fetched.
|
||||||
|
this.view.emit("fetched", "properties", aTarget);
|
||||||
|
});
|
||||||
|
return deferred.promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (aSource.type) {
|
||||||
|
case "longString":
|
||||||
|
this._populateFromLongString(aTarget, aSource).then(() => {
|
||||||
|
deferred.resolve();
|
||||||
|
// Signal that a long string has been fetched.
|
||||||
|
this.view.emit("fetched", "longString", aTarget);
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case "with":
|
||||||
|
case "object":
|
||||||
|
this._populateFromObject(aTarget, aSource.object).then(() => {
|
||||||
|
deferred.resolve();
|
||||||
|
// Signal that variables have been fetched.
|
||||||
|
this.view.emit("fetched", "variables", aTarget);
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case "block":
|
||||||
|
case "function":
|
||||||
|
// Add nodes for every argument and every other variable in scope.
|
||||||
|
let args = aSource.bindings.arguments;
|
||||||
|
if (args) {
|
||||||
|
for (let arg of args) {
|
||||||
|
let name = Object.getOwnPropertyNames(arg)[0];
|
||||||
|
let ref = aTarget.addItem(name, arg[name]);
|
||||||
|
let val = arg[name].value;
|
||||||
|
this.addExpander(ref, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
aTarget.addItems(aSource.bindings.variables, {
|
||||||
|
// Not all variables need to force sorted properties.
|
||||||
|
sorted: VARIABLES_SORTING_ENABLED,
|
||||||
|
// Expansion handlers must be set after the properties are added.
|
||||||
|
callback: this.addExpander
|
||||||
|
});
|
||||||
|
|
||||||
|
// No need to signal that variables have been fetched, since
|
||||||
|
// the scope arguments and variables are already attached to the
|
||||||
|
// environment bindings, so pausing the active thread is unnecessary.
|
||||||
|
|
||||||
|
deferred.resolve();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
let error = "Unknown Debugger.Environment type: " + aSource.type;
|
||||||
|
Cu.reportError(error);
|
||||||
|
deferred.reject(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return deferred.promise;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Release an actor from the controller.
|
||||||
|
*
|
||||||
|
* @param object aActor
|
||||||
|
* The actor to release.
|
||||||
|
*/
|
||||||
|
releaseActor: function(aActor){
|
||||||
|
if (this._releaseActor) {
|
||||||
|
this._releaseActor(aActor);
|
||||||
|
}
|
||||||
|
this._actors.delete(aActor);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Release all the actors referenced by the controller, optionally filtered.
|
||||||
|
*
|
||||||
|
* @param function aFilter [optional]
|
||||||
|
* Callback to filter which actors are released.
|
||||||
|
*/
|
||||||
|
releaseActors: function(aFilter) {
|
||||||
|
for (let actor of this._actors) {
|
||||||
|
if (!aFilter || aFilter(actor)) {
|
||||||
|
this.releaseActor(actor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attaches a VariablesViewController to a VariablesView if it doesn't already
|
||||||
|
* have one.
|
||||||
|
*
|
||||||
|
* @param VariablesView aView
|
||||||
|
* The view to attach to.
|
||||||
|
* @param object aOptions
|
||||||
|
* The options to use in creating the controller.
|
||||||
|
* @return VariablesViewController
|
||||||
|
*/
|
||||||
|
VariablesViewController.attach = function(aView, aOptions) {
|
||||||
|
if (aView.controller) {
|
||||||
|
return aView.controller;
|
||||||
|
}
|
||||||
|
return new VariablesViewController(aView, aOptions);
|
||||||
|
};
|
@ -91,16 +91,16 @@ StyleEditorPanel.prototype = {
|
|||||||
* @param {string} href
|
* @param {string} href
|
||||||
* Url of stylesheet to find and select in editor
|
* Url of stylesheet to find and select in editor
|
||||||
* @param {number} line
|
* @param {number} line
|
||||||
* Line number to jump to after selecting
|
* Line number to jump to after selecting. One-indexed
|
||||||
* @param {number} col
|
* @param {number} col
|
||||||
* Column number to jump to after selecting
|
* Column number to jump to after selecting. One-indexed
|
||||||
*/
|
*/
|
||||||
selectStyleSheet: function(href, line, col) {
|
selectStyleSheet: function(href, line, col) {
|
||||||
if (!this._debuggee || !this.UI) {
|
if (!this._debuggee || !this.UI) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let stylesheet = this._debuggee.styleSheetFromHref(href);
|
let stylesheet = this._debuggee.styleSheetFromHref(href);
|
||||||
this.UI.selectStyleSheet(href, line, col);
|
this.UI.selectStyleSheet(href, line - 1, col - 1);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -48,7 +48,7 @@ function StyleEditorUI(debuggee, panelDoc) {
|
|||||||
this._root = this._panelDoc.getElementById("style-editor-chrome");
|
this._root = this._panelDoc.getElementById("style-editor-chrome");
|
||||||
|
|
||||||
this.editors = [];
|
this.editors = [];
|
||||||
this.selectedStyleSheetIndex = -1;
|
this.selectedEditor = null;
|
||||||
|
|
||||||
this._onStyleSheetCreated = this._onStyleSheetCreated.bind(this);
|
this._onStyleSheetCreated = this._onStyleSheetCreated.bind(this);
|
||||||
this._onStyleSheetsCleared = this._onStyleSheetsCleared.bind(this);
|
this._onStyleSheetsCleared = this._onStyleSheetsCleared.bind(this);
|
||||||
@ -84,6 +84,14 @@ StyleEditorUI.prototype = {
|
|||||||
this._markedDirty = value;
|
this._markedDirty = value;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Index of selected stylesheet in document.styleSheets
|
||||||
|
*/
|
||||||
|
get selectedStyleSheetIndex() {
|
||||||
|
return this.selectedEditor ?
|
||||||
|
this.selectedEditor.styleSheet.styleSheetIndex : -1;
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build the initial UI and wire buttons with event handlers.
|
* Build the initial UI and wire buttons with event handlers.
|
||||||
*/
|
*/
|
||||||
@ -140,10 +148,17 @@ StyleEditorUI.prototype = {
|
|||||||
* Handler for debuggee's 'stylesheets-cleared' event. Remove all editors.
|
* Handler for debuggee's 'stylesheets-cleared' event. Remove all editors.
|
||||||
*/
|
*/
|
||||||
_onStyleSheetsCleared: function() {
|
_onStyleSheetsCleared: function() {
|
||||||
this._clearStyleSheetEditors();
|
// remember selected sheet and line number for next load
|
||||||
|
if (this.selectedEditor) {
|
||||||
|
let href = this.selectedEditor.styleSheet.href;
|
||||||
|
let {line, col} = this.selectedEditor.sourceEditor.getCaretPosition();
|
||||||
|
this.selectStyleSheet(href, line, col);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._clearStyleSheetEditors();
|
||||||
this._view.removeAll();
|
this._view.removeAll();
|
||||||
this.selectedStyleSheetIndex = -1;
|
|
||||||
|
this.selectedEditor = null;
|
||||||
|
|
||||||
this._root.classList.add("loading");
|
this._root.classList.add("loading");
|
||||||
},
|
},
|
||||||
@ -166,11 +181,22 @@ StyleEditorUI.prototype = {
|
|||||||
* StyleSheet object for new sheet
|
* StyleSheet object for new sheet
|
||||||
*/
|
*/
|
||||||
_onDocumentLoad: function(event, styleSheets) {
|
_onDocumentLoad: function(event, styleSheets) {
|
||||||
|
if (this._styleSheetToSelect) {
|
||||||
|
// if selected stylesheet from previous load isn't here,
|
||||||
|
// just set first stylesheet to be selected instead
|
||||||
|
let selectedExists = styleSheets.some((sheet) => {
|
||||||
|
return this._styleSheetToSelect.href == sheet.href;
|
||||||
|
})
|
||||||
|
if (!selectedExists) {
|
||||||
|
this._styleSheetToSelect = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
for (let sheet of styleSheets) {
|
for (let sheet of styleSheets) {
|
||||||
this._addStyleSheetEditor(sheet);
|
this._addStyleSheetEditor(sheet);
|
||||||
}
|
}
|
||||||
// this might be the first stylesheet, so remove loading indicator
|
|
||||||
this._root.classList.remove("loading");
|
this._root.classList.remove("loading");
|
||||||
|
|
||||||
this.emit("document-load");
|
this.emit("document-load");
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -295,13 +321,18 @@ StyleEditorUI.prototype = {
|
|||||||
|
|
||||||
onShow: function(summary, details, data) {
|
onShow: function(summary, details, data) {
|
||||||
let editor = data.editor;
|
let editor = data.editor;
|
||||||
|
this.selectedEditor = editor;
|
||||||
|
this._styleSheetToSelect = null;
|
||||||
|
|
||||||
if (!editor.sourceEditor) {
|
if (!editor.sourceEditor) {
|
||||||
// only initialize source editor when we switch to this view
|
// only initialize source editor when we switch to this view
|
||||||
let inputElement = details.querySelector(".stylesheet-editor-input");
|
let inputElement = details.querySelector(".stylesheet-editor-input");
|
||||||
editor.load(inputElement);
|
editor.load(inputElement);
|
||||||
}
|
}
|
||||||
editor.onShow();
|
editor.onShow();
|
||||||
}
|
|
||||||
|
this.emit("editor-selected", editor);
|
||||||
|
}.bind(this)
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -314,7 +345,6 @@ StyleEditorUI.prototype = {
|
|||||||
for each (let editor in this.editors) {
|
for each (let editor in this.editors) {
|
||||||
if (editor.styleSheet.href == sheet.href) {
|
if (editor.styleSheet.href == sheet.href) {
|
||||||
this._selectEditor(editor, sheet.line, sheet.col);
|
this._selectEditor(editor, sheet.line, sheet.col);
|
||||||
this._styleSheetToSelect = null;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -331,18 +361,14 @@ StyleEditorUI.prototype = {
|
|||||||
* Column number to jump to
|
* Column number to jump to
|
||||||
*/
|
*/
|
||||||
_selectEditor: function(editor, line, col) {
|
_selectEditor: function(editor, line, col) {
|
||||||
line = line || 1;
|
line = line || 0;
|
||||||
col = col || 1;
|
col = col || 0;
|
||||||
|
|
||||||
this.selectedStyleSheetIndex = editor.styleSheet.styleSheetIndex;
|
|
||||||
|
|
||||||
editor.getSourceEditor().then(() => {
|
editor.getSourceEditor().then(() => {
|
||||||
editor.sourceEditor.setCaretPosition(line - 1, col - 1);
|
editor.sourceEditor.setCaretPosition(line, col);
|
||||||
});
|
});
|
||||||
|
|
||||||
this._view.activeSummary = editor.summary;
|
this._view.activeSummary = editor.summary;
|
||||||
|
|
||||||
this.emit("editor-selected", editor);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -354,9 +380,9 @@ StyleEditorUI.prototype = {
|
|||||||
* a stylesheet is not passed and the editor is initialized we ignore
|
* a stylesheet is not passed and the editor is initialized we ignore
|
||||||
* the call.
|
* the call.
|
||||||
* @param {Number} [line]
|
* @param {Number} [line]
|
||||||
* Line to which the caret should be moved (one-indexed).
|
* Line to which the caret should be moved (zero-indexed).
|
||||||
* @param {Number} [col]
|
* @param {Number} [col]
|
||||||
* Column to which the caret should be moved (one-indexed).
|
* Column to which the caret should be moved (zero-indexed).
|
||||||
*/
|
*/
|
||||||
selectStyleSheet: function(href, line, col)
|
selectStyleSheet: function(href, line, col)
|
||||||
{
|
{
|
||||||
|
@ -28,6 +28,7 @@ _BROWSER_TEST_FILES = \
|
|||||||
browser_styleeditor_bug_740541_iframes.js \
|
browser_styleeditor_bug_740541_iframes.js \
|
||||||
browser_styleeditor_bug_851132_middle_click.js \
|
browser_styleeditor_bug_851132_middle_click.js \
|
||||||
browser_styleeditor_nostyle.js \
|
browser_styleeditor_nostyle.js \
|
||||||
|
browser_styleeditor_reload.js \
|
||||||
head.js \
|
head.js \
|
||||||
four.html \
|
four.html \
|
||||||
head.js \
|
head.js \
|
||||||
|
@ -0,0 +1,99 @@
|
|||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
const TESTCASE_URI = TEST_BASE_HTTPS + "simple.html";
|
||||||
|
const NEW_URI = TEST_BASE_HTTPS + "media.html";
|
||||||
|
|
||||||
|
const LINE_NO = 5;
|
||||||
|
const COL_NO = 3;
|
||||||
|
|
||||||
|
let gContentWin;
|
||||||
|
let gUI;
|
||||||
|
|
||||||
|
function test()
|
||||||
|
{
|
||||||
|
waitForExplicitFinish();
|
||||||
|
|
||||||
|
addTabAndOpenStyleEditor(function(panel) {
|
||||||
|
gContentWin = gBrowser.selectedTab.linkedBrowser.contentWindow.wrappedJSObject;
|
||||||
|
gUI = panel.UI;
|
||||||
|
|
||||||
|
let count = 0;
|
||||||
|
gUI.on("editor-added", function editorAdded(event, editor) {
|
||||||
|
if (++count == 2) {
|
||||||
|
gUI.off("editor-added", editorAdded);
|
||||||
|
gUI.editors[0].getSourceEditor().then(runTests);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
content.location = TESTCASE_URI;
|
||||||
|
}
|
||||||
|
|
||||||
|
function runTests()
|
||||||
|
{
|
||||||
|
let count = 0;
|
||||||
|
gUI.once("editor-selected", (event, editor) => {
|
||||||
|
editor.getSourceEditor().then(() => {
|
||||||
|
info("selected second editor, about to reload page");
|
||||||
|
reloadPage();
|
||||||
|
|
||||||
|
gUI.on("editor-added", function editorAdded(event, editor) {
|
||||||
|
if (++count == 2) {
|
||||||
|
gUI.off("editor-added", editorAdded);
|
||||||
|
gUI.editors[1].getSourceEditor().then(testRemembered);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
gUI.selectStyleSheet(gUI.editors[1].styleSheet.href, LINE_NO, COL_NO);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testRemembered()
|
||||||
|
{
|
||||||
|
is(gUI.selectedEditor, gUI.editors[1], "second editor is selected");
|
||||||
|
|
||||||
|
let {line, col} = gUI.selectedEditor.sourceEditor.getCaretPosition();
|
||||||
|
is(line, LINE_NO, "correct line selected");
|
||||||
|
is(col, COL_NO, "correct column selected");
|
||||||
|
|
||||||
|
testNewPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
function testNewPage()
|
||||||
|
{
|
||||||
|
let count = 0;
|
||||||
|
gUI.on("editor-added", function editorAdded(event, editor) {
|
||||||
|
info("editor added here")
|
||||||
|
if (++count == 2) {
|
||||||
|
gUI.off("editor-added", editorAdded);
|
||||||
|
gUI.editors[0].getSourceEditor().then(testNotRemembered);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
info("navigating to a different page");
|
||||||
|
navigatePage();
|
||||||
|
}
|
||||||
|
|
||||||
|
function testNotRemembered()
|
||||||
|
{
|
||||||
|
is(gUI.selectedEditor, gUI.editors[0], "first editor is selected");
|
||||||
|
|
||||||
|
let {line, col} = gUI.selectedEditor.sourceEditor.getCaretPosition();
|
||||||
|
is(line, 0, "first line is selected");
|
||||||
|
is(col, 0, "first column is selected");
|
||||||
|
|
||||||
|
gUI = null;
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
function reloadPage()
|
||||||
|
{
|
||||||
|
gContentWin.location.reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
function navigatePage()
|
||||||
|
{
|
||||||
|
gContentWin.location = NEW_URI;
|
||||||
|
}
|
@ -49,6 +49,7 @@ MOCHITEST_BROWSER_FILES = \
|
|||||||
browser_webconsole_bug_580454_timestamp_l10n.js \
|
browser_webconsole_bug_580454_timestamp_l10n.js \
|
||||||
browser_webconsole_netlogging.js \
|
browser_webconsole_netlogging.js \
|
||||||
browser_webconsole_bug_583816_No_input_and_Tab_key_pressed.js \
|
browser_webconsole_bug_583816_No_input_and_Tab_key_pressed.js \
|
||||||
|
browser_webconsole_bug_734061_No_input_change_and_Tab_key_pressed.js \
|
||||||
browser_webconsole_bug_594477_clickable_output.js \
|
browser_webconsole_bug_594477_clickable_output.js \
|
||||||
browser_webconsole_bug_589162_css_filter.js \
|
browser_webconsole_bug_589162_css_filter.js \
|
||||||
browser_webconsole_bug_597103_deactivateHUDForContext_unfocused_window.js \
|
browser_webconsole_bug_597103_deactivateHUDForContext_unfocused_window.js \
|
||||||
|
@ -0,0 +1,39 @@
|
|||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/browser/test-console.html";
|
||||||
|
|
||||||
|
function test() {
|
||||||
|
addTab(TEST_URI);
|
||||||
|
browser.addEventListener("load", function onLoad() {
|
||||||
|
browser.removeEventListener("load", onLoad, true);
|
||||||
|
openConsole(null, testInputChange);
|
||||||
|
}, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testInputChange(hud) {
|
||||||
|
var jsterm = hud.jsterm;
|
||||||
|
var input = jsterm.inputNode;
|
||||||
|
|
||||||
|
is(input.getAttribute("focused"), "true", "input has focus");
|
||||||
|
EventUtils.synthesizeKey("VK_TAB", {});
|
||||||
|
is(input.getAttribute("focused"), "", "focus moved away");
|
||||||
|
|
||||||
|
// Test user changed something
|
||||||
|
input.focus();
|
||||||
|
EventUtils.synthesizeKey("A", {});
|
||||||
|
EventUtils.synthesizeKey("VK_TAB", {});
|
||||||
|
is(input.getAttribute("focused"), "true", "input is still focused");
|
||||||
|
|
||||||
|
// Test non empty input but not changed since last focus
|
||||||
|
input.blur();
|
||||||
|
input.focus();
|
||||||
|
EventUtils.synthesizeKey("VK_RIGHT", {});
|
||||||
|
EventUtils.synthesizeKey("VK_TAB", {});
|
||||||
|
is(input.getAttribute("focused"), "", "input moved away");
|
||||||
|
|
||||||
|
jsterm = input = null;
|
||||||
|
finishTest();
|
||||||
|
}
|
@ -8,7 +8,7 @@
|
|||||||
// Tests that the Web Console CSP messages are displayed
|
// Tests that the Web Console CSP messages are displayed
|
||||||
|
|
||||||
const TEST_VIOLATION = "https://example.com/browser/browser/devtools/webconsole/test/test_bug_770099_violation.html";
|
const TEST_VIOLATION = "https://example.com/browser/browser/devtools/webconsole/test/test_bug_770099_violation.html";
|
||||||
const CSP_VIOLATION_MSG = "CSP WARN: Directive default-src https://example.com:443 violated by http://some.example.com/test.png"
|
const CSP_VIOLATION_MSG = "Content Security Policy: Directive default-src https://example.com:443 violated by http://some.example.com/test.png"
|
||||||
|
|
||||||
let hud = undefined;
|
let hud = undefined;
|
||||||
|
|
||||||
|
@ -37,6 +37,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
|||||||
XPCOMUtils.defineLazyModuleGetter(this, "VariablesView",
|
XPCOMUtils.defineLazyModuleGetter(this, "VariablesView",
|
||||||
"resource:///modules/devtools/VariablesView.jsm");
|
"resource:///modules/devtools/VariablesView.jsm");
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyModuleGetter(this, "VariablesViewController",
|
||||||
|
"resource:///modules/devtools/VariablesViewController.jsm");
|
||||||
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "EventEmitter",
|
XPCOMUtils.defineLazyModuleGetter(this, "EventEmitter",
|
||||||
"resource:///modules/devtools/shared/event-emitter.js");
|
"resource:///modules/devtools/shared/event-emitter.js");
|
||||||
|
|
||||||
@ -2104,13 +2107,9 @@ WebConsoleFrame.prototype = {
|
|||||||
}
|
}
|
||||||
else if (aNode.classList.contains("webconsole-msg-inspector")) {
|
else if (aNode.classList.contains("webconsole-msg-inspector")) {
|
||||||
let view = aNode._variablesView;
|
let view = aNode._variablesView;
|
||||||
let actors = view ?
|
if (view) {
|
||||||
this.jsterm._objectActorsInVariablesViews.get(view) :
|
view.controller.releaseActors();
|
||||||
new Set();
|
|
||||||
for (let actor of actors) {
|
|
||||||
this._releaseObject(actor);
|
|
||||||
}
|
}
|
||||||
actors.clear();
|
|
||||||
aNode._variablesView = null;
|
aNode._variablesView = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2743,6 +2742,35 @@ WebConsoleFrame.prototype = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see VariablesView.simpleValueEvalMacro
|
||||||
|
*/
|
||||||
|
function simpleValueEvalMacro(aItem, aCurrentString)
|
||||||
|
{
|
||||||
|
return VariablesView.simpleValueEvalMacro(aItem, aCurrentString, "_self");
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see VariablesView.overrideValueEvalMacro
|
||||||
|
*/
|
||||||
|
function overrideValueEvalMacro(aItem, aCurrentString)
|
||||||
|
{
|
||||||
|
return VariablesView.overrideValueEvalMacro(aItem, aCurrentString, "_self");
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see VariablesView.getterOrSetterEvalMacro
|
||||||
|
*/
|
||||||
|
function getterOrSetterEvalMacro(aItem, aCurrentString)
|
||||||
|
{
|
||||||
|
return VariablesView.getterOrSetterEvalMacro(aItem, aCurrentString, "_self");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a JSTerminal (a JavaScript command line). This is attached to an
|
* Create a JSTerminal (a JavaScript command line). This is attached to an
|
||||||
* existing HeadsUpDisplay (a Web Console instance). This code is responsible
|
* existing HeadsUpDisplay (a Web Console instance). This code is responsible
|
||||||
@ -2769,10 +2797,9 @@ function JSTerm(aWebConsoleFrame)
|
|||||||
this.historyPlaceHolder = 0;
|
this.historyPlaceHolder = 0;
|
||||||
this._objectActorsInVariablesViews = new Map();
|
this._objectActorsInVariablesViews = new Map();
|
||||||
|
|
||||||
this._keyPress = this.keyPress.bind(this);
|
this._keyPress = this._keyPress.bind(this);
|
||||||
this._inputEventHandler = this.inputEventHandler.bind(this);
|
this._inputEventHandler = this._inputEventHandler.bind(this);
|
||||||
this._fetchVarProperties = this._fetchVarProperties.bind(this);
|
this._focusEventHandler = this._focusEventHandler.bind(this);
|
||||||
this._fetchVarLongString = this._fetchVarLongString.bind(this);
|
|
||||||
this._onKeypressInVariablesView = this._onKeypressInVariablesView.bind(this);
|
this._onKeypressInVariablesView = this._onKeypressInVariablesView.bind(this);
|
||||||
|
|
||||||
EventEmitter.decorate(this);
|
EventEmitter.decorate(this);
|
||||||
@ -2826,12 +2853,19 @@ JSTerm.prototype = {
|
|||||||
*/
|
*/
|
||||||
lastInputValue: "",
|
lastInputValue: "",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicate input node changed since last focus.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @type boolean
|
||||||
|
*/
|
||||||
|
_inputChanged: false,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* History of code that was executed.
|
* History of code that was executed.
|
||||||
* @type array
|
* @type array
|
||||||
*/
|
*/
|
||||||
history: null,
|
history: null,
|
||||||
|
|
||||||
autocompletePopup: null,
|
autocompletePopup: null,
|
||||||
inputNode: null,
|
inputNode: null,
|
||||||
completeNode: null,
|
completeNode: null,
|
||||||
@ -2877,6 +2911,7 @@ JSTerm.prototype = {
|
|||||||
this.inputNode.addEventListener("keypress", this._keyPress, false);
|
this.inputNode.addEventListener("keypress", this._keyPress, false);
|
||||||
this.inputNode.addEventListener("input", this._inputEventHandler, false);
|
this.inputNode.addEventListener("input", this._inputEventHandler, false);
|
||||||
this.inputNode.addEventListener("keyup", this._inputEventHandler, false);
|
this.inputNode.addEventListener("keyup", this._inputEventHandler, false);
|
||||||
|
this.inputNode.addEventListener("focus", this._focusEventHandler, false);
|
||||||
|
|
||||||
this.lastInputValue && this.setInputValue(this.lastInputValue);
|
this.lastInputValue && this.setInputValue(this.lastInputValue);
|
||||||
},
|
},
|
||||||
@ -3282,7 +3317,27 @@ JSTerm.prototype = {
|
|||||||
view.searchEnabled = !aOptions.hideFilterInput;
|
view.searchEnabled = !aOptions.hideFilterInput;
|
||||||
view.lazyEmpty = this._lazyVariablesView;
|
view.lazyEmpty = this._lazyVariablesView;
|
||||||
view.lazyAppend = this._lazyVariablesView;
|
view.lazyAppend = this._lazyVariablesView;
|
||||||
this._objectActorsInVariablesViews.set(view, new Set());
|
|
||||||
|
VariablesViewController.attach(view, {
|
||||||
|
getGripClient: aGrip => {
|
||||||
|
return new GripClient(this.hud.proxy.client, aGrip);
|
||||||
|
},
|
||||||
|
getLongStringClient: aGrip => {
|
||||||
|
return this.webConsoleClient.longString(aGrip);
|
||||||
|
},
|
||||||
|
releaseActor: aActor => {
|
||||||
|
this.hud._releaseObject(aActor);
|
||||||
|
},
|
||||||
|
simpleValueEvalMacro: simpleValueEvalMacro,
|
||||||
|
overrideValueEvalMacro: overrideValueEvalMacro,
|
||||||
|
getterOrSetterEvalMacro: getterOrSetterEvalMacro,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Relay events from the VariablesView.
|
||||||
|
view.on("fetched", (aEvent, aType, aVar) => {
|
||||||
|
this.emit("variablesview-fetched", aVar);
|
||||||
|
});
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -3304,16 +3359,11 @@ JSTerm.prototype = {
|
|||||||
view.createHierarchy();
|
view.createHierarchy();
|
||||||
view.empty();
|
view.empty();
|
||||||
|
|
||||||
let actors = this._objectActorsInVariablesViews.get(view);
|
// We need to avoid pruning the object inspection starting point.
|
||||||
for (let actor of actors) {
|
// That one is pruned when the console message is removed.
|
||||||
// We need to avoid pruning the object inspection starting point.
|
view.controller.releaseActors(aActor => {
|
||||||
// That one is pruned when the console message is removed.
|
return view._consoleLastObjectActor != aActor;
|
||||||
if (view._consoleLastObjectActor != actor) {
|
});
|
||||||
this.hud._releaseObject(actor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
actors.clear();
|
|
||||||
|
|
||||||
if (aOptions.objectActor) {
|
if (aOptions.objectActor) {
|
||||||
// Make sure eval works in the correct context.
|
// Make sure eval works in the correct context.
|
||||||
@ -3331,11 +3381,11 @@ JSTerm.prototype = {
|
|||||||
scope.expanded = true;
|
scope.expanded = true;
|
||||||
scope.locked = true;
|
scope.locked = true;
|
||||||
|
|
||||||
let container = scope.addVar();
|
let container = scope.addItem();
|
||||||
container.evaluationMacro = this._variablesViewSimpleValueEvalMacro;
|
container.evaluationMacro = simpleValueEvalMacro;
|
||||||
|
|
||||||
if (aOptions.objectActor) {
|
if (aOptions.objectActor) {
|
||||||
this._fetchVarProperties(container, aOptions.objectActor);
|
view.controller.expand(container, aOptions.objectActor);
|
||||||
view._consoleLastObjectActor = aOptions.objectActor.actor;
|
view._consoleLastObjectActor = aOptions.objectActor.actor;
|
||||||
}
|
}
|
||||||
else if (aOptions.rawObject) {
|
else if (aOptions.rawObject) {
|
||||||
@ -3374,80 +3424,6 @@ JSTerm.prototype = {
|
|||||||
this.requestEvaluation(aString, evalOptions).then(onEval, onEval);
|
this.requestEvaluation(aString, evalOptions).then(onEval, onEval);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates the string evaluated when performing simple value changes in the
|
|
||||||
* variables view.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @param Variable | Property aItem
|
|
||||||
* The current variable or property.
|
|
||||||
* @param string aCurrentString
|
|
||||||
* The trimmed user inputted string.
|
|
||||||
* @return string
|
|
||||||
* The string to be evaluated.
|
|
||||||
*/
|
|
||||||
_variablesViewSimpleValueEvalMacro:
|
|
||||||
function JST__variablesViewSimpleValueEvalMacro(aItem, aCurrentString)
|
|
||||||
{
|
|
||||||
return "_self" + aItem.symbolicName + "=" + aCurrentString;
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates the string evaluated when overriding getters and setters with
|
|
||||||
* plain values in the variables view.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @param Property aItem
|
|
||||||
* The current getter or setter property.
|
|
||||||
* @param string aCurrentString
|
|
||||||
* The trimmed user inputted string.
|
|
||||||
* @return string
|
|
||||||
* The string to be evaluated.
|
|
||||||
*/
|
|
||||||
_variablesViewOverrideValueEvalMacro:
|
|
||||||
function JST__variablesViewOverrideValueEvalMacro(aItem, aCurrentString)
|
|
||||||
{
|
|
||||||
let parent = aItem.ownerView;
|
|
||||||
let symbolicName = parent.symbolicName;
|
|
||||||
if (symbolicName.indexOf("_self") != 0) {
|
|
||||||
parent._symbolicName = "_self" + symbolicName;
|
|
||||||
}
|
|
||||||
|
|
||||||
let result = VariablesView.overrideValueEvalMacro.apply(this, arguments);
|
|
||||||
|
|
||||||
parent._symbolicName = symbolicName;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates the string evaluated when performing getters and setters changes
|
|
||||||
* in the variables view.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @param Property aItem
|
|
||||||
* The current getter or setter property.
|
|
||||||
* @param string aCurrentString
|
|
||||||
* The trimmed user inputted string.
|
|
||||||
* @return string
|
|
||||||
* The string to be evaluated.
|
|
||||||
*/
|
|
||||||
_variablesViewGetterOrSetterEvalMacro:
|
|
||||||
function JST__variablesViewGetterOrSetterEvalMacro(aItem, aCurrentString)
|
|
||||||
{
|
|
||||||
let propertyObject = aItem.ownerView;
|
|
||||||
let parentObject = propertyObject.ownerView;
|
|
||||||
let parent = parentObject.symbolicName;
|
|
||||||
parentObject._symbolicName = "_self" + parent;
|
|
||||||
|
|
||||||
let result = VariablesView.getterOrSetterEvalMacro.apply(this, arguments);
|
|
||||||
|
|
||||||
parentObject._symbolicName = parent;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The property deletion function used by the variables view when a property
|
* The property deletion function used by the variables view when a property
|
||||||
* is deleted.
|
* is deleted.
|
||||||
@ -3556,144 +3532,7 @@ JSTerm.prototype = {
|
|||||||
aCallback && aCallback(aResponse);
|
aCallback && aCallback(aResponse);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds properties to a variable in the view. Triggered when a variable is
|
|
||||||
* expanded. It does not expand the variable.
|
|
||||||
*
|
|
||||||
* @param object aVar
|
|
||||||
* The VariablseView Variable instance where the properties get added.
|
|
||||||
* @param object [aGrip]
|
|
||||||
* Optional, the object actor grip of the variable. If the grip is not
|
|
||||||
* provided, then the aVar.value is used as the object actor grip.
|
|
||||||
*/
|
|
||||||
_fetchVarProperties: function JST__fetchVarProperties(aVar, aGrip)
|
|
||||||
{
|
|
||||||
// Retrieve the properties only once.
|
|
||||||
if (aVar._fetched) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
aVar._fetched = true;
|
|
||||||
|
|
||||||
let grip = aGrip || aVar.value;
|
|
||||||
if (!grip) {
|
|
||||||
throw new Error("No object actor grip was given for the variable.");
|
|
||||||
}
|
|
||||||
|
|
||||||
let view = aVar._variablesView;
|
|
||||||
let actors = this._objectActorsInVariablesViews.get(view);
|
|
||||||
|
|
||||||
function addActorForDescriptor(aGrip) {
|
|
||||||
if (WebConsoleUtils.isActorGrip(aGrip)) {
|
|
||||||
actors.add(aGrip.actor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let onNewProperty = (aProperty) => {
|
|
||||||
if (aProperty.getter || aProperty.setter) {
|
|
||||||
aProperty.evaluationMacro = this._variablesViewOverrideValueEvalMacro;
|
|
||||||
let getter = aProperty.get("get");
|
|
||||||
let setter = aProperty.get("set");
|
|
||||||
if (getter) {
|
|
||||||
getter.evaluationMacro = this._variablesViewGetterOrSetterEvalMacro;
|
|
||||||
}
|
|
||||||
if (setter) {
|
|
||||||
setter.evaluationMacro = this._variablesViewGetterOrSetterEvalMacro;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
aProperty.evaluationMacro = this._variablesViewSimpleValueEvalMacro;
|
|
||||||
}
|
|
||||||
|
|
||||||
let grips = [aProperty.value, aProperty.getter, aProperty.setter];
|
|
||||||
grips.forEach(addActorForDescriptor);
|
|
||||||
|
|
||||||
let inspectable = !VariablesView.isPrimitive({ value: aProperty.value });
|
|
||||||
let longString = WebConsoleUtils.isActorGrip(aProperty.value) &&
|
|
||||||
aProperty.value.type == "longString";
|
|
||||||
if (inspectable) {
|
|
||||||
aProperty.onexpand = this._fetchVarProperties;
|
|
||||||
}
|
|
||||||
else if (longString) {
|
|
||||||
aProperty.onexpand = this._fetchVarLongString;
|
|
||||||
aProperty.showArrow();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let client = new GripClient(this.hud.proxy.client, grip);
|
|
||||||
client.getPrototypeAndProperties((aResponse) => {
|
|
||||||
let { ownProperties, prototype, safeGetterValues } = aResponse;
|
|
||||||
let sortable = VariablesView.NON_SORTABLE_CLASSES.indexOf(grip.class) == -1;
|
|
||||||
|
|
||||||
// Merge the safe getter values into one object such that we can use it
|
|
||||||
// in VariablesView.
|
|
||||||
for (let name of Object.keys(safeGetterValues)) {
|
|
||||||
if (name in ownProperties) {
|
|
||||||
ownProperties[name].getterValue = safeGetterValues[name].getterValue;
|
|
||||||
ownProperties[name].getterPrototypeLevel = safeGetterValues[name]
|
|
||||||
.getterPrototypeLevel;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ownProperties[name] = safeGetterValues[name];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add all the variable properties.
|
|
||||||
if (ownProperties) {
|
|
||||||
aVar.addProperties(ownProperties, {
|
|
||||||
sorted: sortable,
|
|
||||||
callback: onNewProperty,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the variable's __proto__.
|
|
||||||
if (prototype && prototype.type != "null") {
|
|
||||||
let proto = aVar.addProperty("__proto__", { value: prototype });
|
|
||||||
onNewProperty(proto);
|
|
||||||
}
|
|
||||||
|
|
||||||
aVar._retrieved = true;
|
|
||||||
view.commitHierarchy();
|
|
||||||
this.emit("variablesview-fetched", aVar);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetch the full string for a given variable that displays a long string.
|
|
||||||
*
|
|
||||||
* @param object aVar
|
|
||||||
* The VariablesView Variable instance where the properties get added.
|
|
||||||
*/
|
|
||||||
_fetchVarLongString: function JST__fetchVarLongString(aVar)
|
|
||||||
{
|
|
||||||
if (aVar._fetched) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
aVar._fetched = true;
|
|
||||||
|
|
||||||
let grip = aVar.value;
|
|
||||||
if (!grip) {
|
|
||||||
throw new Error("No long string actor grip was given for the variable.");
|
|
||||||
}
|
|
||||||
|
|
||||||
let client = this.webConsoleClient.longString(grip);
|
|
||||||
let toIndex = Math.min(grip.length, MAX_LONG_STRING_LENGTH);
|
|
||||||
client.substring(grip.initial.length, toIndex, (aResponse) => {
|
|
||||||
if (aResponse.error) {
|
|
||||||
Cu.reportError("JST__fetchVarLongString substring failure: " +
|
|
||||||
aResponse.error + ": " + aResponse.message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
aVar.onexpand = null;
|
|
||||||
aVar.setGrip(grip.initial + aResponse.substring);
|
|
||||||
aVar.hideArrow();
|
|
||||||
aVar._retrieved = true;
|
|
||||||
|
|
||||||
if (toIndex != grip.length) {
|
|
||||||
this.hud.logWarningAboutStringTooLong();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes a JS object to the JSTerm outputNode.
|
* Writes a JS object to the JSTerm outputNode.
|
||||||
@ -3830,28 +3669,30 @@ JSTerm.prototype = {
|
|||||||
this.lastInputValue = aNewValue;
|
this.lastInputValue = aNewValue;
|
||||||
this.completeNode.value = "";
|
this.completeNode.value = "";
|
||||||
this.resizeInput();
|
this.resizeInput();
|
||||||
|
this._inputChanged = true;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The inputNode "input" and "keyup" event handler.
|
* The inputNode "input" and "keyup" event handler.
|
||||||
*
|
* @private
|
||||||
* @param nsIDOMEvent aEvent
|
|
||||||
*/
|
*/
|
||||||
inputEventHandler: function JSTF_inputEventHandler(aEvent)
|
_inputEventHandler: function JST__inputEventHandler()
|
||||||
{
|
{
|
||||||
if (this.lastInputValue != this.inputNode.value) {
|
if (this.lastInputValue != this.inputNode.value) {
|
||||||
this.resizeInput();
|
this.resizeInput();
|
||||||
this.complete(this.COMPLETE_HINT_ONLY);
|
this.complete(this.COMPLETE_HINT_ONLY);
|
||||||
this.lastInputValue = this.inputNode.value;
|
this.lastInputValue = this.inputNode.value;
|
||||||
|
this._inputChanged = true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The inputNode "keypress" event handler.
|
* The inputNode "keypress" event handler.
|
||||||
*
|
*
|
||||||
|
* @private
|
||||||
* @param nsIDOMEvent aEvent
|
* @param nsIDOMEvent aEvent
|
||||||
*/
|
*/
|
||||||
keyPress: function JSTF_keyPress(aEvent)
|
_keyPress: function JST__keyPress(aEvent)
|
||||||
{
|
{
|
||||||
if (aEvent.ctrlKey) {
|
if (aEvent.ctrlKey) {
|
||||||
let inputNode = this.inputNode;
|
let inputNode = this.inputNode;
|
||||||
@ -3986,17 +3827,25 @@ JSTerm.prototype = {
|
|||||||
this.acceptProposedCompletion()) {
|
this.acceptProposedCompletion()) {
|
||||||
aEvent.preventDefault();
|
aEvent.preventDefault();
|
||||||
}
|
}
|
||||||
else {
|
else if (this._inputChanged) {
|
||||||
this.updateCompleteNode(l10n.getStr("Autocomplete.blank"));
|
this.updateCompleteNode(l10n.getStr("Autocomplete.blank"));
|
||||||
aEvent.preventDefault();
|
aEvent.preventDefault();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The inputNode "focus" event handler.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_focusEventHandler: function JST__focusEventHandler()
|
||||||
|
{
|
||||||
|
this._inputChanged = false;
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Go up/down the history stack of input values.
|
* Go up/down the history stack of input values.
|
||||||
*
|
*
|
||||||
@ -4358,11 +4207,7 @@ JSTerm.prototype = {
|
|||||||
_sidebarDestroy: function JST__sidebarDestroy()
|
_sidebarDestroy: function JST__sidebarDestroy()
|
||||||
{
|
{
|
||||||
if (this._variablesView) {
|
if (this._variablesView) {
|
||||||
let actors = this._objectActorsInVariablesViews.get(this._variablesView);
|
this._variablesView.controller.releaseActors();
|
||||||
for (let actor of actors) {
|
|
||||||
this.hud._releaseObject(actor);
|
|
||||||
}
|
|
||||||
actors.clear();
|
|
||||||
this._variablesView = null;
|
this._variablesView = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4397,6 +4242,7 @@ JSTerm.prototype = {
|
|||||||
this.inputNode.removeEventListener("keypress", this._keyPress, false);
|
this.inputNode.removeEventListener("keypress", this._keyPress, false);
|
||||||
this.inputNode.removeEventListener("input", this._inputEventHandler, false);
|
this.inputNode.removeEventListener("input", this._inputEventHandler, false);
|
||||||
this.inputNode.removeEventListener("keyup", this._inputEventHandler, false);
|
this.inputNode.removeEventListener("keyup", this._inputEventHandler, false);
|
||||||
|
this.inputNode.removeEventListener("focus", this._focusEventHandler, false);
|
||||||
|
|
||||||
this.hud = null;
|
this.hud = null;
|
||||||
},
|
},
|
||||||
|
@ -10,6 +10,6 @@ VPATH = @srcdir@
|
|||||||
include $(DEPTH)/config/autoconf.mk
|
include $(DEPTH)/config/autoconf.mk
|
||||||
|
|
||||||
DISABLED_EXTRA_COMPONENTS = fuelApplication.manifest
|
DISABLED_EXTRA_COMPONENTS = fuelApplication.manifest
|
||||||
EXTRA_PP_COMPONENTS = fuelApplication.js
|
DISABLED_EXTRA_PP_COMPONENTS = fuelApplication.js
|
||||||
|
|
||||||
include $(topsrcdir)/config/rules.mk
|
include $(topsrcdir)/config/rules.mk
|
||||||
|
@ -9,3 +9,7 @@ MODULE = 'fuel'
|
|||||||
EXTRA_COMPONENTS += [
|
EXTRA_COMPONENTS += [
|
||||||
'fuelApplication.manifest',
|
'fuelApplication.manifest',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
EXTRA_PP_COMPONENTS += [
|
||||||
|
'fuelApplication.js',
|
||||||
|
]
|
||||||
|
@ -341,7 +341,7 @@ Section "-Application" APP_IDX
|
|||||||
${AddDisabledDDEHandlerValues} "FirefoxHTML" "$2" "$8,1" \
|
${AddDisabledDDEHandlerValues} "FirefoxHTML" "$2" "$8,1" \
|
||||||
"${AppRegName} Document" ""
|
"${AppRegName} Document" ""
|
||||||
${AddDisabledDDEHandlerValues} "FirefoxURL" "$2" "$8,1" "${AppRegName} URL" \
|
${AddDisabledDDEHandlerValues} "FirefoxURL" "$2" "$8,1" "${AppRegName} URL" \
|
||||||
"true"
|
"delete"
|
||||||
|
|
||||||
; For pre win8, the following keys should only be set if we can write to HKLM.
|
; For pre win8, the following keys should only be set if we can write to HKLM.
|
||||||
; For post win8, the keys below get set in both HKLM and HKCU.
|
; For post win8, the keys below get set in both HKLM and HKCU.
|
||||||
|
@ -412,7 +412,7 @@ FunctionEnd
|
|||||||
"${AppRegName} HTML Document" ""
|
"${AppRegName} HTML Document" ""
|
||||||
|
|
||||||
${AddDisabledDDEHandlerValues} "FirefoxURL" "$2" "$8,1" "${AppRegName} URL" \
|
${AddDisabledDDEHandlerValues} "FirefoxURL" "$2" "$8,1" "${AppRegName} URL" \
|
||||||
"true"
|
"delete"
|
||||||
Call RegisterCEH
|
Call RegisterCEH
|
||||||
|
|
||||||
; An empty string is used for the 4th & 5th params because the following
|
; An empty string is used for the 4th & 5th params because the following
|
||||||
@ -650,7 +650,7 @@ FunctionEnd
|
|||||||
${IsHandlerForInstallDir} "FirefoxURL" $R9
|
${IsHandlerForInstallDir} "FirefoxURL" $R9
|
||||||
${If} "$R9" == "true"
|
${If} "$R9" == "true"
|
||||||
${AddDisabledDDEHandlerValues} "FirefoxURL" "$2" "$8,1" \
|
${AddDisabledDDEHandlerValues} "FirefoxURL" "$2" "$8,1" \
|
||||||
"${AppRegName} URL" "true"
|
"${AppRegName} URL" "delete"
|
||||||
${EndIf}
|
${EndIf}
|
||||||
|
|
||||||
; An empty string is used for the 4th & 5th params because the following
|
; An empty string is used for the 4th & 5th params because the following
|
||||||
|
@ -20,10 +20,10 @@ profiler.label=Profiler
|
|||||||
profiler2.commandkey=VK_F5
|
profiler2.commandkey=VK_F5
|
||||||
profiler.accesskey=P
|
profiler.accesskey=P
|
||||||
|
|
||||||
# LOCALIZATION NOTE (profiler.tooltip):
|
# LOCALIZATION NOTE (profiler.tooltip2):
|
||||||
# This string is displayed in the tooltip of the tab when the profiler is
|
# This string is displayed in the tooltip of the tab when the profiler is
|
||||||
# displayed inside the developer tools window.
|
# displayed inside the developer tools window.
|
||||||
profiler.tooltip=Profiler
|
profiler.tooltip2=JavaScript Profiler
|
||||||
|
|
||||||
# LOCALIZATION NOTE (profiler.profileName):
|
# LOCALIZATION NOTE (profiler.profileName):
|
||||||
# This string is the default name for new profiles. Its parameter is a number.
|
# This string is the default name for new profiles. Its parameter is a number.
|
||||||
@ -82,3 +82,18 @@ profiler.loading=Loading profile…
|
|||||||
# This string is displayed in the profiler whenever there is already
|
# This string is displayed in the profiler whenever there is already
|
||||||
# another running profile. Users can run only one profile at a time.
|
# another running profile. Users can run only one profile at a time.
|
||||||
profiler.alreadyRunning=Profiler is already running. If you want to run this profile stop Profile %S first.
|
profiler.alreadyRunning=Profiler is already running. If you want to run this profile stop Profile %S first.
|
||||||
|
|
||||||
|
# LOCALIZATION NOTE (profiler.stateIdle)
|
||||||
|
# This string is used to show that the profile in question is in IDLE
|
||||||
|
# state meaning that it hasn't been started yet.
|
||||||
|
profiler.stateIdle=Idle
|
||||||
|
|
||||||
|
# LOCALIZATION NOTE (profiler.stateRunning)
|
||||||
|
# This string is used to show that the profile in question is in RUNNING
|
||||||
|
# state meaning that it has been started and currently gathering profile data.
|
||||||
|
profiler.stateRunning=Running
|
||||||
|
|
||||||
|
# LOCALIZATION NOTE (profiler.stateCompleted)
|
||||||
|
# This string is used to show that the profile in question is in COMPLETED
|
||||||
|
# state meaning that it has been started and stopped already.
|
||||||
|
profiler.stateCompleted=Completed
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
this.popup._input = this;
|
this.popup._input = this;
|
||||||
]]>
|
]]>
|
||||||
</constructor>
|
</constructor>
|
||||||
|
|
||||||
<method name="openPopup">
|
<method name="openPopup">
|
||||||
<body>
|
<body>
|
||||||
<![CDATA[
|
<![CDATA[
|
||||||
@ -37,6 +38,21 @@
|
|||||||
]]>
|
]]>
|
||||||
</body>
|
</body>
|
||||||
</method>
|
</method>
|
||||||
|
|
||||||
|
<method name="formatValue">
|
||||||
|
<body>
|
||||||
|
<![CDATA[
|
||||||
|
BrowserUI.formatURI();
|
||||||
|
]]>
|
||||||
|
</body>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="trimValue">
|
||||||
|
<parameter name="aURL"/>
|
||||||
|
<body><![CDATA[
|
||||||
|
return BrowserUI.trimURL(aURL);
|
||||||
|
]]></body>
|
||||||
|
</method>
|
||||||
</implementation>
|
</implementation>
|
||||||
|
|
||||||
<handlers>
|
<handlers>
|
||||||
@ -70,12 +86,12 @@
|
|||||||
<content orient="horizontal">
|
<content orient="horizontal">
|
||||||
<xul:vbox id="results-vbox" class="meta-section viewable-height" flex="1">
|
<xul:vbox id="results-vbox" class="meta-section viewable-height" flex="1">
|
||||||
<xul:label class="meta-section-title" value="&autocompleteResultsHeader.label;"/>
|
<xul:label class="meta-section-title" value="&autocompleteResultsHeader.label;"/>
|
||||||
<richgrid id="results-richgrid" anonid="results" seltype="single" flex="1"/>
|
<richgrid id="results-richgrid" deferlayout="true" anonid="results" seltype="single" flex="1"/>
|
||||||
</xul:vbox>
|
</xul:vbox>
|
||||||
|
|
||||||
<xul:vbox id="searches-vbox" class="meta-section viewable-height" flex="1">
|
<xul:vbox id="searches-vbox" class="meta-section viewable-height" flex="1">
|
||||||
<xul:label class="meta-section-title" value="&autocompleteSearchesHeader.label;"/>
|
<xul:label class="meta-section-title" value="&autocompleteSearchesHeader.label;"/>
|
||||||
<richgrid id="searches-richgrid" anonid="searches" seltype="single" flex="1"/>
|
<richgrid id="searches-richgrid" deferlayout="true" anonid="searches" seltype="single" flex="1"/>
|
||||||
</xul:vbox>
|
</xul:vbox>
|
||||||
</content>
|
</content>
|
||||||
|
|
||||||
@ -162,6 +178,10 @@
|
|||||||
|
|
||||||
this.clearSelection();
|
this.clearSelection();
|
||||||
this.invalidate();
|
this.invalidate();
|
||||||
|
|
||||||
|
this._results.arrangeItemsNow();
|
||||||
|
this._searches.arrangeItemsNow();
|
||||||
|
|
||||||
this._fire("autocompletestart");
|
this._fire("autocompletestart");
|
||||||
]]>
|
]]>
|
||||||
</body>
|
</body>
|
||||||
@ -395,7 +415,7 @@
|
|||||||
<parameter name="aGrid"/>
|
<parameter name="aGrid"/>
|
||||||
<body>
|
<body>
|
||||||
<![CDATA[
|
<![CDATA[
|
||||||
return aGrid.itemCount != undefined;
|
return aGrid && aGrid.itemCount != undefined;
|
||||||
]]>
|
]]>
|
||||||
</body>
|
</body>
|
||||||
</method>
|
</method>
|
||||||
|
@ -126,7 +126,7 @@
|
|||||||
* rectBrowserToClient
|
* rectBrowserToClient
|
||||||
* Converts a rect (left, top, right, bottom).
|
* Converts a rect (left, top, right, bottom).
|
||||||
*
|
*
|
||||||
* @param aMessage - message manager message
|
* @param aRect - rect to convert
|
||||||
* @param aIgnoreScroll ignore root frame scroll.
|
* @param aIgnoreScroll ignore root frame scroll.
|
||||||
* @param aIgnoreScale ignore current scale factor.
|
* @param aIgnoreScale ignore current scale factor.
|
||||||
* @return { left:, top:, right:, bottom: }
|
* @return { left:, top:, right:, bottom: }
|
||||||
|
@ -338,53 +338,13 @@
|
|||||||
<field name="_columnCount">0</field>
|
<field name="_columnCount">0</field>
|
||||||
<property name="columnCount" readonly="true" onget="return this._columnCount;"/>
|
<property name="columnCount" readonly="true" onget="return this._columnCount;"/>
|
||||||
|
|
||||||
<field name="_scheduledArrangeItemsTries">0</field>
|
|
||||||
|
|
||||||
<!-- define a height where we consider an item not yet rendered
|
<!-- define a height where we consider an item not yet rendered
|
||||||
10 is the height of the empty item (padding/border etc. only) -->
|
10 is the height of the empty item (padding/border etc. only) -->
|
||||||
<field name="_itemHeightRenderThreshold">10</field>
|
<field name="_itemHeightRenderThreshold">10</field>
|
||||||
|
|
||||||
<method name="arrangeItems">
|
<property name="_containerRect">
|
||||||
<body>
|
<getter><![CDATA[
|
||||||
<![CDATA[
|
// return the rect that represents our bounding box
|
||||||
if (this.itemCount <= 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let item = this.getItemAtIndex(0);
|
|
||||||
if (item == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let gridItemRect = item.getBoundingClientRect();
|
|
||||||
|
|
||||||
// cap the number of times we reschedule calling arrangeItems
|
|
||||||
let maxRetries = 5;
|
|
||||||
|
|
||||||
// delay as necessary until the item has a proper height
|
|
||||||
if (gridItemRect.height <= this._itemHeightRenderThreshold) {
|
|
||||||
if (this._scheduledArrangeItemsTimerId) {
|
|
||||||
// retry of arrangeItems already scheduled
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// track how many times we've attempted arrangeItems
|
|
||||||
this._scheduledArrangeItemsTries++;
|
|
||||||
|
|
||||||
if (maxRetries > this._scheduledArrangeItemsTries) {
|
|
||||||
// schedule re-try of arrangeItems at the next tick
|
|
||||||
this._scheduledArrangeItemsTimerId = setTimeout(this.arrangeItems.bind(this), 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// items ready to arrange (or retries max exceeded)
|
|
||||||
// reset the flags
|
|
||||||
if (this._scheduledArrangeItemsTimerId) {
|
|
||||||
clearTimeout(this._scheduledArrangeItemsTimerId);
|
|
||||||
delete this._scheduledArrangeItemsTimerId;
|
|
||||||
}
|
|
||||||
if (this._scheduledArrangeItemsTries) {
|
|
||||||
this._scheduledArrangeItemsTries = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Autocomplete is a binding within a binding, so we have to step
|
// Autocomplete is a binding within a binding, so we have to step
|
||||||
// up an additional parentNode.
|
// up an additional parentNode.
|
||||||
@ -394,12 +354,89 @@
|
|||||||
container = this.parentNode.parentNode.getBoundingClientRect();
|
container = this.parentNode.parentNode.getBoundingClientRect();
|
||||||
else
|
else
|
||||||
container = this.parentNode.getBoundingClientRect();
|
container = this.parentNode.getBoundingClientRect();
|
||||||
|
return container;
|
||||||
|
]]></getter>
|
||||||
|
</property>
|
||||||
|
|
||||||
// If we don't have valid dimensions we can't arrange yet
|
<property name="_itemRect">
|
||||||
if (!container.height || !gridItemRect.height) {
|
<getter><![CDATA[
|
||||||
|
// return the rect that represents an item in the grid
|
||||||
|
|
||||||
|
// TODO: when we remove the need for DOM item measurement, 0 items will not be a problem
|
||||||
|
let item = this.itemCount ? this.getItemAtIndex(0) : null;
|
||||||
|
if (item) {
|
||||||
|
let gridItemRect = item.getBoundingClientRect();
|
||||||
|
if (gridItemRect.height > this._itemHeightRenderThreshold) {
|
||||||
|
return gridItemRect;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
]]></getter>
|
||||||
|
</property>
|
||||||
|
|
||||||
|
<!-- do conditions allow layout/arrange of the grid? -->
|
||||||
|
<property name="_canLayout" readonly="true">
|
||||||
|
<getter>
|
||||||
|
<![CDATA[
|
||||||
|
let gridItemRect = this._itemRect;
|
||||||
|
// If we don't have valid item dimensions we can't arrange yet
|
||||||
|
if (!(gridItemRect && gridItemRect.height)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let container = this._containerRect;
|
||||||
|
// If we don't have valid container dimensions we can't arrange yet
|
||||||
|
if (!(container && container.height)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
]]>
|
||||||
|
</getter>
|
||||||
|
</property>
|
||||||
|
|
||||||
|
<field name="_scheduledArrangeItemsTimerId">null</field>
|
||||||
|
<field name="_scheduledArrangeItemsTries">0</field>
|
||||||
|
<field name="_maxArrangeItemsRetries">5</field>
|
||||||
|
<method name="_scheduleArrangeItems">
|
||||||
|
<parameter name="aTime"/>
|
||||||
|
<body>
|
||||||
|
<![CDATA[
|
||||||
|
// cap the number of times we reschedule calling arrangeItems
|
||||||
|
if (
|
||||||
|
!this._scheduledArrangeItemsTimerId &&
|
||||||
|
this._maxArrangeItemsRetries > this._scheduledArrangeItemsTries
|
||||||
|
) {
|
||||||
|
this._scheduledArrangeItemsTimerId = setTimeout(this.arrangeItems.bind(this), aTime || 0);
|
||||||
|
// track how many times we've attempted arrangeItems
|
||||||
|
this._scheduledArrangeItemsTries++;
|
||||||
|
}
|
||||||
|
]]>
|
||||||
|
</body>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="arrangeItems">
|
||||||
|
<body>
|
||||||
|
<![CDATA[
|
||||||
|
if (this.hasAttribute("deferlayout")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!this._canLayout) {
|
||||||
|
// try again later
|
||||||
|
this._scheduleArrangeItems();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let gridItemRect = this._itemRect;
|
||||||
|
let container = this._containerRect;
|
||||||
|
|
||||||
|
// reset the flags
|
||||||
|
if (this._scheduledArrangeItemsTimerId) {
|
||||||
|
clearTimeout(this._scheduledArrangeItemsTimerId);
|
||||||
|
delete this._scheduledArrangeItemsTimerId;
|
||||||
|
}
|
||||||
|
this._scheduledArrangeItemsTries = 0;
|
||||||
|
|
||||||
// We favor overflowing horizontally, not vertically
|
// We favor overflowing horizontally, not vertically
|
||||||
let maxRowCount = Math.floor(container.height / gridItemRect.height) - 1;
|
let maxRowCount = Math.floor(container.height / gridItemRect.height) - 1;
|
||||||
|
|
||||||
@ -418,6 +455,21 @@
|
|||||||
]]>
|
]]>
|
||||||
</body>
|
</body>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="arrangeItemsNow">
|
||||||
|
<body>
|
||||||
|
<![CDATA[
|
||||||
|
this.removeAttribute("deferlayout");
|
||||||
|
// cancel any scheduled arrangeItems and reset flags
|
||||||
|
if (this._scheduledArrangeItemsTimerId) {
|
||||||
|
clearTimeout(this._scheduledArrangeItemsTimerId);
|
||||||
|
delete this._scheduledArrangeItemsTimerId;
|
||||||
|
}
|
||||||
|
this._scheduledArrangeItemsTries = 0;
|
||||||
|
// pass over any params
|
||||||
|
return this.arrangeItems.apply(this, arguments);
|
||||||
|
]]>
|
||||||
|
</body>
|
||||||
|
</method>
|
||||||
|
|
||||||
<!-- Inteface to suppress selection events -->
|
<!-- Inteface to suppress selection events -->
|
||||||
|
|
||||||
|
@ -10,9 +10,9 @@
|
|||||||
<html:div flex="1" class="selection-overlay-inner window-width window-height" anonid="selection-overlay-inner">
|
<html:div flex="1" class="selection-overlay-inner window-width window-height" anonid="selection-overlay-inner">
|
||||||
<xul:stack>
|
<xul:stack>
|
||||||
<html:div anonid="selection-overlay-debug" class="window-width window-height"/>
|
<html:div anonid="selection-overlay-debug" class="window-width window-height"/>
|
||||||
<xul:toolbarbutton id="selectionhandle-mark1" label="^" left="10" top="10" hidden="true"/>
|
<xul:toolbarbutton anonid="selectionhandle-mark1" class="selectionhandle" label="^" left="10" top="10" hidden="true"/>
|
||||||
<xul:toolbarbutton id="selectionhandle-mark2" label="^" left="10" top="10" hidden="true"/>
|
<xul:toolbarbutton anonid="selectionhandle-mark2" class="selectionhandle" label="^" left="10" top="10" hidden="true"/>
|
||||||
<xul:toolbarbutton id="selectionhandle-mark3" label="^" left="10" top="10" hidden="true"/>
|
<xul:toolbarbutton anonid="selectionhandle-mark3" class="selectionhandle" label="^" left="10" top="10" hidden="true"/>
|
||||||
</xul:stack>
|
</xul:stack>
|
||||||
</html:div>
|
</html:div>
|
||||||
</content>
|
</content>
|
||||||
@ -62,18 +62,11 @@
|
|||||||
</getter>
|
</getter>
|
||||||
</property>
|
</property>
|
||||||
|
|
||||||
<method name="init">
|
<method name="getMarker">
|
||||||
|
<parameter name="aMarkerId"/>
|
||||||
<body>
|
<body>
|
||||||
<![CDATA[
|
<![CDATA[
|
||||||
this.enabled = true;
|
return document.getAnonymousElementByAttribute(this, "anonid", aMarkerId);
|
||||||
]]>
|
|
||||||
</body>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
<method name="shutdown">
|
|
||||||
<body>
|
|
||||||
<![CDATA[
|
|
||||||
this.enabled = false;
|
|
||||||
]]>
|
]]>
|
||||||
</body>
|
</body>
|
||||||
</method>
|
</method>
|
||||||
|
@ -109,6 +109,8 @@ let ScriptContexts = {};
|
|||||||
["OfflineApps", "chrome://browser/content/helperui/OfflineApps.js"],
|
["OfflineApps", "chrome://browser/content/helperui/OfflineApps.js"],
|
||||||
["SelectHelperUI", "chrome://browser/content/helperui/SelectHelperUI.js"],
|
["SelectHelperUI", "chrome://browser/content/helperui/SelectHelperUI.js"],
|
||||||
["SelectionHelperUI", "chrome://browser/content/helperui/SelectionHelperUI.js"],
|
["SelectionHelperUI", "chrome://browser/content/helperui/SelectionHelperUI.js"],
|
||||||
|
["SelectionPrototype", "chrome://browser/content/library/SelectionPrototype.js"],
|
||||||
|
["ChromeSelectionHandler", "chrome://browser/content/helperui/ChromeSelectionHandler.js"],
|
||||||
["AnimatedZoom", "chrome://browser/content/AnimatedZoom.js"],
|
["AnimatedZoom", "chrome://browser/content/AnimatedZoom.js"],
|
||||||
["CommandUpdater", "chrome://browser/content/commandUtil.js"],
|
["CommandUpdater", "chrome://browser/content/commandUtil.js"],
|
||||||
["ContextCommands", "chrome://browser/content/ContextCommands.js"],
|
["ContextCommands", "chrome://browser/content/ContextCommands.js"],
|
||||||
|
@ -97,7 +97,11 @@ var BrowserUI = {
|
|||||||
window.addEventListener("MozImprecisePointer", this, true);
|
window.addEventListener("MozImprecisePointer", this, true);
|
||||||
|
|
||||||
Services.prefs.addObserver("browser.cache.disk_cache_ssl", this, false);
|
Services.prefs.addObserver("browser.cache.disk_cache_ssl", this, false);
|
||||||
|
Services.prefs.addObserver("browser.urlbar.formatting.enabled", this, false);
|
||||||
|
Services.prefs.addObserver("browser.urlbar.trimURLs", this, false);
|
||||||
Services.obs.addObserver(this, "metro_viewstate_changed", false);
|
Services.obs.addObserver(this, "metro_viewstate_changed", false);
|
||||||
|
|
||||||
|
this._edit.inputField.controllers.insertControllerAt(0, this._copyCutURIController);
|
||||||
|
|
||||||
// Init core UI modules
|
// Init core UI modules
|
||||||
ContextUI.init();
|
ContextUI.init();
|
||||||
@ -239,11 +243,20 @@ var BrowserUI = {
|
|||||||
|
|
||||||
getDisplayURI: function(browser) {
|
getDisplayURI: function(browser) {
|
||||||
let uri = browser.currentURI;
|
let uri = browser.currentURI;
|
||||||
|
let spec = uri.spec;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
uri = gURIFixup.createExposableURI(uri);
|
spec = gURIFixup.createExposableURI(uri).spec;
|
||||||
} catch (ex) {}
|
} catch (ex) {}
|
||||||
|
|
||||||
return uri.spec;
|
try {
|
||||||
|
let charset = browser.characterSet;
|
||||||
|
let textToSubURI = Cc["@mozilla.org/intl/texttosuburi;1"].
|
||||||
|
getService(Ci.nsITextToSubURI);
|
||||||
|
spec = textToSubURI.unEscapeNonAsciiURI(charset, spec);
|
||||||
|
} catch (ex) {}
|
||||||
|
|
||||||
|
return spec;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -560,6 +573,12 @@ var BrowserUI = {
|
|||||||
case "browser.cache.disk_cache_ssl":
|
case "browser.cache.disk_cache_ssl":
|
||||||
this._sslDiskCacheEnabled = Services.prefs.getBoolPref(aData);
|
this._sslDiskCacheEnabled = Services.prefs.getBoolPref(aData);
|
||||||
break;
|
break;
|
||||||
|
case "browser.urlbar.formatting.enabled":
|
||||||
|
this._formattingEnabled = Services.prefs.getBoolPref(aData);
|
||||||
|
break;
|
||||||
|
case "browser.urlbar.trimURLs":
|
||||||
|
this._mayTrimURLs = Services.prefs.getBoolPref(aData);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "metro_viewstate_changed":
|
case "metro_viewstate_changed":
|
||||||
@ -650,15 +669,138 @@ var BrowserUI = {
|
|||||||
Elements.urlbarState.setAttribute("mode", "view");
|
Elements.urlbarState.setAttribute("mode", "view");
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_trimURL: function _trimURL(aURL) {
|
||||||
|
// This function must not modify the given URL such that calling
|
||||||
|
// nsIURIFixup::createFixupURI with the result will produce a different URI.
|
||||||
|
return aURL /* remove single trailing slash for http/https/ftp URLs */
|
||||||
|
.replace(/^((?:http|https|ftp):\/\/[^/]+)\/$/, "$1")
|
||||||
|
/* remove http:// unless the host starts with "ftp\d*\." or contains "@" */
|
||||||
|
.replace(/^http:\/\/((?!ftp\d*\.)[^\/@]+(?:\/|$))/, "$1");
|
||||||
|
},
|
||||||
|
|
||||||
|
trimURL: function trimURL(aURL) {
|
||||||
|
return this.mayTrimURLs ? this._trimURL(aURL) : aURL;
|
||||||
|
},
|
||||||
|
|
||||||
_setURI: function _setURI(aURL) {
|
_setURI: function _setURI(aURL) {
|
||||||
this._edit.value = aURL;
|
this._edit.value = aURL;
|
||||||
this.lastKnownGoodURL = aURL;
|
this.lastKnownGoodURL = aURL;
|
||||||
},
|
},
|
||||||
|
|
||||||
_urlbarClicked: function _urlbarClicked() {
|
_getSelectedURIForClipboard: function _getSelectedURIForClipboard() {
|
||||||
|
// Grab the actual input field's value, not our value, which could include moz-action:
|
||||||
|
let inputVal = this._edit.inputField.value;
|
||||||
|
let selectedVal = inputVal.substring(this._edit.selectionStart, this._edit.electionEnd);
|
||||||
|
|
||||||
|
// If the selection doesn't start at the beginning or doesn't span the full domain or
|
||||||
|
// the URL bar is modified, nothing else to do here.
|
||||||
|
if (this._edit.selectionStart > 0 || this._edit.valueIsTyped)
|
||||||
|
return selectedVal;
|
||||||
|
// The selection doesn't span the full domain if it doesn't contain a slash and is
|
||||||
|
// followed by some character other than a slash.
|
||||||
|
if (!selectedVal.contains("/")) {
|
||||||
|
let remainder = inputVal.replace(selectedVal, "");
|
||||||
|
if (remainder != "" && remainder[0] != "/")
|
||||||
|
return selectedVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
let uriFixup = Cc["@mozilla.org/docshell/urifixup;1"].getService(Ci.nsIURIFixup);
|
||||||
|
|
||||||
|
let uri;
|
||||||
|
try {
|
||||||
|
uri = uriFixup.createFixupURI(inputVal, Ci.nsIURIFixup.FIXUP_FLAG_USE_UTF8);
|
||||||
|
} catch (e) {}
|
||||||
|
if (!uri)
|
||||||
|
return selectedVal;
|
||||||
|
|
||||||
|
// Only copy exposable URIs
|
||||||
|
try {
|
||||||
|
uri = uriFixup.createExposableURI(uri);
|
||||||
|
} catch (ex) {}
|
||||||
|
|
||||||
|
// If the entire URL is selected, just use the actual loaded URI.
|
||||||
|
if (inputVal == selectedVal) {
|
||||||
|
// ... but only if isn't a javascript: or data: URI, since those
|
||||||
|
// are hard to read when encoded
|
||||||
|
if (!uri.schemeIs("javascript") && !uri.schemeIs("data")) {
|
||||||
|
// Parentheses are known to confuse third-party applications (bug 458565).
|
||||||
|
selectedVal = uri.spec.replace(/[()]/g, function (c) escape(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
return selectedVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Just the beginning of the URL is selected, check for a trimmed value
|
||||||
|
let spec = uri.spec;
|
||||||
|
let trimmedSpec = this.trimURL(spec);
|
||||||
|
if (spec != trimmedSpec) {
|
||||||
|
// Prepend the portion that trimURL removed from the beginning.
|
||||||
|
// This assumes trimURL will only truncate the URL at
|
||||||
|
// the beginning or end (or both).
|
||||||
|
let trimmedSegments = spec.split(trimmedSpec);
|
||||||
|
selectedVal = trimmedSegments[0] + selectedVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
return selectedVal;
|
||||||
|
},
|
||||||
|
|
||||||
|
_copyCutURIController: {
|
||||||
|
doCommand: function(aCommand) {
|
||||||
|
let urlbar = BrowserUI._edit;
|
||||||
|
let val = BrowserUI._getSelectedURIForClipboard();
|
||||||
|
if (!val)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (aCommand == "cmd_cut" && this.isCommandEnabled(aCommand)) {
|
||||||
|
let start = urlbar.selectionStart;
|
||||||
|
let end = urlbar.selectionEnd;
|
||||||
|
urlbar.inputField.value = urlbar.inputField.value.substring(0, start) +
|
||||||
|
urlbar.inputField.value.substring(end);
|
||||||
|
urlbar.selectionStart = urlbar.selectionEnd = start;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cc["@mozilla.org/widget/clipboardhelper;1"]
|
||||||
|
.getService(Ci.nsIClipboardHelper)
|
||||||
|
.copyString(val, document);
|
||||||
|
},
|
||||||
|
|
||||||
|
supportsCommand: function(aCommand) {
|
||||||
|
switch (aCommand) {
|
||||||
|
case "cmd_copy":
|
||||||
|
case "cmd_cut":
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
isCommandEnabled: function(aCommand) {
|
||||||
|
let urlbar = BrowserUI._edit;
|
||||||
|
return this.supportsCommand(aCommand) &&
|
||||||
|
(aCommand != "cmd_cut" || !urlbar.readOnly) &&
|
||||||
|
urlbar.selectionStart < urlbar.selectionEnd;
|
||||||
|
},
|
||||||
|
|
||||||
|
onEvent: function(aEventName) {}
|
||||||
|
},
|
||||||
|
|
||||||
|
_urlbarClicked: function _urlbarClicked(aEvent) {
|
||||||
|
let touchEvent = aEvent.mozInputSource == Ci.nsIDOMMouseEvent.MOZ_SOURCE_TOUCH;
|
||||||
|
|
||||||
// If the urlbar is not already focused, focus it and select the contents.
|
// If the urlbar is not already focused, focus it and select the contents.
|
||||||
if (Elements.urlbarState.getAttribute("mode") != "edit")
|
if (Elements.urlbarState.getAttribute("mode") != "edit") {
|
||||||
this._editURI(true);
|
this._editURI(true);
|
||||||
|
if (touchEvent) {
|
||||||
|
SelectionHelperUI.attachEditSession(ChromeSelectionHandler,
|
||||||
|
aEvent.clientX, aEvent.clientY);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// tap caret handling
|
||||||
|
if (touchEvent) {
|
||||||
|
SelectionHelperUI.attachToCaret(ChromeSelectionHandler,
|
||||||
|
aEvent.clientX, aEvent.clientY);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_editURI: function _editURI(aShouldDismiss) {
|
_editURI: function _editURI(aShouldDismiss) {
|
||||||
@ -667,8 +809,74 @@ var BrowserUI = {
|
|||||||
|
|
||||||
Elements.urlbarState.setAttribute("mode", "edit");
|
Elements.urlbarState.setAttribute("mode", "edit");
|
||||||
StartUI.show();
|
StartUI.show();
|
||||||
if (aShouldDismiss)
|
if (aShouldDismiss) {
|
||||||
ContextUI.dismissTabs();
|
ContextUI.dismissTabs();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
formatURI: function formatURI() {
|
||||||
|
if (!this.formattingEnabled ||
|
||||||
|
Elements.urlbarState.getAttribute("mode") == "edit")
|
||||||
|
return;
|
||||||
|
|
||||||
|
let controller = this._edit.editor.selectionController;
|
||||||
|
let selection = controller.getSelection(controller.SELECTION_URLSECONDARY);
|
||||||
|
selection.removeAllRanges();
|
||||||
|
|
||||||
|
let textNode = this._edit.editor.rootElement.firstChild;
|
||||||
|
let value = textNode.textContent;
|
||||||
|
|
||||||
|
let protocol = value.match(/^[a-z\d.+\-]+:(?=[^\d])/);
|
||||||
|
if (protocol &&
|
||||||
|
["http:", "https:", "ftp:"].indexOf(protocol[0]) == -1)
|
||||||
|
return;
|
||||||
|
let matchedURL = value.match(/^((?:[a-z]+:\/\/)?(?:[^\/]+@)?)(.+?)(?::\d+)?(?:\/|$)/);
|
||||||
|
if (!matchedURL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
let [, preDomain, domain] = matchedURL;
|
||||||
|
let baseDomain = domain;
|
||||||
|
let subDomain = "";
|
||||||
|
// getBaseDomainFromHost doesn't recognize IPv6 literals in brackets as IPs (bug 667159)
|
||||||
|
if (domain[0] != "[") {
|
||||||
|
try {
|
||||||
|
baseDomain = Services.eTLD.getBaseDomainFromHost(domain);
|
||||||
|
if (!domain.endsWith(baseDomain)) {
|
||||||
|
// getBaseDomainFromHost converts its resultant to ACE.
|
||||||
|
let IDNService = Cc["@mozilla.org/network/idn-service;1"]
|
||||||
|
.getService(Ci.nsIIDNService);
|
||||||
|
baseDomain = IDNService.convertACEtoUTF8(baseDomain);
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
if (baseDomain != domain) {
|
||||||
|
subDomain = domain.slice(0, -baseDomain.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
let rangeLength = preDomain.length + subDomain.length;
|
||||||
|
if (rangeLength) {
|
||||||
|
let range = document.createRange();
|
||||||
|
range.setStart(textNode, 0);
|
||||||
|
range.setEnd(textNode, rangeLength);
|
||||||
|
selection.addRange(range);
|
||||||
|
}
|
||||||
|
|
||||||
|
let startRest = preDomain.length + domain.length;
|
||||||
|
if (startRest < value.length) {
|
||||||
|
let range = document.createRange();
|
||||||
|
range.setStart(textNode, startRest);
|
||||||
|
range.setEnd(textNode, value.length);
|
||||||
|
selection.addRange(range);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_clearURIFormatting: function _clearURIFormatting() {
|
||||||
|
if (!this.formattingEnabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
let controller = this._edit.editor.selectionController;
|
||||||
|
let selection = controller.getSelection(controller.SELECTION_URLSECONDARY);
|
||||||
|
selection.removeAllRanges();
|
||||||
},
|
},
|
||||||
|
|
||||||
_urlbarBlurred: function _urlbarBlurred() {
|
_urlbarBlurred: function _urlbarBlurred() {
|
||||||
@ -676,6 +884,7 @@ var BrowserUI = {
|
|||||||
if (state.getAttribute("mode") == "edit")
|
if (state.getAttribute("mode") == "edit")
|
||||||
state.removeAttribute("mode");
|
state.removeAttribute("mode");
|
||||||
this._updateToolbar();
|
this._updateToolbar();
|
||||||
|
this.formatURI();
|
||||||
},
|
},
|
||||||
|
|
||||||
_closeOrQuit: function _closeOrQuit() {
|
_closeOrQuit: function _closeOrQuit() {
|
||||||
@ -959,6 +1168,24 @@ var BrowserUI = {
|
|||||||
return this._sslDiskCacheEnabled;
|
return this._sslDiskCacheEnabled;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_formattingEnabled: null,
|
||||||
|
|
||||||
|
get formattingEnabled() {
|
||||||
|
if (this._formattingEnabled === null) {
|
||||||
|
this._formattingEnabled = Services.prefs.getBoolPref("browser.urlbar.formatting.enabled");
|
||||||
|
}
|
||||||
|
return this._formattingEnabled;
|
||||||
|
},
|
||||||
|
|
||||||
|
_mayTrimURLs: null,
|
||||||
|
|
||||||
|
get mayTrimURLs() {
|
||||||
|
if (this._mayTrimURLs === null) {
|
||||||
|
this._mayTrimURLs = Services.prefs.getBoolPref("browser.urlbar.trimURLs");
|
||||||
|
}
|
||||||
|
return this._mayTrimURLs;
|
||||||
|
},
|
||||||
|
|
||||||
supportsCommand : function(cmd) {
|
supportsCommand : function(cmd) {
|
||||||
var isSupported = false;
|
var isSupported = false;
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
|
@ -89,7 +89,8 @@ setting[type="menulist"] {
|
|||||||
-moz-binding: url("chrome://mozapps/content/extensions/setting.xml#setting-multi");
|
-moz-binding: url("chrome://mozapps/content/extensions/setting.xml#setting-multi");
|
||||||
}
|
}
|
||||||
|
|
||||||
#selection-overlay {
|
#chrome-selection-overlay,
|
||||||
|
#content-selection-overlay {
|
||||||
-moz-binding: url("chrome://browser/content/bindings/selectionoverlay.xml#selection-binding");
|
-moz-binding: url("chrome://browser/content/bindings/selectionoverlay.xml#selection-binding");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user