Add recipe list page generation
This commit is contained in:
parent
8c04995d0b
commit
2ee53cb8f3
159
blocks/ORB/List.pm
Normal file
159
blocks/ORB/List.pm
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
## @file
|
||||||
|
# This file contains the implementation of the list page.
|
||||||
|
#
|
||||||
|
# @author Chris Page <chris@starforge.co.uk>
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see http://www.gnu.org/licenses/.
|
||||||
|
|
||||||
|
## @class
|
||||||
|
package ORB::List;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use parent qw(ORB); # This class extends the ORB block class
|
||||||
|
use experimental qw(smartmatch);
|
||||||
|
use v5.14;
|
||||||
|
use Data::Dumper;
|
||||||
|
## @method private % _build_tag($tag)
|
||||||
|
# Given a reference to a hash containing tag data, generate HTML to
|
||||||
|
# represent the tag
|
||||||
|
#
|
||||||
|
# @param tag A reference to a tag hash
|
||||||
|
# @return A string representing the tag
|
||||||
|
sub _build_tag {
|
||||||
|
my $self = shift;
|
||||||
|
my $tag = shift;
|
||||||
|
|
||||||
|
return $self -> {"template"} -> load_template("list/tag.tem", { "%(name)s" => $tag -> {"name"},
|
||||||
|
"%(color)s" => $tag -> {"color"},
|
||||||
|
"%(bgcol)s" => $tag -> {"background"},
|
||||||
|
"%(faicon)s" => $tag -> {"fa-icon"}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
## @method private $ _generate_list($mode)
|
||||||
|
# Generate the list page. This will create a page containing a list
|
||||||
|
# of recipies based on the specified mode.
|
||||||
|
#
|
||||||
|
# @return An array of two values containing the page title and content.
|
||||||
|
sub _generate_list {
|
||||||
|
my $self = shift;
|
||||||
|
my $mode = shift;
|
||||||
|
|
||||||
|
my $recipes = $self -> {"system"} -> {"recipe"} -> get_recipe_list($mode)
|
||||||
|
or $self -> generate_errorbox(message => $self -> {"system"} -> {"recipe"} -> errstr());
|
||||||
|
|
||||||
|
my @list;
|
||||||
|
foreach my $recipe (@{$recipes}) {
|
||||||
|
my $temp = "";
|
||||||
|
|
||||||
|
if($recipe -> {"temp"} && $recipe -> {"temptype"} ne "N/A") {
|
||||||
|
$temp = $self -> {"template"} -> load_template("list/temp.tem", { "%(temp)s" => $recipe -> {"temp"},
|
||||||
|
"%(temptype)s" => $recipe -> {"temptype"}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
my $controls = "";
|
||||||
|
if($self -> check_permission("recipe.edit", $recipe -> {"metadata_id"})) {
|
||||||
|
$controls .= $self -> {"template"} -> load_template("list/recipe.tem",
|
||||||
|
{ "%(url-edit)s" => $self -> build_url(block => "edit", pathinfo => [ $recipe -> {"id"} ]),
|
||||||
|
"%(url-edit)s" => $self -> build_url(block => "edit", pathinfo => [ "clone", $recipe -> {"id"} ]),
|
||||||
|
"%(url-edit)s" => $self -> build_url(block => "edit", pathinfo => [ "delete", $recipe -> {"id"}]),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
push(@list, $self -> {"template"} -> load_template("list/recipe.tem",
|
||||||
|
{ "%(id)s" => $recipe -> {"id"},
|
||||||
|
"%(url-view)s" => $self -> build_url(block => "view",
|
||||||
|
pathinfo => [ $recipe -> {"id"} ]),
|
||||||
|
"%(name)s" => $recipe -> {"name"},
|
||||||
|
"%(type)s" => $recipe -> {"type"},
|
||||||
|
"%(status)s" => $recipe -> {"status"},
|
||||||
|
"%(time)s" => $self -> {"template"} -> humanise_seconds($recipe -> {"timemins"} * 60, 1),
|
||||||
|
"%(temp)s" => $temp,
|
||||||
|
"%(tags)s" => join("", map { $self -> _build_tag($_) } @{$recipe -> {"tags"}}),
|
||||||
|
"%(controls)s" => $controls,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ($self -> {"template"} -> replace_langvar("LIST_TITLE", { "%(page)s" => uc($mode // "All") }),
|
||||||
|
$self -> {"template"} -> load_template("list/content.tem", {"%(pagemenu)s" => $self -> pagemenu($mode),
|
||||||
|
"%(page)s" => uc($mode // "All"),
|
||||||
|
"%(recipes)s" => join("", @list),
|
||||||
|
}),
|
||||||
|
$self -> {"template"} -> load_template("list/extrahead.tem"),
|
||||||
|
$self -> {"template"} -> load_template("list/extrajs.tem"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# UI handler/dispatcher functions
|
||||||
|
|
||||||
|
## @method private $ _dispatch_ui()
|
||||||
|
# Implements the core behaviour dispatcher for non-api functions. This will
|
||||||
|
# inspect the state of the pathinfo and invoke the appropriate handler
|
||||||
|
# function to generate content for the user.
|
||||||
|
#
|
||||||
|
# @return A string containing the page HTML.
|
||||||
|
sub _dispatch_ui {
|
||||||
|
my $self = shift;
|
||||||
|
|
||||||
|
# We need to determine what the page title should be, and the content to shove in it...
|
||||||
|
my ($title, $body, $extrahead, $extrajs) = ("", "", "", "");
|
||||||
|
my @pathinfo = $self -> {"cgi"} -> multi_param("pathinfo");
|
||||||
|
|
||||||
|
print STDERR "Mode: ".$pathinfo[0]."\n";
|
||||||
|
if(defined($pathinfo[0]) && $pathinfo[0] =~ /^[0a-zA-Z\$]$/) {
|
||||||
|
($title, $body, $extrahead, $extrajs) = $self -> _generate_list($pathinfo[0]);
|
||||||
|
} elsif($pathinfo[0] && lc($pathinfo[0]) eq "all") {
|
||||||
|
($title, $body, $extrahead, $extrajs) = $self -> _generate_list();
|
||||||
|
} else {
|
||||||
|
($title, $body, $extrahead, $extrajs) = $self -> _generate_list('A');
|
||||||
|
}
|
||||||
|
|
||||||
|
# Done generating the page content, return the filled in page template
|
||||||
|
return $self -> generate_orb_page(title => $title,
|
||||||
|
content => $body,
|
||||||
|
extrahead => $extrahead,
|
||||||
|
extrajs => $extrajs,
|
||||||
|
doclink => 'list');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Module interface functions
|
||||||
|
|
||||||
|
## @method $ page_display()
|
||||||
|
# Generate the page content for this module.
|
||||||
|
sub page_display {
|
||||||
|
my $self = shift;
|
||||||
|
|
||||||
|
# Is this an API call, or a normal page operation?
|
||||||
|
my $apiop = $self -> is_api_operation();
|
||||||
|
if(defined($apiop)) {
|
||||||
|
# API call - dispatch to appropriate handler.
|
||||||
|
given($apiop) {
|
||||||
|
default {
|
||||||
|
return $self -> api_response($self -> api_errorhash('bad_op',
|
||||||
|
$self -> {"template"} -> replace_langvar("API_BAD_OP")))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return $self -> _dispatch_ui();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
1;
|
10
lang/en/recipelist.lang
Normal file
10
lang/en/recipelist.lang
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
LIST_TITLE = Recipes - Page %(page)s
|
||||||
|
LIST_SUMMARIES = Summaries
|
||||||
|
LIST_FILTER = Filter
|
||||||
|
LIST_SORT = Sort
|
||||||
|
|
||||||
|
LIST_NAME = Name
|
||||||
|
LIST_TYPE = Type
|
||||||
|
LIST_STATUS = Status
|
||||||
|
|
||||||
|
LIST_OKAY = Okay
|
56
templates/default/css/recipelist.css
Normal file
56
templates/default/css/recipelist.css
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
li.recipe {
|
||||||
|
padding: 3px;
|
||||||
|
border-bottom: 1px solid #e7e7e7;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.recipes {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.recipes li {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ul.recipes li .controls {
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.recipes li:nth-child(even) {
|
||||||
|
background-color: #fafafa;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.recipes li .name { font-weight: bold; word-wrap: break-word; line-height: 1.1; margin-bottom: 4px; }
|
||||||
|
ul.recipes li ul.meta {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0 0 0.2rem 0.5rem;
|
||||||
|
padding: 0;
|
||||||
|
line-height: 1.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.meta li.type,
|
||||||
|
ul.meta li.status,
|
||||||
|
ul.meta li.time,
|
||||||
|
ul.meta li.temp {
|
||||||
|
display: inline-block; color: #888; font-size: 0.7rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.recipes li .tags {
|
||||||
|
font-size: .75rem;
|
||||||
|
line-height: 1;
|
||||||
|
margin-left: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.recipes li .intro {
|
||||||
|
color: #888;
|
||||||
|
padding-right: 0.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.ljs-tag {
|
||||||
|
display: inline-block;
|
||||||
|
padding: .33333rem .5rem;
|
||||||
|
margin-right: .3rem;
|
||||||
|
border-radius: 0;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
23
templates/default/js/delaysearch.js
Normal file
23
templates/default/js/delaysearch.js
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
(function ($, undefined) {
|
||||||
|
$.fn.delaysearch = function (list) {
|
||||||
|
var $this = this;
|
||||||
|
|
||||||
|
var searchTimer;
|
||||||
|
var delayLimit = 3;
|
||||||
|
var delayTime = 1500;
|
||||||
|
|
||||||
|
$this.bind('keyup', function(e) {
|
||||||
|
var target = e.target || e.srcElement; // IE have srcElement
|
||||||
|
clearTimeout(searchTimer);
|
||||||
|
|
||||||
|
var value = $this.val();
|
||||||
|
if(value.length == 0 || value.length >= delayLimit) {
|
||||||
|
list.search(value);
|
||||||
|
} else {
|
||||||
|
searchTimer = setTimeout(list.search, delayTime, value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
};
|
||||||
|
})(jQuery);
|
10
templates/default/js/recipe_list.js
Normal file
10
templates/default/js/recipe_list.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
$(function() {
|
||||||
|
var options = {
|
||||||
|
valueNames: [ 'ljs-name', 'ljs-type', 'ljs-status', 'ljs-time', 'tags' ],
|
||||||
|
plugins: [ ListFuzzySearch() ]
|
||||||
|
};
|
||||||
|
|
||||||
|
var recipeList = new List('recipelist', options);
|
||||||
|
|
||||||
|
$('#listfilter').delaysearch(recipeList);
|
||||||
|
});
|
31
templates/default/list/content.tem
Normal file
31
templates/default/list/content.tem
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
%(pagemenu)s
|
||||||
|
<div id="recipelist" class="columns">
|
||||||
|
<nav aria-label="You are here:" role="navigation">
|
||||||
|
<ul class="breadcrumbs">
|
||||||
|
<li><a href="%(url-front)s">{L_LIST_SUMMARIES}</a></li>
|
||||||
|
<li>%(page)s</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
<div class="column row clearfix">
|
||||||
|
<div class="small input-group nomargin">
|
||||||
|
<input type="search" class="input-group-field" id="listfilter" placeholder="{L_LIST_FILTER}" />
|
||||||
|
<div class="input-group-button button-group">
|
||||||
|
<button class="button" type="button" data-toggle="sort-dropdown">{L_LIST_SORT}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="dropdown-pane" id="sort-dropdown" data-dropdown data-auto-focus="true">
|
||||||
|
<ul class="menu">
|
||||||
|
<li><button class="button sort" data-sort="ljs-name">{L_LIST_NAME}</button></li>
|
||||||
|
<li><button class="button sort" data-sort="ljs-type">{L_LIST_TYPE}</button></li>
|
||||||
|
<li><button class="button sort" data-sort="ljs-status">{L_LIST_STATUS}</button></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<ul class="list recipes">
|
||||||
|
%(recipes)s
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div id="errormodal" class="small reveal" data-reveal>
|
||||||
|
<div><img src="{V_[templatepath]}images/error.png" width="48" height="48" alt="error" /> <span id="errortext"></span></div>
|
||||||
|
<div><button class="button alert float-right nomargin" data-close aria-label="Close">{L_LIST_OKAY}</button></div>
|
||||||
|
</div>
|
5
templates/default/list/controls.tem
Normal file
5
templates/default/list/controls.tem
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<div class="controls button-group float-right">
|
||||||
|
<a href="%(url-edit)s" class="button" title="Edit"><i class="fa fa-edit" aria-hidden="true"></i></a>
|
||||||
|
<a href="%(url-clone)s" class="button" title="Clone"><i class="fa fa-copy" aria-hidden="true"></i></a>
|
||||||
|
<a href="%(url-delete)s" class="button alert" title="Delete"><i class="fa fa-trash" aria-hidden="true"></i></a>
|
||||||
|
</div>
|
1
templates/default/list/extrahead.tem
Normal file
1
templates/default/list/extrahead.tem
Normal file
@ -0,0 +1 @@
|
|||||||
|
<link rel="stylesheet" href="{V_[csspath]}recipelist.css" />
|
6
templates/default/list/extrajs.tem
Normal file
6
templates/default/list/extrajs.tem
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
</script>
|
||||||
|
<script src="{V_[templatepath]}3rdparty/listjs/list.min.js"></script>
|
||||||
|
<script src="{V_[templatepath]}3rdparty/fuzzysearch/list.fuzzysearch.min.js"></script>
|
||||||
|
<script src="{V_[jspath]}delaysearch.js"></script>
|
||||||
|
<script src="{V_[jspath]}recipe_list.js"></script>
|
||||||
|
<script>
|
13
templates/default/list/recipe.tem
Normal file
13
templates/default/list/recipe.tem
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<li class="recipe clearfix" id="recipe-%(id)s">
|
||||||
|
<div class="info float-left">
|
||||||
|
<div class="name"><a href="%(url-view)s" class="ljs-name">%(name)s</a></div>
|
||||||
|
<ul class="meta">
|
||||||
|
<li class="type"><i class="fa fa-book" aria-hidden="true"></i> <span class="ljs-type">%(type)s</span></li>
|
||||||
|
<li class="status"><i class="fa fa-star" aria-hidden="true"></i> <span class="ljs-status">%(status)s</span></li>
|
||||||
|
<li class="time"><i class="fa fa-clock-o" aria-hidden="true"></i> <span class="ljs-time">%(time)s</span></li>
|
||||||
|
%(temp)s
|
||||||
|
</ul>
|
||||||
|
<div class="tags"><span class="intro"><i class="fa fa-tags" aria-hidden="true"></i>:</span>%(tags)s</div>
|
||||||
|
</div>
|
||||||
|
%(controls)s
|
||||||
|
</li>
|
1
templates/default/list/tag.tem
Normal file
1
templates/default/list/tag.tem
Normal file
@ -0,0 +1 @@
|
|||||||
|
<span class="ljs-tag" style="color: %(color)s; background-color: %(bgcol)s"><i class="fa %(faicon)s"></i> %(name)s</span>
|
1
templates/default/list/temp.tem
Normal file
1
templates/default/list/temp.tem
Normal file
@ -0,0 +1 @@
|
|||||||
|
<li class="temp"><i class="fa fa-thermometer-three-quarters" aria-hidden="true"></i> <span class="ljs-temp">%(temp)s%(temptype)s</span></li>
|
Loading…
x
Reference in New Issue
Block a user