Пример #1
0
    def render_entities(self, style_node):
        # We have a complete (start, stop) entity to render.
        if self.completed_entity is not None:
            entity_details = self.get_entity_details(self.completed_entity)
            opts = Options.for_entity(self.entity_decorators, entity_details['type'])
            props = entity_details['data'].copy()
            props['entity'] = {
                'type': entity_details['type'],
            }

            if len(self.element_stack) == 1:
                children = self.element_stack[0]
            else:
                children = DOM.create_element()

                for n in self.element_stack:
                    DOM.append_child(children, n)

            self.completed_entity = None
            self.element_stack = []

            # Is there still another entity? (adjacent) if so add the current style_node for it.
            if self.has_entity():
                self.element_stack.append(style_node)

            return DOM.create_element(opts.element, props, children)

        if self.has_entity():
            self.element_stack.append(style_node)
            return None

        return style_node
Пример #2
0
    def add_node(self, element, text):
        if self.is_unstyled():
            child = DOM.create_text_node(text)
            DOM.append_child(element, child)
        else:
            tags = self.get_style_tags()
            child = element

            # Nest the tags.
            # Set the text and style attribute (if any) on the deepest node.
            for tag in tags:
                new_child = DOM.create_element(tag)
                DOM.append_child(child, new_child)
                child = new_child

            style_value = self.get_style_value()
            if style_value:
                DOM.set_attribute(child, 'style', style_value)

            class_value = self.get_class_value()
            if class_value:
                DOM.set_attribute(child, 'class', class_value)

            DOM.set_text_content(child, text)

        return child
Пример #3
0
    def render_entities(self, style_node):

        if self.completed_entity is not None:
            entity_details = self.get_entity_details(self.completed_entity)
            opts = Options.for_entity(self.entity_decorators,
                                      entity_details['type'])
            props = entity_details['data'].copy()
            props['entity'] = {
                'type': entity_details['type'],
            }

            nodes = DOM.create_element()

            for n in self.element_stack:
                DOM.append_child(nodes, n)

            elt = DOM.create_element(opts.element, props, nodes)

            self.completed_entity = None
            self.element_stack = []
        elif self.has_no_entity():
            elt = style_node
        else:
            self.element_stack.append(style_node)
            elt = None

        return elt
Пример #4
0
    def render(self, content_state=None):
        """
        Starts the export process on a given piece of content state.
        """
        if content_state is None:
            content_state = {}

        blocks = content_state.get('blocks', [])
        wrapper_state = WrapperState(self.block_options, blocks)
        document = DOM.create_element()
        entity_map = content_state.get('entityMap', {})
        min_depth = 0

        for block in blocks:
            # Assume a depth of 0 if it's not specified, like Draft.js would.
            depth = block['depth'] if 'depth' in block else 0
            elt = self.render_block(block, entity_map, wrapper_state)

            if depth > min_depth:
                min_depth = depth

            # At level 0, append the element to the document.
            if depth == 0:
                DOM.append_child(document, elt)

        # If there is no block at depth 0, we need to add the wrapper that contains the whole tree to the document.
        if min_depth > 0 and wrapper_state.stack.length() != 0:
            DOM.append_child(document, wrapper_state.stack.tail().elt)

        return DOM.render(document)
Пример #5
0
    def render(self, content_state=None):
        """
        Starts the export process on a given piece of content state.
        """
        if content_state is None:
            content_state = {}

        blocks = content_state.get('blocks', [])
        wrapper_state = WrapperState(self.block_map, blocks)
        document = DOM.create_element()
        entity_map = content_state.get('entityMap', {})
        min_depth = 0

        for block in blocks:
            depth = block['depth']
            elt = self.render_block(block, entity_map, wrapper_state)

            if depth > min_depth:
                min_depth = depth

            # At level 0, append the element to the document.
            if depth == 0:
                DOM.append_child(document, elt)

        # If there is no block at depth 0, we need to add the wrapper that contains the whole tree to the document.
        if min_depth > 0 and wrapper_state.stack.length() != 0:
            DOM.append_child(document, wrapper_state.stack.tail().elt)

        return DOM.render(document)
Пример #6
0
    def render_block(self, block, entity_map, wrapper_state):
        if block['inlineStyleRanges'] or block['entityRanges']:
            content = DOM.create_element()
            entity_state = EntityState(self.entity_decorators, entity_map)
            style_state = StyleState(self.style_map)

            for (text, commands) in self.build_command_groups(block):
                for command in commands:
                    entity_state.apply(command)
                    style_state.apply(command)

                # Decorators are not rendered inside entities.
                if entity_state.has_no_entity() and self.has_decorators:
                    decorated_node = render_decorators(self.composite_decorators, text, block, wrapper_state.blocks)
                else:
                    decorated_node = text

                styled_node = style_state.render_styles(decorated_node, block, wrapper_state.blocks)
                entity_node = entity_state.render_entities(styled_node)

                if entity_node is not None:
                    DOM.append_child(content, entity_node)

                    # Check whether there actually are two different nodes, confirming we are not inserting an upcoming entity.
                    if styled_node != entity_node and entity_state.has_no_entity():
                        DOM.append_child(content, styled_node)
        # Fast track for blocks which do not contain styles nor entities, which is very common.
        elif self.has_decorators:
            content = render_decorators(self.composite_decorators, block['text'], block, wrapper_state.blocks)
        else:
            content = block['text']

        return wrapper_state.element_for(block, content)
Пример #7
0
    def render_entities(self, style_node):
        # We have a complete (start, stop) entity to render.
        if self.completed_entity is not None:
            entity_details = self.get_entity_details(self.completed_entity)
            opts = Options.for_entity(self.entity_decorators,
                                      entity_details['type'])
            props = entity_details['data'].copy()
            props['entity'] = {
                'type': entity_details['type'],
            }

            if len(self.element_stack) == 1:
                children = self.element_stack[0]
            else:
                children = DOM.create_element()

                for n in self.element_stack:
                    DOM.append_child(children, n)

            self.completed_entity = None
            self.element_stack = []

            # Is there still another entity? (adjacent) if so add the current style_node for it.
            if self.has_entity():
                self.element_stack.append(style_node)

            return DOM.create_element(opts.element, props, children)

        if self.has_entity():
            self.element_stack.append(style_node)
            return None

        return style_node
Пример #8
0
    def update_stack(self, options, depth):
        if depth >= self.stack.length():
            # If the depth is gte the stack length, we need more wrappers.
            depth_levels = range(self.stack.length(), depth + 1)

            for level in depth_levels:
                new_wrapper = Wrapper(level, options)

                # Determine where to append the new wrapper.
                if self.stack.head().last_child is None:
                    # If there is no content in the current wrapper, we need
                    # to add an intermediary node.
                    props = dict(options.props)
                    props['block'] = {
                        'type': options.type,
                        'depth': depth,
                        'data': {},
                    }
                    props['blocks'] = self.blocks

                    wrapper_parent = DOM.create_element(options.element, props)
                    DOM.append_child(self.stack.head().elt, wrapper_parent)
                else:
                    # Otherwise we can append at the end of the last child.
                    wrapper_parent = self.stack.head().last_child

                DOM.append_child(wrapper_parent, new_wrapper.elt)

                self.stack.append(new_wrapper)
        else:
            # Cut the stack to where it now stops, and add new wrapper.
            self.stack.slice(depth)
            self.stack.append(Wrapper(depth, options))
Пример #9
0
    def render_block(self, block, entity_map, wrapper_state):
        content = DOM.create_element()
        entity_state = EntityState(self.entity_decorators, entity_map)
        style_state = StyleState(self.style_map)

        for (text, commands) in self.build_command_groups(block):
            for command in commands:
                entity_state.apply(command)
                style_state.apply(command)

            # Decorators are not rendered inside entities.
            if text and entity_state.has_no_entity() and len(
                    self.composite_decorators) > 0:
                decorated_node = render_decorators(self.composite_decorators,
                                                   text, block)
            else:
                decorated_node = text

            styled_node = style_state.render_styles(decorated_node)
            entity_node = entity_state.render_entities(styled_node)

            if entity_node is not None:
                DOM.append_child(content, entity_node)
                if styled_node != entity_node:
                    DOM.append_child(content, styled_node)

        return wrapper_state.element_for(block, content)
Пример #10
0
    def update_stack(self, options, depth):
        if depth >= self.stack.length():
            # If the depth is gte the stack length, we need more wrappers.
            depth_levels = range(self.stack.length(), depth + 1)

            for level in depth_levels:
                new_wrapper = Wrapper(level, options)

                # Determine where to append the new wrapper.
                if self.stack.head().last_child is None:
                    # If there is no content in the current wrapper, we need
                    # to add an intermediary node.
                    props = dict(options.props)
                    props['block'] = {
                        'type': options.type,
                        'depth': depth,
                        'data': {},
                    }
                    props['blocks'] = self.blocks

                    wrapper_parent = DOM.create_element(options.element, props)
                    DOM.append_child(self.stack.head().elt, wrapper_parent)
                else:
                    # Otherwise we can append at the end of the last child.
                    wrapper_parent = self.stack.head().last_child

                DOM.append_child(wrapper_parent, new_wrapper.elt)

                self.stack.append(new_wrapper)
        else:
            # Cut the stack to where it now stops, and add new wrapper.
            self.stack.slice(depth)
            self.stack.append(Wrapper(depth, options))
Пример #11
0
    def render(self, content_state=None):
        """
        Starts the export process on a given piece of content state.
        """
        if content_state is None:
            content_state = {}

        wrapper_state = WrapperState(self.block_map)
        document = DOM.create_element()
        entity_map = content_state.get('entityMap', {})
        min_depth = 0

        for block in content_state.get('blocks', []):
            depth = block['depth']
            elt = self.render_block(block, entity_map, wrapper_state)

            if depth > min_depth:
                min_depth = depth

            # At level 0, append the element to the document.
            if depth == 0:
                DOM.append_child(document, elt)

        # If there is no block at depth 0, we need to add the wrapper that contains the whole tree to the document.
        if min_depth > 0 and wrapper_state.stack.length() != 0:
            DOM.append_child(document, wrapper_state.stack.tail().elt)

        return DOM.render(document)
Пример #12
0
    def update_stack(self, options, depth):
        if depth >= self.stack.length():
            # If the depth is gte the stack length, we need more wrappers.
            depth_levels = range(self.stack.length(), depth + 1)

            for level in depth_levels:
                new_wrapper = Wrapper(level, options.wrapper)

                wrapper_children = DOM.get_children(self.stack.head().elt)

                # Determine where to append the new wrapper.
                if len(wrapper_children) == 0:
                    # If there is no content in the current wrapper, we need
                    # to add an intermediary node.
                    wrapper_parent = DOM.create_element(
                        options.element[0], options.element[1])
                    DOM.append_child(self.stack.head().elt, wrapper_parent)
                else:
                    # Otherwise we can append at the end of the last child.
                    wrapper_parent = wrapper_children[-1]

                DOM.append_child(wrapper_parent, new_wrapper.elt)

                self.stack.append(new_wrapper)
        else:
            # Cut the stack to where it now stops, and add new wrapper.
            self.stack.slice(depth)
            self.stack.append(Wrapper(depth, options.wrapper))
Пример #13
0
    def create_nodes(self, text, block=None, entity_stack=None):
        if entity_stack:
            text_children = [DOM.create_text_node(text)]
        else:
            text_children = get_decorations(self.composite_decorators, text,
                                            block)

        if self.is_unstyled():
            return list(text_children)

        else:
            tags = self.get_style_tags()
            node = DOM.create_element(tags[0])
            child = node

            # Nest the tags.
            # Set the text and style attribute (if any) on the deepest node.
            for tag in tags[1:]:
                new_child = DOM.create_element(tag)
                DOM.append_child(child, new_child)
                child = new_child

            style_value = self.get_style_value()
            if style_value:
                DOM.set_attribute(child, 'style', style_value)
            for text_child in text_children:
                DOM.append_child(child, text_child)

            return [node]
Пример #14
0
    def __init__(self, root_element, entity_decorators, entity_map):
        self.entity_decorators = entity_decorators
        self.entity_map = entity_map

        stack_start = DOM.create_document_fragment()
        DOM.append_child(root_element, stack_start)

        self.entity_stack = [(stack_start, {})]
Пример #15
0
    def start_command(self, command):
        entity_details = self.get_entity_details(command)
        decorator = self.get_entity_decorator(entity_details)

        new_element = decorator.render(entity_details)
        DOM.append_child(self.current_parent(), new_element)

        self.entity_stack.append([new_element, entity_details])
Пример #16
0
    def render_block(self, block: Block, entity_map: EntityMap,
                     wrapper_state: WrapperState) -> Element:
        has_styles = "inlineStyleRanges" in block and block["inlineStyleRanges"]
        has_entities = "entityRanges" in block and block["entityRanges"]
        has_decorators = should_render_decorators(self.composite_decorators,
                                                  block["text"])

        if has_styles or has_entities:
            content = DOM.create_element()
            entity_state = EntityState(self.entity_options, entity_map)
            style_state = StyleState(
                self.style_options) if has_styles else None

            for (text, commands) in self.build_command_groups(block):
                for command in commands:
                    entity_state.apply(command)
                    if style_state:
                        style_state.apply(command)

                # Decorators are not rendered inside entities.
                if has_decorators and entity_state.has_no_entity():
                    decorated_node = render_decorators(
                        self.composite_decorators,
                        text,
                        block,
                        wrapper_state.blocks,
                    )
                else:
                    decorated_node = text

                if style_state:
                    styled_node = style_state.render_styles(
                        decorated_node, block, wrapper_state.blocks)
                else:
                    styled_node = decorated_node
                entity_node = entity_state.render_entities(
                    styled_node, block, wrapper_state.blocks)

                if entity_node is not None:
                    DOM.append_child(content, entity_node)

                    # Check whether there actually are two different nodes, confirming we are not inserting an upcoming entity.
                    if (styled_node != entity_node
                            and entity_state.has_no_entity()):
                        DOM.append_child(content, styled_node)
        # Fast track for blocks which do not contain styles nor entities, which is very common.
        elif has_decorators:
            content = render_decorators(
                self.composite_decorators,
                block["text"],
                block,
                wrapper_state.blocks,
            )
        else:
            content = block["text"]

        return wrapper_state.element_for(block, content)
Пример #17
0
    def clean_up(self):
        """
        Special method to handle a rare corner case: if there is no block
        at depth 0, we need to add the wrapper that contains the whole
        tree to the document.
        """
        document_length = len(DOM.get_children(self.document))

        if document_length == 0 and self.stack.length() != 0:
            DOM.append_child(self.document, self.stack.tail().elt)
Пример #18
0
    def parent_for(self, options, depth, elt):
        if options.wrapper:
            parent = self.get_wrapper_elt(options, depth)
            DOM.append_child(parent, elt)
            self.stack.stack[-1].last_child = elt
        else:
            # Reset the stack if there is no wrapper.
            self.stack = WrapperStack()
            parent = elt

        return parent
Пример #19
0
def render_decorators(decorators: CompositeDecorators, text: str, block: Block, blocks: Sequence[Block]) -> Element:
    decorated_children = list(apply_decorators(decorators, text, block, blocks))

    if len(decorated_children) == 1:
        decorated_node = decorated_children[0]
    else:
        decorated_node = DOM.create_element()
        for decorated_child in decorated_children:
            DOM.append_child(decorated_node, decorated_child)

    return decorated_node
def render_decorators(decorators, text, block, blocks):
    decorated_children = list(apply_decorators(decorators, text, block, blocks))

    if len(decorated_children) == 1:
        decorated_node = decorated_children[0]
    else:
        decorated_node = DOM.create_element()
        for decorated_child in decorated_children:
            DOM.append_child(decorated_node, decorated_child)

    return decorated_node
Пример #21
0
    def parent_for(self, options, depth, elt):
        if options.wrapper:
            parent = self.get_wrapper_elt(options, depth)
            DOM.append_child(parent, elt)
            self.stack.stack[-1].last_child = elt
        else:
            # Reset the stack if there is no wrapper.
            self.stack = WrapperStack()
            parent = elt

        return parent
def render_decorators(decorators, text, block):
    decorated_children = list(apply_decorators(decorators, text, block))

    if len(decorated_children) == 1:
        decorated_node = decorated_children[0]
    else:
        decorated_node = DOM.create_element()
        for decorated_child in decorated_children:
            DOM.append_child(decorated_node, decorated_child)

    return decorated_node
Пример #23
0
    def parent_for(self, options: Options, depth: int,
                   elt: Element) -> Element:
        if options.wrapper:
            parent = self.get_wrapper_elt(options, depth)
            DOM.append_child(parent, elt)
            self.stack.stack[-1].last_child = elt
        else:
            # Reset the stack if there is no wrapper.
            if self.stack.length() > 0:
                self.stack = WrapperStack()
            parent = elt

        return parent
Пример #24
0
    def set_wrapper(self, options=[], depth=0):
        if len(options) == 0:
            element = DOM.create_document_fragment()
        else:
            element = DOM.create_element(options[0], options[1])

        new_wrapper = [element, depth, options]

        if depth >= len(self.wrapper_stack):
            DOM.append_child(DOM.get_children(self.get_wrapper_elt())[-1], element)

            self.wrapper_stack.append(new_wrapper)
        else:
            # Cut the stack to where it now stops, and add new wrapper.
            self.wrapper_stack = self.wrapper_stack[:depth] + [new_wrapper]
Пример #25
0
    def render_entities(self, style_node: Element, block: Block,
                        blocks: Sequence[Block]) -> Element:
        # We have a complete (start, stop) entity to render.
        if self.completed_entity is not None:
            entity_details = self.get_entity_details(self.completed_entity)
            options = Options.get(
                self.entity_options,
                entity_details["type"],
                ENTITY_TYPES.FALLBACK,
            )
            props = entity_details["data"].copy()
            props["entity"] = {
                "type":
                entity_details["type"],
                "mutability":
                entity_details["mutability"]
                if "mutability" in entity_details else None,
                "block":
                block,
                "blocks":
                blocks,
                "entity_range": {
                    "key": self.completed_entity
                },
            }

            if len(self.element_stack) == 1:
                children = self.element_stack[0]
            else:
                children = DOM.create_element()

                for n in self.element_stack:
                    DOM.append_child(children, n)

            self.completed_entity = None
            self.element_stack = []

            # Is there still another entity? (adjacent) if so add the current style_node for it.
            if self.has_entity():
                self.element_stack.append(style_node)

            return DOM.create_element(options.element, props, children)

        if self.has_entity():
            self.element_stack.append(style_node)
            return None

        return style_node
Пример #26
0
    def render_embed(self, props):
        embed_pre_process = app.config.get("EMBED_PRE_PROCESS")
        if embed_pre_process:
            for callback in embed_pre_process:
                callback(props["data"])
        # we use superdesk.etree.parse_html instead of DOM.parse_html as the later modify the content
        # and we use directly the wrapping <div> returned with "content='html'". This works because
        # we use the lxml engine with DraftJSExporter.
        div = parse_html(props["data"]["html"], content="html")
        div.set("class", "embed-block")
        description = props.get("description")
        if description:
            p = DOM.create_element("p", {"class": "embed-block__description"}, description)
            DOM.append_child(div, p)

        return div
Пример #27
0
    def element_for(self, block):
        type_ = block.get('type', 'unstyled')
        depth = block.get('depth', 0)
        options = Options.for_block(self.block_map, type_)

        # Make an element from the options specified in the block map.
        elt = DOM.create_element(options.element[0], options.element[1])

        parent = self.parent_for(options, depth)
        DOM.append_child(parent, elt)

        # At level 0, the element is added to the document.
        if depth == 0:
            DOM.append_child(self.document, parent)

        return elt
Пример #28
0
    def render_embed(self, props):
        embed_pre_process = app.config.get('EMBED_PRE_PROCESS')
        if embed_pre_process:
            for callback in embed_pre_process:
                callback(props['data'])
        # we use superdesk.etree.parse_html instead of DOM.parse_html as the later modify the content
        # and we use directly the wrapping <div> returned with "content='html'". This works because
        # we use the lxml engine with DraftJSExporter.
        div = parse_html(props['data']['html'], content='html')
        div.set('class', 'embed-block')
        description = props.get('description')
        if description:
            p = DOM.create_element('p', {'class': 'embed-block__description'},
                                   description)
            DOM.append_child(div, p)

        return div
Пример #29
0
    def element_for(self, block):
        type = block.get('type', 'unstyled')
        depth = block.get('depth', 0)
        block_options = self.get_block_options(type)

        # Make an element from the options specified in the block map.
        elt_options = self.map_element_options(block_options.get('element'))
        elt = DOM.create_element(elt_options[0], elt_options[1])

        parent = self.parent_for(type, depth)
        DOM.append_child(parent, elt)

        # At level 0, the element is added to the document.
        if (depth == 0):
            DOM.append_child(self.document, parent)

        return elt
Пример #30
0
    def render_block(self, block, entity_map, wrapper_state):
        if 'inlineStyleRanges' in block and block[
                'inlineStyleRanges'] or 'entityRanges' in block and block[
                    'entityRanges']:
            content = DOM.create_element()
            entity_state = EntityState(self.entity_options, entity_map)
            style_state = StyleState(self.style_options)

            for (text, commands) in self.build_command_groups(block):
                for command in commands:
                    entity_state.apply(command)
                    style_state.apply(command)

                # Decorators are not rendered inside entities.
                if entity_state.has_no_entity() and self.has_decorators:
                    decorated_node = render_decorators(
                        self.composite_decorators, text, block,
                        wrapper_state.blocks)
                else:
                    decorated_node = text

                styled_node = style_state.render_styles(
                    decorated_node, block, wrapper_state.blocks)
                entity_node = entity_state.render_entities(styled_node)

                if entity_node is not None:
                    DOM.append_child(content, entity_node)

                    # Check whether there actually are two different nodes, confirming we are not inserting an upcoming entity.
                    if styled_node != entity_node and entity_state.has_no_entity(
                    ):
                        DOM.append_child(content, styled_node)
        # Fast track for blocks which do not contain styles nor entities, which is very common.
        elif self.has_decorators:
            content = render_decorators(self.composite_decorators,
                                        block['text'], block,
                                        wrapper_state.blocks)
        else:
            content = block['text']

        return wrapper_state.element_for(block, content)
Пример #31
0
    def render_entities(self, style_node: Element, block: Block, blocks: Sequence[Block]) -> Element:
        # We have a complete (start, stop) entity to render.
        if self.completed_entity is not None:
            entity_details = self.get_entity_details(self.completed_entity)
            options = Options.get(self.entity_options, entity_details['type'], ENTITY_TYPES.FALLBACK)
            props = entity_details['data'].copy()
            props['entity'] = {
                'type': entity_details['type'],
                'mutability': entity_details['mutability'] if 'mutability' in entity_details else None,
                'block': block,
                'blocks': blocks,
                'entity_range': {
                    'key': self.completed_entity,
                },
            }

            if len(self.element_stack) == 1:
                children = self.element_stack[0]
            else:
                children = DOM.create_element()

                for n in self.element_stack:
                    DOM.append_child(children, n)

            self.completed_entity = None
            self.element_stack = []

            # Is there still another entity? (adjacent) if so add the current style_node for it.
            if self.has_entity():
                self.element_stack.append(style_node)

            return DOM.create_element(options.element, props, children)

        if self.has_entity():
            self.element_stack.append(style_node)
            return None

        return style_node
Пример #32
0
    def create_node(self, text):
        text_lines = self.replace_linebreaks(text)

        if self.is_unstyled():
            node = text_lines
        else:
            tags = self.get_style_tags()
            node = DOM.create_element(tags[0])
            child = node

            # Nest the tags.
            # Set the text and style attribute (if any) on the deepest node.
            for tag in tags[1:]:
                new_child = DOM.create_element(tag)
                DOM.append_child(child, new_child)
                child = new_child

            style_value = self.get_style_value()
            if style_value:
                DOM.set_attribute(child, 'style', style_value)

            DOM.append_child(child, text_lines)

        return node
Пример #33
0
    def replace_linebreaks(self, text):
        lines = text.split('\n')

        if len(lines) > 1:
            wrapper = DOM.create_document_fragment()

            DOM.append_child(wrapper, DOM.create_text_node(lines[0]))

            for l in lines[1:]:
                DOM.append_child(wrapper, DOM.create_element('br'))
                DOM.append_child(wrapper, DOM.create_text_node(l))
        else:
            wrapper = DOM.create_text_node(text)

        return wrapper
Пример #34
0
    def render_block(self, block, entity_map, wrapper_state):
        content = DOM.create_element()

        if block['inlineStyleRanges'] or block['entityRanges']:
            entity_state = EntityState(self.entity_decorators, entity_map)
            style_state = StyleState(self.style_map)

            for (text, commands) in self.build_command_groups(block):
                for command in commands:
                    entity_state.apply(command)
                    style_state.apply(command)

                # Decorators are not rendered inside entities.
                if text and entity_state.has_no_entity() and len(
                        self.composite_decorators) > 0:
                    decorated_node = render_decorators(
                        self.composite_decorators, text, block,
                        wrapper_state.blocks)
                else:
                    decorated_node = text

                styled_node = style_state.render_styles(
                    decorated_node, block, wrapper_state.blocks)
                entity_node = entity_state.render_entities(styled_node)

                if entity_node is not None:
                    DOM.append_child(content, entity_node)
                    if styled_node != entity_node:
                        DOM.append_child(content, styled_node)
        # Fast track for blocks which do not contain styles nor entities, which is very common.
        else:
            if len(self.composite_decorators) > 0:
                decorated_node = render_decorators(self.composite_decorators,
                                                   block['text'], block,
                                                   wrapper_state.blocks)
            else:
                decorated_node = block['text']

            DOM.append_child(content, decorated_node)

        return wrapper_state.element_for(block, content)
Пример #35
0
    def render_entitities(self, root_element, style_node):
        stack_start = DOM.create_document_fragment()
        DOM.append_child(root_element, stack_start)

        element_stack = [stack_start]
        new_element = stack_start

        if len(self.entity_stack) == 0:
            DOM.append_child(root_element, style_node)
        else:
            for entity_details in self.entity_stack:
                decorator = self.get_entity_decorator(entity_details)
                props = entity_details.copy()

                props['children'] = style_node

                new_element = decorator.render(props)
                DOM.append_child(element_stack[-1], new_element)
                element_stack.append(new_element)

        return new_element
Пример #36
0
    def render_entitities(self, root_element, style_nodes):
        element_stack = []

        if len(self.entity_stack) == 0:
            for node in style_nodes:
                DOM.append_child(root_element, node)
            return root_element

        else:
            for entity_details in self.entity_stack:
                decorator = self.get_entity_decorator(entity_details)

                entity_details['children'] = style_nodes

                new_element = decorator.render(entity_details)
                if not element_stack:
                    DOM.append_child(root_element, new_element)
                    element_stack = [new_element]
                else:
                    DOM.append_child(element_stack[-1], new_element)
                element_stack.append(new_element)

            return new_element
Пример #37
0
 def test_append_child(self):
     parent = DOM.create_element('p')
     DOM.append_child(parent, DOM.create_element('span', {}, 'Test text'))
     self.assertEqual(DOM.render_debug(parent), '<p><span>Test text</span></p>')