001/*
002 * (C) Copyright 2013 Nuxeo SA (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl-2.1.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     <a href="mailto:grenard@nuxeo.com">Guillaume</a>
016 */
017package org.nuxeo.ecm.platform.ui.select2.common;
018
019import java.util.ArrayList;
020import java.util.Arrays;
021import java.util.List;
022
023import net.sf.json.JSONArray;
024import net.sf.json.JSONObject;
025
026import org.apache.commons.lang.StringUtils;
027import org.apache.commons.logging.Log;
028import org.apache.commons.logging.LogFactory;
029import org.nuxeo.ecm.core.schema.types.Schema;
030import org.nuxeo.ecm.platform.usermanager.UserConfig;
031import org.nuxeo.runtime.api.Framework;
032import org.nuxeo.runtime.services.config.ConfigurationService;
033
034/**
035 * Group fields and methods used at initialization and runtime for select2 feature.
036 *
037 * @since 5.7.3
038 */
039public class Select2Common {
040
041    private static final Log log = LogFactory.getLog(Select2Common.class);
042
043    private static final String FORCE_DISPLAY_EMAIL_IN_SUGGESTION = "nuxeo.ui.displayEmailInUserSuggestion";
044
045    public static final String LANG_TOKEN = "{lang}";
046
047    public static final String DEFAULT_LANG = "en";
048
049    public static final String ID = "id";
050
051    public static final String LABEL = "displayLabel";
052
053    public static final String DIRECTORY_DEFAULT_LABEL_COL_NAME = "label";
054
055    public static final String PARENT_FIELD_ID = "parent";
056
057    public static final String PLACEHOLDER = "placeholder";
058
059    public static final String COMPUTED_ID = "computedId";
060
061    public static final String DEFAULT_KEY_SEPARATOR = "/";
062
063    public static final String OBSOLETE_FIELD_ID = "obsolete";
064
065    public static final List<String> SELECT2_USER_WIDGET_TYPE_LIST = new ArrayList<String>(Arrays.asList(
066            "singleUserSuggestion", "multipleUsersSuggestion"));
067
068    public static final List<String> SELECT2_DOC_WIDGET_TYPE_LIST = new ArrayList<String>(Arrays.asList(
069            "singleDocumentSuggestion", "multipleDocumentsSuggestion"));
070
071    public static final String USER_TYPE = "USER_TYPE";
072
073    public static final String GROUP_TYPE = "GROUP_TYPE";
074
075    public static final String TYPE_KEY_NAME = "type";
076
077    public static final String PREFIXED_ID_KEY_NAME = "prefixed_id";
078
079    public static final String SUGGESTION_FORMATTER = "suggestionFormatter";
080
081    public static final String SELECTION_FORMATTER = "selectionFormatter";
082
083    public static final String USER_DEFAULT_SUGGESTION_FORMATTER = "userEntryDefaultFormatter";
084
085    public static final String DOC_DEFAULT_SUGGESTION_FORMATTER = "docEntryDefaultFormatter";
086
087    public static final String WARN_MESSAGE_LABEL = "warn_message";
088
089    public static final List<String> SELECT2_DIR_WIDGET_TYPE_LIST = new ArrayList<String>(Arrays.asList(
090            "suggestOneDirectory", "suggestManyDirectory"));
091
092    public static final List<String> SELECT2_DEFAULT_DOCUMENT_SCHEMAS = new ArrayList<String>(Arrays.asList(
093            "dublincore", "common"));
094
095    public static final String DIR_DEFAULT_SUGGESTION_FORMATTER = "dirEntryDefaultFormatter";
096
097    public static final String READ_ONLY_PARAM = "readonly";
098
099    public static final String RERENDER_JS_FUNCTION_NAME = "reRenderFunctionName";
100
101    public static final String AJAX_RERENDER = "ajaxReRender";
102
103    public static final String USER_DEFAULT_SELECTION_FORMATTER = "userSelectionDefaultFormatter";
104
105    public static final String DOC_DEFAULT_SELECTION_FORMATTER = "docSelectionDefaultFormatter";
106
107    public static final String DIR_DEFAULT_SELECTION_FORMATTER = "dirSelectionDefaultFormatter";
108
109    public static final String WIDTH = "width";
110
111    public static final String DEFAULT_WIDTH = "300";
112
113    public static final String MIN_CHARS = "minChars";
114
115    public static final int DEFAULT_MIN_CHARS = 3;
116
117    public static final String TITLE = "title";
118
119    public static final String DISPLAY_ICON = "displayIcon";
120
121    public static final String OPERATION_ID = "operationId";
122
123    public static final String DIRECTORY_ORDER_FIELD_NAME = "ordering";
124
125    public static final String ABSOLUTE_LABEL = "absoluteLabel";
126
127    private static Boolean forceDisplayEmailInSuggestion = null;
128
129    public static final String ICON = "icon";
130
131    private static boolean isForceDisplayEmailInSuggestion() {
132        if (forceDisplayEmailInSuggestion == null) {
133            ConfigurationService cs = Framework.getService(ConfigurationService.class);
134            forceDisplayEmailInSuggestion = cs.isBooleanPropertyTrue(FORCE_DISPLAY_EMAIL_IN_SUGGESTION);
135        }
136        return forceDisplayEmailInSuggestion;
137    }
138
139    /**
140     * @since 5.9.3
141     */
142    public static String[] getDefaultSchemas() {
143        return getSchemas(null);
144    }
145
146    /**
147     * Compute the field name of the directory that holds the value that we want to display.
148     *
149     * @param schema the directory schema
150     * @param dbl10n are translations carried by directory fields
151     * @param labelFieldName the name or pattern of the fields that held values
152     * @param lang the current language
153     * @throws IllegalArgumentException when cannot compute label field name
154     * @return the final field name where we pick up the value
155     * @since 5.7.3
156     */
157    public static String getLabelFieldName(final Schema schema, boolean dbl10n, String labelFieldName, final String lang) {
158        if (labelFieldName == null || labelFieldName.isEmpty()) {
159            // No labelFieldName provided, we assume it is 'label'
160            labelFieldName = DIRECTORY_DEFAULT_LABEL_COL_NAME;
161        }
162        if (dbl10n) {
163            int i = labelFieldName.indexOf(LANG_TOKEN);
164            if (i >= 0) {
165                // a pattern is provided, let's compute the field name
166                // according
167                // to the current lang
168                StringBuffer buf = new StringBuffer();
169                buf.append(labelFieldName.substring(0, i));
170                buf.append(lang);
171                buf.append(labelFieldName.substring(i + LANG_TOKEN.length()));
172                String result = buf.toString();
173                if (schema.getField(result) != null) {
174                    return result;
175                } else {
176                    // there is no field for the current lang, let's pick
177                    // english by default
178                    buf = new StringBuffer();
179                    buf.append(labelFieldName.substring(0, i));
180                    buf.append(DEFAULT_LANG);
181                    buf.append(labelFieldName.substring(i + LANG_TOKEN.length()));
182                    return buf.toString();
183                }
184            } else {
185                // No pattern
186                String result = labelFieldName + "_" + lang;
187                if (schema.getField(result) != null) {
188                    // we assume that fields are named like 'xxx_en',
189                    // 'xxx_fr', etc.
190                    return result;
191                }
192
193                log.warn(String.format(
194                        "Unable to find field %s in directory schema %s. Trying to fallback on default one.",
195                        labelFieldName, schema.getName()));
196
197                result = DIRECTORY_DEFAULT_LABEL_COL_NAME + "_" + DEFAULT_LANG;
198                if (schema.getField(result) != null) {
199                    // no available locale, fallback to english by default
200                    return result;
201                }
202                result = DIRECTORY_DEFAULT_LABEL_COL_NAME;
203                if (schema.getField(result) != null) {
204                    // no available default locale, fallback to label
205                    return result;
206                }
207
208                if (schema.getField(labelFieldName) != null) {
209                    // let's pretend this is not dbl10n
210                    return labelFieldName;
211                }
212
213                throw new IllegalArgumentException(String.format("Unable to find field %s in directory schema %s",
214                        labelFieldName, schema.getName()));
215            }
216        } else {
217            if (schema.getField(labelFieldName) != null) {
218                return labelFieldName;
219            } else {
220                throw new IllegalArgumentException(String.format("Unable to find field %s in directory schema %s",
221                        labelFieldName, schema.getName()));
222            }
223        }
224    }
225
226    /**
227     * Returns an array containing the given schema names plus the default ones if not included
228     *
229     * @param schemaNames
230     * @since 5.8
231     */
232    public static String[] getSchemas(final String schemaNames) {
233        List<String> result = new ArrayList<String>();
234        result.addAll(Select2Common.SELECT2_DEFAULT_DOCUMENT_SCHEMAS);
235        String[] temp = null;
236        if (schemaNames != null && !schemaNames.isEmpty()) {
237            temp = schemaNames.split(",");
238        }
239        if (temp != null) {
240            for (String s : temp) {
241                result.add(s);
242            }
243        }
244        return result.toArray(new String[result.size()]);
245    }
246
247    public static void computeUserLabel(final JSONObject obj, final String firstLabelField,
248            final String secondLabelField, final String thirdLabelField, final boolean hideFirstLabel,
249            final boolean hideSecondLabel, final boolean hideThirdLabel, boolean displayEmailInSuggestion,
250            final String userId) {
251        String result = "";
252        if (obj != null) {
253
254            if (StringUtils.isNotBlank(firstLabelField) && !hideFirstLabel) {
255                // If firtLabelField given and first label not hidden
256                final String firstLabel = obj.optString(firstLabelField);
257                result += StringUtils.isNotBlank(firstLabel) ? firstLabel : "";
258            } else if (!hideFirstLabel) {
259                // Else we use firstname
260                final String firstname = obj.optString(UserConfig.FIRSTNAME_COLUMN);
261                result += StringUtils.isNotBlank(firstname) ? firstname : "";
262            }
263
264            if (StringUtils.isNotBlank(secondLabelField) && !hideSecondLabel) {
265                // If secondLabelField given and second label not hidden
266                final String secondLabel = obj.optString(firstLabelField);
267                if (StringUtils.isNotBlank(secondLabel)) {
268                    if (StringUtils.isNotBlank(result)) {
269                        result += " ";
270                    }
271                    result += secondLabel;
272                }
273            } else if (!hideSecondLabel) {
274                // Else we use lastname
275                final String lastname = obj.optString(UserConfig.LASTNAME_COLUMN);
276                if (StringUtils.isNotBlank(lastname)) {
277                    if (StringUtils.isNotBlank(result)) {
278                        result += " ";
279                    }
280                    result += lastname;
281                }
282            }
283            if (StringUtils.isBlank(result)) {
284                // At this point, if returned label is empty, we use user id
285                result += StringUtils.isNotBlank(userId) ? userId : "";
286            }
287
288            if (isForceDisplayEmailInSuggestion() || (displayEmailInSuggestion && !hideThirdLabel)) {
289                if (StringUtils.isNotBlank(thirdLabelField)) {
290                    final String thirdLabel = obj.optString(thirdLabelField);
291                    if (StringUtils.isNotBlank(thirdLabel)) {
292                        if (StringUtils.isNotBlank(result)) {
293                            result += " ";
294                        }
295                        result += thirdLabel;
296                    }
297                } else {
298                    // Else we use email
299                    String email = obj.optString(UserConfig.EMAIL_COLUMN);
300                    if (StringUtils.isNotBlank(email)) {
301                        if (StringUtils.isNotBlank(result)) {
302                            result += " ";
303                        }
304                        result += email;
305                    }
306                }
307            }
308
309            obj.put(LABEL, result);
310        }
311    }
312
313    public static void computeGroupLabel(final JSONObject obj, final String groupId, final String groupLabelField,
314            final boolean hideFirstLabel) {
315        String label = null;
316        if (hideFirstLabel) {
317            label = groupId;
318        } else {
319            String groupLabelValue = obj.optString(groupLabelField);
320            if (StringUtils.isNotBlank(groupLabelValue)) {
321                label = groupLabelValue;
322            } else {
323                label = groupId;
324            }
325        }
326        obj.put(LABEL, label);
327    }
328
329    public static void computeUserGroupIcon(final JSONObject obj, final boolean hideIcon) {
330        if (obj != null) {
331            if (!hideIcon) {
332                String userGroupType = obj.optString(TYPE_KEY_NAME);
333                obj.element(DISPLAY_ICON, StringUtils.isNotBlank(userGroupType)
334                        && (userGroupType.equals(USER_TYPE) || userGroupType.equals(GROUP_TYPE)));
335            }
336        }
337    }
338
339    /**
340     * @since 6.0
341     */
342    public static String resolveDefaultEntries(final List<String> list) {
343        if (list == null || list.isEmpty()) {
344            return "[]";
345        } else {
346            JSONArray result = new JSONArray();
347            for (String l : list) {
348                JSONObject obj = new JSONObject();
349                obj.element(Select2Common.ID, l);
350                obj.element(Select2Common.LABEL, l);
351                result.add(obj);
352            }
353            return result.toString();
354        }
355    }
356
357}