%PDF- %PDF-
| Direktori : /proc/self/root/data/old/home/stash/atlassian-stash/static/util/ |
| Current File : //proc/self/root/data/old/home/stash/atlassian-stash/static/util/web-fragment-manager.js |
/**
* This API is currently for internal use only. It is subject to change and shouldn't be used in plugins.
*
* @api private
*/
var WebFragments = (function() {
'use strict';
var has = Object.prototype.hasOwnProperty;
var descriptors = {
item : {},
section : {},
panel : {}
};
var getKeys = function(o) {
var keys = [];
for (var key in o) {
if (has.call(o, key)) {
keys.push(key);
}
}
return keys;
};
// extend an object with properties from another
function extend(a) {
var extenders = Array.prototype.slice.call(arguments, 1);
for(var i = 0, ii = extenders.length; i < ii; i++) {
var b = extenders[i];
if (b) {
for(var keys = getKeys(b), j = 0, jj = keys.length; j < jj; j++) {
var key = keys[j];
a[key] = b[key];
}
}
}
return a;
}
var addDynamicServerData;
if (!window._PageDataPlugin || !_PageDataPlugin.ready) {
addDynamicServerData = function(descriptor) {
return descriptor;
};
} else {
addDynamicServerData = function(descriptor) {
_PageDataPlugin.ready(descriptor.completeModuleKey, descriptor.location, function(data) {
if (has.call(data, 'serverCondition')) {
descriptor.serverCondition = data.serverCondition;
}
if (has.call(data, 'serverContext')) {
descriptor.serverContext = data.serverContext;
}
});
};
}
// functions for creating example web fragments. These are enabled when the url contains a
// web.items, web.panels, or web.sections query string parameter
var examples = {
item : function (location, context) {
return {
url : "#example-web-item-url",
pluginKey : "org.example.plugins",
moduleKey : "example-web-item",
completeModuleKey : "org.example.plugins:example-web-item",
linkText : "Client Web Item: " + location,
hasTooltip : true,
tooltip : "Client Context Items: " + getKeys(context).join(", "),
hasIcon : false,
iconUrl : null,
iconWidth : 0,
iconHeight : 0,
styleClass : "plugin-point",
linkId : null,
description : null,
params : {},
type : 'ITEM',
weight : 1000
};
},
section : function (location, context) {
return {
name : "example-web-section",
key : "example-web-section",
location : location,
labelText : "Client Web Section: " + location,
type : 'SECTION',
params : {},
weight : 1000
};
},
panel : function (location, context) {
return {
view : '<div class="plugin-point web-panel">' +
"<strong>Client Web Panel</strong>: " + location + "<br />" +
"<strong>Client Context Items</strong>: " + getKeys(context).join(", ") +
"</div>",
weight : 1000
};
}
};
// whether an example fragment of the given type should be included
function shouldIncludeExample(type) {
return new RegExp("[\\?&]web\\." + type + "s(=|&|$)").test(window.location.search);
}
// This function is used for reading values from a web fragment descriptor.
// If the value of the property is a function, it is executed with the given context, and the return value is used as the value of the property.
// if the value is not a function, it is returned as-is.
function getValue(expr, context) {
return typeof expr === 'function' ? expr(extend({}, context)) : expr;
}
// This function takes in a descriptor, and returns a concrete fragment object that has been evaluated with the given context,
// ready to be displayed on the page.
// While any property may be a funciton that is evaluated with the given context, there are two special properties that are checked first:
// If provided, context-provider's return value is used as the context for the other properties.
// If provided, the fragment won't be rendered if the condition property evaluates to falsy.
function toFragment(descriptor, context, type) {
var keys, key, i, ii;
var fragment = {
type : type.toUpperCase()
};
if (has.call(descriptor, 'serverCondition') && !descriptor.serverCondition) {
return null;
}
context = extend({}, context, descriptor.serverContext, descriptor.params);
if (has.call(descriptor, 'condition') && !getValue(descriptor.condition, context)) {
return null;
}
if (descriptor['context-provider'] && typeof descriptor['context-provider'] === 'function') {
context = getValue(descriptor['context-provider'], context);
}
for(keys = getKeys(descriptor), i = 0, ii = keys.length; i < ii; i++) {
key = keys[i];
if (!/con(dition|text-provider)|params/.test(key)) {
fragment[key] = getValue(descriptor[key], context);
}
}
if (descriptor.params) {
var params = fragment.params = {};
for(keys = getKeys(descriptor.params), i = 0, ii = keys.length; i < ii; i++) {
key = keys[i];
params[key] = getValue(descriptor.params[key], context);
}
}
return fragment;
}
// returns a function that retrieves all the fragment sof a given type, for a given location.
function fragmentGetter(type) {
var descriptorsByLocation = descriptors[type];
return function(location, context) {
var descriptors = descriptorsByLocation[location];
var fragments = [];
if (descriptors && descriptors.length) {
for(var i = 0, ii = descriptors.length; i < ii; i++) {
var fragment = toFragment(descriptors[i], context, type);
if (fragment) {
fragments.push(fragment);
}
}
}
if (shouldIncludeExample(type)) {
fragments.push(examples[type](location, context));
}
return fragments;
};
}
var getWebPanels = fragmentGetter('panel');
// In Stash, web panels are returned as a pure HTML string.
// So we pull out the evaluated view property (which should be HTML) and return it instead of the whole fragment.
function getWebPanelHtml(location, context) {
var panels = getWebPanels(location, context);
for(var i = 0, ii = panels.length; i < ii; i++) {
panels[i] = panels[i].view;
}
return panels;
}
var getWebItemFragments = fragmentGetter('item');
// There are a few properties on web items that are not provided by descriptors, but are required to be on the resulting fragment.
// We calculate values for those properties before returning the fragment.
function getWebItems(location, context) {
var items = getWebItemFragments(location, context);
for(var i = 0, ii = items.length; i < ii; i++) {
items[i].hasIcon = !!items[i].iconUrl;
items[i].hasTooltip = !!items[i].tooltip;
}
return items;
}
// Registers a descriptor of the given type.
function descriptorAdder(type) {
var descriptorsByLocation = descriptors[type];
return function (descriptor) {
if (!descriptor) {
throw new Error("No descriptor provided");
}
if (typeof descriptor.location !== 'string') {
throw new Error("No location provided, or location was not a string.");
}
if (typeof descriptor.completeModuleKey !== 'string') {
throw new Error("No completeModuleKey provided, or completeModuleKey was not a string.");
}
addDynamicServerData(descriptor);
if (!descriptorsByLocation[descriptor.location]) {
descriptorsByLocation[descriptor.location] = [];
}
descriptorsByLocation[descriptor.location].push(descriptor);
descriptorsByLocation[descriptor.location].sort(weightComparator);
};
}
// Compare function used to sort web fragments by their weight property.
// Weight is guaranteed to be a number if defined.
function weightComparator(a, b) {
return (a.weight >= 0 ? a.weight : 1000) - (b.weight >= 0 ? b.weight : 1000);
}
return {
getWebItems : fragmentGetter('item'),
getWebSections : fragmentGetter('section'),
getWebPanels : getWebPanelHtml,
getWebFragmentDescriptors : function(location, type) {
var descriptorsByType = descriptors[type];
var descriptorsForLocation = descriptorsByType && descriptorsByType[location];
return descriptorsForLocation && descriptorsForLocation.slice();
},
addWebItemDescriptor : descriptorAdder('item'),
addWebSectionDescriptor : descriptorAdder('section'),
addWebPanelDescriptor : descriptorAdder('panel'),
getWebFragments : function(itemLocation, sectionLocation, context) {
if (typeof sectionLocation !== "string") {
context = sectionLocation;
sectionLocation = itemLocation;
}
// this is an odd case - made to match the WebFragmentFunction in Soy
var items = this.getWebItems(itemLocation, context);
var sections = this.getWebSections(sectionLocation, context);
var all = items.concat(sections);
all.sort(weightComparator);
return all;
},
// These are exported only so they can be used by the generated descriptors.
// You shouldn't use them
_getValue : getValue,
_formatI18n : function(transformed, key, fallback) {
var messagePattern = (transformed === key ? fallback : transformed) || key || fallback || '';
return function(context) {
var contextAsArgs = [];
var keys = getKeys(context);
keys.sort();
for(var i = 0, ii = keys.length; i < ii; i++) {
contextAsArgs.push(context[keys[i]]);
}
return AJS.format(messagePattern, contextAsArgs);
};
}
};
}());