001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software, please see the
018 * company website: http://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: http://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.acacia.client.widgets;
029
030import org.opencms.gwt.shared.CmsGwtLog;
031
032import com.google.gwt.regexp.shared.RegExp;
033
034import elemental2.core.JsArray;
035import elemental2.core.JsObject;
036import jsinterop.annotations.JsConstructor;
037import jsinterop.annotations.JsPackage;
038import jsinterop.annotations.JsType;
039import jsinterop.base.Js;
040import jsinterop.base.JsPropertyMap;
041
042/**
043 * Helpers / utilities related to the 'typograf' typography library.
044 */
045public final class CmsTypografUtil {
046
047    /**
048     * Native type for the Typograf class provided by the library of the same name.
049     */
050    @JsType(isNative = true, namespace = JsPackage.GLOBAL)
051    public static class Typograf {
052
053        @JsConstructor
054        public Typograf(JsPropertyMap<Object> options) { /* must be empty */ }
055
056        public static native boolean hasLocale(String locale);
057
058        public native void addSafeTag(String beginRegex, String endRegex);
059
060        public native void disableRule(String rule);
061
062        public native void enableRule(String rule);
063
064        public native String execute(String input);
065    }
066
067    /** Pattern to match entities. */
068    public static final RegExp ENTITY_PATTERN = RegExp.compile("(&[#a-z0-9]+;)", "gi");
069
070    /** Pattern to match safe tags. */
071    public static final RegExp SAFE_TAG_PATTERN = RegExp.compile("%OC(BEGIN|END)ENTITY%", "g");
072
073    /** Tag to insert before an entity. */
074    private static final String OC_BEGIN_ENTITY = "%OCBEGINENTITY%";
075
076    /** Tag to insert after an entity. */
077    private static final String OC_END_ENTITY = "%OCENDENTITY%";
078
079    /**
080     * Hidden default constructor.
081     */
082    private CmsTypografUtil() {
083
084        // empty
085    }
086
087    /**
088     * Creates a 'live' typograf instance to be used for typography while typing in an editor widget.
089     *
090     * @param typografLocale the typograf locale (not the same format as OpenCms locales!)
091     * @return the typograf instance for the locale, or null if it couldn't be created
092     */
093    public static Typograf createLiveInstance(String typografLocale) {
094
095        Typograf typograf = null;
096        if (Typograf.hasLocale(typografLocale)) {
097            try {
098                JsPropertyMap<Object> options = Js.cast(new JsObject());
099                options.set("locale", new JsArray<>(typografLocale, "en-US"));
100                options.set("live", Boolean.TRUE);
101                typograf = new Typograf(options);
102                typograf.disableRule("*");
103                typograf.enableRule("common/punctuation/quote");
104                typograf.addSafeTag(OC_BEGIN_ENTITY, OC_END_ENTITY);
105            } catch (Exception e) {
106                CmsGwtLog.log(e.getLocalizedMessage());
107            }
108        }
109        return typograf;
110    }
111
112    /**
113     * Wraps entities in safe tags.
114     *
115     * @param input the input string
116     * @return the string with wrapped entities
117     */
118    public static String protectEntities(String input) {
119
120        return ENTITY_PATTERN.replace(input, OC_BEGIN_ENTITY + "$1" + OC_END_ENTITY);
121    }
122
123    /**
124     * Removes the safe tags around entities.
125     *
126     * @param input the input string
127     * @return the transformed string
128     */
129    public static String restoreEntities(String input) {
130
131        return SAFE_TAG_PATTERN.replace(input, "");
132
133    }
134
135    /**
136     * Transforms things with typograf, preserving all entities.
137     *
138     * @param typograf the typograf instance
139     * @param value the value to transform
140     * @return the transformed value
141     */
142    public static String transform(Typograf typograf, String value) {
143
144        value = protectEntities(value);
145        value = typograf.execute(value);
146        value = restoreEntities(value);
147        return value;
148    }
149
150}