# HG changeset patch # User Sylvain Thénault # Date 1274087137 -7200 # Node ID 01a7228ab5a07ff5bea8fafe8d76792946027b32 # Parent c035a0fe75d898476eecb7de70e2b65bbdfc9913# Parent 4fcb0c13209882a7992388d1aa9fcc0c2337e42f backport stable diff -r 4fcb0c132098 -r 01a7228ab5a0 __pkginfo__.py --- a/__pkginfo__.py Mon May 17 11:04:52 2010 +0200 +++ b/__pkginfo__.py Mon May 17 11:05:37 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', diff -r 4fcb0c132098 -r 01a7228ab5a0 cwconfig.py --- a/cwconfig.py Mon May 17 11:04:52 2010 +0200 +++ b/cwconfig.py Mon May 17 11:05:37 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') diff -r 4fcb0c132098 -r 01a7228ab5a0 cwctl.py --- a/cwctl.py Mon May 17 11:04:52 2010 +0200 +++ b/cwctl.py Mon May 17 11:05:37 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. + the identifier of the instance to connect. """ name = 'shell' - arguments = ' [batch command file]' + arguments = ' [batch command file(s)] [-- * - *================================================== + * */ 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"] = [ diff -r 4fcb0c132098 -r 01a7228ab5a0 web/data/cubicweb.widgets.js --- a/web/data/cubicweb.widgets.js Mon May 17 11:04:52 2010 +0200 +++ b/web/data/cubicweb.widgets.js Mon May 17 11:05:37 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'); diff -r 4fcb0c132098 -r 01a7228ab5a0 web/data/external_resources --- a/web/data/external_resources Mon May 17 11:04:52 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 diff -r 4fcb0c132098 -r 01a7228ab5a0 web/data/logo.png Binary file web/data/logo.png has changed diff -r 4fcb0c132098 -r 01a7228ab5a0 web/data/mail.gif Binary file web/data/mail.gif has changed diff -r 4fcb0c132098 -r 01a7228ab5a0 web/data/nomail.gif Binary file web/data/nomail.gif has changed diff -r 4fcb0c132098 -r 01a7228ab5a0 web/data/rhythm15.png Binary file web/data/rhythm15.png has changed diff -r 4fcb0c132098 -r 01a7228ab5a0 web/data/rhythm18.png Binary file web/data/rhythm18.png has changed diff -r 4fcb0c132098 -r 01a7228ab5a0 web/data/rhythm20.png Binary file web/data/rhythm20.png has changed diff -r 4fcb0c132098 -r 01a7228ab5a0 web/data/rhythm22.png Binary file web/data/rhythm22.png has changed diff -r 4fcb0c132098 -r 01a7228ab5a0 web/data/rhythm24.png Binary file web/data/rhythm24.png has changed diff -r 4fcb0c132098 -r 01a7228ab5a0 web/data/rhythm26.png Binary file web/data/rhythm26.png has changed diff -r 4fcb0c132098 -r 01a7228ab5a0 web/data/uiprops.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/data/uiprops.py Mon May 17 11:05:37 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' diff -r 4fcb0c132098 -r 01a7228ab5a0 web/formwidgets.py --- a/web/formwidgets.py Mon May 17 11:04:52 2010 +0200 +++ b/web/formwidgets.py Mon May 17 11:05:37 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""" """ % (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''' -
- -  
-''' - # 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 ''\ '%(label)s%(label)s' % { 'label': label, 'imgsrc': imgsrc, diff -r 4fcb0c132098 -r 01a7228ab5a0 web/propertysheet.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/propertysheet.py Mon May 17 11:05:37 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 . +"""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) diff -r 4fcb0c132098 -r 01a7228ab5a0 web/request.py --- a/web/request.py Mon May 17 11:04:52 2010 +0200 +++ b/web/request.py Mon May 17 11:05:37 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'
') return u'
' + @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) diff -r 4fcb0c132098 -r 01a7228ab5a0 web/test/data/pouet.css --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/test/data/pouet.css Mon May 17 11:05:37 2010 +0200 @@ -0,0 +1,3 @@ +body { background-color: %(bgcolor)s + font-size: 100%; + } \ No newline at end of file diff -r 4fcb0c132098 -r 01a7228ab5a0 web/test/data/sheet1.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/test/data/sheet1.py Mon May 17 11:05:37 2010 +0200 @@ -0,0 +1,3 @@ +bgcolor = '#000000' +stylesheets = ['%s/cubicweb.css' % datadir_url] +logo = '%s/logo.png' % datadir_url diff -r 4fcb0c132098 -r 01a7228ab5a0 web/test/data/sheet2.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/test/data/sheet2.py Mon May 17 11:05:37 2010 +0200 @@ -0,0 +1,3 @@ +fontcolor = 'black' +bgcolor = '#FFFFFF' +stylesheets = sheet['stylesheets'] + ['%s/mycube.css' % datadir_url] diff -r 4fcb0c132098 -r 01a7228ab5a0 web/test/unittest_propertysheet.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/test/unittest_propertysheet.py Mon May 17 11:05:37 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() diff -r 4fcb0c132098 -r 01a7228ab5a0 web/test/unittest_views_basecontrollers.py --- a/web/test/unittest_views_basecontrollers.py Mon May 17 11:04:52 2010 +0200 +++ b/web/test/unittest_views_basecontrollers.py Mon May 17 11:05:37 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'])) diff -r 4fcb0c132098 -r 01a7228ab5a0 web/test/unittest_webconfig.py --- a/web/test/unittest_webconfig.py Mon May 17 11:04:52 2010 +0200 +++ b/web/test/unittest_webconfig.py Mon May 17 11:05:37 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 diff -r 4fcb0c132098 -r 01a7228ab5a0 web/views/actions.py --- a/web/views/actions.py Mon May 17 11:04:52 2010 +0200 +++ b/web/views/actions.py Mon May 17 11:05:37 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 . -"""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 @@ -415,6 +416,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 ########################################### diff -r 4fcb0c132098 -r 01a7228ab5a0 web/views/basecomponents.py --- a/web/views/basecomponents.py Mon May 17 11:04:52 2010 +0200 +++ b/web/views/basecomponents.py Mon May 17 11:05:37 2010 +0200 @@ -78,8 +78,8 @@ site_wide = True def call(self): - self.w(u'' - % (self._cw.base_url(), self._cw.external_resource('LOGO'))) + self.w(u'' + % (self._cw.base_url(), self._cw.uiprops['LOGO'])) class ApplHelp(component.Component): diff -r 4fcb0c132098 -r 01a7228ab5a0 web/views/basecontrollers.py --- a/web/views/basecontrollers.py Mon May 17 11:04:52 2010 +0200 +++ b/web/views/basecontrollers.py Mon May 17 11:05:37 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'
') @@ -356,12 +355,12 @@ if divid == 'pageContent': stream.write(u'
') view.render(**kwargs) - extresources = req.html_headers.getvalue(skiphead=True) + extresources = self._cw.html_headers.getvalue(skiphead=True) if extresources: stream.write(u'
\n') # XXX use a widget ? stream.write(extresources) stream.write(u'
\n') - if req.form.get('paginate') and divid == 'pageContent': + if paginate and divid == 'pageContent': stream.write(u'
') 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'
\n') - stream.write(extresources) - stream.write(u'
\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'
\n') - stream.write(extresources) - stream.write(u'
\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): diff -r 4fcb0c132098 -r 01a7228ab5a0 web/views/basetemplates.py --- a/web/views/basetemplates.py Mon May 17 11:04:52 2010 +0200 +++ b/web/views/basetemplates.py Mon May 17 11:05:37 2010 +0200 @@ -168,7 +168,7 @@ self.wview('header', rset=self.cw_rset, view=view) w(u'
\n') self.nav_column(view, 'left') - w(u'\n') @@ -254,7 +254,7 @@ w(u'\n') w(u'
') w(u'
\n') + w(u'\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'
\n') - w(u'') self.w(u'
\n') - self.w(u'
\n') def _main_index(self): req = self._cw @@ -79,7 +78,7 @@ self.w(u'
%s\n' % (xml_escape(href), label)) def folders(self): - self.w(u'

%s

\n' % self._cw._('Browse by category')) + self.w(u'

%s

\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'') def startup_views(self): - self.w(u'

%s

\n' % self._cw._('Startup views')) + self.w(u'

%s

\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'
    ') + for v in views: if v.category != 'startupview' or v.__regid__ in ('index', 'tree', 'manage'): continue - self.w('

    %s

    ' % ( + self.w('
  • %s
  • ' % ( xml_escape(v.url()), xml_escape(self._cw._(v.title).capitalize()))) + self.w(u'
') def entities(self): schema = self._cw.vreg.schema - self.w(u'

%s

\n' % self._cw._('The repository holds the following entities')) + self.w(u'

%s

\n' % self._cw._('Browse by entity type')) manager = self._cw.user.matching_groups('managers') self.w(u'') if manager: diff -r 4fcb0c132098 -r 01a7228ab5a0 web/views/tableview.py --- a/web/views/tableview.py Mon May 17 11:04:52 2010 +0200 +++ b/web/views/tableview.py Mon May 17 11:05:37 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) diff -r 4fcb0c132098 -r 01a7228ab5a0 web/views/xmlrss.py --- a/web/views/xmlrss.py Mon May 17 11:04:52 2010 +0200 +++ b/web/views/xmlrss.py Mon May 17 11:05:37 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 diff -r 4fcb0c132098 -r 01a7228ab5a0 web/webconfig.py --- a/web/webconfig.py Mon May 17 11:04:52 2010 +0200 +++ b/web/webconfig.py Mon May 17 11:05:37 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', @@ -205,10 +208,18 @@ 'group': 'web', 'level': 3, }), + ('use-old-css', + {'type' : 'yn', + 'default': True, + 'help': 'use cubicweb.old.css instead of 3.9 cubicweb.css', + 'group': 'web', 'level': 2, + }), + + )) 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 +250,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 +263,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 +300,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 +311,70 @@ 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) + # XXX pre 3.9 css compat + if self['use-old-css']: + datadir_url = uiprops.context['datadir_url'] + if (datadir_url+'/cubicweb.css') in uiprops['STYLESHEETS']: + idx = uiprops['STYLESHEETS'].index(datadir_url+'/cubicweb.css') + uiprops['STYLESHEETS'][idx] = datadir_url+'/cubicweb.old.css' + if datadir_url+'/cubicweb.reset.css' in uiprops['STYLESHEETS']: + uiprops['STYLESHEETS'].remove(datadir_url+'/cubicweb.reset.css') + + 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 +401,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)) diff -r 4fcb0c132098 -r 01a7228ab5a0 wsgi/handler.py --- a/wsgi/handler.py Mon May 17 11:04:52 2010 +0200 +++ b/wsgi/handler.py Mon May 17 11:05:37 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()