CHECK (prio >= 0 OR ref IS NOT NULL),
grade integer,
cover boolean NOT NULL DEFAULT FALSE,
- source text CHECK (source ~ '^https?://'),
- thumb text[],
+ image jsonb CHECK (image->>'source' ~ '^https?://'
+ AND jsonb_typeof(image->'convert') = 'array'),
wptitle text,
story text,
creator integer REFERENCES login (id),
COMMENT ON COLUMN word.prio IS 'difficulty level or importance; lower values have precedence';
COMMENT ON COLUMN word.grade IS 'ascending hierarchical order, preceding default alphabetical';
COMMENT ON COLUMN word.cover IS 'highlight if selected';
-COMMENT ON COLUMN word.source IS 'URI of downloaded image';
-COMMENT ON COLUMN word.thumb IS 'ImageMagick convert options to create thumbnail from source image';
+COMMENT ON COLUMN word.image IS 'metadata of illustrations, including downloaded URI and ImageMagick convert options';
COMMENT ON COLUMN word.wptitle IS 'reference Wikipedia article';
COMMENT ON COLUMN word.story IS 'paragraph defining or describing the entity, wikipedia intro';
COMMENT ON COLUMN word.updated IS 'last significant change';
coalesce(r.prio, w.prio ) prio,
coalesce(r.grade, w.grade ) grade,
coalesce(r.cover, w.cover ) cover,
- coalesce(r.source, w.source ) source,
- coalesce(r.thumb, w.thumb ) thumb,
+ coalesce(r.image, w.image ) image,
coalesce(r.wptitle, w.wptitle) wptitle,
coalesce(r.story, w.story ) story,
r.creator, r.created, r.updated,
- CASE WHEN r.source IS NULL THEN w.id ELSE r.id END id -- image id
+ CASE WHEN r.image IS NULL THEN w.id ELSE r.id END id -- image id
FROM word r
LEFT JOIN word w ON w.id = r.ref;
use List::Util qw( pairs pairkeys );
use Shiar_Sheet::FormRow;
+use JSON;
my $db = eval {
require Shiar_Sheet::DB;
form => {-label => 'Title'},
alt => {-label => 'Synonyms', -multiple => 1},
wptitle => {-label => 'Wikipedia'},
- source => {-label => 'Image', -src => sub {
+ source => {-label => 'Image', -json => 'image', -src => sub {
return "data/word/org/$_[0]->{id}.jpg";
}},
- thumb => {-label => 'Convert options', -multiple => 1, -src => sub {
+ convert => {-label => 'Convert options', -json => 'image', -multiple => 1, -src => sub {
return "data/word/en/$_[0]->{id}.jpg";
}},
story => {-label => 'Story', type => 'textarea', hidden => 'hidden'},
say '<h1>Search</h1><ul>';
printf("<li><small>%s</small> %s %s</li>\n",
$_->{id}, showlink($_->{form}, "/writer/$_->{id}"),
- sprintf('<img src="/%s" style="height:3ex; width:auto" />', $wordcol{thumb}->{-src}->($_)) x defined $_->{thumb}
+ sprintf('<img src="/%s" style="height:3ex; width:auto" />', $wordcol{convert}->{-src}->($_)) x defined $_->{image}
) for $results->hashes;
say "</ul>\n";
exit;
return Encode::decode_utf8($_[0]);
}
- my $replace = $row;
- $row = {map { $_ =>
- ref $wordcol{$_} eq 'HASH' && $wordcol{$_}->{-multiple} ?
- [ map { parseinput($_) } $post{'@'.$_}->@* ] :
- scalar parseinput($post{$_})
- } keys %wordcol};
+ my $replace = $row; # currently stored
+ $row = {}; # proposed update
+ while (my ($col, $colinfo) = each %wordcol) {
+ ref $colinfo eq 'HASH' or $colinfo = {};
+ my @val = map { parseinput($_) } $post{'@'.$col}->@*;
+ my $val = $colinfo->{-multiple} && @val ? \@val : $val[-1];
+ if (my $jsoncol = $colinfo->{-json}) {
+ defined $val and
+ $row->{$jsoncol}->{$col} = $val; # hash will be encoded
+ }
+ else {
+ $row->{$col} = $val;
+ }
+ }
+ my $imagecol = $row->{image}; # backup image subcolumns
+ ref $_ eq 'HASH' and $_ = encode_json($_) for values %{$row};
if (!$row->{form}) {
if ($row->{ref} ne 'delete') {
require Shiar_Sheet::ImagePrep;
my $image = Shiar_Sheet::ImagePrep->new($wordcol{source}->{-src}->($row));
my $reimage = eval {
- ($row->{source} // '') ne ($replace->{source} // '') or return;
- $image->download($row->{source});
+ ($imagecol->{source} // '') ne ($replace->{source} // '') or return;
+ $image->download($imagecol->{source});
};
!$@ or Alert(["Source image not found", $@]);
- $reimage ||= $row->{thumb} ~~ $replace->{thumb}; # different convert
+ $reimage ||= $row->{image} ~~ $replace->{image}; # different source
$reimage ||= $row->{cover} ~~ $replace->{cover}; # resize
$reimage++ if $fields{rethumb}; # force refresh
if ($reimage) {
eval {
- $image->convert($wordcol{thumb}->{-src}->($row), $row->{thumb});
+ $image->convert($wordcol{convert}->{-src}->($row), $imagecol->{convert});
} or do {
my ($warn, @details) = ref $@ ? @{$@} : $@;
Alert([ "Thumbnail image not generated", $warn ], @details);
$row->{prio} = defined $row->{ref} ? undef : 1 unless exists $row->{prio};
}
+eval {
+ my $imagerow = $row->{image} && decode_json(delete $row->{image}) || {};
+ while (my ($col, $val) = each %{$imagerow}) {
+ $row->{$col} = $val;
+ }
+ 1;
+} or Alert("Error decoding image metadata", $@);
+
my $title = $row->{id} ? "entry <small>#$row->{id}</small>" : 'new entry';
bless $row, 'Shiar_Sheet::FormRow';
:>