Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
D
django-iconify
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Deploy
Releases
Package Registry
Model registry
Operate
Terraform modules
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
AlekSIS®
Libraries
django-iconify
Commits
a83d2654
Verified
Commit
a83d2654
authored
4 years ago
by
Nik | Klampfradler
Browse files
Options
Downloads
Patches
Plain Diff
Add and update source comments and docstrings
parent
50d943b8
No related branches found
Branches containing commit
No related tags found
No related merge requests found
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
dj_iconify/conf.py
+1
-0
1 addition, 0 deletions
dj_iconify/conf.py
dj_iconify/types.py
+93
-5
93 additions, 5 deletions
dj_iconify/types.py
dj_iconify/util.py
+1
-0
1 addition, 0 deletions
dj_iconify/util.py
dj_iconify/views.py
+35
-10
35 additions, 10 deletions
dj_iconify/views.py
with
130 additions
and
15 deletions
dj_iconify/conf.py
+
1
−
0
View file @
a83d2654
"""
App configuration for django-iconify.
"""
from
django.conf
import
settings
from
django.conf
import
settings
_prefix
=
"
ICONIFY_
"
_prefix
=
"
ICONIFY_
"
...
...
This diff is collapsed.
Click to expand it.
dj_iconify/types.py
+
93
−
5
View file @
a83d2654
...
@@ -2,7 +2,7 @@
...
@@ -2,7 +2,7 @@
Documentation: https://docs.iconify.design/types/
Documentation: https://docs.iconify.design/types/
"""
"""
from
typing
import
Collection
,
Dict
,
List
,
Optional
,
Union
from
typing
import
Collection
,
Dict
,
List
,
Optional
,
Sequence
,
Union
from
typing.io
import
TextIO
from
typing.io
import
TextIO
import
json
import
json
...
@@ -10,6 +10,7 @@ from .util import split_css_unit
...
@@ -10,6 +10,7 @@ from .util import split_css_unit
class
IconifyOptional
:
class
IconifyOptional
:
"""
Mixin containing optional attributes all other types can contain.
"""
left
:
Optional
[
int
]
=
None
left
:
Optional
[
int
]
=
None
top
:
Optional
[
int
]
=
None
top
:
Optional
[
int
]
=
None
width
:
Optional
[
int
]
=
None
width
:
Optional
[
int
]
=
None
...
@@ -48,6 +49,10 @@ class IconifyOptional:
...
@@ -48,6 +49,10 @@ class IconifyOptional:
class
IconifyIcon
(
IconifyOptional
):
class
IconifyIcon
(
IconifyOptional
):
"""
Single icon as loaded from Iconify JSON data.
Documentation: https://docs.iconify.design/types/iconify-icon.html
"""
_collection
:
Optional
[
"
IconifyJSON
"
]
_collection
:
Optional
[
"
IconifyJSON
"
]
_name
:
str
_name
:
str
body
:
str
body
:
str
...
@@ -69,6 +74,11 @@ class IconifyIcon(IconifyOptional):
...
@@ -69,6 +74,11 @@ class IconifyIcon(IconifyOptional):
return
res
return
res
def
get_width
(
self
):
def
get_width
(
self
):
"""
Get the width of the icon.
If the icon has an explicit width, it is returned.
If not, the width set in the collection is returned, or the default of 16.
"""
if
self
.
width
:
if
self
.
width
:
return
self
.
width
return
self
.
width
elif
self
.
_collection
and
self
.
_collection
.
width
:
elif
self
.
_collection
and
self
.
_collection
.
width
:
...
@@ -77,6 +87,11 @@ class IconifyIcon(IconifyOptional):
...
@@ -77,6 +87,11 @@ class IconifyIcon(IconifyOptional):
return
16
return
16
def
get_height
(
self
):
def
get_height
(
self
):
"""
Get the height of the icon.
If the icon has an explicit height, it is returned.
If not, the height set in the collection is returned, or the default of 16.
"""
if
self
.
height
:
if
self
.
height
:
return
self
.
height
return
self
.
height
elif
self
.
_collection
and
self
.
_collection
.
height
:
elif
self
.
_collection
and
self
.
_collection
.
height
:
...
@@ -84,67 +99,112 @@ class IconifyIcon(IconifyOptional):
...
@@ -84,67 +99,112 @@ class IconifyIcon(IconifyOptional):
else
:
else
:
return
16
return
16
def
as_svg
(
self
,
color
:
Optional
[
str
]
=
None
,
width
:
Optional
[
str
]
=
None
,
height
:
Optional
[
str
]
=
None
,
rotate
:
Optional
[
str
]
=
None
,
flip
:
Optional
[
str
]
=
None
,
box
:
bool
=
False
)
->
str
:
def
as_svg
(
self
,
color
:
Optional
[
str
]
=
None
,
width
:
Optional
[
str
]
=
None
,
height
:
Optional
[
str
]
=
None
,
rotate
:
Optional
[
str
]
=
None
,
flip
:
Optional
[
Union
[
str
,
Sequence
]]
=
None
,
box
:
bool
=
False
)
->
str
:
"""
Generate a full SVG of this icon.
Some transformations can be applied by passing arguments:
width, height - Scale the icon; if only one is set and the other is not
(or set to
'
auto
'
), the other is calculated, preserving aspect ratio.
Suffixes (i.e. CSS units) are allowed
rotate - Either a degress value with
'
deg
'
suffix, or a number from 0 to 4
expressing the number of 90 degreee rotations
flip - horizontal, vertical, or both values with comma
box - Include a transparent box spanning the whole viewbox
Documentation: https://docs.iconify.design/types/iconify-icon.html
"""
# Original dimensions, the viewbox we use later
orig_width
,
orig_height
=
self
.
get_width
(),
self
.
get_height
()
orig_width
,
orig_height
=
self
.
get_width
(),
self
.
get_height
()
if
width
and
(
height
is
None
or
height
.
lower
()
==
"
auto
"
):
if
width
and
(
height
is
None
or
height
.
lower
()
==
"
auto
"
):
# Width given, determine height automatically
value
,
unit
=
split_css_unit
(
width
)
value
,
unit
=
split_css_unit
(
width
)
height
=
str
(
value
/
(
orig_width
/
orig_height
))
+
unit
height
=
str
(
value
/
(
orig_width
/
orig_height
))
+
unit
elif
height
and
(
width
is
None
or
width
.
lower
()
==
"
auto
"
):
elif
height
and
(
width
is
None
or
width
.
lower
()
==
"
auto
"
):
# Height given, determine width automatically
value
,
unit
=
split_css_unit
(
height
)
value
,
unit
=
split_css_unit
(
height
)
width
=
str
(
value
/
(
orig_height
/
orig_width
))
+
unit
width
=
str
(
value
/
(
orig_height
/
orig_width
))
+
unit
elif
width
is
None
and
height
is
None
:
elif
width
is
None
and
height
is
None
:
# Neither width nor height given, default to browser text size
width
,
height
=
"
1em
"
,
"
1em
"
width
,
height
=
"
1em
"
,
"
1em
"
# Build attributes to inject into <svg> element
svg_dim_attrs
=
f
'
width=
"
{
width
}
"
height=
"
{
height
}
"'
svg_dim_attrs
=
f
'
width=
"
{
width
}
"
height=
"
{
height
}
"'
head
=
f
'
<svg xmlns=
"
http://www.w3.org/2000/svg
"
xmlns:xlink=
"
http://www.w3.org/1999/xlink
"
{
svg_dim_attrs
}
preserveAspectRatio=
"
xMidYMid meet
"
viewBox=
"
0 0
{
orig_width
}
{
orig_height
}
"
style=
"
-ms-transform: rotate(360deg); -webkit-transform: rotate(360deg); transform: rotate(360deg);
"
>
'
# SVG root element (copied bluntly from example output on api.iconify.design)
head
=
(
'
<svg xmlns=
"
http://www.w3.org/2000/svg
"
xmlns:xlink=
"
http://www.w3.org/1999/xlink
"
'
f
'
{
svg_dim_attrs
}
'
'
preserveAspectRatio=
"
xMidYMid meet
"
'
f
'
viewBox=
"
0 0
{
orig_width
}
{
orig_height
}
"
'
'
style=
"
-ms-transform: rotate(360deg); -webkit-transform: rotate(360deg); transform: rotate(360deg);
"
>
'
)
foot
=
"
</svg>
"
foot
=
"
</svg>
"
# Build up all transformations, which are added as an SVG group (<g> element)
transform
=
[]
transform
=
[]
if
rotate
is
not
None
:
if
rotate
is
not
None
:
# Rotation will be around center of viewbox
center_x
,
center_y
=
int
(
orig_width
/
2
),
int
(
orig_height
/
2
)
center_x
,
center_y
=
int
(
orig_width
/
2
),
int
(
orig_height
/
2
)
if
rotate
.
isnumeric
():
if
rotate
.
isnumeric
():
# Plain number, calculate degrees in 90deg steps
deg
=
int
(
rotate
)
*
90
deg
=
int
(
rotate
)
*
90
elif
rotate
.
endswith
(
"
deg
"
):
elif
rotate
.
endswith
(
"
deg
"
):
deg
=
int
(
rotate
[:
-
3
])
deg
=
int
(
rotate
[:
-
3
])
transform
.
append
(
f
"
rotate(
{
deg
}
{
center_x
}
{
center_y
}
)
"
)
transform
.
append
(
f
"
rotate(
{
deg
}
{
center_x
}
{
center_y
}
)
"
)
if
flip
is
not
None
:
if
flip
is
not
None
:
flip
=
flip
.
split
(
"
,
"
)
if
isinstance
(
flip
,
str
):
# Split flip attribute if passed verbatim from request
flip
=
flip
.
split
(
"
,
"
)
# Seed with no-op values
translate_x
,
translate_y
=
0
,
0
translate_x
,
translate_y
=
0
,
0
scale_x
,
scale_y
=
1
,
1
scale_x
,
scale_y
=
1
,
1
if
"
horizontal
"
in
flip
:
if
"
horizontal
"
in
flip
:
# Flip around X axis
translate_x
=
orig_width
translate_x
=
orig_width
scale_x
=
-
1
scale_x
=
-
1
if
"
vertical
"
in
flip
:
if
"
vertical
"
in
flip
:
# Flip around Y axis
translate_y
=
orig_height
translate_y
=
orig_height
scale_y
=
-
1
scale_y
=
-
1
# Build transform functions for <g> attribute
transform
.
append
(
f
"
translate(
{
translate_x
}
{
translate_y
}
)
"
)
transform
.
append
(
f
"
translate(
{
translate_x
}
{
translate_y
}
)
"
)
transform
.
append
(
f
"
scale(
{
scale_x
}
{
scale_y
}
)
"
)
transform
.
append
(
f
"
scale(
{
scale_x
}
{
scale_y
}
)
"
)
if
transform
:
if
transform
:
# Generate a <g> attribute if any transformations were generated
transform
=
"
"
.
join
(
transform
)
transform
=
"
"
.
join
(
transform
)
g
=
f
'
<g transform=
"
{
transform
}
"
>
'
,
"
</g>
"
g
=
f
'
<g transform=
"
{
transform
}
"
>
'
,
"
</g>
"
else
:
else
:
# use dummy empty strings to make string building easier further down
g
=
""
,
""
g
=
""
,
""
# Body from icon data
body
=
self
.
body
body
=
self
.
body
if
color
is
not
None
:
if
color
is
not
None
:
# Color is replaced anywhere it appears as attribute value
# FIXME Find a better way to repalce only color values safely
body
=
body
.
replace
(
'"
currentColor
"'
,
f
'"
{
color
}
"'
)
body
=
body
.
replace
(
'"
currentColor
"'
,
f
'"
{
color
}
"'
)
if
box
:
if
box
:
# Add a transparent box spanning the whole viewbox for browsers that do not support viewbox
box
=
f
'
<rect x=
"
0
"
y=
"
0
"
width=
"
{
orig_width
}
"
height=
"
{
orig_height
}
"
fill=
"
rgba(0, 0, 0, 0)
"
/>
'
box
=
f
'
<rect x=
"
0
"
y=
"
0
"
width=
"
{
orig_width
}
"
height=
"
{
orig_height
}
"
fill=
"
rgba(0, 0, 0, 0)
"
/>
'
else
:
else
:
# Dummy empty string for easier string building further down
box
=
""
box
=
""
# Construct final SVG data
svg
=
f
"
{
head
}{
g
[
0
]
}{
body
}{
g
[
1
]
}{
box
}{
foot
}
"
svg
=
f
"
{
head
}{
g
[
0
]
}{
body
}{
g
[
1
]
}{
box
}{
foot
}
"
return
svg
return
svg
class
IconifyAlias
(
IconifyOptional
):
class
IconifyAlias
(
IconifyOptional
):
"""
Alias for an icon.
Documentation: https://docs.iconify.design/types/iconify-alias.html
"""
_collection
:
Optional
[
"
IconifyJSON
"
]
_collection
:
Optional
[
"
IconifyJSON
"
]
parent
:
str
parent
:
str
def
get_icon
(
self
):
def
get_icon
(
self
):
"""
Get the real icon by retrieving it from the parent collection, if any.
"""
if
self
.
_collection
:
if
self
.
_collection
:
return
self
.
_collection
.
get_icon
(
self
.
parent
)
return
self
.
_collection
.
get_icon
(
self
.
parent
)
...
@@ -165,6 +225,10 @@ class IconifyAlias(IconifyOptional):
...
@@ -165,6 +225,10 @@ class IconifyAlias(IconifyOptional):
class
IconifyInfo
(
IconifyOptional
):
class
IconifyInfo
(
IconifyOptional
):
"""
Meta information on a colelction.
No documentation; guessed from the JSON data provided by Iconify.
"""
name
:
str
name
:
str
author
:
Dict
[
str
,
str
]
# FIXME turn intoreal object
author
:
Dict
[
str
,
str
]
# FIXME turn intoreal object
license_
:
Dict
[
str
,
str
]
# FIXME turn into real object
license_
:
Dict
[
str
,
str
]
# FIXME turn into real object
...
@@ -174,6 +238,7 @@ class IconifyInfo(IconifyOptional):
...
@@ -174,6 +238,7 @@ class IconifyInfo(IconifyOptional):
@property
@property
def
total
(
self
):
def
total
(
self
):
"""
Determine icon count from parent collection.
"""
if
self
.
_collection
:
if
self
.
_collection
:
return
len
(
self
.
_collection
.
icons
)
return
len
(
self
.
_collection
.
icons
)
...
@@ -213,6 +278,10 @@ class IconifyInfo(IconifyOptional):
...
@@ -213,6 +278,10 @@ class IconifyInfo(IconifyOptional):
class
IconifyJSON
(
IconifyOptional
):
class
IconifyJSON
(
IconifyOptional
):
"""
One collection as a whole.
Documentation: https://docs.iconify.design/types/iconify-json.html
"""
prefix
:
str
prefix
:
str
icons
:
Dict
[
str
,
IconifyIcon
]
icons
:
Dict
[
str
,
IconifyIcon
]
aliases
:
Optional
[
Dict
[
str
,
IconifyAlias
]]
aliases
:
Optional
[
Dict
[
str
,
IconifyAlias
]]
...
@@ -220,6 +289,11 @@ class IconifyJSON(IconifyOptional):
...
@@ -220,6 +289,11 @@ class IconifyJSON(IconifyOptional):
not_found
:
List
[
str
]
not_found
:
List
[
str
]
def
get_icon
(
self
,
name
:
str
):
def
get_icon
(
self
,
name
:
str
):
"""
Get an icon by name.
First, tries to find a real icon with the name. If none is found, tries
to resolve the name from aliases.
"""
if
name
in
self
.
icons
.
keys
():
if
name
in
self
.
icons
.
keys
():
return
self
.
icons
[
name
]
return
self
.
icons
[
name
]
elif
name
in
self
.
aliases
.
keys
():
elif
name
in
self
.
aliases
.
keys
():
...
@@ -227,9 +301,16 @@ class IconifyJSON(IconifyOptional):
...
@@ -227,9 +301,16 @@ class IconifyJSON(IconifyOptional):
@classmethod
@classmethod
def
from_dict
(
cls
,
collection
:
Optional
[
dict
]
=
None
,
only
:
Optional
[
Collection
[
str
]]
=
None
)
->
"
IconifyJSON
"
:
def
from_dict
(
cls
,
collection
:
Optional
[
dict
]
=
None
,
only
:
Optional
[
Collection
[
str
]]
=
None
)
->
"
IconifyJSON
"
:
"""
Construct collection from a dictionary (probably from JSON, originally).
If the only parameter is passed a sequence or set, only icons and aliases with
these names are loaded (and real icons for aliases).
"""
if
collection
is
None
:
if
collection
is
None
:
# Load from a dummy empty collection
collection
=
{}
collection
=
{}
if
only
is
None
:
if
only
is
None
:
# Construct a list of all names from source collection
only
=
set
(
collection
[
"
icons
"
].
keys
())
only
=
set
(
collection
[
"
icons
"
].
keys
())
if
"
aliases
"
in
collection
:
if
"
aliases
"
in
collection
:
only
|=
set
(
collection
[
"
aliases
"
].
keys
())
only
|=
set
(
collection
[
"
aliases
"
].
keys
())
...
@@ -240,17 +321,23 @@ class IconifyJSON(IconifyOptional):
...
@@ -240,17 +321,23 @@ class IconifyJSON(IconifyOptional):
self
.
icons
,
self
.
aliases
=
{},
{}
self
.
icons
,
self
.
aliases
=
{},
{}
self
.
not_found
=
[]
self
.
not_found
=
[]
for
name
in
only
:
for
name
in
only
:
# Try to find a real icon with the name
icon_dict
=
collection
[
"
icons
"
].
get
(
name
,
None
)
icon_dict
=
collection
[
"
icons
"
].
get
(
name
,
None
)
if
icon_dict
:
if
icon_dict
:
self
.
icons
[
name
]
=
IconifyIcon
.
from_dict
(
name
,
icon_dict
,
collection
=
self
)
self
.
icons
[
name
]
=
IconifyIcon
.
from_dict
(
name
,
icon_dict
,
collection
=
self
)
continue
continue
# If we got here, try finding an alias with the name
alias_dict
=
collection
[
"
aliases
"
].
get
(
name
,
None
)
alias_dict
=
collection
[
"
aliases
"
].
get
(
name
,
None
)
if
alias_dict
:
if
alias_dict
:
self
.
aliases
[
name
]
=
IconifyAlias
.
from_dict
(
alias_dict
,
collection
=
self
)
self
.
aliases
[
name
]
=
IconifyAlias
.
from_dict
(
alias_dict
,
collection
=
self
)
# Make sure we also get the real icon to resolve the alias
self
.
icons
[
alias_dict
[
"
parent
"
]]
=
IconifyIcon
.
from_dict
(
alias_dict
[
"
parent
"
],
collection
[
"
icons
"
][
alias_dict
[
"
parent
"
]],
collection
=
self
)
self
.
icons
[
alias_dict
[
"
parent
"
]]
=
IconifyIcon
.
from_dict
(
alias_dict
[
"
parent
"
],
collection
[
"
icons
"
][
alias_dict
[
"
parent
"
]],
collection
=
self
)
continue
continue
# If we got here, track the we did not find the icon
# Undocumented, but the original API server seems to return this field in its
# response instead of throwing a 404 error or so
self
.
not_found
.
append
(
name
)
self
.
not_found
.
append
(
name
)
if
"
info
"
in
collection
:
if
"
info
"
in
collection
:
...
@@ -262,6 +349,7 @@ class IconifyJSON(IconifyOptional):
...
@@ -262,6 +349,7 @@ class IconifyJSON(IconifyOptional):
@classmethod
@classmethod
def
from_file
(
cls
,
src_file
:
Union
[
str
,
TextIO
]
=
None
,
**
kwargs
)
->
"
IconifyJSON
"
:
def
from_file
(
cls
,
src_file
:
Union
[
str
,
TextIO
]
=
None
,
**
kwargs
)
->
"
IconifyJSON
"
:
"""
Construct collection by reading a JSON file and calling from_dict.
"""
if
isinstance
(
src_file
,
str
):
if
isinstance
(
src_file
,
str
):
with
open
(
src_file
,
"
r
"
)
as
in_file
:
with
open
(
src_file
,
"
r
"
)
as
in_file
:
src
=
json
.
load
(
in_file
)
src
=
json
.
load
(
in_file
)
...
...
This diff is collapsed.
Click to expand it.
dj_iconify/util.py
+
1
−
0
View file @
a83d2654
"""
Utility code used by other parts of django-iconify.
"""
import
re
import
re
...
...
This diff is collapsed.
Click to expand it.
dj_iconify/views.py
+
35
−
10
View file @
a83d2654
"""
Iconify API endpoints as views.
Documentation: https://docs.iconify.design/sources/api/queries.html
"""
import
json
import
json
import
os
import
os
import
re
import
re
...
@@ -11,12 +15,24 @@ from .types import IconifyJSON
...
@@ -11,12 +15,24 @@ from .types import IconifyJSON
class
BaseJSONView
(
View
):
class
BaseJSONView
(
View
):
"""
Base view that wraps JSON and JSONP responses.
It relies on the following query parameters:
callback - name of the JavaScript callback function to call via JSONP
pretty - 1 or true to pretty-print JSON (default is condensed)
The URL route has to pass an argument called format_ containing js or json
to determine the output format.
"""
default_callback
:
str
=
"
Console.log
"
default_callback
:
str
=
"
Console.log
"
def
get_data
(
self
,
request
:
HttpRequest
)
->
dict
:
def
get_data
(
self
,
request
:
HttpRequest
)
->
dict
:
"""
Generate a dictionary contianing the data to return.
"""
raise
NotImplementedError
(
"
You must implement this method in your view.
"
)
raise
NotImplementedError
(
"
You must implement this method in your view.
"
)
def
get
(
self
,
request
:
HttpRequest
,
format_
:
str
=
"
json
"
,
*
args
,
**
kwargs
)
->
HttpResponse
:
def
get
(
self
,
request
:
HttpRequest
,
format_
:
str
=
"
json
"
,
*
args
,
**
kwargs
)
->
HttpResponse
:
"""
Get the JSON or JSONP response containing the data from the get_data method.
"""
# For JSONP, the callback name has to be passed
# For JSONP, the callback name has to be passed
if
format_
==
"
js
"
:
if
format_
==
"
js
"
:
callback
=
request
.
GET
.
get
(
"
callback
"
,
self
.
default_callback
)
callback
=
request
.
GET
.
get
(
"
callback
"
,
self
.
default_callback
)
...
@@ -27,27 +43,36 @@ class BaseJSONView(View):
...
@@ -27,27 +43,36 @@ class BaseJSONView(View):
else
:
else
:
indent
=
None
indent
=
None
# Call main function implemented by children
data
=
self
.
get_data
(
request
,
*
args
,
**
kwargs
)
data
=
self
.
get_data
(
request
,
*
args
,
**
kwargs
)
# Get result JSON and form response
# Get result JSON and form response
res
=
json
.
dumps
(
data
,
indent
=
indent
,
sort_keys
=
True
)
res
=
json
.
dumps
(
data
,
indent
=
indent
,
sort_keys
=
True
)
if
format_
==
"
js
"
:
if
format_
==
"
js
"
:
# Format is JSONP
res
=
f
"
{
callback
}
(
{
res
}
)
"
res
=
f
"
{
callback
}
(
{
res
}
)
"
return
HttpResponse
(
res
,
content_type
=
"
application/javascript
"
)
return
HttpResponse
(
res
,
content_type
=
"
application/javascript
"
)
else
:
else
:
# Format is plain JSON
return
HttpResponse
(
res
,
content_type
=
"
application/json
"
)
return
HttpResponse
(
res
,
content_type
=
"
application/json
"
)
class
ConfigView
(
View
):
class
ConfigView
(
View
):
"""
Get JavaScript snippet to conifugre Iconify for our API.
"""
"""
Get JavaScript snippet to conifugre Iconify for our API.
This sets the API base URL to the endpoint determined by Django
'
s reverse
URL mapper.
"""
def
get
(
self
,
request
:
HttpRequest
)
->
HttpResponse
:
def
get
(
self
,
request
:
HttpRequest
)
->
HttpResponse
:
# Guess the base URL by reverse-mapping the URL for a fake icon set
rev
=
reverse
(
"
iconify_json
"
,
kwargs
=
{
"
collection
"
:
"
prefix
"
,
"
format_
"
:
"
js
"
})
rev
=
reverse
(
"
iconify_json
"
,
kwargs
=
{
"
collection
"
:
"
prefix
"
,
"
format_
"
:
"
js
"
})
# Iconify SVG Framework expects placeholders {prefix} and {icons} in API URL
api_pattern
=
rev
[:
-
9
]
+
"
{prefix}.js?icons={icons}
"
api_pattern
=
rev
[:
-
9
]
+
"
{prefix}.js?icons={icons}
"
# Put together configuration as dict and output as JSON
config
=
{
config
=
{
"
defaultAPI
"
:
api_pattern
,
"
defaultAPI
"
:
api_pattern
,
}
}
config_json
=
json
.
dumps
(
config
)
config_json
=
json
.
dumps
(
config
)
return
HttpResponse
(
f
"
var IconifyConfig =
{
config_json
}
"
,
content_type
=
"
text/javascript
"
)
return
HttpResponse
(
f
"
var IconifyConfig =
{
config_json
}
"
,
content_type
=
"
text/javascript
"
)
...
@@ -55,7 +80,7 @@ class ConfigView(View):
...
@@ -55,7 +80,7 @@ class ConfigView(View):
class
CollectionView
(
BaseJSONView
):
class
CollectionView
(
BaseJSONView
):
"""
Retrieve the meta-data for a single collection.
"""
"""
Retrieve the meta-data for a single collection.
"""
def
get_data
(
self
,
request
:
HttpRequest
)
->
dict
:
def
get_data
(
self
,
request
:
HttpRequest
)
->
dict
:
#
Ic
on name
s are
passed
as comma-separated list
#
Collecti
on name
is
passed
in the prefix query parameter
collection
=
request
.
GET
.
get
(
"
prefix
"
,
None
)
collection
=
request
.
GET
.
get
(
"
prefix
"
,
None
)
if
collection
is
None
or
not
re
.
match
(
r
'
[A-Za-z0-9-]+
'
,
collection
):
if
collection
is
None
or
not
re
.
match
(
r
'
[A-Za-z0-9-]+
'
,
collection
):
return
HttpResponseBadRequest
(
"
You must provide a valid prefix name.
"
)
return
HttpResponseBadRequest
(
"
You must provide a valid prefix name.
"
)
...
@@ -67,12 +92,15 @@ class CollectionView(BaseJSONView):
...
@@ -67,12 +92,15 @@ class CollectionView(BaseJSONView):
except
FileNotFoundError
as
exc
:
except
FileNotFoundError
as
exc
:
raise
Http404
(
f
"
Icon collection
{
collection
}
not found
"
)
from
exc
raise
Http404
(
f
"
Icon collection
{
collection
}
not found
"
)
from
exc
# Return the info member, which holds the data we want
return
icon_set
.
info
.
as_dict
()
return
icon_set
.
info
.
as_dict
()
class
CollectionsView
(
BaseJSONView
):
class
CollectionsView
(
BaseJSONView
):
"""
Retrieve the available collections with meta-data.
"""
"""
Retrieve the available collections with meta-data.
"""
def
get_data
(
self
,
request
:
HttpRequest
)
->
dict
:
def
get_data
(
self
,
request
:
HttpRequest
)
->
dict
:
# Read the pre-compiled collections list and return it verbatim
# FIXME Consider using type models to generate from sources
collections_path
=
os
.
path
.
join
(
JSON_ROOT
,
"
collections.json
"
)
collections_path
=
os
.
path
.
join
(
JSON_ROOT
,
"
collections.json
"
)
with
open
(
collections_path
,
"
r
"
)
as
collections_file
:
with
open
(
collections_path
,
"
r
"
)
as
collections_file
:
data
=
json
.
load
(
collections_file
)
data
=
json
.
load
(
collections_file
)
...
@@ -84,11 +112,6 @@ class IconifyJSONView(BaseJSONView):
...
@@ -84,11 +112,6 @@ class IconifyJSONView(BaseJSONView):
default_callback
:
str
=
"
SimpleSVG._loaderCallback
"
default_callback
:
str
=
"
SimpleSVG._loaderCallback
"
def
get_data
(
self
,
request
:
HttpRequest
,
collection
:
str
)
->
dict
:
def
get_data
(
self
,
request
:
HttpRequest
,
collection
:
str
)
->
dict
:
"""
Retrieve a set of icons using a GET request.
The view supports both JSON and JSONP responses.
"""
# Icon names are passed as comma-separated list
# Icon names are passed as comma-separated list
icons
=
request
.
GET
.
get
(
"
icons
"
,
None
)
icons
=
request
.
GET
.
get
(
"
icons
"
,
None
)
if
icons
is
not
None
:
if
icons
is
not
None
:
...
@@ -105,9 +128,11 @@ class IconifyJSONView(BaseJSONView):
...
@@ -105,9 +128,11 @@ class IconifyJSONView(BaseJSONView):
class
IconifySVGView
(
View
):
class
IconifySVGView
(
View
):
"""
Serve the Iconify SVG retrieval API.
"""
"""
Serve the Iconify SVG retrieval API.
It serves a single icon as SVG, allowing some transformations.
"""
def
get
(
self
,
request
:
HttpRequest
,
collection
:
str
,
name
:
str
)
->
HttpResponse
:
def
get
(
self
,
request
:
HttpRequest
,
collection
:
str
,
name
:
str
)
->
HttpResponse
:
"""
Retrieve a single icon as SVG.
"""
# General retrieval parameters
# General retrieval parameters
download
=
request
.
GET
.
get
(
"
download
"
,
"
0
"
).
lower
()
in
(
"
1
"
,
"
true
"
)
download
=
request
.
GET
.
get
(
"
download
"
,
"
0
"
).
lower
()
in
(
"
1
"
,
"
true
"
)
box
=
request
.
GET
.
get
(
"
box
"
,
"
0
"
).
lower
()
in
(
"
1
"
,
"
true
"
)
box
=
request
.
GET
.
get
(
"
box
"
,
"
0
"
).
lower
()
in
(
"
1
"
,
"
true
"
)
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment