Author: bcsaller Date: Wed Jan 25 23:28:34 2006 New Revision: 18495 Added: Bling/ Bling/trunk/ Bling/trunk/Bling/ Bling/trunk/Bling/.skeletor Bling/trunk/Bling/Extensions/ Bling/trunk/Bling/Extensions/Install.py Bling/trunk/Bling/Extensions/__init__.py Bling/trunk/Bling/LICENSE Bling/trunk/Bling/Makefile Bling/trunk/Bling/README.txt Bling/trunk/Bling/__init__.py Bling/trunk/Bling/ajax.py Bling/trunk/Bling/conf/ Bling/trunk/Bling/conf/depends.conf Bling/trunk/Bling/conf/depends.xml Bling/trunk/Bling/config.py Bling/trunk/Bling/content/ Bling/trunk/Bling/content/__init__.py Bling/trunk/Bling/distext/ Bling/trunk/Bling/distext/__init__.py Bling/trunk/Bling/distext/doc.py Bling/trunk/Bling/distext/install.py Bling/trunk/Bling/distext/pkgconfig.py Bling/trunk/Bling/distext/test.py Bling/trunk/Bling/distext/utils.py Bling/trunk/Bling/docs/ Bling/trunk/Bling/docs/Makefile Bling/trunk/Bling/docs/style.css Bling/trunk/Bling/docs/walkthrough.rst Bling/trunk/Bling/permissions.py Bling/trunk/Bling/refresh.txt Bling/trunk/Bling/setup.py Bling/trunk/Bling/skins/ Bling/trunk/Bling/skins/bling/ Bling/trunk/Bling/skins/bling/behaviour.js Bling/trunk/Bling/skins/bling/bling.js Bling/trunk/Bling/skins/bling/builder.js Bling/trunk/Bling/skins/bling/controls.js Bling/trunk/Bling/skins/bling/cssQuery.js Bling/trunk/Bling/skins/bling/dragdrop.js Bling/trunk/Bling/skins/bling/dval.py Bling/trunk/Bling/skins/bling/echo.py Bling/trunk/Bling/skins/bling/effects.js Bling/trunk/Bling/skins/bling/prototype.js Bling/trunk/Bling/skins/bling/rico.js Bling/trunk/Bling/skins/bling/scriptaculous.js Bling/trunk/Bling/skins/bling/slider.js Bling/trunk/Bling/skins/bling/test.pt Bling/trunk/Bling/tests/ Bling/trunk/Bling/tests/__init__.py Bling/trunk/Bling/tests/test_bling.py Bling/trunk/Bling/tools/ Bling/trunk/Bling/tools/__init__.py Bling/trunk/Bling/utils.py Bling/trunk/Bling/version.txt Log: Moving this to the collective on Limi's request Added: Bling/trunk/Bling/.skeletor ============================================================================== --- (empty file) +++ Bling/trunk/Bling/.skeletor Wed Jan 25 23:28:34 2006 @@ -0,0 +1,15 @@ +[default] +ProductDescription = Ajax utilis, server side to generate client side w/o much JS +ProductVersion = 0.1 + +[base] +TargetDir = /home/bcsaller/zope/know/Products +ProductName = Bling + +[license] +TargetDir = /home/bcsaller/zope/know/Products +ProductLicense = GPL +ProductName = Bling + +[content_type] + Added: Bling/trunk/Bling/Extensions/Install.py ============================================================================== --- (empty file) +++ Bling/trunk/Bling/Extensions/Install.py Wed Jan 25 23:28:34 2006 @@ -0,0 +1,54 @@ +from StringIO import StringIO +from Products.Archetypes.public import listTypes +from Products.Archetypes.Extensions.utils import installTypes, install_subskin +from Products.CMFDynamicViewFTI.migrate import migrateFTIs +#{ProductInstallImport, code, insertBefore}# + +from Products.Bling.utils import installDependencies +from Products.Bling import config +from Products.Bling.permissions import SITEWIDE_PERMISSIONS + +# This is the current list of depends +resources = ['cssQuery.js', + 'prototype.js', + 'scriptaculous.js', + 'behaviour.js', + 'rico.js', + 'bling.js'] + +def update_registries(self, out): + # Register two sets of javascripts, the global sequence of + # libraries, and the behaviors specific to our particular + # search application + portal_js = self.portal_javascripts + existing = portal_js.getResourceIds() + for resource in resources: + if resource not in existing: + portal_js.manage_addScript(id=resource, enabled=True) + # Register the CSS too + portal_css = self.portal_css + if 'bling.css' not in portal_css.getResourceIds(): + portal_css.manage_addStylesheet(id = 'bling.css', enabled=True) + + + +def install(self): + out = StringIO() + + installDependencies(self) + #{ProductInstallBegin, code, insertAfter}# + install_subskin(self, out, config.GLOBALS) + update_registries(self, out) + + #{ProductInstallEnd, code, insertBefore}# + + print >> out, "Successfully installed %s." % config.PROJECT_NAME + return out.getvalue() + +def uninstall(self): + portal_js = self.portal_javascripts + existing = portal_js.getResourceIds() + for resource in resources: + if resource not in existing: + portal_js.manage_removeScript(resource) + Added: Bling/trunk/Bling/Extensions/__init__.py ============================================================================== --- (empty file) +++ Bling/trunk/Bling/Extensions/__init__.py Wed Jan 25 23:28:34 2006 @@ -0,0 +1 @@ +# import this Added: Bling/trunk/Bling/LICENSE ============================================================================== --- (empty file) +++ Bling/trunk/Bling/LICENSE Wed Jan 25 23:28:34 2006 @@ -0,0 +1,222 @@ + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS Added: Bling/trunk/Bling/Makefile ============================================================================== --- (empty file) +++ Bling/trunk/Bling/Makefile Wed Jan 25 23:28:34 2006 @@ -0,0 +1,19 @@ +all: test doc + @echo "If the tests pass and the docs are created you should be fine" + + +doc: + @make -C docs docs + @python setup.py doc + + +dist: + @python setup.py bdist_egg +test: + @python tests/test_bling.py + +clean: + @find . -name "*.pyc" -exec rm {} \; + @find . -name "*~" -exec rm {} \; + @rm -rf *.egg-info + @${MAKE} -C docs clean Added: Bling/trunk/Bling/README.txt ============================================================================== --- (empty file) +++ Bling/trunk/Bling/README.txt Wed Jan 25 23:28:34 2006 @@ -0,0 +1,5 @@ +Bling + +Ajax utilis, server side to generate client side w/o much JS + +This is basically just a port of the Rail Javascript helpers for now. Later they can be changes to AT and so on Added: Bling/trunk/Bling/__init__.py ============================================================================== --- (empty file) +++ Bling/trunk/Bling/__init__.py Wed Jan 25 23:28:34 2006 @@ -0,0 +1,23 @@ +#{Header, text, replace}# +""" +Bling + +Ajax utilis, server side to generate client side w/o much JS + +$Id: $ +""" +__authors__ = 'bcsaller', +__docformat__ = 'text/restructured' + +from Products.CMFCore.DirectoryView import registerDirectory +import config + +# Register the skins directory +registerDirectory(config.SKINS_DIR, config.GLOBALS) + +def initialize(context): + from AccessControl import ModuleSecurityInfo + from AccessControl import allow_module, allow_class + allow_module('Products.Bling.ajax') + + Added: Bling/trunk/Bling/ajax.py ============================================================================== --- (empty file) +++ Bling/trunk/Bling/ajax.py Wed Jan 25 23:28:34 2006 @@ -0,0 +1,263 @@ +''' +Bling +------ +Ajax support utilities. These methods are called in the ZPTs + +tal:define="ajax python:modules['Bling.ajax']" + +tal:content="structure python:ajax.linkTo(url, target_id)" + +''' +from StringIO import StringIO +import re + +CALLBACKS = ['uninitialized', 'loading', 'loaded', 'interactive', 'complete', 'failure' , 'success'] +CALLBACKS.extend([str(i) for i in range(100, 599)]) + +def mapInsert(where): + return {'before' : 'Insertion.Before', + 'after' : 'Insertion.After', + 'top' : 'Insertion.Top', + 'bottom' : 'Insertion.Bottom', + }.get(where, "null") + +def collapse(function): + return function.replace("\n", " ") + +def escape_js(js): + if not js: return '' + js = re.sub("\r\n|\n|\r", " ", js) + js = re.sub("(['\"])", r"\\\1", js) + return js + +def javascript_tag(content): + return '''<script type="text/javascript"><!-- + %s + --></script>''' % content + + +def build_callbacks(options): + callbacks = {} + for callback, code in options.iteritems(): + if callback in CALLBACKS: + name = "on"+ callback.title() + callbacks[name] = "function(request){%s}" % code + return callbacks + +def options_for_javascript(options): + """returns the javascript text for a set of options""" + return "{%s}" % ",".join(["%s:%s" %(k,v) for k,v in options.items()]) + +def options_for_ajax(options): + # We pass the options as a dict so we can modify it inplace + # XXX: this needs to be extensible if I want to handle it like + # this + ajax = build_callbacks(options) + ajax['method'] = repr(options.get("method", "post")) + ajax['insertion'] = mapInsert(options.get('where')) + + if options.get('form'): + ajax['parameters'] = "Form.serialize(this)" + elif options.get('submit'): + ajax['parameters'] = "Form.serialize($('%s'))" % options['submit'] + elif options.get('with'): + ajax['parameters'] = options['with'] + + ajax['asynchronous'] = options.get("synchronous", "true") + + if 'js' in options: ajax.update(options['js']) + return options_for_javascript(ajax) + + +def remoteFunction(url, **kwargs): + # is this a remote invocation or does it update + # a known DOM target? + update = '' + function = StringIO() + + d = kwargs.get('update') + if d: + update = [] + if isinstance(d, dict): + s = d.get('success') + f = d.get('failure') + if s: + if not s.startswith("$"): s = "$('%s')" % s + update.append("success: %s" % s) + if f: + if not f.startswith("$"): f = "$('%s')" % f + update.append("failure: %s" % f) + update = "{%s}" % ",".join(update) + else: + update = "$('%s')" % d + + # Function Style + if update: + print >>function, "new Ajax.Updater(%s," % update + else: + print >>function, "new Ajax.Request(", + + # Server URL (which must be adjusted to the server env already) + print >>function, "%r," % url + + # Javascript options + print >>function, options_for_ajax(kwargs) + + print >>function, ")" + + function = function.getvalue() + if kwargs.get("before"): + function = "%s;%s" %(kwargs['before'], function) + if kwargs.get("after"): + function = "%s;%s" %(function, kwargs['after'], ) + if kwargs.get("condition"): + function = "if (%s) {%s}" %(kwargs['condition'], function) + if kwargs.get("confirm"): + function = "if (confirm('%s')) { %s }" % ( + escape_js(kwargs['confirm']), + function) + return function + +def linkTo(name, url, options = None, **kwargs): + # register the js function + if options: kwargs.update(options) + function = remoteFunction(url, **kwargs) + function = collapse(function) + return '<a href="#" onclick="%s;return false">%s</a>' % ( + function, + name) + + +def remoteForm(url, options=None, **kwargs): + '''link a form to a remote url + usage: tal:define="form python:ajax.remoteForm(url, options)" + tal:attributes="onsubmit form/onsubmit; + method form/method; + action form/action; " + ''' + if options: kwargs.update(options) + function = remoteFunction(url, **kwargs) + function = "%s;return false;" % collapse(function) + return {'method' : kwargs.get("method", "post"), + 'action' : url, + 'onsubmit': function, + } + + +def submitRemote(url, options=None, **kwargs): + '''used in an input tag to create a ajax POST trigger + usage: tal:define="form python:ajax.remoteForm(url, options)" + tal:attributes="onclick form/onclick; + method form/method; + action form/action; + type form/type" + ''' + + if options: kwargs.update(options) + function = remoteFunction(url, **kwargs) + function = "%s;return false;" % collapse(function) + return {'method' : kwargs.get("method", "post"), + 'action' : url, + 'onclick': function, + 'type' : 'button'} + + +def build_observer(klass, url, field_id, options): + output = StringIO() + if "with" not in options: + # use the observed value by default + if "withvalue" in options: + options['with'] = "'name=%s&value=' + value" % (field_id) + else: + options['with'] = "Form.Element.serialize(%s)" % field_id + field_id = "$('%s')" % field_id + + + callback = remoteFunction(url, **options) + callback = collapse(callback) + + print >>output, "new %s(%s," % (klass, field_id) + if options.get("frequency"): + print >>output, "%s," % options['frequency'] + print >>output, "function(element, value) { %s })" % callback + return javascript_tag(output.getvalue()) + + +def observeField(url, field_id=None, options=None, **kwargs): + if options: kwargs.update(options) + if kwargs.get("frequency"): + klass = "Form.Element.Observer" + else: + klass = "Form.Element.EventObserver" + + return build_observer(klass, url, field_id, kwargs) + +def observeForm(url, form_id, options=None, **kwargs): + if options: kwargs.update(options) + if kwargs.get("frequency"): + klass = "Form.Observer" + else: + klass = "Form.EventObserver" + return build_observer(klass, url, form_id, kwargs) + + +def visualEffect(name, target, options=None, **kwargs): + if options: kwargs.update(options) + return "new Effect.%s($('%s'),%s)" %(name, target, options_for_javascript(kwargs)) + + +def eval_remote(): + return "eval(request.responseText)" + + +def update_element(element_id, options=None, **kwargs): + if options: kwargs.update(options) + content = kwargs.get("content", "") + #content = escape_js(content) + position = mapInsert(kwargs.get('where')) + function = { + 'update' : "new Insertion.%s('%s', '%s')" % ( position, + element_id, + content), + 'empty' : "$('%s').innerHTML = ''" % element_id, + 'remove' : "Element.remove('%s')" % element_id, + }.get(kwargs.get('action')) + + return function + +def checkedField(url, field_id, options=None, **kwargs): + if options: kwargs.update(options) + # The id of the error location + error = kwargs.get("error", "error") + onError = "%s; Field.activate('%s');" % ( + visualEffect('Appear', error), + field_id) + + return observeField(url, field_id, + {'update' : + { 'success' : error, + 'failure' : error}, + 'success' : visualEffect('DropOut', error), + 'failure' : onError}, **kwargs) + +def inPlaceEditor(url, field_id, options=None, **kwargs): + """will call url with <field_id>=value. Save and return the value + in your method. + + takes rows, cols + """ + + if options: kwargs.update(options) + # we hack the form submit to include both the name and the value + kwargs.setdefault('js', {})['callback'] = \ + """function(form, value) { return 'name=%s&value=' + value}""" % (field_id) + + options = options_for_ajax(kwargs) + return javascript_tag("new Ajax.InPlaceEditor('%s', '%s', %s);" % ( + field_id, url, options)) + + +__all__ = ['remoteFunction', 'linkTo', "remoteForm", "submitRemote", + "observeField", 'visualEffect' + ] + Added: Bling/trunk/Bling/conf/depends.conf ============================================================================== --- (empty file) +++ Bling/trunk/Bling/conf/depends.conf Wed Jan 25 23:28:34 2006 @@ -0,0 +1,8 @@ +# List the product dependencies here +# +# Dependencies take the following form: +# +# require kupu +# optional ATReferenceWidget + +#{ProductDepends, text, insertBefore}# Added: Bling/trunk/Bling/conf/depends.xml ============================================================================== --- (empty file) +++ Bling/trunk/Bling/conf/depends.xml Wed Jan 25 23:28:34 2006 @@ -0,0 +1,9 @@ +<schema> + <description format="rest"> +Dependency Schema. Simply indicate which products your depends on and +the runtime can install them for you or take appropriate action. + </description> + +<multikey name="require" attribute="require" handler="required"/> +<multikey name="optional" attribute="optional" handler="optional"/> +</schema> Added: Bling/trunk/Bling/config.py ============================================================================== --- (empty file) +++ Bling/trunk/Bling/config.py Wed Jan 25 23:28:34 2006 @@ -0,0 +1,15 @@ +""" +Bling + +Ajax utilis, server side to generate client side w/o much JS + +$Id: $ +""" + +__authors__ = 'bcsaller', +__docformat__ = 'text/restructured' + +PROJECT_NAME = 'Bling' +SKINS_DIR = 'skins' +GLOBALS = globals() + Added: Bling/trunk/Bling/content/__init__.py ============================================================================== --- (empty file) +++ Bling/trunk/Bling/content/__init__.py Wed Jan 25 23:28:34 2006 @@ -0,0 +1 @@ +#{ModuleLevelCode, code, insertAfter}# Added: Bling/trunk/Bling/distext/__init__.py ============================================================================== --- (empty file) +++ Bling/trunk/Bling/distext/__init__.py Wed Jan 25 23:28:34 2006 @@ -0,0 +1,16 @@ +"""This package contains extensions to distutils. Its my hope we can +move some of this into a proper set of Plone shared code +""" +from test import TestCommand +from doc import DocCommand +import utils + +def extensions(): + return { + 'test' : TestCommand, + 'doc' : DocCommand, + } + + +__all__ = ['TestCommand', 'DocCommand', 'utils'] + Added: Bling/trunk/Bling/distext/doc.py ============================================================================== --- (empty file) +++ Bling/trunk/Bling/distext/doc.py Wed Jan 25 23:28:34 2006 @@ -0,0 +1,34 @@ +from distutils.cmd import Command +from utils import useBuildPath, getBuildPath +import os, sys + +class DocCommand(Command): + """Command to build the documentation associated with a project""" + + description = """Command to build the documentation associated with a project""" + + user_options = [] + + def initialize_options(self): + pass + + def finalize_options(self): + pass + + def run(self): + # make sure the tests pass and we can use the build dir to + # generate docs + #self.run_command('test') + useBuildPath() + + base_pkg = self.distribution.packages[0] + self.announce('building docs %s' % base_pkg) + + base_dir = os.path.join(getBuildPath(), base_pkg) + + doc_dir = os.path.join(os.getcwd(), "docs") + os.system("epydoc -qq --pdf --inheritance listed -n %s -o %s %s &> /dev/null" % (base_pkg, + doc_dir, + base_dir)) + + self.announce("documentation built") Added: Bling/trunk/Bling/distext/install.py ============================================================================== --- (empty file) +++ Bling/trunk/Bling/distext/install.py Wed Jan 25 23:28:34 2006 @@ -0,0 +1,52 @@ +from distutils.command.install import install +from distutils.errors import DistutilsOptionError +from utils import useBuildPath, getBuildPath +import os, sys + + + +PRODUCT_SCHEME = { + 'purelib': '$base', + 'platlib': '$base', + 'data' : '$base', + } + +SCHEME_KEYS = ('purelib', 'platlib', 'data') + + +class InstallCommand(install): + """Build and install a Product in a Zope/Plone site""" + + description = """Build and install a Product in a Zope/Plone site""" + + def finalize_options(self): + if not self.prefix or not os.access(self.prefix, os.W_OK): + self.guess_prefix() + + install.finalize_options(self) + # Process the install arguments as they exist in stock + # distutils to mean a Products directory + + if not self.prefix: + raise DistutilsOptionError, \ + ("must supply a prefix that is your products directory") + if not os.access(self.prefix, os.W_OK): + raise DistutilsOptionError, \ + ("specify your products dir using --prefix (must be writeable)") + + def guess_prefix(self): + """The user could have set an environ var for Products""" + # XXX: or set a file in their homedir + pd = os.environ.get("PRODUCTS_DIR") + if pd is not None: + self.prefix = pd + + def select_scheme(self, name): + """Ignore the scheme the system detected and use the uniform + product installer (which is flat) + """ + # it's the caller's problem if they supply a bad name! + scheme = PRODUCT_SCHEME + for key in SCHEME_KEYS: + attrname = 'install_' + key + setattr(self, attrname, scheme[key]) Added: Bling/trunk/Bling/distext/pkgconfig.py ============================================================================== --- (empty file) +++ Bling/trunk/Bling/distext/pkgconfig.py Wed Jan 25 23:28:34 2006 @@ -0,0 +1,44 @@ +""" +pkgconfig +~~~~~~~~~~~~~~~~~~~~ +A small wrapper around pkg-config program used to manage libraries and +dependencies. + +""" + +__author__ = 'Benjamin Saller <bcs...@ob...>' +__docformat__ = 'restructuredtext' +__copyright__ = 'Copyright ObjectRealms, LLC. 2005' +__license__ = 'The GNU Public License V2+' + + +from subprocess import Popen, PIPE + +PKG_CONFIG="pkg-config" +def pkgconfig(packages): + """Given a list of packages return a list of all includes and a + list of all library dependencies. If the package doesn't exist and + exception will be thrown + """ + + # Process Includes + includes = "%s --cflags-only-I %s" % (PKG_CONFIG, packages) + p = Popen([includes], shell=True, + stdin=PIPE, stdout=PIPE, stderr=PIPE, + close_fds=True) + + includes_list = [b[2:] for b in p.stdout.read().split()] + p.wait() + if p.returncode != 0: raise ValueError(p.stderr.read()) + + # Process Libs + libs = "%s --libs-only-l %s" % (PKG_CONFIG, packages) + p = Popen([libs], shell=True, + stdin=PIPE, stdout=PIPE, stderr=PIPE, + close_fds=True) + + libs_list = [b[2:] for b in p.stdout.read().split()] + p.wait() + if p.returncode != 0: raise ValueError(p.stderr.read()) + + return includes_list, libs_list Added: Bling/trunk/Bling/distext/test.py ============================================================================== --- (empty file) +++ Bling/trunk/Bling/distext/test.py Wed Jan 25 23:28:34 2006 @@ -0,0 +1,42 @@ +from distutils.cmd import Command +from utils import useBuildPath, getBuildPath +import os, sys + +class TestCommand(Command): + """Command to run unit tests after installation""" + + description = "run unit tests after installation" + + user_options = [] + + def initialize_options(self): + pass + + def finalize_options(self): + pass + + def run(self): + # build and use the just built lib + self.run_command('build') + useBuildPath() + + base_pkg = self.distribution.packages[0] + + self.announce('running unittest for %s' % base_pkg) + + # Change into the build tests directory + old_path = os.getcwd() + os.chdir(os.path.join(getBuildPath(), + base_pkg, + "tests")) + # make sure we can import these tests which currently + # do a scan of cwd + sys.path.insert(0, '.') + + # import the module and invoke its main() + m = __import__("tests.runalltests", + globals(), globals(), ['runalltests']) + m.main() + os.chdir(old_path) + + Added: Bling/trunk/Bling/distext/utils.py ============================================================================== --- (empty file) +++ Bling/trunk/Bling/distext/utils.py Wed Jan 25 23:28:34 2006 @@ -0,0 +1,17 @@ +#!/usr/bin/python2.4 +import os, sys +from distutils.util import get_platform + + +def getBuildPath(): + plat_specifier = ".%s-%s" % (get_platform(), sys.version[0:3]) + build_platlib = os.path.join("build", 'lib' + plat_specifier) + test_lib = os.path.abspath(build_platlib) + if not os.path.exists(test_lib): + build_platlib = os.path.join("build", 'lib') + test_lib = os.path.abspath(build_platlib) + return test_lib + +def useBuildPath(): + sys.path.insert(0, getBuildPath()) + Added: Bling/trunk/Bling/docs/Makefile ============================================================================== --- (empty file) +++ Bling/trunk/Bling/docs/Makefile Wed Jan 25 23:28:34 2006 @@ -0,0 +1,8 @@ +all: docs + +docs: walkthrough.rst style.css + @rst2html --stylesheet-path=style.css walkthrough.rst > walkthrough.html + +clean: + @rm -f walkthrough.html + Added: Bling/trunk/Bling/docs/style.css ============================================================================== --- (empty file) +++ Bling/trunk/Bling/docs/style.css Wed Jan 25 23:28:34 2006 @@ -0,0 +1,72 @@ +body { + background: #f2f2f2; + color: #5f4f33; + font-family: arial, sans; + font-size: 12px; + font-style: normal; + line-height: normal; + text-transform: none; +} + +.docinfo { + text-align: left; +} + + +dt { + font-weight: bold; +} + +.literal-block { + whitespace: pre; + font: 1.2em monospace; + font-weight: bold; + border: 1px solid black; + background-color: #c7c1ab; + padding: 4px; + margin-right: 10%; + } + +h1, h2, h3, h4, h5, h6 { + color: black; + border-bottom: 2px inset black; + width: 80%; +} + +div { + padding-right: 30px; + } + +@media projection { + h1, h2, h3, h4, h5, h6, hr { + page-break-before: always; + } + + hr { + clear: both; + border: 0; + } + + h1, h2 { + font-size: 50px; + } + + + h1.title { + page-break-before: avoid; + } + + body{ + background: url(http://objectrealms.net/images/icon.gif) no-repeat fixed 95% 95%; + font-size: 100%; + } + + dl, ol, ul { + font-size: 1.2em !important; + text-align: left; + margin: .5em; + } + + /* A sort of funny presentation style */ + / * p { display: none; } */ +} Added: Bling/trunk/Bling/docs/walkthrough.rst ============================================================================== --- (empty file) +++ Bling/trunk/Bling/docs/walkthrough.rst Wed Jan 25 23:28:34 2006 @@ -0,0 +1,116 @@ +=========================================== +Bling +=========================================== + +:author: bcsaller +:date: 12/06/2005 +:version: Version 0.1 + + + +Introduction +~~~~~~~~~~~~ + +The big picture: What does this product do? What problem(s) does it solve? +Who is it intended for? + +Using Bling +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +How does one use this used? + +Code overview +~~~~~~~~~~~~~ + +A high level sketch of the main code components and how they interact. + +Code details +~~~~~~~~~~~~ + +Any details of the code's operation that are particularly useful + +Are there any settings that need configuring on installation? + +Code Layout +~~~~~~~~~~~ + +:: + + /Project/ + /content + /docs + /Extensions + /lib + /skins/ + /projectskin + /tests/ + /tools + + README.txt + __init__.py + config.py + permissions.py + version.txt + + + +Descriptions of each project element follow: + +content/ + Projects that introduce content types should place each + content types implementation in a file in this directory. + +distext/ + Infrastructure used in package management. + +doc/ + Information about installing and using your product go here + +Extensions/ + The installer for your product goes here and will be used by + the QuickInstaller product to easily add/remove your product from a + site. + +lib/ + Library level code for this project. Many projects only + introduce skins and content types and will not need to include a lib + directory. + +skins/ + PageTemplates, Python scripts and static content (typically + images) related to your project go into subdirectories here with names + that make sense to you. + +tests/ + Every project should include tests of new features and code + that it introduces. Plone and Archetypes leverage powerful testing + frameworks that make this simple to do. It speeds development and + saves debugging time. + +tools/ + If your project provides additional tools you might include + those here. + + +README.txt + Your projects letter of introduction. + +__init__.py + Includes boilerplate code that will register the project + elements with Zope and Archetypes as needed. + + +config.py + Typically I use config.py to include static definitions and + variables that are the product of import time decisions. config.py + should contain only immutable variables as a matter of convention. + +permissions.py + If you require additional security permissions for your new + content or tools it is suggested you place them here + +version.txt + A simple text file containing a version string used when + talking about the product. + + Added: Bling/trunk/Bling/permissions.py ============================================================================== --- (empty file) +++ Bling/trunk/Bling/permissions.py Wed Jan 25 23:28:34 2006 @@ -0,0 +1,56 @@ +from Products.Archetypes import public as atapi +from Products.CMFCore import permissions as cmfcore_permissions +import config + +# This file is used to set up permissions for your product. + +# The code below will create a unique add permission for each of your +# content types. The permission for adding the type MyContentType will +# be 'MyProject: Add MyContentType'. If instead you want to specify +# your own add permission (e.g. use the CMF's 'Add portal content' +# permission), you can use the ADD_PERMISSIONS dictionary to do so. + +# ADD_PERMISSIONS is used to specify the name of the permission +# used for adding one of your content types. For example: +# +# ADD_PERMISSIONS = {'MyFirstContentType': 'Add portal content', +# 'MySecondContentType': 'My other permission', +# } + +ADD_PERMISSIONS = {} + +# The SITEWIDE_PERMISSIONS dictionary is used for assigning permissions +# to different roles site-wide. For example, if you create the new roles +# 'Czar' and 'Peasant', you could give them the 'Add portal folders' and +# 'Delete objects' permissions like so: +# +# SITEWIDE_PERMISSIONS = ( +# (['Czar', 'Peasant'], ['Add portal folders', 'Delete objects'']), +# ) +# +# In general, the pattern is +# +# SITEWIDE_PERMISSIONS = ( +# ([list of roles], [list of permissions]), +# ([second list of roles], [second list of permissions]), +# ) +# +# The site-wide permissions are set in Extensions/Install.py + +SITEWIDE_PERMISSIONS = () + + +def initialize(): + permissions = {} + types = atapi.listTypes(config.PROJECT_NAME) + for atype in types: + portal_type = atype['portal_type'] + permission = ADD_PERMISSIONS.get(portal_type, None) + if permission is None: + # construct a permission on the fly + permission = "%s: Add %s" % (config.PROJECT_NAME, + portal_type) + cmfcore_permissions.setDefaultRoles(permission, ('Manager',)) + permissions[portal_type] = permission + + return permissions Added: Bling/trunk/Bling/refresh.txt ============================================================================== Added: Bling/trunk/Bling/setup.py ============================================================================== --- (empty file) +++ Bling/trunk/Bling/setup.py Wed Jan 25 23:28:34 2006 @@ -0,0 +1,35 @@ +from setuptools import setup, find_packages +import distext + +classifiers = [ + "Programming Language :: Python", + "Development Status :: 3 - Alpha", + "Natural Language :: English", + "Operating System :: OS Independent", + #{ProductClassifier, text, insertBefore}#, + ] +setup( + name = 'Bling', + author = 'bcsaller', + maintainer = 'bcsaller', + maintainer_email = 'bcs...@ob...', + url = "", + license = "GPL", + version = '0.1', + platforms = ["Python >= 2.4", "Zope >= 2.8", "Plone >= 2.1"], + description = """Ajax utilis, server side to generate client side w/o much JS""", + classifiers = classifiers, + packages = ['.'] + find_packages(), + entry_points = { + 'zope2.initialize': + ['initialize=Bling:initialize'] + }, + + package_data = { + 'Bling': + ['*', 'conf/*', 'content/*', 'distext/*', 'docs/*', 'Extensions/*', 'skins/*', 'tests/*', 'tools/*'] + }, + + zip_safe = False, + cmdclass = distext.extensions(), + ) Added: Bling/trunk/Bling/skins/bling/behaviour.js ============================================================================== --- (empty file) +++ Bling/trunk/Bling/skins/bling/behaviour.js Wed Jan 25 23:28:34 2006 @@ -0,0 +1,101 @@ +/** + +ModifiedBehavior v1.0 by Ron Lancaster based on Ben Nolan's Behaviour, June 2005 implementation. +Modified to use Dean Edward's CSS Query. + +Description +---------- + +Uses css selectors to apply javascript Behaviors to enable unobtrusive javascript in html documents. + +Dependencies +------------ + +Requires [Dean Edwards CSSQuery](http://dean.edwards.name/my/cssQuery/ "CSSQuery"). + +Usage +------ + + Behavior.register( + "b.someclass", + function(element) { + element.onclick = function(){ + alert(this.innerHTML); + } + } + ); + + Behavior.register( + "#someid u", + function(element) { + element.onmouseover = function(){ + this.innerHTML = "BLAH!"; + } + }, + getElementByID("parent") + ); + +Call `Behavior.apply()` to re-apply the rules (if you update the dom, etc). + +License +------ + +Reproduced under BSD licensed. Same license as Ben Nolan's implementation. + +More information for Ben Nolan's implementation: <http://ripcord.co.nz/behaviour/> + +*/ + +var Behavior = { + + // private data member + list : new Array(), + + // private method + addLoadEvent : function(func) { + var oldonload = window.onload; + + if (typeof window.onload != 'function') { + window.onload = func; + } else { + window.onload = function() { + oldonload(); + func(); + } + } + }, + + // void apply() : Applies the registered ruleset. + apply : function() { + for (i = 0; i < Behavior.list.length; i++) { + var rule = Behavior.list[i]; + var tags = cssQuery(rule.selector, rule.from); + if (tags) { + for (j = 0; j < tags.length; j++) { + rule.action(tags[j]); + } + } + } + }, + + // void register() : register a css selector, and the action (function) to take, + // from (optional) is a document, element or array of elements which is filtered by selector. + register : function(selector, action, from) { + Behavior.list.push(new BehaviorRule(selector, from, action)); + }, + + // void start() : initial application of ruleset at document load. + start : function() { + Behavior.addLoadEvent(function() { + Behavior.apply(); + }); + } +} + +function BehaviorRule(selector, from, action) { + this.selector = selector; + this.from = from; + this.action = action; +} + +Behavior.start(); \ No newline at end of file Added: Bling/trunk/Bling/skins/bling/bling.js ============================================================================== --- (empty file) +++ Bling/trunk/Bling/skins/bling/bling.js Wed Jan 25 23:28:34 2006 @@ -0,0 +1,165 @@ +Ajax.InPlaceDesign = Class.create(); +Ajax.InPlaceDesign.prototype = { + + initialize: function(element, url, options) { + this.url = url; + this.element = $(element); + this.options = Object.extend({}); + + this.onclickListener = this.createForm.bindAsEventListener(this); + Event.observe(this.element, 'dblclick', this.onclickListener); + tinyMCE.init({ + mode : "none", + theme : "advanced", + plugins : "ajax_save", + auto_resize : true, + table_inline_editing : true, + theme_advanced_buttons1 : + "save,bold,italic,underline,separator,strikethrough,justifyleft,justifycenter,justifyright,justifyfull,bullist,numlist,undo,redo", + theme_advanced_buttons2 : "", + theme_advanced_buttons3 : "", + theme_advanced_toolbar_location : "bottom", + theme_advanced_toolbar_align : "left", + theme_advanced_fonts : + "Arial=arial,helvetica,sans-serif;Courier New=courier new,courier,monospace", + extended_valid_elements : + "a[name|href|target|title|onclick],img[class|src|border=0|alt|title|hspace|vspace|width|height|align|onmouseover|onmouseout|name],hr[class|width|size|noshade],font[face|size|color|style],span[class|align|style]" + }); + + }, + + createForm: function () { + this.form = document.createElement("form"); + this.form.id = this.element.id + "_form"; + this.form.name = this.element.id + "_form"; + + // Add element as a child and replace self + var parent = this.element.parentNode; + parent.insertBefore(this.form, this.element); + parent.removeChild(this.element); + this.form.appendChild(this.element); + this.form.onsubmit = this.onSubmit.bind(this); + //Now that element is wrapped in a form + // we can create the editor + this.createEditField(); + }, + + createEditField: function () { + tinyMCE.execCommand('mceAddControl', true, this.element.id); + }, + + onSubmit: function() { + // onLoading resets these so we need to save them away for the Ajax call + var form = this.form; + var value = tinyMCE.selectedInstance.forElement.innerHTML; + + // do this first, sometimes the ajax call returns before we get a chance to switch on Saving... + // which means this will actually switch on Saving... *after* we've left edit mode causing Saving... + // to be displayed indefinitely + this.onLoading(); + + new Ajax.Updater( + { + success: this.element, + // don't update on failure (this could be an option) + failure: null + }, + this.url, + Object.extend({ + parameters: this.options.callback(form, value), + onComplete: this.onComplete.bind(this), + onFailure: this.onFailure.bind(this) + }, this.options.ajaxOptions) + ); + // stop the event to avoid a page refresh in Safari + if (arguments.length > 1) { + Event.stop(arguments[0]); + } + return false; + }, + + onComplete: function(transport) { + this.options.onComplete.bind(this)(transport, this.element); + }, + + onFailure: function(transport) { + alert("Error communicating with the server: " + transport.responseText.stripTags()); + }, + + onLoading: function() { + this.saving = true; + this.removeForm(); + this.leaveHover(); + this.showSaving(); + }, + + showSaving: function() { + this.oldInnerHTML = this.element.innerHTML; + this.element.innerHTML = this.options.savingText; + Element.addClassName(this.element, this.options.savingClassName); + this.element.style.backgroundColor = this.originalBackground; + Element.show(this.element); + }, + + removeForm: function() { + if(this.form) { + if (this.form.parentNode) Element.remove(this.form); + this.form = null; + tinyMCE.execCommand('mceRemoveControl', true, this.element.id); + } + }, + +}; + +// Ajax.InPlaceDesign = Class.create(); +// Ajax.InPlaceDesign.prototype = { +// initialize : function(element, url, options) { +// this.url = url; +// this.element = $(element); +// this.options = options; +// this.onclickListener = this.createForm.bindAsEventListener(this); +// Event.observe(this.element, 'dblclick', this.onclickListener); +// }, + +// // enterEditMode: function(evt) { +// // if (this.saving) return; +// // if (this.editing) return; +// // this.editing = true; +// // this.onEnterEditMode(); +// // //Element.hide(this.element); +// // this.createForm(); +// // this.element.parentNode.insertBefore(this.form, this.element); +// // Field.scrollFreeActivate(this.editField); +// // // stop the event to avoid a page refresh in Safari +// // if (evt) { +// // Event.stop(evt); +// // } +// // return false; +// // }, + +// createForm: function(evt) { +// tinyMCE.init({ +// mode : "exact", +// elements : this.element.id, +// //save_callback: "save +// theme : "advanced", +// auto_resize : true, +// plugins: "save, advimage", +// theme_advanced_buttons1 : +// "save,bold,italic,underline,separator,strikethrough,justifyleft,justifycenter,justifyright, justifyfull,bullist,numlist,undo,redo,link,unlink", +// theme_advanced_buttons2 : "", +// theme_advanced_buttons3 : "", +// theme_advanced_toolbar_location : "bottom", +// theme_advanced_toolbar_align : "left", +// extended_valid_elements : +// "a[name|href|target|title|onclick],img[class|src|border=0|alt|title|hspace|vspace|width|height|align|onmouseover|onmouseout|name],hr[class|width|size|noshade],font[face|size|color|style],span[class|align|style]" +// }); +// }, + + +// onEnterEditMode: function() {}, +// onLeaveEditMode: function() {}, + +// }; + + Added: Bling/trunk/Bling/skins/bling/builder.js ============================================================================== --- (empty file) +++ Bling/trunk/Bling/skins/bling/builder.js Wed Jan 25 23:28:34 2006 @@ -0,0 +1,101 @@ +// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// +// See scriptaculous.js for full license. + +var Builder = { + NODEMAP: { + AREA: 'map', + CAPTION: 'table', + COL: 'table', + COLGROUP: 'table', + LEGEND: 'fieldset', + OPTGROUP: 'select', + OPTION: 'select', + PARAM: 'object', + TBODY: 'table', + TD: 'table', + TFOOT: 'table', + TH: 'table', + THEAD: 'table', + TR: 'table' + }, + // note: For Firefox < 1.5, OPTION and OPTGROUP tags are currently broken, + // due to a Firefox bug + node: function(elementName) { + elementName = elementName.toUpperCase(); + + // try innerHTML approach + var parentTag = this.NODEMAP[elementName] || 'div'; + var parentElement = document.createElement(parentTag); + try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707 + parentElement.innerHTML = "<" + elementName + "></" + elementName + ">"; + } catch(e) {} + var element = parentElement.firstChild || null; + + // see if browser added wrapping tags + if(element && (element.tagName != elementName)) + element = element.getElementsByTagName(elementName)[0]; + + // fallback to createElement approach + if(!element) element = document.createElement(elementName); + + // abort if nothing could be created + if(!element) return; + + // attributes (or text) + if(arguments[1]) + if(this._isStringOrNumber(arguments[1]) || + (arguments[1] instanceof Array)) { + this._children(element, arguments[1]); + } else { + var attrs = this._attributes(arguments[1]); + if(attrs.length) { + try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707 + parentElement.innerHTML = "<" +elementName + " " + + attrs + "></" + elementName + ">"; + } catch(e) {} + element = parentElement.firstChild || null; + // workaround firefox 1.0.X bug + if(!element) { + element = document.createElement(elementName); + for(attr in arguments[1]) + element[attr == 'class' ? 'className' : attr] = arguments[1][attr]; + } + if(element.tagName != elementName) + element = parentElement.getElementsByTagName(elementName)[0]; + } + } + + // text, or array of children + if(arguments[2]) + this._children(element, arguments[2]); + + return element; + }, + _text: function(text) { + return document.createTextNode(text); + }, + _attributes: function(attributes) { + var attrs = []; + for(attribute in attributes) + attrs.push((attribute=='className' ? 'class' : attribute) + + '="' + attributes[attribute].toString().escapeHTML() + '"'); + return attrs.join(" "); + }, + _children: function(element, children) { + if(typeof children=='object') { // array can hold nodes and text + children.flatten().each( function(e) { + if(typeof e=='object') + element.appendChild(e) + else + if(Builder._isStringOrNumber(e)) + element.appendChild(Builder._text(e)); + }); + } else + if(Builder._isStringOrNumber(children)) + element.appendChild(Builder._text(children)); + }, + _isStringOrNumber: function(param) { + return(typeof param=='string' || typeof param=='number'); + } +} \ No newline at end of file Added: Bling/trunk/Bling/skins/bling/controls.js ============================================================================== --- (empty file) +++ Bling/trunk/Bling/skins/bling/controls.js Wed Jan 25 23:28:34 2006 @@ -0,0 +1,750 @@ +// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// (c) 2005 Ivan Krstic (http://blogs.law.harvard.edu/ivan) +// (c) 2005 Jon Tirsen (http://www.tirsen.com) +// Contributors: +// Richard Livsey +// Rahul Bhargava +// Rob Wills +// +// See scriptaculous.js for full license. + +// Autocompleter.Base handles all the autocompletion functionality +// that's independent of the data source for autocompletion. This +// includes drawing the autocompletion menu, observing keyboard +// and mouse events, and similar. +// +// Specific autocompleters need to provide, at the very least, +// a getUpdatedChoices function that will be invoked every time +// the text inside the monitored textbox changes. This method +// should get the text for which to provide autocompletion by +// invoking this.getToken(), NOT by directly accessing +// this.element.value. This is to allow incremental tokenized +// autocompletion. Specific auto-completion logic (AJAX, etc) +// belongs in getUpdatedChoices. +// +// Tokenized incremental autocompletion is enabled automatically +// when an autocompleter is instantiated with the 'tokens' option +// in the options parameter, e.g.: +// new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' }); +// will incrementally autocomplete with a comma as the token. +// Additionally, ',' in the above example can be replaced with +// a token array, e.g. { tokens: [',', '\n'] } which +// enables autocompletion on multiple tokens. This is most +// useful when one of the tokens is \n (a newline), as it +// allows smart autocompletion after linebreaks. + +var Autocompleter = {} +Autocompleter.Base = function() {}; +Autocompleter.Base.prototype = { + baseInitialize: function(element, update, options) { + this.element = $(element); + this.update = $(update); + this.hasFocus = false; + this.changed = false; + this.active = false; + this.index = 0; + this.entryCount = 0; + + if (this.setOptions) + this.setOptions(options); + else + this.options = options || {}; + + this.options.paramName = this.options.paramName || this.element.name; + this.options.tokens =... [truncated message content] |