Note: due to legacy code written before these standards were adopted, CiviCRM still has quite a few other global variables and functions. Aside from the 2 listed below, they all need to be removed from the global scope. You can help!
### Location
### Location
Javascript code should only really be found in three main locations
1 Inline scripts should be included in smarty .tpl template files. This should only be done where its limited to a specific page or form. Inline js must be enclosed in smarty {literal} tags
1 Inline scripts should be included in smarty .tpl template files. This should only be done where its limited to a specific page or form. Inline js must be enclosed in smarty {literal} tags
2. For any Javascript that acts as untility functions e.g. AJAX or any helper Javascript should go in the js/ folder of civicrm-core repo
3. For all angular javascript code that should go in an ang/ folder
...
...
@@ -37,7 +37,7 @@ PE is a philosophy that the basic functionality of a webpage should not depend o
## Globals
CiviCRM Provides two Javascript globals:
CiviCRM Provides two Javascript globals:
* CRM - Contains all globally needed variables and functions for CiviCRM. Also contains server-side variables and translations.
* ts - Function for translating strings. Signature is identical to its php counterpart.
...
...
@@ -57,4 +57,147 @@ Exception: CiviCRM reserves a space in the document header where CRM.$ == jQuery
Note: Some CMSs do not add jQuery to the page, in which case the global jQuery would not exist (except within the header as noted above). Don't rely on it.
Note: Yes, 2 copies of jQuery on the same page is inefficient. There is a solution for Drupal 7 to combine them: https://www.drupal.org/project/civi_jquery
Note: Yes, 2 copies of jQuery on the same page is inefficient. There is a solution for Drupal 7 to combine them: [civi_jquery](https://www.drupal.org/project/civi_jquery).
## Adding Javascript Files
CiviCRM contains a Resource controller which allows extensions to add in .js files into pages and forms as is needed. This can also be done through any hook implementation as well.
An Example of adding in a file called bar.js from the extension com.example.foo
You can also specify other regions of the page to place the script in (the most common reason for this is because jQuery plugins must be added to the "html-header" region). See [Resource Reference](https://wiki.civicrm.org/confluence/display/CRMDOC43/Resource+Reference) for more details.
## Using CiviCRM Javascript in non CiviCRM pages
If you are working outside the context of CiviCRM pages (e.g. on a Drupal page, Wordpress widget, Joomla page, etc) you need to explicitly tell CiviCRM to load its javascript in to the page header. You can add your own scripts as well.
Note when your using CiviCRM's resource manager to add scripts to non civicrm pages they need to be put as region 'html-header' because CiviCRM has no control over any of the other regions in non-civicrm pages.
## Enclosing your code
In Javacript all code needs to be closures to create the variable scope. Without closures, all variables would be global and there would be a significant risk of name collisions.
The simplest closure you could write would be:
```javascript
CRM.$(function($){
// your code here
});
```
Remember that CRM.$ is our alias of jQuery. So the first line is shorthand notation for CRM.$('document').ready(function($) {
The function receives jQuery as it's param, so now we have access to jQuery as the familiar $ for use in our code.
If your code needs to work across multiple versions of CiviCRM, where jQuery was the older cj as well as the current CRM.$ you can use:
```javascript
(function($){
// your code here
})(CRM.$||cj)
```
For more examples you can take a look at a [gist](https://gist.github.com/totten/9591b10d4bc09c78108d) from Tim Otten on javascript alternatives For more information on javascript closures, [here is some further reading](http://www.adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth).
## Accessing CiviCRM API from JS
If the current user has sufficient permissions (usually "Access CiviCRM") then your script can call the api and accomplish almost anything in CiviCRM. The syntax is:
For more details, see [AJAX API](http://wiki.civicrm.org/confluence/display/CRMDOC43/AJAX+Interface) docs.
## Server-Side Variables
Just as you can dynamically add scripts to the page you can also add variables. They will be added to the CRM object in JSON format. Because this object is shared by many CiviCRM components, you should choose a unique namespace (typically the name of your extension). Example:
As with PHP coding, any string that will be displayed to the user should be wrapped in ts() to translate the string. e.g. ts('hello')
When your script file is being added to the page by CRM_Core_Resources it will be automatically scanned for all strings enclosed in ts() and their translations will be added as client-side variables. The javascript ts() function will use these localized strings. It can also perform variable substitution. See example below.
!!!Note
Because translated strings are added to the client-side by CRM_Core_Resources addScriptFile method, they will not be automatically added if you include your js on the page any other way. The ts() function will still work and perform variable substitution, but the localized string will not be available. There are 3 solutions to this problem depending on your context:
1. If this is an inline script in a smarty template, use the {ts} function (see legacy issues below for an example). Note that {ts} cannot handle client-side variable substitution, only server-side template variables.
2. If this is an inline script in a php file, use the php ts() function to do your translation and concatenate the result into your script. Or, if you need client-side variable substitution use the 3rd solution:
3. If this is a javascript file being added to the page in a nonstandard way (or is one of the above two scenarios but you need client-side variable substitution), you could manually add any needed strings using the CRM_Core_Resources addString method
## UI Elements
CiviCRM ships with a number of UI widgets and plugins to create standardized "look and feel" More information can be found in [UI Elements Reference](https://wiki.civicrm.org/confluence/display/CRMDOC/UI+Elements+Reference).
## Quality Control
CiviCRM has a number of mechanisms that it uses to ensure quality of javascript that is submitted to core.
### JSHint
CiviCRM uses JSHint as part of the style checking process whenever a Pull Request is submitted against the civicrm-core repo. It ensures that all Javascript submitted meets CiviCRM's current Javascript stndard.
### Qunit
CiviCRM has a small set up of Qunit which is an automated testing system. It's generally inspired by the xUnit family (JUnit, PHPUnit, etc) and allows you to test low- and mid-level component functionality. It's most suitable for testing pure Javascript components. For a general introduction, see the [README](https://github.com/civicrm/civicrm-core/blob/master/tests/qunit/README.txt) and [example test](https://github.com/civicrm/civicrm-core/tree/master/tests/qunit/example) that ship with CiviCRM. It is currently only run manually through a web broweser.
### Karma
For testing CiviCRM's Angular implementation in Core, CiviCRM has intergrated some Karma tests into the standard test suite that is run against each Pull request.
## Javascript in Markup
Putting javascript code directly into html tags is deprecated. We are migrating our existing code away from this practice.
- It doesn't allow for separation of concerns between the presentation layer (html) and the business logic (js code).
```js
CRM.$(function($){
$('a.my-selector').on('click',function(){
// code goes here
});
});
```
Note: sometimes you want to add a handler to an element that does not exist yet in the markup (or might be replaced), like each row in a datatable. For that use the delegation provided by jQuery's "on" method and attach the handler to some outer container that is going to be there more permanently.
## ClientSide MVC
In the past, PHP-based webapps like CiviCRM have treated javascript as little more than an extension of css. But increasingly they are realizing the potential of Javascript to handle business logic. Javascript can be used to create robust, responsive, user-friendly webapps. But with this complexity comes the need for structure. While CiviCRM has not officially adopted a clientside MVC framework, version 4.3 includes a new UI for editing profiles which was built using Underscore, Backbone and Marionette. And 4.5 includes a new case-configuration interface built on Angular. In 4.6 CiviMail User Interface was re-written in Angular.
More detail can be found in the [Angular reference documents](https://docs.civicrm.org/dev/en/stable/framework/angular/)