Search in sources :

Example 1 with IText

use of org.thymeleaf.model.IText in project thymeleaf by thymeleaf.

the class IteratedGatheringModelProcessable method computeIterationModels.

/*
     * Internal-only method, meant to reshape the gathered model so that white space is adequately handled
     * during iteration. As a result, this method will produce different Model object for the first, the middle
     * and the last iterations.
     */
private IterationModels computeIterationModels(final IterationWhiteSpaceHandling iterationWhiteSpaceHandling) {
    /*
         * Nothing to iterate
         */
    if (iterationWhiteSpaceHandling == IterationWhiteSpaceHandling.ZERO_ITER) {
        return IterationModels.EMPTY;
    }
    /*
         * Get the originally gathered model. This will serve as a base for any needed modifications
         */
    final Model innerModel = getInnerModel();
    final int gatheredModelSize = innerModel.size();
    /*
         * If there is only one iteration, we need to perform no modifications at all, whichever the template mode
         */
    if (iterationWhiteSpaceHandling == IterationWhiteSpaceHandling.SINGLE_ITER) {
        return new IterationModels(innerModel, innerModel, innerModel);
    }
    /*
         * If template mode is a markup one, we will only need to take care of the existence of a preceding white space
         */
    if (!this.templateMode.isText()) {
        if (this.precedingWhitespace != null) {
            final Model modelWithWhiteSpace = new Model(innerModel);
            modelWithWhiteSpace.insert(0, this.precedingWhitespace);
            return new IterationModels(innerModel, modelWithWhiteSpace, modelWithWhiteSpace);
        }
        return new IterationModels(innerModel, innerModel, innerModel);
    }
    if (innerModel.size() <= 2) {
        // This does only contain the template open + close events -- nothing to be done
        return new IterationModels(innerModel, innerModel, innerModel);
    }
    int firstBodyEventCutPoint = -1;
    int lastBodyEventCutPoint = -1;
    // we know there is at least one body event
    final ITemplateEvent firstBodyEvent = innerModel.get(1);
    Text firstTextBodyEvent = null;
    if (innerModel.get(0) instanceof OpenElementTag && firstBodyEvent instanceof IText) {
        firstTextBodyEvent = Text.asEngineText((IText) firstBodyEvent);
        final int firstTextEventLen = firstTextBodyEvent.length();
        int i = 0;
        char c;
        while (i < firstTextEventLen && firstBodyEventCutPoint < 0) {
            c = firstTextBodyEvent.charAt(i);
            if (c == '\n') {
                firstBodyEventCutPoint = i + 1;
                // we've already assigned the value we were looking for
                break;
            } else if (Character.isWhitespace(c)) {
                i++;
                continue;
            } else {
                // We will not be able to perform any whitespace reduction here
                break;
            }
        }
    }
    final ITemplateEvent lastBodyEvent = innerModel.get(gatheredModelSize - 2);
    Text lastTextBodyEvent = null;
    if (firstBodyEventCutPoint >= 0 && innerModel.get(gatheredModelSize - 1) instanceof CloseElementTag && lastBodyEvent instanceof IText) {
        lastTextBodyEvent = Text.asEngineText((IText) lastBodyEvent);
        final int lastTextEventLen = lastTextBodyEvent.length();
        int i = lastTextEventLen - 1;
        char c;
        while (i >= 0 && lastBodyEventCutPoint < 0) {
            c = lastTextBodyEvent.charAt(i);
            if (c == '\n') {
                lastBodyEventCutPoint = i + 1;
                // we've already assigned the value we were looking for
                break;
            } else if (Character.isWhitespace(c)) {
                i--;
                continue;
            } else {
                // We will not be able to perform any whitespace reduction here
                break;
            }
        }
    }
    /*
         * If there is no reason to perform any modifications, just use the gathered model
         */
    if (firstBodyEventCutPoint < 0 || lastBodyEventCutPoint < 0) {
        // We don't have the scenario required for performing the needed whitespace collapsing operation
        return new IterationModels(innerModel, innerModel, innerModel);
    }
    if (firstBodyEvent == lastBodyEvent) {
        // If the first and the last event are actually the same, we need to take better care of how we manage whitespace
        final Text textForFirst = new Text(firstTextBodyEvent.subSequence(0, lastBodyEventCutPoint));
        final Text textForMiddle = new Text(firstTextBodyEvent.subSequence(firstBodyEventCutPoint, lastBodyEventCutPoint));
        final Text textForLast = new Text(firstTextBodyEvent.subSequence(firstBodyEventCutPoint, firstTextBodyEvent.length()));
        final Model modelFirst = new Model(innerModel);
        modelFirst.replace(1, textForFirst);
        final Model modelMiddle = new Model(innerModel);
        modelMiddle.replace(1, textForMiddle);
        final Model modelLast = new Model(innerModel);
        modelLast.replace(1, textForLast);
        return new IterationModels(modelFirst, modelMiddle, modelLast);
    }
    // At this point, we know the first and last body events are different objects
    final Model modelFirst = new Model(innerModel);
    final Model modelMiddle = new Model(innerModel);
    final Model modelLast = new Model(innerModel);
    if (firstBodyEventCutPoint > 0) {
        final Text headTextForMiddleAndMax = new Text(firstTextBodyEvent.subSequence(firstBodyEventCutPoint, firstTextBodyEvent.length()));
        modelMiddle.replace(1, headTextForMiddleAndMax);
        modelLast.replace(1, headTextForMiddleAndMax);
    }
    if (lastBodyEventCutPoint < lastTextBodyEvent.length()) {
        final Text tailTextForFirstAndMiddle = new Text(lastTextBodyEvent.subSequence(0, lastBodyEventCutPoint));
        modelFirst.replace(gatheredModelSize - 2, tailTextForFirstAndMiddle);
        modelMiddle.replace(gatheredModelSize - 2, tailTextForFirstAndMiddle);
    }
    return new IterationModels(modelFirst, modelMiddle, modelLast);
}
Also used : ITemplateEvent(org.thymeleaf.model.ITemplateEvent) IText(org.thymeleaf.model.IText) IText(org.thymeleaf.model.IText)

Example 2 with IText

use of org.thymeleaf.model.IText in project thymeleaf by thymeleaf.

the class ProcessorTemplateHandler method handleText.

@Override
public void handleText(final IText itext) {
    /*
         * If processing is stopped, we should queue this for later handling
         * In theory, given the origin of events (parser or cache) should get stopped immediately, this should
         * only happen if a pre-processor is producing additional events.
         */
    if (this.throttleEngine && this.flowController.stopProcessing) {
        queueEvent(itext);
        return;
    }
    /*
         * CHECK WHETHER WE ARE GATHERING AN ELEMENT's MODEL
         */
    if (!this.modelController.shouldProcessText(itext)) {
        return;
    }
    /*
         * FAIL FAST in case this structure has no associated processors.
         */
    if (this.textProcessors.length == 0) {
        this.next.handleText(itext);
        return;
    }
    /*
         * CAST EVENT TO ENGINE-SPECIFIC IMPLEMENTATION
         */
    Text text = Text.asEngineText(itext);
    /*
         * DECLARE VARIABLES THAT MIGHT BE NEEDED FOR TAKING ACTIONS INSTRUCTED BY THE PROCESSORS
         */
    boolean discardEvent = false;
    Model model = null;
    ITemplateHandler modelHandler = this;
    final TextStructureHandler structureHandler = this.textStructureHandler;
    /*
         * EXECUTE PROCESSORS
         */
    for (int i = 0; !discardEvent && i < this.textProcessors.length; i++) {
        structureHandler.reset();
        this.textProcessors[i].process(this.context, text, structureHandler);
        if (structureHandler.setText) {
            text = new Text(structureHandler.setTextValue);
        } else if (structureHandler.replaceWithModel) {
            model = resetModel(model, true);
            model.addModel(structureHandler.replaceWithModelValue);
            modelHandler = structureHandler.replaceWithModelProcessable ? this : this.next;
            discardEvent = true;
        } else if (structureHandler.removeText) {
            model = null;
            discardEvent = true;
        }
    }
    /*
         * PROCESS THE REST OF THE HANDLER CHAIN
         */
    if (!discardEvent) {
        this.next.handleText(text);
    }
    /*
         * PROCESS THE QUEUED MODEL IF NEEDED (or handle it as pending if we are throttling the engine)
         */
    if (model == null || model.size() == 0) {
        return;
    }
    if (!this.throttleEngine) {
        model.process(modelHandler);
    } else {
        queueProcessable(new SimpleModelProcessable(model, modelHandler, this.flowController));
    }
}
Also used : IText(org.thymeleaf.model.IText)

Aggregations

IText (org.thymeleaf.model.IText)2 ITemplateEvent (org.thymeleaf.model.ITemplateEvent)1