From 856b495995be279888eb7844d78e1931a85cfc09 Mon Sep 17 00:00:00 2001 From: Ruud Date: Mon, 4 Feb 2013 21:48:02 +0100 Subject: [PATCH] Minifier --- couchpotato/core/_base/clientscript/main.py | 128 ++++- couchpotato/core/plugins/base.py | 2 +- couchpotato/core/plugins/file/main.py | 2 +- couchpotato/static/scripts/library/prefix_free.js | 22 +- couchpotato/static/style/page/settings.css | 651 ---------------------- couchpotato/static/style/settings.css | 651 ++++++++++++++++++++++ couchpotato/templates/_desktop.html | 43 +- libs/minify/__init__.py | 0 libs/minify/cssmin.py | 223 ++++++++ libs/minify/jsmin.py | 218 ++++++++ 10 files changed, 1237 insertions(+), 703 deletions(-) delete mode 100644 couchpotato/static/style/page/settings.css create mode 100644 couchpotato/static/style/settings.css create mode 100644 libs/minify/__init__.py create mode 100644 libs/minify/cssmin.py create mode 100644 libs/minify/jsmin.py diff --git a/couchpotato/core/_base/clientscript/main.py b/couchpotato/core/_base/clientscript/main.py index bb380be..e8624b0 100644 --- a/couchpotato/core/_base/clientscript/main.py +++ b/couchpotato/core/_base/clientscript/main.py @@ -1,15 +1,58 @@ from couchpotato.core.event import addEvent +from couchpotato.core.helpers.variable import tryInt from couchpotato.core.logger import CPLog from couchpotato.core.plugins.base import Plugin +from couchpotato.environment import Env +from minify.cssmin import cssmin +from minify.jsmin import jsmin +import os log = CPLog(__name__) class ClientScript(Plugin): - urls = { - 'style': {}, - 'script': {}, + core_static = { + 'style': [ + 'style/main.css', + 'style/uniform.generic.css', + 'style/uniform.css', + 'style/settings.css', + ], + 'script': [ + 'scripts/library/mootools.js', + 'scripts/library/mootools_more.js', + 'scripts/library/prefix_free.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/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', + 'scripts/page/wanted.js', + 'scripts/page/settings.js', + 'scripts/page/about.js', + 'scripts/page/manage.js', + ], + } + + + urls = {'style': {}, 'script': {}, } + minified = {'style': {}, 'script': {}, } + paths = {'style': {}, 'script': {}, } + comment = { + 'style': '/*** %s:%d ***/\n', + 'script': '// %s:%d\n' } html = { @@ -24,6 +67,66 @@ class ClientScript(Plugin): addEvent('clientscript.get_styles', self.getStyles) addEvent('clientscript.get_scripts', self.getScripts) + addEvent('app.load', self.minify) + + self.addCore() + + 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 = 'api/%s/static/%s?%s' % (Env.setting('api_key'), rel_path, tryInt(os.path.getmtime(file_path))) + + if static_type == 'script': + self.registerScript(core_url, file_path, position = 'front') + else: + self.registerStyle(core_url, file_path, position = 'front') + + + def minify(self): + + 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) + self._minify(file_type, files, position, position + '.' + ext) + + def _minify(self, file_type, files, position, out): + + cache = Env.get('cache_dir') + out_name = 'minified_' + out + out = os.path.join(cache, out_name) + + raw = [] + for file_path in files: + f = open(file_path, 'r').read() + + if file_type == 'script': + data = jsmin(f) + else: + data = cssmin(f) + data = data.replace('../images/', '../static/images/') + + raw.append({'file': file_path, 'date': int(os.path.getmtime(file_path)), 'data': data}) + + # Combine all files together with some comments + data = '' + for r in raw: + data += self.comment.get(file_type) % (r.get('file'), r.get('date')) + data += r.get('data') + '\n\n' + + self.createFile(out, data.strip()) + + if not self.minified.get(file_type): + self.minified[file_type] = {} + if not self.minified[file_type].get(position): + self.minified[file_type][position] = [] + + minified_url = 'api/%s/file.cache/%s?%s' % (Env.setting('api_key'), out_name, tryInt(os.path.getmtime(out))) + self.minified[file_type][position].append(minified_url) + def getStyles(self, *args, **kwargs): return self.get('style', *args, **kwargs) @@ -35,22 +138,27 @@ class ClientScript(Plugin): data = '' if as_html else [] try: + if Env.get('dev'): + return self.minified[type][location] + return self.urls[type][location] except Exception, e: log.error(e) return data - def registerStyle(self, path, position = 'head'): - self.register(path, 'style', position) + def registerStyle(self, api_path, file_path, position = 'head'): + self.register(api_path, file_path, 'style', position) - def registerScript(self, path, position = 'head'): - self.register(path, 'script', position) + def registerScript(self, api_path, file_path, position = 'head'): + self.register(api_path, file_path, 'script', position) - def register(self, filepath, type, location): + def register(self, api_path, file_path, type, location): if not self.urls[type].get(location): self.urls[type][location] = [] + self.urls[type][location].append(api_path) - filePath = filepath - self.urls[type][location].append(filePath) + if not self.paths[type].get(location): + self.paths[type][location] = [] + self.paths[type][location].append(file_path) diff --git a/couchpotato/core/plugins/base.py b/couchpotato/core/plugins/base.py index 73a2c30..edecaa9 100644 --- a/couchpotato/core/plugins/base.py +++ b/couchpotato/core/plugins/base.py @@ -64,7 +64,7 @@ class Plugin(object): for f in glob.glob(os.path.join(self.plugin_path, 'static', '*')): ext = getExt(f) if ext in ['js', 'css']: - fireEvent('register_%s' % ('script' if ext in 'js' else 'style'), path + os.path.basename(f)) + fireEvent('register_%s' % ('script' if ext in 'js' else 'style'), path + os.path.basename(f), f) def showStatic(self, filename): d = os.path.join(self.plugin_path, 'static') diff --git a/couchpotato/core/plugins/file/main.py b/couchpotato/core/plugins/file/main.py index a9eab33..0dc0178 100644 --- a/couchpotato/core/plugins/file/main.py +++ b/couchpotato/core/plugins/file/main.py @@ -71,7 +71,7 @@ class FileManager(Plugin): db = get_session() for root, dirs, walk_files in os.walk(Env.get('cache_dir')): for filename in walk_files: - if root == python_cache: continue + if root == python_cache or 'minified' in filename: continue file_path = os.path.join(root, filename) f = db.query(File).filter(File.path == toUnicode(file_path)).first() if not f: diff --git a/couchpotato/static/scripts/library/prefix_free.js b/couchpotato/static/scripts/library/prefix_free.js index 8dd99e2..b6d9812 100644 --- a/couchpotato/static/scripts/library/prefix_free.js +++ b/couchpotato/static/scripts/library/prefix_free.js @@ -24,6 +24,9 @@ var self = window.StyleFix = { var url = link.href || link.getAttribute('data-href'), base = url.replace(/[^\/]+$/, ''), + base_scheme = (/^[a-z]{3,10}:/.exec(base) || [''])[0], + base_domain = (/^[a-z]{3,10}:\/\/[^\/]+/.exec(base) || [''])[0], + base_query = /^([^?]*)\??/.exec(url)[1], parent = link.parentNode, xhr = new XMLHttpRequest(), process; @@ -43,12 +46,23 @@ var self = window.StyleFix = { // Convert relative URLs to absolute, if needed if(base) { css = css.replace(/url\(\s*?((?:"|')?)(.+?)\1\s*?\)/gi, function($0, quote, url) { - if(!/^([a-z]{3,10}:|\/|#)/i.test(url)) { // If url not absolute & not a hash + if(/^([a-z]{3,10}:|#)/i.test(url)) { // Absolute & or hash-relative + return $0; + } + else if(/^\/\//.test(url)) { // Scheme-relative // May contain sequences like /../ and /./ but those DO work + return 'url("' + base_scheme + url + '")'; + } + else if(/^\//.test(url)) { // Domain-relative + return 'url("' + base_domain + url + '")'; + } + else if(/^\?/.test(url)) { // Query-relative + return 'url("' + base_query + url + '")'; + } + else { + // Path-relative return 'url("' + base + url + '")'; } - - return $0; }); // behavior URLs shoudn’t be converted (Issue #19) @@ -470,4 +484,4 @@ root.className += ' ' + self.prefix; StyleFix.register(self.prefixCSS); -})(document.documentElement); +})(document.documentElement); \ No newline at end of file diff --git a/couchpotato/static/style/page/settings.css b/couchpotato/static/style/page/settings.css deleted file mode 100644 index bcd0b77..0000000 --- a/couchpotato/static/style/page/settings.css +++ /dev/null @@ -1,651 +0,0 @@ -.page.settings:after { - content: "."; - display: block; - clear: both; - visibility: hidden; - line-height: 0; - height: 0; -} - - .page.settings .tabs { - float: left; - width: 20%; - font-size: 20px; - text-align: right; - list-style: none; - padding: 40px 0; - margin: 0; - min-height: 470px; - background-image: -*-linear-gradient( - 20deg, - rgba(0,0,0,0) 50%, - rgba(0,0,0,0.3) 100% - ); - } - .page.settings .tabs a { - display: block; - padding: 7px 15px; - font-weight: normal; - transition: all 0.3s ease-in-out; - color: rgba(255, 255, 255, 0.8); - text-shadow: none; - } - .page.settings .tabs a:hover, - .page.settings .tabs .active a { - background: rgb(78, 89, 105); - color: #fff; - } - .page.settings .tabs > li { - border-bottom: 1px solid rgb(78, 89, 105); - } - - .page.settings .tabs .subtabs { - list-style: none; - padding: 0; - margin: -5px 0 10px; - } - - .page.settings .tabs .subtabs a { - font-size: 13px; - padding: 0 15px; - font-weight: normal; - transition: all .3s ease-in-out; - color: rgba(255, 255, 255, 0.7); - } - - .page.settings .tabs .subtabs .active a { - color: #fff; - background: rgb(78, 89, 105); - } - - - .page.settings .containers { - width: 80%; - float: left; - padding: 20px 2%; - min-height: 300px; - } - - .page .advanced { - display: none; - color: #edc07f; - } - .page.show_advanced .advanced { display: block; } - - .page.settings .tab_content { - display: none; - } - .page.settings .tab_content.active { display: block; } - - .page fieldset { - padding: 10px 0; - } - .page fieldset h2 { - font-weight: normal; - font-size: 25px; - padding: 0 9px 10px 30px; - margin: 0; - border-bottom: 1px solid #333; - box-shadow: 0 1px 0px rgba(255,255,255, 0.15); - } - .page fieldset h2 .hint { - font-size: 12px; - margin-left: 10px; - } - .page fieldset h2 .hint a { - margin: 0 !important; - padding: 0; - } - - .page fieldset.disabled .ctrlHolder { - display: none; - } - .page fieldset > .ctrlHolder:first-child { - display: block; - padding: 0; - width: auto; - margin: 0; - position: relative; - margin-bottom: -23px; - border: none; - width: 20px; - } - - .page .ctrlHolder { - line-height: 25px; - padding: 10px 10px 10px 30px; - font-size: 14px; - border: 0; - } - .page .ctrlHolder.save_success:not(:first-child) { - background: url('../../images/icon.check.png') no-repeat 7px center; - } - .page .ctrlHolder:last-child { border: none; } - .page .ctrlHolder:hover { background-color: rgba(255,255,255,0.05); } - .page .ctrlHolder.focused { background-color: rgba(255,255,255,0.2); } - .page .ctrlHolder.focused:first-child, .page .ctrlHolder:first-child{ background-color: transparent; } - - .page .ctrlHolder .formHint { - width: 47%; - margin: -18px 0; - padding: 0; - color: #fff !important; - display: inline-block; - vertical-align: middle; - padding-left: 2%; - } - - .page .check + .formHint { - float: none; - width: auto; - display: inline-block; - padding-left: 1% !important; - height: 24px; - vertical-align: middle; - } - - .page .ctrlHolder label { - font-weight: bold; - width: 20%; - margin: 0; - padding: 6px 0 0; - } - - .page .xsmall { width: 20px !important; text-align: center; } - - .page .enabler { - display: block; - } - - .page .option_list { - margin-bottom: 20px; - } - - .page .option_list .enabler { - padding: 0; - margin-left: 5px !important; - } - - .page .option_list .enabler:not(.disabled) { - margin: 0 0 0 30px; - } - - .page .option_list .enabler:not(.disabled) .ctrlHolder:first-child { - margin: 10px 0 -33px 0; - } - - .page .option_list h3 { - padding: 0; - margin: 10px 5px 0; - text-align: center; - font-weight: normal; - text-shadow: none; - text-transform: uppercase; - font-size: 12px; - background: rgba(255,255,255,0.03); - } - - .page .option_list .enabler.disabled { - display: inline-block; - margin: 3px 3px 3px 20px; - padding: 4px 0; - width: 173px; - vertical-align: top; - } - - .page .option_list .enabler.disabled h2 { - border: none; - box-shadow: none; - padding: 0 10px 0 25px; - font-size: 16px; - } - - .page .option_list .enabler:not(.disabled) h2 { - font-size: 16px; - font-weight: bold; - border: none; - border-top: 1px solid rgba(255,255,255, 0.15); - box-shadow: 0 -1px 0px #333; - margin: 0; - padding: 10px 0 5px 25px; - } - .page .option_list .enabler:not(.disabled):first-child h2 { - border: none; - box-shadow: none; - } - - .page .option_list .enabler.disabled h2 .hint { - display: none; - } - .page .option_list .enabler h2 .hint { - font-weight: normal; - } - - .page input[type=text], .page input[type=password] { - padding: 5px 3px; - margin: 0; - width: 30%; - border-radius: 3px; - } - .page .input.xsmall { width: 5% } - .page .input.small { width: 10% } - .page .input.medium { width: 15% } - .page .input.large { width: 25% } - .page .input.xlarge { width: 30% } - - .page .advanced_toggle { - clear: both; - display: block; - text-align: right; - height: 20px; - margin: 0; - } - .page .advanced_toggle span { padding: 0 5px; } - .page.show_advanced .advanced_toggle { - color: #edc07f; - } - - .page .directory { - display: inline-block; - padding: 0 4% 0 4px; - font-size: 13px; - width: 30%; - background-image: url('../../images/icon.folder.gif'); - background-repeat: no-repeat; - background-position: 97% center; - overflow: hidden; - vertical-align: top; - } - .page .directory > span { - height: 25px; - display: inline-block; - float: right; - text-align: right; - white-space: nowrap; - cursor: pointer; - } - - .page .directory_list { - z-index: 2; - position: absolute; - width: 450px; - margin: 28px 0 20px 18%; - background: #5c697b; - border-radius: 3px; - box-shadow: 0 0 50px rgba(0,0,0,0.55); - } - - .page .directory_list .pointer { - border-right: 6px solid transparent; - border-left: 6px solid transparent; - border-bottom: 6px solid #5c697b; - display: block; - position: absolute; - width: 0px; - margin: -6px 0 0 22%; - } - - .page .directory_list ul { - width: 92%; - height: 300px; - overflow: auto; - margin: 0 4%; - font-size: 16px; - } - - .page .directory_list li { - padding: 4px 10px; - cursor: pointer; - margin: 0 !important; - border-top: 1px solid rgba(255,255,255,0.1); - background: url('../../images/right.arrow.png') no-repeat 98% center; - } - .page .directory_list li:last-child { - border-bottom: 1px solid rgba(255,255,255,0.1); - } - - .page .directory_list li:hover { - background-color: #515c68; - } - - .page .directory_list li.empty { - background: none; - height: 100px; - text-align: center; - font-style: italic; - border: none; - line-height: 100px; - cursor: default; - color: #BBB; - text-shadow: none; - font-size: 12px; - } - - .page .directory_list .actions { - clear: both; - padding: 4% 4% 2%; - min-height: 25px; - } - - .page .directory_list .actions label { - float: right; - width: auto; - padding: 0; - } - .page .directory_list .actions .inlay { - margin: -2px 0 0 7px; - } - - .page .directory_list .actions .back { - font-weight: bold; - width: 160px; - display: inline-block; - padding: 0; - line-height: 120%; - vertical-align: top; - } - - .page .directory_list .actions:last-child { - float: right; - padding: 4%; - } - - .page .directory_list .actions:last-child > span { - padding: 0 5px; - text-shadow: none; - } - - .page .directory_list .actions:last-child > .clear { - left: -90%; - position: relative; - background-color: #af3128; -} - - .page .directory_list .actions:last-child > .cancel { - font-weight: bold; - color: #ddd; - } - - .page .directory_list .actions:last-child > .save { - background: #9dc156; - } - - - .page .multi_directory.is_empty .delete { - visibility: hidden; - } - - .page .multi_directory .delete { - display: none; - } - .page .multi_directory:hover .delete { - display: inline-block; - width: 22px; - height: 24px; - vertical-align: top; - background-position: center; - margin-left: 5px; - } - - - .page .tag_input select { - width: 20%; - display: inline-block; - } - - .page .tag_input .selection { - border-radius: 0 10px 10px 0; - height: 26px; - } - - .page .tag_input > input { - display: none; - } - - .page .tag_input > ul { - list-style: none; - border-radius: 3px; - cursor: text; - width: 30%; - margin: 0 !important; - min-height: 27px; - line-height: 0; - display: inline-block; - } - .page .tag_input:hover > ul { - border-radius: 3px 0 0 3px; - } - .page .tag_input:hover .formHint { display: none; } - - .page .tag_input > ul > li { - display: inline-block; - min-height: 20px; - min-width: 2px; - font-size: 12px; - padding: 0; - margin: 4px 0 0 !important; - border-width: 0; - background: 0; - line-height: 20px; - } - .page .tag_input > ul > li:first-child { min-width: 4px; } - .page .tag_input li.choice { - cursor: -moz-grab; - cursor: -webkit-grab; - cursor: grab; - padding: 0; - border-radius: 2px; - } - .page .tag_input > ul:hover > li.choice { - background: -*-linear-gradient( - 270deg, - rgba(255,255,255,0.3) 0%, - rgba(255,255,255,0.1) 100% - ); - } - .page .tag_input > ul > li.choice:hover, - .page .tag_input > ul > li.choice.selected { - background: -*-linear-gradient( - 270deg, - #5b9bd1 0%, - #406db8 100% - ); - } - - .page .tag_input .select { - display: none; - } - .page .tag_input:hover .select { display: inline-block; } - - .page .tag_input li input { - background: 0; - border: 0; - color: #fff; - outline-width: 0; - padding: 0; - min-width: 2px; - } - .page .tag_input li:first-child input { - padding-left: 2px; - min-width: 0; - } - - .page .tag_input li:not(.choice) span { - white-space: pre; - position: absolute; - top: -9999px; - } - - .page .tag_input .delete { - display: none; - height: 10px; - width: 16px; - position: absolute; - margin: -9px 0 0 -16px; - border-radius: 30px 30px 0 0; - cursor: pointer; - background: url('../../images/icon.delete.png') no-repeat center 2px, -*-linear-gradient( - 270deg, - #5b9bd1 0%, - #5b9bd1 100% - ); - background-size: 65%; - } - .page .tag_input .choice:hover .delete, - .page .tag_input .choice.selected .delete { display: inline-block; } - .page .tag_input .choice .delete:hover { - height: 14px; - margin-top: -13px; - } - - .page .combined_table .head { - margin: 0 0 0 60px; - } - .page .disabled .head { display: none; } - .page .combined_table .head abbr { - display: inline-block; - font-weight: bold; - border-bottom: 1px dotted #fff; - line-height: 140%; - cursor: help; - } - .page .combined_table .head abbr.use, .page .combined_table .head abbr.automation_urls_use { - display: none; - } - .page .combined_table .head abbr.host { - margin-right: 197px; - } - - .page .combined_table .ctrlHolder { - padding-top: 2px; - padding-bottom: 3px; - } - .page .combined_table .ctrlHolder.hide { display: none; } - - .page .combined_table .ctrlHolder > * { - margin: 0 10px 0 0; - } - - .page .combined_table .ctrlHolder .delete { - display: none; - width: 22px; - height: 22px; - vertical-align: middle; - background-position: left center; - } - .page .combined_table .ctrlHolder:hover .delete { - display: inline-block; - } - - .page .combined_table .ctrlHolder.is_empty .delete, .page.settings .combined_table .ctrlHolder.is_empty .check { - visibility: hidden; -} - - .page .tab_about .usenet { - padding: 20px 30px 0; - font-size: 17px; - } - - .page .tab_about .usenet a { - padding: 0 5px; - } - - .page .tab_about .usenet ul { - float: left; - width: 50%; - margin: 10px 0; - padding: 0; - } - - .page .tab_about .usenet li { - background: url('../../images/icon.check.png') no-repeat left center; - padding: 0 0 0 25px; - } - - .page .tab_about .donate { - float: left; - width: 42%; - text-align: center; - font-size: 17px; - padding: 0 0 0 4%; - margin: 20px 0 0; - border-left: 1px solid #333; - box-shadow: -1px 0 0 rgba(255,255,255, 0.15); - } - .page .tab_about .donate form { - padding: 10px 0 0; - } - - .page .tab_about .info { - padding: 20px 30px; - margin: 0; - overflow: hidden; - } - - .page .tab_about .info dt { - clear: both; - float: left; - width: 17%; - font-weight: bold; - } - - .page .tab_about .info dd { - float: right; - width: 80%; - padding: 0; - margin: 0; - font-style: italic; - } - .page .tab_about .info dd.version { cursor: pointer; } - - .page .tab_about .group_actions > div { - padding: 30px; - text-align: center; - } - - .page .tab_about .group_actions a { - margin: 0 10px; - font-size: 20px; - } - -.group_userscript { - background: center bottom no-repeat; - min-height: 360px; - font-size: 20px; - font-weight: normal; -} - - .group_userscript h2 .hint { - display: block; - margin: 0 !important; - } - - .group_userscript .userscript { - float: left; - margin: 14px 0 0 25px; - height: 36px; - line-height: 25px; - } - - .group_userscript .or { - float: left; - margin: 20px -10px 0 10px; - } - - .group_userscript .bookmarklet { - display: block; - display: block; - float: left; - padding: 20px 15px 0 25px; - border-radius: 5px; - } - - .group_userscript .bookmarklet span { - margin-left: 10px; - display: inline-block; - } - -.active .group_imdb_automation:not(.disabled) { - background: url('../../images/imdb_watchlist.png') no-repeat right 50px; - min-height: 210px; -} \ No newline at end of file diff --git a/couchpotato/static/style/settings.css b/couchpotato/static/style/settings.css new file mode 100644 index 0000000..bcd0b77 --- /dev/null +++ b/couchpotato/static/style/settings.css @@ -0,0 +1,651 @@ +.page.settings:after { + content: "."; + display: block; + clear: both; + visibility: hidden; + line-height: 0; + height: 0; +} + + .page.settings .tabs { + float: left; + width: 20%; + font-size: 20px; + text-align: right; + list-style: none; + padding: 40px 0; + margin: 0; + min-height: 470px; + background-image: -*-linear-gradient( + 20deg, + rgba(0,0,0,0) 50%, + rgba(0,0,0,0.3) 100% + ); + } + .page.settings .tabs a { + display: block; + padding: 7px 15px; + font-weight: normal; + transition: all 0.3s ease-in-out; + color: rgba(255, 255, 255, 0.8); + text-shadow: none; + } + .page.settings .tabs a:hover, + .page.settings .tabs .active a { + background: rgb(78, 89, 105); + color: #fff; + } + .page.settings .tabs > li { + border-bottom: 1px solid rgb(78, 89, 105); + } + + .page.settings .tabs .subtabs { + list-style: none; + padding: 0; + margin: -5px 0 10px; + } + + .page.settings .tabs .subtabs a { + font-size: 13px; + padding: 0 15px; + font-weight: normal; + transition: all .3s ease-in-out; + color: rgba(255, 255, 255, 0.7); + } + + .page.settings .tabs .subtabs .active a { + color: #fff; + background: rgb(78, 89, 105); + } + + + .page.settings .containers { + width: 80%; + float: left; + padding: 20px 2%; + min-height: 300px; + } + + .page .advanced { + display: none; + color: #edc07f; + } + .page.show_advanced .advanced { display: block; } + + .page.settings .tab_content { + display: none; + } + .page.settings .tab_content.active { display: block; } + + .page fieldset { + padding: 10px 0; + } + .page fieldset h2 { + font-weight: normal; + font-size: 25px; + padding: 0 9px 10px 30px; + margin: 0; + border-bottom: 1px solid #333; + box-shadow: 0 1px 0px rgba(255,255,255, 0.15); + } + .page fieldset h2 .hint { + font-size: 12px; + margin-left: 10px; + } + .page fieldset h2 .hint a { + margin: 0 !important; + padding: 0; + } + + .page fieldset.disabled .ctrlHolder { + display: none; + } + .page fieldset > .ctrlHolder:first-child { + display: block; + padding: 0; + width: auto; + margin: 0; + position: relative; + margin-bottom: -23px; + border: none; + width: 20px; + } + + .page .ctrlHolder { + line-height: 25px; + padding: 10px 10px 10px 30px; + font-size: 14px; + border: 0; + } + .page .ctrlHolder.save_success:not(:first-child) { + background: url('../../images/icon.check.png') no-repeat 7px center; + } + .page .ctrlHolder:last-child { border: none; } + .page .ctrlHolder:hover { background-color: rgba(255,255,255,0.05); } + .page .ctrlHolder.focused { background-color: rgba(255,255,255,0.2); } + .page .ctrlHolder.focused:first-child, .page .ctrlHolder:first-child{ background-color: transparent; } + + .page .ctrlHolder .formHint { + width: 47%; + margin: -18px 0; + padding: 0; + color: #fff !important; + display: inline-block; + vertical-align: middle; + padding-left: 2%; + } + + .page .check + .formHint { + float: none; + width: auto; + display: inline-block; + padding-left: 1% !important; + height: 24px; + vertical-align: middle; + } + + .page .ctrlHolder label { + font-weight: bold; + width: 20%; + margin: 0; + padding: 6px 0 0; + } + + .page .xsmall { width: 20px !important; text-align: center; } + + .page .enabler { + display: block; + } + + .page .option_list { + margin-bottom: 20px; + } + + .page .option_list .enabler { + padding: 0; + margin-left: 5px !important; + } + + .page .option_list .enabler:not(.disabled) { + margin: 0 0 0 30px; + } + + .page .option_list .enabler:not(.disabled) .ctrlHolder:first-child { + margin: 10px 0 -33px 0; + } + + .page .option_list h3 { + padding: 0; + margin: 10px 5px 0; + text-align: center; + font-weight: normal; + text-shadow: none; + text-transform: uppercase; + font-size: 12px; + background: rgba(255,255,255,0.03); + } + + .page .option_list .enabler.disabled { + display: inline-block; + margin: 3px 3px 3px 20px; + padding: 4px 0; + width: 173px; + vertical-align: top; + } + + .page .option_list .enabler.disabled h2 { + border: none; + box-shadow: none; + padding: 0 10px 0 25px; + font-size: 16px; + } + + .page .option_list .enabler:not(.disabled) h2 { + font-size: 16px; + font-weight: bold; + border: none; + border-top: 1px solid rgba(255,255,255, 0.15); + box-shadow: 0 -1px 0px #333; + margin: 0; + padding: 10px 0 5px 25px; + } + .page .option_list .enabler:not(.disabled):first-child h2 { + border: none; + box-shadow: none; + } + + .page .option_list .enabler.disabled h2 .hint { + display: none; + } + .page .option_list .enabler h2 .hint { + font-weight: normal; + } + + .page input[type=text], .page input[type=password] { + padding: 5px 3px; + margin: 0; + width: 30%; + border-radius: 3px; + } + .page .input.xsmall { width: 5% } + .page .input.small { width: 10% } + .page .input.medium { width: 15% } + .page .input.large { width: 25% } + .page .input.xlarge { width: 30% } + + .page .advanced_toggle { + clear: both; + display: block; + text-align: right; + height: 20px; + margin: 0; + } + .page .advanced_toggle span { padding: 0 5px; } + .page.show_advanced .advanced_toggle { + color: #edc07f; + } + + .page .directory { + display: inline-block; + padding: 0 4% 0 4px; + font-size: 13px; + width: 30%; + background-image: url('../../images/icon.folder.gif'); + background-repeat: no-repeat; + background-position: 97% center; + overflow: hidden; + vertical-align: top; + } + .page .directory > span { + height: 25px; + display: inline-block; + float: right; + text-align: right; + white-space: nowrap; + cursor: pointer; + } + + .page .directory_list { + z-index: 2; + position: absolute; + width: 450px; + margin: 28px 0 20px 18%; + background: #5c697b; + border-radius: 3px; + box-shadow: 0 0 50px rgba(0,0,0,0.55); + } + + .page .directory_list .pointer { + border-right: 6px solid transparent; + border-left: 6px solid transparent; + border-bottom: 6px solid #5c697b; + display: block; + position: absolute; + width: 0px; + margin: -6px 0 0 22%; + } + + .page .directory_list ul { + width: 92%; + height: 300px; + overflow: auto; + margin: 0 4%; + font-size: 16px; + } + + .page .directory_list li { + padding: 4px 10px; + cursor: pointer; + margin: 0 !important; + border-top: 1px solid rgba(255,255,255,0.1); + background: url('../../images/right.arrow.png') no-repeat 98% center; + } + .page .directory_list li:last-child { + border-bottom: 1px solid rgba(255,255,255,0.1); + } + + .page .directory_list li:hover { + background-color: #515c68; + } + + .page .directory_list li.empty { + background: none; + height: 100px; + text-align: center; + font-style: italic; + border: none; + line-height: 100px; + cursor: default; + color: #BBB; + text-shadow: none; + font-size: 12px; + } + + .page .directory_list .actions { + clear: both; + padding: 4% 4% 2%; + min-height: 25px; + } + + .page .directory_list .actions label { + float: right; + width: auto; + padding: 0; + } + .page .directory_list .actions .inlay { + margin: -2px 0 0 7px; + } + + .page .directory_list .actions .back { + font-weight: bold; + width: 160px; + display: inline-block; + padding: 0; + line-height: 120%; + vertical-align: top; + } + + .page .directory_list .actions:last-child { + float: right; + padding: 4%; + } + + .page .directory_list .actions:last-child > span { + padding: 0 5px; + text-shadow: none; + } + + .page .directory_list .actions:last-child > .clear { + left: -90%; + position: relative; + background-color: #af3128; +} + + .page .directory_list .actions:last-child > .cancel { + font-weight: bold; + color: #ddd; + } + + .page .directory_list .actions:last-child > .save { + background: #9dc156; + } + + + .page .multi_directory.is_empty .delete { + visibility: hidden; + } + + .page .multi_directory .delete { + display: none; + } + .page .multi_directory:hover .delete { + display: inline-block; + width: 22px; + height: 24px; + vertical-align: top; + background-position: center; + margin-left: 5px; + } + + + .page .tag_input select { + width: 20%; + display: inline-block; + } + + .page .tag_input .selection { + border-radius: 0 10px 10px 0; + height: 26px; + } + + .page .tag_input > input { + display: none; + } + + .page .tag_input > ul { + list-style: none; + border-radius: 3px; + cursor: text; + width: 30%; + margin: 0 !important; + min-height: 27px; + line-height: 0; + display: inline-block; + } + .page .tag_input:hover > ul { + border-radius: 3px 0 0 3px; + } + .page .tag_input:hover .formHint { display: none; } + + .page .tag_input > ul > li { + display: inline-block; + min-height: 20px; + min-width: 2px; + font-size: 12px; + padding: 0; + margin: 4px 0 0 !important; + border-width: 0; + background: 0; + line-height: 20px; + } + .page .tag_input > ul > li:first-child { min-width: 4px; } + .page .tag_input li.choice { + cursor: -moz-grab; + cursor: -webkit-grab; + cursor: grab; + padding: 0; + border-radius: 2px; + } + .page .tag_input > ul:hover > li.choice { + background: -*-linear-gradient( + 270deg, + rgba(255,255,255,0.3) 0%, + rgba(255,255,255,0.1) 100% + ); + } + .page .tag_input > ul > li.choice:hover, + .page .tag_input > ul > li.choice.selected { + background: -*-linear-gradient( + 270deg, + #5b9bd1 0%, + #406db8 100% + ); + } + + .page .tag_input .select { + display: none; + } + .page .tag_input:hover .select { display: inline-block; } + + .page .tag_input li input { + background: 0; + border: 0; + color: #fff; + outline-width: 0; + padding: 0; + min-width: 2px; + } + .page .tag_input li:first-child input { + padding-left: 2px; + min-width: 0; + } + + .page .tag_input li:not(.choice) span { + white-space: pre; + position: absolute; + top: -9999px; + } + + .page .tag_input .delete { + display: none; + height: 10px; + width: 16px; + position: absolute; + margin: -9px 0 0 -16px; + border-radius: 30px 30px 0 0; + cursor: pointer; + background: url('../../images/icon.delete.png') no-repeat center 2px, -*-linear-gradient( + 270deg, + #5b9bd1 0%, + #5b9bd1 100% + ); + background-size: 65%; + } + .page .tag_input .choice:hover .delete, + .page .tag_input .choice.selected .delete { display: inline-block; } + .page .tag_input .choice .delete:hover { + height: 14px; + margin-top: -13px; + } + + .page .combined_table .head { + margin: 0 0 0 60px; + } + .page .disabled .head { display: none; } + .page .combined_table .head abbr { + display: inline-block; + font-weight: bold; + border-bottom: 1px dotted #fff; + line-height: 140%; + cursor: help; + } + .page .combined_table .head abbr.use, .page .combined_table .head abbr.automation_urls_use { + display: none; + } + .page .combined_table .head abbr.host { + margin-right: 197px; + } + + .page .combined_table .ctrlHolder { + padding-top: 2px; + padding-bottom: 3px; + } + .page .combined_table .ctrlHolder.hide { display: none; } + + .page .combined_table .ctrlHolder > * { + margin: 0 10px 0 0; + } + + .page .combined_table .ctrlHolder .delete { + display: none; + width: 22px; + height: 22px; + vertical-align: middle; + background-position: left center; + } + .page .combined_table .ctrlHolder:hover .delete { + display: inline-block; + } + + .page .combined_table .ctrlHolder.is_empty .delete, .page.settings .combined_table .ctrlHolder.is_empty .check { + visibility: hidden; +} + + .page .tab_about .usenet { + padding: 20px 30px 0; + font-size: 17px; + } + + .page .tab_about .usenet a { + padding: 0 5px; + } + + .page .tab_about .usenet ul { + float: left; + width: 50%; + margin: 10px 0; + padding: 0; + } + + .page .tab_about .usenet li { + background: url('../../images/icon.check.png') no-repeat left center; + padding: 0 0 0 25px; + } + + .page .tab_about .donate { + float: left; + width: 42%; + text-align: center; + font-size: 17px; + padding: 0 0 0 4%; + margin: 20px 0 0; + border-left: 1px solid #333; + box-shadow: -1px 0 0 rgba(255,255,255, 0.15); + } + .page .tab_about .donate form { + padding: 10px 0 0; + } + + .page .tab_about .info { + padding: 20px 30px; + margin: 0; + overflow: hidden; + } + + .page .tab_about .info dt { + clear: both; + float: left; + width: 17%; + font-weight: bold; + } + + .page .tab_about .info dd { + float: right; + width: 80%; + padding: 0; + margin: 0; + font-style: italic; + } + .page .tab_about .info dd.version { cursor: pointer; } + + .page .tab_about .group_actions > div { + padding: 30px; + text-align: center; + } + + .page .tab_about .group_actions a { + margin: 0 10px; + font-size: 20px; + } + +.group_userscript { + background: center bottom no-repeat; + min-height: 360px; + font-size: 20px; + font-weight: normal; +} + + .group_userscript h2 .hint { + display: block; + margin: 0 !important; + } + + .group_userscript .userscript { + float: left; + margin: 14px 0 0 25px; + height: 36px; + line-height: 25px; + } + + .group_userscript .or { + float: left; + margin: 20px -10px 0 10px; + } + + .group_userscript .bookmarklet { + display: block; + display: block; + float: left; + padding: 20px 15px 0 25px; + border-radius: 5px; + } + + .group_userscript .bookmarklet span { + margin-left: 10px; + display: inline-block; + } + +.active .group_imdb_automation:not(.disabled) { + background: url('../../images/imdb_watchlist.png') no-repeat right 50px; + min-height: 210px; +} \ No newline at end of file diff --git a/couchpotato/templates/_desktop.html b/couchpotato/templates/_desktop.html index 8689b66..1d61806 100644 --- a/couchpotato/templates/_desktop.html +++ b/couchpotato/templates/_desktop.html @@ -1,43 +1,14 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {% for url in fireEvent('clientscript.get_scripts', as_html = True, single = True) %} + {% for url in fireEvent('clientscript.get_styles', as_html = True, location = 'front', single = True) %} + {% endfor %} + {% for url in fireEvent('clientscript.get_scripts', as_html = True, location = 'front', single = True) %} + {% endfor %} + + {% for url in fireEvent('clientscript.get_scripts', as_html = True, location = 'head', single = True) %} {% endfor %} - {% for url in fireEvent('clientscript.get_styles', as_html = True, single = True) %} + {% for url in fireEvent('clientscript.get_styles', as_html = True, location = 'head', single = True) %} {% endfor %} diff --git a/libs/minify/__init__.py b/libs/minify/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/libs/minify/cssmin.py b/libs/minify/cssmin.py new file mode 100644 index 0000000..c29cb83 --- /dev/null +++ b/libs/minify/cssmin.py @@ -0,0 +1,223 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# `cssmin.py` - A Python port of the YUI CSS compressor. + + +from StringIO import StringIO # The pure-Python StringIO supports unicode. +import re + + +__version__ = '0.1.1' + + +def remove_comments(css): + """Remove all CSS comment blocks.""" + + iemac = False + preserve = False + comment_start = css.find("/*") + while comment_start >= 0: + # Preserve comments that look like `/*!...*/`. + # Slicing is used to make sure we don"t get an IndexError. + preserve = css[comment_start + 2:comment_start + 3] == "!" + + comment_end = css.find("*/", comment_start + 2) + if comment_end < 0: + if not preserve: + css = css[:comment_start] + break + elif comment_end >= (comment_start + 2): + if css[comment_end - 1] == "\\": + # This is an IE Mac-specific comment; leave this one and the + # following one alone. + comment_start = comment_end + 2 + iemac = True + elif iemac: + comment_start = comment_end + 2 + iemac = False + elif not preserve: + css = css[:comment_start] + css[comment_end + 2:] + else: + comment_start = comment_end + 2 + comment_start = css.find("/*", comment_start) + + return css + + +def remove_unnecessary_whitespace(css): + """Remove unnecessary whitespace characters.""" + + def pseudoclasscolon(css): + + """ + Prevents 'p :link' from becoming 'p:link'. + + Translates 'p :link' into 'p ___PSEUDOCLASSCOLON___link'; this is + translated back again later. + """ + + regex = re.compile(r"(^|\})(([^\{\:])+\:)+([^\{]*\{)") + match = regex.search(css) + while match: + css = ''.join([ + css[:match.start()], + match.group().replace(":", "___PSEUDOCLASSCOLON___"), + css[match.end():]]) + match = regex.search(css) + return css + + css = pseudoclasscolon(css) + # Remove spaces from before things. + css = re.sub(r"\s+([!{};:>+\(\)\],])", r"\1", css) + + # If there is a `@charset`, then only allow one, and move to the beginning. + css = re.sub(r"^(.*)(@charset \"[^\"]*\";)", r"\2\1", css) + css = re.sub(r"^(\s*@charset [^;]+;\s*)+", r"\1", css) + + # Put the space back in for a few cases, such as `@media screen` and + # `(-webkit-min-device-pixel-ratio:0)`. + css = re.sub(r"\band\(", "and (", css) + + # Put the colons back. + css = css.replace('___PSEUDOCLASSCOLON___', ':') + + # Remove spaces from after things. + css = re.sub(r"([!{}:;>+\(\[,])\s+", r"\1", css) + + return css + + +def remove_unnecessary_semicolons(css): + """Remove unnecessary semicolons.""" + + return re.sub(r";+\}", "}", css) + + +def remove_empty_rules(css): + """Remove empty rules.""" + + return re.sub(r"[^\}\{]+\{\}", "", css) + + +def normalize_rgb_colors_to_hex(css): + """Convert `rgb(51,102,153)` to `#336699`.""" + + regex = re.compile(r"rgb\s*\(\s*([0-9,\s]+)\s*\)") + match = regex.search(css) + while match: + colors = match.group(1).split(",") + hexcolor = '#%.2x%.2x%.2x' % tuple(map(int, colors)) + css = css.replace(match.group(), hexcolor) + match = regex.search(css) + return css + + +def condense_zero_units(css): + """Replace `0(px, em, %, etc)` with `0`.""" + + return re.sub(r"([\s:])(0)(px|em|%|in|cm|mm|pc|pt|ex)", r"\1\2", css) + + +def condense_multidimensional_zeros(css): + """Replace `:0 0 0 0;`, `:0 0 0;` etc. with `:0;`.""" + + css = css.replace(":0 0 0 0;", ":0;") + css = css.replace(":0 0 0;", ":0;") + css = css.replace(":0 0;", ":0;") + + # Revert `background-position:0;` to the valid `background-position:0 0;`. + css = css.replace("background-position:0;", "background-position:0 0;") + + return css + + +def condense_floating_points(css): + """Replace `0.6` with `.6` where possible.""" + + return re.sub(r"(:|\s)0+\.(\d+)", r"\1.\2", css) + + +def condense_hex_colors(css): + """Shorten colors from #AABBCC to #ABC where possible.""" + + regex = re.compile(r"([^\"'=\s])(\s*)#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])") + match = regex.search(css) + while match: + first = match.group(3) + match.group(5) + match.group(7) + second = match.group(4) + match.group(6) + match.group(8) + if first.lower() == second.lower(): + css = css.replace(match.group(), match.group(1) + match.group(2) + '#' + first) + match = regex.search(css, match.end() - 3) + else: + match = regex.search(css, match.end()) + return css + + +def condense_whitespace(css): + """Condense multiple adjacent whitespace characters into one.""" + + return re.sub(r"\s+", " ", css) + + +def condense_semicolons(css): + """Condense multiple adjacent semicolon characters into one.""" + + return re.sub(r";;+", ";", css) + + +def wrap_css_lines(css, line_length): + """Wrap the lines of the given CSS to an approximate length.""" + + lines = [] + line_start = 0 + for i, char in enumerate(css): + # It's safe to break after `}` characters. + if char == '}' and (i - line_start >= line_length): + lines.append(css[line_start:i + 1]) + line_start = i + 1 + + if line_start < len(css): + lines.append(css[line_start:]) + return '\n'.join(lines) + + +def cssmin(css, wrap = None): + css = remove_comments(css) + css = condense_whitespace(css) + # A pseudo class for the Box Model Hack + # (see http://tantek.com/CSS/Examples/boxmodelhack.html) + css = css.replace('"\\"}\\""', "___PSEUDOCLASSBMH___") + #css = remove_unnecessary_whitespace(css) + css = remove_unnecessary_semicolons(css) + css = condense_zero_units(css) + css = condense_multidimensional_zeros(css) + css = condense_floating_points(css) + css = normalize_rgb_colors_to_hex(css) + css = condense_hex_colors(css) + if wrap is not None: + css = wrap_css_lines(css, wrap) + css = css.replace("___PSEUDOCLASSBMH___", '"\\"}\\""') + css = condense_semicolons(css) + return css.strip() + + +def main(): + import optparse + import sys + + p = optparse.OptionParser( + prog = "cssmin", version = __version__, + usage = "%prog [--wrap N]", + description = """Reads raw CSS from stdin, and writes compressed CSS to stdout.""") + + p.add_option( + '-w', '--wrap', type = 'int', default = None, metavar = 'N', + help = "Wrap output to approximately N chars per line.") + + options, args = p.parse_args() + sys.stdout.write(cssmin(sys.stdin.read(), wrap = options.wrap)) + + +if __name__ == '__main__': + main() diff --git a/libs/minify/jsmin.py b/libs/minify/jsmin.py new file mode 100644 index 0000000..a1b81f9 --- /dev/null +++ b/libs/minify/jsmin.py @@ -0,0 +1,218 @@ +#!/usr/bin/python + +# This code is original from jsmin by Douglas Crockford, it was translated to +# Python by Baruch Even. The original code had the following copyright and +# license. +# +# /* jsmin.c +# 2007-05-22 +# +# Copyright (c) 2002 Douglas Crockford (www.crockford.com) +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# The Software shall be used for Good, not Evil. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# */ + +from StringIO import StringIO + +def jsmin(js): + ins = StringIO(js) + outs = StringIO() + JavascriptMinify().minify(ins, outs) + str = outs.getvalue() + if len(str) > 0 and str[0] == '\n': + str = str[1:] + return str + +def isAlphanum(c): + """return true if the character is a letter, digit, underscore, + dollar sign, or non-ASCII character. + """ + return ((c >= 'a' and c <= 'z') or (c >= '0' and c <= '9') or + (c >= 'A' and c <= 'Z') or c == '_' or c == '$' or c == '\\' or (c is not None and ord(c) > 126)); + +class UnterminatedComment(Exception): + pass + +class UnterminatedStringLiteral(Exception): + pass + +class UnterminatedRegularExpression(Exception): + pass + +class JavascriptMinify(object): + + def _outA(self): + self.outstream.write(self.theA) + def _outB(self): + self.outstream.write(self.theB) + + def _get(self): + """return the next character from stdin. Watch out for lookahead. If + the character is a control character, translate it to a space or + linefeed. + """ + c = self.theLookahead + self.theLookahead = None + if c == None: + c = self.instream.read(1) + if c >= ' ' or c == '\n': + return c + if c == '': # EOF + return '\000' + if c == '\r': + return '\n' + return ' ' + + def _peek(self): + self.theLookahead = self._get() + return self.theLookahead + + def _next(self): + """get the next character, excluding comments. peek() is used to see + if a '/' is followed by a '/' or '*'. + """ + c = self._get() + if c == '/': + p = self._peek() + if p == '/': + c = self._get() + while c > '\n': + c = self._get() + return c + if p == '*': + c = self._get() + while 1: + c = self._get() + if c == '*': + if self._peek() == '/': + self._get() + return ' ' + if c == '\000': + raise UnterminatedComment() + + return c + + def _action(self, action): + """do something! What you do is determined by the argument: + 1 Output A. Copy B to A. Get the next B. + 2 Copy B to A. Get the next B. (Delete A). + 3 Get the next B. (Delete B). + action treats a string as a single character. Wow! + action recognizes a regular expression if it is preceded by ( or , or =. + """ + if action <= 1: + self._outA() + + if action <= 2: + self.theA = self.theB + if self.theA == "'" or self.theA == '"': + while 1: + self._outA() + self.theA = self._get() + if self.theA == self.theB: + break + if self.theA <= '\n': + raise UnterminatedStringLiteral() + if self.theA == '\\': + self._outA() + self.theA = self._get() + + + if action <= 3: + self.theB = self._next() + if self.theB == '/' and (self.theA == '(' or self.theA == ',' or + self.theA == '=' or self.theA == ':' or + self.theA == '[' or self.theA == '?' or + self.theA == '!' or self.theA == '&' or + self.theA == '|' or self.theA == ';' or + self.theA == '{' or self.theA == '}' or + self.theA == '\n'): + self._outA() + self._outB() + while 1: + self.theA = self._get() + if self.theA == '/': + break + elif self.theA == '\\': + self._outA() + self.theA = self._get() + elif self.theA <= '\n': + raise UnterminatedRegularExpression() + self._outA() + self.theB = self._next() + + + def _jsmin(self): + """Copy the input to the output, deleting the characters which are + insignificant to JavaScript. Comments will be removed. Tabs will be + replaced with spaces. Carriage returns will be replaced with linefeeds. + Most spaces and linefeeds will be removed. + """ + self.theA = '\n' + self._action(3) + + while self.theA != '\000': + if self.theA == ' ': + if isAlphanum(self.theB): + self._action(1) + else: + self._action(2) + elif self.theA == '\n': + if self.theB in ['{', '[', '(', '+', '-']: + self._action(1) + elif self.theB == ' ': + self._action(3) + else: + if isAlphanum(self.theB): + self._action(1) + else: + self._action(2) + else: + if self.theB == ' ': + if isAlphanum(self.theA): + self._action(1) + else: + self._action(3) + elif self.theB == '\n': + if self.theA in ['}', ']', ')', '+', '-', '"', '\'']: + self._action(1) + else: + if isAlphanum(self.theA): + self._action(1) + else: + self._action(3) + else: + self._action(1) + + def minify(self, instream, outstream): + self.instream = instream + self.outstream = outstream + self.theA = '\n' + self.theB = None + self.theLookahead = None + + self._jsmin() + self.instream.close() + +if __name__ == '__main__': + import sys + jsm = JavascriptMinify() + jsm.minify(sys.stdin, sys.stdout)