Skip to content

Commit ba5c375

Browse files
jukentKevin Paul
and
Kevin Paul
authored
Adding tutorial content videos (#147)
* Add tutorial recordings to resource gallery * Add thumbnails from youtube videos * Update thumbnails * Add thumbnails to correct path * Delete ptss-cartopy.jpeg * Delete ptss-dask1.jpeg * Delete ptss-oop.jpeg * Delete ptss-geocatviz.jpeg * Delete ptss-firstpackage.jpeg * Delete ptss-git.png * Delete ptss-txtfile.jpeg * Delete ptss-xarray1.jpeg * Delete ptss-writingfx.jpeg * Delete ptss-dask2.jpeg * Delete ptss-datadict.jpeg * Delete ptss-pandas.jpeg * Delete ptss-matplotlib.jpeg * Delete ptss-numpy.jpeg * Delete ptss-xarray2.jpeg * Delete ptss-geocatplot.jpeg * Delete ptss-jupyter.jpeg * Fix indent * update blackdoc v0.3.4 * Add videos * Add data viz domain tag * Add thumbnails * Add thumbnails for git * delete images in wrong directory * revert changes * add links to github repos in description * fix links with href * fix remaining links * use truncate to fix html * add truncatehtml to setup.cfg * update pre-commit * pre-commit * rm raw_input * del sys * Update portal/_extensions/truncatehtml.py Co-authored-by: Kevin Paul <[email protected]> * content sp Co-authored-by: Kevin Paul <[email protected]>
1 parent a877ff6 commit ba5c375

23 files changed

+497
-5
lines changed

.pre-commit-config.yaml

+3-3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ repos:
1010
- id: double-quote-string-fixer
1111

1212
- repo: https://github.com/ambv/black
13-
rev: 21.6b0
13+
rev: 21.9b0
1414
hooks:
1515
- id: black
1616

@@ -29,7 +29,7 @@ repos:
2929
hooks:
3030
- id: seed-isort-config
3131
- repo: https://github.com/pre-commit/mirrors-isort
32-
rev: v5.8.0
32+
rev: v5.9.3
3333
hooks:
3434
- id: isort
3535

@@ -39,7 +39,7 @@ repos:
3939
# - id: prettier
4040

4141
- repo: https://github.com/nbQA-dev/nbQA
42-
rev: 0.13.0
42+
rev: 1.1.1
4343
hooks:
4444
- id: nbqa-black
4545
additional_dependencies: [black==20.8b1]

portal/_extensions/truncatehtml.py

+179
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
#!/usr/bin/env python
2+
3+
# Copyright (c) 2015 Eric Entzel
4+
5+
# Permission is hereby granted, free of charge, to any person obtaining a copy
6+
# of this software and associated documentation files (the "Software"), to deal
7+
# in the Software without restriction, including without limitation the rights
8+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
# copies of the Software, and to permit persons to whom the Software is
10+
# furnished to do so, subject to the following conditions:
11+
12+
# The above copyright notice and this permission notice shall be included in all
13+
# copies or substantial portions of the Software.
14+
15+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
# SOFTWARE.
22+
23+
from __future__ import print_function
24+
25+
END = -1
26+
27+
# HTML5 void-elements that do not require a closing tag
28+
# https://html.spec.whatwg.org/multipage/syntax.html#void-elements
29+
VOID_ELEMENTS = (
30+
'area',
31+
'base',
32+
'br',
33+
'col',
34+
'embed',
35+
'hr',
36+
'img',
37+
'input',
38+
'link',
39+
'meta',
40+
'param',
41+
'source',
42+
'track',
43+
'wbr',
44+
)
45+
46+
47+
class UnbalancedError(Exception):
48+
pass
49+
50+
51+
class OpenTag:
52+
def __init__(self, tag, rest=''):
53+
self.tag = tag
54+
self.rest = rest
55+
56+
def as_string(self):
57+
return '<' + self.tag + self.rest + '>'
58+
59+
60+
class CloseTag(OpenTag):
61+
def as_string(self):
62+
return '</' + self.tag + '>'
63+
64+
65+
class SelfClosingTag(OpenTag):
66+
pass
67+
68+
69+
class Tokenizer:
70+
def __init__(self, input):
71+
self.input = input
72+
self.counter = 0 # points at the next unconsumed character of the input
73+
74+
def __next_char(self):
75+
self.counter += 1
76+
return self.input[self.counter]
77+
78+
def next_token(self):
79+
try:
80+
char = self.input[self.counter]
81+
self.counter += 1
82+
if char == '&':
83+
return self.__entity()
84+
elif char != '<':
85+
return char
86+
elif self.input[self.counter] == '/':
87+
self.counter += 1
88+
return self.__close_tag()
89+
else:
90+
return self.__open_tag()
91+
except IndexError:
92+
return END
93+
94+
def __entity(self):
95+
"""Return a token representing an HTML character entity.
96+
Precondition: self.counter points at the charcter after the &
97+
Postcondition: self.counter points at the character after the ;
98+
"""
99+
char = self.input[self.counter]
100+
entity = ['&']
101+
while char != ';':
102+
entity.append(char)
103+
char = self.__next_char()
104+
entity.append(';')
105+
self.counter += 1
106+
return ''.join(entity)
107+
108+
def __open_tag(self):
109+
"""Return an open/close tag token.
110+
Precondition: self.counter points at the first character of the tag name
111+
Postcondition: self.counter points at the character after the <tag>
112+
"""
113+
char = self.input[self.counter]
114+
tag = []
115+
rest = []
116+
while char != '>' and char != ' ':
117+
tag.append(char)
118+
char = self.__next_char()
119+
while char != '>':
120+
rest.append(char)
121+
char = self.__next_char()
122+
if self.input[self.counter - 1] == '/':
123+
self.counter += 1
124+
return SelfClosingTag(''.join(tag), ''.join(rest))
125+
elif ''.join(tag) in VOID_ELEMENTS:
126+
self.counter += 1
127+
return SelfClosingTag(''.join(tag), ''.join(rest))
128+
else:
129+
self.counter += 1
130+
return OpenTag(''.join(tag), ''.join(rest))
131+
132+
def __close_tag(self):
133+
"""Return an open/close tag token.
134+
Precondition: self.counter points at the first character of the tag name
135+
Postcondition: self.counter points at the character after the <tag>
136+
"""
137+
char = self.input[self.counter]
138+
tag = []
139+
while char != '>':
140+
tag.append(char)
141+
char = self.__next_char()
142+
self.counter += 1
143+
return CloseTag(''.join(tag))
144+
145+
146+
def truncate(str, target_len, ellipsis=''):
147+
"""Returns a copy of str truncated to target_len characters,
148+
preserving HTML markup (which does not count towards the length).
149+
Any tags that would be left open by truncation will be closed at
150+
the end of the returned string. Optionally append ellipsis if
151+
the string was truncated."""
152+
stack = [] # open tags are pushed on here, then popped when the matching close tag is found
153+
retval = [] # string to be returned
154+
length = 0 # number of characters (not counting markup) placed in retval so far
155+
tokens = Tokenizer(str)
156+
tok = tokens.next_token()
157+
while tok != END:
158+
if length >= target_len and tok == ' ':
159+
retval.append(ellipsis)
160+
break
161+
if tok.__class__.__name__ == 'OpenTag':
162+
stack.append(tok)
163+
retval.append(tok.as_string())
164+
elif tok.__class__.__name__ == 'CloseTag':
165+
if stack[-1].tag == tok.tag:
166+
stack.pop()
167+
retval.append(tok.as_string())
168+
else:
169+
raise UnbalancedError(tok.as_string())
170+
elif tok.__class__.__name__ == 'SelfClosingTag':
171+
retval.append(tok.as_string())
172+
else:
173+
retval.append(tok)
174+
length += 1
175+
tok = tokens.next_token()
176+
while len(stack) > 0:
177+
tok = CloseTag(stack.pop().tag)
178+
retval.append(tok.as_string())
179+
return ''.join(retval)

portal/_extensions/yaml_gallery_generator.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from textwrap import dedent
44

55
import yaml
6+
from truncatehtml import truncate
67

78

89
def _tag_in_item(item, tag_str=None):
@@ -117,7 +118,9 @@ def build_from_items(items, filename, title='Gallery', subtitle=None, menu_html=
117118
short_description = item['description']
118119
modal_str = ''
119120
else:
120-
short_description = item['description'][:max_descr_len] + ' <a class="modal-btn">...more</a>'
121+
short_description = truncate(
122+
item['description'], max_descr_len, ellipsis='<a class="modal-btn"> ...more</a>'
123+
)
121124
modal_str = f"""
122125
<div class="modal">
123126
<div class="content">
Loading
7.01 KB
Loading
7.25 KB
Loading
7.7 KB
Loading
6.18 KB
Loading
7.21 KB
Loading
6.16 KB
Loading
7.28 KB
Loading
47.3 KB
Loading
9.34 KB
Loading
6.49 KB
Loading
10.7 KB
Loading
5.93 KB
Loading
5.81 KB
Loading
8.19 KB
Loading
5.88 KB
Loading
8.62 KB
Loading
7.59 KB
Loading

0 commit comments

Comments
 (0)