--- a/.hgtags Fri Mar 12 15:05:33 2010 +0100
+++ b/.hgtags Fri Mar 12 16:11:56 2010 +0100
@@ -105,3 +105,5 @@
4ae30c9ca11b1edad67d25b76fce672171d02023 cubicweb-version-3.6.1
b9cdfe3341d1228687515d9af8686971ad5e6f5c cubicweb-debian-version-3.6.1-1
0a16f07112b90fb61d2e905855fece77e5a7e39c cubicweb-debian-version-3.6.1-2
+bfebe3d14d5390492925fc294dfdafad890a7104 cubicweb-version-3.6.2
+f3b4bb9121a0e7ee5961310ff79e61c890948a77 cubicweb-debian-version-3.6.2-1
--- a/__pkginfo__.py Fri Mar 12 15:05:33 2010 +0100
+++ b/__pkginfo__.py Fri Mar 12 16:11:56 2010 +0100
@@ -7,7 +7,7 @@
distname = "cubicweb"
modname = "cubicweb"
-numversion = (3, 6, 1)
+numversion = (3, 6, 2)
version = '.'.join(str(num) for num in numversion)
license = 'LGPL'
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/_gcdebug.py Fri Mar 12 16:11:56 2010 +0100
@@ -0,0 +1,87 @@
+
+import gc, types, weakref
+
+from cubicweb.schema import CubicWebRelationSchema, CubicWebEntitySchema
+
+listiterator = type(iter([]))
+
+IGNORE_CLASSES = (
+ type, tuple, dict, list, set, frozenset, type(len),
+ weakref.ref, weakref.WeakKeyDictionary,
+ listiterator,
+ property, classmethod,
+ types.ModuleType, types.FunctionType, types.MethodType,
+ types.MemberDescriptorType, types.GetSetDescriptorType,
+ )
+
+def _get_counted_class(obj, classes):
+ for cls in classes:
+ if isinstance(obj, cls):
+ return cls
+ raise AssertionError()
+
+def gc_info(countclasses,
+ ignoreclasses=IGNORE_CLASSES,
+ viewreferrersclasses=(), showobjs=False, maxlevel=1):
+ gc.collect()
+ gc.collect()
+ counters = {}
+ ocounters = {}
+ for obj in gc.get_objects():
+ if isinstance(obj, countclasses):
+ cls = _get_counted_class(obj, countclasses)
+ try:
+ counters[cls.__name__] += 1
+ except KeyError:
+ counters[cls.__name__] = 1
+ elif not isinstance(obj, ignoreclasses):
+ try:
+ key = '%s.%s' % (obj.__class__.__module__,
+ obj.__class__.__name__)
+ except AttributeError:
+ key = str(obj)
+ try:
+ ocounters[key] += 1
+ except KeyError:
+ ocounters[key] = 1
+ if isinstance(obj, viewreferrersclasses):
+ print ' ', obj, referrers(obj, showobjs, maxlevel)
+ return counters, ocounters, gc.garbage
+
+
+def referrers(obj, showobj=False, maxlevel=1):
+ objreferrers = _referrers(obj, maxlevel)
+ try:
+ return sorted(set((type(x), showobj and x or getattr(x, '__name__', '%#x' % id(x)))
+ for x in objreferrers))
+ except TypeError:
+ s = set()
+ unhashable = []
+ for x in objreferrers:
+ try:
+ s.add(x)
+ except TypeError:
+ unhashable.append(x)
+ return sorted(s) + unhashable
+
+def _referrers(obj, maxlevel, _seen=None, _level=0):
+ interesting = []
+ if _seen is None:
+ _seen = set()
+ for x in gc.get_referrers(obj):
+ if id(x) in _seen:
+ continue
+ _seen.add(id(x))
+ if isinstance(x, types.FrameType):
+ continue
+ if isinstance(x, (CubicWebRelationSchema, CubicWebEntitySchema)):
+ continue
+ if isinstance(x, (list, tuple, set, dict, listiterator)):
+ if _level >= maxlevel:
+ pass
+ #interesting.append(x)
+ else:
+ interesting += _referrers(x, maxlevel, _seen, _level+1)
+ else:
+ interesting.append(x)
+ return interesting
--- a/cwconfig.py Fri Mar 12 15:05:33 2010 +0100
+++ b/cwconfig.py Fri Mar 12 16:11:56 2010 +0100
@@ -217,7 +217,9 @@
if os.environ.get('APYCOT_ROOT'):
mode = 'test'
- if CWDEV:
+ # allow to test cubes within apycot using cubicweb not installed by
+ # apycot
+ if __file__.startswith(os.environ['APYCOT_ROOT']):
CUBES_DIR = '%(APYCOT_ROOT)s/local/share/cubicweb/cubes/' % os.environ
# create __init__ file
file(join(CUBES_DIR, '__init__.py'), 'w').close()
@@ -638,16 +640,18 @@
"""base class for cubicweb server and web configurations"""
INSTANCES_DATA_DIR = None
- if CubicWebNoAppConfiguration.mode == 'test':
+ if os.environ.get('APYCOT_ROOT'):
root = os.environ['APYCOT_ROOT']
REGISTRY_DIR = '%s/etc/cubicweb.d/' % root
+ if not exists(REGISTRY_DIR):
+ os.makedirs(REGISTRY_DIR)
RUNTIME_DIR = tempfile.gettempdir()
- if CWDEV:
+ # allow to test cubes within apycot using cubicweb not installed by
+ # apycot
+ if __file__.startswith(os.environ['APYCOT_ROOT']):
MIGRATION_DIR = '%s/local/share/cubicweb/migration/' % root
else:
MIGRATION_DIR = '/usr/share/cubicweb/migration/'
- if not exists(REGISTRY_DIR):
- os.makedirs(REGISTRY_DIR)
else:
if CubicWebNoAppConfiguration.mode == 'user':
REGISTRY_DIR = expanduser('~/etc/cubicweb.d/')
--- a/debian/changelog Fri Mar 12 15:05:33 2010 +0100
+++ b/debian/changelog Fri Mar 12 16:11:56 2010 +0100
@@ -1,3 +1,18 @@
+cubicweb (3.6.2-2) unstable; urgency=low
+
+ * remove postgresql-contrib from cubicweb dependency (using tsearch
+ which is included with postgres >= 8.3)
+ * add postgresql-client | mysql-client to cubicweb-server dependencies, necessary
+ for dump/restore of database
+
+ --
+
+cubicweb (3.6.2-1) unstable; urgency=low
+
+ * new upstream release
+
+ -- Sylvain Thénault <sylvain.thenault@logilab.fr> Thu, 11 Mar 2010 19:49:04 +0100
+
cubicweb (3.6.1-2) unstable; urgency=low
* remove depends to python-elementtree (included in python>=2.5)
--- a/debian/control Fri Mar 12 15:05:33 2010 +0100
+++ b/debian/control Fri Mar 12 16:11:56 2010 +0100
@@ -16,7 +16,7 @@
Architecture: all
XB-Python-Version: ${python:Versions}
Depends: ${python:Depends}, cubicweb-server (= ${source:Version}), cubicweb-twisted (= ${source:Version})
-XB-Recommends: (postgresql, postgresql-plpython, postgresql-contrib) | mysql | sqlite3
+XB-Recommends: (postgresql, postgresql-plpython) | mysql | sqlite3
Recommends: postgresql | mysql | sqlite3
Description: the complete CubicWeb framework
CubicWeb is a semantic web application framework.
@@ -33,7 +33,8 @@
Conflicts: cubicweb-multisources
Replaces: cubicweb-multisources
Provides: cubicweb-multisources
-Depends: ${python:Depends}, cubicweb-common (= ${source:Version}), cubicweb-ctl (= ${source:Version}), python-logilab-database, python-psycopg2 | python-mysqldb | python-pysqlite2
+# postgresql/mysql -client packages for backup/restore of non local database
+Depends: ${python:Depends}, cubicweb-common (= ${source:Version}), cubicweb-ctl (= ${source:Version}), python-logilab-database, (python-psycopg2, postgresql-client) | (python-mysqldb, mysql-client) | python-pysqlite2
Recommends: pyro, cubicweb-documentation (= ${source:Version})
Description: server part of the CubicWeb framework
CubicWeb is a semantic web application framework.
--- a/doc/book/en/admin/instance-config.rst Fri Mar 12 15:05:33 2010 +0100
+++ b/doc/book/en/admin/instance-config.rst Fri Mar 12 16:11:56 2010 +0100
@@ -49,13 +49,13 @@
and `https://localhost/demo` and actually running on port 8080, it
takes to the http:::
- RewriteCond %(REQUEST_URI) ^/demo
+ RewriteCond %{REQUEST_URI} ^/demo
RewriteRule ^/demo$ /demo/
RewriteRule ^/demo/(.*) http://127.0.0.1:8080/$1 [L,P]
and for the https:::
- RewriteCond %(REQUEST_URI) ^/ demo
+ RewriteCond %{REQUEST_URI} ^/ demo
RewriteRule ^/demo$/demo/
RewriteRule ^/demo/(.*) http://127.0.0.1:8080/https/$1 [L,P]
@@ -63,7 +63,7 @@
and we will file in the all-in-one.conf of the instance:::
base-url = http://localhost/demo
- https-url = `https://localhost/demo`
+ https-url = https://localhost/demo
Setting up the web client
-------------------------
--- a/i18n/en.po Fri Mar 12 15:05:33 2010 +0100
+++ b/i18n/en.po Fri Mar 12 16:11:56 2010 +0100
@@ -369,6 +369,9 @@
msgid "From:"
msgstr ""
+msgid "Garbage collection information"
+msgstr ""
+
msgid "Help"
msgstr ""
@@ -390,6 +393,12 @@
msgid "Interval_plural"
msgstr "Intervals"
+msgid "Looked up classes"
+msgstr ""
+
+msgid "Most referenced classes"
+msgstr ""
+
msgid "New BaseTransition"
msgstr "XXX"
@@ -648,6 +657,9 @@
msgid "UniqueConstraint"
msgstr "unique constraint"
+msgid "Unreachable objects"
+msgstr ""
+
msgid "Update permissions"
msgstr ""
@@ -2717,6 +2729,9 @@
msgid "may"
msgstr ""
+msgid "memory leak debugging"
+msgstr ""
+
msgid "milestone"
msgstr ""
--- a/i18n/es.po Fri Mar 12 15:05:33 2010 +0100
+++ b/i18n/es.po Fri Mar 12 16:11:56 2010 +0100
@@ -377,6 +377,9 @@
msgid "From:"
msgstr "De: "
+msgid "Garbage collection information"
+msgstr ""
+
msgid "Help"
msgstr ""
@@ -398,6 +401,12 @@
msgid "Interval_plural"
msgstr "Duraciones"
+msgid "Looked up classes"
+msgstr ""
+
+msgid "Most referenced classes"
+msgstr ""
+
msgid "New BaseTransition"
msgstr ""
@@ -656,6 +665,9 @@
msgid "UniqueConstraint"
msgstr ""
+msgid "Unreachable objects"
+msgstr ""
+
msgid "Update permissions"
msgstr "Autorización de modificar"
@@ -2785,6 +2797,9 @@
msgid "may"
msgstr "Mayo"
+msgid "memory leak debugging"
+msgstr ""
+
msgid "milestone"
msgstr "Milestone"
--- a/i18n/fr.po Fri Mar 12 15:05:33 2010 +0100
+++ b/i18n/fr.po Fri Mar 12 16:11:56 2010 +0100
@@ -376,6 +376,9 @@
msgid "From:"
msgstr "De :"
+msgid "Garbage collection information"
+msgstr "Information sur le ramasse-miette"
+
msgid "Help"
msgstr "Aide"
@@ -397,6 +400,12 @@
msgid "Interval_plural"
msgstr "Durées"
+msgid "Looked up classes"
+msgstr "Classes recherchées"
+
+msgid "Most referenced classes"
+msgstr "Classes les plus référencées"
+
msgid "New BaseTransition"
msgstr "XXX"
@@ -655,6 +664,9 @@
msgid "UniqueConstraint"
msgstr "contrainte d'unicité"
+msgid "Unreachable objects"
+msgstr "Objets inacessible"
+
msgid "Update permissions"
msgstr "Permissions de modifier"
@@ -2811,6 +2823,9 @@
msgid "may"
msgstr "mai"
+msgid "memory leak debugging"
+msgstr "Déboguage des fuites de mémoire"
+
msgid "milestone"
msgstr "jalon"
--- a/req.py Fri Mar 12 15:05:33 2010 +0100
+++ b/req.py Fri Mar 12 16:11:56 2010 +0100
@@ -7,9 +7,10 @@
"""
__docformat__ = "restructuredtext en"
+from urlparse import urlsplit, urlunsplit
from urllib import quote as urlquote, unquote as urlunquote
from datetime import time, datetime, timedelta
-from cgi import parse_qsl
+from cgi import parse_qs, parse_qsl
from logilab.common.decorators import cached
from logilab.common.deprecation import deprecated
@@ -239,7 +240,7 @@
def build_url_params(self, **kwargs):
"""return encoded params to incorporate them in an URL"""
args = []
- for param, values in kwargs.items():
+ for param, values in kwargs.iteritems():
if not isinstance(values, (list, tuple)):
values = (values,)
for value in values:
@@ -279,6 +280,25 @@
except UnicodeDecodeError: # might occurs on manually typed URLs
yield unicode(key, 'iso-8859-1'), unicode(val, 'iso-8859-1')
+
+ def rebuild_url(self, url, **newparams):
+ """return the given url with newparams inserted. If any new params
+ is already specified in the url, it's overriden by the new value
+
+ newparams may only be mono-valued.
+ """
+ if isinstance(url, unicode):
+ url = url.encode(self.encoding)
+ schema, netloc, path, query, fragment = urlsplit(url)
+ query = parse_qs(query)
+ # sort for testing predictability
+ for key, val in sorted(newparams.iteritems()):
+ query[key] = (self.url_quote(val),)
+ query = '&'.join(u'%s=%s' % (param, value)
+ for param, values in query.items()
+ for value in values)
+ return urlunsplit((schema, netloc, path, query, fragment))
+
# bound user related methods ###############################################
@cached
--- a/server/migractions.py Fri Mar 12 15:05:33 2010 +0100
+++ b/server/migractions.py Fri Mar 12 16:11:56 2010 +0100
@@ -147,9 +147,9 @@
try:
for source in repo.sources:
try:
- source.backup(osp.join(tmpdir, source.uri))
- except Exception, exc:
- print '-> error trying to backup %s [%s]' % (source.uri, exc)
+ source.backup(osp.join(tmpdir, source.uri, self.confirm))
+ except Exception, ex:
+ print '-> error trying to backup %s [%s]' % (source.uri, ex)
if not self.confirm('Continue anyway?', default='n'):
raise SystemExit(1)
else:
@@ -189,7 +189,6 @@
bkup = tarfile.open(backupfile, 'r|gz')
bkup.extractall(path=tmpdir)
bkup.close()
-
self.config.open_connections_pools = False
repo = self.repo_connect()
for source in repo.sources:
--- a/server/repository.py Fri Mar 12 15:05:33 2010 +0100
+++ b/server/repository.py Fri Mar 12 16:11:56 2010 +0100
@@ -360,10 +360,15 @@
def stats(self): # XXX restrict to managers session?
import threading
results = {}
- for hits, misses, title in (
- (self.querier.cache_hit, self.querier.cache_miss, 'rqlt_st'),
- (self.system_source.cache_hit, self.system_source.cache_miss, 'sql'),
+ querier = self.querier
+ source = self.system_source
+ for size, maxsize, hits, misses, title in (
+ (len(querier._rql_cache), self.config['rql-cache-size'],
+ querier.cache_hit, querier.cache_miss, 'rqlt_st'),
+ (len(source._cache), self.config['rql-cache-size'],
+ source.cache_hit, source.cache_miss, 'sql'),
):
+ results['%s_cache_size' % title] = '%s / %s' % (size, maxsize)
results['%s_cache_hit' % title] = hits
results['%s_cache_miss' % title] = misses
results['%s_cache_hit_percent' % title] = (hits * 100) / (hits + misses)
--- a/server/session.py Fri Mar 12 15:05:33 2010 +0100
+++ b/server/session.py Fri Mar 12 16:11:56 2010 +0100
@@ -741,6 +741,7 @@
self.error('thread %s still alive after 10 seconds, will close '
'session anyway', thread)
self.rollback()
+ del self._threaddata
# transaction data/operations management ##################################
--- a/server/sources/extlite.py Fri Mar 12 15:05:33 2010 +0100
+++ b/server/sources/extlite.py Fri Mar 12 16:11:56 2010 +0100
@@ -87,11 +87,11 @@
AbstractSource.__init__(self, repo, appschema, source_config,
*args, **kwargs)
- def backup(self, backupfile):
+ def backup(self, backupfile, confirm):
"""method called to create a backup of the source's data"""
self.close_pool_connections()
try:
- self.sqladapter.backup_to_file(backupfile)
+ self.sqladapter.backup_to_file(backupfile, confirm)
finally:
self.open_pool_connections()
--- a/server/sources/native.py Fri Mar 12 15:05:33 2010 +0100
+++ b/server/sources/native.py Fri Mar 12 16:11:56 2010 +0100
@@ -13,7 +13,7 @@
"""
__docformat__ = "restructuredtext en"
-from threading import Lock
+from o_threading import Lock
from datetime import datetime
from base64 import b64decode, b64encode
@@ -205,11 +205,11 @@
pool.pool_reset()
self.repo._free_pool(pool)
- def backup(self, backupfile):
+ def backup(self, backupfile, confirm):
"""method called to create a backup of the source's data"""
self.close_pool_connections()
try:
- self.backup_to_file(backupfile)
+ self.backup_to_file(backupfile, confirm)
finally:
self.open_pool_connections()
--- a/server/sqlutils.py Fri Mar 12 15:05:33 2010 +0100
+++ b/server/sqlutils.py Fri Mar 12 16:11:56 2010 +0100
@@ -159,7 +159,7 @@
"""open and return a connection to the database"""
return self.dbhelper.get_connection()
- def backup_to_file(self, backupfile):
+ def backup_to_file(self, backupfile, confirm):
for cmd in self.dbhelper.backup_commands(backupfile,
keepownership=False):
if _run_command(cmd):
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/unittest_req.py Fri Mar 12 16:11:56 2010 +0100
@@ -0,0 +1,16 @@
+from logilab.common.testlib import TestCase, unittest_main
+from cubicweb.req import RequestSessionBase
+
+class RebuildURLTC(TestCase):
+ def test(self):
+ rebuild_url = RequestSessionBase(None).rebuild_url
+ self.assertEquals(rebuild_url('http://logilab.fr?__message=pouet', __message='hop'),
+ 'http://logilab.fr?__message=hop')
+ self.assertEquals(rebuild_url('http://logilab.fr', __message='hop'),
+ 'http://logilab.fr?__message=hop')
+ self.assertEquals(rebuild_url('http://logilab.fr?vid=index', __message='hop'),
+ 'http://logilab.fr?__message=hop&vid=index')
+
+
+if __name__ == '__main__':
+ unittest_main()
--- a/test/unittest_utils.py Fri Mar 12 15:05:33 2010 +0100
+++ b/test/unittest_utils.py Fri Mar 12 16:11:56 2010 +0100
@@ -59,7 +59,7 @@
l.extend(extension)
yield self.assertEquals, l, expected
-class JSONEncoerTests(TestCase):
+class JSONEncoderTC(TestCase):
def setUp(self):
if simplejson is None:
self.skip('simplejson not available')
@@ -81,5 +81,6 @@
def test_encoding_unknown_stuff(self):
self.assertEquals(self.encode(TestCase), 'null')
+
if __name__ == '__main__':
unittest_main()
--- a/utils.py Fri Mar 12 15:05:33 2010 +0100
+++ b/utils.py Fri Mar 12 16:11:56 2010 +0100
@@ -160,7 +160,6 @@
warn('[3.7] specifying jsoncall is not needed anymore',
DeprecationWarning, stacklevel=2)
self.add_post_inline_script(u"""jQuery(CubicWeb).one('server-response', function(event) {
-%s
});""" % jscode)
@@ -182,10 +181,10 @@
if (cssfile, media) not in self.cssfiles:
self.cssfiles.append( (cssfile, media) )
- def add_ie_css(self, cssfile, media='all'):
+ def add_ie_css(self, cssfile, media='all', iespec=u'[if lt IE 8]'):
"""registers some IE specific CSS"""
- if (cssfile, media) not in self.ie_cssfiles:
- self.ie_cssfiles.append( (cssfile, media) )
+ if (cssfile, media, iespec) not in self.ie_cssfiles:
+ self.ie_cssfiles.append( (cssfile, media, iespec) )
def add_unload_pagedata(self):
"""registers onunload callback to clean page data on server"""
@@ -215,8 +214,8 @@
(media, xml_escape(cssfile)))
# 3/ ie css if necessary
if self.ie_cssfiles:
- w(u'<!--[if lt IE 8]>\n')
- for cssfile, media in self.ie_cssfiles:
+ for cssfile, media, iespec in self.ie_cssfiles:
+ w(u'<!--%s>\n' % iespec)
w(u'<link rel="stylesheet" type="text/css" media="%s" href="%s"/>\n' %
(media, xml_escape(cssfile)))
w(u'<![endif]--> \n')
--- a/web/data/jquery.autocomplete.js Fri Mar 12 15:05:33 2010 +0100
+++ b/web/data/jquery.autocomplete.js Fri Mar 12 16:11:56 2010 +0100
@@ -1,15 +1,13 @@
/*
- * Autocomplete - jQuery plugin 1.0.2
+ * jQuery Autocomplete plugin 1.1
*
- * Copyright (c) 2007 Dylan Verheul, Dan G. Switzer, Anjesh Tuladhar, Jörn Zaefferer
+ * Copyright (c) 2009 Jörn Zaefferer
*
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
- * Revision: $Id: jquery.autocomplete.js 5747 2008-06-25 18:30:55Z joern.zaefferer $
- *
- */;(function($){$.fn.extend({autocomplete:function(urlOrData,options){var isUrl=typeof urlOrData=="string";options=$.extend({},$.Autocompleter.defaults,{url:isUrl?urlOrData:null,data:isUrl?null:urlOrData,delay:isUrl?$.Autocompleter.defaults.delay:10,max:options&&!options.scroll?10:150},options);options.highlight=options.highlight||function(value){return value;};options.formatMatch=options.formatMatch||options.formatItem;return this.each(function(){new $.Autocompleter(this,options);});},result:function(handler){return this.bind("result",handler);},search:function(handler){return this.trigger("search",[handler]);},flushCache:function(){return this.trigger("flushCache");},setOptions:function(options){return this.trigger("setOptions",[options]);},unautocomplete:function(){return this.trigger("unautocomplete");}});$.Autocompleter=function(input,options){var KEY={UP:38,DOWN:40,DEL:46,TAB:9,RETURN:13,ESC:27,COMMA:188,PAGEUP:33,PAGEDOWN:34,BACKSPACE:8};var $input=$(input).attr("autocomplete","off").addClass(options.inputClass);var timeout;var previousValue="";var cache=$.Autocompleter.Cache(options);var hasFocus=0;var lastKeyPressCode;var config={mouseDownOnSelect:false};var select=$.Autocompleter.Select(options,input,selectCurrent,config);var blockSubmit;$.browser.opera&&$(input.form).bind("submit.autocomplete",function(){if(blockSubmit){blockSubmit=false;return false;}});$input.bind(($.browser.opera?"keypress":"keydown")+".autocomplete",function(event){lastKeyPressCode=event.keyCode;switch(event.keyCode){case KEY.UP:event.preventDefault();if(select.visible()){select.prev();}else{onChange(0,true);}break;case KEY.DOWN:event.preventDefault();if(select.visible()){select.next();}else{onChange(0,true);}break;case KEY.PAGEUP:event.preventDefault();if(select.visible()){select.pageUp();}else{onChange(0,true);}break;case KEY.PAGEDOWN:event.preventDefault();if(select.visible()){select.pageDown();}else{onChange(0,true);}break;case options.multiple&&$.trim(options.multipleSeparator)==","&&KEY.COMMA:case KEY.TAB:case KEY.RETURN:if(selectCurrent()){event.preventDefault();blockSubmit=true;return false;}break;case KEY.ESC:select.hide();break;default:clearTimeout(timeout);timeout=setTimeout(onChange,options.delay);break;}}).focus(function(){hasFocus++;}).blur(function(){hasFocus=0;if(!config.mouseDownOnSelect){hideResults();}}).click(function(){if(hasFocus++>1&&!select.visible()){onChange(0,true);}}).bind("search",function(){var fn=(arguments.length>1)?arguments[1]:null;function findValueCallback(q,data){var result;if(data&&data.length){for(var i=0;i<data.length;i++){if(data[i].result.toLowerCase()==q.toLowerCase()){result=data[i];break;}}}if(typeof fn=="function")fn(result);else $input.trigger("result",result&&[result.data,result.value]);}$.each(trimWords($input.val()),function(i,value){request(value,findValueCallback,findValueCallback);});}).bind("flushCache",function(){cache.flush();}).bind("setOptions",function(){$.extend(options,arguments[1]);if("data"in arguments[1])cache.populate();}).bind("unautocomplete",function(){select.unbind();$input.unbind();$(input.form).unbind(".autocomplete");});function selectCurrent(){var selected=select.selected();if(!selected)return false;var v=selected.result;previousValue=v;if(options.multiple){var words=trimWords($input.val());if(words.length>1){v=words.slice(0,words.length-1).join(options.multipleSeparator)+options.multipleSeparator+v;}v+=options.multipleSeparator;}$input.val(v);hideResultsNow();$input.trigger("result",[selected.data,selected.value]);return true;}function onChange(crap,skipPrevCheck){if(lastKeyPressCode==KEY.DEL){select.hide();return;}var currentValue=$input.val();if(!skipPrevCheck&¤tValue==previousValue)return;previousValue=currentValue;currentValue=lastWord(currentValue);if(currentValue.length>=options.minChars){$input.addClass(options.loadingClass);if(!options.matchCase)currentValue=currentValue.toLowerCase();request(currentValue,receiveData,hideResultsNow);}else{stopLoading();select.hide();}};function trimWords(value){if(!value){return[""];}var words=value.split(options.multipleSeparator);var result=[];$.each(words,function(i,value){if($.trim(value))result[i]=$.trim(value);});return result;}function lastWord(value){if(!options.multiple)return value;var words=trimWords(value);return words[words.length-1];}function autoFill(q,sValue){if(options.autoFill&&(lastWord($input.val()).toLowerCase()==q.toLowerCase())&&lastKeyPressCode!=KEY.BACKSPACE){$input.val($input.val()+sValue.substring(lastWord(previousValue).length));$.Autocompleter.Selection(input,previousValue.length,previousValue.length+sValue.length);}};function hideResults(){clearTimeout(timeout);timeout=setTimeout(hideResultsNow,200);};function hideResultsNow(){var wasVisible=select.visible();select.hide();clearTimeout(timeout);stopLoading();if(options.mustMatch){$input.search(function(result){if(!result){if(options.multiple){var words=trimWords($input.val()).slice(0,-1);$input.val(words.join(options.multipleSeparator)+(words.length?options.multipleSeparator:""));}else
-$input.val("");}});}if(wasVisible)$.Autocompleter.Selection(input,input.value.length,input.value.length);};function receiveData(q,data){if(data&&data.length&&hasFocus){stopLoading();select.display(data,q);autoFill(q,data[0].value);select.show();}else{hideResultsNow();}};function request(term,success,failure){if(!options.matchCase)term=term.toLowerCase();var data=cache.load(term);if(data&&data.length){success(term,data);}else if((typeof options.url=="string")&&(options.url.length>0)){var extraParams={timestamp:+new Date()};$.each(options.extraParams,function(key,param){extraParams[key]=typeof param=="function"?param():param;});$.ajax({mode:"abort",port:"autocomplete"+input.name,dataType:options.dataType,url:options.url,data:$.extend({q:lastWord(term),limit:options.max},extraParams),success:function(data){var parsed=options.parse&&options.parse(data)||parse(data);cache.add(term,parsed);success(term,parsed);}});}else{select.emptyList();failure(term);}};function parse(data){var parsed=[];var rows=data.split("\n");for(var i=0;i<rows.length;i++){var row=$.trim(rows[i]);if(row){row=row.split("|");parsed[parsed.length]={data:row,value:row[0],result:options.formatResult&&options.formatResult(row,row[0])||row[0]};}}return parsed;};function stopLoading(){$input.removeClass(options.loadingClass);};};$.Autocompleter.defaults={inputClass:"ac_input",resultsClass:"ac_results",loadingClass:"ac_loading",minChars:1,delay:400,matchCase:false,matchSubset:true,matchContains:false,cacheLength:10,max:100,mustMatch:false,extraParams:{},selectFirst:true,formatItem:function(row){return row[0];},formatMatch:null,autoFill:false,width:0,multiple:false,multipleSeparator:", ",highlight:function(value,term){return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)("+term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi,"\\$1")+")(?![^<>]*>)(?![^&;]+;)","gi"),"<strong>$1</strong>");},scroll:true,scrollHeight:180};$.Autocompleter.Cache=function(options){var data={};var length=0;function matchSubset(s,sub){if(!options.matchCase)s=s.toLowerCase();var i=s.indexOf(sub);if(i==-1)return false;return i==0||options.matchContains;};function add(q,value){if(length>options.cacheLength){flush();}if(!data[q]){length++;}data[q]=value;}function populate(){if(!options.data)return false;var stMatchSets={},nullData=0;if(!options.url)options.cacheLength=1;stMatchSets[""]=[];for(var i=0,ol=options.data.length;i<ol;i++){var rawValue=options.data[i];rawValue=(typeof rawValue=="string")?[rawValue]:rawValue;var value=options.formatMatch(rawValue,i+1,options.data.length);if(value===false)continue;var firstChar=value.charAt(0).toLowerCase();if(!stMatchSets[firstChar])stMatchSets[firstChar]=[];var row={value:value,data:rawValue,result:options.formatResult&&options.formatResult(rawValue)||value};stMatchSets[firstChar].push(row);if(nullData++<options.max){stMatchSets[""].push(row);}};$.each(stMatchSets,function(i,value){options.cacheLength++;add(i,value);});}setTimeout(populate,25);function flush(){data={};length=0;}return{flush:flush,add:add,populate:populate,load:function(q){if(!options.cacheLength||!length)return null;if(!options.url&&options.matchContains){var csub=[];for(var k in data){if(k.length>0){var c=data[k];$.each(c,function(i,x){if(matchSubset(x.value,q)){csub.push(x);}});}}return csub;}else
+ * Revision: $Id: jquery.autocomplete.js 15 2009-08-22 10:30:27Z joern.zaefferer $
+ */;(function($){$.fn.extend({autocomplete:function(urlOrData,options){var isUrl=typeof urlOrData=="string";options=$.extend({},$.Autocompleter.defaults,{url:isUrl?urlOrData:null,data:isUrl?null:urlOrData,delay:isUrl?$.Autocompleter.defaults.delay:10,max:options&&!options.scroll?10:150},options);options.highlight=options.highlight||function(value){return value;};options.formatMatch=options.formatMatch||options.formatItem;return this.each(function(){new $.Autocompleter(this,options);});},result:function(handler){return this.bind("result",handler);},search:function(handler){return this.trigger("search",[handler]);},flushCache:function(){return this.trigger("flushCache");},setOptions:function(options){return this.trigger("setOptions",[options]);},unautocomplete:function(){return this.trigger("unautocomplete");}});$.Autocompleter=function(input,options){var KEY={UP:38,DOWN:40,DEL:46,TAB:9,RETURN:13,ESC:27,COMMA:188,PAGEUP:33,PAGEDOWN:34,BACKSPACE:8};var $input=$(input).attr("autocomplete","off").addClass(options.inputClass);var timeout;var previousValue="";var cache=$.Autocompleter.Cache(options);var hasFocus=0;var lastKeyPressCode;var config={mouseDownOnSelect:false};var select=$.Autocompleter.Select(options,input,selectCurrent,config);var blockSubmit;$.browser.opera&&$(input.form).bind("submit.autocomplete",function(){if(blockSubmit){blockSubmit=false;return false;}});$input.bind(($.browser.opera?"keypress":"keydown")+".autocomplete",function(event){hasFocus=1;lastKeyPressCode=event.keyCode;switch(event.keyCode){case KEY.UP:event.preventDefault();if(select.visible()){select.prev();}else{onChange(0,true);}break;case KEY.DOWN:event.preventDefault();if(select.visible()){select.next();}else{onChange(0,true);}break;case KEY.PAGEUP:event.preventDefault();if(select.visible()){select.pageUp();}else{onChange(0,true);}break;case KEY.PAGEDOWN:event.preventDefault();if(select.visible()){select.pageDown();}else{onChange(0,true);}break;case options.multiple&&$.trim(options.multipleSeparator)==","&&KEY.COMMA:case KEY.TAB:case KEY.RETURN:if(selectCurrent()){event.preventDefault();blockSubmit=true;return false;}break;case KEY.ESC:select.hide();break;default:clearTimeout(timeout);timeout=setTimeout(onChange,options.delay);break;}}).focus(function(){hasFocus++;}).blur(function(){hasFocus=0;if(!config.mouseDownOnSelect){hideResults();}}).click(function(){if(hasFocus++>1&&!select.visible()){onChange(0,true);}}).bind("search",function(){var fn=(arguments.length>1)?arguments[1]:null;function findValueCallback(q,data){var result;if(data&&data.length){for(var i=0;i<data.length;i++){if(data[i].result.toLowerCase()==q.toLowerCase()){result=data[i];break;}}}if(typeof fn=="function")fn(result);else $input.trigger("result",result&&[result.data,result.value]);}$.each(trimWords($input.val()),function(i,value){request(value,findValueCallback,findValueCallback);});}).bind("flushCache",function(){cache.flush();}).bind("setOptions",function(){$.extend(options,arguments[1]);if("data"in arguments[1])cache.populate();}).bind("unautocomplete",function(){select.unbind();$input.unbind();$(input.form).unbind(".autocomplete");});function selectCurrent(){var selected=select.selected();if(!selected)return false;var v=selected.result;previousValue=v;if(options.multiple){var words=trimWords($input.val());if(words.length>1){var seperator=options.multipleSeparator.length;var cursorAt=$(input).selection().start;var wordAt,progress=0;$.each(words,function(i,word){progress+=word.length;if(cursorAt<=progress){wordAt=i;return false;}progress+=seperator;});words[wordAt]=v;v=words.join(options.multipleSeparator);}v+=options.multipleSeparator;}$input.val(v);hideResultsNow();$input.trigger("result",[selected.data,selected.value]);return true;}function onChange(crap,skipPrevCheck){if(lastKeyPressCode==KEY.DEL){select.hide();return;}var currentValue=$input.val();if(!skipPrevCheck&¤tValue==previousValue)return;previousValue=currentValue;currentValue=lastWord(currentValue);if(currentValue.length>=options.minChars){$input.addClass(options.loadingClass);if(!options.matchCase)currentValue=currentValue.toLowerCase();request(currentValue,receiveData,hideResultsNow);}else{stopLoading();select.hide();}};function trimWords(value){if(!value)return[""];if(!options.multiple)return[$.trim(value)];return $.map(value.split(options.multipleSeparator),function(word){return $.trim(value).length?$.trim(word):null;});}function lastWord(value){if(!options.multiple)return value;var words=trimWords(value);if(words.length==1)return words[0];var cursorAt=$(input).selection().start;if(cursorAt==value.length){words=trimWords(value)}else{words=trimWords(value.replace(value.substring(cursorAt),""));}return words[words.length-1];}function autoFill(q,sValue){if(options.autoFill&&(lastWord($input.val()).toLowerCase()==q.toLowerCase())&&lastKeyPressCode!=KEY.BACKSPACE){$input.val($input.val()+sValue.substring(lastWord(previousValue).length));$(input).selection(previousValue.length,previousValue.length+sValue.length);}};function hideResults(){clearTimeout(timeout);timeout=setTimeout(hideResultsNow,200);};function hideResultsNow(){var wasVisible=select.visible();select.hide();clearTimeout(timeout);stopLoading();if(options.mustMatch){$input.search(function(result){if(!result){if(options.multiple){var words=trimWords($input.val()).slice(0,-1);$input.val(words.join(options.multipleSeparator)+(words.length?options.multipleSeparator:""));}else{$input.val("");$input.trigger("result",null);}}});}};function receiveData(q,data){if(data&&data.length&&hasFocus){stopLoading();select.display(data,q);autoFill(q,data[0].value);select.show();}else{hideResultsNow();}};function request(term,success,failure){if(!options.matchCase)term=term.toLowerCase();var data=cache.load(term);if(data&&data.length){success(term,data);}else if((typeof options.url=="string")&&(options.url.length>0)){var extraParams={timestamp:+new Date()};$.each(options.extraParams,function(key,param){extraParams[key]=typeof param=="function"?param():param;});$.ajax({mode:"abort",port:"autocomplete"+input.name,dataType:options.dataType,url:options.url,data:$.extend({q:lastWord(term),limit:options.max},extraParams),success:function(data){var parsed=options.parse&&options.parse(data)||parse(data);cache.add(term,parsed);success(term,parsed);}});}else{select.emptyList();failure(term);}};function parse(data){var parsed=[];var rows=data.split("\n");for(var i=0;i<rows.length;i++){var row=$.trim(rows[i]);if(row){row=row.split("|");parsed[parsed.length]={data:row,value:row[0],result:options.formatResult&&options.formatResult(row,row[0])||row[0]};}}return parsed;};function stopLoading(){$input.removeClass(options.loadingClass);};};$.Autocompleter.defaults={inputClass:"ac_input",resultsClass:"ac_results",loadingClass:"ac_loading",minChars:1,delay:400,matchCase:false,matchSubset:true,matchContains:false,cacheLength:10,max:100,mustMatch:false,extraParams:{},selectFirst:true,formatItem:function(row){return row[0];},formatMatch:null,autoFill:false,width:0,multiple:false,multipleSeparator:", ",highlight:function(value,term){return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)("+term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi,"\\$1")+")(?![^<>]*>)(?![^&;]+;)","gi"),"<strong>$1</strong>");},scroll:true,scrollHeight:180};$.Autocompleter.Cache=function(options){var data={};var length=0;function matchSubset(s,sub){if(!options.matchCase)s=s.toLowerCase();var i=s.indexOf(sub);if(options.matchContains=="word"){i=s.toLowerCase().search("\\b"+sub.toLowerCase());}if(i==-1)return false;return i==0||options.matchContains;};function add(q,value){if(length>options.cacheLength){flush();}if(!data[q]){length++;}data[q]=value;}function populate(){if(!options.data)return false;var stMatchSets={},nullData=0;if(!options.url)options.cacheLength=1;stMatchSets[""]=[];for(var i=0,ol=options.data.length;i<ol;i++){var rawValue=options.data[i];rawValue=(typeof rawValue=="string")?[rawValue]:rawValue;var value=options.formatMatch(rawValue,i+1,options.data.length);if(value===false)continue;var firstChar=value.charAt(0).toLowerCase();if(!stMatchSets[firstChar])stMatchSets[firstChar]=[];var row={value:value,data:rawValue,result:options.formatResult&&options.formatResult(rawValue)||value};stMatchSets[firstChar].push(row);if(nullData++<options.max){stMatchSets[""].push(row);}};$.each(stMatchSets,function(i,value){options.cacheLength++;add(i,value);});}setTimeout(populate,25);function flush(){data={};length=0;}return{flush:flush,add:add,populate:populate,load:function(q){if(!options.cacheLength||!length)return null;if(!options.url&&options.matchContains){var csub=[];for(var k in data){if(k.length>0){var c=data[k];$.each(c,function(i,x){if(matchSubset(x.value,q)){csub.push(x);}});}}return csub;}else
if(data[q]){return data[q];}else
-if(options.matchSubset){for(var i=q.length-1;i>=options.minChars;i--){var c=data[q.substr(0,i)];if(c){var csub=[];$.each(c,function(i,x){if(matchSubset(x.value,q)){csub[csub.length]=x;}});return csub;}}}return null;}};};$.Autocompleter.Select=function(options,input,select,config){var CLASSES={ACTIVE:"ac_over"};var listItems,active=-1,data,term="",needsInit=true,element,list;function init(){if(!needsInit)return;element=$("<div/>").hide().addClass(options.resultsClass).css("position","absolute").appendTo(document.body);list=$("<ul/>").appendTo(element).mouseover(function(event){if(target(event).nodeName&&target(event).nodeName.toUpperCase()=='LI'){active=$("li",list).removeClass(CLASSES.ACTIVE).index(target(event));$(target(event)).addClass(CLASSES.ACTIVE);}}).click(function(event){$(target(event)).addClass(CLASSES.ACTIVE);select();input.focus();return false;}).mousedown(function(){config.mouseDownOnSelect=true;}).mouseup(function(){config.mouseDownOnSelect=false;});if(options.width>0)element.css("width",options.width);needsInit=false;}function target(event){var element=event.target;while(element&&element.tagName!="LI")element=element.parentNode;if(!element)return[];return element;}function moveSelect(step){listItems.slice(active,active+1).removeClass(CLASSES.ACTIVE);movePosition(step);var activeItem=listItems.slice(active,active+1).addClass(CLASSES.ACTIVE);if(options.scroll){var offset=0;listItems.slice(0,active).each(function(){offset+=this.offsetHeight;});if((offset+activeItem[0].offsetHeight-list.scrollTop())>list[0].clientHeight){list.scrollTop(offset+activeItem[0].offsetHeight-list.innerHeight());}else if(offset<list.scrollTop()){list.scrollTop(offset);}}};function movePosition(step){active+=step;if(active<0){active=listItems.size()-1;}else if(active>=listItems.size()){active=0;}}function limitNumberOfItems(available){return options.max&&options.max<available?options.max:available;}function fillList(){list.empty();var max=limitNumberOfItems(data.length);for(var i=0;i<max;i++){if(!data[i])continue;var formatted=options.formatItem(data[i].data,i+1,max,data[i].value,term);if(formatted===false)continue;var li=$("<li/>").html(options.highlight(formatted,term)).addClass(i%2==0?"ac_even":"ac_odd").appendTo(list)[0];$.data(li,"ac_data",data[i]);}listItems=list.find("li");if(options.selectFirst){listItems.slice(0,1).addClass(CLASSES.ACTIVE);active=0;}if($.fn.bgiframe)list.bgiframe();}return{display:function(d,q){init();data=d;term=q;fillList();},next:function(){moveSelect(1);},prev:function(){moveSelect(-1);},pageUp:function(){if(active!=0&&active-8<0){moveSelect(-active);}else{moveSelect(-8);}},pageDown:function(){if(active!=listItems.size()-1&&active+8>listItems.size()){moveSelect(listItems.size()-1-active);}else{moveSelect(8);}},hide:function(){element&&element.hide();listItems&&listItems.removeClass(CLASSES.ACTIVE);active=-1;},visible:function(){return element&&element.is(":visible");},current:function(){return this.visible()&&(listItems.filter("."+CLASSES.ACTIVE)[0]||options.selectFirst&&listItems[0]);},show:function(){var offset=$(input).offset();element.css({width:typeof options.width=="string"||options.width>0?options.width:$(input).width(),top:offset.top+input.offsetHeight,left:offset.left}).show();if(options.scroll){list.scrollTop(0);list.css({maxHeight:options.scrollHeight,overflow:'auto'});if($.browser.msie&&typeof document.body.style.maxHeight==="undefined"){var listHeight=0;listItems.each(function(){listHeight+=this.offsetHeight;});var scrollbarsVisible=listHeight>options.scrollHeight;list.css('height',scrollbarsVisible?options.scrollHeight:listHeight);if(!scrollbarsVisible){listItems.width(list.width()-parseInt(listItems.css("padding-left"))-parseInt(listItems.css("padding-right")));}}}},selected:function(){var selected=listItems&&listItems.filter("."+CLASSES.ACTIVE).removeClass(CLASSES.ACTIVE);return selected&&selected.length&&$.data(selected[0],"ac_data");},emptyList:function(){list&&list.empty();},unbind:function(){element&&element.remove();}};};$.Autocompleter.Selection=function(field,start,end){if(field.createTextRange){var selRange=field.createTextRange();selRange.collapse(true);selRange.moveStart("character",start);selRange.moveEnd("character",end);selRange.select();}else if(field.setSelectionRange){field.setSelectionRange(start,end);}else{if(field.selectionStart){field.selectionStart=start;field.selectionEnd=end;}}field.focus();};})(jQuery);
\ No newline at end of file
+if(options.matchSubset){for(var i=q.length-1;i>=options.minChars;i--){var c=data[q.substr(0,i)];if(c){var csub=[];$.each(c,function(i,x){if(matchSubset(x.value,q)){csub[csub.length]=x;}});return csub;}}}return null;}};};$.Autocompleter.Select=function(options,input,select,config){var CLASSES={ACTIVE:"ac_over"};var listItems,active=-1,data,term="",needsInit=true,element,list;function init(){if(!needsInit)return;element=$("<div/>").hide().addClass(options.resultsClass).css("position","absolute").appendTo(document.body);list=$("<ul/>").appendTo(element).mouseover(function(event){if(target(event).nodeName&&target(event).nodeName.toUpperCase()=='LI'){active=$("li",list).removeClass(CLASSES.ACTIVE).index(target(event));$(target(event)).addClass(CLASSES.ACTIVE);}}).click(function(event){$(target(event)).addClass(CLASSES.ACTIVE);select();input.focus();return false;}).mousedown(function(){config.mouseDownOnSelect=true;}).mouseup(function(){config.mouseDownOnSelect=false;});if(options.width>0)element.css("width",options.width);needsInit=false;}function target(event){var element=event.target;while(element&&element.tagName.toUpperCase()!="LI")element=element.parentNode;if(!element)return[];return element;}function moveSelect(step){listItems.slice(active,active+1).removeClass(CLASSES.ACTIVE);movePosition(step);var activeItem=listItems.slice(active,active+1).addClass(CLASSES.ACTIVE);if(options.scroll){var offset=0;listItems.slice(0,active).each(function(){offset+=this.offsetHeight;});if((offset+activeItem[0].offsetHeight-list.scrollTop())>list[0].clientHeight){list.scrollTop(offset+activeItem[0].offsetHeight-list.innerHeight());}else if(offset<list.scrollTop()){list.scrollTop(offset);}}};function movePosition(step){active+=step;if(active<0){active=listItems.size()-1;}else if(active>=listItems.size()){active=0;}}function limitNumberOfItems(available){return options.max&&options.max<available?options.max:available;}function fillList(){list.empty();var max=limitNumberOfItems(data.length);for(var i=0;i<max;i++){if(!data[i])continue;var formatted=options.formatItem(data[i].data,i+1,max,data[i].value,term);if(formatted===false)continue;var li=$("<li/>").html(options.highlight(formatted,term)).addClass(i%2==0?"ac_even":"ac_odd").appendTo(list)[0];$.data(li,"ac_data",data[i]);}listItems=list.find("li");if(options.selectFirst){listItems.slice(0,1).addClass(CLASSES.ACTIVE);active=0;}if($.fn.bgiframe)list.bgiframe();}return{display:function(d,q){init();data=d;term=q;fillList();},next:function(){moveSelect(1);},prev:function(){moveSelect(-1);},pageUp:function(){if(active!=0&&active-8<0){moveSelect(-active);}else{moveSelect(-8);}},pageDown:function(){if(active!=listItems.size()-1&&active+8>listItems.size()){moveSelect(listItems.size()-1-active);}else{moveSelect(8);}},hide:function(){element&&element.hide();listItems&&listItems.removeClass(CLASSES.ACTIVE);active=-1;},visible:function(){return element&&element.is(":visible");},current:function(){return this.visible()&&(listItems.filter("."+CLASSES.ACTIVE)[0]||options.selectFirst&&listItems[0]);},show:function(){var offset=$(input).offset();element.css({width:typeof options.width=="string"||options.width>0?options.width:$(input).width(),top:offset.top+input.offsetHeight,left:offset.left}).show();if(options.scroll){list.scrollTop(0);list.css({maxHeight:options.scrollHeight,overflow:'auto'});if($.browser.msie&&typeof document.body.style.maxHeight==="undefined"){var listHeight=0;listItems.each(function(){listHeight+=this.offsetHeight;});var scrollbarsVisible=listHeight>options.scrollHeight;list.css('height',scrollbarsVisible?options.scrollHeight:listHeight);if(!scrollbarsVisible){listItems.width(list.width()-parseInt(listItems.css("padding-left"))-parseInt(listItems.css("padding-right")));}}}},selected:function(){var selected=listItems&&listItems.filter("."+CLASSES.ACTIVE).removeClass(CLASSES.ACTIVE);return selected&&selected.length&&$.data(selected[0],"ac_data");},emptyList:function(){list&&list.empty();},unbind:function(){element&&element.remove();}};};$.fn.selection=function(start,end){if(start!==undefined){return this.each(function(){if(this.createTextRange){var selRange=this.createTextRange();if(end===undefined||start==end){selRange.move("character",start);selRange.select();}else{selRange.collapse(true);selRange.moveStart("character",start);selRange.moveEnd("character",end);selRange.select();}}else if(this.setSelectionRange){this.setSelectionRange(start,end);}else if(this.selectionStart){this.selectionStart=start;this.selectionEnd=end;}});}var field=this[0];if(field.createTextRange){var range=document.selection.createRange(),orig=field.value,teststring="<->",textLength=range.text.length;range.text=teststring;var caretAt=field.value.indexOf(teststring);field.value=orig;this.selection(caretAt,caretAt+textLength);return{start:caretAt,end:caretAt+textLength}}else if(field.selectionStart!==undefined){return{start:field.selectionStart,end:field.selectionEnd}}};})(jQuery);
\ No newline at end of file
--- a/web/formfields.py Fri Mar 12 15:05:33 2010 +0100
+++ b/web/formfields.py Fri Mar 12 16:11:56 2010 +0100
@@ -14,7 +14,6 @@
from logilab.mtconverter import xml_escape
from logilab.common.date import ustrftime
-from logilab.common.decorators import cached
from yams.schema import KNOWN_METAATTRIBUTES
from yams.constraints import (SizeConstraint, StaticVocabularyConstraint,
@@ -189,19 +188,28 @@
"""return the widget instance associated to this field"""
return self.widget
- # cached is necessary else we get some pb on entity creation : entity.eid is
- # modified from creation mark (eg 'X') to its actual eid (eg 123), and then
- # `field.input_name()` won't return the right key anymore if not cached
- # (first call to input_name done *before* eventual eid affectation).
- @cached
def input_name(self, form, suffix=None):
"""return 'qualified name' for this field"""
- name = self.role_name()
- if suffix is not None:
- name += suffix
- if self.eidparam:
- return eid_param(name, form.edited_entity.eid)
- return name
+ # caching is necessary else we get some pb on entity creation :
+ # entity.eid is modified from creation mark (eg 'X') to its actual eid
+ # (eg 123), and then `field.input_name()` won't return the right key
+ # anymore if not cached (first call to input_name done *before* eventual
+ # eid affectation).
+ #
+ # note that you should NOT use @cached else it will create a memory leak
+ # on persistent fields (eg created once for all on a form class) because
+ # of the 'form' appobject argument: the cache will keep growing as new
+ # form are created...
+ try:
+ return form.formvalues[(self, 'input_name', suffix)]
+ except KeyError:
+ name = self.role_name()
+ if suffix is not None:
+ name += suffix
+ if self.eidparam:
+ name = eid_param(name, form.edited_entity.eid)
+ form.formvalues[(self, 'input_name', suffix)] = name
+ return name
def role_name(self):
"""return <field.name>-<field.role> if role is specified, else field.name"""
--- a/web/formwidgets.py Fri Mar 12 15:05:33 2010 +0100
+++ b/web/formwidgets.py Fri Mar 12 16:11:56 2010 +0100
@@ -456,16 +456,17 @@
needs_js = ('jquery.timePicker.js',)
needs_css = ('jquery.timepicker.css',)
- def __init__(self, timestr=None, timesteps=30, **kwargs):
+ def __init__(self, timestr=None, timesteps=30, separator=u':', **kwargs):
super(JQueryTimePicker, self).__init__(**kwargs)
self.timestr = timestr
self.timesteps = timesteps
+ self.separator = separator
def _render(self, form, field, renderer):
req = form._cw
domid = field.dom_id(form, self.suffix)
- req.add_onload(u'jqNode("%s").timePicker({selectedTime: "%s", step: %s})' % (
- domid, self.timestr, self.timesteps))
+ req.add_onload(u'jqNode("%s").timePicker({selectedTime: "%s", step: %s, separator: "%s"})' % (
+ domid, self.timestr, self.timesteps, self.separator))
if self.timestr is None:
value = self.values(form, field)[0]
else:
--- a/web/request.py Fri Mar 12 15:05:33 2010 +0100
+++ b/web/request.py Fri Mar 12 16:11:56 2010 +0100
@@ -311,7 +311,11 @@
if breadcrumbs is None:
breadcrumbs = SizeConstrainedList(10)
self.set_session_data('breadcrumbs', breadcrumbs)
- breadcrumbs.append(self.url())
+ breadcrumbs.append(self.url())
+ else:
+ url = self.url()
+ if breadcrumbs[-1] != url:
+ breadcrumbs.append(url)
def last_visited_page(self):
breadcrumbs = self.get_session_data('breadcrumbs', None)
@@ -516,26 +520,33 @@
jsfile = self.datadir_url + jsfile
self.html_headers.add_js(jsfile)
- def add_css(self, cssfiles, media=u'all', localfile=True, ieonly=False):
+ def add_css(self, cssfiles, media=u'all', localfile=True, ieonly=False,
+ iespec=u'[if lt IE 8]'):
"""specify a CSS file to include in the HTML headers
:param cssfiles: a CSS filename or a list of CSS filenames
:param media: the CSS's media if necessary
:param localfile: if True, the default data dir prefix is added to the
CSS filename
+ :param ieonly: True if this css is specific to IE
+ :param iespec: conditional expression that will be used around
+ the css inclusion. cf:
+ http://msdn.microsoft.com/en-us/library/ms537512(VS.85).aspx
"""
if isinstance(cssfiles, basestring):
cssfiles = (cssfiles,)
if ieonly:
if self.ie_browser():
+ extraargs = [iespec]
add_css = self.html_headers.add_ie_css
else:
return # no need to do anything on non IE browsers
else:
+ extraargs = []
add_css = self.html_headers.add_css
for cssfile in cssfiles:
if localfile:
cssfile = self.datadir_url + cssfile
- add_css(cssfile, media)
+ add_css(cssfile, media, *extraargs)
def build_ajax_replace_url(self, nodeid, rql, vid, replacemode='replace',
**extraparams):
--- a/web/views/authentication.py Fri Mar 12 15:05:33 2010 +0100
+++ b/web/views/authentication.py Fri Mar 12 16:11:56 2010 +0100
@@ -114,8 +114,11 @@
login, authinfo = retreiver.authentication_information(req)
except NoAuthInfo:
continue
- cnx = self._authenticate(req, login, authinfo)
- break
+ try:
+ cnx = self._authenticate(req, login, authinfo)
+ break
+ except ExplicitLogin:
+ continue # the next one may succeed
else:
raise ExplicitLogin()
for retreiver_ in self.authinforetreivers:
@@ -124,7 +127,6 @@
def _authenticate(self, req, login, authinfo):
# remove possibly cached cursor coming from closed connection
- clear_cache(req, 'cursor')
cnxprops = ConnectionProperties(self.vreg.config.repo_method,
close=False, log=self.log_queries)
try:
--- a/web/views/debug.py Fri Mar 12 15:05:33 2010 +0100
+++ b/web/views/debug.py Fri Mar 12 16:11:56 2010 +0100
@@ -27,13 +27,13 @@
class ProcessInformationView(StartupView):
+ """display various web server /repository information"""
__regid__ = 'info'
__select__ = none_rset() & match_user_groups('managers')
title = _('server information')
def call(self, **kwargs):
- """display server information"""
req = self._cw
dtformat = req.property_value('ui.datetime-format')
_ = req._
@@ -111,24 +111,59 @@
class RegistryView(StartupView):
+ """display vregistry content"""
__regid__ = 'registry'
__select__ = StartupView.__select__ & match_user_groups('managers')
title = _('registry')
def call(self, **kwargs):
- """The default view representing the instance's management"""
self.w(u'<h1>%s</h1>' % _("Registry's content"))
keys = sorted(self._cw.vreg)
- self.w(u'<p>%s</p>\n' % ' - '.join('<a href="/_registry#%s">%s</a>'
- % (key, key) for key in keys))
+ url = self._cw.url()
+ self.w(u'<p>%s</p>\n' % ' - '.join('<a href="%s#%s">%s</a>'
+ % (url, key, key) for key in keys))
for key in keys:
- self.w(u'<h2><a name="%s">%s</a></h2>' % (key, key))
- items = self._cw.vreg[key].items()
- if items:
- self.w(u'<table><tbody>')
- for key, value in sorted(items):
- self.w(u'<tr><td>%s</td><td>%s</td></tr>'
- % (key, xml_escape(repr(value))))
- self.w(u'</tbody></table>\n')
+ self.w(u'<h2 id="%s">%s</h2>' % (key, key))
+ if self._cw.vreg[key]:
+ values = sorted(self._cw.vreg[key].iteritems())
+ self.wview('pyvaltable', pyvalue=[(key, xml_escape(repr(val)))
+ for key, val in values])
else:
self.w(u'<p>Empty</p>\n')
+
+
+class GCView(StartupView):
+ """display garbage collector information"""
+ __regid__ = 'gc'
+ __select__ = StartupView.__select__ & match_user_groups('managers')
+ title = _('memory leak debugging')
+
+ def call(self, **kwargs):
+ from cubicweb._gcdebug import gc_info
+ from rql.stmts import Union
+ from cubicweb.appobject import AppObject
+ from cubicweb.rset import ResultSet
+ from cubicweb.dbapi import Connection, Cursor
+ from cubicweb.web.request import CubicWebRequestBase
+ lookupclasses = (AppObject,
+ Union, ResultSet,
+ Connection, Cursor,
+ CubicWebRequestBase)
+ try:
+ from cubicweb.server.session import Session, ChildSession, InternalSession
+ lookupclasses += (InternalSession, ChildSession, Session)
+ except ImportError:
+ pass # no server part installed
+ self.w(u'<h1>%s</h1>' % _('Garbage collection information'))
+ counters, ocounters, garbage = gc_info(lookupclasses,
+ viewreferrersclasses=())
+ self.w(u'<h3>%s</h3>' % _('Looked up classes'))
+ values = sorted(counters.iteritems(), key=lambda x: x[1], reverse=True)
+ self.wview('pyvaltable', pyvalue=values)
+ self.w(u'<h3>%s</h3>' % _('Most referenced classes'))
+ values = sorted(ocounters.iteritems(), key=lambda x: x[1], reverse=True)
+ self.wview('pyvaltable', pyvalue=values[:self._cw.form.get('nb', 20)])
+ if garbage:
+ self.w(u'<h3>%s</h3>' % _('Unreachable objects'))
+ values = sorted(xml_escape(repr(o) for o in garbage))
+ self.wview('pyvallist', pyvalue=values)
--- a/web/views/pyviews.py Fri Mar 12 15:05:33 2010 +0100
+++ b/web/views/pyviews.py Fri Mar 12 16:11:56 2010 +0100
@@ -17,18 +17,23 @@
def call(self, pyvalue, headers=None):
if headers is None:
headers = self._cw.form.get('headers')
- self.w(u'<table class="listing">\n')
+ w = self.w
+ w(u'<table class="listing">\n')
if headers:
- self.w(u'<tr>')
+ w(u'<thead>')
+ w(u'<tr>')
for header in headers:
- self.w(u'<th>%s</th>' % header)
- self.w(u'</tr>\n')
+ w(u'<th>%s</th>' % header)
+ w(u'</tr>\n')
+ w(u'</thead>')
+ w(u'<tbody>')
for row in pyvalue:
- self.w(u'<tr>')
+ w(u'<tr>')
for cell in row:
- self.w(u'<td>%s</td>' % cell)
- self.w(u'</tr>\n')
- self.w(u'</table>\n')
+ w(u'<td>%s</td>' % cell)
+ w(u'</tr>\n')
+ w(u'</tbody>')
+ w(u'</table>\n')
class PyValListView(View):
--- a/web/views/xmlrss.py Fri Mar 12 15:05:33 2010 +0100
+++ b/web/views/xmlrss.py Fri Mar 12 16:11:56 2010 +0100
@@ -148,6 +148,7 @@
content_type = 'text/xml'
http_cache_manager = httpcache.MaxAgeHTTPCacheManager
cache_max_age = 60*60*2 # stay in http cache for 2 hours by default
+ item_vid = 'rssitem'
def _open(self):
req = self._cw
@@ -174,7 +175,7 @@
self._close()
def cell_call(self, row, col):
- self.wview('rssitem', self.cw_rset, row=row, col=col)
+ self.wview(self.item_vid, self.cw_rset, row=row, col=col)
class RSSItemView(EntityView):