15
15
import base64
16
16
import traceback
17
17
from urllib .parse import urlparse
18
- from textwrap import dedent
19
18
20
19
import flask
21
20
64
63
65
64
from . import _pages
66
65
from ._pages import (
67
- _infer_module_name ,
68
- _parse_path_variables ,
69
66
_parse_query_string ,
67
+ _page_meta_tags ,
68
+ _path_to_page ,
69
+ _import_layouts_from_pages ,
70
70
)
71
71
72
72
# Add explicit mapping for map files
@@ -210,6 +210,9 @@ class Dash:
210
210
to be True. Default `None`.
211
211
:type use_pages: boolean
212
212
213
+ :param include_pages_meta: Include the page meta tags for twitter cards.
214
+ :type include_pages_meta: bool
215
+
213
216
:param assets_url_path: The local urls for assets will be:
214
217
``requests_pathname_prefix + assets_url_path + '/' + asset_path``
215
218
where ``asset_path`` is the path to a file inside ``assets_folder``.
@@ -348,6 +351,7 @@ def __init__( # pylint: disable=too-many-statements
348
351
assets_external_path = None ,
349
352
eager_loading = False ,
350
353
include_assets_files = True ,
354
+ include_pages_meta = True ,
351
355
url_base_pathname = None ,
352
356
requests_pathname_prefix = None ,
353
357
routes_pathname_prefix = None ,
@@ -418,6 +422,7 @@ def __init__( # pylint: disable=too-many-statements
418
422
extra_hot_reload_paths = extra_hot_reload_paths or [],
419
423
title = title ,
420
424
update_title = update_title ,
425
+ include_pages_meta = include_pages_meta ,
421
426
)
422
427
self .config .set_read_only (
423
428
[
@@ -854,67 +859,24 @@ def _generate_config_html(self):
854
859
def _generate_renderer (self ):
855
860
return f'<script id="_dash-renderer" type="application/javascript">{ self .renderer } </script>'
856
861
857
- def _generate_meta_html (self ):
858
- meta_tags = self . config . meta_tags
862
+ def _generate_meta (self ):
863
+ meta_tags = []
859
864
has_ie_compat = any (
860
- x .get ("http-equiv" , "" ) == "X-UA-Compatible" for x in meta_tags
865
+ x .get ("http-equiv" , "" ) == "X-UA-Compatible" for x in self . config . meta_tags
861
866
)
862
- has_charset = any ("charset" in x for x in meta_tags )
863
- has_viewport = any (x .get ("name" ) == "viewport" for x in meta_tags )
867
+ has_charset = any ("charset" in x for x in self . config . meta_tags )
868
+ has_viewport = any (x .get ("name" ) == "viewport" for x in self . config . meta_tags )
864
869
865
- tags = []
866
870
if not has_ie_compat :
867
- tags .append ('<meta http-equiv=" X-UA-Compatible" content=" IE=edge">' )
871
+ meta_tags .append ({ " http-equiv" : " X-UA-Compatible", " content" : " IE=edge"} )
868
872
if not has_charset :
869
- tags .append ('<meta charset=" UTF-8">' )
873
+ meta_tags .append ({ " charset" : " UTF-8"} )
870
874
if not has_viewport :
871
- tags .append (
872
- '<meta name=" viewport" content=" width=device-width, initial-scale=1">'
875
+ meta_tags .append (
876
+ { " name" : " viewport", " content" : " width=device-width, initial-scale=1"}
873
877
)
874
878
875
- tags += [format_tag ("meta" , x , opened = True ) for x in meta_tags ]
876
-
877
- return "\n " .join (tags )
878
-
879
- def _pages_meta_tags (self ):
880
- start_page , path_variables = self ._path_to_page (flask .request .path .strip ("/" ))
881
-
882
- # use the supplied image_url or create url based on image in the assets folder
883
- image = start_page .get ("image" , "" )
884
- if image :
885
- image = self .get_asset_url (image )
886
- assets_image_url = (
887
- "" .join ([flask .request .url_root , image .lstrip ("/" )]) if image else None
888
- )
889
- supplied_image_url = start_page .get ("image_url" )
890
- image_url = supplied_image_url if supplied_image_url else assets_image_url
891
-
892
- title = start_page .get ("title" , self .title )
893
- if callable (title ):
894
- title = title (** path_variables ) if path_variables else title ()
895
-
896
- description = start_page .get ("description" , "" )
897
- if callable (description ):
898
- description = (
899
- description (** path_variables ) if path_variables else description ()
900
- )
901
-
902
- return dedent (
903
- f"""
904
- <meta name="description" content="{ description } " />
905
- <!-- Twitter Card data -->
906
- <meta property="twitter:card" content="summary_large_image">
907
- <meta property="twitter:url" content="{ flask .request .url } ">
908
- <meta property="twitter:title" content="{ title } ">
909
- <meta property="twitter:description" content="{ description } ">
910
- <meta property="twitter:image" content="{ image_url } ">
911
- <!-- Open Graph data -->
912
- <meta property="og:title" content="{ title } " />
913
- <meta property="og:type" content="website" />
914
- <meta property="og:description" content="{ description } " />
915
- <meta property="og:image" content="{ image_url } ">
916
- """
917
- )
879
+ return meta_tags + self .config .meta_tags
918
880
919
881
# Serve the JS bundles for each package
920
882
def serve_component_suites (self , package_name , fingerprinted_path ):
@@ -959,14 +921,14 @@ def index(self, *args, **kwargs): # pylint: disable=unused-argument
959
921
scripts = self ._generate_scripts_html ()
960
922
css = self ._generate_css_dist_html ()
961
923
config = self ._generate_config_html ()
962
- metas = self ._generate_meta_html ()
924
+ metas = self ._generate_meta ()
963
925
renderer = self ._generate_renderer ()
964
926
965
927
# use self.title instead of app.config.title for backwards compatibility
966
928
title = self .title
967
- pages_metas = ""
968
- if self .use_pages :
969
- pages_metas = self . _pages_meta_tags ()
929
+
930
+ if self .use_pages and self . config . include_pages_meta :
931
+ metas = _page_meta_tags ( self ) + metas
970
932
971
933
if self ._favicon :
972
934
favicon_mod_time = os .path .getmtime (
@@ -983,8 +945,12 @@ def index(self, *args, **kwargs): # pylint: disable=unused-argument
983
945
opened = True ,
984
946
)
985
947
948
+ tags = "\n " .join (
949
+ format_tag ("meta" , x , opened = True , sanitize = True ) for x in metas
950
+ )
951
+
986
952
index = self .interpolate_index (
987
- metas = pages_metas + metas ,
953
+ metas = tags ,
988
954
title = title ,
989
955
css = css ,
990
956
config = config ,
@@ -1988,57 +1954,11 @@ def verify_url_part(served_part, url_part, part_name):
1988
1954
1989
1955
self .server .run (host = host , port = port , debug = debug , ** flask_run_options )
1990
1956
1991
- def _import_layouts_from_pages (self ):
1992
- for root , dirs , files in os .walk (self .config .pages_folder ):
1993
- dirs [:] = [
1994
- d for d in dirs if not d .startswith ("." ) and not d .startswith ("_" )
1995
- ]
1996
- for file in files :
1997
- if (
1998
- file .startswith ("_" )
1999
- or file .startswith ("." )
2000
- or not file .endswith (".py" )
2001
- ):
2002
- continue
2003
- page_path = os .path .join (root , file )
2004
- with open (page_path , encoding = "utf-8" ) as f :
2005
- content = f .read ()
2006
- if "register_page" not in content :
2007
- continue
2008
-
2009
- module_name = _infer_module_name (page_path )
2010
- spec = importlib .util .spec_from_file_location (module_name , page_path )
2011
- page_module = importlib .util .module_from_spec (spec )
2012
- spec .loader .exec_module (page_module )
2013
- sys .modules [module_name ] = page_module
2014
-
2015
- if (
2016
- module_name in _pages .PAGE_REGISTRY
2017
- and not _pages .PAGE_REGISTRY [module_name ]["supplied_layout" ]
2018
- ):
2019
- _validate .validate_pages_layout (module_name , page_module )
2020
- _pages .PAGE_REGISTRY [module_name ]["layout" ] = getattr (
2021
- page_module , "layout"
2022
- )
2023
-
2024
- @staticmethod
2025
- def _path_to_page (path_id ):
2026
- path_variables = None
2027
- for page in _pages .PAGE_REGISTRY .values ():
2028
- if page ["path_template" ]:
2029
- template_id = page ["path_template" ].strip ("/" )
2030
- path_variables = _parse_path_variables (path_id , template_id )
2031
- if path_variables :
2032
- return page , path_variables
2033
- if path_id == page ["path" ].strip ("/" ):
2034
- return page , path_variables
2035
- return {}, None
2036
-
2037
1957
def enable_pages (self ):
2038
1958
if not self .use_pages :
2039
1959
return
2040
1960
if self .pages_folder :
2041
- self . _import_layouts_from_pages ()
1961
+ _import_layouts_from_pages (self . config . pages_folder )
2042
1962
2043
1963
@self .server .before_request
2044
1964
def router ():
@@ -2060,9 +1980,7 @@ def update(pathname, search):
2060
1980
"""
2061
1981
2062
1982
query_parameters = _parse_query_string (search )
2063
- page , path_variables = self ._path_to_page (
2064
- self .strip_relative_path (pathname )
2065
- )
1983
+ page , path_variables = _path_to_page (self .strip_relative_path (pathname ))
2066
1984
2067
1985
# get layout
2068
1986
if page == {}:
0 commit comments