You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

234 lines
8.0 KiB

11 years ago
import os
import re
11 years ago
import time
11 years ago
11 years ago
from couchpotato.core.event import addEvent, fireEvent
12 years ago
from couchpotato.core.helpers.encoding import ss
12 years ago
from couchpotato.core.helpers.variable import tryInt
from couchpotato.core.logger import CPLog
from couchpotato.core.plugins.base import Plugin
12 years ago
from couchpotato.environment import Env
11 years ago
from scss import Scss
from tornado.web import StaticFileHandler
11 years ago
log = CPLog(__name__)
autoload = 'ClientScript'
class ClientScript(Plugin):
12 years ago
core_static = {
'style': [
11 years ago
'style/main.scss',
12 years ago
'style/uniform.generic.css',
'style/uniform.css',
'style/settings.css',
],
'script': [
'scripts/library/mootools.js',
'scripts/library/mootools_more.js',
'scripts/library/uniform.js',
'scripts/library/form_replacement/form_check.js',
'scripts/library/form_replacement/form_radio.js',
'scripts/library/form_replacement/form_dropdown.js',
'scripts/library/form_replacement/form_selectoption.js',
'scripts/library/question.js',
'scripts/library/scrollspy.js',
'scripts/library/spin.js',
'scripts/library/Array.stableSort.js',
'scripts/library/async.js',
12 years ago
'scripts/couchpotato.js',
'scripts/api.js',
'scripts/library/history.js',
'scripts/page.js',
'scripts/block.js',
'scripts/block/navigation.js',
'scripts/block/footer.js',
'scripts/block/menu.js',
12 years ago
'scripts/page/home.js',
12 years ago
'scripts/page/settings.js',
'scripts/page/about.js',
],
}
11 years ago
watcher = None
11 years ago
paths = {'style': {}, 'script': {}}
12 years ago
comment = {
11 years ago
'style': '/*** %s:%d ***/\n',
'script': '// %s:%d\n'
}
html = {
'style': '<link rel="stylesheet" href="%s" type="text/css">',
'script': '<script type="text/javascript" src="%s"></script>',
}
def __init__(self):
addEvent('register_style', self.registerStyle)
addEvent('register_script', self.registerScript)
addEvent('clientscript.get_styles', self.getStyles)
addEvent('clientscript.get_scripts', self.getScripts)
11 years ago
addEvent('app.load', self.livereload, priority = 1)
addEvent('app.load', self.compile)
12 years ago
self.addCore()
11 years ago
def livereload(self):
if Env.get('dev'):
from livereload import Server
from livereload.watcher import Watcher
self.livereload_server = Server()
self.livereload_server.watch('%s/minified/*.css' % Env.get('cache_dir'))
self.livereload_server.watch('%s/*.css' % os.path.join(Env.get('app_dir'), 'couchpotato', 'static', 'style'))
self.watcher = Watcher()
fireEvent('schedule.interval', 'livereload.watcher', self.watcher.examine, seconds = .5)
self.livereload_server.serve(port = 35729)
12 years ago
def addCore(self):
for static_type in self.core_static:
for rel_path in self.core_static.get(static_type):
file_path = os.path.join(Env.get('app_dir'), 'couchpotato', 'static', rel_path)
core_url = 'static/%s' % rel_path
12 years ago
if static_type == 'script':
self.registerScript(core_url, file_path, position = 'front')
else:
self.registerStyle(core_url, file_path, position = 'front')
11 years ago
def compile(self):
12 years ago
# Create cache dir
cache = Env.get('cache_dir')
parent_dir = os.path.join(cache, 'minified')
self.makeDir(parent_dir)
Env.get('app').add_handlers(".*$", [(Env.get('web_base') + 'minified/(.*)', StaticFileHandler, {'path': parent_dir})])
12 years ago
for file_type in ['style', 'script']:
ext = 'js' if file_type is 'script' else 'css'
positions = self.paths.get(file_type, {})
for position in positions:
files = positions.get(position)
11 years ago
self._compile(file_type, files, position, position + '.' + ext)
12 years ago
11 years ago
def _compile(self, file_type, paths, position, out):
12 years ago
cache = Env.get('cache_dir')
out_name = out
11 years ago
minified_dir = os.path.join(cache, 'minified')
data_combined = ''
12 years ago
raw = []
new_paths = []
for x in paths:
file_path, urls = x
11 years ago
12 years ago
f = open(file_path, 'r').read()
11 years ago
# Compile scss
if file_path[-5:] == '.scss':
12 years ago
11 years ago
# Compile to css
compiler = Scss(live_errors = True, search_paths = [os.path.dirname(file_path)])
f = compiler.compile(f)
12 years ago
11 years ago
# Reload watcher
if Env.get('dev'):
self.watcher.watch(file_path, self.compile)
12 years ago
url_path = urls.get('original_url')
11 years ago
compiled_file_name = position + '_%s.css' % url_path.replace('/', '_').split('.scss')[0]
compiled_file_path = os.path.join(minified_dir, compiled_file_name)
self.createFile(compiled_file_path, f.strip())
12 years ago
11 years ago
# Remove scss path
urls['url'] = 'minified/%s?%s' % (compiled_file_name, tryInt(time.time()))
new_paths.append((file_path, urls))
12 years ago
11 years ago
if not Env.get('dev'):
12 years ago
11 years ago
if file_type == 'script':
data = f
else:
data = self.prefix(f)
data = data.replace('../images/', '../static/images/')
data = data.replace('../fonts/', '../static/fonts/')
data = data.replace('../../static/', '../static/') # Replace inside plugins
11 years ago
data_combined += self.comment.get(file_type) % (ss(file_path), int(os.path.getmtime(file_path)))
data_combined += data + '\n\n'
else:
new_paths.append(x)
11 years ago
# Combine all files together with some comments
if not Env.get('dev'):
out_path = os.path.join(minified_dir, out_name)
self.createFile(out_path, data_combined.strip())
11 years ago
minified_url = 'minified/%s?%s' % (out_name, tryInt(os.path.getmtime(out)))
new_paths.append((out_path, {'url': minified_url}))
self.paths[file_type][position] = new_paths
11 years ago
def getStyles(self, *args, **kwargs):
return self.get('style', *args, **kwargs)
12 years ago
11 years ago
def getScripts(self, *args, **kwargs):
return self.get('script', *args, **kwargs)
11 years ago
def get(self, type, location = 'head'):
paths = self.paths[type][location]
return [x[1].get('url', x[1].get('original_url')) for x in paths]
12 years ago
def registerStyle(self, api_path, file_path, position = 'head'):
self.register(api_path, file_path, 'style', position)
12 years ago
def registerScript(self, api_path, file_path, position = 'head'):
self.register(api_path, file_path, 'script', position)
12 years ago
def register(self, api_path, file_path, type, location):
api_path = '%s?%s' % (api_path, tryInt(os.path.getmtime(file_path)))
12 years ago
if not self.paths[type].get(location):
self.paths[type][location] = []
self.paths[type][location].append((file_path, {'original_url': api_path}))
prefix_properties = ['border-radius', 'transform', 'transition', 'box-shadow']
prefix_tags = ['ms', 'moz', 'webkit']
11 years ago
def prefix(self, data):
trimmed_data = re.sub('(\t|\n|\r)+', '', data)
new_data = ''
colon_split = trimmed_data.split(';')
for splt in colon_split:
curl_split = splt.strip().split('{')
for curly in curl_split:
curly = curly.strip()
for prop in self.prefix_properties:
if curly[:len(prop) + 1] == prop + ':':
for tag in self.prefix_tags:
new_data += ' -%s-%s; ' % (tag, curly)
new_data += curly + (' { ' if len(curl_split) > 1 else ' ')
new_data += '; '
new_data = new_data.replace('{ ;', '; ').replace('} ;', '} ')
return new_data