Skip to content
Snippets Groups Projects
Commit a45bb90b authored by Jared Hancock's avatar Jared Hancock
Browse files

orgs: Add UI support to configure contacts and collaboration

parent ac2210f9
Branches
Tags
No related merge requests found
.ui-multiselect { padding:2px 0 2px 4px; text-align:left }
.ui-multiselect span.ui-icon { float:right }
.ui-multiselect-single .ui-multiselect-checkboxes input { position:absolute !important; top: auto !important; left:-9999px; }
.ui-multiselect-single .ui-multiselect-checkboxes label { padding:5px !important }
.ui-multiselect-header { margin-bottom:3px; padding:3px 0 3px 4px }
.ui-multiselect-header ul { font-size:0.9em }
.ui-multiselect-header ul li { float:left; padding:0 10px 0 0 }
.ui-multiselect-header a { text-decoration:none }
.ui-multiselect-header a:hover { text-decoration:underline }
.ui-multiselect-header span.ui-icon { float:left }
.ui-multiselect-header li.ui-multiselect-close { float:right; text-align:right; padding-right:0 }
.ui-multiselect-menu { display:none; padding:3px; position:absolute; z-index:10000; text-align: left }
.ui-multiselect-checkboxes { position:relative /* fixes bug in IE6/7 */; overflow-y:auto }
.ui-multiselect-checkboxes label { cursor:default; display:block; border:1px solid transparent; padding:3px 1px }
.ui-multiselect-checkboxes label input { position:relative; top:1px }
.ui-multiselect-checkboxes li { clear:both; font-size:0.9em; padding-right:3px }
.ui-multiselect-checkboxes li.ui-multiselect-optgroup-label { text-align:center; font-weight:bold; border-bottom:1px solid }
.ui-multiselect-checkboxes li.ui-multiselect-optgroup-label a { display:block; padding:3px; margin:1px 0; text-decoration:none }
/* remove label borders in IE6 because IE6 does not support transparency */
* html .ui-multiselect-checkboxes label { border:none }
......@@ -61,11 +61,12 @@ class OrgsAjaxAPI extends AjaxController {
);
$forms = $org->getForms();
$action = "#orgs/{$org->id}/profile";
include(STAFFINC_DIR . 'templates/org.tmpl.php');
include(STAFFINC_DIR . 'templates/org-profile.tmpl.php');
}
function updateOrg($id) {
function updateOrg($id, $profile=false) {
global $thisstaff;
if(!$thisstaff)
......@@ -78,7 +79,15 @@ class OrgsAjaxAPI extends AjaxController {
Http::response(201, $org->to_json());
$forms = $org->getForms();
include(STAFFINC_DIR . 'templates/org.tmpl.php');
if ($profile) {
$action = "#orgs/{$org->id}/profile";
include(STAFFINC_DIR . 'templates/org-profile.tmpl.php');
}
else {
$action = "#orgs/{$org->id}";
include(STAFFINC_DIR . 'templates/org.tmpl.php');
}
}
......
......@@ -28,6 +28,10 @@ class OrganizationModel extends VerySimpleModel {
)
);
const COLLAB_ALL_MEMBERS = 0x0001;
const COLLAB_PRIMARY_CONTACT = 0x0002;
const ASSIGN_AGENT_MANAGER = 0x0004;
function getId() {
return $this->id;
}
......@@ -43,6 +47,22 @@ class OrganizationModel extends VerySimpleModel {
function getCreateDate() {
return $this->created;
}
function check($flag) {
return 0 !== ($this->status & $flag);
}
protected function clearStatus($flag) {
return $this->set('status', $this->get('status') & ~$flag);
}
protected function setStatus($flag) {
return $this->set('status', $this->get('status') | $flag);
}
function allMembers() {
return $this->users;
}
}
class Organization extends OrganizationModel {
......@@ -96,6 +116,19 @@ class Organization extends OrganizationModel {
return $this->_forms;
}
function getInfo() {
$base = $this->ht;
foreach (array(
'collab-all-flag' => Organization::COLLAB_ALL_MEMBERS,
'collab-pc-flag' => Organization::COLLAB_PRIMARY_CONTACT,
'assign-am-flag' => Organization::ASSIGN_AGENT_MANAGER,
) as $ck=>$flag) {
if ($this->check($flag))
$base[$ck] = true;
}
return $base;
}
function to_json() {
$info = array(
......@@ -129,7 +162,18 @@ class Organization extends OrganizationModel {
}
}
if (!$valid)
if ($vars['domain']) {
foreach (explode(',', $vars['domain']) as $d) {
if (!Validator::is_email('test' . trim($d))) {
$errors['domain'] = 'Enter a valid email domain, like @domain.com';
}
}
}
if ($vars['staff_id'] && (!$staff = Staff::lookup($vars['staff_id'])))
$errors['staff_id'] = 'Select a staff member from the list';
if (!$valid || $errors)
return false;
foreach ($this->getDynamicData() as $cd) {
......@@ -142,7 +186,29 @@ class Organization extends OrganizationModel {
$cd->save();
}
return true;
// Set flags
foreach (array(
'collab-all-flag' => Organization::COLLAB_ALL_MEMBERS,
'collab-pc-flag' => Organization::COLLAB_PRIMARY_CONTACT,
'assign-am-flag' => Organization::ASSIGN_AGENT_MANAGER,
) as $ck=>$flag) {
if ($vars[$ck])
$this->setStatus($flag);
else
$this->clearStatus($flag);
}
// Set staff and primary contacts
$this->set('domain', $vars['domain']);
$this->set('staff_id', $staff ? $staff->getId() : 0);
if ($vars['contacts'] && is_array($vars['contacts'])) {
foreach ($this->allMembers() as $u) {
$u->setPrimaryContact(array_search($u->id, $vars['contacts']) !== false);
$u->save();
}
}
return $this->save();
}
static function fromVars($vars) {
......
......@@ -77,6 +77,8 @@ class UserModel extends VerySimpleModel {
)
);
const PRIMARY_ORG_CONTACT = 0x0001;
function getId() {
return $this->id;
}
......@@ -110,6 +112,29 @@ class UserModel extends VerySimpleModel {
return true;
}
protected function hasStatus($flag) {
return $this->get('status') & $flag !== 0;
}
protected function clearStatus($flag) {
return $this->set('status', $this->get('status') & ~$flag);
}
protected function setStatus($flag) {
return $this->set('status', $this->get('status') | $flag);
}
function isPrimaryContact() {
return $this->hasStatus(User::PRIMARY_ORG_CONTACT);
}
function setPrimaryContact($flag) {
if ($flag)
$this->setStatus(User::PRIMARY_ORG_CONTACT);
else
$this->clearStatus(User::PRIMARY_ORG_CONTACT);
}
}
class User extends UserModel {
......
<?php
$info=($_POST && $errors)?Format::input($_POST):@Format::htmlchars($org->getInfo());
if (!$info['title'])
$info['title'] = Format::htmlchars($org->getName());
?>
<script type="text/javascript" src="<?php echo ROOT_PATH; ?>js/jquery.multiselect.min.js"></script>
<link rel="stylesheet" href="<?php echo ROOT_PATH; ?>css/jquery.multiselect.css"/>
<h3><?php echo $info['title']; ?></h3>
<b><a class="close" href="#"><i class="icon-remove-circle"></i></a></b>
<hr/>
<?php
if ($info['error']) {
echo sprintf('<p id="msg_error">%s</p>', $info['error']);
} elseif ($info['msg']) {
echo sprintf('<p id="msg_notice">%s</p>', $info['msg']);
} ?>
<ul class="tabs">
<li><a href="#tab-profile" class="active"
><i class="icon-edit"></i>&nbsp;Fields</a></li>
<li><a href="#contact-settings"
><i class="icon-fixed-width icon-cogs faded"></i>&nbsp;Settings</a></li>
</ul>
<form method="post" class="org" action="<?php echo $action; ?>">
<div class="tab_content" id="tab-profile" style="margin:5px;">
<?php
$action = $info['action'] ? $info['action'] : ('#orgs/'.$org->getId());
if ($ticket && $ticket->getOwnerId() == $user->getId())
$action = '#tickets/'.$ticket->getId().'/user';
?>
<input type="hidden" name="id" value="<?php echo $org->getId(); ?>" />
<table width="100%">
<?php
if (!$forms) $forms = $org->getForms();
foreach ($forms as $form)
$form->render();
?>
</table>
</div>
<div class="tab_content" id="contact-settings" style="display:none;margin:5px;">
<table style="width:100%">
<tbody>
<tr>
<td width="180">
Account Manager:
</td>
<td>
<select name="staff_id">
<option value="0" selected="selected">&mdash; None &mdash;</option><?php
if (($agents=Staff::getAvailableStaffMembers())) {
foreach($agents as $id => $name) {
echo sprintf('<option value="%s" %s>%s</option>',
$id,(($info['staff_id']==$id)?'selected="selected"':''),$name);
}
} ?>
</select>
<br/><span class="error"><?php echo $errors['staff_id']; ?></span>
</td>
</tr>
<tr>
<td width="180">
Auto-Assignment:
</td>
<td>
<input type="checkbox" name="assign-am-flag" value="1" <?php echo $info['assign-am-flag']?'checked="checked"':''; ?>>
Assign tickets from this organization to the <em>Account Manager</em>
</tr>
<tr>
<td width="180">
Primary Contacts:
</td>
<td>
<select name="contacts[]" id="primary_contacts" multiple="multiple">
<?php foreach ($org->allMembers() as $u) { ?>
<option value="<?php echo $u->id; ?>" <?php
if ($u->isPrimaryContact())
echo 'selected="selected"'; ?>><?php echo $u->getName(); ?></option>
<?php } ?>
</select>
<br/><span class="error"><?php echo $errors['contacts']; ?></span>
</td>
<tr>
<th colspan="2">
Automated Collaboration:
</th>
</tr>
<tr>
<td width="180">
Primary Contacts:
</td>
<td>
<input type="checkbox" name="collab-pc-flag" value="1" <?php echo $info['collab-pc-flag']?'checked="checked"':''; ?>>
Add to all tickets from this organization
</td>
</tr>
<tr>
<td width="180">
Organization Members:
</td>
<td>
<input type="checkbox" name="collab-all-flag" value="1" <?php echo $info['collab-all-flag']?'checked="checked"':''; ?>>
Add to all tickets from this organization
</td>
</tr>
<tr>
<th colspan="2">
Main Domain
</th>
</tr>
<tr>
<td style="width:180px">
Auto Add Members From:
</td>
<td>
<input type="text" size="40" maxlength="60" name="domain"
value="<?php echo $info['domain']; ?>" />
<br/><span class="error"><?php echo $errors['domain']; ?></span>
</td>
</tr>
</tbody>
</table>
</div>
<div class="clear"></div>
<hr>
<p class="full-width">
<span class="buttons" style="float:left">
<input type="reset" value="Reset">
<input type="button" name="cancel" class="<?php
echo $account ? 'cancel' : 'close'; ?>" value="Cancel">
</span>
<span class="buttons" style="float:right">
<input type="submit" value="Update Organization">
</span>
</p>
</form>
<script type="text/javascript">
$(function() {
$('a#editorg').click( function(e) {
e.preventDefault();
$('div#org-profile').hide();
$('div#org-form').fadeIn();
return false;
});
$(document).on('click', 'form.org input.cancel', function (e) {
e.preventDefault();
$('div#org-form').hide();
$('div#org-profile').fadeIn();
return false;
});
$("#primary_contacts").multiselect({'noneSelectedText':'Select Contacts'});
});
</script>
/*
* jQuery MultiSelect UI Widget 1.13
* Copyright (c) 2012 Eric Hynds
*
* http://www.erichynds.com/jquery/jquery-ui-multiselect-widget/
*
* Depends:
* - jQuery 1.4.2+
* - jQuery UI 1.8 widget factory
*
* Optional:
* - jQuery UI effects
* - jQuery UI position utility
*
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
*/
(function(d){var k=0;d.widget("ech.multiselect",{options:{header:!0,height:175,minWidth:225,classes:"",checkAllText:"Check all",uncheckAllText:"Uncheck all",noneSelectedText:"Select options",selectedText:"# selected",selectedList:0,show:null,hide:null,autoOpen:!1,multiple:!0,position:{}},_create:function(){var a=this.element.hide(),b=this.options;this.speed=d.fx.speeds._default;this._isOpen=!1;a=(this.button=d('<button type="button"><span class="ui-icon ui-icon-triangle-2-n-s"></span></button>')).addClass("ui-multiselect ui-widget ui-state-default ui-corner-all").addClass(b.classes).attr({title:a.attr("title"),"aria-haspopup":!0,tabIndex:a.attr("tabIndex")}).insertAfter(a);(this.buttonlabel=d("<span />")).html(b.noneSelectedText).appendTo(a);var a=(this.menu=d("<div />")).addClass("ui-multiselect-menu ui-widget ui-widget-content ui-corner-all").addClass(b.classes).appendTo(document.body),c=(this.header=d("<div />")).addClass("ui-widget-header ui-corner-all ui-multiselect-header ui-helper-clearfix").appendTo(a);(this.headerLinkContainer=d("<ul />")).addClass("ui-helper-reset").html(function(){return!0===b.header?'<li><a class="ui-multiselect-all" href="#"><span class="ui-icon ui-icon-check"></span><span>'+b.checkAllText+'</span></a></li><li><a class="ui-multiselect-none" href="#"><span class="ui-icon ui-icon-closethick"></span><span>'+b.uncheckAllText+"</span></a></li>":"string"===typeof b.header?"<li>"+b.header+"</li>":""}).append('<li class="ui-multiselect-close"><a href="#" class="ui-multiselect-close"><span class="ui-icon ui-icon-circle-close"></span></a></li>').appendTo(c);(this.checkboxContainer=d("<ul />")).addClass("ui-multiselect-checkboxes ui-helper-reset").appendTo(a);this._bindEvents();this.refresh(!0);b.multiple||a.addClass("ui-multiselect-single")},_init:function(){!1===this.options.header&&this.header.hide();this.options.multiple||this.headerLinkContainer.find(".ui-multiselect-all, .ui-multiselect-none").hide();this.options.autoOpen&&this.open();this.element.is(":disabled")&&this.disable()},refresh:function(a){var b=this.element,c=this.options,f=this.menu,h=this.checkboxContainer,g=[],e="",i=b.attr("id")||k++;b.find("option").each(function(b){d(this);var a=this.parentNode,f=this.innerHTML,h=this.title,k=this.value,b="ui-multiselect-"+(this.id||i+"-option-"+b),l=this.disabled,n=this.selected,m=["ui-corner-all"],o=(l?"ui-multiselect-disabled ":" ")+this.className,j;"OPTGROUP"===a.tagName&&(j=a.getAttribute("label"),-1===d.inArray(j,g)&&(e+='<li class="ui-multiselect-optgroup-label '+a.className+'"><a href="#">'+j+"</a></li>",g.push(j)));l&&m.push("ui-state-disabled");n&&!c.multiple&&m.push("ui-state-active");e+='<li class="'+o+'">';e+='<label for="'+b+'" title="'+h+'" class="'+m.join(" ")+'">';e+='<input id="'+b+'" name="multiselect_'+i+'" type="'+(c.multiple?"checkbox":"radio")+'" value="'+k+'" title="'+f+'"';n&&(e+=' checked="checked"',e+=' aria-selected="true"');l&&(e+=' disabled="disabled"',e+=' aria-disabled="true"');e+=" /><span>"+f+"</span></label></li>"});h.html(e);this.labels=f.find("label");this.inputs=this.labels.children("input");this._setButtonWidth();this._setMenuWidth();this.button[0].defaultValue=this.update();a||this._trigger("refresh")},update:function(){var a=this.options,b=this.inputs,c=b.filter(":checked"),f=c.length,a=0===f?a.noneSelectedText:d.isFunction(a.selectedText)?a.selectedText.call(this,f,b.length,c.get()):/\d/.test(a.selectedList)&&0<a.selectedList&&f<=a.selectedList?c.map(function(){return d(this).next().html()}).get().join(", "):a.selectedText.replace("#",f).replace("#",b.length);this.buttonlabel.html(a);return a},_bindEvents:function(){function a(){b[b._isOpen? "close":"open"]();return!1}var b=this,c=this.button;c.find("span").bind("click.multiselect",a);c.bind({click:a,keypress:function(a){switch(a.which){case 27:case 38:case 37:b.close();break;case 39:case 40:b.open()}},mouseenter:function(){c.hasClass("ui-state-disabled")||d(this).addClass("ui-state-hover")},mouseleave:function(){d(this).removeClass("ui-state-hover")},focus:function(){c.hasClass("ui-state-disabled")||d(this).addClass("ui-state-focus")},blur:function(){d(this).removeClass("ui-state-focus")}});this.header.delegate("a","click.multiselect",function(a){if(d(this).hasClass("ui-multiselect-close"))b.close();else b[d(this).hasClass("ui-multiselect-all")?"checkAll":"uncheckAll"]();a.preventDefault()});this.menu.delegate("li.ui-multiselect-optgroup-label a","click.multiselect",function(a){a.preventDefault();var c=d(this),g=c.parent().nextUntil("li.ui-multiselect-optgroup-label").find("input:visible:not(:disabled)"),e=g.get(),c=c.parent().text();!1!==b._trigger("beforeoptgrouptoggle",a,{inputs:e,label:c})&&(b._toggleChecked(g.filter(":checked").length!==g.length,g),b._trigger("optgrouptoggle",a,{inputs:e,label:c,checked:e[0].checked}))}).delegate("label","mouseenter.multiselect",function(){d(this).hasClass("ui-state-disabled")||(b.labels.removeClass("ui-state-hover"),d(this).addClass("ui-state-hover").find("input").focus())}).delegate("label","keydown.multiselect",function(a){a.preventDefault();switch(a.which){case 9:case 27:b.close();break;case 38:case 40:case 37:case 39:b._traverse(a.which,this);break;case 13:d(this).find("input")[0].click()}}).delegate('input[type="checkbox"], input[type="radio"]',"click.multiselect",function(a){var c=d(this),g=this.value,e=this.checked,i=b.element.find("option");this.disabled||!1===b._trigger("click",a,{value:g,text:this.title,checked:e})?a.preventDefault():(c.focus(),c.attr("aria-selected",e),i.each(function(){this.value===g?this.selected=e:b.options.multiple||(this.selected=!1)}),b.options.multiple||(b.labels.removeClass("ui-state-active"),c.closest("label").toggleClass("ui-state-active",e),b.close()),b.element.trigger("change"),setTimeout(d.proxy(b.update,b),10))});d(document).bind("mousedown.multiselect",function(a){b._isOpen&&(!d.contains(b.menu[0],a.target)&&!d.contains(b.button[0],a.target)&&a.target!==b.button[0])&&b.close()});d(this.element[0].form).bind("reset.multiselect",function(){setTimeout(d.proxy(b.refresh,b),10)})},_setButtonWidth:function(){var a=this.element.outerWidth(),b=this.options;/\d/.test(b.minWidth)&&a<b.minWidth&&(a=b.minWidth);this.button.width(a)},_setMenuWidth:function(){var a=this.menu,b=this.button.outerWidth()-parseInt(a.css("padding-left"),10)-parseInt(a.css("padding-right"),10)-parseInt(a.css("border-right-width"),10)-parseInt(a.css("border-left-width"),10);a.width(b||this.button.outerWidth())},_traverse:function(a,b){var c=d(b),f=38===a||37===a,c=c.parent()[f?"prevAll":"nextAll"]("li:not(.ui-multiselect-disabled, .ui-multiselect-optgroup-label)")[f?"last":"first"]();c.length?c.find("label").trigger("mouseover"):(c=this.menu.find("ul").last(),this.menu.find("label")[f? "last":"first"]().trigger("mouseover"),c.scrollTop(f?c.height():0))},_toggleState:function(a,b){return function(){this.disabled||(this[a]=b);b?this.setAttribute("aria-selected",!0):this.removeAttribute("aria-selected")}},_toggleChecked:function(a,b){var c=b&&b.length?b:this.inputs,f=this;c.each(this._toggleState("checked",a));c.eq(0).focus();this.update();var h=c.map(function(){return this.value}).get();this.element.find("option").each(function(){!this.disabled&&-1<d.inArray(this.value,h)&&f._toggleState("selected",a).call(this)});c.length&&this.element.trigger("change")},_toggleDisabled:function(a){this.button.attr({disabled:a,"aria-disabled":a})[a?"addClass":"removeClass"]("ui-state-disabled");var b=this.menu.find("input"),b=a?b.filter(":enabled").data("ech-multiselect-disabled",!0):b.filter(function(){return!0===d.data(this,"ech-multiselect-disabled")}).removeData("ech-multiselect-disabled");b.attr({disabled:a,"arial-disabled":a}).parent()[a?"addClass":"removeClass"]("ui-state-disabled");this.element.attr({disabled:a,"aria-disabled":a})},open:function(){var a=this.button,b=this.menu,c=this.speed,f=this.options,h=[];if(!(!1===this._trigger("beforeopen")||a.hasClass("ui-state-disabled")||this._isOpen)){var g=b.find("ul").last(),e=f.show,i=a.offset();d.isArray(f.show)&&(e=f.show[0],c=f.show[1]||this.speed);e&&(h=[e,c]);g.scrollTop(0).height(f.height);d.ui.position&&!d.isEmptyObject(f.position)?(f.position.of=f.position.of||a,b.show().position(f.position).hide()):b.css({top:i.top+a.outerHeight(),left:i.left});d.fn.show.apply(b,h);this.labels.eq(0).trigger("mouseover").trigger("mouseenter").find("input").trigger("focus");a.addClass("ui-state-active");this._isOpen=!0;this._trigger("open")}},close:function(){if(!1!==this._trigger("beforeclose")){var a=this.options,b=a.hide,c=this.speed,f=[];d.isArray(a.hide)&&(b=a.hide[0],c=a.hide[1]||this.speed);b&&(f=[b,c]);d.fn.hide.apply(this.menu,f);this.button.removeClass("ui-state-active").trigger("blur").trigger("mouseleave");this._isOpen=!1;this._trigger("close")}},enable:function(){this._toggleDisabled(!1)},disable:function(){this._toggleDisabled(!0)},checkAll:function(){this._toggleChecked(!0);this._trigger("checkAll")},uncheckAll:function(){this._toggleChecked(!1);this._trigger("uncheckAll")},getChecked:function(){return this.menu.find("input").filter(":checked")},destroy:function(){d.Widget.prototype.destroy.call(this);this.button.remove();this.menu.remove();this.element.show();return this},isOpen:function(){return this._isOpen},widget:function(){return this.menu},getButton:function(){return this.button},_setOption:function(a,b){var c=this.menu;switch(a){case "header":c.find("div.ui-multiselect-header")[b?"show":"hide"]();break;case "checkAllText":c.find("a.ui-multiselect-all span").eq(-1).text(b);break;case "uncheckAllText":c.find("a.ui-multiselect-none span").eq(-1).text(b);break;case "height":c.find("ul").last().height(parseInt(b,10));break;case "minWidth":this.options[a]=parseInt(b,10);this._setButtonWidth();this._setMenuWidth();break;case "selectedText":case "selectedList":case "noneSelectedText":this.options[a]=b;this.update();break;case "classes":c.add(this.button).removeClass(this.options.classes).addClass(b);break;case "multiple":c.toggleClass("ui-multiselect-single",!b),this.options.multiple=b,this.element[0].multiple=b,this.refresh()}d.Widget.prototype._setOption.apply(this,arguments)}})})(jQuery);
......@@ -96,6 +96,7 @@ $dispatcher = patterns('',
url_get('^/search$', 'search'),
url_get('^/(?P<id>\d+)$', 'getOrg'),
url_post('^/(?P<id>\d+)$', 'updateOrg'),
url_post('^/(?P<id>\d+)/profile$', 'updateOrg', array(true)),
url_get('^/(?P<id>\d+)/edit$', 'editOrg'),
url_get('^/lookup/form$', 'lookup'),
url_post('^/lookup/form$', 'addOrg'),
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment