new collapsible text box widget

pull/26/head
Ondřej Hruška 6 years ago
parent fa9325577f
commit 3f8fa07a82
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 2
      app/Http/Controllers/TableController.php
  2. 80
      app/View/CollapsibleTextBoxWidget.php
  3. 5
      app/View/WidgetFactory.php
  4. 6
      resources/assets/js/app.js
  5. 37
      resources/assets/sass/_block-collapse.scss
  6. 16
      resources/assets/sass/_helpers.scss
  7. 1
      resources/assets/sass/app.scss
  8. 2
      resources/assets/sass/bootstrap-customizations/_card.scss
  9. 4
      resources/assets/sass/bootstrap-customizations/_variables.scss
  10. 24
      resources/views/profile/view.blade.php
  11. 62
      resources/views/table/view.blade.php

@ -23,7 +23,7 @@ class TableController extends Controller
'table' => $tableModel,
'revision' => $revision,
'columns' => Column::columnsFromJson(json_decode($revision->columns)),
'rows' => $revision->rows,
'rows' => $revision->rows()->paginate(25),
]);
}

@ -0,0 +1,80 @@
<?php
namespace App\View;
/**
* Collapsible text box widget
*/
class CollapsibleTextBoxWidget
{
private $maxHeight;
private $collapsing;
private $text;
private $srPrefix;
private $srEscape;
/**
* Add a prefix inside the text box shown only to screen readers, Lynx etc.
*
* @param string $content
* @param bool $escape - use html escape, default true
* @return $this
*/
public function srPrefix($content, $escape=true)
{
$this->srEscape = $escape;
$this->srPrefix = $content;
return $this;
}
/**
* @param string $text - text to show
* @param int $thresholdLength - mb_character length that triggers the collapsible behavior; choose experimentally
* @param string $maxHeight - max height CSS value (e.g. 8em)
*/
public function __construct($text, $thresholdLength, $maxHeight)
{
$this->text = $text;
$this->collapsing = mb_strlen($text) > $thresholdLength;
$this->maxHeight = $maxHeight;
}
private function processText($t)
{
$out = e($t);
$out = str_replace("\r\n", "\n", $out);
$out = '<p class="last-p-mb-0"> '.str_replace("\n\n",
" </p>". '<p class="last-p-mb-0"> ', $out).' </p>';
$out = nl2br($out);
$out = preg_replace('|(https?://[^\s]+)|i', '<a href="\1">\1</a>', $out);
return $out;
}
public function render()
{
$content = $this->processText($this->text);
$prefix = '';
if ($this->srPrefix) {
$prefix = '<span class="sr-only">'.
($this->srEscape ? e($this->srPrefix) : $this->srPrefix).
'&nbsp;</span>';
}
if ($this->collapsing) {
return '<div class="block-collapse" style="max-height:'.$this->maxHeight.'">' . $prefix . $content . '</div>';
} else {
return $prefix.'<div>' . $prefix . $content . '</div>';
}
}
public function __toString()
{
return (string) $this->render();
}
}

@ -31,6 +31,11 @@ class WidgetFactory
"</div>";
}
public function collapsible($text, $thrSize, $maxHeight)
{
return new CollapsibleTextBoxWidget($text, $thrSize, $maxHeight);
}
private function baseWidget($view, $name, $label)
{
return (new Widget($view, $name, $label))->layout($this->labelCols, $this->fieldCols);

@ -20,6 +20,12 @@ $(function () {
$notifs.addClass('hidden')
}, 500)
}, 2500)
$('.block-collapse').on('click', (e) => {
$(e.target).closest('.block-collapse').addClass('reveal')
}).on('dblclick', (e) => {
$(e.target).closest('.block-collapse').removeClass('reveal')
});
})
// auto-alias

@ -0,0 +1,37 @@
.block-collapse {
overflow: hidden;
text-overflow: ellipsis;
position: relative;
&::before,
&::after {
position: absolute;
right: 0;
bottom: 0;
text-align: right;
height: 1.7em;
line-height: 1.7em;
cursor: pointer;
}
&::after{
content: '';
width: 70%;
background: linear-gradient(to right, rgba(255, 255, 255, 0), white 90%);
}
&::before {
content: '';
z-index: 10;
color: $gray-500;
}
&.reveal {
max-height: unset !important; // override inline styles
&::before, &::after {
display: none;
}
}
}

@ -26,3 +26,19 @@
.border-dotted {
border-style: dotted !important;
}
.last-p-mb-0 {
&:last-child {
margin-bottom: 0;
}
}
@each $color, $value in $colors {
.border-#{$color} {
border-color: $value !important;
}
}
.box-shadow {
box-shadow: 0 2px 3px rgba(black, .3);
}

@ -7,6 +7,7 @@ html {
@import "helpers";
@import "fa-utils";
@import "block-collapse";
@import "bootstrap-customizations/paginate";
@import "bootstrap-customizations/card";

@ -14,7 +14,7 @@
}
.card {
box-shadow: 0 2px 3px rgba(black, .3);
@extend .box-shadow;
}
.card-header-extra {

@ -15,9 +15,9 @@ $font-family-sans-serif: "IBM Plex Sans", "Droid Sans", "Helvetica Neue", "Helve
$font-size-base: 1rem;
$line-height-base: 1.6;
$link-color: $gray-800;
$link-color: darken($primary, 15%);
$link-decoration: none;
$link-hover-color: darken($link-color, 15%);
$link-hover-color: darken($primary, 10%);
$link-hover-decoration: underline;
$card-cap-bg: lighten($primary, 5);

@ -30,27 +30,9 @@
<div class="card-body">
@if($user->bio)
@if(mb_strlen($user->bio) > 250)
<p id="bio-short mb-2" aria-hidden=true>
@sr(About me:)
{{mb_substr($user->bio, 0, 250)}}…
<a class="text-muted small" @tooltip(Show more) href="#" onclick="$('#bio-short').addClass('hidden'); $('#bio-full').removeClass('hidden'); return false;">
[more]
</a>
</p>
<p id="bio-full" class="hidden mb-2">
@sr(About me:)
{{ $user->bio }}
<a class="text-muted small" @tooltip(Collapse) href="#" onclick="$('#bio-full').addClass('hidden'); $('#bio-short').removeClass('hidden'); return false;">
[collapse]
</a>
</p>
@else
<p class="mb-2">
@sr(About me:)
{{ $user->bio }}
</p>
@endif
<div class="mb-3">
{!! Widget::collapsible($user->bio, 350, '8em')->srPrefix('About me:') !!}
</div>
@endif
<table>

@ -10,13 +10,68 @@
<div class="row justify-content-center">
<h2>{{ $table->title }}</h2>
</div>
<div class="row justify-content-center">
<div class="col-md-10">
<div class="row mx-auto col-md-12 justify-content-center mb-1 border rounded px-0 py-2 box-shadow mb-3">
<div class="col-md-6">
@if($table->description)
<p class="last-p-mb-0">
<b>Description</b><br>
{!! Widget::collapsible($table->description, 400, '8em') !!}
</p>
@endif
@if($table->origin)
<p class="last-p-mb-0">
<b>Source</b><br>
{{ $table->origin }}
</p>
@endif
</div>
<div class="col-md-4 border-left">
<table>
<tbody>
<tr>
<th class="text-right pr-2">License</th>
<td>{{ $table->license ?: 'CC0' }}</td>
</tr>
<tr>
<th class="text-right pr-2">Created</th>
<td>{{ $table->created_at->format("M j, Y") }}</td>
</tr>
<tr>
<th class="text-right pr-2">Updated</th>
<td>{{ $table->updated_at->format("M j, Y") }}</td>
</tr>
<tr>
<th class="text-right pr-2">Revisions</th>
<td>{{ $table->revisions()->count() }}</td>
</tr>
</tbody>
</table>
</div>
<div class="col-md-2 border-left">
Right Column with buttons etc, maybe
</div>
</div>
<div class="row justify-content-center mb-2">
<div class="col-md-12 d-flex">
<nav class="text-center ml-auto" aria-label="Pages of the table">
{{ $rows->links(null, ['ulClass' => 'mb-0']) }}
</nav>
</div>
</div>
<div class="row justify-content-center">
<div class="col-12">
<table class="table table-hover table-sm">
<thead>
<tr>
<th>ID</th>
@foreach($columns as $col)
<th>{{ $col->title }}</th>
@endforeach
@ -25,7 +80,6 @@
<tbody>
@foreach($rows as $row)
<tr>
<td>#{{ $row->id }}</td>
@php($rdata = json_decode($row['data'], true))
@foreach($columns as $col)
<td data-id="{{ $row->id }}">{{ $rdata[$col->name] }}</td>

Loading…
Cancel
Save