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 get_theme_media_map(theme):
  33. media_map = {}
  34. for media in theme.media.all():
  35. escaped_url = json.dumps(media.file.url)
  36. media_map[media.name] = escaped_url
  37. media_filename = str(media.file).split("/")[-1]
  38. media_map[media_filename] = escaped_url
  39. return media_map
  40. def rebuild_css(media_map, css):
  41. if css.build_file:
  42. css.build_file.delete(save=False)
  43. css_source = css.source_file.read().decode("utf-8")
  44. build_source = change_css_source(media_map, css_source).encode("utf-8")
  45. build_file_name = css.name
  46. if css.source_hash in build_file_name:
  47. build_file_name = build_file_name.replace(".%s" % css.source_hash, "")
  48. build_file = ContentFile(build_source, build_file_name)
  49. css.build_file = build_file
  50. css.build_hash = get_file_hash(build_file)
  51. css.size = len(build_source)
  52. css.save()
  53. CSS_URL_REGEX = re.compile(r"url\((.+)\)")
  54. def change_css_source(media_map, css_source):
  55. url_replacer = get_url_replacer(media_map)
  56. return CSS_URL_REGEX.sub(url_replacer, css_source).strip()
  57. def get_url_replacer(media_map):
  58. def replacer(matchobj):
  59. url = matchobj.group(1).strip("\"'").strip()
  60. if is_url_absolute(url):
  61. return matchobj.group(0)
  62. media_name = url.split("/")[-1]
  63. if media_name in media_map:
  64. return "url(%s)" % media_map[media_name]
  65. return matchobj.group(0)
  66. return replacer
  67. def is_url_absolute(url):
  68. if url.startswith("//") or url.startswith("://"):
  69. return True
  70. if url.lower().startswith("https://"):
  71. return True
  72. if url.lower().startswith("http://"):
  73. return True
  74. return False
  75. def get_next_css_order(theme):
  76. last_css = theme.css.order_by("order").last()
  77. if last_css:
  78. return last_css.order + 1
  79. return 0
  80. def move_css_up(theme, css):
  81. previous_css = theme.css.filter(order__lt=css.order).order_by("-order").first()
  82. if not previous_css:
  83. return False
  84. css.order, previous_css.order = previous_css.order, css.order
  85. css.save(update_fields=["order"])
  86. previous_css.save(update_fields=["order"])
  87. return True
  88. def move_css_down(theme, css):
  89. next_css = theme.css.filter(order__gt=css.order).order_by("order").first()
  90. if not next_css:
  91. return False
  92. css.order, next_css.order = next_css.order, css.order
  93. css.save(update_fields=["order"])
  94. next_css.save(update_fields=["order"])
  95. return True