Commit c291e0da authored by Mathieu Lutfy's avatar Mathieu Lutfy Committed by Aegir user

ops #794: Install CiviVolunteer 2.2.2-beta1 and AngularProfiles 1.0.2.

parent abbe3b40
<?php
require_once 'CRM/Core/Page.php';
class CRM_AngularProfiles_Page_Template extends CRM_Core_Page {
function run() {
CRM_Core_Region::instance('page-header')->add(array(
'template' => 'CRM/UF/Page/ProfileTemplates.tpl',
));
parent::run();
}
}
This diff is collapsed.
# org.civicrm.angularprofiles
This extension is a utility for allowing angular pages to load the backbone profile editor/selector widget.
It comes prebuilt with a service for loading backbone and necessary files as well as a directive to turn a standard input into the profile widget.
**Note:**
This module does no permission checking and if the user does not have sufficient privilege to use the widget an error message is generated (depending on context this can take the form of an alert box) once for each widget included on the page.
This module was built in conjunction with [CiviVolunteer](https://github.com/civicrm/org.civicrm.volunteer) and a working example can be seen in that project in the project edit view.
###Examples:
####Verifying that backbone is loaded:
```javascript
angular.module('myModule').config(function($routeProvider) {
resolve: {
profile_status: function(crmProfiles) {
return crmProfiles.load();
}
}
}
angular.module('myModule').controller('myController', function($scope,profile_status) {
[...]
}
```
####Use the crm-profile-selector directive to include the widget:
```html
<input crm-profile-selector="{}" ng-model="profile.uf_group_id" />
```
<?php
// AUTO-GENERATED FILE -- Civix may overwrite any changes made to this file
/**
* (Delegated) Implements hook_civicrm_config().
*
* @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_config
*/
function _angularprofiles_civix_civicrm_config(&$config = NULL) {
static $configured = FALSE;
if ($configured) {
return;
}
$configured = TRUE;
$template =& CRM_Core_Smarty::singleton();
$extRoot = dirname(__FILE__) . DIRECTORY_SEPARATOR;
$extDir = $extRoot . 'templates';
if ( is_array( $template->template_dir ) ) {
array_unshift( $template->template_dir, $extDir );
}
else {
$template->template_dir = array( $extDir, $template->template_dir );
}
$include_path = $extRoot . PATH_SEPARATOR . get_include_path( );
set_include_path($include_path);
}
/**
* (Delegated) Implements hook_civicrm_xmlMenu().
*
* @param $files array(string)
*
* @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_xmlMenu
*/
function _angularprofiles_civix_civicrm_xmlMenu(&$files) {
foreach (_angularprofiles_civix_glob(__DIR__ . '/xml/Menu/*.xml') as $file) {
$files[] = $file;
}
}
/**
* Implements hook_civicrm_install().
*
* @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_install
*/
function _angularprofiles_civix_civicrm_install() {
_angularprofiles_civix_civicrm_config();
if ($upgrader = _angularprofiles_civix_upgrader()) {
$upgrader->onInstall();
}
}
/**
* Implements hook_civicrm_uninstall().
*
* @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_uninstall
*/
function _angularprofiles_civix_civicrm_uninstall() {
_angularprofiles_civix_civicrm_config();
if ($upgrader = _angularprofiles_civix_upgrader()) {
$upgrader->onUninstall();
}
}
/**
* (Delegated) Implements hook_civicrm_enable().
*
* @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_enable
*/
function _angularprofiles_civix_civicrm_enable() {
_angularprofiles_civix_civicrm_config();
if ($upgrader = _angularprofiles_civix_upgrader()) {
if (is_callable(array($upgrader, 'onEnable'))) {
$upgrader->onEnable();
}
}
}
/**
* (Delegated) Implements hook_civicrm_disable().
*
* @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_disable
* @return mixed
*/
function _angularprofiles_civix_civicrm_disable() {
_angularprofiles_civix_civicrm_config();
if ($upgrader = _angularprofiles_civix_upgrader()) {
if (is_callable(array($upgrader, 'onDisable'))) {
$upgrader->onDisable();
}
}
}
/**
* (Delegated) Implements hook_civicrm_upgrade().
*
* @param $op string, the type of operation being performed; 'check' or 'enqueue'
* @param $queue CRM_Queue_Queue, (for 'enqueue') the modifiable list of pending up upgrade tasks
*
* @return mixed based on op. for 'check', returns array(boolean) (TRUE if upgrades are pending)
* for 'enqueue', returns void
*
* @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_upgrade
*/
function _angularprofiles_civix_civicrm_upgrade($op, CRM_Queue_Queue $queue = NULL) {
if ($upgrader = _angularprofiles_civix_upgrader()) {
return $upgrader->onUpgrade($op, $queue);
}
}
/**
* @return CRM_AngularProfiles_Upgrader
*/
function _angularprofiles_civix_upgrader() {
if (!file_exists(__DIR__.'/CRM/AngularProfiles/Upgrader.php')) {
return NULL;
}
else {
return CRM_AngularProfiles_Upgrader_Base::instance();
}
}
/**
* Search directory tree for files which match a glob pattern
*
* Note: Dot-directories (like "..", ".git", or ".svn") will be ignored.
* Note: In Civi 4.3+, delegate to CRM_Utils_File::findFiles()
*
* @param $dir string, base dir
* @param $pattern string, glob pattern, eg "*.txt"
* @return array(string)
*/
function _angularprofiles_civix_find_files($dir, $pattern) {
if (is_callable(array('CRM_Utils_File', 'findFiles'))) {
return CRM_Utils_File::findFiles($dir, $pattern);
}
$todos = array($dir);
$result = array();
while (!empty($todos)) {
$subdir = array_shift($todos);
foreach (_angularprofiles_civix_glob("$subdir/$pattern") as $match) {
if (!is_dir($match)) {
$result[] = $match;
}
}
if ($dh = opendir($subdir)) {
while (FALSE !== ($entry = readdir($dh))) {
$path = $subdir . DIRECTORY_SEPARATOR . $entry;
if ($entry{0} == '.') {
} elseif (is_dir($path)) {
$todos[] = $path;
}
}
closedir($dh);
}
}
return $result;
}
/**
* (Delegated) Implements hook_civicrm_managed().
*
* Find any *.mgd.php files, merge their content, and return.
*
* @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_managed
*/
function _angularprofiles_civix_civicrm_managed(&$entities) {
$mgdFiles = _angularprofiles_civix_find_files(__DIR__, '*.mgd.php');
foreach ($mgdFiles as $file) {
$es = include $file;
foreach ($es as $e) {
if (empty($e['module'])) {
$e['module'] = 'org.civicrm.angularprofiles';
}
$entities[] = $e;
}
}
}
/**
* (Delegated) Implements hook_civicrm_caseTypes().
*
* Find any and return any files matching "xml/case/*.xml"
*
* Note: This hook only runs in CiviCRM 4.4+.
*
* @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_caseTypes
*/
function _angularprofiles_civix_civicrm_caseTypes(&$caseTypes) {
if (!is_dir(__DIR__ . '/xml/case')) {
return;
}
foreach (_angularprofiles_civix_glob(__DIR__ . '/xml/case/*.xml') as $file) {
$name = preg_replace('/\.xml$/', '', basename($file));
if ($name != CRM_Case_XMLProcessor::mungeCaseType($name)) {
$errorMessage = sprintf("Case-type file name is malformed (%s vs %s)", $name, CRM_Case_XMLProcessor::mungeCaseType($name));
CRM_Core_Error::fatal($errorMessage);
// throw new CRM_Core_Exception($errorMessage);
}
$caseTypes[$name] = array(
'module' => 'org.civicrm.angularprofiles',
'name' => $name,
'file' => $file,
);
}
}
/**
* (Delegated) Implements hook_civicrm_angularModules().
*
* Find any and return any files matching "ang/*.ang.php"
*
* Note: This hook only runs in CiviCRM 4.5+.
*
* @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_angularModules
*/
function _angularprofiles_civix_civicrm_angularModules(&$angularModules) {
if (!is_dir(__DIR__ . '/ang')) {
return;
}
$files = _angularprofiles_civix_glob(__DIR__ . '/ang/*.ang.php');
foreach ($files as $file) {
$name = preg_replace(':\.ang\.php$:', '', basename($file));
$module = include $file;
if (empty($module['ext'])) {
$module['ext'] = 'org.civicrm.angularprofiles';
}
$angularModules[$name] = $module;
}
}
/**
* Glob wrapper which is guaranteed to return an array.
*
* The documentation for glob() says, "On some systems it is impossible to
* distinguish between empty match and an error." Anecdotally, the return
* result for an empty match is sometimes array() and sometimes FALSE.
* This wrapper provides consistency.
*
* @link http://php.net/glob
* @param string $pattern
* @return array, possibly empty
*/
function _angularprofiles_civix_glob($pattern) {
$result = glob($pattern);
return is_array($result) ? $result : array();
}
/**
* Inserts a navigation menu item at a given place in the hierarchy.
*
* @param array $menu - menu hierarchy
* @param string $path - path where insertion should happen (ie. Administer/System Settings)
* @param array $item - menu you need to insert (parent/child attributes will be filled for you)
* @param int $parentId - used internally to recurse in the menu structure
*/
function _angularprofiles_civix_insert_navigation_menu(&$menu, $path, $item, $parentId = NULL) {
static $navId;
// If we are done going down the path, insert menu
if (empty($path)) {
if (!$navId) $navId = CRM_Core_DAO::singleValueQuery("SELECT max(id) FROM civicrm_navigation");
$navId ++;
$menu[$navId] = array (
'attributes' => array_merge($item, array(
'label' => CRM_Utils_Array::value('name', $item),
'active' => 1,
'parentID' => $parentId,
'navID' => $navId,
))
);
return true;
}
else {
// Find an recurse into the next level down
$found = false;
$path = explode('/', $path);
$first = array_shift($path);
foreach ($menu as $key => &$entry) {
if ($entry['attributes']['name'] == $first) {
if (!$entry['child']) $entry['child'] = array();
$found = _angularprofiles_civix_insert_navigation_menu($entry['child'], implode('/', $path), $item, $key);
}
}
return $found;
}
}
/**
* (Delegated) Implements hook_civicrm_alterSettingsFolders().
*
* @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_alterSettingsFolders
*/
function _angularprofiles_civix_civicrm_alterSettingsFolders(&$metaDataFolders = NULL) {
static $configured = FALSE;
if ($configured) {
return;
}
$configured = TRUE;
$settingsDir = __DIR__ . DIRECTORY_SEPARATOR . 'settings';
if(is_dir($settingsDir) && !in_array($settingsDir, $metaDataFolders)) {
$metaDataFolders[] = $settingsDir;
}
}
<?php
require_once 'angularprofiles.civix.php';
/**
* Implementation of hook_civicrm_config
*
* @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_config
* @param $config
*/
function angularprofiles_civicrm_config(&$config) {
_angularprofiles_civix_civicrm_config($config);
}
/**
* Implementation of hook_civicrm_xmlMenu
*
* @param $files array(string)
*
* @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_xmlMenu
*/
function angularprofiles_civicrm_xmlMenu(&$files) {
_angularprofiles_civix_civicrm_xmlMenu($files);
}
/**
* Implementation of hook_civicrm_install
*
* @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_install
*/
function angularprofiles_civicrm_install() {
return _angularprofiles_civix_civicrm_install();
}
/**
* Implementation of hook_civicrm_uninstall
*
* @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_uninstall
*/
function angularprofiles_civicrm_uninstall() {
return _angularprofiles_civix_civicrm_uninstall();
}
/**
* Implementation of hook_civicrm_enable
*
* @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_enable
*/
function angularprofiles_civicrm_enable() {
return _angularprofiles_civix_civicrm_enable();
}
/**
* Implementation of hook_civicrm_disable
*
* @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_disable
*/
function angularprofiles_civicrm_disable() {
return _angularprofiles_civix_civicrm_disable();
}
/**
* Implementation of hook_civicrm_upgrade
*
* @param $op string, the type of operation being performed; 'check' or 'enqueue'
* @param $queue CRM_Queue_Queue, (for 'enqueue') the modifiable list of pending up upgrade tasks
*
* @return mixed based on op. for 'check', returns array(boolean) (TRUE if upgrades are pending)
* for 'enqueue', returns void
*
* @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_upgrade
*/
function angularprofiles_civicrm_upgrade($op, CRM_Queue_Queue $queue = NULL) {
return _angularprofiles_civix_civicrm_upgrade($op, $queue);
}
/**
* Implementation of hook_civicrm_managed
*
* Generate a list of entities to create/deactivate/delete when this module
* is installed, disabled, uninstalled.
*
* @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_managed
* @param $entities
*/
function angularprofiles_civicrm_managed(&$entities) {
return _angularprofiles_civix_civicrm_managed($entities);
}
/**
* Implementation of hook_civicrm_caseTypes
*
* Generate a list of case-types
*
* Note: This hook only runs in CiviCRM 4.4+.
*
* @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_caseTypes
* @param $caseTypes
*/
function angularprofiles_civicrm_caseTypes(&$caseTypes) {
_angularprofiles_civix_civicrm_caseTypes($caseTypes);
}
/**
* Implementation of hook_civicrm_alterSettingsFolders
*
* @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_alterSettingsFolders
* @param null $metaDataFolders
*/
function angularprofiles_civicrm_alterSettingsFolders(&$metaDataFolders = NULL) {
_angularprofiles_civix_civicrm_alterSettingsFolders($metaDataFolders);
}
/**
* @param $angularModule
*/
function angularprofiles_civicrm_angularModules(&$angularModule) {
$angularModule['crmProfileUtils'] = array(
'ext' => 'org.civicrm.angularprofiles',
'js' => array('js/*.js'),
'partials' => array('partials'),
);
}
<?php
/**
* Profile.GetAngularSettings API specification (optional)
* This is used for documentation and validation.
*
* @param array $spec description of fields supported by this API call
* @return void
* @see http://wiki.civicrm.org/confluence/display/CRM/API+Architecture+Standards
*/
function _civicrm_api3_profile_getangularsettings_spec(&$spec) {
}
/**
* Profile.GetAngularSettings API
*
* @param array $params
* @return array API result descriptor
* @see civicrm_api3_create_success
* @see civicrm_api3_create_error
* @throws API_Exception
*/
function civicrm_api3_profile_getangularsettings($params) {
$returnValues = array(
'PseudoConstant' => array(
'locationType' => CRM_Core_PseudoConstant::get('CRM_Core_DAO_Address', 'location_type_id'),
'websiteType' => CRM_Core_PseudoConstant::get('CRM_Core_DAO_Website', 'website_type_id'),
'phoneType' => CRM_Core_PseudoConstant::get('CRM_Core_DAO_Phone', 'phone_type_id'),
),
'initialProfileList' => civicrm_api('UFGroup', 'get', array(
'version' => 3,
'sequential' => 1,
'is_active' => 1,
'rowCount' => 1000, // FIXME
)),
'contactSubTypes' => CRM_Contact_BAO_ContactType::subTypes(),
'profilePreviewKey' => CRM_Core_Key::get('CRM_UF_Form_Inline_Preview', TRUE),
);
return civicrm_api3_create_success($returnValues, $params, 'Profile', 'getangularsettings');
}
<?xml version="1.0"?>
<extension key="org.civicrm.angularprofiles" type="module">
<file>angularprofiles</file>
<name>Angular Profiles</name>
<description>A Utility extension that provides Profile support to AngularJS pages</description>
<license>AGPL-3.0</license>
<maintainer>
<author>Tobias Lounsbury</author>
<email>toby@ginkgostreet.com</email>
</maintainer>
<releaseDate>2016-06-20</releaseDate>
<version>4.6-1.0.2</version>
<develStage>stable</develStage>
<compatibility>
<ver>4.6</ver>
<ver>4.7</ver>
</compatibility>
<comments>
This extension is a utility for allowing AngularJS pages to load CiviCRM's Backbone.js-based profile editor/selector
widget. It comes prebuilt with a service for loading Backbone.js and necessary files as well as an AngularJS directive
to turn a standard input into the profile widget.
</comments>
<civix>
<namespace>CRM/AngularProfiles</namespace>
</civix>
<urls>
<url desc="Documentation">https://github.com/ginkgostreet/org.civicrm.angularprofiles</url>
</urls>
</extension>
(function(angular, $, _) {
angular.module('crmProfileUtils', []);
angular.module('crmProfileUtils').factory('crmProfiles', function($q, crmApi){
//This was done as a recursive function because the scripts
//Must execute in order.
function loadNextScript(scripts, callback, fail) {
var script = scripts.shift();
CRM.$.getScript(CRM.config.resourceBase + script.url)
.done(function(scriptData, status) {
if(scripts.length) {
loadNextScript(scripts, callback, fail);
} else {
callback();
}
}).fail(function(jqxhr, settings, exception) {
fail(exception);
});
}
function loadStyleFile(url) {
CRM.$("#backbone_resources").append("<link href='"+url+"' />");
}
function loadBackbone() {
var deferred = $q.defer();
var scripts = [
{url: 'packages/jquery/plugins/jstree/jquery.jstree.js', weight: 0},
{url: 'packages/backbone/json2.js', weight: 100},
{url: 'packages/backbone/backbone.js', weight: 120},
{url: 'packages/backbone/backbone.marionette.js', weight: 125},
{url: 'packages/backbone/backbone.collectionsubset.js', weight: 125},
{url: 'packages/backbone-forms/distribution/backbone-forms.js', weight: 130},
{url: 'packages/backbone-forms/distribution/adapters/backbone.bootstrap-modal.min.js', weight: 140},
{url: 'packages/backbone-forms/distribution/editors/list.min.js', weight: 140},
{url: 'js/crm.backbone.js', weight: 150},
{url: 'js/model/crm.schema-mapped.js', weight: 200},
{url: 'js/model/crm.uf.js', weight: 200},
{url: 'js/model/crm.designer.js', weight: 200},
{url: 'js/model/crm.profile-selector.js', weight: 200},
{url: 'js/view/crm.designer.js', weight: 200},
{url: 'js/view/crm.profile-selector.js', weight: 200},
{url: 'js/jquery/jquery.crmProfileSelector.js', weight: 250},
{url: 'js/crm.designerapp.js', weight: 250}
];
scripts.sort(function(a, b){
return a.weight-b.weight;
});
//mess with the jQuery versions
CRM.origJQuery = window.jQuery;
window.jQuery = CRM.$;
//We need to put underscore on the global scope or backbone fails to load
window._ = CRM._;
loadStyleFile(CRM.config.resourceBase + 'packages/jquery/plugins/jstree/themes/default/style.css');
loadStyleFile(CRM.config.resourceBase + 'packages/backbone-forms/distribution/templates/default.css');
loadStyleFile(CRM.config.resourceBase + 'css/crm.designer.css');
//This is a recursive function that takes a list of scripts
//and a pair of callbacks. It will load the scripts in order
//from the list, and then call the callback. Errors will result in
//Calling the error callback.
loadNextScript(scripts, function () {
window.jQuery = CRM.origJQuery;
delete CRM.origJQuery;
delete window._;
deferred.resolve(true);
}, function(status) {
deferred.resolve(status);
});
return deferred.promise;
}
function loadSettings() {
var deferred = $q.defer();
//Fetch the settings from the api
crmApi('profile', 'getangularsettings').then(function(result) {
if(result.hasOwnProperty('values')) {
CRM.$.extend(true, CRM, result.values);