2 #Last-update: 08/05/07 12:39:17
11 AJS_MINI_SRC = 'AJS_compressed.js'
15 # Standard stuff that may change in the future
18 "ul", "li", "td", "tr", "th",
19 "tbody", "table", "input", "span", "b",
20 "a", "div", "img", "button", "h1",
21 "h2", "h3", "br", "textarea", "form",
22 "p", "select", "option", "iframe", "script",
23 "center", "dl", "dt", "dd", "small",
30 '$f': 'getFormElement',
34 'DI': 'documentInsert',
35 'ACN': 'appendChildNodes',
36 'RCN': 'replaceChildNodes',
37 'AEV': 'addEventListener',
38 'REV': 'removeEventListener',
39 '$bytc': 'getElementsByTagAndClassName'
42 AJS_TEMPLATE = """//AJS JavaScript library (minify'ed version)
43 //Copyright (c) 2006 Amir Salihefendic. All rights reserved.
44 //Copyright (c) 2005 Bob Ippolito. All rights reserved.
45 //License: http://www.opensource.org/licenses/mit-license.php
46 //Visit http://orangoo.com/AmiNation/AJS for full version.
57 AJS.$ = AJS.getElement;
58 AJS.$$ = AJS.getElements;
59 AJS.$f = AJS.getFormElement;
62 AJS.$A = AJS.createArray;
63 AJS.DI = AJS.documentInsert;
64 AJS.ACN = AJS.appendChildNodes;
65 AJS.RCN = AJS.replaceChildNodes;
66 AJS.AEV = AJS.addEventListener;
67 AJS.REV = AJS.removeEventListener;
68 AJS.$bytc = AJS.getElementsByTagAndClassName;
70 AJS.addEventListener(window, 'unload', AJS._unloadListeners);
71 AJS._createDomShortcuts();
81 return open(AJS_SRC).read()
83 def writeAjsMini(code):
84 open(AJS_MINI_SRC, "w").write(code)
90 self.code = getAjsCode()
97 ajs_code = re.search("AJS =(.|\n)*\n}\n", self.code).group(0)
98 fns = re.findall("\s+((\w*?):.*?{(.|\n)*?\n\s*})(,|\n+})\n", ajs_code)
100 self.ajs_fns[f[1]] = f[0]
102 def getFnCode(self, fn_name, caller=None):
104 Returns the code of function and it's dependencies as a list
106 fn_name = self._unfoldFn(fn_name)
108 if self.ajs_fns.get(fn_name):
109 r.append(self.ajs_fns[fn_name])
110 for dep_fn in self.ajs_deps[fn_name]:
111 if fn_name != dep_fn and dep_fn != caller:
112 r.extend(self.getFnCode(dep_fn, fn_name))
113 elif fn_name not in ['listeners', 'Class']:
114 print 'Could not find "%s"' % fn_name
117 def getAjsClassCode(self):
118 return re.search("AJS.Class =(.|\n)*\n};\n", self.code).group(0)
120 def getAjsDeferredCode(self):
121 return re.search("AJSDeferred =(.|\n)*\n};\n", self.code).group(0)
125 Parses AJS and for every function it finds dependencies for the other functions.
127 for fn_name, fn_code in self.ajs_fns.items():
128 self.ajs_deps[fn_name] = self._findFns(fn_code)
130 def _findFns(self, inner):
132 Searches after AJS.fnX( in inner and returns all the fnX in a Set.
134 s = re.findall("AJS\.([\w_$]*?)(?:\(|,|\.)", inner)
136 return self._unfoldFns(s)
138 def _unfoldFns(self, list):
141 AJS.B, AJS.H1 etc. to _createDomShortcuts
142 AJS.$ to AJS.getElement etc.
144 return [self._unfoldFn(n) for n in list]
146 def _unfoldFn(self, fn_name):
147 if fn_name.lower() in DOM_SHORTCUTS:
148 return "_createDomShortcuts"
149 elif FN_SHORTCUTS.get(fn_name):
150 return FN_SHORTCUTS[fn_name]
155 class ExternalCodeAnalyzer:
157 def __init__(self, files):
158 self.found_ajs_fns = []
161 def findFunctions(self):
163 self.found_ajs_fns.extend( self._parseFile(f) )
164 return list(Set(self.found_ajs_fns))
166 def _parseFile(self, f):
168 Parses the file, looks for AJS functions and returns all the found functions.
170 code = open(f).read()
171 return re.findall("AJS\.([\w_$]*?)\(", code)
177 def __init__(self, fn_list):
178 self.code = getAjsCode()
179 self.analyzer = AjsAnalyzer()
180 self.fn_list = fn_list
182 #Append standard functions
183 req = ['_unloadListeners', 'createDOM', '_createDomShortcuts', 'log', 'addEventListener']
184 self.fn_list.extend(req)
186 #Append AJSDeferred only if needed
187 in_list = lambda x: x in self.fn_list
188 if in_list('getRequest') or in_list('loadJSONDoc'):
189 self.deferred = self._minify(self.analyzer.getAjsDeferredCode())
190 self.fn_list.append('isObject')
194 def writeToOutput(self):
197 d['functions'] = ",\n".join(fns)
198 d['AJSDeferred'] = self.deferred
199 d['AJSClass'] = self.analyzer.getAjsClassCode()
201 mini_code = AJS_TEMPLATE % d
202 writeAjsMini(mini_code)
204 def _minify(self, code):
206 for l in code.split("\n"):
207 if l not in ['\n', '']:
208 new_lines.append(l.lstrip())
209 return "\n".join(new_lines)
213 Returns a list with real code of functions
216 for fn in self.fn_list:
217 r.extend(self.analyzer.getFnCode(fn))
220 return [self._minify(fn) for fn in r]
223 if __name__ == '__main__':
228 python AJS_minify.py [-o output_file] ajs_file js_file.js html_using_ajs.html ...
230 Using relative paths:
231 python AJS_minify.py -o AJS_mini.js AJS.js test.js index.html
232 This will create AJS_mini.js from test.js and index.html.
233 Using absolute paths:
234 python AJS_minify.py ~/Desktop/AJS/AJS.js ~/Desktop/GreyBox_v3_42/greybox/greybox.js
235 This will create a new file called '%s' that has the needed AJS functions.""" % AJS_MINI_SRC
239 if sys.argv[1] == '-o':
240 AJS_MINI_SRC = sys.argv[2]
241 AJS_SRC = sys.argv[3]
244 AJS_SRC = sys.argv[1]
247 print 'Parsing through:\n %s' % "\n ".join(FILES)
249 code_analyzer = ExternalCodeAnalyzer(FILES)
250 found_fns = code_analyzer.findFunctions()
251 print 'Found following AJS functions:\n %s' % ("\n ".join(found_fns))
253 composer = AjsComposer(found_fns)
254 composer.writeToOutput()
255 print "Written the minified code to '%s'" % AJS_MINI_SRC