Skip to content

Commit 5ce2310

Browse files
committed
added movie_listing
SQUASHED: SQUASHED-AUTO-COMMIT-object-Set-AUTO-COMMIT-src-components-demo-movie-listing.html-AUTO-COMMIT-src-components-demo-movie-listing.js,
1 parent df1992d commit 5ce2310

File tree

2 files changed

+332
-0
lines changed

2 files changed

+332
-0
lines changed
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<template id="movie-listing" >
2+
<style data-src="/src/external/font-awesome/css/font-awesome.css"></style>
3+
<style data-src="/templates/livelystyle.css"></style>
4+
<style>
5+
:host {
6+
7+
}
8+
#content {
9+
10+
}
11+
12+
.poster img {
13+
width: 120px;
14+
}
15+
.poster {
16+
height: 185px;
17+
overflow: hidden;
18+
}
19+
20+
.movie {
21+
font-size: 10pt;
22+
text-align: center;
23+
padding: 10px;
24+
width: 160px;
25+
height: 270px;
26+
display: inline-block;
27+
overflow: hidden;
28+
}
29+
30+
.year {
31+
color: gray;
32+
}
33+
34+
.year.conflict {
35+
color: red;
36+
}
37+
38+
.genre {
39+
color: gray;
40+
font-style: italic;
41+
font-size:8pt;
42+
}
43+
.file {
44+
font-size:6pt;
45+
white-space: nowrap;
46+
}
47+
48+
.file .checkbox {
49+
position: relative;
50+
top: 4px;
51+
}
52+
</style>
53+
<div id="content">
54+
</div>
55+
</template>
56+
Lines changed: 276 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,276 @@
1+
import ContextMenu from 'src/client/contextmenu.js';
2+
import Morph from 'src/components/widgets/lively-morph.js';
3+
4+
export default class MovieListing extends Morph {
5+
6+
initialize() {
7+
8+
}
9+
10+
attachedCallback() {
11+
this.get("#content").innerHTML = ""
12+
var container = lively.query(this, "lively-container");
13+
this.createView(container).then(view => {
14+
this.get("#content").appendChild(view)
15+
})
16+
}
17+
18+
async createView(container) {
19+
20+
var dir = container.getDir()
21+
// "cached://" +
22+
var listSource = await fetch( dir + "/movies.jsonl").then(r => r.text())
23+
var selectedMoviesURL = dir + "/selected_movies"
24+
25+
this.selectedMovies = new Set()
26+
var selectedMoviesResp = await fetch(selectedMoviesURL)
27+
if (selectedMoviesResp.status == 200) {
28+
try {
29+
var selectedMoviesSource = await selectedMoviesResp.text()
30+
this.selectedMovies = new Set(selectedMoviesSource.split("\n"))
31+
lively.notify("loaded " + this.selectedMovies.size)
32+
} catch(e) {
33+
lively.error("Error loading selected movies", e)
34+
}
35+
} else {
36+
lively.notify("could not load selected movies")
37+
}
38+
39+
var files = listSource.split("\n").map(ea => {
40+
try {
41+
return JSON.parse(ea)
42+
} catch(e) {
43+
return null
44+
}
45+
}).filter(ea => ea)
46+
47+
48+
var movies = files
49+
.filter(ea => ea.imdb)
50+
.map(ea => ea.imdb)
51+
.uniq().map(ea => {
52+
var all =files.filter(file => file.imdb == ea)
53+
var first = all[0]
54+
first.files = all
55+
return first
56+
})
57+
.filter(ea => ea.year)
58+
59+
var genres = new Map()
60+
for(let movie of movies) {
61+
for(let genre of (movie.genre || "").split(/, /)) {
62+
var bag = genres.get(genre) || []
63+
bag.push(movie)
64+
genres.set(genre, bag)
65+
}
66+
}
67+
68+
let serverURL = lively.files.serverURL(dir)
69+
// does only make sense when accessing a localhost server,
70+
// otherwise a pdf viewer would be opened on a remote machine?
71+
72+
var style = document.createElement("style")
73+
style.textContent = `
74+
75+
76+
77+
`
78+
let playFile = (file) => {
79+
var url = dir + "/"+ encodeURI(file.filename)
80+
let playPath = url.replace(serverURL,"").replace(/^\//,"")
81+
var openURL = serverURL + "/_open/" + playPath
82+
lively.notify("open " + openURL)
83+
fetch(openURL)
84+
}
85+
86+
let selectFile = async (file, checkbox) => {
87+
if (checkbox.checked) {
88+
this.selectedMovies.add(file.filename)
89+
} else {
90+
this.selectedMovies.delete(file.filename)
91+
}
92+
saveSelectedMovies()
93+
}
94+
95+
let saveSelectedMovies = async () => {
96+
var newSource = Array.from(this.selectedMovies).sort().join("\n") + "\n"
97+
await lively.files.saveFile(selectedMoviesURL, newSource)
98+
lively.notify("updated selected movies")
99+
}
100+
101+
102+
this.movieItems = movies.map(movie => {
103+
var title = <a class="title" click={() => {
104+
lively.openInspector(movie)
105+
}}></a>
106+
title.innerHTML = movie.files[0].title // contains HTML
107+
108+
109+
if (movie.year == movie.extract_year) {
110+
var year = <span class="year">({movie.year})</span>
111+
} else {
112+
year = <span class="year conflict">({movie.extract_year})</span>
113+
}
114+
115+
var item = <div class="movie">
116+
<div class="poster">
117+
<img src={dir + "_imdb_/posters/" + movie.imdb+ ".jpg"}
118+
click={() => window.open("https://www.imdb.com/title/" + movie.imdb)}
119+
></img>
120+
</div>
121+
{title}
122+
{year}
123+
<span class="rating">({movie.rating})</span>
124+
<br />
125+
<span class="genre">{movie.files[0].genre || ""}</span>
126+
{... movie.files.map(file => {
127+
var checkbox = <input class="checkbox" type="checkbox"></input>
128+
if (this.selectedMovies.has(file.filename)) {
129+
checkbox.checked = true
130+
}
131+
132+
checkbox.addEventListener("click", evt => selectFile(file, checkbox))
133+
134+
var fileItem = <div class="file">{checkbox}<a click={() => {
135+
playFile(file)
136+
}}>{file.filename.replace(/.*\//,"")}</a></div>
137+
fileItem.addEventListener('contextmenu', evt => {
138+
if (!evt.shiftKey) {
139+
evt.stopPropagation();
140+
evt.preventDefault();
141+
var menu = new ContextMenu(fileItem, [
142+
["open", () => playFile(file)],
143+
[`rename`, () => container.renameFile(dir + file.filename, false)],
144+
]);
145+
menu.openIn(document.body, evt, fileItem);
146+
return true;
147+
}
148+
149+
}, false);
150+
151+
return fileItem
152+
153+
})}
154+
</div>
155+
156+
item.movie = movie
157+
return item
158+
});
159+
this.currentMovieItems = this.movieItems
160+
161+
162+
this.pane = <div class="movies">
163+
{...this.movieItems}
164+
</div>
165+
166+
167+
let sortBy = (func, reverse) => {
168+
this.pane.innerHTML = ""
169+
let items = this.currentMovieItems.sortBy(func)
170+
if(reverse) {
171+
items = items.reverse()
172+
}
173+
items.forEach(ea => {
174+
this.pane.appendChild(ea)
175+
})
176+
}
177+
let currentReverse=true
178+
179+
let sortByYear = () => {
180+
sortBy(ea => ea.movie.year, currentReverse)
181+
}
182+
183+
let sortByRating = () => {
184+
sortBy(ea => Number(ea.movie.rating) || 0 , currentReverse)
185+
186+
}
187+
188+
let filterGenre = (genre) => {
189+
this.setCurrentMovieItems(this.movieItems
190+
.sortBy(ea => ea.movie.year)
191+
.reverse()
192+
.filter(ea => ea.movie.genre && ea.movie.genre.match(genre)))
193+
}
194+
195+
196+
197+
this.navbar = container.get("lively-container-navbar")
198+
this.navbarDetails = this.navbar.get("#details")
199+
200+
let createGenreFilter = (genre) => {
201+
var bag = genres.get(genre)
202+
203+
var detailsItem = this.navbar.createDetailsItem(genre + " (" + bag.length+")")
204+
detailsItem.classList.add("subitem")
205+
detailsItem.classList.add("level2")
206+
this.navbarDetails.querySelector("ul").appendChild(detailsItem)
207+
detailsItem.addEventListener("click", () => filterGenre(genre))
208+
}
209+
210+
211+
212+
213+
214+
this.createSelectedMoviesFilter()
215+
this.createConflictingYearMoviesFilter()
216+
217+
for(let genre of genres.keys()) {
218+
createGenreFilter(genre)
219+
}
220+
221+
222+
var view = <div>
223+
{style}
224+
<div>
225+
<button click={() => sortByYear()}>by year</button>
226+
<button click={() => sortByRating()}>by rating</button>
227+
<button click={() => this.deselectAll()}>deselect all</button>
228+
</div>
229+
{this.pane}
230+
</div>
231+
view.model = this
232+
return view
233+
}
234+
235+
deselectAll() {
236+
this.selectedMovies = new Set()
237+
}
238+
239+
setCurrentMovieItems(items) {
240+
this.currentMovieItems = items
241+
this.pane.innerHTML = ""
242+
this.currentMovieItems.forEach(ea => {
243+
this.pane.appendChild(ea)
244+
})
245+
}
246+
247+
createSelectedMoviesFilter() {
248+
var detailsItem = this.navbar.createDetailsItem("_selected")
249+
detailsItem.classList.add("subitem")
250+
detailsItem.classList.add("level2")
251+
this.navbarDetails.querySelector("ul").appendChild(detailsItem)
252+
detailsItem.addEventListener("click", () => this.filterSelected())
253+
}
254+
255+
filterSelected() {
256+
this.setCurrentMovieItems(this.movieItems
257+
.sortBy(ea => ea.movie.year)
258+
.reverse()
259+
.filter(ea => this.selectedMovies.has(ea.movie.filename)))
260+
}
261+
262+
filterConflictingYear() {
263+
this.setCurrentMovieItems(this.movieItems
264+
.sortBy(ea => ea.movie.year)
265+
.reverse()
266+
.filter(ea => ea.movie.year != ea.movie.extract_year))
267+
}
268+
269+
createConflictingYearMoviesFilter(){
270+
var detailsItem = this.navbar.createDetailsItem("_conflicting")
271+
detailsItem.classList.add("subitem")
272+
detailsItem.classList.add("level2")
273+
this.navbarDetails.querySelector("ul").appendChild(detailsItem)
274+
detailsItem.addEventListener("click", () => this.filterConflictingYear())
275+
}
276+
}

0 commit comments

Comments
 (0)