/** * Extracts and escapes text from the given value, for outputting to the HTTP client. * * <p>Note: this returns escaped text, except if the given argument is a {@see RawText} instance, in which case it * returns raw text. * * @param string|RawText $s * @return string */ function _e($s) { if (!is_scalar($s)) { if (is_null($s)) { return ''; } if ($s instanceof RawText) { return $s->toString(); } if ($s instanceof RenderableInterface) { $s = $s->getRendering(); } elseif (is_object($s) && method_exists($s, '__toString')) { $s = (string) $s; } else { if (is_iterable($s)) { return iteratorOf($s)->current(); } return sprintf('[%s]', typeOf($s)); } } return htmlentities($s, ENT_QUOTES, 'UTF-8', false); }
protected function table($data, $title = '', $depth = 0, $typeColumn = true, $columnHeaders = true, $maxDepth = -1) { $isList = false; $originalData = $data; if ($this->caption) { $title = $this->caption; $this->caption = ''; } // DISPLAY PRIMITIVE VALUES if (!is_array($data) && !is_object($data) || is_null($data) || $data instanceof \PowerString) { return Debug::toString($data); } // SETUP TABULAR DISPLAY OF ARRAYS AND OBJECTS $w1 = DebugConsole::$settings->tablePropertyColumnWidth; $c1 = ''; if (is_array($data)) { if (!count($data)) { return '<i>[]</i>'; } if ($depth == DebugConsole::$settings->tableMaxDepth || $depth == $maxDepth) { return '<i>(...)</i>'; } ++$depth; $label = 'Key'; if (isset($data[0])) { $isList = true; $label = 'Index'; $w1 = DebugConsole::$settings->tableIndexColumnWidth; $c1 = ' class="n"'; } } elseif (is_object($data)) { if ($depth == DebugConsole::$settings->tableMaxDepth || $depth == $maxDepth) { return '<i>(...)</i>'; } ++$depth; // Note: Selenia's CustomInspectionInterface implements the inspect() method, but this library is not dependent on // any external interface. if ($data instanceof CustomInspectionInterface) { return $data->inspect(); } elseif (method_exists($data, '__debugInfo')) { $data = $data->__debugInfo(); if (empty($data)) { return '<i>(empty)</i>'; } } else { if ($it = iteratorOf($data, false)) { $data = iterator_to_array($it); } else { $data = get_object_vars($data); if (empty($data)) { return '<i>(not inspectable)</i>'; } } } if (!is_string($data)) { $label = 'Property'; uksort($data, 'strnatcasecmp'); } } // DRAW TABLE $filter = isset($this->filter) ? $this->filter : function () { return true; }; ob_start(null, 0); if ($depth >= DebugConsole::$settings->tableCollapseDepth) { echo '<div class="__expand"><a class="fa fa-plus-square" href="javascript:void(0)" onclick="this.parentNode.className+=\' show\'"></a>'; } if (is_string($data)) { echo $data; } else { ?> <table class="__console-table<?php echo $title ? ' with-caption' : ''; ?> "> <?php echo $title ? "<caption>{$title}</caption>" : ''; if (empty($data)) { echo '<thead><tr><td colspan=3><i>[]</i>'; } else { if (DebugConsole::$settings->tableUseColumWidths) { ?> <colgroup> <col width="<?php echo $w1; ?> "> <?php if ($typeColumn) { ?> <col width="<?php echo DebugConsole::$settings->tableTypeColumnWidth; ?> "> <?php } ?> <col width="100%"> </colgroup> <?php } if ($columnHeaders) { ?> <thead> <tr> <th><?php echo $label; ?> </th> <?php if ($typeColumn) { ?> <th>Type</th> <?php } ?> <th>Value</th> </thead> <?php } ?> <tbody> <?php $c = 0; foreach ($data as $k => $v) { if ($isList && ++$c > DebugConsole::$settings->maxIndexedArrayItems) { echo '<tr><td><i>(...)</i>'; break; } $x = $filter($k, $v, $originalData); if (!$x) { continue; } ?> <tr> <th<?php echo $c1; ?> ><?php echo strlen($k) ? $k : "<i>''</i>"; ?> </th> <?php if ($typeColumn) { ?> <td><?php echo Debug::getType($v); ?> </td> <?php } ?> <td class="v"><?php echo $x === '...' ? '<i>ommited</i>' : $this->table($v, '', $depth, $typeColumn, $columnHeaders, $maxDepth); ?> </td> <?php } ?> </tbody> <?php } ?> </table><?php } if ($depth >= DebugConsole::$settings->tableCollapseDepth) { echo '</div>'; } return trim(ob_get_clean()); }
protected function render() { $prop = $this->props; $isMultiple = $prop->multiple; $assets = $this->context->getAssetsService(); $assets->addInlineScript("selenia.ext.select.props['{$prop->id}']=" . JavascriptCodeGen::makeOptions(['autoOpenLinked' => $prop->autoOpenLinked, 'dataUrl' => $prop->dataUrl, 'emptyLabel' => $prop->emptyLabel, 'emptySelection' => $prop->emptySelection, 'id' => $prop->id, 'labelField' => $prop->labelField, 'linkedSelector' => $prop->linkedSelector, 'linkedUrl' => $prop->linkedUrl, 'multiple' => $prop->multiple, 'noResultsText' => $prop->noResultsText, 'valueField' => $prop->valueField, 'value' => $prop->value])); // If required, add auto-add tag behavior to this Chosen. if ($prop->autoTag && $prop->multiple) { $assets->addInlineScript("\n\$(function () {\n \$ ('#{$prop->id}+.chosen-container .chosen-choices input').on ('keyup', function (ev) { console.log(ev);\n var v = \$ (this).val ();\n if (ev.keyCode == 13 && v) {\n var tags = \$ ('#{$prop->id} option').map (function (i, e) { return \$ (e).val () });\n var found = false, l = v.length;\n tags.each (function (i, x) {\n if (x.substr (0, l) == v) {\n found = true;\n return false\n }\n });\n if (found) return;\n \$ ('#{$prop->id}').append (\"<option>\" + v + \"</option>\");\n \$ ('#{$prop->id}').trigger ('chosen:updated');\n ev.preventDefault ();\n var e = jQuery.Event (\"keyup\");\n e.which = 13;\n \$ ('#{$prop->id}+.chosen-container .chosen-choices input').val (v).trigger ('keyup').trigger (e);\n }\n })\n});\n"); } $this->attr('name', $prop->multiple ? "{$prop->name}[]" : $prop->name); $this->attrIf($isMultiple, 'multiple', ''); $this->attrIf($prop->onChange, 'onchange', $prop->onChange); $this->beginContent(); if ($prop->emptySelection && !$prop->multiple) { $sel = exists($prop->value) ? '' : ' selected'; echo '<option value=""' . $sel . '>' . $prop->emptyLabel . '</option>'; } $viewModel = $prop->get('data'); if (isset($viewModel)) { /** @var \Iterator $dataIter */ $dataIter = iteratorOf($viewModel); $dataIter->rewind(); if ($dataIter->valid()) { $values = $selValue = null; // SETUP MULTI-SELECT if ($isMultiple) { if (isset($prop->value) && !is_iterable($prop->value)) { throw new ComponentException($this, sprintf("Value of multiple selection component must be iterable or null; %s was given.", typeOf($prop->value))); } $it = Flow::from($prop->value); $it->rewind(); $values = $it->valid() && is_scalar($it->current()) ? $it->all() : $it->map(pluck($prop->valueField))->all(); } else { $selValue = strval($prop->get('value')); } // NOW RENDER IT $template = $this->getChildren('listItemTemplate'); $first = true; do { $v = $dataIter->current(); $value = getField($v, $prop->valueField); $label = getField($v, $prop->labelField); if (!strlen($label)) { $label = $prop->emptyLabel; } if ($isMultiple) { $sel = array_search($value, $values) !== false ? ' selected' : ''; } else { if ($first && !$prop->emptySelection && !$prop->multiple && !exists($selValue)) { $prop->value = $selValue = $value; } $eq = $prop->strict ? $value === $selValue : $value == $selValue; if ($eq) { $this->selectedLabel = $label; } $sel = $eq ? ' selected' : ''; } if ($template) { // Render templated list $viewModel['value'] = $value; $viewModel['label'] = $label; Component::renderSet($template); } else { // Render standard list echo "<option value=\"{$value}\"{$sel}>{$label}</option>"; } $dataIter->next(); $first = false; } while ($dataIter->valid()); } } }