web/request.py
brancholdstable
changeset 6665 90f2f20367bc
parent 6353 b622602f8e9d
child 6543 66145280a7e6
--- a/web/request.py	Tue Jul 27 12:36:03 2010 +0200
+++ b/web/request.py	Wed Nov 03 16:38:28 2010 +0100
@@ -27,6 +27,7 @@
 from datetime import date
 from urlparse import urlsplit
 from itertools import count
+from warnings import warn
 
 from rql.utils import rqlvar_maker
 
@@ -36,15 +37,13 @@
 
 from cubicweb.dbapi import DBAPIRequest
 from cubicweb.mail import header
-from cubicweb.uilib import remove_html_tags
+from cubicweb.uilib import remove_html_tags, js
 from cubicweb.utils import SizeConstrainedList, HTMLHead, make_uid
 from cubicweb.view import STRICT_DOCTYPE, TRANSITIONAL_DOCTYPE_NOEXT
 from cubicweb.web import (INTERNAL_FIELD_VALUE, LOGGER, NothingToEdit,
-                          RequestError, StatusResponse, json)
+                          RequestError, StatusResponse)
 from cubicweb.web.http_headers import Headers
 
-dumps = json.dumps
-
 _MARKER = object()
 
 
@@ -83,6 +82,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
@@ -94,12 +99,8 @@
         # search state: 'normal' or 'linksearch' (eg searching for an object
         # to create a relation with another)
         self.search_state = ('normal',)
-        # tabindex generator
-        self.tabindexgen = count(1)
-        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()
@@ -127,6 +128,13 @@
         """
         return self.set_varmaker()
 
+    def _get_tabindex_func(self):
+        nextfunc = self.get_page_data('nexttabfunc')
+        if nextfunc is None:
+            nextfunc = count(1).next
+            self.set_page_data('nexttabfunc', nextfunc)
+        return nextfunc
+
     def set_varmaker(self):
         varmaker = self.get_page_data('rql_varmaker')
         if varmaker is None:
@@ -139,6 +147,8 @@
         or an anonymous connection is open
         """
         super(CubicWebRequestBase, self).set_session(session, user)
+        # tabindex generator
+        self.next_tabindex = self._get_tabindex_func()
         # set request language
         vreg = self.vreg
         if self.user:
@@ -339,23 +349,37 @@
             return breadcrumbs.pop()
         return self.base_url()
 
-    def user_rql_callback(self, args, msg=None):
+    def user_rql_callback(self, rqlargs, *args, **kwargs):
         """register a user callback to execute some rql query and return an url
-        to call it ready to be inserted in html
+        to call it ready to be inserted in html.
+
+        rqlargs should be a tuple containing argument to give to the execute function.
+
+        For other allowed arguments, see :meth:`user_callback` method
         """
         def rqlexec(req, rql, args=None, key=None):
             req.execute(rql, args, key)
-        return self.user_callback(rqlexec, args, msg)
+        return self.user_callback(rqlexec, rqlargs, *args, **kwargs)
+
+    def user_callback(self, cb, cbargs, *args, **kwargs):
+        """register the given user callback and return an url to call it ready
+        to be inserted in html.
 
-    def user_callback(self, cb, args, msg=None, nonify=False):
-        """register the given user callback and return an url to call it ready to be
-        inserted in html
+        You can specify the underlying js function to call using a 'jsfunc'
+        named args, to one of :func:`userCallback`,
+        ':func:`userCallbackThenUpdateUI`, ':func:`userCallbackThenReloadPage`
+        (the default). Take care arguments may vary according to the used
+        function.
         """
         self.add_js('cubicweb.ajax.js')
-        cbname = self.register_onetime_callback(cb, *args)
-        msg = dumps(msg or '')
-        return "javascript:userCallbackThenReloadPage('%s', %s)" % (
-            cbname, msg)
+        jsfunc = kwargs.pop('jsfunc', 'userCallbackThenReloadPage')
+        if 'msg' in kwargs:
+            warn('[3.10] msg should be given as positional argument',
+                 DeprecationWarning, stacklevel=2)
+            args = (kwargs.pop('msg'),) + args
+        assert not kwargs, 'dunno what to do with remaining kwargs: %s' % kwargs
+        cbname = self.register_onetime_callback(cb, *cbargs)
+        return "javascript: %s" % getattr(js, jsfunc)(cbname, *args)
 
     def register_onetime_callback(self, func, *args):
         cbname = 'cb_%s' % (
@@ -366,7 +390,6 @@
             try:
                 ret = func(req, *args)
             except TypeError:
-                from warnings import warn
                 warn('[3.2] user callback should now take request as argument')
                 ret = func(*args)
             self.unregister_callback(self.pageid, cbname)
@@ -508,7 +531,7 @@
         """set output content type for this request. An optional filename
         may be given
         """
-        if content_type.startswith('text/'):
+        if content_type.startswith('text/') and ';charset=' not in content_type:
             content_type += ';charset=' + (encoding or self.encoding)
         self.set_header('content-type', content_type)
         if filename:
@@ -564,24 +587,30 @@
                 cssfile = self.datadir_url + cssfile
             add_css(cssfile, media, *extraargs)
 
+    @deprecated('[3.9] use ajax_replace_url() instead, naming rql and vid arguments')
     def build_ajax_replace_url(self, nodeid, rql, vid, replacemode='replace',
                                **extraparams):
+        return self.ajax_replace_url(nodeid, replacemode, rql=rql, vid=vid,
+                                     **extraparams)
+
+    def ajax_replace_url(self, nodeid, replacemode='replace', **extraparams):
         """builds an ajax url that will replace nodeid's content
 
         :param nodeid: the dom id of the node to replace
-        :param rql: rql to execute
-        :param vid: the view to apply on the resultset
         :param replacemode: defines how the replacement should be done.
 
-        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
+          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
+
+        Arbitrary extra named arguments may be given, they will be included as
+        parameters of the generated url.
         """
-        url = self.build_url('view', rql=rql, vid=vid, __notemplate=1,
-                             **extraparams)
-        return "javascript: loadxhtml('%s', '%s', '%s')" % (
-            nodeid, xml_escape(url), replacemode)
+        extraparams.setdefault('fname', 'view')
+        url = self.build_url('json', **extraparams)
+        return "javascript: $('#%s').%s; noop()" % (
+            nodeid, js.loadxhtml(url, None, 'get', replacemode))
 
     # urls/path management ####################################################
 
@@ -589,10 +618,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 +643,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 +718,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 +823,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)