mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-25 15:00:58 +01:00
248d79f36d
Summary: See <https://discourse.phabricator-community.org/t/non-functional-actions-menu-on-live-phame-views/2593>. Several layers here: The "Actions" button is broken because a menu behavior is failing, since we aren't rendering the menu. When a behavior fails to initialize, catch and log the exception and continue. Previously, we stopped initializing behaviors if any failed, but behaviors are usually independent and continuing with an explicit exception seems reasonable. Give "JX.log()" some "sprintf()" semantics to make logging the behavior failure easier. We can probably afford these extra 200 bytes now in 2019. This fixes the button and gives us explicit errors in the log. So far, so good. Then, when a page won't render chrome, don't try to render the main menu. This fixes the actual errors (we no longer try to initialize menu behaviors for nodes which don't exist). Completely hide the "Actions" and "Comment" flows if the viewer isn't logged in. Although this isn't completely consistent with other applications, I think it's more appropriate for Phame. In applications like Maniphest, we show a full set of controls (but disable them) so that users who are not currently logged in have a clear path to interact with the content, under the assumption that this is a relatively common workflow. This is probably less common for Phame, where we expect most anonymous viewers not to log in or interact. Finally, parametrize a one-off border color and add a border under the crumbs at the top of the page. Test Plan: - Viewed a "Live" Phame blog post page, clicked "Actions", got a dropdown. Reviewers: amckinley Reviewed By: amckinley Differential Revision: https://secure.phabricator.com/D20378
116 lines
3.2 KiB
JavaScript
116 lines
3.2 KiB
JavaScript
/**
|
|
* @provides javelin-behavior
|
|
* @requires javelin-magical-init
|
|
* javelin-util
|
|
*
|
|
* @javelin-installs JX.behavior
|
|
* @javelin-installs JX.initBehaviors
|
|
*
|
|
* @javelin
|
|
*/
|
|
|
|
/**
|
|
* Define a Javelin behavior, which holds glue code in a structured way. See
|
|
* @{article:Concepts: Behaviors} for a detailed description of Javelin
|
|
* behaviors.
|
|
*
|
|
* To define a behavior, provide a name and a function:
|
|
*
|
|
* JX.behavior('win-a-hog', function(config, statics) {
|
|
* alert("YOU WON A HOG NAMED " + config.hogName + "!");
|
|
* });
|
|
*
|
|
* @param string Behavior name.
|
|
* @param function Behavior callback/definition.
|
|
* @return void
|
|
*/
|
|
JX.behavior = function(name, control_function) {
|
|
if (__DEV__) {
|
|
if (JX.behavior._behaviors.hasOwnProperty(name)) {
|
|
JX.$E(
|
|
'JX.behavior("' + name + '", ...): '+
|
|
'behavior is already registered.');
|
|
}
|
|
if (!control_function) {
|
|
JX.$E(
|
|
'JX.behavior("' + name + '", <nothing>): '+
|
|
'initialization function is required.');
|
|
}
|
|
if (typeof control_function != 'function') {
|
|
JX.$E(
|
|
'JX.behavior("' + name + '", <garbage>): ' +
|
|
'initialization function is not a function.');
|
|
}
|
|
// IE does not enumerate over these properties
|
|
var enumerables = {
|
|
toString: true,
|
|
hasOwnProperty: true,
|
|
valueOf: true,
|
|
isPrototypeOf: true,
|
|
propertyIsEnumerable: true,
|
|
toLocaleString: true,
|
|
constructor: true
|
|
};
|
|
if (enumerables[name]) {
|
|
JX.$E(
|
|
'JX.behavior("' + name + '", <garbage>): ' +
|
|
'do not use this property as a behavior.'
|
|
);
|
|
}
|
|
}
|
|
JX.behavior._behaviors[name] = control_function;
|
|
JX.behavior._statics[name] = {};
|
|
};
|
|
|
|
|
|
/**
|
|
* Execute previously defined Javelin behaviors, running the glue code they
|
|
* contain to glue stuff together. See @{article:Concepts: Behaviors} for more
|
|
* information on Javelin behaviors.
|
|
*
|
|
* Normally, you do not call this function yourself; instead, your server-side
|
|
* library builds it for you.
|
|
*
|
|
* @param dict Map of behaviors to invoke: keys are behavior names, and values
|
|
* are lists of configuration dictionaries. The behavior will be
|
|
* invoked once for each configuration dictionary.
|
|
* @return void
|
|
*/
|
|
JX.initBehaviors = function(map) {
|
|
var missing_behaviors = [];
|
|
for (var name in map) {
|
|
if (!(name in JX.behavior._behaviors)) {
|
|
missing_behaviors.push(name);
|
|
continue;
|
|
}
|
|
var configs = map[name];
|
|
if (!configs.length) {
|
|
if (JX.behavior._initialized.hasOwnProperty(name)) {
|
|
continue;
|
|
}
|
|
configs = [null];
|
|
}
|
|
for (var ii = 0; ii < configs.length; ii++) {
|
|
try {
|
|
JX.behavior._behaviors[name](configs[ii], JX.behavior._statics[name]);
|
|
} catch (behavior_exception) {
|
|
JX.log(
|
|
'JX.initBehaviors(...): behavior "%s" raised an error during setup.',
|
|
name);
|
|
JX.log(behavior_exception);
|
|
}
|
|
}
|
|
JX.behavior._initialized[name] = true;
|
|
}
|
|
if (missing_behaviors.length) {
|
|
JX.$E(
|
|
'JX.initBehavior(map): behavior(s) not registered: ' +
|
|
missing_behaviors.join(', ')
|
|
);
|
|
}
|
|
};
|
|
|
|
JX.behavior._behaviors = {};
|
|
JX.behavior._statics = {};
|
|
JX.behavior._initialized = {};
|
|
JX.flushHoldingQueue('behavior', JX.behavior);
|