Newer
Older
$data = $this->field->getSource();
$config = $this->field->getConfiguration();
if ($datetime = parent::getValue()) {
$datetime = is_int($datetime) ? $datetime :
strtotime($datetime);
if ($datetime && isset($data[$this->name . ':time'])) {
list($hr, $min) = explode(':', $data[$this->name . ':time']);
$datetime += $hr * 3600 + $min * 60;
}
if ($datetime && $config['gmt'])
$datetime -= (int) (3600 * $_SESSION['TZ_OFFSET'] +
($_SESSION['TZ_DST'] ? date('I',$datetime) : 0));
}
class SectionBreakWidget extends Widget {
function render($mode=false) {
?><div class="form-header section-break"><h3><?php
echo Format::htmlchars($this->field->get('label'));
?></h3><em><?php echo Format::htmlchars($this->field->get('hint'));
?></em></div>
<?php
}
}
class ThreadEntryWidget extends Widget {
function render($client=null) {
global $cfg;
$object_id = false;
if (!$client) {
$namespace = 'ticket.staff';
}
else {
$namespace = 'ticket.client';
$object_id = substr(session_id(), -12);
}
list($draft, $attrs) = Draft::getDraftAndDataAttrs($namespace, $object_id, $this->value);
?><div style="margin-bottom:0.5em;margin-top:0.5em"><strong><?php
echo Format::htmlchars($this->field->get('label'));
?></strong>:</div>
<textarea style="width:100%;" name="<?php echo $this->field->get('name'); ?>"
placeholder="<?php echo Format::htmlchars($this->field->get('hint')); ?>"
class="<?php if ($cfg->isHtmlThreadEnabled()) echo 'richtext';
?> draft draft-delete" <?php echo $attrs; ?>
cols="21" rows="8" style="width:80%;"><?php echo
$draft ?: Format::htmlchars($this->value); ?></textarea>
$config = $this->field->getConfiguration();
if (!$config['attachments'])
return;
$attachments = $this->getAttachments($config);
print $attachments->render($client);
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;
class FileUploadWidget extends Widget {
static $media = array(
'css' => array(
'/css/filedrop.css',
),
);
function render($how) {
$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; }
);
foreach ($this->value ?: array() as $fid) {
$found = false;
foreach ($attachments as $f) {
if ($f['id'] == $fid) {
$files[] = $f;
$found = true;
break;
}
}
if (!$found && ($file = AttachmentFile::lookup($fid))) {
$files[] = array(
'id' => $file->getId(),
'name' => $file->getName(),
'type' => $file->getType(),
'size' => $file->getSize(),
);
}
}
?><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 ($config['size'] ?: 1048576) / 1048576; ?>,
name: '<?php echo $name; ?>[]',
files: <?php echo JsonDataEncoder::encode($files); ?>
});});
</script>
<?php
}
function getValue() {
$data = $this->field->getSource();
$ids = array();
// Handle manual uploads (IE<10)
if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_FILES[$this->name])) {
foreach (AttachmentFile::format($_FILES[$this->name]) as $file) {
try {
$ids[] = $this->field->uploadFile($file);
}
catch (FileUploadError $ex) {}
}
return array_merge($ids, parent::getValue() ?: array());
}
// If no value was sent, assume an empty list
elseif ($data && is_array($data) && !isset($data[$this->name]))
return parent::getValue();
}
}
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'),
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
'label'=>__('Content'), 'required'=>true, 'default'=>'',
'hint'=>__('Free text shown in the form, such as a disclaimer'),
)),
);
}
function hasData() {
return false;
}
function isBlockLevel() {
return true;
}
}
class FreeTextWidget extends Widget {
function render($mode=false) {
$config = $this->field->getConfiguration();
?><div class=""><h3><?php
echo Format::htmlchars($this->field->get('label'));
?></h3><em><?php
echo Format::htmlchars($this->field->get('hint'));
?></em><div><?php
echo Format::viewableImages($config['content']); ?></div>
</div>
<?php
}
}
class VisibilityConstraint {
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) {
$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; ?>);
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
<?php } ?>
})();
</script><?php
}
/**
* Determines if the field was visible when the form was submitted
*/
function isVisible($field) {
return $this->compileQPhp($this->constraint, $field);
}
function compileQPhp(Q $Q, $field) {
$form = $field->getForm();
$expr = array();
foreach ($Q->constraints as $c=>$value) {
if ($value instanceof Q) {
$expr[] = $this->compileQPhp($value, $field);
}
else {
@list($f, $op) = explode('__', $c, 2);
$field = $form->getField($f);
$wval = $field->getClean();
switch ($op) {
case 'eq':
case null:
$expr[] = ($wval == $value && $field->isVisible());
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
}
}
}
$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, $op) = explode('__', $c, 2);
$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) = explode('__', $c, 2);
$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))
);
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
}
}
}
$glue = $Q->isOred() ? ' || ' : ' && ';
$expression = implode($glue, $expr);
if (count($expr) > 1)
$expression = '('.$expression.')';
if ($Q->isNegated)
$expression = '!'.$expression;
return $expression;
}
}
class Q {
const NEGATED = 0x0001;
const ANY = 0x0002;
var $constraints;
var $flags;
var $negated = false;
var $ored = false;
function __construct($filter, $flags=0) {
$this->constraints = $filter;
$this->negated = $flags & self::NEGATED;
$this->ored = $flags & self::ANY;
}
function isNegated() {
return $this->negated;
}
function isOred() {
return $this->ored;
}
function negate() {
$this->negated = !$this->negated;
return $this;
}
static function not(array $constraints) {
return new static($constraints, self::NEGATED);
}
static function any(array $constraints) {
return new static($constraints, self::ORED);
}
}