css.py 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. import json
  2. import re
  3. from django.core.files.base import ContentFile
  4. from .utils import get_file_hash
  5. def create_css(theme, css):
  6. order = None
  7. if css_exists(theme, css):
  8. order = get_css_order(theme, css)
  9. delete_css(theme, css)
  10. save_css(theme, css, order)
  11. def css_exists(theme, css):
  12. return theme.css.filter(name=css.name).exists()
  13. def get_css_order(theme, css):
  14. return theme.css.get(name=css.name).order
  15. def delete_css(theme, css):
  16. theme.css.get(name=css.name).delete()
  17. def save_css(theme, css, order=None):
  18. if order is None:
  19. order = get_next_css_order(theme)
  20. theme.css.create(
  21. name=css.name,
  22. source_file=css,
  23. source_hash=get_file_hash(css),
  24. source_needs_building=css_needs_rebuilding(css),
  25. size=css.size,
  26. order=order,
  27. )
  28. def css_needs_rebuilding(css):
  29. css.seek(0)
  30. css_source = css.read().decode("utf-8")
  31. return "url(" in css_source
  32. def rebuild_css(theme, css):
  33. css_source = css.source_file.read()
  34. build_source = change_css_source(theme, css_source)
  35. if css.build_source:
  36. css.build_source.delete(save=False)
  37. build_file_name = css.name
  38. if css.source_hash in build_file_name:
  39. build_file_name = build_file_name.replace(".%s" % css.source_hash, "")
  40. build_file = ContentFile(build_source, build_file_name)
  41. css.build_file = build_file
  42. css.build_hash = get_file_hash(build_file)
  43. css.size = len(build_source.encode("utf-8"))
  44. css.save()
  45. CSS_URL_REGEX = re.compile(r"url\((.+)\)")
  46. def change_css_source(theme, css_source):
  47. media_map = get_theme_media_map(theme)
  48. url_replacer = get_url_replacer(media_map)
  49. return CSS_URL_REGEX.sub(url_replacer, css_source).strip()
  50. def get_theme_media_map(theme):
  51. media_map = {}
  52. for media in theme.media.all():
  53. escaped_url = json.dumps(media.file.url)
  54. media_map[media.name] = escaped_url
  55. media_filename = str(media.file).split("/")[-1]
  56. media_map[media_filename] = escaped_url
  57. return media_map
  58. def get_url_replacer(media_map):
  59. def replacer(matchobj):
  60. url = matchobj.group(1).strip("\"'").strip()
  61. if is_url_absolute(url):
  62. return matchobj.group(0)
  63. media_name = url.split("/")[-1]
  64. if media_name in media_map:
  65. return "url(%s)" % media_map[media_name]
  66. return matchobj.group(0)
  67. return replacer
  68. def is_url_absolute(url):
  69. if url.startswith("//") or url.startswith("://"):
  70. return True
  71. if url.lower().startswith("https://"):
  72. return True
  73. if url.lower().startswith("http://"):
  74. return True
  75. return False
  76. def get_next_css_order(theme):
  77. last_css = theme.css.order_by("order").last()
  78. if last_css:
  79. return last_css.order + 1
  80. return 0
  81. def move_css_up(theme, css):
  82. previous_css = theme.css.filter(order__lt=css.order).order_by("-order").first()
  83. if not previous_css:
  84. return False
  85. css.order, previous_css.order = previous_css.order, css.order
  86. css.save(update_fields=["order"])
  87. previous_css.save(update_fields=["order"])
  88. return True
  89. def move_css_down(theme, css):
  90. next_css = theme.css.filter(order__gt=css.order).order_by("order").first()
  91. if not next_css:
  92. return False
  93. css.order, next_css.order = next_css.order, css.order
  94. css.save(update_fields=["order"])
  95. next_css.save(update_fields=["order"])
  96. return True