diff --git a/r2/Makefile b/r2/Makefile index 32785db74..041b3feaf 100644 --- a/r2/Makefile +++ b/r2/Makefile @@ -21,20 +21,22 @@ ################################################################################ # Javascript files to be compressified -js_targets = jquery.js jquery.json.js jquery.reddit.js reddit.js ui.core.js ui.datepicker.js sponsored.js jquery.flot.js compact.js blogbutton.js +js_sources = jquery.json.js jquery.reddit.js reddit.js base.js ui.core.js ui.datepicker.js sponsored.js jquery.flot.js jquery.lazyload.js compact.js blogbutton.js +js_targets = button.js jquery.flot.js sponsored.js +localized_js_targets = reddit.js mobile.js +localized_js_outputs = $(localized_js_targets:.js=.*.js) + # CSS targets main_css = reddit.css css_targets = reddit-ie6-hax.css reddit-ie7-hax.css mobile.css spreadshirt.css compact.css -SED=sed -CAT=cat -CSS_COMPRESS = $(SED) -e 's/ \+/ /' -e 's/\/\*.*\*\///g' -e 's/: /:/' | grep -v "^ *$$" - package = r2 static_dir = $(package)/public/static -contrib = $(package)/lib/contrib -JSCOMPRESS = $(contrib)/jsmin.py +SED=sed +CAT=cat +JS_COMPRESS = paster run standalone $(package)/lib/js.py -c "build_reddit_js()" +CSS_COMPRESS = $(SED) -e 's/ \+/ /' -e 's/\/\*.*\*\///g' -e 's/: /:/' | grep -v "^ *$$" # If admin codebase is install, get its path so that we can build ini # files against the primary production.ini @@ -42,17 +44,18 @@ PRIVATEREPOS = $(shell python -c 'exec "try: import r2admin; print r2admin.__pat #------ -JSTARGETS := $(foreach js, $(js_targets), $(static_dir)/$(js)) -CSSTARGETS := $(foreach css, $(css_targets), $(static_dir)/$(css)) -SPRITES := $(static_dir)/sprite.png -MAINCSS := $(foreach css, $(main_css), $(static_dir)/$(css)) +JSTARGETS = $(foreach js, $(js_targets) $(localized_js_targets), $(static_dir)/$(js)) +JSOUTPUTS = $(foreach js, $(js_targets) $(localized_js_outputs), $(static_dir)/$(js)) +JSSOURCES = $(foreach js, $(js_sources), $(static_dir)/js/$(js)) +CSSTARGETS = $(foreach css, $(css_targets), $(static_dir)/$(css)) +SPRITES = $(static_dir)/sprite.png +MAINCSS = $(foreach css, $(main_css), $(static_dir)/$(css)) RTLCSS = $(CSSTARGETS:.css=-rtl.css) $(MAINCSS:.css=-rtl.css) PYX_FILES := $(shell find . -name \*.pyx) PYXSO_FILES := $(PYX_FILES:.pyx=.so) - -MD5S = $(JSTARGETS:=.md5) $(CSSTARGETS:=.md5) $(MAINCSS:=.md5) $(RTLCSS:=.md5) +MD5S = $(JSOUTPUTS) $(CSSTARGETS) $(MAINCSS) $(RTLCSS) INIUPDATE = $(wildcard *.update) INIS = $(INIUPDATE:.update=.ini) @@ -67,15 +70,17 @@ else endif -all: $(JSTARGETS) $(CSSTARGETS) $(MAINCSS) $(MD5S) $(RTLCSS) $(INIS) $(PYXSO_FILES) +all: pyx static $(INIS) -.PHONY: js css md5 rtl clean all +.PHONY: pyx js css rtl static md5 clean clean_static all -$(MD5S): %.md5 : % - cat $< | openssl md5 > $@ +md5: + for name in $(MD5S) ; do \ + cat $$name | openssl md5 > $$name.md5 ; \ + done -$(JSTARGETS): $(static_dir)/%.js : $(static_dir)/js/%.js - $(JSCOMPRESS) < $< > $@ +$(JSTARGETS): $(JSSOURCES) + $(JS_COMPRESS) $(CSSTARGETS): $(static_dir)/%.css : $(static_dir)/css/%.css $(CAT) $< | $(CSS_COMPRESS) > $@ @@ -96,14 +101,18 @@ $(PYXSO_FILES): %.so : %.pyx PYTHONPATH=tmp python pyx_setup.py develop -d tmp -b tmp $< rm -r tmp +pyx: $(PYXSO_FILES) -js: $(JSTARGETS) +static: js css rtl md5 -css: $(CSSTARGETS) +js: pyx $(JSTARGETS) -md5: $(MD5S) +css: $(CSSTARGETS) $(MAINCSS) rtl: $(RTLCSS) -clean: - rm $(JSTARGETS) $(CSSTARGETS) $(SPRITES) $(MAINCSS) $(MD5S) $(INIS) +clean: clean_static + rm -f $(PYXSO_FILES) + +clean_static: + rm -f $(JSOUTPUTS) $(CSSTARGETS) $(SPRITES) $(MAINCSS) $(MD5S) $(INIS) diff --git a/r2/r2/lib/contrib/closure_compiler/COPYING b/r2/r2/lib/contrib/closure_compiler/COPYING new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/r2/r2/lib/contrib/closure_compiler/COPYING @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/r2/r2/lib/contrib/closure_compiler/README b/r2/r2/lib/contrib/closure_compiler/README new file mode 100644 index 000000000..ece717586 --- /dev/null +++ b/r2/r2/lib/contrib/closure_compiler/README @@ -0,0 +1,278 @@ +/* + * Copyright 2009 The Closure Compiler Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// +// Contents +// + +The Closure Compiler performs checking, instrumentation, and +optimizations on JavaScript code. The purpose of this README is to +explain how to build and run the Closure Compiler. + +The Closure Compiler requires Java 6 or higher. +http://www.java.com/ + + +// +// Building The Closure Compiler +// + +There are three ways to get a Closure Compiler executable. + +1) Use one we built for you. + +Pre-built Closure binaries can be found at +http://code.google.com/p/closure-compiler/downloads/list + + +2) Check out the source and build it with Apache Ant. + +First, check out the full source tree of the Closure Compiler. There +are instructions on how to do this at the project site. +http://code.google.com/p/closure-compiler/source/checkout + +Apache Ant is a cross-platform build tool. +http://ant.apache.org/ + +At the root of the source tree, there is an Ant file named +build.xml. To use it, navigate to the same directory and type the +command + +ant jar + +This will produce a jar file called "build/compiler.jar". + + +3) Check out the source and build it with Eclipse. + +Eclipse is a cross-platform IDE. +http://www.eclipse.org/ + +Under Eclipse's File menu, click "New > Project ..." and create a +"Java Project." You will see an options screen. Give the project a +name, select "Create project from existing source," and choose the +root of the checked-out source tree as the existing directory. Verify +that you are using JRE version 6 or higher. + +Eclipse can use the build.xml file to discover rules. When you +navigate to the build.xml file, you will see all the build rules in +the "Outline" pane. Run the "jar" rule to build the compiler in +build/compiler.jar. + + +// +// Running The Closure Compiler +// + +Once you have the jar binary, running the Closure Compiler is straightforward. + +On the command line, type + +java -jar compiler.jar + +This starts the compiler in interactive mode. Type + +var x = 17 + 25; + +then hit "Enter", then hit "Ctrl-Z" (on Windows) or "Ctrl-D" (on Mac or Linux) +and "Enter" again. The Compiler will respond: + +var x=42; + +The Closure Compiler has many options for reading input from a file, +writing output to a file, checking your code, and running +optimizations. To learn more, type + +java -jar compiler.jar --help + +You can read more detailed documentation about the many flags at +http://code.google.com/closure/compiler/docs/gettingstarted_app.html + + +// +// Compiling Multiple Scripts +// + +If you have multiple scripts, you should compile them all together with +one compile command. + +java -jar compiler.jar --js=in1.js --js=in2.js ... --js_output_file=out.js + +The Closure Compiler will concatenate the files in the order they're +passed at the command line. + +If you need to compile many, many scripts together, you may start to +run into problems with managing dependencies between scripts. You +should check out the Closure Library. It contains functions for +enforcing dependencies between scripts, and a tool called calcdeps.py +that knows how to give scripts to the Closure Compiler in the right +order. + +http://code.google.com/p/closure-library/ + +// +// Licensing +// + +Unless otherwise stated, all source files are licensed under +the Apache License, Version 2.0. + + +----- +Code under: +src/com/google/javascript/rhino +test/com/google/javascript/rhino + +URL: http://www.mozilla.org/rhino +Version: 1.5R3, with heavy modifications +License: Netscape Public License and MPL / GPL dual license + +Description: A partial copy of Mozilla Rhino. Mozilla Rhino is an +implementation of JavaScript for the JVM. The JavaScript parser and +the parse tree data structures were extracted and modified +significantly for use by Google's JavaScript compiler. + +Local Modifications: The packages have been renamespaced. All code not +relavant to parsing has been removed. A JSDoc parser and static typing +system have been added. + + +----- +Code in: +lib/libtrunk_rhino_parser_jarjared.jar + +Rhino +URL: http://www.mozilla.org/rhino +Version: Trunk +License: Netscape Public License and MPL / GPL dual license + +Description: Mozilla Rhino is an implementation of JavaScript for the JVM. + +Local Modifications: None. We've used JarJar to renamespace the code +post-compilation. See: +http://code.google.com/p/jarjar/ + + +----- +Code in: +lib/args4j.jar + +Args4j +URL: https://args4j.dev.java.net/ +Version: 2.0.12 +License: MIT + +Description: +args4j is a small Java class library that makes it easy to parse command line +options/arguments in your CUI application. + +Local Modifications: None. + + +----- +Code in: +lib/guava.jar + +Guava Libraries +URL: http://code.google.com/p/guava-libraries/ +Version: r08 +License: Apache License 2.0 + +Description: Google's core Java libraries. + +Local Modifications: None. + + +----- +Code in: +lib/jsr305.jar + +Annotations for software defect detection +URL: http://code.google.com/p/jsr-305/ +Version: svn revision 47 +License: BSD License + +Description: Annotations for software defect detection. + +Local Modifications: None. + + +---- +Code in: +lib/junit.jar + +JUnit +URL: http://sourceforge.net/projects/junit/ +Version: 4.8.2 +License: Common Public License 1.0 + +Description: A framework for writing and running automated tests in Java. + +Local Modifications: None. + + +--- +Code in: +lib/protobuf-java.jar + +Protocol Buffers +URL: http://code.google.com/p/protobuf/ +Version: 2.3.0 +License: New BSD License + +Description: Supporting libraries for protocol buffers, +an encoding of structured data. + +Local Modifications: None + + +--- +Code in: +lib/ant.jar +lib/ant-launcher.jar + +URL: http://ant.apache.org/bindownload.cgi +Version: 1.8.1 +License: Apache License 2.0 +Description: + Ant is a Java based build tool. In theory it is kind of like "make" + without make's wrinkles and with the full portability of pure java code. + +Local Modifications: None + + +--- +Code in: +lib/json.jar +URL: http://json.org/java/index.html +Version: JSON version 20090211 +License: MIT license +Description: +JSON is a set of java files for use in transmitting data in JSON format. + +Local Modifications: None + +--- +Code in: +tools/maven-ant-tasks-2.1.1.jar +URL: http://maven.apache.org +Version 2.1.1 +License: Apache License 2.0 +Description: + Maven Ant tasks are used to manage dependencies and to install/deploy to + maven repositories. + +Local Modifications: None diff --git a/r2/r2/lib/contrib/closure_compiler/compiler.jar b/r2/r2/lib/contrib/closure_compiler/compiler.jar new file mode 100644 index 000000000..2f6837d3e Binary files /dev/null and b/r2/r2/lib/contrib/closure_compiler/compiler.jar differ diff --git a/r2/r2/lib/contrib/jsmin.py b/r2/r2/lib/contrib/jsmin.py deleted file mode 100755 index 607f1460a..000000000 --- a/r2/r2/lib/contrib/jsmin.py +++ /dev/null @@ -1,218 +0,0 @@ -#!/usr/bin/env 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 an unescaped '/' is followed by a '/' or '*'. - """ - c = self._get() - if c == '/' and self.theA != '\\': - 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) diff --git a/r2/r2/lib/js.py b/r2/r2/lib/js.py new file mode 100755 index 000000000..ccfda21b4 --- /dev/null +++ b/r2/r2/lib/js.py @@ -0,0 +1,197 @@ +#!/usr/bin/env python +import sys +import os.path +from subprocess import Popen, PIPE +import re +import json +from pylons import g, c + +script_tag = '\n' +inline_script_tag = '\n' + +class ClosureError(Exception): pass +class ClosureCompiler(object): + def __init__(self, jarpath, args=None): + self.jarpath = jarpath + self.args = args or [] + + def _run(self, data, out=PIPE, args=None, expected_code=0): + args = args or [] + p = Popen(["java", "-jar", self.jarpath] + self.args + args, + stdin=PIPE, stdout=out, stderr=PIPE) + out, msg = p.communicate(data) + if p.returncode != expected_code: + raise ClosureError(msg) + else: + return out, msg + + def compile(self, data, dest, args=None): + """Run closure compiler on a string of source code `data`, writing the + result to output file `dest`. A ClosureError exception will be raised if + the operation is unsuccessful.""" + return self._run(data, dest, args)[0] + +class Source(object): + """An abstract collection of JavaScript code.""" + def get_source(self): + """Return the full JavaScript source code.""" + return NotImplementedError + + def use(self): + """Return HTML to insert the JavaScript source inside a template.""" + return NotImplementedError + +class FileSource(Source): + """A JavaScript source file on disk.""" + def __init__(self, name): + self.name = name + + def get_source(self): + return open(self.path).read() + + @property + def path(self): + """The path to the source file on the filesystem.""" + return os.path.join(g.paths["static_files"], "static/js", self.name) + + def use(self): + from r2.lib.template_helpers import static + path = [g.static_path, self.name] + if g.uncompressedJS: + path.insert(1, "js") + return script_tag.format(src=static(os.path.join(*path))) + +class Module(Source): + """A module of JS code consisting of a collection of sources.""" + def __init__(self, name, *sources): + self.name = name + self.sources = [] + sources = sources or (name,) + for source in sources: + if not isinstance(source, Source): + source = FileSource(source) + self.sources.append(source) + + def get_source(self): + return "\n".join(s.get_source() for s in self.sources) + + @property + def path(self): + """The destination path of the module file on the filesystem.""" + return os.path.join(g.paths["static_files"], "static", self.name) + + def build(self, closure): + print >> sys.stderr, "Compiling {0}...".format(self.name), + with open(self.path, "w") as out: + closure.compile(self.get_source(), out) + print >> sys.stderr, " done." + + def use(self): + from r2.lib.template_helpers import static + if g.uncompressedJS: + return "".join(source.use() for source in self.sources) + else: + url = os.path.join(g.static_path, self.name) + return script_tag.format(src=static(url)) + +class StringsSource(Source): + """A virtual source consisting of localized strings from r2.lib.strings.""" + def __init__(self, lang=None, keys=None, prepend="r.strings = "): + self.lang = lang + self.keys = keys + self.prepend = prepend + + def get_source(self): + from pylons.i18n import get_lang + from r2.lib import strings, translation + + if self.lang: + old_lang = get_lang() + translation.set_lang(self.lang) + + data = {} + if self.keys is not None: + for key in self.keys: + data[key] = strings.strings[key] + else: + data = dict(strings.strings) + + output = self.prepend + json.dumps(data) + "\n" + + if self.lang: + translation.set_lang(old_lang) + + return output + + def use(self): + return inline_script_tag.format(content=self.get_source()) + +class LocalizedModule(Module): + """A module that is localized with r2.lib.strings. + + References to `r.strings.` are parsed out of the module source. + A StringsSource is created and included which contains localized versions + of the strings referenced in the module. + """ + def build(self, closure): + Module.build(self, closure) + + reddit_source = open(self.path).read() + string_keys = re.findall("r\.strings\.([\w$_]+)", reddit_source) + + print >> sys.stderr, "Creating language-specific files:" + path_name, path_ext = os.path.splitext(self.path) + for lang in g.languages: + strings = StringsSource(lang, string_keys) + source = strings.get_source() + lang_path = path_name + "." + lang + path_ext + with open(lang_path, "w") as out: + print >> sys.stderr, " " + lang_path + out.write(reddit_source+source) + + def use(self): + from pylons.i18n import get_lang + from r2.lib.template_helpers import static + embed = Module.use(self) + if g.uncompressedJS: + return embed + StringsSource().use() + else: + name, ext = os.path.splitext(self.name) + url = os.path.join(g.static_path, name + "." + get_lang()[0] + ext) + return script_tag.format(src=static(url)) + +module = {} + +module["reddit"] = LocalizedModule("reddit.js", + "jquery.json.js", + "jquery.reddit.js", + "base.js", + "reddit.js", +) + +module["mobile"] = LocalizedModule("mobile.js", + module["reddit"], + "jquery.lazyload.js", + "compact.js" +) + +module["button"] = Module("button.js", + "jquery.reddit.js", + "blogbutton.js" +) + +module["sponsored"] = Module("sponsored.js", + "ui.core.js", + "ui.datepicker.js", + "sponsored.js" +) + +module["flot"] = Module("jquery.flot.js") + +def build_reddit_js(): + closure = ClosureCompiler("r2/lib/contrib/closure_compiler/compiler.jar") + for name in module: + module[name].build(closure) + +if __name__=="__main__": + build_reddit_js() diff --git a/r2/r2/lib/strings.py b/r2/r2/lib/strings.py index 083ef7ef5..146fde546 100644 --- a/r2/r2/lib/strings.py +++ b/r2/r2/lib/strings.py @@ -175,6 +175,12 @@ class StringHandler(object): return dict((k, _(v)) for k, v in rval.iteritems()) else: raise AttributeError + + def __iter__(self): + return iter(self.string_dict) + + def keys(self): + return self.string_dict.keys() strings = StringHandler(**string_dict) diff --git a/r2/r2/public/static/button/button1.html b/r2/r2/public/static/button/button1.html index efe0d2c44..d3d137046 100644 --- a/r2/r2/public/static/button/button1.html +++ b/r2/r2/public/static/button/button1.html @@ -6,8 +6,7 @@ - - + - - +