view src/bridge/bridge_constructor/constructors/embedded/embedded_template.py @ 2169:f472179305a1

tools(templates): workflow improvments: - template theme can be specified in parenthesis: (some_theme)path/to/template.html. Withtout parenthesis, "default" is used - static content are supposed to be in [theme]/static, error pages in [theme]/error/[err_code].html - default page are used in some case (2 for now): if error page with specified code doesn't exists, a base page is used, and if a page doesn't exist for a theme, the same one for default theme is looked for - CSS files are automatically found for HTML pages - CSS files can be split, the'll be added in the template according to the page requested. - theme CSS file is looked for, and if not found the default theme equivalent is looked for. - each element of a path can be associated to a CSS file, and styles.css is always there. For instance if blog/articles.html is requested, the following CSS can be included: "styles.css", "blog.css", "blog_article.css". They all must be in /static - if the automatic finding of CSS files is not wanted, css_files arguments can be used instead, with full relative path (i.e. including theme) - CSS files can be merged and included inline with css_inline argument - root_path can be specified, it will be used as a prefix for static files - requested theme (which may differ from actual theme, e.g. if the template is not found and default one is used instead) is available in template with "theme" variable - added getThemeAndRoot method to retrieve theme and theme root path from template
author Goffi <goffi@goffi.org>
date Sun, 05 Mar 2017 23:41:10 +0100
parents 442423faf220
children 8b37a62336c3
line wrap: on
line source

#!/usr/bin/env python2
#-*- coding: utf-8 -*-

# SàT: a XMPP client
# Copyright (C) 2009-2016 Jérôme Poisson (goffi@goffi.org)

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# This program 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 Affero General Public License for more details.

# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

from sat.core.log import getLogger
log = getLogger(__name__)
from sat.core import exceptions


class _Bridge(object):
    def __init__(self):
        log.debug(u"Init embedded bridge...")
        self._methods_cbs = {}
        self._signals_cbs = {
            "core": {},
            "plugin": {}
            }

    def bridgeConnect(self, callback, errback):
        callback()

    def register_method(self, name, callback):
        log.debug(u"registering embedded bridge method [{}]".format(name))
        if name in self._methods_cbs:
            raise exceptions.ConflictError(u"method {} is already regitered".format(name))
        self._methods_cbs[name] = callback

    def register_signal(self, functionName, handler, iface="core"):
        iface_dict = self._signals_cbs[iface]
        if functionName in iface_dict:
            raise exceptions.ConflictError(u"signal {name} is already regitered for interface {iface}".format(name=functionName, iface=iface))
        iface_dict[functionName] = handler

    def call_method(self, name, out_sign, async_, args, kwargs):
        callback = kwargs.pop("callback", None)
        errback = kwargs.pop("errback", None)
        if async_:
            d = self._methods_cbs[name](*args, **kwargs)
            if callback is not None:
                d.addCallback(callback if out_sign else lambda dummy: callback())
            if errback is None:
                d.addErrback(lambda failure_: log.error(failure_))
            else:
                d.addErrback(errback)
            return d
        else:
            try:
                ret = self._methods_cbs[name](*args, **kwargs)
            except Exception as e:
                if errback is not None:
                    errback(e)
                else:
                    raise e
            else:
                if callback is None:
                    return ret
                else:
                    if out_sign:
                        callback(ret)
                    else:
                        callback()

    def send_signal(self, name, args, kwargs):
        try:
            cb = self._signals_cbs["plugin"][name]
        except KeyError:
            log.debug(u"ignoring signal {}: no callback registered".format(name))
        else:
            cb(*args, **kwargs)

    def addMethod(self, name, int_suffix, in_sign, out_sign, method, async=False, doc={}):
        #FIXME: doc parameter is kept only temporary, the time to remove it from calls
        log.debug("Adding method [{}] to embedded bridge".format(name))
        self.register_method(name, method)
        setattr(self.__class__, name, lambda self_, *args, **kwargs: self.call_method(name, out_sign, async, args, kwargs))

    def addSignal(self, name, int_suffix, signature, doc={}):
        setattr(self.__class__, name, lambda self_, *args, **kwargs: self.send_signal(name, args, kwargs))

    ## signals ##

##SIGNALS_PART##
    ## methods ##

##METHODS_PART##

# we want the same instance for both core and frontend
bridge = None
def Bridge():
    global bridge
    if bridge is None:
        bridge = _Bridge()
    return bridge