summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYorhel <git@yorhel.nl>2019-11-04 11:52:45 +0100
committerYorhel <git@yorhel.nl>2019-11-10 12:44:55 +0100
commitde6df4ab815a4f4447122d7f19888afd1b3e50ec (patch)
tree2eb3ce6ba9ebaf0d6c5fa588b7d2e4c4f87bc684
parent6821b9ab3f3b24e4d635a0763122d0ed2b1c0b72 (diff)
ulist: Add (nonfunctional) releases + options UI; More consistent naming
-rw-r--r--Makefile6
-rw-r--r--data/style.css12
-rw-r--r--elm/Lib/Html.elm10
-rw-r--r--elm/Lib/Util.elm5
-rw-r--r--elm/UList/DateEdit.elm (renamed from elm/ULists/DateEdit.elm)2
-rw-r--r--elm/UList/LabelEdit.elm (renamed from elm/ULists/LabelEdit.elm)6
-rw-r--r--elm/UList/LabelEdit.js (renamed from elm/ULists/LabelEdit.js)6
-rw-r--r--elm/UList/ManageLabels.elm (renamed from elm/ULists/ManageLabels.elm)2
-rw-r--r--elm/UList/ManageLabels.js (renamed from elm/ULists/ManageLabels.js)4
-rw-r--r--elm/UList/Opt.elm79
-rw-r--r--elm/UList/VoteEdit.elm (renamed from elm/ULists/VoteEdit.elm)6
-rw-r--r--elm/UList/VoteEdit.js (renamed from elm/ULists/VoteEdit.js)6
-rw-r--r--elm/checkall.js10
-rw-r--r--elm/checkhidden.js4
-rw-r--r--lib/VNWeb/Elm.pm2
-rw-r--r--lib/VNWeb/User/Lists.pm48
16 files changed, 167 insertions, 41 deletions
diff --git a/Makefile b/Makefile
index 5f20e31d..18e25f47 100644
--- a/Makefile
+++ b/Makefile
@@ -120,9 +120,9 @@ static/f/vndb.min.js: static/f/vndb.js
JS_FILES=\
elm/polyfills.js \
elm/pagevars.js \
- elm/ULists/ManageLabels.js \
- elm/ULists/LabelEdit.js \
- elm/ULists/VoteEdit.js \
+ elm/UList/ManageLabels.js \
+ elm/UList/LabelEdit.js \
+ elm/UList/VoteEdit.js \
elm/Lib/Ffi.js \
elm/elm-init.js \
elm/checkall.js \
diff --git a/data/style.css b/data/style.css
index 092f853b..54d9bec8 100644
--- a/data/style.css
+++ b/data/style.css
@@ -159,8 +159,8 @@ p.linkradio { padding: 2px }
.linkradio input:checked + label:before { content: '✓' }
.linkradio em { font-weight: normal; font-style: normal; color: $grayedout$ }
-.spinner { content: ''; border: 3px solid #9eaebd; border-bottom-color: transparent; border-radius: 100%; animation: spin 1s infinite linear; width: 14px; height: 14px; display: inline-block; margin: auto }
-span.spinner { width: 1ex; height: 1ex }
+.spinner { content: ''; box-sizing: border-box; border: 3px solid #9eaebd; border-bottom-color: transparent; border-radius: 100%; animation: spin 1s infinite linear; width: 16px; height: 16px; display: inline-block; margin: auto }
+span.spinner { width: 1em; height: 1em }
@keyframes spin { from { transform:rotate(0deg); } to { transform:rotate(360deg); } }
.textpreview .head { width: 100%; text-align: right }
@@ -817,6 +817,14 @@ div.votelist td.tc2 { width: 50px; text-align: right; padding-right: 10px }
.labeledit > div > ul li label { display: block; padding-left: 10px; border: 0; padding: 3px 5px 3px 3px }
.labeledit > div > ul li label:hover { background: $boxbg$ }
+.ulist .tc_opt { padding: 0 0 5px 70px }
+.ulist .tc_opt textarea { width: 500px; height: 50px }
+.ulist .tc_opt textarea + div { display: inline-block; padding-left: 10px }
+.ulist .tc_opt .tco1 { white-space: nowrap; width: 70px }
+.ulist .tc_opt .tco2 { white-space: nowrap; width: 70px }
+.ulist .tc_opt .tco3 { white-space: nowrap; width: 100px }
+.ulist .tc_opt .tco4 { white-space: nowrap; width: 60px; text-align: right; padding-bottom: 0 }
+
/***** User VN list browser ******/
diff --git a/elm/Lib/Html.elm b/elm/Lib/Html.elm
index 770e9142..6e67cefb 100644
--- a/elm/Lib/Html.elm
+++ b/elm/Lib/Html.elm
@@ -6,6 +6,8 @@ import Html.Events exposing (..)
import Json.Decode as JD
import List
import Lib.Api as Api
+import Lib.Util exposing (..)
+import Gen.Types as T
-- onClick with stopPropagation & preventDefault
@@ -165,3 +167,11 @@ formField lbl cont =
txt -> genlbl (String.concat txt)
, td (class "field" :: if lbl == "none" then [ colspan 2 ] else []) cont
]
+
+
+
+langIcon : String -> Html m
+langIcon l = abbr [ class "icons lang", class l, title (Maybe.withDefault "" <| lookup l T.languages) ] [ text " " ]
+
+releaseTypeIcon : String -> Html m
+releaseTypeIcon t = abbr [ class ("icons rt"++t), title (Maybe.withDefault "" <| lookup t T.releaseTypes) ] [ text " " ]
diff --git a/elm/Lib/Util.elm b/elm/Lib/Util.elm
index 186cf365..b86fcbad 100644
--- a/elm/Lib/Util.elm
+++ b/elm/Lib/Util.elm
@@ -30,3 +30,8 @@ hasDuplicates l =
case List.foldr step (Just Dict.empty) l of
Nothing -> True
Just _ -> False
+
+
+-- Haskell's 'lookup' - find an entry in an association list
+lookup : a -> List (a,b) -> Maybe b
+lookup n l = List.filter (\(a,_) -> a == n) l |> List.head |> Maybe.map Tuple.second
diff --git a/elm/ULists/DateEdit.elm b/elm/UList/DateEdit.elm
index 98ccf5d0..dc6b18e8 100644
--- a/elm/ULists/DateEdit.elm
+++ b/elm/UList/DateEdit.elm
@@ -1,4 +1,4 @@
-module ULists.DateEdit exposing (main)
+module UList.DateEdit exposing (main)
import Html exposing (..)
import Html.Attributes exposing (..)
diff --git a/elm/ULists/LabelEdit.elm b/elm/UList/LabelEdit.elm
index b6a03de2..ce65e414 100644
--- a/elm/ULists/LabelEdit.elm
+++ b/elm/UList/LabelEdit.elm
@@ -1,4 +1,4 @@
-port module ULists.LabelEdit exposing (main)
+port module UList.LabelEdit exposing (main)
import Html exposing (..)
import Html.Attributes exposing (..)
@@ -24,7 +24,7 @@ main = Browser.element
, update = update
}
-port ulistsLabelChanged : Bool -> Cmd msg
+port ulistLabelChanged : Bool -> Cmd msg
type alias Model =
{ uid : Int
@@ -79,7 +79,7 @@ update msg model =
Saved l b (GApi.Success) ->
let nmodel = { model | sel = if b then Set.insert l model.sel else Set.remove l model.sel, state = Dict.remove l model.state }
public = List.any (\lb -> lb.id /= 7 && not lb.private && Set.member lb.id nmodel.sel) nmodel.labels
- in (nmodel, ulistsLabelChanged public)
+ in (nmodel, ulistLabelChanged public)
Saved l b e -> ({ model | state = Dict.insert l (Api.Error e) model.state }, Cmd.none)
diff --git a/elm/ULists/LabelEdit.js b/elm/UList/LabelEdit.js
index f1c0c278..6617bf11 100644
--- a/elm/ULists/LabelEdit.js
+++ b/elm/UList/LabelEdit.js
@@ -1,9 +1,9 @@
-var init = Elm.ULists.LabelEdit.init;
-Elm.ULists.LabelEdit.init = function(opt) {
+var init = Elm.UList.LabelEdit.init;
+Elm.UList.LabelEdit.init = function(opt) {
opt.flags.uid = pageVars.uid;
opt.flags.labels = pageVars.labels;
var app = init(opt);
- app.ports.ulistsLabelChanged.subscribe(function(pub) {
+ app.ports.ulistLabelChanged.subscribe(function(pub) {
var l = document.getElementById('ulist_public_'+opt.flags.vid);
l.setAttribute('data-publabel', pub?1:'');
l.classList.toggle('invisible', !((l.getAttribute('data-voted') && !pageVars.voteprivate) || l.getAttribute('data-publabel')))
diff --git a/elm/ULists/ManageLabels.elm b/elm/UList/ManageLabels.elm
index 1e953b0a..755c4e08 100644
--- a/elm/ULists/ManageLabels.elm
+++ b/elm/UList/ManageLabels.elm
@@ -1,4 +1,4 @@
-module ULists.ManageLabels exposing (main)
+module UList.ManageLabels exposing (main)
import Html exposing (..)
import Html.Attributes exposing (..)
diff --git a/elm/ULists/ManageLabels.js b/elm/UList/ManageLabels.js
index 1061a1e3..41ea1c12 100644
--- a/elm/ULists/ManageLabels.js
+++ b/elm/UList/ManageLabels.js
@@ -5,8 +5,8 @@ document.querySelectorAll('#managelabels').forEach(function(b) {
return false;
});
-var init = Elm.ULists.ManageLabels.init;
-Elm.ULists.ManageLabels.init = function(opt) {
+var init = Elm.UList.ManageLabels.init;
+Elm.UList.ManageLabels.init = function(opt) {
opt.flags = { uid: pageVars.uid, labels: pageVars.labels };
init(opt);
};
diff --git a/elm/UList/Opt.elm b/elm/UList/Opt.elm
new file mode 100644
index 00000000..22350b7c
--- /dev/null
+++ b/elm/UList/Opt.elm
@@ -0,0 +1,79 @@
+module UList.Opt exposing (main)
+
+import Html exposing (..)
+import Html.Attributes exposing (..)
+import Html.Events exposing (..)
+import Task
+import Process
+import Browser
+import Lib.Util exposing (..)
+import Lib.Html exposing (..)
+import Lib.Api as Api
+import Gen.Types as T
+import Gen.Api as GApi
+import Gen.UListVNOpt as GVO
+
+
+main : Program GVO.Send Model Msg
+main = Browser.element
+ { init = \f -> (init f, Cmd.none)
+ , subscriptions = always Sub.none
+ , view = view
+ , update = update
+ }
+
+type alias Model =
+ { state : Api.State
+ , flags : GVO.Send
+ , del : Bool
+ }
+
+init : GVO.Send -> Model
+init f =
+ { state = Api.Normal
+ , flags = f
+ , del = False
+ }
+
+type Msg
+ = Del Bool
+
+
+update : Msg -> Model -> (Model, Cmd Msg)
+update msg model =
+ case msg of
+ Del b -> ({ model | del = b }, Cmd.none)
+
+
+view : Model -> Html Msg
+view model =
+ let
+ opt =
+ [ tr []
+ [ td [ colspan 5 ]
+ [ textarea ([ placeholder "Notes", rows 2, cols 100 ] ++ GVO.valNotes) [ text model.flags.notes ]
+ , div [ ]
+ [ div [ class "spinner" ] []
+ , br_ 2
+ , a [ href "#", onClickD (Del True) ] [ text "Remove VN" ]
+ ]
+ ]
+ ]
+ , tfoot []
+ [ tr []
+ [ td [ colspan 5 ] [ a [ href "#" ] [ text "Add release" ] ] ]
+ ]
+ ]
+
+ rel i r =
+ tr []
+ [ if model.flags.own
+ then td [ class "tco1" ] [ a [ href "#" ] [ text "remove" ] ]
+ else text ""
+ , td [ class "tco2" ] [ text <| Maybe.withDefault "status" <| lookup r.status T.rlistStatus ]
+ , td [ class "tco3" ] [ text "2018-11-10" ]
+ , td [ class "tco4" ] <| List.map langIcon r.lang ++ [ releaseTypeIcon r.rtype ]
+ , td [ class "tco5" ] [ a [ href ("/r"++String.fromInt r.id), title r.original ] [ text r.title ] ]
+ ]
+
+ in table [] <| (if model.flags.own then opt else []) ++ List.indexedMap rel model.flags.rels
diff --git a/elm/ULists/VoteEdit.elm b/elm/UList/VoteEdit.elm
index 60814e5d..8007d648 100644
--- a/elm/ULists/VoteEdit.elm
+++ b/elm/UList/VoteEdit.elm
@@ -1,4 +1,4 @@
-port module ULists.VoteEdit exposing (main)
+port module UList.VoteEdit exposing (main)
import Html exposing (..)
import Html.Attributes exposing (..)
@@ -21,7 +21,7 @@ main = Browser.element
, update = update
}
-port ulistsVoteChanged : Bool -> Cmd msg
+port ulistVoteChanged : Bool -> Cmd msg
type alias Model =
{ state : Api.State
@@ -66,7 +66,7 @@ update msg model =
Saved GApi.Success ->
let flags = model.flags
nflags = { flags | vote = Just model.text }
- in ({ model | flags = nflags, state = Api.Normal }, ulistsVoteChanged (model.text /= "" && model.text /= "-"))
+ in ({ model | flags = nflags, state = Api.Normal }, ulistVoteChanged (model.text /= "" && model.text /= "-"))
Saved e -> ({ model | state = Api.Error e }, Cmd.none)
diff --git a/elm/ULists/VoteEdit.js b/elm/UList/VoteEdit.js
index 4a3e304c..99d5b31b 100644
--- a/elm/ULists/VoteEdit.js
+++ b/elm/UList/VoteEdit.js
@@ -1,7 +1,7 @@
-var init = Elm.ULists.VoteEdit.init;
-Elm.ULists.VoteEdit.init = function(opt) {
+var init = Elm.UList.VoteEdit.init;
+Elm.UList.VoteEdit.init = function(opt) {
var app = init(opt);
- app.ports.ulistsVoteChanged.subscribe(function(voted) {
+ app.ports.ulistVoteChanged.subscribe(function(voted) {
var l = document.getElementById('ulist_public_'+opt.flags.vid);
l.setAttribute('data-voted', voted?1:'');
l.classList.toggle('invisible', !((l.getAttribute('data-voted') && !pageVars.voteprivate) || l.getAttribute('data-publabel')))
diff --git a/elm/checkall.js b/elm/checkall.js
index 4343ffc8..5b7dc44e 100644
--- a/elm/checkall.js
+++ b/elm/checkall.js
@@ -5,12 +5,10 @@
* Checking that will synchronize all other checkboxes with name="$somename".
*/
document.querySelectorAll('input[type=checkbox].checkall').forEach(function(el) {
- el.onclick = function() {
+ el.addEventListener('click', function() {
document.querySelectorAll('input[type=checkbox][name="'+el.name+'"]').forEach(function(el2) {
- if(!el2.classList.contains('hidden')) {
- if(el2.checked != el.checked)
- el2.click();
- }
+ if(el2.checked != el.checked)
+ el2.click();
});
- };
+ });
});
diff --git a/elm/checkhidden.js b/elm/checkhidden.js
index 0f76d646..cfe2f8a2 100644
--- a/elm/checkhidden.js
+++ b/elm/checkhidden.js
@@ -5,9 +5,11 @@
* Checking that will toggle the 'hidden' class of all elements with the "$somename" class.
*/
document.querySelectorAll('input[type=checkbox].checkhidden').forEach(function(el) {
- el.onclick = function() {
+ var f = function() {
document.querySelectorAll('.'+el.value).forEach(function(el2) {
el2.classList.toggle('hidden', !el.checked);
});
};
+ f();
+ el.addEventListener('click', f);
});
diff --git a/lib/VNWeb/Elm.pm b/lib/VNWeb/Elm.pm
index 1cdfcb88..80487839 100644
--- a/lib/VNWeb/Elm.pm
+++ b/lib/VNWeb/Elm.pm
@@ -237,6 +237,8 @@ sub write_types {
$data .= def languages => 'List (String, String)' =>
list map tuple(string $_, string $LANGUAGE{$_}),
sort { $LANGUAGE{$a} cmp $LANGUAGE{$b} } keys %LANGUAGE;
+ $data .= def releaseTypes => 'List (String, String)' => list map tuple(string $_, string $RELEASE_TYPE{$_}), keys %RELEASE_TYPE;
+ $data .= def rlistStatus => 'List (Int, String)' => list map tuple($_, string $RLIST_STATUS{$_}), keys %RLIST_STATUS;
write_module Types => $data;
}
diff --git a/lib/VNWeb/User/Lists.pm b/lib/VNWeb/User/Lists.pm
index e745db71..0aa10630 100644
--- a/lib/VNWeb/User/Lists.pm
+++ b/lib/VNWeb/User/Lists.pm
@@ -13,10 +13,10 @@ my $LABELS = form_compile any => {
} }
};
-
elm_form 'ManageLabels', undef, $LABELS;
+
my $VNVOTE = form_compile any => {
uid => { id => 1 },
vid => { id => 1 },
@@ -26,6 +26,7 @@ my $VNVOTE = form_compile any => {
elm_form 'VoteEdit', undef, $VNVOTE;
+
my $VNLABELS = {
uid => { id => 1 },
vid => { id => 1 },
@@ -41,6 +42,7 @@ my $VNLABELS_IN = form_compile in => $VNLABELS;
elm_form 'LabelEdit', $VNLABELS_OUT, $VNLABELS_IN;
+
my $VNDATE = form_compile any => {
uid => { id => 1 },
vid => { id => 1 },
@@ -51,7 +53,28 @@ my $VNDATE = form_compile any => {
elm_form 'DateEdit', undef, $VNDATE;
-# TODO: Filters to find unlabeled VNs or VNs with notes?
+
+my $VNOPT = form_compile any => {
+ own => { anybool => 1 },
+ uid => { id => 1 },
+ vid => { id => 1 },
+ notes => { required => 0, default => '', maxlength => 2000 },
+ rels => { aoh => {
+ id => { id => 1 },
+ title => {},
+ original => {},
+ released => { uint => 1 },
+ rtype => {},
+ status => { uint => 1 },
+ lang => { type => 'array', values => {} },
+ } },
+};
+
+elm_form 'UListVNOpt', undef, $VNOPT;
+
+
+
+# TODO: Filters to find unlabeled VNs or VNs with/without notes?
sub filters_ {
my($own, $labels) = @_;
@@ -135,28 +158,30 @@ sub vn_ {
my @l = grep $labels{$_->{id}} && $_->{id} != 7, @$labels;
my $txt = @l ? join ', ', map $_->{label}, @l : '-';
if($own) {
- elm_ 'ULists.LabelEdit' => $VNLABELS_OUT, { vid => $v->{id}, selected => [ grep $_ != 7, $v->{labels}->@* ] }, $txt;
+ elm_ 'UList.LabelEdit' => $VNLABELS_OUT, { vid => $v->{id}, selected => [ grep $_ != 7, $v->{labels}->@* ] }, $txt;
} else {
txt_ $txt;
}
};
td_ mkclass(tc4 => 1, compact => $own, stealth => $own), sub {
txt_ fmtvote $v->{vote} if !$own;
- elm_ 'ULists.VoteEdit' => $VNVOTE, { uid => $uid, vid => $v->{id}, vote => fmtvote($v->{vote}) }, fmtvote $v->{vote} if $own;
+ elm_ 'UList.VoteEdit' => $VNVOTE, { uid => $uid, vid => $v->{id}, vote => fmtvote($v->{vote}) }, fmtvote $v->{vote} if $own;
};
td_ class => 'tc5', fmtdate $v->{added}, 'compact';
td_ class => 'tc6', sub {
txt_ $v->{started}||'' if !$own;
- elm_ 'ULists.DateEdit' => $VNDATE, { uid => $uid, vid => $v->{id}, date => $v->{started}||'', start => 1 }, $v->{started}||'' if $own;
+ elm_ 'UList.DateEdit' => $VNDATE, { uid => $uid, vid => $v->{id}, date => $v->{started}||'', start => 1 }, $v->{started}||'' if $own;
};
td_ class => 'tc7', sub {
txt_ $v->{finished}||'' if !$own;
- elm_ 'ULists.DateEdit' => $VNDATE, { uid => $uid, vid => $v->{id}, date => $v->{finished}||'', start => 0 }, $v->{finished}||'' if $own;
+ elm_ 'UList.DateEdit' => $VNDATE, { uid => $uid, vid => $v->{id}, date => $v->{finished}||'', start => 0 }, $v->{finished}||'' if $own;
};
};
tr_ mkclass(hidden => 1, 'collapsed_vid'.$v->{id} => 1, odd => $n % 2 == 0), sub {
- td_ colspan => 7, 'Options, releases and note stuff here (likely Elm)';
+ td_ colspan => 7, class => 'tc_opt', sub {
+ elm_ 'UList.Opt' => $VNOPT, { own => $own, uid => $uid, vid => $v->{id}, notes => $v->{notes}, rels => $v->{rels} };
+ };
};
}
@@ -191,7 +216,7 @@ sub listing_ {
enrich_flatten labels => id => vid => sql('SELECT vid, lbl FROM ulist_vns_labels WHERE uid =', \$uid, 'AND vid IN'), $lst;
enrich rels => id => vid => sub { sql '
- SELECT rv.vid, r.id, r.title, r.original, r.released, r.type, rl.status
+ SELECT rv.vid, r.id, r.title, r.original, r.released, r.type as rtype, rl.status
FROM rlists rl
JOIN releases r ON rl.rid = r.id
JOIN releases_vn rv ON rv.id = r.id
@@ -204,9 +229,7 @@ sub listing_ {
my sub url { '?'.query_encode %$opt, @_ }
- # TODO: In-line editable notes, remove-from-list
- # TODO: Releases
- # TODO: Thumbnail view
+ # TODO: Thumbnail view?
paginate_ \&url, $opt->{p}, [ $count, 50 ], 't';
div_ class => 'mainbox browse ulist', sub {
table_ sub {
@@ -229,7 +252,6 @@ sub listing_ {
}
-# TODO: Keep this URL? Steal /u+/list when that one's gone?
# TODO: Display something useful when all labels are private?
# TODO: Ability to add VNs from this page
TUWF::get qr{/$RE{uid}/ulist}, sub {
@@ -257,7 +279,7 @@ TUWF::get qr{/$RE{uid}/ulist}, sub {
div_ class => 'mainbox', sub {
h1_ $title;
$opt = filters_ $own, $labels;
- elm_ 'ULists.ManageLabels' if $own;
+ elm_ 'UList.ManageLabels' if $own;
};
listing_ $u->{id}, $own, $opt, $labels;
};