Пример #1
0
    def reaction(self, *connection_strings):
        # The JS version (no decorator functionality)

        if len(connection_strings) < 2:
            raise RuntimeError(
                'Component.reaction() (js) needs a function and '
                'one or more connection strings.')

        # Get callable
        if callable(connection_strings[0]):
            func = connection_strings[0]
            connection_strings = connection_strings[1:]
        elif callable(connection_strings[-1]):
            func = connection_strings[-1]
            connection_strings = connection_strings[:-1]
        else:
            raise TypeError('Component.reaction() requires a callable.')

        # Verify connection strings
        for i in range(len(connection_strings)):
            s = connection_strings[i]
            if not (isinstance(s, str) and len(s)):
                raise ValueError('Connection string must be nonempty strings.')

        # Get function name (Flexx sets __name__ on methods)
        name = RawJS("func.__name__ || func.name || 'anonymous'")
        # name = name.split(' ')[-1].split('flx_')[-1]
        nameparts = RawJS("name.split(' ')")
        nameparts = RawJS("nameparts[nameparts.length-1].split('flx_')")
        name = nameparts[-1]
        mode = 'normal'
        return self.__create_reaction_ob(func, name, mode, connection_strings)
Пример #2
0
def foo(a, b):
    x = RawJS('a + b')
    y = 0
    RawJS("""
    for (i=0; i<8; i++) {
        y += i * x;
    }
    """)
    RawJS("""while (y>0) {
        x += y;
        y -= 1;
    }
    """)
Пример #3
0
 def _validate_browser_capabilities(self):
     # We test a handful of features here, and assume that if these work,
     # all of Flexx works. It is not a hard guarantee, of course, because
     # the user can use modern features in an application.
     RawJS("""
     var el = window.document.getElementById('flexx-spinner');
     if (    window.WebSocket === undefined || // IE10+
             Object.keys === undefined || // IE9+
             false
        ) {
         var msg = ('Flexx does not support this browser.<br>' +
                    'Try Firefox, Chrome, ' +
                    'or a more recent version of the current browser.');
         if (el) { el.children[0].innerHTML = msg; }
         else { window.alert(msg); }
         return false;
     } else if (''.startsWith === undefined) { // probably IE
         var msg = ('Flexx support for this browser is limited.<br>' +
                    'Consider using Firefox, Chrome, or maybe Edge.');
         if (el) { el.children[0].innerHTML = msg; }
         return true;
     } else {
         return true;
     }
     """)
Пример #4
0
    def __create_reaction_ob(self, reaction_func, name, mode, connection_strings):
        # Keep ref to the reaction function, see comment in create_action().

        # Create function that becomes our "reaction object"
        def reaction():
            return reaction_func.apply(self, arguments)  # arguments == events

        # Attach methods to the function object (this gets replaced)
        REACTION_METHODS_HOOK  # noqa

        # Init reaction
        that = self
        RawJS("Component.prototype._REACTION_COUNT += 1")
        reaction._id = RawJS("'r' + Component.prototype._REACTION_COUNT")
        reaction._name = name
        reaction._mode = mode
        reaction._ob1 = lambda : that  # no weakref in JS
        reaction._init(connection_strings, self)

        return reaction
Пример #5
0
 def spin(self, n=1):
     RawJS("""
     if (!window.document.body) {return;}
     var el = window.document.body.children[0];
     if (el && el.classList.contains("flx-spinner")) {
         if (n === null) {
             el.style.display = 'none';  // Stop the spinner
         } else {
             el.children[0].innerHTML += '&#9632'.repeat(n);
         }
     }
     """)
Пример #6
0
    def _create_pointer_event(self, e):
        # Get offset to fix positions
        rect = self.node.getBoundingClientRect()
        offset = rect.left, rect.top

        if e.type.startswith('touch'):
            # Touch event - select one touch to represent the main position
            t = e.changedTouches[0]
            pos = float(t.clientX - offset[0]), float(t.clientY - offset[1])
            page_pos = t.pageX, t.pageY
            button = 0
            buttons = []
            # Include basic support for multi-touch
            touches = {}
            for i in range(e.changedTouches.length):
                t = e.changedTouches[i]
                if t.target is not e.target:
                    continue
                touches[t.identifier] = (float(t.clientX - offset[0]),
                                         float(t.clientY - offset[1]), t.force)
        else:
            # Mouse event
            pos = float(e.clientX - offset[0]), float(e.clientY - offset[1])
            page_pos = e.pageX, e.pageY
            # Fix buttons
            if e.buttons:
                buttons_mask = RawJS(
                    "e.buttons.toString(2).split('').reverse().join('')")
            else:
                # libjavascriptcoregtk-3.0-0  version 2.4.11-1 does not define
                # e.buttons
                buttons_mask = [e.button.toString(2)]
            buttons = [i + 1 for i in range(5) if buttons_mask[i] == '1']
            button = {0: 1, 1: 3, 2: 2, 3: 4, 4: 5}[e.button]
            touches = {
                -1: (pos[0], pos[1], 1)
            }  # key must not clash with real touches

        # note: our button has a value as in JS "which"
        modifiers = [
            n for n in ('Alt', 'Shift', 'Ctrl', 'Meta')
            if e[n.toLowerCase() + 'Key']
        ]
        # Create event dict
        return dict(
            pos=pos,
            page_pos=page_pos,
            touches=touches,
            button=button,
            buttons=buttons,
            modifiers=modifiers,
        )
Пример #7
0
    def __init__(self, *init_args, **property_values):

        RawJS('Component.prototype._COUNT += 1')
        self._id = RawJS("this.__name__ + Component.prototype._COUNT")
        self._disposed = False

        # Init some internal variables
        self.__handlers = {}  # reactions connecting to this component
        self.__pending_events = []
        self.__anonymous_reactions = []
        self.__initial_mutation = False

        # Create actions
        for i in range(len(self.__actions__)):
            name = self.__actions__[i]
            self.__create_action(self[name], name)
        # Create emitters
        for i in range(len(self.__emitters__)):
            name = self.__emitters__[i]
            self.__handlers[name] = []
            self.__create_emitter(self[name], name)
        # Create properties
        for i in range(len(self.__properties__)):
            name = self.__properties__[i]
            self.__handlers[name] = []
            self.__create_property(name)
        # Create attributes
        for i in range(len(self.__attributes__)):
            name = self.__attributes__[i]
            self.__create_attribute(name)

        # With self as the active component (and thus mutatable), init the
        # values of all properties, and apply user-defined initialization
        with self:
            self._comp_init_property_values(property_values)
            self.init(*init_args)

        # Connect reactions and fire initial events
        self._comp_init_reactions()
Пример #8
0
 def spin(self, n=1):
     RawJS("""
     var el = window.document.getElementById('flexx-spinner');
     if (el) {
         if (n === null) {  // Hide the spinner overlay, now or in a bit
             if (el.children[0].innerHTML.indexOf('limited') > 0) {
                 setTimeout(function() { el.style.display = 'none'; }, 2000);
             } else {
                 el.style.display = 'none';
             }
         } else {
             for (var i=0; i<n; i++) { el.children[1].innerHTML += '&#9632'; }
         }
     }
     """)
Пример #9
0
def get_weeknumber(t):
    """Get the ISO 8601 week number."""
    # From https://weeknumber.net/how-to/javascript
    date = Date(t * 1000)  # noqa
    RawJS("""
    date.setHours(0, 0, 0, 0);
    // Thursday in current week decides the year.
    date.setDate(date.getDate() + 3 - (date.getDay() + 6) % 7);
    // January 4 is always in week 1.
    var week1 = new Date(date.getFullYear(), 0, 4);
    // Adjust to Thursday in week 1 and count number of weeks from date to week1.
    var res = 1 + Math.round(((date.getTime() - week1.getTime()) / 86400000
                               - 3 + (week1.getDay() + 6) % 7) / 7);
    """)
    return res  # noqa
Пример #10
0
    def keep_checking_size_of(self, ob, check=True):
        """ This is a service that the session provides.
        """
        # Gets called by the Widget class for toplevel widgets. That
        # is, toplevel to Flexx: they might not be toplevel for the
        # browser. This method will make sure that they know their size
        # in any case, at least once each second.
        if check:
            self.instances_to_check_size[ob.id] = ob
        else:
            self.instances_to_check_size.pop(ob.id, None)

    def _check_size_of_objects(self):
        for ob in self.instances_to_check_size.values():
            if ob._disposed is False:
                ob.check_real_size()


# In Python, we need some extras for the serializer to work
if this_is_js():
    # Include bsdf.js
    window.flexx = Flexx()
    bsdf = RawJS("flexx.require('bsdf')")
    serializer = bsdf.BsdfSerializer()
    window.flexx.serializer = serializer
else:
    # Import vendored bsdf lite module
    from . import bsdf_lite as bsdf
    serializer = bsdf.BsdfLiteSerializer()
    serializer.__module__ = __name__
Пример #11
0
def test_raw_js():
    
    with raises(TypeError):
        RawJS()
    with raises(TypeError):
        RawJS(3)
    
    # Empty
    r1 = RawJS('')
    assert str(r1) == ''
    assert r1.get_code() == ''
    assert r1.get_code(4) == ''
    assert '0' in repr(r1)
    assert r1.__module__.endswith(__name__)
    
    # Short single line
    r2 = RawJS('require("foobar")')
    assert 'require(' in repr(r2)
    assert 'require(' in str(r2)
    assert r2.get_code().startswith('require')
    assert r2.get_code(4).startswith('    require')
    assert r2.get_code(2).startswith('  require')
    assert '\n' not in r2.get_code()
    
    # Long single line
    r2b = RawJS('require("foobar")'*10)
    assert 'require(' not in repr(r2b)
    assert '1' in repr(r2b)
    
    # Multiline, start at first line
    r3 = RawJS("""for ... {
                      yyyy  
                  }
               """)
    assert 'lines' in repr(r3)
    assert 'for ...' in str(r3)
    assert str(r3).endswith('}\n')
    assert r3.get_code().count('\n') == 3
    assert r3.get_code().startswith('for')
    assert r3.get_code(4).startswith('    for')
    assert '\n    yyyy\n' in r3.get_code(0)
    assert '\n        yyyy\n' in r3.get_code(4)
    
    # Multiline, exactly the same, but start at second line; same results
    r4 = RawJS("""
        for ... {
            yyyy  
        }
        """)
    assert 'lines' in repr(r4)
    assert 'for ...' in str(r4)
    assert str(r4).endswith('}\n')
    assert r4.get_code().count('\n') == 3
    assert r4.get_code().startswith('for')
    assert r4.get_code(4).startswith('    for')
    assert '\n    yyyy\n' in r4.get_code(0)
    assert '\n        yyyy\n' in r4.get_code(4)
    
    # Multiline, now newline at the ned
    r5 = RawJS("""
        for ... {
            yyyy  
        }""")
    assert r5.get_code().count('\n') == 2
    assert str(r5).endswith('}')
Пример #12
0
 def _create_dom(self):
     global window
     node = window.document.createElement('input')
     RawJS('$')(node).datepicker()
     return node
Пример #13
0
 def func(a, b):
     RawJS("""
     var c = 3;
     return a + b + c;
     """)
Пример #14
0
 def load_viz(self):
     
     w, h = self.size
     
     nodes = d3.range(200).map(lambda: {'radius': Math.random() * 12 + 4})
     color = d3.scale.category10()
     
     force = d3.layout.force().gravity(0.05).charge(lambda d, i: 0 if i else -2000)\
         .nodes(nodes).size([w, h])
     
     root = nodes[0]
     root.radius = 0
     root.fixed = True
     
     force.start()
     
     x = d3.select('#' + self.id)
     print(x, self.id)
     svg = RawJS('x.append("svg").attr("width", w).attr("height", h)')
     
     x = RawJS(
         'svg.selectAll("circle").data(nodes.slice(1)).enter().append("circle")')
     x.attr("r", lambda d: d.radius).style("fill", lambda d, i: color(i % 3))
     
     def on_tick(e):
         q = d3.geom.quadtree(nodes)
         i = 0
         n = nodes.length
         while i < n-1:
             i += 1
             q.visit(collide(nodes[i]))
         svg.selectAll("circle").attr("cx", lambda d: d.x).attr("cy", lambda d: d.y)
     
     force.on("tick", on_tick)
     
     def on_mousemove():
         p1 = d3.mouse(self.node)
         root.px = p1[0]
         root.py = p1[1]
         force.resume()
     
     svg.on("mousemove", on_mousemove)
     
     def collide(node):
         r = node.radius + 16
         nx1 = node.x - r
         nx2 = node.x + r
         ny1 = node.y - r
         ny2 = node.y + r
         
         def func(quad, x1, y1, x2, y2):
             if quad.point and quad.point is not node:
                 x = node.x - quad.point.x
                 y = node.y - quad.point.y
                 s = Math.sqrt(x * x + y * y)
                 r = node.radius + quad.point.radius
                 if (s < r):
                     s = (s - r) / s * .5
                     x *= s
                     y *= s
                     node.x -= x
                     node.y -= y
                     quad.point.x += x
                     quad.point.y += y
             return x1 > nx2 or x2 < nx1 or y1 > ny2 or y2 < ny1
         return func