# JavaScript API

Bitbucket Server exposes a JavaScript API for use in building your plugin's UI and behavior in the browser.

## JSDoc
 
- [JavaScript API reference](./javascript/) documentation is available.

## Compatibility Policy

The JS API's compatibility policy matches that of Bitbucket's other APIs. JS APIs will not contain breaking changes between
minor versions (e.g. 4.0 and 4.1). Instead, any removed or modified methods and properties will log warnings in the
browser console when used, and the legacy behavior will cease to work in the next major release (e.g. Bitbucket Server 5.0).

"Breaking changes" describes incompatible changes in behavior when valid inputs are given to any API functions, and
incompatible type changes in data properties. Behavior for invalid inputs may change at any release, and mutation of API
modules is not supported. See [API Scope](#API_Scope) for details.

## Loading the APIs

JavaScript APIs are not guaranteed to be available on the page. Before using an API you **MUST** depend on the matching web-resource
module for that API. Each JS module will list its web resource key, which should be listed as a `<dependency>{key}</dependency>` in your `<web-resource/>` module. See the [Web Resource Plugin Module](https://developer.atlassian.com/display/DOCS/Web+Resource+Plugin+Module) documentation for details.

## Asynchronous Module Definition (AMD)

### require()

Our JavaScript APIs are delivered using [Asynchronus Module Definitions (AMD)](https://github.com/amdjs/amdjs-api) patterns. This means they can referenced with the global function `require`. Given an array of string identifiers, `require` will call your callback with the modules referenced.

```javascript
require(['bitbucket/feature/files/file-handlers', 'some/other/module'], function(fileHandlers, someOtherModule) {
    // do things with the file-handlers module and some other module.
});
```
#### Asynchronous execution

It is important to note that your callback to the require function **MAY** be executed asynchronously. You should not depend on your callback being called by any certain point in time. For example, you should not expect that your code is executed before `DOMContentLoaded` (also known as `$(document).ready()`)

#### Synchronous modules

For _some_ but not all modules we also support a synchronous version of `require`, usable like
`var module = require("bitbucket/x")`. This is to support use cases like registering a [File Handler](./javascript/file-handlers_.html).
These modules will explicitly note their synchronous `require` support in documentation, and synchronous support should
not be otherwise assumed, even if it happens to work when attempted.

See the "Events and AMD" section below for an example of combining synchronous and asynchronous dependencies.

### define()

You can also define your own modules using `define`. Note that you **SHOULD** prefix any modules you define
with a unique key (e.g. `"mycompany/"`) to avoid conflicts with Bitbucket or other plugins. You **MUST NOT** begin your module names with `"bitbucket/"`,
`"atlassian/"`, or `"internal/"`. These prefixes are explicitly reserved for use by Atlassian Bitbucket core.

The format of a define call is `define(module name string, array of dependency ids, callback that returns the module)`

```javascript
define('mycompany/things/helper', ['any', 'module', 'dependencies'], function(any, module, dependencies) {
    var helper = { ... };
    return helper;
});
```

It should be noted that, like `require`, `define` **MAY** be called asynchronously, and you should **NOT** depend on your callback being called by any particular point in time.

#### Good module names

* mycompany/my-module
* mycompany/my-other-module
* mycompany/my-topic/my-third-module

#### Bad module names
* my-module
* bitbucket/my-module
* atlassian/my-module
* internal/my-module

## API Scope

The scope of the JS API is limited to the `require` and `define` global functions, and within that, the `"aui"` module and any modules prefixed
with `"bitbucket/"` except those prefixed with `"bitbucket/internal"`.  Use of any modules with the `"bitbucket/internal"` prefix is not covered
by this API and **SHOULD NOT** be used. Similarly, use of any global properties or functions is not covered by this API and **SHOULD NOT** be used.

### Private naming (`_` or `internal.` prefix)

Any property whose name begins with an underscore is considered private and **SHOULD NOT** be used. E.g. `publicObject._privateProperty`
may not be stable between versions of Bitbucket, but `publicObject.publicProperty` will be.

Similarly, events named starting with `internal.` are for internal use and will not be stable between releases of Bitbucket.

### Data properties

Public data properties will guarantee the following between minor versions:

* If a value is a primitive or object `Number`, `Boolean`, `String`, `Array`, `Date`, `Function` or other `Object`, it will continue to be `typeof` or `instanceof` that type.
* If a value is `instanceof Object` (including Arrays, Dates, and Functions), these stability guarantees apply recursively to all non-private properties on that object.

### Functions

When public functions are called, we guarantee the following between minor versions:

* Any arguments that are valid input to the function as specified in the [JS API Reference](./javascript/) will remain valid between minor versions.
* When called with valid arguments, the return value will remain valid and will be of the return type(s) specified in the reference docs.

### Browser Support

The API's behavior is guaranteed stable only within the [browsers supported by Bitbucket](https://confluence.atlassian.com/display/BitbucketServer/Supported+platforms) for any given release. Since our browser support
is not guaranteed stable between minor versions, this means the supported browsers for the API may change between minor versions.
For example, if support for IE11 is removed in Bitbucket Server 4.x, the behavior of API methods is no longer guaranteed to work in IE11 in Bitbucket Server 4.x+.

### Explicitly out of scope

The following uses are explicitly _out_ of scope for the API. Their behavior is undefined and we make no guarantees about their stability.

* Calling a method property of an object (e.g. `foo.doSomething()`) with any `this` value that isn't that exact object (e.g. `foo.doSomething.call(bar)`).
* Calling any function with a non-`Object` `this` value (e.g., `false`, `null`, `"string"`). We `'use strict'` which means these may behave differently in different browsers.

And note that the following **MAY** change between minor releases:

* Behavior when calling a function with more arguments than are specified in the [reference documentation](./javascript/). We may add extra arguments to functions in minor releases.

    * UNSUPPORTED: `threeArgFunc(one, two, three, four)`

* Behavior when calling a function with object arguments that contain extra properties. These properties may gain meaning in a minor release (e.g. new options are supported).

    * UNSUPPORTED: `func({ validOption: 'a', somethingExtra : 'invalid' })`

* When omitting an optional argument or argument property in a function call, the default behavior of that function may change (but will remain valid).

    * Bitbucket x.y:   `getPrimaryColor() === 'blue'`
    * Bitbucket x.y+1: `getPrimaryColor() === 'yellow'`

* Properties on an object's `prototype` may become enumerable properties on the object itself, or visa versa.
* The configuration of a property may change: (e.g., a `value` may be replaced by `get`/`set` pairs, may change `enumerable` or `writable` values, etc).

## Useful JS patterns

There are a few useful patterns when working against the Bitbucket JS API. Some are also useful in JS at large.

### Immediately-invoked function expressions (IIFE)

When using an AMD module, your code is within a closure, and thus is protected and (somewhat) sandboxed from the global environment. E.g.,

```javascript
require(['some', 'modules'], function() {
    // code in here can be isolated
});
```

When not using AMD, you should isolate your code using an IIFE, so it is less likely to affect or be affected by the global scope:

```javascript
(function() {
    // this code has the same isolation benefits.
})();
```

This ensures that you won't inadvertently create any global variables that have naming conflicts with another plugin.

### Promises

We use a lot of Promises in Bitbucket. Specifically we use the jQuery implementation of Promises and Deferreds. Promises allow
you to pass around a result before that result is actually calculated and available. They are similar to Futures. For any function,
rather than passing in callbacks that will be called when a result is ready, we generally pass _out_ a Promise you can observe for
success or failure.

E.g. where we might have had a function like this:

```javascript
function cookBacon(cookTime, tastyBaconCallback, ruinedBaconCallback) {
    var burner = getStove().getBurner();
    var pan = getPan();
    var bacon = getBacon();

    pan.add(bacon);
    burner.put(pan);
    burner.light('medium');

    setTimeout(function() {
        if (!bacon.isCrispy()) {
            ruinedBaconCallback('Bit longer next time.');
        } else if (bacon.isBurnt()) {
            ruinedBaconCallback('Bit less next time.');
        } else {
            tastyBaconCallback(bacon);
        }
    }, cookTime);
}
```

We do something like this:

```javascript
function cookBacon(cookTime) {
    var deferred = new $.Deferred();

    var burner = getStove().getBurner();
    var pan = getPan();
    var bacon = getBacon();

    pan.add(bacon);
    burner.put(pan);
    burner.light('medium');

    setTimeout(function() {
        if (!bacon.isCrispy()) {
            deferred.reject('Bit longer next time.');
        } else if (bacon.isBurnt()) {
            deferred.reject('Bit less next time.');
        } else {
            deferred.resolve(bacon);
        }
    }, cookTime);

    return deferred.promise();
}
```

Note that the interface becomes simpler - there are no more callbacks required. If you want to wait for the bacon, you
write code like:

```javascript
cookBacon(5 * 60 * 1000).then(function success(bacon) {
    eat(bacon);
}, function failure(suggestion) {
    console.log(suggestion);
})
```

The biggest advantages to Promises are seen when you begin to chain them together, or wait on multiple of them. Check out
[JQuery's Promise documentation](http://api.jquery.com/category/deferred-object/) for more information.

### Events and AMD

Because AMD callbacks may not be called synchronously, it's recommended that you listen for events _outside_ of a require
call when you expect those events to occur before or soon after the page is loaded. The events module is one of a few that
can be loaded synchronously.

E.g.

```javascript
(function() {
    var registry;
    var things;

    function tryInit() {
        if (registry && things) {
            things.foo();
            registry.enableContext('my-shortcut-context');
        }
    }

    // Synchronously get a reference to the `events` module.
    var events = require('bitbucket/util/events');
    // Listen for our event
    events.on('stash.widget.keyboard-shortcuts.register-contexts', function(r) {
        registry = r;
        tryInit();
    });

    // Require any dependencies we need separately from attaching our event listeners.
    require(['things'], function(t) {
        things = t;
        tryInit();
    });
})();
```

This example could be simplified with the use of Promises as well:

```javascript
(function() {
    var gotThings = new $.Deferred();

    // Require any dependencies we need separately from attaching our event listeners.
    require(['things'], gotThings.resolve.bind(gotThings));

    // Synchronously get a reference to the `events` module.
    var events = require('bitbucket/util/events');
    // Listen for our event
    events.on('stash.widget.keyboard-shortcuts.register-contexts', function(registry) {
        gotThings.then(function(things) {
            things.foo();
            registry.enableContext('my-shortcut-context');
        });
    });
})();
```

