Newer
Older
?><div class="form-header section-break"><h3><?php
echo Format::htmlchars($this->field->getLocal('label'));
?></h3><em><?php echo Format::htmlchars($this->field->getLocal('hint'));
?></em></div>
<?php
}
}
class ThreadEntryWidget extends Widget {
$object_id = false;
if ($options['client']) {
$namespace = $options['draft-namespace']
?: 'ticket.client';
$object_id = substr(session_id(), -12);
} else {
$namespace = $options['draft-namespace'] ?: 'ticket.staff';
list($draft, $attrs) = Draft::getDraftAndDataAttrs($namespace, $object_id, $this->value);
<textarea style="width:100%;" name="<?php echo $this->field->get('name'); ?>"
placeholder="<?php echo Format::htmlchars($this->field->get('placeholder')); ?>"
class="<?php if ($config['html']) echo 'richtext';
?> draft draft-delete" <?php echo $attrs; ?>
cols="21" rows="8" style="width:80%;"><?php echo
Format::htmlchars($this->value) ?: $draft; ?></textarea>
if (!$config['attachments'])
return;
$attachments = $this->getAttachments($config);
print $attachments->render($options);
foreach ($attachments->getMedia() as $type=>$urls) {
foreach ($urls as $url)
Form::emitMedia($url, $type);
function getAttachments($config=false) {
if (!$config)
$config = $this->field->getConfiguration();
$field = new FileUploadField(array(
'id'=>'attach',
'name'=>'attach:' . $this->field->get('id'),
'configuration'=>$config)
);
$field->setForm($this->field->getForm());
return $field;
function parseValue() {
parent::parseValue();
if (isset($this->value)) {
$value = $this->value;
$config = $this->field->getConfiguration();
// Trim spaces based on text input type.
// Preserve original input if not empty.
if ($config['html'])
$this->value = trim($value, " <>br/\t\n\r") ? $value : '';
else
$this->value = trim($value) ? $value : '';
}
}
class FileUploadWidget extends Widget {
static $media = array(
'css' => array(
'/css/filedrop.css',
),
);
$config = $this->field->getConfiguration();
$name = $this->field->getFormName();
$id = substr(md5(spl_object_hash($this)), 10);
$attachments = $this->field->getFiles();
$mimetypes = array_filter($config['__mimetypes'],
function($t) { return strpos($t, '/') !== false; }
);
$maxfilesize = ($config['size'] ?: 1048576) / 1048576;
$files = $F = array();
$new = array_fill_keys($this->field->getClean(), 1);
foreach ($attachments as $a) {
$F[] = $a->file;
unset($new[$a->file_id]);
}
// Add in newly added files not yet saved (if redisplaying after an
// error)
if ($new) {
$F = array_merge($F, AttachmentFile::objects()
->filter(array('id__in' => array_keys($new)))
foreach ($F as $file) {
$files[] = array(
'id' => $file->getId(),
'name' => $file->getName(),
'type' => $file->getType(),
'size' => $file->getSize(),
'download_url' => $file->getDownloadUrl(),
);
?><div id="<?php echo $id;
?>" class="filedrop"><div class="files"></div>
<div class="dropzone"><i class="icon-upload"></i>
<?php echo sprintf(
__('Drop files here or %s choose them %s'),
'<a href="#" class="manual">', '</a>'); ?>
<input type="file" multiple="multiple"
id="file-<?php echo $id; ?>" style="display:none;"
accept="<?php echo implode(',', $config['__mimetypes']); ?>"/>
$(function(){$('#<?php echo $id; ?> .dropzone').filedropbox({
url: 'ajax.php/form/upload/<?php echo $this->field->get('id') ?>',
link: $('#<?php echo $id; ?>').find('a.manual'),
fallback_id: 'file-<?php echo $id; ?>',
allowedfileextensions: <?php echo JsonDataEncoder::encode(
$config['__extensions'] ?: array()); ?>,
allowedfiletypes: <?php echo JsonDataEncoder::encode(
maxfiles: <?php echo $config['max'] ?: 20; ?>,
maxfilesize: <?php echo $maxfilesize; ?>,
name: '<?php echo $name; ?>[]',
files: <?php echo JsonDataEncoder::encode($files); ?>
});});
</script>
<?php
}
function getValue() {
$ids = array();
// Handle manual uploads (IE<10)
if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_FILES[$this->name])) {
foreach (AttachmentFile::format($_FILES[$this->name]) as $file) {
$F = $this->field->uploadFile($file);
$ids[] = $F->getId();
// Files uploaded here MUST have been uploaded by this user and
// identified in the session
//
// If no value was sent, assume an empty list
if (!($files = parent::getValue()))
$allowed = array();
// Files already attached to the field are allowed
foreach ($this->field->getFiles() as $F) {
// FIXME: This will need special porting in v1.10
$allowed[$F->id] = 1;
// New files uploaded in this session are allowed
if (isset($_SESSION[':uploadedFiles']))
$allowed += $_SESSION[':uploadedFiles'];
// Canned attachments initiated by this session
if (isset($_SESSION[':cannedFiles']))
$allowed += $_SESSION[':cannedFiles'];
// Parse the files and make sure it's allowed.
foreach ($files as $info) {
@list($id, $name) = explode(',', $info, 2);
if (!isset($allowed[$id]))
continue;
// Keep the values as the IDs
if ($name)
$ids[$name] = $id;
else
$ids[] = $id;
}
class FileUploadError extends Exception {}
class FreeTextField extends FormField {
static $widget = 'FreeTextWidget';
function getConfigurationOptions() {
return array(
'content' => new TextareaField(array(
'configuration' => array('html' => true, 'size'=>'large'),
'label'=>__('Content'), 'required'=>true, 'default'=>'',
'hint'=>__('Free text shown in the form, such as a disclaimer'),
)),
'attachments' => new FileUploadField(array(
'id'=>'attach',
'name'=>'files',
'configuration' => array('extensions'=>'')
)),
);
}
function hasData() {
return false;
}
function isBlockLevel() {
return true;
}
/* utils */
function to_config($config) {
if ($config && isset($config['attachments']))
$keepers = $config['attachments'] = array_values($config['attachments']);
$this->getAttachments()->keepOnlyFileIds($keepers);
return $config;
}
function db_cleanup($field=false) {
$this->getAttachments()->deleteAll();
}
function getAttachments() {
if (!isset($this->attachments))
$this->attachments = GenericAttachments::forIdAndType($this->get('id'), 'I');
return $this->attachments;
}
function getFiles() {
if (!($attachments = $this->getAttachments()))
return array();
return $attachments->all();
}
}
class FreeTextWidget extends Widget {
$class = $config['classes'] ?: 'thread-body bleed';
?><div class="<?php echo $class; ?>"><?php
if ($label = $this->field->getLocal('label')) { ?>
<h3><?php
echo Format::htmlchars($label);
?></h3><?php
}
if ($hint = $this->field->getLocal('hint')) { ?>
<em><?php
echo Format::htmlchars($hint);
?></em><?php
} ?>
<div><?php
echo Format::viewableImages($config['content']); ?></div>
</div>
<?php
if (($attachments = $this->field->getFiles()) && count($attachments)) { ?>
<section class="freetext-files">
<div class="title"><?php echo __('Related Resources'); ?></div>
<?php foreach ($attachments as $attach) { ?>
<a href="<?php echo $attach->file->getDownloadUrl(); ?>"
target="_blank" download="<?php echo $attach->file->getDownloadUrl();
?>" class="truncate no-pjax">
<?php echo Format::htmlchars($attach->getFilename()); ?>
</a>
</div>
<?php } ?>
</section>
<?php }
class ColorPickerWidget extends Widget {
static $media = array(
'css' => array(
'css/spectrum.css',
),
'js' => array(
'js/spectrum.js',
),
);
function render($options=array()) {
?><input type="color"
id="<?php echo $this->id; ?>"
name="<?php echo $this->name; ?>"
value="<?php echo Format::htmlchars($this->value); ?>"/><?php
}
}
static $operators = array(
'eq' => 1,
);
const HIDDEN = 0x0001;
const VISIBLE = 0x0002;
var $initial;
var $constraint;
function __construct($constraint, $initial=self::VISIBLE) {
$this->constraint = $constraint;
$this->initial = $initial;
}
function emitJavascript($field) {
if (!$this->constraint->constraints)
return;
$func = 'recheck';
$form = $field->getForm();
?>
<script type="text/javascript">
!(function() {
var <?php echo $func; ?> = function() {
var target = $('#field<?php echo $field->getWidget()->id; ?>');
<?php $fields = $this->getAllFields($this->constraint);
foreach ($fields as $f) {
$field = $form->getField($f);
echo sprintf('var %1$s = $("#%1$s");',
}
$expression = $this->compileQ($this->constraint, $form);
?>
if (<?php echo $expression; ?>)
$(this).trigger('show');
});
else
target.slideUp('fast', function (){
$(this).trigger('hide');
});
};
<?php foreach ($fields as $f) {
$w = $form->getField($f)->getWidget();
?>
$('#<?php echo $w->id; ?>').on('change', <?php echo $func; ?>);
$('#field<?php echo $w->id; ?>').on('show hide', <?php
echo $func; ?>);
<?php } ?>
})();
</script><?php
}
/**
* Determines if the field was visible when the form was submitted
*/
function isVisible($field) {
// Assume initial visibility if constraint is not provided.
if (!$this->constraint->constraints)
return $this->initial == self::VISIBLE;
return $this->compileQPhp($this->constraint, $field);
}
static function splitFieldAndOp($field) {
if (false !== ($last = strrpos($field, '__'))) {
$op = substr($field, $last + 2);
if (isset(static::$operators[$op]))
$field = substr($field, 0, strrpos($field, '__'));
}
return array($field, $op);
}
function compileQPhp(Q $Q, $field) {
if (!($form = $field->getForm())) {
return $this->initial == self::VISIBLE;
}
$expr = array();
foreach ($Q->constraints as $c=>$value) {
if ($value instanceof Q) {
$expr[] = $this->compileQPhp($value, $field);
}
else {
@list($f, $op) = self::splitFieldAndOp($c);
$wval = $field ? $field->getClean() : null;
switch ($op) {
case 'eq':
case null:
$expr[] = ($wval == $value && $field->isVisible());
}
}
}
$glue = $Q->isOred()
? function($a, $b) { return $a || $b; }
: function($a, $b) { return $a && $b; };
$initial = !$Q->isOred();
$expression = array_reduce($expr, $glue, $initial);
if ($Q->isNegated)
$expression = !$expression;
return $expression;
}
function getAllFields(Q $Q, &$fields=array()) {
foreach ($Q->constraints as $c=>$value) {
if ($c instanceof Q) {
$this->getAllFields($c, $fields);
}
else {
@list($f) = self::splitFieldAndOp($c);
$fields[$f] = true;
}
}
return array_keys($fields);
}
function compileQ($Q, $form) {
$expr = array();
foreach ($Q->constraints as $c=>$value) {
if ($value instanceof Q) {
$expr[] = $this->compileQ($value, $form);
}
else {
list($f, $op) = self::splitFieldAndOp($c);
$widget = $form->getField($f)->getWidget();
$id = $widget->id;
$expr[] = sprintf('(%s.is(":visible") && %s)',
$id,
sprintf('%s == %s',
sprintf($widget->getJsValueGetter(), $id),
JsonDataEncoder::encode($value))
);
}
}
}
$glue = $Q->isOred() ? ' || ' : ' && ';
$expression = implode($glue, $expr);
if (count($expr) > 1)
$expression = '('.$expression.')';
if ($Q->isNegated)
$expression = '!'.$expression;
return $expression;
}
}
class AssignmentForm extends Form {
static $id = 'assign';
var $_assignee = null;
function getFields() {
if ($this->fields)
return $this->fields;
$fields = array(
'assignee' => new AssigneeField(array(
'id'=>1,
'label' => __('Assignee'),
'flags' => hexdec(0X450F3),
'required' => true,
'validator-error' => __('Assignee selection required'),
'configuration' => array(
'criteria' => array(
'available' => true,
),
),
)
),
'comments' => new TextareaField(array(
'id' => 2,
'label'=> '',
'required'=>false,
'default'=>'',
'configuration' => array(
'html' => true,
'placeholder' => __('Optional reason for the assignment'),
),
)
),
);
$fields['assignee']->setChoices($this->_assignees);
$this->setFields($fields);
return $this->fields;
}
function getField($name) {
if (($fields = $this->getFields())
&& isset($fields[$name]))
return $fields[$name];
}
function isValid($include=false) {
if (!parent::isValid($include) || !($f=$this->getField('assignee')))
return false;
// Do additional assignment validation
if (!($assignee = $this->getAssignee())) {
$f->addError(__('Unknown assignee'));
} elseif ($assignee instanceof Staff) {
// Make sure the agent is available
if (!$assignee->isAvailable())
$f->addError(__('Agent is unavailable for assignment'));
} elseif ($assignee instanceof Team) {
// Make sure the team is active and has members
if (!$assignee->isActive())
$f->addError(__('Team is disabled'));
elseif (!$assignee->getNumMembers())
$f->addError(__('Team does not have members'));
}
return !$this->errors();
}
function render($options) {
switch(strtolower($options['template'])) {
case 'simple':
$inc = STAFFINC_DIR . 'templates/dynamic-form-simple.tmpl.php';
break;
default:
throw new Exception(sprintf(__('%s: Unknown template style %s'),
'FormUtils', $options['template']));
}
$form = $this;
include $inc;
}
function setAssignees($assignees) {
$this->_assignees = $assignees;
$this->_fields = array();
}
function getAssignees() {
return $this->_assignees;
}
if (!isset($this->_assignee))
$this->_assignee = $this->getField('assignee')->getClean();
function getComments() {
return $this->getField('comments')->getClean();
}
}
class ClaimForm extends AssignmentForm {
var $_fields;
function setFields($fields) {
$this->_fields = $fields;
parent::setFields($fields);
}
function getFields() {
if ($this->_fields)
return $this->_fields;
// Disable && hide assignee field selection
if (isset($fields['assignee'])) {
$visibility = new VisibilityConstraint(
new Q(array()), VisibilityConstraint::HIDDEN);
$fields['assignee']->set('visibility', $visibility);
}
// Change coments placeholder to reflect claim
if (isset($fields['comments'])) {
$fields['comments']->configure('placeholder',
__('Optional reason for the claim'));
}
$this->setFields($fields);
return $this->fields;
4623
4624
4625
4626
4627
4628
4629
4630
4631
4632
4633
4634
4635
4636
4637
4638
4639
4640
4641
4642
4643
4644
4645
4646
4647
4648
4649
4650
4651
4652
4653
4654
4655
4656
4657
4658
4659
4660
4661
4662
4663
4664
4665
4666
4667
4668
4669
4670
4671
4672
4673
4674
4675
4676
4677
4678
4679
4680
4681
4682
4683
4684
4685
4686
4687
4688
4689
4690
4691
4692
4693
4694
4695
4696
4697
4698
4699
4700
4701
4702
4703
4704
4705
4706
4707
4708
4709
4710
4711
4712
4713
4714
4715
4716
4717
4718
4719
4720
4721
4722
4723
4724
4725
4726
4727
4728
4729
4730
4731
4732
4733
4734
4735
4736
4737
4738
4739
4740
4741
4742
4743
4744
class ReferralForm extends Form {
static $id = 'refer';
var $_target = null;
var $_choices = null;
var $_prompt = '';
function getFields() {
if ($this->fields)
return $this->fields;
$fields = array(
'target' => new AssigneeField(array(
'id'=>1,
'label' => __('Referee'),
'flags' => hexdec(0X450F3),
'required' => true,
'validator-error' => __('Selection required'),
'configuration' => array(
'criteria' => array(
'available' => true,
),
'prompt' => $this->_prompt,
),
)
),
'comments' => new TextareaField(array(
'id' => 2,
'label'=> '',
'required'=>false,
'default'=>'',
'configuration' => array(
'html' => true,
'size' => 'small',
'placeholder' => __('Optional reason for the referral'),
),
)
),
);
if (isset($this->_choices))
$fields['target']->setChoices($this->_choices);
$this->setFields($fields);
return $this->fields;
}
function getField($name) {
if (($fields = $this->getFields())
&& isset($fields[$name]))
return $fields[$name];
}
function isValid($include=false) {
if (!parent::isValid($include) || !($f=$this->getField('target')))
return false;
// Do additional assignment validation
$choice = $this->getTarget();
switch (true) {
case $choice instanceof Staff:
// Make sure the agent is available
if (!$choice->isAvailable())
$f->addError(__('Agent is unavailable for assignment'));
break;
case $choice instanceof Team:
// Make sure the team is active and has members
if (!$choice->isActive())
$f->addError(__('Team is disabled'));
elseif (!$choice->getNumMembers())
$f->addError(__('Team does not have members'));
break;
case $choice instanceof Dept:
break;
default:
$f->addError(__('Unknown selection'));
}
return !$this->errors();
}
function render($options) {
switch(strtolower($options['template'])) {
case 'simple':
$inc = STAFFINC_DIR . 'templates/dynamic-form-simple.tmpl.php';
break;
default:
throw new Exception(sprintf(__('%s: Unknown template style %s'),
'FormUtils', $options['template']));
}
$form = $this;
include $inc;
}
function setChoices($choices, $prompt='') {
$this->_choices = $choices;
$this->_prompt = $prompt;
$this->_fields = array();
}
function getTarget() {
if (!isset($this->_target))
$this->_target = $this->getField('target')->getClean();
return $this->_target;
}
function getComments() {
return $this->getField('comments')->getClean();
}
}
class TransferForm extends Form {
static $id = 'transfer';
var $_dept = null;
function __construct($source=null, $options=array()) {
parent::__construct($source, $options);
function getFields() {
if ($this->fields)
return $this->fields;
$fields = array(
'dept' => new DepartmentField(array(
'id'=>1,
'label' => __('Department'),
'flags' => hexdec(0X450F3),
'required' => true,
'validator-error' => __('Department selection is required'),
)
),
'comments' => new TextareaField(array(
'id' => 2,
'label'=> '',
'required'=>false,
'default'=>'',
'configuration' => array(
'html' => true,
'placeholder' => __('Optional reason for the transfer'),
),
)
),
);
$this->setFields($fields);
return $this->fields;
function isValid($include=false) {
if (!parent::isValid($include))
return false;
// Do additional validations
if (!($dept = $this->getDept()))
$this->getField('dept')->addError(
__('Unknown department'));
return !$this->errors();
function render($options) {
switch(strtolower($options['template'])) {
case 'simple':
$inc = STAFFINC_DIR . 'templates/dynamic-form-simple.tmpl.php';
break;
default:
throw new Exception(sprintf(__('%s: Unknown template style %s'),
get_class(), $options['template']));
}
$form = $this;
include $inc;
function getDept() {
if (!isset($this->_dept)) {
if (($id = $this->getField('dept')->getClean()))
$this->_dept = Dept::lookup($id);
}
return $this->_dept;
/**
* FieldUnchanged
*
* Thrown in the to_database() method to indicate the value should not be
* saved in the database (it wasn't changed in the request)
*/
class FieldUnchanged extends Exception {}