Skip to content

Commit ba5c375

Browse files
jukentKevin Paul
andauthored
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

Lines changed: 3 additions & 3 deletions
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

Lines changed: 179 additions & 0 deletions
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

Lines changed: 4 additions & 1 deletion
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">
9.46 KB
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

0 commit comments

Comments
 (0)