--- a/__pkginfo__.py Mon May 10 15:20:54 2010 +0200
+++ b/__pkginfo__.py Mon May 10 16:59:32 2010 +0200
@@ -40,7 +40,7 @@
]
__depends__ = {
- 'logilab-common': '>= 0.50.0',
+ 'logilab-common': '>= 0.50.1',
'logilab-mtconverter': '>= 0.6.0',
'rql': '>= 0.26.0',
'yams': '>= 0.28.1',
--- a/cwconfig.py Mon May 10 15:20:54 2010 +0200
+++ b/cwconfig.py Mon May 10 16:59:32 2010 +0200
@@ -293,8 +293,6 @@
log_format = '%(asctime)s - (%(name)s) %(levelname)s: %(message)s'
# nor remove appobjects based on unused interface
cleanup_interface_sobjects = True
- # debug mode
- debugmode = False
if (CWDEV and _forced_mode != 'system'):
@@ -660,12 +658,14 @@
vregpath.append(path + '.py')
return vregpath
- def __init__(self):
+ def __init__(self, debugmode=False):
register_stored_procedures()
ConfigurationMixIn.__init__(self)
+ self.debugmode = debugmode
self.adjust_sys_path()
self.load_defaults()
- self.translations = {}
+ # will be properly initialized later by _gettext_init
+ self.translations = {'en': (unicode, lambda ctx, msgid: unicode(msgid) )}
# don't register ReStructured Text directives by simple import, avoid pb
# with eg sphinx.
# XXX should be done properly with a function from cw.uicfg
@@ -680,16 +680,14 @@
# overriden in CubicWebConfiguration
self.cls_adjust_sys_path()
- def init_log(self, logthreshold=None, debug=False,
- logfile=None, syslog=False):
+ def init_log(self, logthreshold=None, logfile=None, syslog=False):
"""init the log service"""
if logthreshold is None:
- if debug:
+ if self.debugmode:
logthreshold = 'DEBUG'
else:
logthreshold = self['log-threshold']
- self.debugmode = debug
- init_log(debug, syslog, logthreshold, logfile, self.log_format)
+ init_log(self.debugmode, syslog, logthreshold, logfile, self.log_format)
# configure simpleTal logger
logging.getLogger('simpleTAL').setLevel(logging.ERROR)
@@ -803,12 +801,12 @@
return mdir
@classmethod
- def config_for(cls, appid, config=None):
+ def config_for(cls, appid, config=None, debugmode=False):
"""return a configuration instance for the given instance identifier
"""
config = config or guess_configuration(cls.instance_home(appid))
configcls = configuration_cls(config)
- return configcls(appid)
+ return configcls(appid, debugmode)
@classmethod
def possible_configurations(cls, appid):
@@ -876,9 +874,9 @@
# instance methods used to get instance specific resources #############
- def __init__(self, appid):
+ def __init__(self, appid, debugmode=False):
self.appid = appid
- CubicWebNoAppConfiguration.__init__(self)
+ CubicWebNoAppConfiguration.__init__(self, debugmode)
self._cubes = None
self._site_loaded = set()
self.load_file_configuration(self.main_config_file())
@@ -988,14 +986,14 @@
super(CubicWebConfiguration, self).load_configuration()
if self.apphome and self.set_language:
# init gettext
- self._set_language()
+ self._gettext_init()
- def init_log(self, logthreshold=None, debug=False, force=False):
+ def init_log(self, logthreshold=None, force=False):
"""init the log service"""
if not force and hasattr(self, '_logging_initialized'):
return
self._logging_initialized = True
- CubicWebNoAppConfiguration.init_log(self, logthreshold, debug,
+ CubicWebNoAppConfiguration.init_log(self, logthreshold,
logfile=self.get('log-file'))
# read a config file if it exists
logconfig = join(self.apphome, 'logging.conf')
@@ -1016,7 +1014,7 @@
if lang != 'en':
yield lang
- def _set_language(self):
+ def _gettext_init(self):
"""set language for gettext"""
from gettext import translation
path = join(self.apphome, 'i18n')
--- a/cwctl.py Mon May 10 15:20:54 2010 +0200
+++ b/cwctl.py Mon May 10 16:59:32 2010 +0200
@@ -477,14 +477,13 @@
def start_instance(self, appid):
"""start the instance's server"""
- debug = self['debug']
force = self['force']
loglevel = self['loglevel']
- config = cwcfg.config_for(appid)
+ config = cwcfg.config_for(appid, debugmode=self['debug'])
if loglevel is not None:
loglevel = 'LOG_%s' % loglevel.upper()
config.global_set_option('log-threshold', loglevel)
- config.init_log(loglevel, debug=debug, force=True)
+ config.init_log(loglevel, force=True)
if self['profile']:
config.global_set_option('profile', self.config.profile)
helper = self.config_helper(config, cmdname='start')
@@ -493,7 +492,7 @@
msg = "%s seems to be running. Remove %s by hand if necessary or use \
the --force option."
raise ExecutionError(msg % (appid, pidf))
- helper.start_server(config, debug)
+ helper.start_server(config)
class StopInstanceCommand(InstanceCommand):
@@ -781,11 +780,15 @@
repository internals (session, etc...) so most migration commands won't be
available.
+ Arguments after bare "--" string will not be processed by the shell command
+ You can use it to pass extra arguments to your script and expect for
+ them in '__args__' afterwards.
+
<instance>
the identifier of the instance to connect.
"""
name = 'shell'
- arguments = '<instance> [batch command file]'
+ arguments = '<instance> [batch command file(s)] [-- <script arguments>]'
options = (
('system-only',
{'short': 'S', 'action' : 'store_true',
@@ -861,8 +864,11 @@
mih = config.migration_handler()
try:
if args:
- for arg in args:
- mih.cmd_process_script(arg)
+ # use cmdline parser to access left/right attributes only
+ # remember that usage requires instance appid as first argument
+ scripts, args = self.cmdline_parser.largs[1:], self.cmdline_parser.rargs
+ for script in scripts:
+ mih.cmd_process_script(script, scriptargs=args)
else:
mih.interactive_shell()
finally:
--- a/cwvreg.py Mon May 10 15:20:54 2010 +0200
+++ b/cwvreg.py Mon May 10 16:59:32 2010 +0200
@@ -442,14 +442,13 @@
* contentnavigation XXX to merge with components? to kill?
"""
- def __init__(self, config, debug=None, initlog=True):
+ def __init__(self, config, initlog=True):
if initlog:
# first init log service
- config.init_log(debug=debug)
+ config.init_log()
super(CubicWebVRegistry, self).__init__(config)
self.schema = None
self.initialized = False
- self.reset()
# XXX give force_reload (or refactor [re]loading...)
if self.config.mode != 'test':
# don't clear rtags during test, this may cause breakage with
@@ -519,7 +518,6 @@
if not cube in cubes:
cpath = cfg.build_vregistry_cube_path([cfg.cube_dir(cube)])
cleanup_sys_modules(cpath)
- self.reset()
self.register_objects(path, force_reload)
CW_EVENT_MANAGER.emit('after-registry-reload')
--- a/dbapi.py Mon May 10 15:20:54 2010 +0200
+++ b/dbapi.py Mon May 10 16:59:32 2010 +0200
@@ -254,9 +254,6 @@
self.session = None
self.cnx = self.user = _NeedAuthAccessMock()
- def base_url(self):
- return self.vreg.config['base-url']
-
def from_controller(self):
return 'view'
--- a/debian/control Mon May 10 15:20:54 2010 +0200
+++ b/debian/control Mon May 10 16:59:32 2010 +0200
@@ -97,7 +97,7 @@
Package: cubicweb-common
Architecture: all
XB-Python-Version: ${python:Versions}
-Depends: ${python:Depends}, graphviz, gettext, python-logilab-mtconverter (>= 0.6.0), python-logilab-common (>= 0.50.0), python-yams (>= 0.29.0), python-rql (>= 0.26.0), python-lxml
+Depends: ${python:Depends}, graphviz, gettext, python-logilab-mtconverter (>= 0.6.0), python-logilab-common (>= 0.50.1), python-yams (>= 0.29.0), python-rql (>= 0.26.0), python-lxml
Recommends: python-simpletal (>= 4.0), python-crypto
Conflicts: cubicweb-core
Replaces: cubicweb-core
--- a/devtools/__init__.py Mon May 10 15:20:54 2010 +0200
+++ b/devtools/__init__.py Mon May 10 16:59:32 2010 +0200
@@ -181,10 +181,6 @@
def available_languages(self, *args):
return ('en', 'fr', 'de')
- def ext_resources_file(self):
- """return instance's external resources file"""
- return join(self.apphome, 'data', 'external_resources')
-
def pyro_enabled(self):
# but export PYRO_MULTITHREAD=0 or you get problems with sqlite and threads
return True
--- a/devtools/devctl.py Mon May 10 15:20:54 2010 +0200
+++ b/devtools/devctl.py Mon May 10 16:59:32 2010 +0200
@@ -66,7 +66,7 @@
return None
def main_config_file(self):
return None
- def init_log(self, debug=None):
+ def init_log(self):
pass
def load_configuration(self):
pass
@@ -596,7 +596,7 @@
exclude = SKEL_EXCLUDE
if self['layout'] == 'simple':
exclude += ('sobjects.py*', 'precreate.py*', 'realdb_test*',
- 'cubes.*', 'external_resources*')
+ 'cubes.*', 'uiprops.py*')
copy_skeleton(skeldir, cubedir, context, exclude=exclude)
def _ask_for_dependencies(self):
--- a/devtools/fake.py Mon May 10 15:20:54 2010 +0200
+++ b/devtools/fake.py Mon May 10 16:59:32 2010 +0200
@@ -30,6 +30,7 @@
class FakeConfig(dict, BaseApptestConfiguration):
translations = {}
+ uiprops = {}
apphome = None
def __init__(self, appid='data', apphome=None, cubes=()):
self.appid = appid
@@ -39,6 +40,7 @@
self['uid'] = None
self['base-url'] = BASE_URL
self['rql-cache-size'] = 100
+ self.datadir_url = BASE_URL + 'data/'
def cubes(self, expand=False):
return self._cubes
@@ -66,10 +68,6 @@
def header_if_modified_since(self):
return None
- def base_url(self):
- """return the root url of the instance"""
- return BASE_URL
-
def relative_path(self, includeparams=True):
"""return the normalized path of the request (ie at least relative
to the instance's root, but some other normalization may be needed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/annexes/docstrings-conventions.rst Mon May 10 16:59:32 2010 +0200
@@ -0,0 +1,106 @@
+Javascript docstrings
+=====================
+
+Whereas in Python source code we only need to include a module docstrings
+using the directive `.. automodule:: mypythonmodule`, we will have to
+explicitely define Javascript modules and functions in the doctrings since
+there is no native directive to include Javascript files.
+
+Rest generation
+---------------
+
+`pyjsrest` is a small utility parsing Javascript doctrings and generating the
+corresponding Restructured file used by Sphinx to generate HTML documentation.
+This script will have the following structure::
+
+ ===========
+ filename.js
+ ===========
+ .. module:: filename.js
+
+We use the `.. module::` directive to register a javascript library
+as a Python module for Sphinx. This provides an entry in the module index.
+
+The contents of the docstring found in the javascript file will be added as is
+following the module declaration. No treatment will be done on the doctring.
+All the documentation structure will be in the docstrings and will comply
+with the following rules.
+
+Docstring structure
+-------------------
+
+Basically we document javascript with RestructuredText docstring
+following the same convention as documenting Python code.
+
+The doctring in Javascript files must be contained in standard
+Javascript comment signs, starting with `/**` and ending with `*/`,
+such as::
+
+ /**
+ * My comment starts here.
+ * This is the second line prefixed with a `*`.
+ * ...
+ * ...
+ * All the follwing line will be prefixed with a `*` followed by a space.
+ * ...
+ * ...
+ */
+
+
+Comments line prefixed by `//` will be ignored. They are reserved for source
+code comments dedicated to developers.
+
+
+Javscript functions docstring
+-----------------------------
+
+By default, the `function` directive describes a module-level function.
+
+`function` directive
+~~~~~~~~~~~~~~~~~~~~
+
+Its purpose is to define the function prototype such as::
+
+ .. function:: loadxhtml(url, data, reqtype, mode)
+
+If any namespace is used, we should add it in the prototype for now,
+until we define an appropriate directive.
+::
+ .. function:: jQuery.fn.loadxhtml(url, data, reqtype, mode)
+
+Function parameters
+~~~~~~~~~~~~~~~~~~~
+
+We will define function parameters as a bulleted list, where the
+parameter name will be backquoted and followed by its description.
+
+Example of a javascript function docstring::
+
+ .. function:: loadxhtml(url, data, reqtype, mode)
+
+ cubicweb loadxhtml plugin to make jquery handle xhtml response
+
+ fetches `url` and replaces this's content with the result
+
+ Its arguments are:
+
+ * `url`
+
+ * `mode`, how the replacement should be done (default is 'replace')
+ Possible values are :
+ - 'replace' to replace the node's content with the generated HTML
+ - 'swap' to replace the node itself with the generated HTML
+ - 'append' to append the generated HTML to the node's content
+
+
+Optional parameter specification
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Javascript functions handle arguments not listed in the function signature.
+In the javascript code, they will be flagged using `/* ... */`. In the docstring,
+we flag those optional arguments the same way we would define it in
+Python::
+
+ .. function:: asyncRemoteExec(fname, arg1=None, arg2=None)
+
+
--- a/doc/book/en/annexes/index.rst Mon May 10 15:20:54 2010 +0200
+++ b/doc/book/en/annexes/index.rst Mon May 10 16:59:32 2010 +0200
@@ -17,3 +17,5 @@
rql/index
mercurial
depends
+ javascript-api
+ docstrings-conventions
--- a/doc/book/en/devweb/js.rst Mon May 10 15:20:54 2010 +0200
+++ b/doc/book/en/devweb/js.rst Mon May 10 16:59:32 2010 +0200
@@ -350,3 +350,11 @@
There is also javascript support for massmailing, gmap (google maps),
fckcwconfig (fck editor), timeline, calendar, goa (CubicWeb over
AppEngine), flot (charts drawing), tabs and bookmarks.
+
+API
+~~~
+
+.. toctree::
+ :maxdepth: 1
+
+ js_api/index
--- a/doc/book/en/makefile Mon May 10 15:20:54 2010 +0200
+++ b/doc/book/en/makefile Mon May 10 16:59:32 2010 +0200
@@ -11,6 +11,10 @@
PAPER =
#BUILDDIR = build
BUILDDIR = ~/tmp/cwdoc
+CWDIR = ../../..
+JSDIR = ${CWDIR}/web/data
+JSTORST = ${CWDIR}/doc/tools/pyjsrest.py
+BUILDJS = devweb/js_api
# Internal variables for sphinx
PAPEROPT_a4 = -D latex_paper_size=a4
@@ -18,6 +22,7 @@
ALLSPHINXOPTS = -d ${BUILDDIR}/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
.PHONY: help clean html web pickle htmlhelp latex changes linkcheck
help:
@@ -36,6 +41,7 @@
rm -rf apidoc/
rm -f *.html
-rm -rf ${BUILDDIR}/*
+ -rm -rf ${BUILDJS}
all: ${TARGET} apidoc html
@@ -48,12 +54,16 @@
epydoc --html -o apidoc -n "cubicweb" --exclude=setup --exclude=__pkginfo__ ../../../
# run sphinx ###
-html:
+html: js
mkdir -p ${BUILDDIR}/html ${BUILDDIR}/doctrees
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) ${BUILDDIR}/html
@echo
@echo "Build finished. The HTML pages are in ${BUILDDIR}/html."
+js:
+ mkdir -p ${BUILDJS}
+ $(JSTORST) -p ${JSDIR} -o ${BUILDJS}
+
pickle:
mkdir -p ${BUILDDIR}/pickle ${BUILDDIR}/doctrees
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) ${BUILDDIR}/pickle
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/refactoring-the-css-with-uiprops.rst Mon May 10 16:59:32 2010 +0200
@@ -0,0 +1,73 @@
+=========================================
+Refactoring the CSSs with UI properties
+=========================================
+
+Overview
+=========
+
+Managing styles progressively became difficult in CubicWeb. The
+introduction of uiprops is an attempt to fix this problem.
+
+The goal is to make it possible to use variables in our CSSs.
+
+These variables are defined or computed in the uiprops.py python file
+and inserted in the CSS using the Python string interpolation syntax.
+
+A quick example, put in ``uiprops.py``::
+
+ defaultBgColor = '#eee'
+
+and in your css::
+
+ body { background-color: %(defaultBgColor)s; }
+
+
+The good practices are:
+
+- define a variable in uiprops to avoid repetitions in the CSS
+ (colors, borders, fonts, etc.)
+
+- define a variable in uiprops when you need to compute values
+ (compute a color palette, etc.)
+
+The algorithm implemented in CubicWeb is the following:
+
+- read uiprops file while walk up the chain of cube dependencies: if
+ cube myblog depends on cube comment, the variables defined in myblog
+ will have precedence over the ones in comment
+
+- replace the %(varname)s in all the CSSs of all the cubes
+
+Keep in mind that the browser will then interpret the CSSs and apply
+the standard cascading mechanism.
+
+FAQ
+====
+
+- How do I keep the old style?
+
+ Put ``STYLESHEET = [data('cubicweb.old.css')]`` in your uiprops.py
+ file and think about something else.
+
+- What are the changes in cubicweb.css?
+
+ Version 3.9.0 of cubicweb changed the following in the default html
+ markup and css:
+
+ =============== ==================================
+ old new
+ =============== ==================================
+ .navcol #navColumnLeft, #navColumnRight
+ #contentcol #contentColumn
+ .footer #footer
+ .logo #logo
+ .simpleMessage .loginMessage
+ .appMsg (styles are removed from css)
+ .searchMessage (styles are removed from css)
+ =============== ==================================
+
+ Introduction of the new cubicweb.reset.css based on Eric Meyer's
+ reset css.
+
+ Lots of margin, padding, etc.
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/tools/pyjsrest.py Mon May 10 16:59:32 2010 +0200
@@ -0,0 +1,110 @@
+#!/usr/bin/env python
+"""
+Parser for Javascript comments.
+"""
+from __future__ import with_statement
+
+import sys, os, getopt, re
+
+def clean_comment(match):
+ comment = match.group()
+ comment = strip_stars(comment)
+ return comment
+
+# Rest utilities
+def rest_title(title, level, level_markups=['=', '=', '-', '~', '+', '`']):
+ size = len(title)
+ if level == 0:
+ return '\n'.join((level_markups[level] * size, title, level_markups[0] * size)) + '\n'
+ return '\n'.join(('\n' + title, level_markups[level] * size)) + '\n'
+
+def get_doc_comments(text):
+ """
+ Return a list of all documentation comments in the file text. Each
+ comment is a pair, with the first element being the comment text and
+ the second element being the line after it, which may be needed to
+ guess function & arguments.
+
+ >>> get_doc_comments(read_file('examples/module.js'))[0][0][:40]
+ '/**\n * This is the module documentation.'
+ >>> get_doc_comments(read_file('examples/module.js'))[1][0][7:50]
+ 'This is documentation for the first method.'
+ >>> get_doc_comments(read_file('examples/module.js'))[1][1]
+ 'function the_first_function(arg1, arg2) '
+ >>> get_doc_comments(read_file('examples/module.js'))[2][0]
+ '/** This is the documentation for the second function. */'
+
+ """
+ return [clean_comment(match) for match in re.finditer('/\*\*.*?\*/',
+ text, re.DOTALL|re.MULTILINE)]
+
+RE_STARS = re.compile('^\s*?\* ?', re.MULTILINE)
+
+
+def strip_stars(doc_comment):
+ """
+ Strip leading stars from a doc comment.
+
+ >>> strip_stars('/** This is a comment. */')
+ 'This is a comment.'
+ >>> strip_stars('/**\n * This is a\n * multiline comment. */')
+ 'This is a\n multiline comment.'
+ >>> strip_stars('/** \n\t * This is a\n\t * multiline comment. \n*/')
+ 'This is a\n multiline comment.'
+
+ """
+ return RE_STARS.sub('', doc_comment[3:-2]).strip()
+
+def parse_js_files(args=sys.argv):
+ """
+ Main command-line invocation.
+ """
+ try:
+ opts, args = getopt.gnu_getopt(args[1:], 'p:o:h', [
+ 'jspath=', 'output=', 'help'])
+ opts = dict(opts)
+ except getopt.GetoptError:
+ usage()
+ sys.exit(2)
+
+ rst_dir = opts.get('--output') or opts.get('-o')
+ if rst_dir is None and len(args) != 1:
+ rst_dir = 'apidocs'
+ js_dir = opts.get('--jspath') or opts.get('-p')
+ if not os.path.exists(os.path.join(rst_dir)):
+ os.makedirs(os.path.join(rst_dir))
+
+ f_index = open(os.path.join(rst_dir, 'index.rst'), 'wb')
+ f_index.write('''
+.. toctree::
+ :maxdepth: 1
+
+'''
+)
+ for js_path, js_dirs, js_files in os.walk(js_dir):
+ rst_path = re.sub('%s%s*' % (js_dir, os.path.sep), '', js_path)
+ for js_file in js_files:
+ if not js_file.endswith('.js'):
+ continue
+ if not os.path.exists(os.path.join(rst_dir, rst_path)):
+ os.makedirs(os.path.join(rst_dir, rst_path))
+ rst_content = extract_rest(js_path, js_file)
+ filename = os.path.join(rst_path, js_file[:-3])
+ # add to index
+ f_index.write(' %s\n' % filename)
+ # save rst file
+ with open(os.path.join(rst_dir, filename) + '.rst', 'wb') as f_rst:
+ f_rst.write(rst_content)
+ f_index.close()
+
+def extract_rest(js_dir, js_file):
+ js_filepath = os.path.join(js_dir, js_file)
+ filecontent = open(js_filepath, 'U').read()
+ comments = get_doc_comments(filecontent)
+ rst = rest_title(js_file, 0)
+ rst += '.. module:: %s\n\n' % js_file
+ rst += '\n\n'.join(comments)
+ return rst
+
+if __name__ == '__main__':
+ parse_js_files()
--- a/etwist/request.py Mon May 10 15:20:54 2010 +0200
+++ b/etwist/request.py Mon May 10 16:59:32 2010 +0200
@@ -15,9 +15,8 @@
#
# You should have received a copy of the GNU Lesser General Public License along
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
-"""Twisted request handler for CubicWeb
+"""Twisted request handler for CubicWeb"""
-"""
__docformat__ = "restructuredtext en"
from datetime import datetime
@@ -55,9 +54,9 @@
return self._twreq.method
def relative_path(self, includeparams=True):
- """return the normalized path of the request (ie at least relative
- to the instance's root, but some other normalization may be needed
- so that the returned path may be used to compare to generated urls
+ """return the normalized path of the request (ie at least relative to
+ the instance's root, but some other normalization may be needed so that
+ the returned path may be used to compare to generated urls
:param includeparams:
boolean indicating if GET form parameters should be kept in the path
@@ -68,8 +67,8 @@
return path
def get_header(self, header, default=None, raw=True):
- """return the value associated with the given input header,
- raise KeyError if the header is not set
+ """return the value associated with the given input header, raise
+ KeyError if the header is not set
"""
if raw:
return self._headers_in.getRawHeaders(header, [default])[0]
--- a/etwist/server.py Mon May 10 15:20:54 2010 +0200
+++ b/etwist/server.py Mon May 10 16:59:32 2010 +0200
@@ -122,12 +122,11 @@
class CubicWebRootResource(resource.Resource):
- def __init__(self, config, debug=None):
- self.debugmode = debug
+ def __init__(self, config):
self.config = config
# instantiate publisher here and not in init_publisher to get some
# checks done before daemonization (eg versions consistency)
- self.appli = CubicWebPublisher(config, debug=self.debugmode)
+ self.appli = CubicWebPublisher(config)
self.base_url = config['base-url']
self.https_url = config['https-url']
self.children = {}
@@ -179,6 +178,9 @@
pre_path = request.path.split('/')[1:]
if pre_path[0] == 'https':
pre_path.pop(0)
+ uiprops = self.config.https_uiprops
+ else:
+ uiprops = self.config.uiprops
directory = pre_path[0]
# Anything in data/, static/, fckeditor/ and the generated versioned
# data directory is treated as static files
@@ -188,7 +190,7 @@
if directory == 'static':
return File(self.config.static_directory)
if directory == 'fckeditor':
- return File(self.config.ext_resources['FCKEDITOR_PATH'])
+ return File(uiprops['FCKEDITOR_PATH'])
if directory != 'data':
# versioned directory, use specific file with http cache
# headers so their are cached for a very long time
@@ -196,7 +198,7 @@
else:
cls = File
if path == 'fckeditor':
- return cls(self.config.ext_resources['FCKEDITOR_PATH'])
+ return cls(uiprops['FCKEDITOR_PATH'])
if path == directory: # recurse
return self
datadir = self.config.locate_resource(path)
@@ -210,7 +212,10 @@
def render(self, request):
"""Render a page from the root resource"""
# reload modified files in debug mode
- if self.debugmode:
+ if self.config.debugmode:
+ self.config.uiprops.reload_if_needed()
+ if self.https_url:
+ self.config.https_uiprops.reload_if_needed()
self.appli.vreg.reload_if_needed()
if self.config['profile']: # default profiler don't trace threads
return self.render_request(request)
@@ -405,15 +410,15 @@
LOGGER = getLogger('cubicweb.twisted')
set_log_methods(CubicWebRootResource, LOGGER)
-def run(config, debug):
+def run(config):
# create the site
- root_resource = CubicWebRootResource(config, debug)
+ root_resource = CubicWebRootResource(config)
website = server.Site(root_resource)
# serve it via standard HTTP on port set in the configuration
port = config['port'] or 8080
reactor.listenTCP(port, website)
logger = getLogger('cubicweb.twisted')
- if not debug:
+ if not config.debugmode:
if sys.platform == 'win32':
raise ConfigurationError("Under windows, you must use the service management "
"commands (e.g : 'net start my_instance)'")
--- a/etwist/twctl.py Mon May 10 15:20:54 2010 +0200
+++ b/etwist/twctl.py Mon May 10 16:59:32 2010 +0200
@@ -32,9 +32,9 @@
cmdname = 'start'
cfgname = 'twisted'
- def start_server(self, config, debug):
+ def start_server(self, config):
from cubicweb.etwist import server
- server.run(config, debug)
+ server.run(config)
class TWStopHandler(CommandHandler):
cmdname = 'stop'
--- a/goa/skel/loader.py Mon May 10 15:20:54 2010 +0200
+++ b/goa/skel/loader.py Mon May 10 16:59:32 2010 +0200
@@ -30,7 +30,7 @@
# apply monkey patches first
goa.do_monkey_patch()
# get instance's configuration (will be loaded from app.conf file)
- GAEConfiguration.ext_resources['JAVASCRIPTS'].append('DATADIR/goa.js')
+ GAEConfiguration.uiprops['JAVASCRIPTS'].append('DATADIR/goa.js')
config = GAEConfiguration('toto', APPLROOT)
# create default groups
create_groups()
--- a/goa/skel/main.py Mon May 10 15:20:54 2010 +0200
+++ b/goa/skel/main.py Mon May 10 16:59:32 2010 +0200
@@ -31,7 +31,7 @@
# get instance's configuration (will be loaded from app.conf file)
from cubicweb.goa.goaconfig import GAEConfiguration
-GAEConfiguration.ext_resources['JAVASCRIPTS'].append('DATADIR/goa.js')
+GAEConfiguration.uiprops['JAVASCRIPTS'].append('DATADIR/goa.js')
config = GAEConfiguration('toto', APPLROOT)
# dynamic objects registry
--- a/goa/tools/laxctl.py Mon May 10 15:20:54 2010 +0200
+++ b/goa/tools/laxctl.py Mon May 10 16:59:32 2010 +0200
@@ -43,7 +43,7 @@
do_monkey_patch()
from cubicweb.goa.goavreg import GAEVregistry
from cubicweb.goa.goaconfig import GAEConfiguration
- #WebConfiguration.ext_resources['JAVASCRIPTS'].append('DATADIR/goa.js')
+ #WebConfiguration.uiprops['JAVASCRIPTS'].append('DATADIR/goa.js')
config = GAEConfiguration('toto', applroot)
vreg = GAEVregistry(config)
vreg.set_schema(config.load_schema())
--- a/i18n/fr.po Mon May 10 15:20:54 2010 +0200
+++ b/i18n/fr.po Mon May 10 16:59:32 2010 +0200
@@ -534,7 +534,7 @@
msgstr "Nouvelle transition workflow"
msgid "No result matching query"
-msgstr "aucun résultat"
+msgstr "Aucun résultat ne correspond à la requête"
msgid "Non exhaustive list of views that may apply to entities of this type"
msgstr "Liste non exhausite des vues s'appliquant à ce type d'entité"
--- a/migration.py Mon May 10 15:20:54 2010 +0200
+++ b/migration.py Mon May 10 16:59:32 2010 +0200
@@ -111,7 +111,7 @@
self.config = config
if config:
# no config on shell to a remote instance
- self.config.init_log(logthreshold=logging.ERROR, debug=True)
+ self.config.init_log(logthreshold=logging.ERROR)
# 0: no confirmation, 1: only main commands confirmed, 2 ask for everything
self.verbosity = verbosity
self.need_wrap = True
@@ -281,14 +281,25 @@
return context
def cmd_process_script(self, migrscript, funcname=None, *args, **kwargs):
- """execute a migration script
- in interactive mode, display the migration script path, ask for
- confirmation and execute it if confirmed
+ """execute a migration script in interactive mode
+
+ Display the migration script path, ask for confirmation and execute it
+ if confirmed
+
+ Context environment can have these variables defined:
+ - __name__ : will be determine by funcname parameter
+ - __file__ : is the name of the script if it exists
+ - __args__ : script arguments coming from command-line
+
+ :param migrscript: name of the script
+ :param funcname: defines __name__ inside the shell (or use __main__)
+ :params args: optional arguments for funcname
+ :keyword scriptargs: optional arguments of the script
"""
migrscript = os.path.normpath(migrscript)
if migrscript.endswith('.py'):
script_mode = 'python'
- elif migrscript.endswith('.txt') or migrscript.endswith('.rst'):
+ elif migrscript.endswith(('.txt', '.rst')):
script_mode = 'doctest'
else:
raise Exception('This is not a valid cubicweb shell input')
@@ -300,7 +311,8 @@
pyname = '__main__'
else:
pyname = splitext(basename(migrscript))[0]
- scriptlocals.update({'__file__': migrscript, '__name__': pyname})
+ scriptlocals.update({'__file__': migrscript, '__name__': pyname,
+ '__args__': kwargs.pop("scriptargs", [])})
execfile(migrscript, scriptlocals)
if funcname is not None:
try:
--- a/req.py Mon May 10 15:20:54 2010 +0200
+++ b/req.py Mon May 10 16:59:32 2010 +0200
@@ -371,11 +371,11 @@
raise ValueError(self._('can\'t parse %(value)r (expected %(format)s)')
% {'value': value, 'format': format})
- # abstract methods to override according to the web front-end #############
-
def base_url(self):
"""return the root url of the instance"""
- raise NotImplementedError
+ return self.vreg.config['base-url']
+
+ # abstract methods to override according to the web front-end #############
def describe(self, eid):
"""return a tuple (type, sourceuri, extid) for the entity with id <eid>"""
--- a/selectors.py Mon May 10 15:20:54 2010 +0200
+++ b/selectors.py Mon May 10 16:59:32 2010 +0200
@@ -594,7 +594,7 @@
class multi_lines_rset(Selector):
- """If `nb`is specified, return 1 if the result set has exactly `nb` row of
+ """If `nb` is specified, return 1 if the result set has exactly `nb` row of
result. Else (`nb` is None), return 1 if the result set contains *at least*
two rows.
"""
@@ -612,7 +612,7 @@
class multi_columns_rset(multi_lines_rset):
- """If `nb`is specified, return 1 if the result set has exactly `nb` column
+ """If `nb` is specified, return 1 if the result set has exactly `nb` column
per row. Else (`nb` is None), return 1 if the result set contains *at least*
two columns per row. Return 0 for empty result set.
"""
@@ -1298,6 +1298,10 @@
return None
super(is_in_state, self).__init__(score)
+@objectify_selector
+def debug_mode(cls, req, rset=None, **kwargs):
+ """Return 1 if running in debug mode"""
+ return req.vreg.config.debugmode and 1 or 0
## deprecated stuff ############################################################
--- a/server/repository.py Mon May 10 15:20:54 2010 +0200
+++ b/server/repository.py Mon May 10 16:59:32 2010 +0200
@@ -104,10 +104,10 @@
XXX protect pyro access
"""
- def __init__(self, config, vreg=None, debug=False):
+ def __init__(self, config, vreg=None):
self.config = config
if vreg is None:
- vreg = cwvreg.CubicWebVRegistry(config, debug)
+ vreg = cwvreg.CubicWebVRegistry(config)
self.vreg = vreg
self.pyro_registered = False
self.info('starting repository from %s', self.config.apphome)
@@ -152,13 +152,6 @@
if not isinstance(session.user, InternalManager):
session.user.__class__ = usercls
- def _bootstrap_hook_registry(self):
- """called during bootstrap since we need the metadata hooks"""
- hooksdirectory = join(CW_SOFTWARE_ROOT, 'hooks')
- self.vreg.init_registration([hooksdirectory])
- self.vreg.load_file(join(hooksdirectory, 'metadata.py'),
- 'cubicweb.hooks.metadata')
-
def open_connections_pools(self):
config = self.config
self._available_pools = Queue.Queue()
@@ -184,7 +177,9 @@
for modname in ('__init__', 'authobjs', 'wfobjs'):
self.vreg.load_file(join(etdirectory, '%s.py' % modname),
'cubicweb.entities.%s' % modname)
- self._bootstrap_hook_registry()
+ hooksdirectory = join(CW_SOFTWARE_ROOT, 'hooks')
+ self.vreg.load_file(join(hooksdirectory, 'metadata.py'),
+ 'cubicweb.hooks.metadata')
elif config.read_instance_schema:
# normal start: load the instance schema from the database
self.fill_schema()
@@ -233,8 +228,7 @@
if resetvreg:
if self.config._cubes is None:
self.config.init_cubes(self.get_cubes())
- # full reload of all appobjects
- self.vreg.reset()
+ # trigger full reload of all appobjects
self.vreg.set_schema(schema)
else:
self.vreg._set_schema(schema)
--- a/server/serverctl.py Mon May 10 15:20:54 2010 +0200
+++ b/server/serverctl.py Mon May 10 16:59:32 2010 +0200
@@ -249,9 +249,9 @@
cmdname = 'start'
cfgname = 'repository'
- def start_server(self, ctlconf, debug):
+ def start_server(self, ctlconf):
command = ['cubicweb-ctl start-repository ']
- if debug:
+ if ctlconf.debugmode:
command.append('--debug')
command.append(self.config.appid)
os.system(' '.join(command))
--- a/server/session.py Mon May 10 15:20:54 2010 +0200
+++ b/server/session.py Mon May 10 16:59:32 2010 +0200
@@ -302,16 +302,15 @@
def set_language(self, language):
"""i18n configuration for translation"""
- vreg = self.vreg
language = language or self.user.property_value('ui.language')
try:
- gettext, pgettext = vreg.config.translations[language]
+ gettext, pgettext = self.vreg.config.translations[language]
self._ = self.__ = gettext
self.pgettext = pgettext
except KeyError:
- language = vreg.property_value('ui.language')
+ language = self.vreg.property_value('ui.language')
try:
- gettext, pgettext = vreg.config.translations[language]
+ gettext, pgettext = self.vreg.config.translations[language]
self._ = self.__ = gettext
self.pgettext = pgettext
except KeyError:
@@ -626,16 +625,6 @@
else:
del self.transaction_data['ecache'][eid]
- def base_url(self):
- url = self.repo.config['base-url']
- if not url:
- try:
- url = self.repo.config.default_base_url()
- except AttributeError: # default_base_url() might not be available
- self.warning('missing base-url definition in server config')
- url = u''
- return url
-
def from_controller(self):
"""return the id (string) of the controller issuing the request (no
sense here, always return 'view')
--- a/skeleton/data/external_resources.tmpl Mon May 10 15:20:54 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,11 +0,0 @@
-# -*- shell-script -*-
-###############################################################################
-#
-# put here information about external resources used by your components,
-# or to overides existing external resources configuration
-#
-###############################################################################
-
-# CSS stylesheets to include in HTML headers
-# uncomment the line below to use template specific stylesheet
-# STYLESHEETS = DATADIR/cubes.%(cubename)s.css
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/skeleton/uiprops.py.tmpl Mon May 10 16:59:32 2010 +0200
@@ -0,0 +1,15 @@
+###############################################################################
+#
+# Put here information about external resources / styles used by your cube,
+# or to overides existing UI properties.
+#
+# Existing properties are available through the `sheet` dictionary available
+# in the global namespace. You also have access to a `data` function which
+# will return proper url for resources in the 'data' directory.
+#
+# /!\ this file should not be imported /!\
+###############################################################################
+
+# CSS stylesheets to include in HTML headers
+# uncomment the line below to use template specific stylesheet
+# STYLESHEETS = sheet['STYLESHEETS'] + [data('cubes.%(cubename)s.css')]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/data/scripts/script1.py Mon May 10 16:59:32 2010 +0200
@@ -0,0 +1,3 @@
+assert 'data/scripts/script1.py' == __file__
+assert '__main__' == __name__
+assert [] == __args__, __args__
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/data/scripts/script2.py Mon May 10 16:59:32 2010 +0200
@@ -0,0 +1,3 @@
+assert 'data/scripts/script2.py' == __file__
+assert '__main__' == __name__
+assert ['-v'] == __args__, __args__
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/data/scripts/script3.py Mon May 10 16:59:32 2010 +0200
@@ -0,0 +1,3 @@
+assert 'data/scripts/script3.py' == __file__
+assert '__main__' == __name__
+assert ['-vd', '-f', 'FILE.TXT'] == __args__, __args__
--- a/test/unittest_cwctl.py Mon May 10 15:20:54 2010 +0200
+++ b/test/unittest_cwctl.py Mon May 10 16:59:32 2010 +0200
@@ -24,8 +24,12 @@
from logilab.common.testlib import TestCase, unittest_main
from cubicweb.cwconfig import CubicWebConfiguration
+from cubicweb.devtools.testlib import CubicWebTC
+from cubicweb.server.migractions import ServerMigrationHelper
+
CubicWebConfiguration.load_cwctl_plugins() # XXX necessary?
+
class CubicWebCtlTC(TestCase):
def setUp(self):
self.stream = StringIO()
@@ -37,5 +41,25 @@
from cubicweb.cwctl import ListCommand
ListCommand().run([])
+
+class CubicWebShellTC(CubicWebTC):
+
+ def test_process_script_args_context(self):
+ repo = self.cnx._repo
+ mih = ServerMigrationHelper(None, repo=repo, cnx=self.cnx,
+ interactive=False,
+ # hack so it don't try to load fs schema
+ schema=1)
+ scripts = {'script1.py': list(),
+ 'script2.py': ['-v'],
+ 'script3.py': ['-vd', '-f', 'FILE.TXT'],
+ }
+ mih.cmd_process_script('data/scripts/script1.py', funcname=None)
+ for script, args in scripts.items():
+ scriptname = os.path.join('data/scripts/', script)
+ self.assert_(os.path.exists(scriptname))
+ mih.cmd_process_script(scriptname, None, scriptargs=args)
+
+
if __name__ == '__main__':
unittest_main()
--- a/test/unittest_vregistry.py Mon May 10 15:20:54 2010 +0200
+++ b/test/unittest_vregistry.py Mon May 10 16:59:32 2010 +0200
@@ -56,21 +56,25 @@
def test_load_subinterface_based_appobjects(self):
- self.vreg.reset()
self.vreg.register_objects([join(BASE, 'web', 'views', 'iprogress.py')])
# check progressbar was kicked
self.failIf(self.vreg['views'].get('progressbar'))
+ # we've to emulate register_objects to add custom MyCard objects
+ path = [join(BASE, 'entities', '__init__.py'),
+ join(BASE, 'web', 'views', 'iprogress.py')]
+ filemods = self.vreg.init_registration(path, None)
+ for filepath, modname in filemods:
+ self.vreg.load_file(filepath, modname)
class MyCard(Card):
__implements__ = (IMileStone,)
- self.vreg.reset()
self.vreg._loadedmods[__name__] = {}
self.vreg.register(MyCard)
- self.vreg.register_objects([join(BASE, 'entities', '__init__.py'),
- join(BASE, 'web', 'views', 'iprogress.py')])
+ self.vreg.initialization_completed()
# check progressbar isn't kicked
self.assertEquals(len(self.vreg['views']['progressbar']), 1)
def test_properties(self):
+ self.vreg.reset()
self.failIf('system.version.cubicweb' in self.vreg['propertydefs'])
self.failUnless(self.vreg.property_info('system.version.cubicweb'))
self.assertRaises(UnknownProperty, self.vreg.property_info, 'a.non.existent.key')
--- a/vregistry.py Mon May 10 15:20:54 2010 +0200
+++ b/vregistry.py Mon May 10 16:59:32 2010 +0200
@@ -406,6 +406,7 @@
# initialization methods ###################################################
def init_registration(self, path, extrapath=None):
+ self.reset()
# compute list of all modules that have to be loaded
self._toloadmods, filemods = _toload_info(path, extrapath)
# XXX is _loadedmods still necessary ? It seems like it's useful
--- a/web/application.py Mon May 10 15:20:54 2010 +0200
+++ b/web/application.py Mon May 10 16:59:32 2010 +0200
@@ -280,12 +280,12 @@
to publish HTTP request.
"""
- def __init__(self, config, debug=None,
+ def __init__(self, config,
session_handler_fact=CookieSessionHandler,
vreg=None):
self.info('starting web instance from %s', config.apphome)
if vreg is None:
- vreg = cwvreg.CubicWebVRegistry(config, debug=debug)
+ vreg = cwvreg.CubicWebVRegistry(config)
self.vreg = vreg
# connect to the repository and get instance's schema
self.repo = config.repository(vreg)
--- a/web/data/cubicweb.css Mon May 10 15:20:54 2010 +0200
+++ b/web/data/cubicweb.css Mon May 10 16:59:32 2010 +0200
@@ -3,82 +3,61 @@
* :copyright: 2003-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
* :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
*/
+
/***************************************/
-/* xhtml tags styles */
+/* xhtml tags */
/***************************************/
-*{
- margin:0px;
- padding :0px;
+/* scale and rhythm cf http://lamb.cc/typograph/ */
+body {
+ font-family: %(defaultFont)s;
+ font-size: %(defaultSize)s;
+ line-height: %(defaultLineHeight)s;
+ color: %(defaultColor)s;
}
+h1, h2, h3 { margin-top:0; margin-bottom:0; }
+
+/* got rhythm ? beat of 12*1.25 = 15 px */
+.rhythm_bg { background: url(/data/%(baseRhythmBg)s) repeat ! important; }
+
+/* scale 3:5 stranded */
+/* h1 { font-size:2em; } */
+/* h2 { font-size:1.61538em; } */
+/* h3 { font-size:1.23077em; } */
+
+/* scale le corbusier */
+/* h1 { font-size:2.11538em; } */
+/* h2 { font-size:1.61538em; } */
+/* h3 { font-size:1.30769em; } */
+
+/* scale traditional */
+h1 { font-size: %(h1FontSize)s; }
+h2 { font-size: %(h2FontSize)s; }
+h3 { font-size: %(h3FontSize)s; }
+
+/* paddings */
+h1 {
+ border-bottom: %(h1BorderBottomStyle)s;
+ padding: %(h1Padding)s;
+ margin: %(h1Margin)s;
+}
+h2 { padding: %(h2Padding)s; }
+h3 { padding: %(h3Padding)s; }
html, body {
background: #e2e2e2;
}
-body {
- font-size: 69%;
- font-weight: normal;
- font-family: Verdana, sans-serif;
-}
-
-h1 {
- font-size: 188%;
- margin: 0.2em 0px 0.3em;
- border-bottom: 1px solid #000;
-}
-
-h2, h3 {
- margin-top: 0.2em;
- margin-bottom: 0.3em;
-}
-
-h2 {
- font-size: 135%;
-}
-
-h3 {
- font-size: 130%;
-}
-
-h4 {
- font-size: 120%;
- margin: 0.2em 0px;
-}
-
-h5 {
- font-size:110%;
-}
-
-h6{
- font-size:105%;
-}
-
a, a:active, a:visited, a:link {
- color: #ff4500;
+ color: %(aColor)s;
text-decoration: none;
}
-a:hover{
+a:hover {
text-decoration: underline;
}
-a img, img {
- border: none;
- text-align: center;
-}
-
-p {
- margin: 0em 0px 0.2em;
- padding-top: 2px;
-}
-
-table, td, input, select{
- font-size: 100%;
-}
-
table {
- border-collapse: collapse;
border: none;
}
@@ -86,84 +65,58 @@
vertical-align: top;
}
-table td img {
- vertical-align: middle;
- margin-right: 10px;
-}
-
-ol {
- margin: 1px 0px 1px 16px;
-}
-
-ul{
- margin: 1px 0px 1px 4px;
- list-style-type: none;
-}
-
-ul li {
- margin-top: 2px;
- padding: 0px 0px 2px 8px;
- background: url("bullet_orange.png") 0% 6px no-repeat;
-}
-
-dt {
- font-size:1.17em;
- font-weight:600;
-}
-
-dd {
- margin: 0.6em 0 1.5em 2em;
-}
-
-fieldset {
- border: none;
-}
-
-legend {
- padding: 0px 2px;
- font: bold 1em Verdana, sans-serif;
-}
-
-input, textarea {
- padding: 0.2em;
- vertical-align: middle;
- border: 1px solid #ccc;
-}
-
-input:focus {
- border: 1px inset #ff7700;
-}
-
label, .label {
font-weight: bold;
}
-iframe {
- border: 0px;
+pre {
+ clear: both;
+ font-family: 'Courier New', monospace;
+ letter-spacing: 0.015em;
+ padding: 0.5em;
+ margin: 0 1.5em 1.5em;
+ background-color: #f0f0f0;
+ border: 1px solid #ccbca7;
}
-pre {
- font-family: Courier, "Courier New", Monaco, monospace;
- font-size: 100%;
- color: #000;
- background-color: #f2f2f2;
- border: 1px solid #ccc;
+p {
+ text-align: justify;
+ margin-bottom: %(defaultLineHeightEm)s;
+}
+
+ol, ul {
+ list-style-type: disc;
+ margin-bottom: %(defaultLineHeightEm)s;
}
-code {
- font-size: 120%;
- color: #000;
- background-color: #f2f2f2;
- border: 1px solid #ccc;
+ol ol,
+ul ul{
+ margin-left: 8px;
+ margin-bottom : 0px;
+}
+
+p + ul {
+ margin-top: -%(defaultLineHeightEm)s;
+}
+
+li {
+ margin-left: 1.5em;
}
-blockquote {
- font-family: Courier, "Courier New", serif;
- font-size: 120%;
- margin: 5px 0px;
- padding: 0.8em;
- background-color: #f2f2f2;
- border: 1px solid #ccc;
+h2 a, h2 a:active, h2 a:visited, h2 a:link,
+h3 a, h3 a:active, h3 a:visited, h3 a:link {
+ color: inherit;
+ text-decoration: none;
+}
+
+input, textarea {
+ border: 1px solid %(pageContentBorderColor)s;
+ padding: 0.1em;
+ vertical-align: middle;
+}
+
+input:focus {
+ border: 1px inset %(headerBgColor)s;
}
/***************************************/
@@ -179,8 +132,8 @@
}
.hr {
- border-bottom: 1px dotted #ccc;
- margin: 1em 0px;
+ border-bottom: 1px dotted %(pageContentBorderColor)s;
+ height: 17px;
}
.left {
@@ -200,14 +153,16 @@
visibility: hidden;
}
-li.invisible { list-style: none; background: none; padding: 0px 0px
-1px 1px; }
+li.invisible {
+ list-style: none;
+ background: none;
+ padding: 0px 0px 1px 1px;
+}
li.invisible div{
display: inline;
}
-
/***************************************/
/* LAYOUT */
/***************************************/
@@ -215,7 +170,7 @@
/* header */
table#header {
- background: #ff7700 url("banner.png") left top repeat-x;
+ background: %(headerBgColor)s url("banner.png") left top repeat-x;
text-align: left;
}
@@ -224,86 +179,94 @@
}
table#header a {
-color: #000;
+ color: %(defaultColor)s;
+}
+
+table#header img#logo{
+ vertical-align: middle;
}
span#appliName {
- font-weight: bold;
- color: #000;
- white-space: nowrap;
+ font-weight: bold;
+ color: %(defaultColor)s;
+ white-space: nowrap;
}
table#header td#headtext {
width: 100%;
}
+/* Popup on login box and userActionBox */
+div.popupWrapper{
+ position:relative;
+ z-index:100;
+}
+
+div.popup {
+ position: absolute;
+ background: #fff;
+ border: 1px solid #fff;
+ text-align: left;
+ z-index: 400;
+}
+
+div.popup ul li a {
+ text-decoration: none;
+ color: #000;
+}
+
/* FIXME appear with 4px width in IE6 */
div#stateheader{
min-width: 66%;
}
-/* Popup on login box and userActionBox */
-div.popupWrapper{
- position:relative;
- z-index:100;
-}
-
-div.popup {
- position: absolute;
- background: #fff;
- border: 1px solid black;
- text-align: left;
- z-index:400;
-}
-
-div.popup ul li a {
- text-decoration: none;
- color: black;
-}
-
/* main zone */
div#page {
- background: #e2e2e2;
- position: relative;
- min-height: 800px;
+ min-height: %(pageMinHeight)s;
+ margin: %(defaultLayoutMargin)s;
}
-table#mainLayout{
- margin:0px 3px;
+table#mainLayout #navColumnLeft {
+ width: 16em;
+ padding-right: %(defaultLayoutMargin)s;
+}
+
+table#mainLayout #navColumnRight {
+ width: 16em;
+ padding-left: %(defaultLayoutMargin)s;
}
-table#mainLayout td#contentcol {
- padding: 8px 10px 5px;
+div#pageContent {
+ clear: both;
+/* margin-top:-1px; /* enable when testing rhythm */
+ background: %(pageContentBgColor)s;
+ border: 1px solid %(pageContentBorderColor)s;
+ padding: 0px %(pageContentPadding)s %(pageContentPadding)s;
}
-table#mainLayout td.navcol {
- width: 16em;
+
+div#breadcrumbs {
+ padding: %(pageContentPadding)s 0 0 0;
}
+/*FIXME */
#contentheader {
margin: 0px;
padding: 0.2em 0.5em 0.5em 0.5em;
}
#contentheader a {
- color: #000;
-}
-
-div#pageContent {
- clear: both;
- padding: 10px 1em 2em;
- background: #ffffff;
- border: 1px solid #ccc;
+ color: %(defaultColor)s;
}
/* rql bar */
div#rqlinput {
- border: 1px solid #cfceb7;
margin-bottom: 8px;
padding: 3px;
- background: #cfceb7;
+ background: %(actionBoxTitleBgColor)s;
+ border: 1px solid %(actionBoxTitleBgColor)s;
}
input#rql{
@@ -311,26 +274,17 @@
}
/* boxes */
-div.navboxes {
- margin-top: 8px;
-}
div.boxFrame {
width: 100%;
}
div.boxTitle {
- padding-top: 0px;
- padding-bottom: 0.2em;
+ overflow: hidden;
font: bold 100% Georgia;
- overflow: hidden;
color: #fff;
- background: #ff9900 url("search.png") left bottom repeat-x;
-}
-
-div.searchBoxFrame div.boxTitle,
-div.greyBoxFrame div.boxTitle {
- background: #cfceb7;
+ padding: 0px 0px 0.2em;
+ background: %(headerBgColor)s url("search.png") left bottom repeat-x;
}
div.boxTitle span,
@@ -339,14 +293,19 @@
white-space: nowrap;
}
+div.searchBoxFrame div.boxTitle,
+div.greyBoxFrame div.boxTitle {
+ background: %(actionBoxTitleBgColor)s;
+}
+
div.sideBoxTitle span,
div.searchBoxFrame div.boxTitle span,
div.greyBoxFrame div.boxTitle span {
- color: #222211;
+ color: %(defaultColor)s;
}
.boxFrame a {
- color: #000;
+ color: %(defaultColor)s;
}
div.boxContent {
@@ -355,6 +314,21 @@
border-top: none;
}
+a.boxMenu {
+ display: block;
+ padding: 1px 9px 1px 3px;
+ background: transparent url("puce_down.png") 98% 6px no-repeat;
+}
+a.boxMenu:hover {
+ background: %(sideBoxBodyBgColor)s url("puce_down.png") 98% 6px no-repeat;
+ cursor: pointer;
+}
+
+a.popupMenu {
+ background: transparent url("puce_down_black.png") 2% 6px no-repeat;
+ padding-left: 2em;
+}
+
ul.boxListing {
margin: 0px;
padding: 0px 3px;
@@ -362,65 +336,47 @@
ul.boxListing li,
ul.boxListing ul li {
- display: inline;
+ list-style-type: none;
margin: 0px;
padding: 0px;
background-image: none;
}
ul.boxListing ul {
- margin: 0px 0px 0px 7px;
padding: 1px 3px;
}
ul.boxListing a {
- color: #000;
- display: block;
+ color: %(defaultColor)s;
padding: 1px 9px 1px 3px;
}
ul.boxListing .selected {
- color: #FF4500;
+ color: %(aColor)s;
font-weight: bold;
}
ul.boxListing a.boxBookmark:hover,
ul.boxListing a:hover,
ul.boxListing ul li a:hover {
+ color: #111100;
text-decoration: none;
- background: #eeedd9;
- color: #111100;
+ background: %(sideBoxBodyBgColor)s;
}
ul.boxListing a.boxMenu:hover {
- background: #eeedd9 url(puce_down.png) no-repeat scroll 98% 6px;
- cursor:pointer;
- border-top:medium none;
- }
-a.boxMenu {
- background: transparent url("puce_down.png") 98% 6px no-repeat;
- display: block;
- padding: 1px 9px 1px 3px;
-}
-
-
-a.popupMenu {
- background: transparent url("puce_down_black.png") 2% 6px no-repeat;
- padding-left: 2em;
+ cursor: pointer;
+ border-top: medium none;
+ background: %(sideBoxBodyBgColor)s url(puce_down.png) no-repeat scroll 98% 6px;
}
ul.boxListing ul li a:hover {
- background: #eeedd9 url("bullet_orange.png") 0% 6px no-repeat;
-}
-
-a.boxMenu:hover {
- background: #eeedd9 url("puce_down.png") 98% 6px no-repeat;
- cursor: pointer;
+ background: %(sideBoxBodyBgColor)s url("bullet_orange.png") 0% 6px no-repeat;
}
ul.boxListing a.boxBookmark {
padding-left: 3px;
- background-image:none;
+ background-image: none;
background:#fff;
}
@@ -440,7 +396,7 @@
}
div.sideBoxTitle {
- background: #cfceb7;
+ background: %(actionBoxTitleBgColor)s;
display: block;
font: bold 100% Georgia;
}
@@ -450,15 +406,20 @@
margin-bottom: 0.5em;
}
+ul.sideBox,
+ul.sideBox ul{
+ margin-bottom: 0px;
+}
+
ul.sideBox li{
- list-style: none;
- background: none;
+ list-style-type : none;
padding: 0px 0px 1px 1px;
- }
+ margin: 1px 0 1px 4px;
+}
div.sideBoxBody {
padding: 0.2em 5px;
- background: #eeedd9;
+ background: %(sideBoxBodyBgColor)s;
}
div.sideBoxBody a {
@@ -474,10 +435,10 @@
}
input.rqlsubmit{
- background: #fffff8 url("go.png") 50% 50% no-repeat;
+ margin: 0px;
width: 20px;
height: 20px;
- margin: 0px;
+ background: %(buttonBgColor)s url("go.png") 50% 50% no-repeat;
}
input#norql{
@@ -497,7 +458,7 @@
}
div#userActionsBox a.popupMenu {
- color: black;
+ color: #000;
text-decoration: underline;
padding-right: 2em;
}
@@ -521,7 +482,7 @@
/**************/
div#etyperestriction {
margin-bottom: 1ex;
- border-bottom: 1px solid #ccc;
+ border-bottom: 1px solid %(pageContentBorderColor)s;
}
span.slice a:visited,
@@ -531,7 +492,7 @@
span.selectedSlice a:visited,
span.selectedSlice a {
- color: #000;
+ color: %(defaultColor)s;
}
/* FIXME should be moved to cubes/folder */
@@ -546,19 +507,13 @@
}
div.prevnext a {
- color: #000;
+ color: %(defaultColor)s;
}
/***************************************/
/* entity views */
/***************************************/
-.mainInfo {
- margin-right: 1em;
- padding: 0.2em;
-}
-
-
div.mainRelated {
border: none;
margin-right: 1em;
@@ -577,7 +532,7 @@
}
div.section {
- margin-top: 0.5em;
+/* margin-top: 0.5em; */
width:100%;
}
@@ -611,50 +566,44 @@
.warning,
.message,
-.errorMessage ,
-.searchMessage{
+.errorMessage{
padding: 0.3em 0.3em 0.3em 1em;
font-weight: bold;
}
-.simpleMessage {
- margin: 4px 0px;
- font-weight: bold;
- color: #ff7700;
+.searchMessage{
+ padding-top: %(defaultLayoutMargin)s;
}
-div#appMsg, div.appMsg {
- border: 1px solid #cfceb7;
- margin-bottom: 8px;
- padding: 3px;
- background: #f8f8ee;
+.loginMessage {
+ margin: 4px 0px;
+ font-weight: bold;
+ color: %(headerBgColor)s;
+}
+
+div#appMsg {
+ border: 1px solid %(actionBoxTitleBgColor)s;
+ margin-bottom: %(defaultLayoutMargin)s;
}
.message {
margin: 0px;
- background: #f8f8ee url("information.png") 5px center no-repeat;
+ background: #fff url("information.png") 5px center no-repeat;
padding-left: 15px;
}
.errorMessage {
margin: 10px 0px;
padding-left: 25px;
- background: #f7f6f1 url("critical.png") 2px center no-repeat;
+ background: #fff url("critical.png") 2px center no-repeat;
color: #ed0d0d;
- border: 1px solid #cfceb7;
-}
-
-.searchMessage {
- margin-top: 0.5em;
- border-top: 1px solid #cfceb7;
- background: #eeedd9 url("information.png") 0% 50% no-repeat; /*dcdbc7*/
+ border: 1px solid %(actionBoxTitleBgColor)s;
}
.stateMessage {
- border: 1px solid #ccc;
- background: #f8f8ee url("information.png") 10px 50% no-repeat;
+ border: 1px solid %(pageContentBorderColor)s;
+ background: #fff url("information.png") 10px 50% no-repeat;
padding:4px 0px 4px 20px;
- border-width: 1px 0px 1px 0px;
}
/* warning messages like "There are too many results ..." */
@@ -668,8 +617,8 @@
position: fixed;
right: 5px;
top: 0px;
- background: #222211;
- color: white;
+ background: %(defaultColor)s;
+ color: #fff;
font-weight: bold;
display: none;
}
@@ -679,64 +628,59 @@
/***************************************/
table.listing {
+ width: 100%;
padding: 10px 0em;
- color: #000;
- width: 100%;
- border-right: 1px solid #dfdfdf;
+ color: %(defaultColor)s;
+ border: 1px solid %(listingBorderColor)s;
+}
+
+table.listing tr th {
+ font-weight: bold;
+ background: #dfdfdf;
+ font-size: 8pt;
+ padding: 3px 0px 3px 5px;
+ border: 1px solid %(listingBorderColor)s;
+ border-right:none}
+
+table.listing thead tr {
+/* border: 1px solid #dfdfdf; */
}
table.listing thead th.over {
- background-color: #746B6B;
+ background-color: #746b6b;
cursor: pointer;
}
-table.listing tr th {
- border: 1px solid #dfdfdf;
- border-right:none;
- font-size: 8pt;
- padding: 4px;
-}
-
table.listing tr .header {
- border-right: 1px solid #dfdfdf;
+ border-right: 1px solid %(listingBorderColor)s;
cursor: pointer;
}
table.listing td {
- color: #3D3D3D;
padding: 4px;
- background-color: #FFF;
+ padding: 3px 0px 3px 5px;
vertical-align: top;
-}
-
-table.listing th,
-table.listing td {
- padding: 3px 0px 3px 5px;
- border: 1px solid #dfdfdf;
+ border: 1px solid %(listingBorderColor)s;
border-right: none;
-}
-
-table.listing th {
- font-weight: bold;
- background: #ebe8d9 url("button.png") repeat-x;
+ background-color: #fff;
}
table.listing td a,
table.listing td a:visited {
- color: #666;
+ color: %(defaultColor)s;
}
table.listing a:hover,
table.listing tr.highlighted td a {
- color:#000;
+ color:%(defaultColor)s;
}
table.listing td.top {
- border: 1px solid white;
+ border: 1px solid #fff;
border-bottom: none;
text-align: right ! important;
- /* insane IE row bug workaround */
+ /* insane IE row bug workraound */
position: relative;
left: -1px;
top: -1px;
@@ -790,7 +734,7 @@
}
#add_newopt{
- background: #fffff8 url("go.png") 50% 50% no-repeat;
+ background: %(buttonBgColor)s url("go.png") 50% 50% no-repeat;
width: 20px;
line-height: 20px;
display:block;
@@ -803,9 +747,9 @@
input.button{
margin: 1em 1em 0px 0px;
- border: 1px solid #edecd2;
- border-color:#edecd2 #cfceb7 #cfceb7 #edecd2;
- background: #fffff8 url("button.png") bottom left repeat-x;
+ border: 1px solid %(buttonBorderColor)s;
+ border-color: %(buttonBorderColor)s %(actionBoxTitleBgColor)s %(actionBoxTitleBgColor)s %(buttonBorderColor)s;
+ background: %(buttonBgColor)s url("button.png") bottom left repeat-x;
}
/* FileItemInnerView jquery.treeview.css */
@@ -818,11 +762,11 @@
/* footer */
/***************************************/
-div.footer {
+div#footer {
text-align: center;
}
-div.footer a {
- color: #000;
+div#footer a {
+ color: %(defaultColor)s;
text-decoration: none;
}
@@ -841,15 +785,15 @@
/***************************************/
.title {
text-align: left;
- font-size: large;
+ font-size: large;
font-weight: bold;
}
.validateButton {
margin: 1em 1em 0px 0px;
- border: 1px solid #edecd2;
- border-color:#edecd2 #cfceb7 #cfceb7 #edecd2;
- background: #fffff8 url("button.png") bottom left repeat-x;
+ border: 1px solid %(buttonBorderColor)s;
+ border-color: %(buttonBorderColor)s %(actionBoxTitleBgColor)s %(actionBoxTitleBgColor)s %(buttonBorderColor)s;
+ background: %(buttonBgColor)s url("button.png") bottom left repeat-x;
}
/********************************/
@@ -859,3 +803,14 @@
.otherView {
float: right;
}
+
+/********************************/
+/* overwite other css here */
+/********************************/
+
+/* ui.tabs.css */
+ul .ui-tabs-nav,
+ul .ui-tabs-panel {
+ font-family: %(defaultFont)s;
+ font-size: %(defaultSize)s;
+}
--- a/web/data/cubicweb.manageview.css Mon May 10 15:20:54 2010 +0200
+++ b/web/data/cubicweb.manageview.css Mon May 10 16:59:32 2010 +0200
@@ -6,9 +6,9 @@
width: 100%;
}
-table.startup td {
- padding: 0.1em 0.2em;
-}
+/* table.startup td { */
+/* padding: 0.1em 0.2em; */
+/* } */
table.startup td.addcol {
text-align: right;
@@ -16,7 +16,5 @@
}
table.startup th{
- padding-top: 3px;
- padding-bottom: 3px;
text-align: left;
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/data/cubicweb.old.css Mon May 10 16:59:32 2010 +0200
@@ -0,0 +1,862 @@
+/*
+ * :organization: Logilab
+ * :copyright: 2003-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+ * :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
+ */
+
+/***************************************/
+/* xhtml tags */
+/***************************************/
+* {
+ margin: 0px;
+ padding: 0px;
+}
+
+html, body {
+ background: #e2e2e2;
+}
+
+body {
+ font-size: 69%;
+ font-weight: normal;
+ font-family: Verdana, sans-serif;
+}
+
+h1 {
+ font-size: 188%;
+ margin: 0.2em 0px 0.3em;
+ border-bottom: 1px solid #000;
+}
+
+h2, h3 {
+ margin-top: 0.2em;
+ margin-bottom: 0.3em;
+}
+
+h2 {
+ font-size: 135%;
+}
+
+h3 {
+ font-size: 130%;
+}
+
+h4 {
+ font-size: 120%;
+ margin: 0.2em 0px;
+}
+
+h5 {
+ font-size:110%;
+}
+
+h6{
+ font-size:105%;
+}
+
+a, a:active, a:visited, a:link {
+ color: #ff4500;
+ text-decoration: none;
+}
+
+a:hover{
+ text-decoration: underline;
+}
+
+a img, img {
+ border: none;
+ text-align: center;
+}
+
+p {
+ margin: 0em 0px 0.2em;
+ padding-top: 2px;
+}
+
+table, td, input, select{
+ font-size: 100%;
+}
+
+table {
+ border-collapse: collapse;
+ border: none;
+}
+
+table th, table td {
+ vertical-align: top;
+}
+
+table td img {
+ vertical-align: middle;
+ margin-right: 10px;
+}
+
+ol {
+ margin: 1px 0px 1px 16px;
+}
+
+ul{
+ margin: 1px 0px 1px 4px;
+ list-style-type: none;
+}
+
+ul li {
+ margin-top: 2px;
+ padding: 0px 0px 2px 8px;
+ background: url("bullet_orange.png") 0% 6px no-repeat;
+}
+
+dt {
+ font-size:1.17em;
+ font-weight:600;
+}
+
+dd {
+ margin: 0.6em 0 1.5em 2em;
+}
+
+fieldset {
+ border: none;
+}
+
+legend {
+ padding: 0px 2px;
+ font: bold 1em Verdana, sans-serif;
+}
+
+input, textarea {
+ padding: 0.2em;
+ vertical-align: middle;
+ border: 1px solid #ccc;
+}
+
+input:focus {
+ border: 1px inset #ff7700;
+}
+
+label, .label {
+ font-weight: bold;
+}
+
+iframe {
+ border: 0px;
+}
+
+pre {
+ font-family: Courier, "Courier New", Monaco, monospace;
+ font-size: 100%;
+ color: #000;
+ background-color: #f2f2f2;
+ border: 1px solid #ccc;
+}
+
+code {
+ font-size: 120%;
+ color: #000;
+ background-color: #f2f2f2;
+ border: 1px solid #ccc;
+}
+
+blockquote {
+ font-family: Courier, "Courier New", serif;
+ font-size: 120%;
+ margin: 5px 0px;
+ padding: 0.8em;
+ background-color: #f2f2f2;
+ border: 1px solid #ccc;
+}
+
+/***************************************/
+/* generic classes */
+/***************************************/
+
+.odd {
+ background-color: #f7f6f1;
+}
+
+.even {
+ background-color: transparent;
+}
+
+.hr {
+ border-bottom: 1px dotted #ccc;
+ margin: 1em 0px;
+}
+
+.left {
+ float: left;
+}
+
+.right {
+ float: right;
+}
+
+.clear {
+ clear: both;
+}
+
+.hidden {
+ display: none;
+ visibility: hidden;
+}
+
+li.invisible { list-style: none; background: none; padding: 0px 0px
+1px 1px; }
+
+li.invisible div{
+ display: inline;
+}
+
+
+/***************************************/
+/* LAYOUT */
+/***************************************/
+
+/* header */
+
+table#header {
+ background: #ff7700 url("banner.png") left top repeat-x;
+ text-align: left;
+}
+
+table#header td {
+ vertical-align: middle;
+}
+
+table#header a {
+color: #000;
+}
+
+span#appliName {
+ font-weight: bold;
+ color: #000;
+ white-space: nowrap;
+}
+
+table#header td#headtext {
+ width: 100%;
+}
+
+/* FIXME appear with 4px width in IE6 */
+div#stateheader{
+ min-width: 66%;
+}
+
+/* Popup on login box and userActionBox */
+div.popupWrapper{
+ position:relative;
+ z-index:100;
+}
+
+div.popup {
+ position: absolute;
+ background: #fff;
+ border: 1px solid black;
+ text-align: left;
+ z-index:400;
+}
+
+div.popup ul li a {
+ text-decoration: none;
+ color: black;
+}
+
+/* main zone */
+
+div#page {
+ background: #e2e2e2;
+ position: relative;
+ min-height: 800px;
+}
+
+table#mainLayout{
+ margin:0px 3px;
+}
+
+table#mainLayout td#contentColumn {
+ padding: 8px 10px 5px;
+}
+
+table#mainLayout td#navColumnLeft,
+table#mainLayout td#navColumnRight {
+ width: 16em;
+}
+
+#contentheader {
+ margin: 0px;
+ padding: 0.2em 0.5em 0.5em 0.5em;
+}
+
+#contentheader a {
+ color: #000;
+}
+
+div#pageContent {
+ clear: both;
+ padding: 10px 1em 2em;
+ background: #ffffff;
+ border: 1px solid #ccc;
+}
+
+/* rql bar */
+
+div#rqlinput {
+ border: 1px solid #cfceb7;
+ margin-bottom: 8px;
+ padding: 3px;
+ background: #cfceb7;
+}
+
+input#rql{
+ width: 95%;
+}
+
+/* boxes */
+div.navboxes {
+ margin-top: 8px;
+}
+
+div.boxFrame {
+ width: 100%;
+}
+
+div.boxTitle {
+ padding-top: 0px;
+ padding-bottom: 0.2em;
+ font: bold 100% Georgia;
+ overflow: hidden;
+ color: #fff;
+ background: #ff9900 url("search.png") left bottom repeat-x;
+}
+
+div.searchBoxFrame div.boxTitle,
+div.greyBoxFrame div.boxTitle {
+ background: #cfceb7;
+}
+
+div.boxTitle span,
+div.sideBoxTitle span {
+ padding: 0px 5px;
+ white-space: nowrap;
+}
+
+div.sideBoxTitle span,
+div.searchBoxFrame div.boxTitle span,
+div.greyBoxFrame div.boxTitle span {
+ color: #222211;
+}
+
+.boxFrame a {
+ color: #000;
+}
+
+div.boxContent {
+ padding: 3px 0px;
+ background: #fff;
+ border-top: none;
+}
+
+ul.boxListing {
+ margin: 0px;
+ padding: 0px 3px;
+}
+
+ul.boxListing li,
+ul.boxListing ul li {
+ display: inline;
+ margin: 0px;
+ padding: 0px;
+ background-image: none;
+}
+
+ul.boxListing ul {
+ margin: 0px 0px 0px 7px;
+ padding: 1px 3px;
+}
+
+ul.boxListing a {
+ color: #000;
+ display: block;
+ padding: 1px 9px 1px 3px;
+}
+
+ul.boxListing .selected {
+ color: #FF4500;
+ font-weight: bold;
+}
+
+ul.boxListing a.boxBookmark:hover,
+ul.boxListing a:hover,
+ul.boxListing ul li a:hover {
+ text-decoration: none;
+ background: #eeedd9;
+ color: #111100;
+}
+
+ul.boxListing a.boxMenu:hover {
+ background: #eeedd9 url(puce_down.png) no-repeat scroll 98% 6px;
+ cursor:pointer;
+ border-top:medium none;
+ }
+a.boxMenu {
+ background: transparent url("puce_down.png") 98% 6px no-repeat;
+ display: block;
+ padding: 1px 9px 1px 3px;
+}
+
+
+a.popupMenu {
+ background: transparent url("puce_down_black.png") 2% 6px no-repeat;
+ padding-left: 2em;
+}
+
+ul.boxListing ul li a:hover {
+ background: #eeedd9 url("bullet_orange.png") 0% 6px no-repeat;
+}
+
+a.boxMenu:hover {
+ background: #eeedd9 url("puce_down.png") 98% 6px no-repeat;
+ cursor: pointer;
+}
+
+ul.boxListing a.boxBookmark {
+ padding-left: 3px;
+ background-image:none;
+ background:#fff;
+}
+
+ul.boxListing ul li a {
+ background: #fff url("bullet_orange.png") 0% 6px no-repeat;
+ padding: 1px 3px 0px 10px;
+}
+
+div.searchBoxFrame div.boxContent {
+ padding: 4px 4px 3px;
+ background: #f0eff0 url("gradient-grey-up.png") left top repeat-x;
+}
+
+div.shadow{
+ height: 14px;
+ background: url("shadow.gif") no-repeat top right;
+}
+
+div.sideBoxTitle {
+ background: #cfceb7;
+ display: block;
+ font: bold 100% Georgia;
+}
+
+div.sideBox {
+ padding: 0 0 0.2em;
+ margin-bottom: 0.5em;
+}
+
+ul.sideBox li{
+ list-style: none;
+ background: none;
+ padding: 0px 0px 1px 1px;
+ }
+
+div.sideBoxBody {
+ padding: 0.2em 5px;
+ background: #eeedd9;
+}
+
+div.sideBoxBody a {
+ color:#555544;
+}
+
+div.sideBoxBody a:hover {
+ text-decoration: underline;
+}
+
+div.sideBox table td {
+ padding-right: 1em;
+}
+
+input.rqlsubmit{
+ background: #fffff8 url("go.png") 50% 50% no-repeat;
+ width: 20px;
+ height: 20px;
+ margin: 0px;
+}
+
+input#norql{
+ width:13em;
+ margin-right: 2px;
+}
+
+/* user actions menu */
+a.logout, a.logout:visited, a.logout:hover{
+ color: #fff;
+ text-decoration: none;
+}
+
+div#userActionsBox {
+ width: 14em;
+ text-align: right;
+}
+
+div#userActionsBox a.popupMenu {
+ color: black;
+ text-decoration: underline;
+ padding-right: 2em;
+}
+
+/* download box XXX move to its own file? */
+div.downloadBoxTitle{
+ background : #8FBC8F;
+ font-weight: bold;
+}
+
+div.downloadBox{
+ font-weight: bold;
+}
+
+div.downloadBox div.sideBoxBody{
+ background : #EEFED9;
+}
+
+/**************/
+/* navigation */
+/**************/
+div#etyperestriction {
+ margin-bottom: 1ex;
+ border-bottom: 1px solid #ccc;
+}
+
+span.slice a:visited,
+span.slice a:hover{
+ color: #555544;
+}
+
+span.selectedSlice a:visited,
+span.selectedSlice a {
+ color: #000;
+}
+
+/* FIXME should be moved to cubes/folder */
+div.navigation a {
+ text-align: center;
+ text-decoration: none;
+}
+
+div.prevnext {
+ width: 100%;
+ margin-bottom: 1em;
+}
+
+div.prevnext a {
+ color: #000;
+}
+
+/***************************************/
+/* entity views */
+/***************************************/
+
+.mainInfo {
+ margin-right: 1em;
+ padding: 0.2em;
+}
+
+
+div.mainRelated {
+ border: none;
+ margin-right: 1em;
+ padding: 0.5em 0.2em 0.2em;
+}
+
+div.primaryRight{
+ }
+
+div.metadata {
+ font-size: 90%;
+ margin: 5px 0px 3px;
+ color: #666;
+ font-style: italic;
+ text-align: right;
+}
+
+div.section {
+ margin-top: 0.5em;
+ width:100%;
+}
+
+div.section a:hover {
+ text-decoration: none;
+}
+
+/* basic entity view */
+
+tr.entityfield th {
+ text-align: left;
+ padding-right: 0.5em;
+}
+
+div.field {
+ display: inline;
+}
+
+div.ctxtoolbar {
+ float: right;
+ padding-left: 24px;
+ position: relative;
+}
+div.toolbarButton {
+ display: inline;
+}
+
+/***************************************/
+/* messages */
+/***************************************/
+
+.warning,
+.message,
+.errorMessage ,
+.searchMessage{
+ padding: 0.3em 0.3em 0.3em 1em;
+ font-weight: bold;
+}
+
+.loginMessage {
+ margin: 4px 0px;
+ font-weight: bold;
+ color: #ff7700;
+}
+
+div#appMsg, div.appMsg{
+ border: 1px solid #cfceb7;
+ margin-bottom: 8px;
+ padding: 3px;
+ background: #f8f8ee;
+}
+
+.message {
+ margin: 0px;
+ background: #f8f8ee url("information.png") 5px center no-repeat;
+ padding-left: 15px;
+}
+
+.errorMessage {
+ margin: 10px 0px;
+ padding-left: 25px;
+ background: #f7f6f1 url("critical.png") 2px center no-repeat;
+ color: #ed0d0d;
+ border: 1px solid #cfceb7;
+}
+
+.searchMessage {
+ margin-top: 0.5em;
+ border-top: 1px solid #cfceb7;
+ background: #eeedd9 url("information.png") 0% 50% no-repeat; /*dcdbc7*/
+}
+
+.stateMessage {
+ border: 1px solid #ccc;
+ background: #f8f8ee url("information.png") 10px 50% no-repeat;
+ padding:4px 0px 4px 20px;
+ border-width: 1px 0px 1px 0px;
+}
+
+/* warning messages like "There are too many results ..." */
+.warning {
+ padding-left: 25px;
+ background: #f2f2f2 url("critical.png") 3px 50% no-repeat;
+}
+
+/* label shown in the top-right hand corner during form validation */
+div#progress {
+ position: fixed;
+ right: 5px;
+ top: 0px;
+ background: #222211;
+ color: white;
+ font-weight: bold;
+ display: none;
+}
+
+/***************************************/
+/* listing table */
+/***************************************/
+
+table.listing {
+ padding: 10px 0em;
+ color: #000;
+ width: 100%;
+ border-right: 1px solid #dfdfdf;
+}
+
+
+table.listing thead th.over {
+ background-color: #746B6B;
+ cursor: pointer;
+}
+
+table.listing tr th {
+ border: 1px solid #dfdfdf;
+ border-right:none;
+ font-size: 8pt;
+ padding: 4px;
+}
+
+table.listing tr .header {
+ border-right: 1px solid #dfdfdf;
+ cursor: pointer;
+}
+
+table.listing td {
+ color: #3D3D3D;
+ padding: 4px;
+ background-color: #FFF;
+ vertical-align: top;
+}
+
+table.listing th,
+table.listing td {
+ padding: 3px 0px 3px 5px;
+ border: 1px solid #dfdfdf;
+ border-right: none;
+}
+
+table.listing th {
+ font-weight: bold;
+ background: #ebe8d9 url("button.png") repeat-x;
+}
+
+table.listing td a,
+table.listing td a:visited {
+ color: #666;
+}
+
+table.listing a:hover,
+table.listing tr.highlighted td a {
+ color:#000;
+}
+
+table.listing td.top {
+ border: 1px solid white;
+ border-bottom: none;
+ text-align: right ! important;
+ /* insane IE row bug workaround */
+ position: relative;
+ left: -1px;
+ top: -1px;
+}
+
+table.htableForm {
+ vertical-align: middle;
+}
+table.htableForm td{
+ padding-left: 1em;
+ padding-top: 0.5em;
+}
+table.htableForm th{
+ padding-left: 1em;
+}
+table.htableForm .validateButton {
+ margin-right: 0.2em;
+ vertical-align: top;
+ margin-bottom: 0.2em; /* because vertical-align doesn't seems to have any effect */
+}
+
+/***************************************/
+/* error view (views/management.py) */
+/***************************************/
+
+div.pycontext { /* html traceback */
+ font-family: Verdana, sans-serif;
+ font-size: 80%;
+ padding: 1em;
+ margin: 10px 0px 5px 20px;
+ background-color: #dee7ec;
+}
+
+div.pycontext span.name {
+ color: #ff0000;
+}
+
+
+/***************************************/
+/* addcombobox */
+/***************************************/
+
+input#newopt{
+ width:120px ;
+ display:block;
+ float:left;
+ }
+
+div#newvalue{
+ margin-top:2px;
+ }
+
+#add_newopt{
+ background: #fffff8 url("go.png") 50% 50% no-repeat;
+ width: 20px;
+ line-height: 20px;
+ display:block;
+ float:left;
+}
+
+/***************************************/
+/* buttons */
+/***************************************/
+
+input.button{
+ margin: 1em 1em 0px 0px;
+ border: 1px solid #edecd2;
+ border-color:#edecd2 #cfceb7 #cfceb7 #edecd2;
+ background: #fffff8 url("button.png") bottom left repeat-x;
+}
+
+/* FileItemInnerView jquery.treeview.css */
+.folder {
+ /* disable odd/even under folder class */
+ background-color: transparent;
+}
+
+/***************************************/
+/* footer */
+/***************************************/
+
+div#footer {
+ text-align: center;
+}
+div#footer a {
+ color: #000;
+ text-decoration: none;
+}
+
+
+/****************************************/
+/* FIXME must by managed by cubes */
+/****************************************/
+.needsvalidation {
+ font-style: italic;
+ color: gray;
+}
+
+
+/***************************************/
+/* FIXME : Deprecated ? entity view ? */
+/***************************************/
+.title {
+ text-align: left;
+ font-size: large;
+ font-weight: bold;
+}
+
+.validateButton {
+ margin: 1em 1em 0px 0px;
+ border: 1px solid #edecd2;
+ border-color:#edecd2 #cfceb7 #cfceb7 #edecd2;
+ background: #fffff8 url("button.png") bottom left repeat-x;
+}
+
+/********************************/
+/* placement of alt. view icons */
+/********************************/
+
+.otherView {
+ float: right;
+}
--- a/web/data/cubicweb.print.css Mon May 10 15:20:54 2010 +0200
+++ b/web/data/cubicweb.print.css Mon May 10 16:59:32 2010 +0200
@@ -1,4 +1,15 @@
-td#speedbar, img.logo, div.header{
- display:none }
+* {
+ color: #000 !important;
+}
-a{color:black }
\ No newline at end of file
+div#popupLoginBox,
+div#popupLoginBox,
+img#logo, div.header,
+#navColumnLeft, #navColumnRight,
+#footer {
+ display: none
+}
+
+div#pageContent{
+ border: none;
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/data/cubicweb.reset.css Mon May 10 16:59:32 2010 +0200
@@ -0,0 +1,62 @@
+/* http://meyerweb.com/eric/tools/css/reset/ */
+/* v1.0 | 20080212 */
+
+html, body, div, span, applet, object, iframe,
+h1, h2, h3, h4, h5, h6, p, blockquote, pre,
+a, abbr, acronym, address, big, cite, code,
+del, dfn, em, font, img, ins, kbd, q, s, samp,
+small, strike, strong, sub, sup, tt, var,
+b, u, i, center,
+dl, dt, dd, ol, ul, li,
+fieldset, form, label, legend,
+table, caption, tbody, tfoot, thead, tr, th, td {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ outline: 0;
+ font-size: 100%;
+ vertical-align: baseline;
+ background: transparent;
+}
+body {
+ line-height: 1;
+}
+ol, ul {
+ list-style: none;
+}
+blockquote, q {
+ quotes: none;
+}
+blockquote:before, blockquote:after,
+q:before, q:after {
+ content: '';
+ content: none;
+}
+
+/* remember to define focus styles! */
+:focus {
+ outline: 0;
+}
+
+/* remember to highlight inserts somehow! */
+ins {
+ text-decoration: none;
+}
+del {
+ text-decoration: line-through;
+}
+
+/* tables still need 'cellspacing="0"' in the markup */
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+
+/* Logilab */
+img{
+ border: none;
+}
+
+fieldset {
+ border: none;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/data/cubicweb.rhythm.js Mon May 10 16:59:32 2010 +0200
@@ -0,0 +1,7 @@
+$(document).ready(function() {
+ $('a.rhythm').click(function (event){
+ $('div#pageContent').toggleClass('rhythm_bg');
+ $('div#page').toggleClass('rhythm_bg');
+ event.preventDefault();
+ });
+ });
--- a/web/data/cubicweb.timeline-bundle.js Mon May 10 15:20:54 2010 +0200
+++ b/web/data/cubicweb.timeline-bundle.js Mon May 10 16:59:32 2010 +0200
@@ -1,14 +1,14 @@
var SimileAjax_urlPrefix = baseuri() + 'data/';
var Timeline_urlPrefix = baseuri() + 'data/';
-/*==================================================
+/*
* Simile Ajax API
*
* Include this file in your HTML file as follows:
*
* <script src="http://simile.mit.edu/ajax/api/simile-ajax-api.js" type="text/javascript"></script>
*
- *==================================================
+ *
*/
if (typeof SimileAjax == "undefined") {
@@ -213,9 +213,9 @@
SimileAjax.loaded = true;
})();
}
-/*==================================================
+/*
* Platform Utility Functions and Constants
- *==================================================
+ *
*/
/* This must be called after our jQuery has been loaded
@@ -319,9 +319,10 @@
SimileAjax.Platform.getDefaultLocale = function() {
return SimileAjax.Platform.clientLocale;
-};/*==================================================
+};
+/*
* Debug Utility Functions
- *==================================================
+ *
*/
SimileAjax.Debug = {
@@ -678,9 +679,9 @@
}
};
})();
-/*==================================================
+/*
* DOM Utility Functions
- *==================================================
+ *
*/
SimileAjax.DOM = new Object();
@@ -1040,9 +1041,9 @@
SimileAjax.includeCssFile(document, SimileAjax.urlPrefix + "styles/graphics-ie6.css");
}
-/*==================================================
+/*
* Opacity, translucency
- *==================================================
+ *
*/
SimileAjax.Graphics._createTranslucentImage1 = function(url, verticalAlign) {
var elmt = document.createElement("img");
@@ -1119,9 +1120,9 @@
}
};
-/*==================================================
+/*
* Bubble
- *==================================================
+ *
*/
SimileAjax.Graphics.bubbleConfig = {
@@ -1479,9 +1480,9 @@
};
};
-/*==================================================
+/*
* Animation
- *==================================================
+ *
*/
/**
@@ -1549,11 +1550,11 @@
}
};
-/*==================================================
+/*
* CopyPasteButton
*
* Adapted from http://spaces.live.com/editorial/rayozzie/demo/liveclip/liveclipsample/techPreview.html.
- *==================================================
+ *
*/
/**
@@ -1606,9 +1607,9 @@
return div;
};
-/*==================================================
+/*
* getWidthHeight
- *==================================================
+ *
*/
SimileAjax.Graphics.getWidthHeight = function(el) {
// RETURNS hash {width: w, height: h} in pixels
@@ -1633,9 +1634,9 @@
};
-/*==================================================
+/*
* FontRenderingContext
- *==================================================
+ *
*/
SimileAjax.Graphics.getFontRenderingContext = function(elmt, width) {
return new SimileAjax.Graphics._FontRenderingContext(elmt, width);
@@ -2127,9 +2128,9 @@
var d = new Date().getTimezoneOffset();
return d / -60;
};
-/*==================================================
+/*
* String Utility Functions and Constants
- *==================================================
+ *
*/
String.prototype.trim = function() {
@@ -2170,9 +2171,9 @@
}
return result;
};
-/*==================================================
+/*
* HTML Utility Functions
- *==================================================
+ *
*/
SimileAjax.HTML = new Object();
@@ -2655,9 +2656,9 @@
return (this._a.length > 0) ? this._a[this._a.length - 1] : null;
};
-/*==================================================
+/*
* Event Index
- *==================================================
+ *
*/
SimileAjax.EventIndex = function(unit) {
@@ -2889,9 +2890,9 @@
return this._index < this._events.length() ?
this._events.elementAt(this._index++) : null;
}
-};/*==================================================
+};/*
* Default Unit
- *==================================================
+ *
*/
SimileAjax.NativeDateUnit = new Object();
@@ -2953,9 +2954,9 @@
return new Date(v.getTime() + n);
};
-/*==================================================
+/*
* General, miscellaneous SimileAjax stuff
- *==================================================
+ *
*/
SimileAjax.ListenerQueue = function(wildcardHandlerName) {
@@ -2998,7 +2999,7 @@
}
};
-/*======================================================================
+/*
* History
*
* This is a singleton that keeps track of undoable user actions and
@@ -3020,7 +3021,7 @@
*
* An iframe is inserted into the document's body element to track
* onload events.
- *======================================================================
+ *
*/
SimileAjax.History = {
@@ -3632,7 +3633,7 @@
}
return elmt;
};
-/*==================================================
+/*
* Timeline API
*
* This file will load all the Javascript files
@@ -3696,7 +3697,7 @@
* Note that the Ajax version is usually NOT the same as the Timeline version.
* See variable simile_ajax_ver below for the current version
*
- *==================================================
+ *
*/
(function() {
@@ -3928,7 +3929,7 @@
loadMe();
}
})();
-/*=================================================
+/*
*
* Coding standards:
*
@@ -3950,14 +3951,14 @@
* We also want to use jslint: http://www.jslint.com/
*
*
- *==================================================
+ *
*/
-/*==================================================
+/*
* Timeline VERSION
- *==================================================
+ *
*/
// Note: version is also stored in the build.xml file
Timeline.version = 'pre 2.4.0'; // use format 'pre 1.2.3' for trunk versions
@@ -3965,9 +3966,9 @@
Timeline.display_version = Timeline.version + ' (with Ajax lib ' + Timeline.ajax_lib_version + ')';
// cf method Timeline.writeVersion
-/*==================================================
+/*
* Timeline
- *==================================================
+ *
*/
Timeline.strings = {}; // localization string tables
Timeline.HORIZONTAL = 0;
@@ -4183,9 +4184,9 @@
-/*==================================================
+/*
* Timeline Implementation object
- *==================================================
+ *
*/
Timeline._Impl = function(elmt, bandInfos, orientation, unit, timelineID) {
SimileAjax.WindowManager.initialize();
@@ -4585,7 +4586,7 @@
this.paint();
};
-/*=================================================
+/*
*
* Coding standards:
*
@@ -4607,14 +4608,14 @@
* We also want to use jslint: http://www.jslint.com/
*
*
- *==================================================
+ *
*/
-/*==================================================
+/*
* Band
- *==================================================
+ *
*/
Timeline._Band = function(timeline, bandInfo, index) {
// hack for easier subclassing
@@ -5344,9 +5345,9 @@
Timeline._Band.prototype.closeBubble = function() {
SimileAjax.WindowManager.cancelPopups();
};
-/*==================================================
+/*
* Classic Theme
- *==================================================
+ *
*/
@@ -5523,14 +5524,14 @@
};
this.mouseWheel = 'scroll'; // 'default', 'zoom', 'scroll'
-};/*==================================================
+};/*
* An "ether" is a object that maps date/time to pixel coordinates.
- *==================================================
+ *
*/
-/*==================================================
+/*
* Linear Ether
- *==================================================
+ *
*/
Timeline.LinearEther = function(params) {
@@ -5601,9 +5602,9 @@
};
-/*==================================================
+/*
* Hot Zone Ether
- *==================================================
+ *
*/
Timeline.HotZoneEther = function(params) {
@@ -5828,9 +5829,9 @@
Timeline.HotZoneEther.prototype._getScale = function() {
return this._interval / this._pixelsPerInterval;
};
-/*==================================================
+/*
* Gregorian Ether Painter
- *==================================================
+ *
*/
Timeline.GregorianEtherPainter = function(params) {
@@ -5919,9 +5920,9 @@
};
-/*==================================================
+/*
* Hot Zone Gregorian Ether Painter
- *==================================================
+ *
*/
Timeline.HotZoneGregorianEtherPainter = function(params) {
@@ -6080,9 +6081,9 @@
}
};
-/*==================================================
+/*
* Year Count Ether Painter
- *==================================================
+ *
*/
Timeline.YearCountEtherPainter = function(params) {
@@ -6169,9 +6170,9 @@
Timeline.YearCountEtherPainter.prototype.softPaint = function() {
};
-/*==================================================
+/*
* Quarterly Ether Painter
- *==================================================
+ *
*/
Timeline.QuarterlyEtherPainter = function(params) {
@@ -6257,9 +6258,9 @@
Timeline.QuarterlyEtherPainter.prototype.softPaint = function() {
};
-/*==================================================
+/*
* Ether Interval Marker Layout
- *==================================================
+ *
*/
Timeline.EtherIntervalMarkerLayout = function(timeline, band, theme, align, showLine) {
@@ -6363,9 +6364,9 @@
};
};
-/*==================================================
+/*
* Ether Highlight Layout
- *==================================================
+ *
*/
Timeline.EtherHighlight = function(timeline, band, theme, backgroundLayer) {
@@ -6404,9 +6405,9 @@
}
}
};
-/*==================================================
+/*
* Event Utils
- *==================================================
+ *
*/
Timeline.EventUtils = {};
@@ -6421,7 +6422,7 @@
};
Timeline.EventUtils.decodeEventElID = function(elementID) {
- /*==================================================
+ /*
*
* Use this function to decode an event element's id on a band (label div,
* tape div or icon img).
@@ -6447,7 +6448,7 @@
* by using Timeline.getTimeline, Timeline.getBand, or
* Timeline.getEvent and passing in the element's id
*
- *==================================================
+ *
*/
var parts = elementID.split('-');
@@ -6467,9 +6468,9 @@
// elType should be one of {label | icon | tapeN | highlightN}
return elType + "-tl-" + timeline.timelineID +
"-" + band.getIndex() + "-" + evt.getID();
-};/*==================================================
+};/*
* Gregorian Date Labeller
- *==================================================
+ *
*/
Timeline.GregorianDateLabeller = function(locale, timeZone) {
@@ -6558,9 +6559,9 @@
return { text: text, emphasized: emphasized };
}
-/*==================================================
+/*
* Default Event Source
- *==================================================
+ *
*/
@@ -7125,12 +7126,12 @@
};
-/*==================================================
+/*
* Original Event Painter
- *==================================================
+ *
*/
-/*==================================================
+/*
*
* To enable a single event listener to monitor everything
* on a Timeline, we need a way to map from an event's icon,
@@ -7152,7 +7153,7 @@
* You can then retrieve the band/timeline objects and event object
* by using Timeline.EventUtils.decodeEventElID
*
- *==================================================
+ *
*/
/*
@@ -7818,9 +7819,9 @@
this._eventPaintListeners[i](this._band, op, evt, els);
}
};
-/*==================================================
+/*
* Detailed Event Painter
- *==================================================
+ *
*/
// Note: a number of features from original-painter
@@ -8509,9 +8510,9 @@
this._onSelectListeners[i](eventID);
}
};
-/*==================================================
+/*
* Overview Event Painter
- *==================================================
+ *
*/
Timeline.OverviewEventPainter = function(params) {
@@ -8767,9 +8768,9 @@
Timeline.OverviewEventPainter.prototype.showBubble = function(evt) {
// not implemented
};
-/*==================================================
+/*
* Compact Event Painter
- *==================================================
+ *
*/
Timeline.CompactEventPainter = function(params) {
@@ -9831,9 +9832,9 @@
this._onSelectListeners[i](eventIDs);
}
};
-/*==================================================
+/*
* Span Highlight Decorator
- *==================================================
+ *
*/
Timeline.SpanHighlightDecorator = function(params) {
@@ -9948,9 +9949,9 @@
Timeline.SpanHighlightDecorator.prototype.softPaint = function() {
};
-/*==================================================
+/*
* Point Highlight Decorator
- *==================================================
+ *
*/
Timeline.PointHighlightDecorator = function(params) {
@@ -10015,9 +10016,9 @@
Timeline.PointHighlightDecorator.prototype.softPaint = function() {
};
-/*==================================================
+/*
* Default Unit
- *==================================================
+ *
*/
Timeline.NativeDateUnit = new Object();
@@ -10083,35 +10084,35 @@
return new Date(v.getTime() + n);
};
-/*==================================================
+/*
* Common localization strings
- *==================================================
+ *
*/
Timeline.strings["fr"] = {
wikiLinkLabel: "Discute"
};
-/*==================================================
+/*
* Localization of labellers.js
- *==================================================
+ *
*/
Timeline.GregorianDateLabeller.monthNames["fr"] = [
"jan", "fev", "mar", "avr", "mai", "jui", "jui", "aou", "sep", "oct", "nov", "dec"
];
-/*==================================================
+/*
* Common localization strings
- *==================================================
+ *
*/
Timeline.strings["en"] = {
wikiLinkLabel: "Discuss"
};
-/*==================================================
+/*
* Localization of labellers.js
- *==================================================
+ *
*/
Timeline.GregorianDateLabeller.monthNames["en"] = [
--- a/web/data/cubicweb.widgets.js Mon May 10 15:20:54 2010 +0200
+++ b/web/data/cubicweb.widgets.js Mon May 10 16:59:32 2010 +0200
@@ -313,34 +313,5 @@
});
-/*
- * ComboBox with a textinput : allows to add a new value
- */
-
-Widgets.AddComboBox = defclass('AddComboBox', null, {
- __init__ : function(wdgnode) {
- jQuery("#add_newopt").click(function() {
- var new_val = jQuery("#newopt").val();
- if (!new_val){
- return false;
- }
- name = wdgnode.getAttribute('name').split(':');
- this.rel = name[0];
- this.eid_to = name[1];
- this.etype_to = wdgnode.getAttribute('cubicweb:etype_to');
- this.etype_from = wdgnode.getAttribute('cubicweb:etype_from');
- var d = asyncRemoteExec('add_and_link_new_entity', this.etype_to, this.rel, this.eid_to, this.etype_from, 'new_val');
- d.addCallback(function (eid) {
- jQuery(wdgnode).find("option[selected]").removeAttr("selected");
- var new_option = OPTION({'value':eid, 'selected':'selected'}, value=new_val);
- wdgnode.appendChild(new_option);
- });
- d.addErrback(function (xxx) {
- log('xxx =', xxx);
- });
- });
- }
-});
-
CubicWeb.provide('widgets.js');
--- a/web/data/external_resources Mon May 10 15:20:54 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +0,0 @@
-# -*- shell-script -*-
-###############################################################################
-#
-# external resources file for core library resources
-#
-# Commented values are default values used by the application.
-#
-###############################################################################
-
-
-# CSS stylesheets to include in HTML headers
-#STYLESHEETS = DATADIR/cubicweb.css
-
-# CSS stylesheets for print
-#STYLESHEETS_PRINT = DATADIR/cubicweb.print.css
-
-#CSS stylesheets for IE
-#IE_STYLESHEETS = DATADIR/cubicweb.ie.css
-
-# Javascripts files to include in HTML headers
-#JAVASCRIPTS = DATADIR/jquery.js, DATADIR/cubicweb.python.js, DATADIR/jquery.json.js, DATADIR/cubicweb.compat.js, DATADIR/cubicweb.htmlhelpers.js
-
-# path to favicon (relative to the application main script, seen as a
-# directory, hence .. when you are not using an absolute path)
-#FAVICON = DATADIR/favicon.ico
-
-# path to the logo (relative to the application main script, seen as a
-# directory, hence .. when you are not using an absolute path)
-LOGO = DATADIR/logo.png
-
-# rss logo (link to get the rss view of a selection)
-RSS_LOGO = DATADIR/rss.png
-RSS_LOGO_16 = DATADIR/feed-icon16x16.png
-RSS_LOGO_32 = DATADIR/feed-icon32x32.png
-
-# path to search image
-SEARCH_GO = DATADIR/go.png
-
-#FCKEDITOR_PATH = /usr/share/fckeditor/
-
-PUCE_UP = DATADIR/puce_up.png
-PUCE_DOWN = DATADIR/puce_down.png
-
-# icons for entity types
-BOOKMARK_ICON = DATADIR/icon_bookmark.gif
-EMAILADDRESS_ICON = DATADIR/icon_emailaddress.gif
-EUSER_ICON = DATADIR/icon_euser.gif
-STATE_ICON = DATADIR/icon_state.gif
-
-# other icons
-CALENDAR_ICON = DATADIR/calendar.gif
-CANCEL_EMAIL_ICON = DATADIR/sendcancel.png
-SEND_EMAIL_ICON = DATADIR/sendok.png
-DOWNLOAD_ICON = DATADIR/download.gif
-UPLOAD_ICON = DATADIR/upload.gif
-GMARKER_ICON = DATADIR/gmap_blue_marker.png
-UP_ICON = DATADIR/up.gif
-
-OK_ICON = DATADIR/ok.png
-CANCEL_ICON = DATADIR/cancel.png
-APPLY_ICON = DATADIR/plus.png
-TRASH_ICON = DATADIR/trash_can_small.png
Binary file web/data/logo.png has changed
Binary file web/data/rhythm15.png has changed
Binary file web/data/rhythm18.png has changed
Binary file web/data/rhythm20.png has changed
Binary file web/data/rhythm22.png has changed
Binary file web/data/rhythm24.png has changed
Binary file web/data/rhythm26.png has changed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/data/uiprops.py Mon May 10 16:59:32 2010 +0200
@@ -0,0 +1,111 @@
+"""define default ui properties"""
+
+# CSS stylesheets to include systematically in HTML headers
+# use the following line if you *need* to keep the old stylesheet
+#STYLESHEETS = [data('cubicweb.old.css')]
+STYLESHEETS = [data('cubicweb.reset.css'),
+ data('cubicweb.css')]
+STYLESHEETS_IE = [data('cubicweb.ie.css')]
+STYLESHEETS_PRINT = [data('cubicweb.print.css')]
+
+# Javascripts files to include systematically in HTML headers
+JAVASCRIPTS = [data('jquery.js'),
+ data('jquery.corner.js'),
+ data('jquery.json.js'),
+ data('cubicweb.compat.js'),
+ data('cubicweb.python.js'),
+ data('cubicweb.htmlhelpers.js')]
+
+# where is installed fckeditor
+FCKEDITOR_PATH = '/usr/share/fckeditor/'
+
+# favicon and logo for the instance
+FAVICON = data('favicon.ico')
+LOGO = data('logo.png')
+
+# rss logo (link to get the rss view of a selection)
+RSS_LOGO = data('rss.png')
+RSS_LOGO_16 = data('feed-icon16x16.png')
+RSS_LOGO_32 = data('feed-icon32x32.png')
+
+# XXX cleanup resources below, some of them are probably not used
+# (at least entity types icons...)
+
+# images
+HELP = data('help.png')
+SEARCH_GO = data('go.png')
+PUCE_UP = data('puce_up.png')
+PUCE_DOWN = data('puce_down.png')
+
+# button icons
+OK_ICON = data('ok.png')
+CANCEL_ICON = data('cancel.png')
+APPLY_ICON = data('plus.png')
+TRASH_ICON = data('trash_can_small.png')
+
+# icons for entity types
+BOOKMARK_ICON = data('icon_bookmark.gif')
+EMAILADDRESS_ICON = data('icon_emailaddress.gif')
+EUSER_ICON = data('icon_euser.gif')
+STATE_ICON = data('icon_state.gif')
+
+# other icons
+CALENDAR_ICON = data('calendar.gif')
+CANCEL_EMAIL_ICON = data('sendcancel.png')
+SEND_EMAIL_ICON = data('sendok.png')
+DOWNLOAD_ICON = data('download.gif')
+UPLOAD_ICON = data('upload.gif')
+GMARKER_ICON = data('gmap_blue_marker.png')
+UP_ICON = data('up.gif')
+
+# colors, fonts, etc
+
+# default (body, html)
+defaultColor = '#000'
+defaultFont = 'Verdana,sans-serif'
+defaultSize = '12px'
+defaultLineHeight = '1.5'
+defaultLineHeightEm = defaultLineHeight + 'em'
+baseRhythmBg = 'rhythm18.png'
+
+# XXX
+defaultLayoutMargin = '8px'
+
+# header
+headerBgColor = '#ff7700'
+
+# h
+h1FontSize = '1.5em'
+h1BorderBottomStyle = '0.06em solid black'
+h1Padding = '0 0 0.14em 0 '
+h1Margin = '0.8em 0 0.5em'
+
+h2FontSize = '1.33333em'
+h2Padding = '0.4em 0 0.35em 0'
+h2Margin = '0'
+
+h3FontSize = '1.16667em'
+h3Padding = '0.5em 0 0.57em 0'
+h3Margin = '0'
+
+# links
+aColor = '#ff4500'
+aActiveColor = aVisitedColor = aLinkColor = aColor
+
+# page frame
+pageContentBorderColor = '#ccc'
+pageContentBgColor = '#fff'
+pageContentPadding = '1em'
+pageMinHeight = '800px'
+
+# button
+buttonBorderColor = '#edecd2'
+buttonBgColor = '#fffff8'
+
+# action, search, sideBoxes
+actionBoxTitleBgColor = '#cfceb7'
+sideBoxBodyBgColor = '#eeedd9'
+
+
+# table listing
+listingBorderColor = '#878787'
--- a/web/formwidgets.py Mon May 10 15:20:54 2010 +0200
+++ b/web/formwidgets.py Mon May 10 16:59:32 2010 +0200
@@ -60,7 +60,6 @@
.. autoclass:: cubicweb.web.formwidgets.AjaxWidget
.. autoclass:: cubicweb.web.formwidgets.AutoCompletionWidget
-.. kill or document AddComboBoxWidget
.. kill or document StaticFileAutoCompletionWidget
.. kill or document LazyRestrictedAutoCompletionWidget
.. kill or document RestrictedAutoCompletionWidget
@@ -550,7 +549,7 @@
return (u"""<a onclick="toggleCalendar('%s', '%s', %s, %s);" class="calhelper">
<img src="%s" title="%s" alt="" /></a><div class="calpopup hidden" id="%s"></div>"""
% (helperid, inputid, year, month,
- form._cw.external_resource('CALENDAR_ICON'),
+ form._cw.uiprops['CALENDAR_ICON'],
form._cw._('calendar'), helperid) )
@@ -574,7 +573,7 @@
req.add_onload(u'jqNode("%s").datepicker('
'{buttonImage: "%s", dateFormat: "%s", firstDay: 1,'
' showOn: "button", buttonImageOnly: true})' % (
- domid, req.external_resource('CALENDAR_ICON'), fmt))
+ domid, req.uiprops['CALENDAR_ICON'], fmt))
if self.datestr is None:
value = self.values(form, field)[0]
else:
@@ -776,24 +775,6 @@
return entity.view('combobox')
-class AddComboBoxWidget(Select):
- def attributes(self, form, field):
- attrs = super(AddComboBoxWidget, self).attributes(form, field)
- init_ajax_attributes(attrs, 'AddComboBox')
- # XXX entity form specific
- entity = form.edited_entity
- attrs['cubicweb:etype_to'] = entity.e_schema
- etype_from = entity.e_schema.subjrels[field.name].objects(entity.e_schema)[0]
- attrs['cubicweb:etype_from'] = etype_from
- return attrs
-
- def _render(self, form, field, renderer):
- return super(AddComboBoxWidget, self)._render(form, field, renderer) + u'''
-<div id="newvalue">
- <input type="text" id="newopt" />
- <a href="javascript:noop()" id="add_newopt"> </a></div>
-'''
-
# more widgets #################################################################
class IntervalWidget(FieldWidget):
@@ -954,7 +935,7 @@
if self.settabindex and not 'tabindex' in attrs:
attrs['tabindex'] = form._cw.next_tabindex()
if self.icon:
- img = tags.img(src=form._cw.external_resource(self.icon), alt=self.icon)
+ img = tags.img(src=form._cw.uiprops[self.icon], alt=self.icon)
else:
img = u''
return tags.button(img + xml_escape(label), escapecontent=False,
@@ -985,7 +966,7 @@
def render(self, form, field=None, renderer=None):
label = form._cw._(self.label)
- imgsrc = form._cw.external_resource(self.imgressource)
+ imgsrc = form._cw.uiprops[self.imgressource]
return '<a id="%(domid)s" href="%(href)s">'\
'<img src="%(imgsrc)s" alt="%(label)s"/>%(label)s</a>' % {
'label': label, 'imgsrc': imgsrc,
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/propertysheet.py Mon May 10 16:59:32 2010 +0200
@@ -0,0 +1,100 @@
+# copyright 2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
+#
+# This file is part of CubicWeb.
+#
+# CubicWeb is free software: you can redistribute it and/or modify it under the
+# terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation, either version 2.1 of the License, or (at your option)
+# any later version.
+#
+# CubicWeb is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
+"""property sheets allowing configuration of the web ui"""
+
+__docformat__ = "restructuredtext en"
+
+import re
+import os
+import os.path as osp
+
+
+class PropertySheet(dict):
+ def __init__(self, cache_directory, **context):
+ self._cache_directory = cache_directory
+ self.context = context
+ self.reset()
+ context['sheet'] = self
+ self._percent_rgx = re.compile('%(?!\()')
+
+ def reset(self):
+ self.clear()
+ self._ordered_propfiles = []
+ self._propfile_mtime = {}
+ self._sourcefile_mtime = {}
+ self._cache = {}
+
+ def load(self, fpath):
+ scriptglobals = self.context.copy()
+ scriptglobals['__file__'] = fpath
+ execfile(fpath, scriptglobals, self)
+ self._propfile_mtime[fpath] = os.stat(fpath)[-2]
+ self._ordered_propfiles.append(fpath)
+
+ def need_reload(self):
+ for rid, (adirectory, rdirectory, mtime) in self._cache.items():
+ if os.stat(osp.join(rdirectory, rid))[-2] > mtime:
+ del self._cache[rid]
+ for fpath, mtime in self._propfile_mtime.iteritems():
+ if os.stat(fpath)[-2] > mtime:
+ return True
+ return False
+
+ def reload(self):
+ ordered_files = self._ordered_propfiles
+ self.reset()
+ for fpath in ordered_files:
+ self.load(fpath)
+
+ def reload_if_needed(self):
+ if self.need_reload():
+ self.reload()
+
+ def process_resource(self, rdirectory, rid):
+ try:
+ return self._cache[rid][0]
+ except KeyError:
+ cachefile = osp.join(self._cache_directory, rid)
+ self.debug('caching processed %s/%s into %s',
+ rdirectory, rid, cachefile)
+ rcachedir = osp.dirname(cachefile)
+ if not osp.exists(rcachedir):
+ os.makedirs(rcachedir)
+ sourcefile = osp.join(rdirectory, rid)
+ content = file(sourcefile).read()
+ # XXX replace % not followed by a paren by %% to avoid having to do
+ # this in the source css file ?
+ try:
+ content = self.compile(content)
+ except ValueError, ex:
+ self.error("can't process %s/%s: %s", rdirectory, rid, ex)
+ adirectory = rdirectory
+ else:
+ stream = file(cachefile, 'w')
+ stream.write(content)
+ stream.close()
+ adirectory = self._cache_directory
+ self._cache[rid] = (adirectory, rdirectory, os.stat(sourcefile)[-2])
+ return adirectory
+
+ def compile(self, content):
+ return self._percent_rgx.sub('%%', content) % self
+
+from cubicweb.web import LOGGER
+from logilab.common.logging_ext import set_log_methods
+set_log_methods(PropertySheet, LOGGER)
--- a/web/request.py Mon May 10 15:20:54 2010 +0200
+++ b/web/request.py Mon May 10 16:59:32 2010 +0200
@@ -83,6 +83,12 @@
super(CubicWebRequestBase, self).__init__(vreg)
self.authmode = vreg.config['auth-mode']
self.https = https
+ if https:
+ self.uiprops = vreg.config.https_uiprops
+ self.datadir_url = vreg.config.https_datadir_url
+ else:
+ self.uiprops = vreg.config.uiprops
+ self.datadir_url = vreg.config.datadir_url
# raw html headers that can be added from any view
self.html_headers = HTMLHead()
# form parameters
@@ -99,7 +105,6 @@
self.next_tabindex = self.tabindexgen.next
# page id, set by htmlheader template
self.pageid = None
- self.datadir_url = self._datadir_url()
self._set_pageid()
# prepare output header
self.headers_out = Headers()
@@ -589,10 +594,6 @@
"""return currently accessed url"""
return self.base_url() + self.relative_path(includeparams)
- def _datadir_url(self):
- """return url of the instance's data directory"""
- return self.base_url() + 'data%s/' % self.vreg.config.instance_md5_version()
-
def selected(self, url):
"""return True if the url is equivalent to currently accessed url"""
reqpath = self.relative_path().lower()
@@ -618,25 +619,6 @@
return controller
return 'view'
- def external_resource(self, rid, default=_MARKER):
- """return a path to an external resource, using its identifier
-
- raise KeyError if the resource is not defined
- """
- try:
- value = self.vreg.config.ext_resources[rid]
- except KeyError:
- if default is _MARKER:
- raise
- return default
- if value is None:
- return None
- baseurl = self.datadir_url[:-1] # remove trailing /
- if isinstance(value, list):
- return [v.replace('DATADIR', baseurl) for v in value]
- return value.replace('DATADIR', baseurl)
- external_resource = cached(external_resource, keyarg=1)
-
def validate_cache(self):
"""raise a `DirectResponse` exception if a cached page along the way
exists and is still usable.
@@ -712,12 +694,6 @@
auth, ex.__class__.__name__, ex)
return None, None
- @deprecated("[3.4] use parse_accept_header('Accept-Language')")
- def header_accept_language(self):
- """returns an ordered list of preferred languages"""
- return [value.split('-')[0] for value in
- self.parse_accept_header('Accept-Language')]
-
def parse_accept_header(self, header):
"""returns an ordered list of preferred languages"""
accepteds = self.get_header(header, '')
@@ -823,5 +799,25 @@
u'<div xmlns="http://www.w3.org/1999/xhtml" xmlns:cubicweb="http://www.logilab.org/2008/cubicweb">')
return u'<div>'
+ @deprecated('[3.9] use req.uiprops[rid]')
+ def external_resource(self, rid, default=_MARKER):
+ """return a path to an external resource, using its identifier
+
+ raise `KeyError` if the resource is not defined
+ """
+ try:
+ return self.uiprops[rid]
+ except KeyError:
+ if default is _MARKER:
+ raise
+ return default
+
+ @deprecated("[3.4] use parse_accept_header('Accept-Language')")
+ def header_accept_language(self):
+ """returns an ordered list of preferred languages"""
+ return [value.split('-')[0] for value in
+ self.parse_accept_header('Accept-Language')]
+
+
from cubicweb import set_log_methods
set_log_methods(CubicWebRequestBase, LOGGER)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/test/data/pouet.css Mon May 10 16:59:32 2010 +0200
@@ -0,0 +1,3 @@
+body { background-color: %(bgcolor)s
+ font-size: 100%;
+ }
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/test/data/sheet1.py Mon May 10 16:59:32 2010 +0200
@@ -0,0 +1,3 @@
+bgcolor = '#000000'
+stylesheets = ['%s/cubicweb.css' % datadir_url]
+logo = '%s/logo.png' % datadir_url
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/test/data/sheet2.py Mon May 10 16:59:32 2010 +0200
@@ -0,0 +1,3 @@
+fontcolor = 'black'
+bgcolor = '#FFFFFF'
+stylesheets = sheet['stylesheets'] + ['%s/mycube.css' % datadir_url]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/test/unittest_propertysheet.py Mon May 10 16:59:32 2010 +0200
@@ -0,0 +1,49 @@
+import os
+from os.path import join, dirname
+from shutil import rmtree
+
+from logilab.common.testlib import TestCase, unittest_main
+
+from cubicweb.web.propertysheet import *
+
+DATADIR = join(dirname(__file__), 'data')
+CACHEDIR = join(DATADIR, 'uicache')
+
+class PropertySheetTC(TestCase):
+
+ def tearDown(self):
+ rmtree(CACHEDIR)
+
+ def test(self):
+ ps = PropertySheet(CACHEDIR, datadir_url='http://cwtest.com')
+ ps.load(join(DATADIR, 'sheet1.py'))
+ ps.load(join(DATADIR, 'sheet2.py'))
+ # defined by sheet1
+ self.assertEquals(ps['logo'], 'http://cwtest.com/logo.png')
+ # defined by sheet1, overriden by sheet2
+ self.assertEquals(ps['bgcolor'], '#FFFFFF')
+ # defined by sheet2
+ self.assertEquals(ps['fontcolor'], 'black')
+ # defined by sheet1, extended by sheet2
+ self.assertEquals(ps['stylesheets'], ['http://cwtest.com/cubicweb.css',
+ 'http://cwtest.com/mycube.css'])
+ self.assertEquals(ps.compile('a {bgcolor: %(bgcolor)s; size: 1%;}'),
+ 'a {bgcolor: #FFFFFF; size: 1%;}')
+ self.assertEquals(ps.process_resource(DATADIR, 'pouet.css'),
+ CACHEDIR)
+ self.failUnless('pouet.css' in ps._cache)
+ self.failIf(ps.need_reload())
+ os.utime(join(DATADIR, 'sheet1.py'), None)
+ self.failUnless('pouet.css' in ps._cache)
+ self.failUnless(ps.need_reload())
+ self.failUnless('pouet.css' in ps._cache)
+ ps.reload()
+ self.failIf('pouet.css' in ps._cache)
+ self.failIf(ps.need_reload())
+ ps.process_resource(DATADIR, 'pouet.css') # put in cache
+ os.utime(join(DATADIR, 'pouet.css'), None)
+ self.failIf(ps.need_reload())
+ self.failIf('pouet.css' in ps._cache)
+
+if __name__ == '__main__':
+ unittest_main()
--- a/web/test/unittest_views_basecontrollers.py Mon May 10 15:20:54 2010 +0200
+++ b/web/test/unittest_views_basecontrollers.py Mon May 10 16:59:32 2010 +0200
@@ -643,7 +643,7 @@
# silly tests
def test_external_resource(self):
self.assertEquals(self.remote_call('external_resource', 'RSS_LOGO')[0],
- json.dumps(self.request().external_resource('RSS_LOGO')))
+ json.dumps(self.config.uiprops['RSS_LOGO']))
def test_i18n(self):
self.assertEquals(self.remote_call('i18n', ['bimboom'])[0],
json.dumps(['bimboom']))
--- a/web/test/unittest_webconfig.py Mon May 10 15:20:54 2010 +0200
+++ b/web/test/unittest_webconfig.py Mon May 10 16:59:32 2010 +0200
@@ -33,15 +33,14 @@
def test_nonregr_print_css_as_list(self):
"""make sure PRINT_CSS *must* is a list"""
config = self.config
- req = fake.FakeRequest()
- print_css = req.external_resource('STYLESHEETS_PRINT')
+ print_css = config.uiprops['STYLESHEETS_PRINT']
self.failUnless(isinstance(print_css, list))
- ie_css = req.external_resource('IE_STYLESHEETS')
+ ie_css = config.uiprops['STYLESHEETS_IE']
self.failUnless(isinstance(ie_css, list))
def test_locate_resource(self):
- self.failUnless('FILE_ICON' in self.config.ext_resources)
- rname = self.config.ext_resources['FILE_ICON'].replace('DATADIR/', '')
+ self.failUnless('FILE_ICON' in self.config.uiprops)
+ rname = self.config.uiprops['FILE_ICON'].replace(self.config.datadir_url, '')
self.failUnless('file' in self.config.locate_resource(rname).split(os.sep))
cubicwebcsspath = self.config.locate_resource('cubicweb.css').split(os.sep)
self.failUnless('web' in cubicwebcsspath or 'shared' in cubicwebcsspath) # 'shared' if tests under apycot
--- a/web/views/actions.py Mon May 10 15:20:54 2010 +0200
+++ b/web/views/actions.py Mon May 10 16:59:32 2010 +0200
@@ -15,21 +15,22 @@
#
# You should have received a copy of the GNU Lesser General Public License along
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
-"""Set of HTML base actions
+"""Set of HTML base actions"""
-"""
__docformat__ = "restructuredtext en"
_ = unicode
from warnings import warn
+from logilab.mtconverter import xml_escape
+
from cubicweb.schema import display_name
from cubicweb.appobject import objectify_selector
from cubicweb.selectors import (EntitySelector, yes,
one_line_rset, multi_lines_rset, one_etype_rset, relation_possible,
nonempty_rset, non_final_entity,
authenticated_user, match_user_groups, match_search_state,
- has_permission, has_add_permission, implements,
+ has_permission, has_add_permission, implements, debug_mode,
)
from cubicweb.web import uicfg, controller, action
from cubicweb.web.views import linksearch_select_url, vid_from_rset
@@ -412,6 +413,20 @@
def url(self):
return 'http://www.cubicweb.org'
+class GotRhythmAction(action.Action):
+ __regid__ = 'rhythm'
+ __select__ = debug_mode()
+
+ category = 'footer'
+ order = 3
+ title = _('Got rhythm?')
+
+ def url(self):
+ return xml_escape(self._cw.url()+'#')
+
+ def html_class(self):
+ self._cw.add_js('cubicweb.rhythm.js')
+ return 'rhythm'
## default actions ui configuration ###########################################
--- a/web/views/basecomponents.py Mon May 10 15:20:54 2010 +0200
+++ b/web/views/basecomponents.py Mon May 10 16:59:32 2010 +0200
@@ -78,8 +78,8 @@
site_wide = True
def call(self):
- self.w(u'<a href="%s"><img class="logo" src="%s" alt="logo"/></a>'
- % (self._cw.base_url(), self._cw.external_resource('LOGO')))
+ self.w(u'<a href="%s"><img id="logo" src="%s" alt="logo"/></a>'
+ % (self._cw.base_url(), self._cw.uiprops['LOGO']))
class ApplHelp(component.Component):
--- a/web/views/basecontrollers.py Mon May 10 15:20:54 2010 +0200
+++ b/web/views/basecontrollers.py Mon May 10 16:59:32 2010 +0200
@@ -340,12 +340,11 @@
return None
return None
- def _call_view(self, view, **kwargs):
- req = self._cw
- divid = req.form.get('divid', 'pageContent')
+ def _call_view(self, view, paginate=False, **kwargs):
+ divid = self._cw.form.get('divid', 'pageContent')
# we need to call pagination before with the stream set
stream = view.set_stream()
- if req.form.get('paginate'):
+ if paginate:
if divid == 'pageContent':
# mimick main template behaviour
stream.write(u'<div id="pageContent">')
@@ -356,12 +355,12 @@
if divid == 'pageContent':
stream.write(u'<div id="contentmain">')
view.render(**kwargs)
- extresources = req.html_headers.getvalue(skiphead=True)
+ extresources = self._cw.html_headers.getvalue(skiphead=True)
if extresources:
stream.write(u'<div class="ajaxHtmlHead">\n') # XXX use a widget ?
stream.write(extresources)
stream.write(u'</div>\n')
- if req.form.get('paginate') and divid == 'pageContent':
+ if paginate and divid == 'pageContent':
stream.write(u'</div></div>')
return stream.getvalue()
@@ -381,7 +380,7 @@
vid = req.form.get('fallbackvid', 'noresult')
view = self._cw.vreg['views'].select(vid, req, rset=rset)
self.validate_cache(view)
- return self._call_view(view)
+ return self._call_view(view, paginate=req.form.get('paginate'))
@xhtmlize
def js_prop_widget(self, propkey, varname, tabindex=None):
@@ -419,16 +418,7 @@
**extraargs)
#except NoSelectableObject:
# raise RemoteCallFailed('unselectable')
- extraargs = extraargs or {}
- stream = comp.set_stream()
- comp.render(**extraargs)
- # XXX why not _call_view ?
- extresources = self._cw.html_headers.getvalue(skiphead=True)
- if extresources:
- stream.write(u'<div class="ajaxHtmlHead">\n')
- stream.write(extresources)
- stream.write(u'</div>\n')
- return stream.getvalue()
+ return self._call_view(comp, **extraargs)
@check_pageid
@xhtmlize
@@ -457,15 +447,7 @@
args['reload'] = json.loads(args['reload'])
rset = req.eid_rset(int(self._cw.form['eid']))
view = req.vreg['views'].select('doreledit', req, rset=rset, rtype=args['rtype'])
- stream = view.set_stream()
- view.render(**args)
- # XXX why not _call_view ?
- extresources = req.html_headers.getvalue(skiphead=True)
- if extresources:
- stream.write(u'<div class="ajaxHtmlHead">\n')
- stream.write(extresources)
- stream.write(u'</div>\n')
- return stream.getvalue()
+ return self._call_view(view, **args)
@jsonize
def js_i18n(self, msgids):
@@ -481,7 +463,7 @@
@jsonize
def js_external_resource(self, resource):
"""returns the URL of the external resource named `resource`"""
- return self._cw.external_resource(resource)
+ return self._cw.uiprops[resource]
@check_pageid
@jsonize
@@ -581,14 +563,6 @@
def js_add_pending_delete(self, (eidfrom, rel, eidto)):
self._add_pending(eidfrom, rel, eidto, 'delete')
- # XXX specific code. Kill me and my AddComboBox friend
- @jsonize
- def js_add_and_link_new_entity(self, etype_to, rel, eid_to, etype_from, value_from):
- # create a new entity
- eid_from = self._cw.execute('INSERT %s T : T name "%s"' % ( etype_from, value_from ))[0][0]
- # link the new entity to the main entity
- rql = 'SET F %(rel)s T WHERE F eid %(eid_to)s, T eid %(eid_from)s' % {'rel' : rel, 'eid_to' : eid_to, 'eid_from' : eid_from}
- return eid_from
# XXX move to massmailing
class SendMailController(Controller):
--- a/web/views/basetemplates.py Mon May 10 15:20:54 2010 +0200
+++ b/web/views/basetemplates.py Mon May 10 16:59:32 2010 +0200
@@ -168,7 +168,7 @@
self.wview('header', rset=self.cw_rset, view=view)
w(u'<div id="page"><table width="100%" border="0" id="mainLayout"><tr>\n')
self.nav_column(view, 'left')
- w(u'<td id="contentcol">\n')
+ w(u'<td id="contentColumn">\n')
components = self._cw.vreg['components']
rqlcomp = components.select_or_none('rqlinput', self._cw, rset=self.cw_rset)
if rqlcomp:
@@ -190,7 +190,7 @@
boxes = list(self._cw.vreg['boxes'].poss_visible_objects(
self._cw, rset=self.cw_rset, view=view, context=context))
if boxes:
- self.w(u'<td class="navcol"><div class="navboxes">\n')
+ self.w(u'<td id="navColumn%s"><div class="navboxes">\n' % context.capitalize())
for box in boxes:
box.render(w=self.w, view=view)
self.w(u'</div></td>\n')
@@ -254,7 +254,7 @@
w(u'<body>\n')
w(u'<div id="page">')
w(u'<table width="100%" height="100%" border="0"><tr>\n')
- w(u'<td class="navcol">\n')
+ w(u'<td id="navColumnLeft">\n')
self.topleft_header()
boxes = list(self._cw.vreg['boxes'].poss_visible_objects(
self._cw, rset=self.cw_rset, view=view, context='left'))
@@ -294,22 +294,22 @@
self.alternates()
def favicon(self):
- favicon = self._cw.external_resource('FAVICON', None)
+ favicon = self._cw.uiprops.get('FAVICON', None)
if favicon:
self.whead(u'<link rel="shortcut icon" href="%s"/>\n' % favicon)
def stylesheets(self):
req = self._cw
add_css = req.add_css
- for css in req.external_resource('STYLESHEETS'):
+ for css in req.uiprops['STYLESHEETS']:
add_css(css, localfile=False)
- for css in req.external_resource('STYLESHEETS_PRINT'):
+ for css in req.uiprops['STYLESHEETS_PRINT']:
add_css(css, u'print', localfile=False)
- for css in req.external_resource('IE_STYLESHEETS'):
+ for css in req.uiprops['STYLESHEETS_IE']:
add_css(css, localfile=False, ieonly=True)
def javascripts(self):
- for jscript in self._cw.external_resource('JAVASCRIPTS'):
+ for jscript in self._cw.uiprops['JAVASCRIPTS']:
self._cw.add_js(jscript, localfile=False)
def alternates(self):
@@ -389,13 +389,15 @@
def call(self, **kwargs):
req = self._cw
- self.w(u'<div class="footer">')
+ self.w(u'<div id="footer">')
actions = self._cw.vreg['actions'].possible_actions(self._cw,
rset=self.cw_rset)
footeractions = actions.get('footer', ())
for i, action in enumerate(footeractions):
- self.w(u'<a href="%s">%s</a>' % (action.url(),
- self._cw._(action.title)))
+ self.w(u'<a href="%s"' % action.url())
+ if getattr(action, 'html_class'):
+ self.w(u' class="%s"' % action.html_class())
+ self.w(u'>%s</a>' % self._cw._(action.title))
if i < (len(footeractions) - 1):
self.w(u' | ')
self.w(u'</div>')
@@ -468,7 +470,7 @@
self.w(u'<div id="loginTitle">%s</div>' % stitle)
self.w(u'<div id="loginContent">\n')
if showmessage and self._cw.message:
- self.w(u'<div class="simpleMessage">%s</div>\n' % self._cw.message)
+ self.w(u'<div class="loginMessage">%s</div>\n' % self._cw.message)
if self._cw.vreg.config['auth-mode'] != 'http':
# Cookie authentication
self.login_form(id)
--- a/web/views/idownloadable.py Mon May 10 15:20:54 2010 +0200
+++ b/web/views/idownloadable.py Mon May 10 16:59:32 2010 +0200
@@ -48,7 +48,7 @@
w(u'<div class="sideBox downloadBox"><div class="sideBoxBody">')
w(u'<a href="%s"><img src="%s" alt="%s"/> %s</a>'
% (xml_escape(entity.download_url()),
- req.external_resource('DOWNLOAD_ICON'),
+ req.uiprops['DOWNLOAD_ICON'],
_('download icon'), xml_escape(label or entity.dc_title())))
w(u'%s</div>' % footer)
w(u'</div></div>\n')
--- a/web/views/igeocodable.py Mon May 10 15:20:54 2010 +0200
+++ b/web/views/igeocodable.py Mon May 10 16:59:32 2010 +0200
@@ -59,7 +59,7 @@
if hasattr(entity, 'marker_icon'):
icon = entity.marker_icon()
else:
- icon = (self._cw.external_resource('GMARKER_ICON'), (20, 34), (4, 34), None)
+ icon = (self._cw.uiprops['GMARKER_ICON'], (20, 34), (4, 34), None)
return {'latitude': entity.latitude, 'longitude': entity.longitude,
'title': entity.dc_long_title(),
#icon defines : (icon._url, icon.size, icon.iconAncho', icon.shadow)
--- a/web/views/management.py Mon May 10 15:20:54 2010 +0200
+++ b/web/views/management.py Mon May 10 16:59:32 2010 +0200
@@ -205,7 +205,7 @@
cversions = []
for cube in self._cw.vreg.config.cubes():
cubeversion = vcconf.get(cube, self._cw._('no version information'))
- w(u"<b>Package %s version:</b> %s<br/>\n" % (cube, cubeversion))
+ w(u"<b>Cube %s version:</b> %s<br/>\n" % (cube, cubeversion))
cversions.append((cube, cubeversion))
w(u"</div>")
# creates a bug submission link if submit-mail is set
@@ -239,7 +239,7 @@
binfo += u'\n'.join(u' * %s = %s' % (k, v) for k, v in req.form.iteritems())
binfo += u'\n\n:CubicWeb version: %s\n' % (eversion,)
for pkg, pkgversion in cubes:
- binfo += u":Package %s version: %s\n" % (pkg, pkgversion)
+ binfo += u":Cube %s version: %s\n" % (pkg, pkgversion)
binfo += '\n'
return binfo
--- a/web/views/schema.py Mon May 10 15:20:54 2010 +0200
+++ b/web/views/schema.py Mon May 10 16:59:32 2010 +0200
@@ -248,7 +248,7 @@
eschema.type, self._cw.build_url('cwetype/%s' % eschema.type),
eschema.type, _(eschema.type)))
self.w(u'<a href="%s#schema_security"><img src="%s" alt="%s"/></a>' % (
- url, self._cw.external_resource('UP_ICON'), _('up')))
+ url, self._cw.uiprops['UP_ICON'], _('up')))
self.w(u'</h3>')
self.w(u'<div style="margin: 0px 1.5em">')
self.permissions_table(eschema)
@@ -277,7 +277,7 @@
rschema.type, self._cw.build_url('cwrtype/%s' % rschema.type),
rschema.type, _(rschema.type)))
self.w(u'<a href="%s#schema_security"><img src="%s" alt="%s"/></a>' % (
- url, self._cw.external_resource('UP_ICON'), _('up')))
+ url, self._cw.uiprops['UP_ICON'], _('up')))
self.w(u'</h3>')
self.grouped_permissions_table(rschema)
--- a/web/views/startup.py Mon May 10 15:20:54 2010 +0200
+++ b/web/views/startup.py Mon May 10 16:59:32 2010 +0200
@@ -42,7 +42,7 @@
def call(self, **kwargs):
"""The default view representing the instance's management"""
self._cw.add_css('cubicweb.manageview.css')
- self.w(u'<div>\n')
+ self.w(u'<h1>%s</h1>' % self._cw.property_value('ui.site-title'))
if not self.display_folders():
self._main_index()
else:
@@ -53,7 +53,6 @@
self.folders()
self.w(u'</td>')
self.w(u'</tr></table>\n')
- self.w(u'</div>\n')
def _main_index(self):
req = self._cw
@@ -79,7 +78,7 @@
self.w(u'<br/><a href="%s">%s</a>\n' % (xml_escape(href), label))
def folders(self):
- self.w(u'<h4>%s</h4>\n' % self._cw._('Browse by category'))
+ self.w(u'<h2>%s</h2>\n' % self._cw._('Browse by category'))
self._cw.vreg['views'].select('tree', self._cw).render(w=self.w)
def create_links(self):
@@ -93,19 +92,24 @@
self.w(u'</ul>')
def startup_views(self):
- self.w(u'<h4>%s</h4>\n' % self._cw._('Startup views'))
+ self.w(u'<h2>%s</h2>\n' % self._cw._('Startup views'))
self.startupviews_table()
def startupviews_table(self):
- for v in self._cw.vreg['views'].possible_views(self._cw, None):
+ views = self._cw.vreg['views'].possible_views(self._cw, None)
+ if not views:
+ return
+ self.w(u'<ul>')
+ for v in views:
if v.category != 'startupview' or v.__regid__ in ('index', 'tree', 'manage'):
continue
- self.w('<p><a href="%s">%s</a></p>' % (
+ self.w('<li><a href="%s">%s</a></li>' % (
xml_escape(v.url()), xml_escape(self._cw._(v.title).capitalize())))
+ self.w(u'</ul>')
def entities(self):
schema = self._cw.vreg.schema
- self.w(u'<h4>%s</h4>\n' % self._cw._('The repository holds the following entities'))
+ self.w(u'<h2>%s</h2>\n' % self._cw._('Browse by entity type'))
manager = self._cw.user.matching_groups('managers')
self.w(u'<table class="startup">')
if manager:
--- a/web/views/tableview.py Mon May 10 15:20:54 2010 +0200
+++ b/web/views/tableview.py Mon May 10 16:59:32 2010 +0200
@@ -204,7 +204,7 @@
def render_actions(self, divid, actions):
box = MenuWidget('', 'tableActionsBox', _class='', islist=False)
- label = tags.img(src=self._cw.external_resource('PUCE_DOWN'),
+ label = tags.img(src=self._cw.uiprops['PUCE_DOWN'],
alt=xml_escape(self._cw._('action(s) on this selection')))
menu = PopupBoxMenu(label, isitem=False, link_class='actionsBox',
ident='%sActions' % divid)
--- a/web/views/xmlrss.py Mon May 10 15:20:54 2010 +0200
+++ b/web/views/xmlrss.py Mon May 10 16:59:32 2010 +0200
@@ -147,7 +147,7 @@
def call(self, **kwargs):
try:
- rss = self._cw.external_resource('RSS_LOGO')
+ rss = self._cw.uiprops['RSS_LOGO']
except KeyError:
self.error('missing RSS_LOGO external resource')
return
--- a/web/webconfig.py Mon May 10 15:20:54 2010 +0200
+++ b/web/webconfig.py Mon May 10 16:59:32 2010 +0200
@@ -23,8 +23,10 @@
import os
from os.path import join, exists, split
+from warnings import warn
from logilab.common.decorators import cached
+from logilab.common.deprecation import deprecated
from cubicweb.toolsutils import read_config
from cubicweb.cwconfig import CubicWebConfiguration, register_persistent_options, merge_options
@@ -77,6 +79,7 @@
"""
cubicweb_appobject_path = CubicWebConfiguration.cubicweb_appobject_path | set([join('web', 'views')])
cube_appobject_path = CubicWebConfiguration.cube_appobject_path | set(['views'])
+ uiprops = {'FCKEDITOR_PATH': ''}
options = merge_options(CubicWebConfiguration.options + (
('anonymous-user',
@@ -208,7 +211,7 @@
))
def fckeditor_installed(self):
- return exists(self.ext_resources['FCKEDITOR_PATH'])
+ return exists(self.uiprops['FCKEDITOR_PATH'])
def eproperty_definitions(self):
for key, pdef in super(WebConfiguration, self).eproperty_definitions():
@@ -239,30 +242,6 @@
def vc_config(self):
return self.repository().get_versions()
- # mapping to external resources (id -> path) (`external_resources` file) ##
- ext_resources = {
- 'FAVICON': 'DATADIR/favicon.ico',
- 'LOGO': 'DATADIR/logo.png',
- 'RSS_LOGO': 'DATADIR/rss.png',
- 'HELP': 'DATADIR/help.png',
- 'CALENDAR_ICON': 'DATADIR/calendar.gif',
- 'SEARCH_GO':'DATADIR/go.png',
-
- 'FCKEDITOR_PATH': '/usr/share/fckeditor/',
-
- 'IE_STYLESHEETS': ['DATADIR/cubicweb.ie.css'],
- 'STYLESHEETS': ['DATADIR/cubicweb.css'],
- 'STYLESHEETS_PRINT': ['DATADIR/cubicweb.print.css'],
-
- 'JAVASCRIPTS': ['DATADIR/jquery.js',
- 'DATADIR/jquery.corner.js',
- 'DATADIR/jquery.json.js',
- 'DATADIR/cubicweb.compat.js',
- 'DATADIR/cubicweb.python.js',
- 'DATADIR/cubicweb.htmlhelpers.js'],
- }
-
-
def anonymous_user(self):
"""return a login and password to use for anonymous users. None
may be returned for both if anonymous connections are not allowed
@@ -276,26 +255,30 @@
user = unicode(user)
return user, passwd
- def has_resource(self, rid):
- """return true if an external resource is defined"""
- return bool(self.ext_resources.get(rid))
-
- @cached
def locate_resource(self, rid):
"""return the directory where the given resource may be found"""
return self._fs_locate(rid, 'data')
- @cached
def locate_doc_file(self, fname):
"""return the directory where the given resource may be found"""
return self._fs_locate(fname, 'wdoc')
- def _fs_locate(self, rid, rdirectory):
+ @cached
+ def _fs_path_locate(self, rid, rdirectory):
"""return the directory where the given resource may be found"""
path = [self.apphome] + self.cubes_path() + [join(self.shared_dir())]
for directory in path:
if exists(join(directory, rdirectory, rid)):
- return join(directory, rdirectory)
+ return directory
+
+ def _fs_locate(self, rid, rdirectory):
+ """return the directory where the given resource may be found"""
+ directory = self._fs_path_locate(rid, rdirectory)
+ if directory is None:
+ return None
+ if rdirectory == 'data' and rid.endswith('.css'):
+ return self.uiprops.process_resource(join(directory, rdirectory), rid)
+ return join(directory, rdirectory)
def locate_all_files(self, rid, rdirectory='wdoc'):
"""return all files corresponding to the given resource"""
@@ -309,8 +292,8 @@
"""load instance's configuration files"""
super(WebConfiguration, self).load_configuration()
# load external resources definition
- self._build_ext_resources()
self._init_base_url()
+ self._build_ui_properties()
def _init_base_url(self):
# normalize base url(s)
@@ -320,29 +303,62 @@
if not self.repairing:
self.global_set_option('base-url', baseurl)
httpsurl = self['https-url']
- if httpsurl and httpsurl[-1] != '/':
- httpsurl += '/'
- if not self.repairing:
- self.global_set_option('https-url', httpsurl)
+ if httpsurl:
+ if httpsurl[-1] != '/':
+ httpsurl += '/'
+ if not self.repairing:
+ self.global_set_option('https-url', httpsurl)
+ if self.debugmode:
+ self.https_datadir_url = httpsurl + 'data/'
+ else:
+ self.https_datadir_url = httpsurl + 'data%s/' % self.instance_md5_version()
+ if self.debugmode:
+ self.datadir_url = baseurl + 'data/'
+ else:
+ self.datadir_url = baseurl + 'data%s/' % self.instance_md5_version()
- def _build_ext_resources(self):
- libresourcesfile = join(self.shared_dir(), 'data', 'external_resources')
- self.ext_resources.update(read_config(libresourcesfile))
+ def _build_ui_properties(self):
+ # self.datadir_url[:-1] to remove trailing /
+ from cubicweb.web.propertysheet import PropertySheet
+ self.uiprops = PropertySheet(
+ join(self.appdatahome, 'uicache'),
+ data=lambda x: self.datadir_url + x,
+ datadir_url=self.datadir_url[:-1])
+ self._init_uiprops(self.uiprops)
+ if self['https-url']:
+ self.https_uiprops = PropertySheet(
+ join(self.appdatahome, 'uicache'),
+ data=lambda x: self.https_datadir_url + x,
+ datadir_url=self.https_datadir_url[:-1])
+ self._init_uiprops(self.https_uiprops)
+
+ def _init_uiprops(self, uiprops):
+ libuiprops = join(self.shared_dir(), 'data', 'uiprops.py')
+ uiprops.load(libuiprops)
for path in reversed([self.apphome] + self.cubes_path()):
- resourcesfile = join(path, 'data', 'external_resources')
- if exists(resourcesfile):
- self.debug('loading %s', resourcesfile)
- self.ext_resources.update(read_config(resourcesfile))
- resourcesfile = join(self.apphome, 'external_resources')
+ self._load_ui_properties_file(uiprops, path)
+ self._load_ui_properties_file(uiprops, self.apphome)
+
+ def _load_ui_properties_file(self, uiprops, path):
+ resourcesfile = join(path, 'data', 'external_resources')
if exists(resourcesfile):
- self.debug('loading %s', resourcesfile)
- self.ext_resources.update(read_config(resourcesfile))
- for resource in ('STYLESHEETS', 'STYLESHEETS_PRINT',
- 'IE_STYLESHEETS', 'JAVASCRIPTS'):
- val = self.ext_resources[resource]
- if isinstance(val, str):
- files = [w.strip() for w in val.split(',') if w.strip()]
- self.ext_resources[resource] = files
+ warn('[3.9] %s file is deprecated, use an uiprops.py file'
+ % resourcesfile, DeprecationWarning)
+ datadir_url = uiprops.context['datadir_url']
+ for rid, val in read_config(resourcesfile).iteritems():
+ if rid in ('STYLESHEETS', 'STYLESHEETS_PRINT',
+ 'IE_STYLESHEETS', 'JAVASCRIPTS'):
+ val = [w.strip().replace('DATADIR', datadir_url)
+ for w in val.split(',') if w.strip()]
+ if rid == 'IE_STYLESHEETS':
+ rid = 'STYLESHEETS_IE'
+ else:
+ val = val.strip().replace('DATADIR', datadir_url)
+ uiprops[rid] = val
+ uipropsfile = join(path, 'uiprops.py')
+ if exists(uipropsfile):
+ self.debug('loading %s', uipropsfile)
+ uiprops.load(uipropsfile)
# static files handling ###################################################
@@ -369,3 +385,8 @@
def static_file_del(self, rpath):
if self.static_file_exists(rpath):
os.remove(join(self.static_directory, rpath))
+
+ @deprecated('[3.9] use _cw.uiprops.get(rid)')
+ def has_resource(self, rid):
+ """return true if an external resource is defined"""
+ return bool(self.uiprops.get(rid))
--- a/wsgi/handler.py Mon May 10 15:20:54 2010 +0200
+++ b/wsgi/handler.py Mon May 10 16:59:32 2010 +0200
@@ -100,9 +100,8 @@
NOTE: no pyro
"""
- def __init__(self, config, debug=None, vreg=None):
- self.appli = CubicWebPublisher(config, debug=debug, vreg=vreg)
- self.debugmode = debug
+ def __init__(self, config, vreg=None):
+ self.appli = CubicWebPublisher(config, vreg=vreg)
self.config = config
self.base_url = None
# self.base_url = config['base-url'] or config.default_base_url()