Skip to content
Snippets Groups Projects
class.forms.php 174 KiB
Newer Older
  • Learn to ignore specific revisions
  •             $class = sprintf('class="%s"', implode(' ', $class));
    
                $this->value = Format::viewableImages($this->value);
            }
    
            if (isset($config['context']))
                $attrs['data-root-context'] = '"'.$config['context'].'"';
    
            <span style="display:inline-block;width:100%">
    
            <textarea <?php echo $rows." ".$cols." ".$maxlength." ".$class
    
                    .' '.Format::array_implode('=', ' ', $attrs)
    
                    .' placeholder="'.$config['placeholder'].'"'; ?>
    
                id="<?php echo $this->id; ?>"
    
    Jared Hancock's avatar
    Jared Hancock committed
                name="<?php echo $this->name; ?>"><?php
                    echo Format::htmlchars($this->value);
                ?></textarea>
            </span>
            <?php
        }
    
    Peter Rotich's avatar
    Peter Rotich committed
    
        function parseValue() {
            parent::parseValue();
            if (isset($this->value)) {
                $value = $this->value;
                $config = $this->field->getConfiguration();
                // Trim empty 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 : '';
            }
        }
    
    
    Jared Hancock's avatar
    Jared Hancock committed
    }
    
    class PhoneNumberWidget extends Widget {
    
        function render($options=array()) {
    
            $config = $this->field->getConfiguration();
    
    Jared Hancock's avatar
    Jared Hancock committed
            list($phone, $ext) = explode("X", $this->value);
            ?>
    
            <input id="<?php echo $this->id; ?>" type="tel" name="<?php echo $this->name; ?>" value="<?php
    
            echo Format::htmlchars($phone); ?>"/><?php
    
            // Allow display of extension field even if disabled if the phone
            // number being edited has an extension
    
            if ($ext || $config['ext']) { ?> <?php echo __('Ext'); ?>:
    
                <input type="text" name="<?php
    
                echo $this->name; ?>-ext" value="<?php echo Format::htmlchars($ext);
                    ?>" size="5"/>
    
    Jared Hancock's avatar
    Jared Hancock committed
        }
    
        function getValue() {
    
            $data = $this->field->getSource();
            $base = parent::getValue();
            if ($base === null)
                return $base;
            $ext = $data["{$this->name}-ext"];
    
            // NOTE: 'X' is significant. Don't change it
    
    Jared Hancock's avatar
    Jared Hancock committed
            if ($ext) $ext = 'X'.$ext;
    
            return $base . $ext;
    
    Jared Hancock's avatar
    Jared Hancock committed
        }
    }
    
    class ChoicesWidget extends Widget {
    
        function render($options=array()) {
    
    Peter Rotich's avatar
    Peter Rotich committed
            $mode = null;
            if (isset($options['mode']))
                $mode = $options['mode'];
            elseif (isset($this->field->options['render_mode']))
                $mode = $this->field->options['render_mode'];
    
                if (!($val = (string) $this->field))
    
                    $val = sprintf('<span class="faded">%s</span>', __('None'));
    
    Jared Hancock's avatar
    Jared Hancock committed
            $config = $this->field->getConfiguration();
    
            if ($mode == 'search') {
                $config['multiselect'] = true;
            }
    
    
    Jared Hancock's avatar
    Jared Hancock committed
            // Determine the value for the default (the one listed if nothing is
            // selected)
    
    Peter Rotich's avatar
    Peter Rotich committed
            $choices = $this->field->getChoices(true);
    
            $prompt = ($config['prompt'])
                ? $this->field->getLocal('prompt', $config['prompt'])
                : __('Select'
                /* Used as a default prompt for a custom drop-down list */);
    
            $have_def = false;
    
            // We don't consider the 'default' when rendering in 'search' mode
            if (!strcasecmp($mode, 'search')) {
                $def_val = $prompt;
            } else {
    
                $def_key = $this->field->get('default');
                if (!$def_key && $config['default'])
                    $def_key = $config['default'];
    
                if (is_array($def_key))
                    $def_key = key($def_key);
    
                $have_def = isset($choices[$def_key]);
    
                $def_val = $have_def ? $choices[$def_key] : $prompt;
    
            $values = $this->value;
    
            if (!is_array($values) && isset($values)) {
    
                $values = array($values => $this->field->getChoice($values));
            }
    
            if (!is_array($values))
    
    Peter Rotich's avatar
    Peter Rotich committed
                $values = $have_def ? array($def_key => $choices[$def_key]) : array();
    
    
            if (isset($config['classes']))
                $classes = 'class="'.$config['classes'].'"';
    
            ?>
            <select name="<?php echo $this->name; ?>[]"
    
                <?php echo implode(' ', array_filter(array($classes))); ?>
    
                id="<?php echo $this->id; ?>"
    
                <?php if (isset($config['data']))
                  foreach ($config['data'] as $D=>$V)
                    echo ' data-'.$D.'="'.Format::htmlchars($V).'"';
                ?>
    
                data-placeholder="<?php echo $prompt; ?>"
    
                <?php if ($config['multiselect'])
    
    Jared Hancock's avatar
    Jared Hancock committed
                    echo ' multiple="multiple"'; ?>>
    
                <?php if (!$have_def && !$config['multiselect']) { ?>
    
    Jared Hancock's avatar
    Jared Hancock committed
                <option value="<?php echo $def_key; ?>">&mdash; <?php
                    echo $def_val; ?> &mdash;</option>
    
            $this->emitChoices($choices, $values, $have_def, $def_key); ?>
    
    Jared Hancock's avatar
    Jared Hancock committed
            </select>
            <?php
    
            if ($config['multiselect']) {
             ?>
            <script type="text/javascript">
            $(function() {
    
                $("#<?php echo $this->id; ?>")
    
    Jared Hancock's avatar
    Jared Hancock committed
                .select2({'minimumResultsForSearch':10, 'width': '350px'});
    
        function emitChoices($choices, $values=array(), $have_def=false, $def_key=null) {
    
            reset($choices);
            if (is_array(current($choices)) || current($choices) instanceof Traversable)
    
                return $this->emitComplexChoices($choices, $values, $have_def, $def_key);
    
    
            foreach ($choices as $key => $name) {
                if (!$have_def && $key == $def_key)
                    continue; ?>
                <option value="<?php echo $key; ?>" <?php
                    if (isset($values[$key])) echo 'selected="selected"';
    
                ?>><?php echo Format::htmlchars($name); ?></option>
    
        function emitComplexChoices($choices, $values=array(), $have_def=false, $def_key=null) {
    
            foreach ($choices as $label => $group) {
                if (!count($group)) continue;
                ?>
    
                <optgroup label="<?php echo $label; ?>"><?php
                foreach ($group as $key => $name) {
                    if (!$have_def && $key == $def_key)
                        continue; ?>
                <option value="<?php echo $key; ?>" <?php
                    if (isset($values[$key])) echo 'selected="selected"';
    
                ?>><?php echo Format::htmlchars($name); ?></option>
    
            if (!($value = parent::getValue()))
                return null;
    
            if ($value && !is_array($value))
                $value = array($value);
    
    
            // Assume multiselect
            $values = array();
            $choices = $this->field->getChoices();
    
    
            if ($choices && is_array($value)) {
                // Complex choices
                if (is_array(current($choices))
                        || current($choices) instanceof Traversable) {
                    foreach ($choices as $label => $group) {
                         foreach ($group as $k => $v)
                            if (in_array($k, $value))
                                $values[$k] = $v;
                    }
                } else {
                    foreach($value as $k => $v) {
                        if (isset($choices[$v]))
                            $values[$v] = $choices[$v];
                        elseif (($i=$this->field->lookupChoice($v)))
                            $values += $i;
    
    
        function getJsValueGetter() {
            return '%s.find(":selected").val()';
        }
    
    /**
     * A widget for the ChoiceField which will render a list of radio boxes or
     * checkboxes depending on the value of $config['multiple']. Complex choices
     * are also supported and will be rendered as divs.
     */
    class BoxChoicesWidget extends Widget {
        function render($options=array()) {
            $this->emitChoices($this->field->getChoices());
        }
    
        function emitChoices($choices) {
    
          static $uid = 1;
    
    
          if (!isset($this->value))
              $this->value = $this->field->get('default');
          $config = $this->field->getConfiguration();
          $type = $config['multiple'] ? 'checkbox' : 'radio';
    
    
          $classes = array('checkbox');
    
          if (isset($config['classes']))
    
              $classes = array_merge($classes, (array) $config['classes']);
    
    
          foreach ($choices as $k => $v) {
              if (is_array($v)) {
                  $this->renderSectionBreak($k);
                  $this->emitChoices($v);
                  continue;
              }
    
              $id = sprintf("%s-%s", $this->id, $uid++);
    
            <label class="<?php echo implode(' ', $classes); ?>"
                for="<?php echo $id; ?>">
            <input id="<?php echo $id; ?>" type="<?php echo $type; ?>"
                name="<?php echo $this->name; ?>[]" <?php
    
                if ($this->value[$k]) echo 'checked="checked"'; ?> value="<?php
                echo Format::htmlchars($k); ?>"/>
            <?php
    
            if ($v) {
                echo Format::viewableImages($v);
            } ?>
    
            </label>
    <?php   }
        }
    
        function renderSectionBreak($label) { ?>
            <div><?php echo Format::htmlchars($label); ?></div>
    <?php
        }
    
        function getValue() {
            $data = $this->field->getSource();
            if (count($data)) {
                if (!isset($data[$this->name]))
                    return array();
                return $this->collectValues($data[$this->name], $this->field->getChoices());
            }
            return parent::getValue();
        }
    
        function collectValues($data, $choices) {
            $value = array();
            foreach ($choices as $k => $v) {
                if (is_array($v))
                    $value = array_merge($value, $this->collectValues($data, $v));
                elseif (@in_array($k, $data))
                    $value[$k] = $v;
            }
            return $value;
        }
    }
    
    /**
     * An extension to the BoxChoicesWidget which will render complex choices in
     * tabs.
     */
    class TabbedBoxChoicesWidget extends BoxChoicesWidget {
        function render($options=array()) {
            $tabs = array();
            foreach ($this->field->getChoices() as $label=>$group) {
                if (is_array($group)) {
                    $tabs[$label] = $group;
                }
                else {
                    $this->emitChoices(array($label=>$group));
                }
            }
            if ($tabs) {
                ?>
                <div>
                <ul class="alt tabs">
    <?php       $i = 0;
                foreach ($tabs as $label => $group) {
                    $active = $i++ == 0; ?>
                    <li <?php if ($active) echo 'class="active"';
                      ?>><a href="#<?php echo sprintf('%s-%s', $this->name, Format::slugify($label));
                      ?>"><?php echo Format::htmlchars($label); ?></a></li>
    <?php       } ?>
                </ul>
    <?php       $i = 0;
                foreach ($tabs as $label => $group) {
                    $first = $i++ == 0; ?>
                    <div class="tab_content <?php if (!$first) echo 'hidden'; ?>" id="<?php
                      echo sprintf('%s-%s', $this->name, Format::slugify($label));?>">
    <?php           $this->emitChoices($group); ?>
                    </div>
    <?php       } ?>
                </div>
    <?php   }
        }
    }
    
    
    Peter Rotich's avatar
    Peter Rotich committed
    /**
    * TimezoneWidget extends ChoicesWidget to add auto-detect and select2 search
    * options
    *
    **/
    class TimezoneWidget extends ChoicesWidget {
    
        function render($options=array()) {
            parent::render($options);
            $config = $this->field->getConfiguration();
            if (@$config['autodetect']) {
            ?>
            <button type="button" class="action-button" onclick="javascript:
                $('head').append($('<script>').attr('src', '<?php
                echo ROOT_PATH; ?>js/jstz.min.js'));
                var recheck = setInterval(function() {
                    if (window.jstz !== undefined) {
                        clearInterval(recheck);
                        var zone = jstz.determine();
                        $('#<?php echo $this->id; ?>').val(zone.name()).trigger('change');
    
                    }
                }, 100);
                return false;"
                style="vertical-align:middle">
                <i class="icon-map-marker"></i> <?php echo __('Auto Detect'); ?>
            </button>
            <?php
            } ?>
            <script type="text/javascript">
                $(function() {
                    $('#<?php echo $this->id; ?>').select2({
                        allowClear: true,
                        width: '300px'
                    });
                });
            </script>
          <?php
        }
    }
    
    
    Jared Hancock's avatar
    Jared Hancock committed
    class CheckboxWidget extends Widget {
        function __construct($field) {
            parent::__construct($field);
            $this->name = '_field-checkboxes';
        }
    
    
        function render($options=array()) {
    
    Jared Hancock's avatar
    Jared Hancock committed
            $config = $this->field->getConfiguration();
    
            if (!isset($this->value))
                $this->value = $this->field->get('default');
    
            $classes = array('checkbox');
    
            if (isset($config['classes']))
    
                $classes = array_merge($classes, (array) $config['classes']);
    
            <label class="<?php echo implode(' ', $classes); ?>">
    
            <input id="<?php echo $this->id; ?>"
    
                type="checkbox" name="<?php echo $this->name; ?>[]" <?php
    
    Jared Hancock's avatar
    Jared Hancock committed
                if ($this->value) echo 'checked="checked"'; ?> value="<?php
                echo $this->field->get('id'); ?>"/>
            <?php
    
            if ($config['desc']) {
                echo Format::viewableImages($config['desc']);
    
            </label>
    
    <?php
    
    Jared Hancock's avatar
    Jared Hancock committed
        }
    
        function getValue() {
    
            $data = $this->field->getSource();
    
            if (count($data)) {
                if (!isset($data[$this->name]))
    
                return @in_array($this->field->get('id'), $data[$this->name]);
    
    Jared Hancock's avatar
    Jared Hancock committed
            return parent::getValue();
        }
    
    
        function getJsValueGetter() {
    
            return '%s.is(":checked")';
    
    Jared Hancock's avatar
    Jared Hancock committed
    }
    
    class DatetimePickerWidget extends Widget {
    
        function render($options=array()) {
    
    Jared Hancock's avatar
    Jared Hancock committed
            $config = $this->field->getConfiguration();
    
            $timezone = $this->field->getTimezone();
    
    Peter Rotich's avatar
    Peter Rotich committed
            $dateFormat = $cfg->getDateFormat(true);
            $timeFormat = $cfg->getTimeFormat(true);
    
    Peter Rotich's avatar
    Peter Rotich committed
            if (!isset($this->value) && ($default=$this->field->get('default')))
                $this->value = $default;
    
    
    Jared Hancock's avatar
    Jared Hancock committed
            if ($this->value) {
    
    Peter Rotich's avatar
    Peter Rotich committed
    
                if (is_int($this->value))
                    // Assuming UTC timezone.
                    $datetime = DateTime::createFromFormat('U', $this->value);
    
    Peter Rotich's avatar
    Peter Rotich committed
                    $datetime = Format::parseDateTime($this->value);
    
    
    
                if ($config['time'])
    
    Peter Rotich's avatar
    Peter Rotich committed
                    // Convert to user's timezone for update.
                    $datetime->setTimezone($timezone);
    
    
    Peter Rotich's avatar
    Peter Rotich committed
                // Get formatted date
    
    Peter Rotich's avatar
    Peter Rotich committed
                $this->value = Format::date($datetime->getTimestamp(), false,
    
                            false, $timezone ? $timezone->getName() : 'UTC');
    
    Peter Rotich's avatar
    Peter Rotich committed
                // Get formatted time
    
                if ($config['time']) {
    
    Peter Rotich's avatar
    Peter Rotich committed
                     $this->value .=' '.Format::time($datetime->getTimestamp(),
                             false, $timeFormat, $timezone ?
                             $timezone->getName() : 'UTC');
    
    Peter Rotich's avatar
    Peter Rotich committed
            } else {
    
    Peter Rotich's avatar
    Peter Rotich committed
                // For timezone display purposes
    
    Peter Rotich's avatar
    Peter Rotich committed
                $datetime = new DateTime('now');
                $datetime->setTimezone($timezone);
    
    Jared Hancock's avatar
    Jared Hancock committed
            }
            ?>
            <input type="text" name="<?php echo $this->name; ?>"
    
    Peter Rotich's avatar
    Peter Rotich committed
                id="<?php echo $this->id; ?>" style="display:inline-block;width:auto"
    
    Peter Rotich's avatar
    Peter Rotich committed
                value="<?php echo $this->value; ?>"
    
                size="<?php $config['time'] ? 20 : 12; ?>"
    
                autocomplete="off" class="dp" />
    
            <?php
            // Timezone hint
            echo sprintf('&nbsp;<span class="faded">(<a href="#"
                        data-placement="top" data-toggle="tooltip"
                        title="%s">%s</a>)</span>',
                    $datetime->getTimezone()->getName(),
                    $datetime->format('T'));
            ?>
    
    Jared Hancock's avatar
    Jared Hancock committed
            <script type="text/javascript">
                $(function() {
    
                    $('input[name="<?php echo $this->name; ?>"]').<?php echo
                    $config['time'] ? 'datetimepicker':'datepicker';?>({
    
    Jared Hancock's avatar
    Jared Hancock committed
                        <?php
    
    Peter Rotich's avatar
    Peter Rotich committed
                        if ($dt=$this->field->getMinDateTime())
                            echo sprintf("minDate: new Date(%s),\n", $dt->format('U')*1000);
                        if ($dt=$this->field->getMaxDateTime())
                            echo sprintf("maxDate: new Date(%s),\n", $dt->format('U')*1000);
    
    Jared Hancock's avatar
    Jared Hancock committed
                        elseif (!$config['future'])
    
    Peter Rotich's avatar
    Peter Rotich committed
                            echo "maxDate: new Date().getTime(),\n";
    
    
                        // Set time options
                        if ($config['time']) {
                            // Set Timezone
                            echo sprintf("timezone: %s,\n",
                                    ($datetime->getOffset()/60));
                            echo sprintf("
                                    controlType: 'select',\n
                                    timeInput: true,\n
                                    timeFormat: \"%s\",\n",
    
    Peter Rotich's avatar
    Peter Rotich committed
                                    Format::dtfmt_php2js($timeFormat));
    
    Jared Hancock's avatar
    Jared Hancock committed
                        ?>
                        numberOfMonths: 2,
                        showButtonPanel: true,
                        buttonImage: './images/cal.png',
    
    Peter Rotich's avatar
    Peter Rotich committed
                        dateFormat: '<?php echo
                            Format::dtfmt_php2js($dateFormat); ?>'
    
    Jared Hancock's avatar
    Jared Hancock committed
                    });
                });
            </script>
            <?php
        }
    
        /**
         * Function: getValue
         * Combines the datepicker date value and the time dropdown selected
    
    Peter Rotich's avatar
    Peter Rotich committed
         * time value into a single date and time string value in DateTime::W3C
    
    Jared Hancock's avatar
    Jared Hancock committed
         */
        function getValue() {
    
    Peter Rotich's avatar
    Peter Rotich committed
            if ($value = parent::getValue()) {
                // See if we have time
                $data = $this->field->getSource();
    
                // Parse value into datetime object
    
    Peter Rotich's avatar
    Peter Rotich committed
                $dt = Format::parseDateTime($value);
    
                // Effective timezone for the selection
                if (($timezone = $this->field->getTimezone()))
                    $dt->setTimezone($timezone);
                // Format date time to universal format
    
    Peter Rotich's avatar
    Peter Rotich committed
                $value = $dt->format('Y-m-d H:i:s T');
    
    Peter Rotich's avatar
    Peter Rotich committed
    
            return $value;
    
    class SectionBreakWidget extends Widget {
    
        function render($options=array()) {
    
            ?><div class="form-header section-break"><h3><?php
    
            echo Format::htmlchars($this->field->getLocal('label'));
    
    JediKev's avatar
    JediKev committed
            ?></h3><em><?php echo Format::display($this->field->getLocal('hint'));
    
            ?></em></div>
            <?php
        }
    }
    
    class ThreadEntryWidget extends Widget {
    
        function render($options=array()) {
    
    Peter Rotich's avatar
    Peter Rotich committed
            $config = $this->field->getConfiguration();
    
            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'); ?>"
    
    Peter Rotich's avatar
    Peter Rotich committed
                placeholder="<?php echo Format::htmlchars($this->field->get('placeholder')); ?>"
    
    Peter Rotich's avatar
    Peter Rotich committed
                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(
    
                'name'=>'attach:' . $this->field->get('id'),
    
            $field->setForm($this->field->getForm());
            return $field;
    
    Peter Rotich's avatar
    Peter Rotich committed
    
        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',
            ),
        );
    
    
        function render($options=array()) {
    
            $config = $this->field->getConfiguration();
            $name = $this->field->getFormName();
    
            $id = substr(md5(spl_object_hash($this)), 10);
    
            $mimetypes = array_filter($config['__mimetypes'],
                function($t) { return strpos($t, '/') !== false; }
            );
    
            $maxfilesize = ($config['size'] ?: 1048576) / 1048576;
    
    JediKev's avatar
    JediKev committed
            $files = array();
    
            $new = $this->field->getClean(false);
    
            foreach ($this->field->getAttachments() as $att) {
                unset($new[$att->file_id]);
    
                $files[] = array(
    
    JediKev's avatar
    JediKev committed
                    'id' => $att->file->getId(),
                    'name' => $att->getFilename(),
                    'type' => $att->file->getType(),
                    'size' => $att->file->getSize(),
                    'download_url' => $att->file->getDownloadUrl(),
    
    
            // Add in newly added files not yet saved (if redisplaying after an
            // error)
            if ($new) {
                $F = AttachmentFile::objects()
                    ->filter(array('id__in' => array_keys($new)))
                    ->all();
    
                foreach ($F as $f) {
                    $f->tmp_name = $new[$f->getId()];
                    $files[] = array(
                        'id' => $f->getId(),
                        'name' => $f->getName(),
                        'type' => $f->getType(),
                        'size' => $f->getSize(),
                        'download_url' => $f->getDownloadUrl(),
                    );
                }
            }
    
    
                ?>" class="filedrop"><div class="files"></div>
                <div class="dropzone"><i class="icon-upload"></i>
    
    Jared Hancock's avatar
    Jared Hancock committed
                <?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']); ?>"/>
    
            <script type="text/javascript">
    
            $(function(){$('#<?php echo $id; ?> .dropzone').filedropbox({
    
              url: 'ajax.php/form/upload/<?php echo $this->field->get('id') ?>',
    
              link: $('#<?php echo $id; ?>').find('a.manual'),
    
              paramname: 'upload[]',
    
              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; ?>,
    
    JediKev's avatar
    JediKev committed
              maxfilesize: <?php echo str_replace(',', '.', $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);
    
    aydreeihn's avatar
    aydreeihn committed
                        $ids[$F->getId()] = $F->getName();
    
                    }
                    catch (FileUploadError $ex) {}
    
            // Files uploaded here MUST have been uploaded by this user and
            // identified in the session
            //
    
            // If no value was sent, assume an empty list
    
    aydreeihn's avatar
    aydreeihn committed
            if (!($files = parent::getValue()))
    
                return array();
    
    aydreeihn's avatar
    aydreeihn committed
            if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    
    aydreeihn's avatar
    aydreeihn committed
                $_files = array();
                foreach ($files as $info) {
                    if (@list($id, $name) = explode(',', $info, 2))
                        $_files[$id] = $name;
    
    aydreeihn's avatar
    aydreeihn committed
                }
    
    aydreeihn's avatar
    aydreeihn committed
                $files = $_files;
    
            $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
    
    aydreeihn's avatar
    aydreeihn committed
                $allowed[$F->id] = $F->getName();
    
    
            // 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.
    
    aydreeihn's avatar
    aydreeihn committed
            foreach ($files as $id => $name) {
    
                if (!isset($allowed[$id]))
                    continue;
    
                // Keep the values as the IDs
    
                $ids[$id] = $name ?: $allowed[$id];
    
    class FileUploadError extends Exception {}
    
    
    class FreeTextField extends FormField {
        static $widget = 'FreeTextWidget';
    
        protected $attachments;
    
    
        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',
    
                    'label' => __('Attachments'),
    
                    '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'];
    
            $this->getAttachments()->keepOnlyFileIds($keepers);
    
            return $config;
        }
    
    
        function db_cleanup($field=false) {
    
            if ($field && $this->getFiles())
    
                $this->getAttachments()->deleteAll();
        }
    
        function getAttachments() {
            if (!isset($this->attachments))
                $this->attachments = GenericAttachments::forIdAndType($this->get('id'), 'I');
    
    
            return $this->attachments ?: array();
    
        }
    
        function getFiles() {
    
            if (!isset($this->files)) {
                $files = array();
                if (($attachments=$this->getAttachments()))
                    foreach ($attachments->all() as $a)
                        $files[] = $a->getFile();
                $this->files = $files;
            }
            return $this->files;
    
    }
    
    class FreeTextWidget extends Widget {
    
        function render($options=array()) {
    
            $config = $this->field->getConfiguration();
    
            $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->getAttachments()) && count($attachments)) { ?>
    
                <section class="freetext-files">
                <div class="title"><?php echo __('Related Resources'); ?></div>
    
    Peter Rotich's avatar
    Peter Rotich committed
                <?php foreach ($attachments->all() as $attach) {
    
    Peter Rotich's avatar
    Peter Rotich committed
                    $filename = Format::htmlchars($attach->getFilename());
    
    Peter Rotich's avatar
    Peter Rotich committed
                    ?>
    
                    <div class="file">
    
                    <a href="<?php echo $attach->file->getDownloadUrl(); ?>"
    
                        target="_blank" download="<?php echo $filename; ?>"
                        class="truncate no-pjax">
    
                        <i class="icon-file"></i>
    
                        <?php echo $filename; ?>
    
                    </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
        }
    }
    
    
    class VisibilityConstraint {
    
        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");',
    
                    $field->getWidget()->id);
    
            }
            $expression = $this->compileQ($this->constraint, $form);
    ?>
    
              if (<?php echo $expression; ?>)
    
    Peter Rotich's avatar
    Peter Rotich committed
                target.slideDown('fast', function (){
    
                    $(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);
    
                    $field = $form->getField($f);
    
                    $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;
    
                    switch ($op) {
                    case 'eq':
    
                        $expr[] = sprintf('(%s.is(":visible") && %s)',
                                $id,
                                sprintf('%s == %s',
                                    sprintf($widget->getJsValueGetter(), $id),
                                    JsonDataEncoder::encode($value))
                                );