Source: core/UrlUtilsMixin.js

/**
 * Copyright (C) 2005-2016 Alfresco Software Limited.
 *
 * This file is part of Alfresco
 *
 * Alfresco is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Alfresco is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * This is a mixin that provides URL related utility functions. The majority of the functions were ported
 * from the original YUI2 based Share code defined in alfresco.js - they are therefore somewhat Share specific.
 *
 * @module alfresco/core/UrlUtilsMixin
 * @extends module:alfresco/core/PathUtils
 * @author Dave Draper
 */
define(["dojo/_base/declare",
        "alfresco/core/PathUtils",
        "alfresco/core/ObjectTypeUtils",
        "alfresco/enums/urlTypes",
        "alfresco/util/urlUtils",
        "service/constants/Default",
        "dojo/_base/lang",
        "jquery"],
        function(declare, PathUtils, ObjectTypeUtils, urlTypes, urlUtils, AlfConstants, lang, jquery) {

   return declare([PathUtils], {

      /**
       * This indicates whether or not the linked pages are "Aikau-style" page. An Aikau style page is where
       * the a combination of "page-id" and "ws" URL tokens are used to construct a page. This defaults to false
       * for use in Alfresco Share where pages for located items are typically standard "Surf-style" pages.
       *
       * @instance
       * @type {boolean}
       * @default
       */
      useAikauPages: false,

      /**
       * It's possible to explicitly set a specific URI template to use for generating links. If this is not
       * set then a default of "sitepage" is used which is known to be configured in in both Alfresco Share
       * and in applications generated from the Aikau Maven archetype.
       *
       * @instance
       * @type {string}
       * @default
       */
      sitePageTemplate: null,

      /**
       * This function can be used to build a page taking into account that the page can either be
       * a Surf Page (as used by Alfresco Share) or an Aikau page (as used by custom page in Share or
       * a standalone Aikau client).
       *
       * @instance
       * @param  {string} page This is the pageid (for Share) or WebScript URL (for Aikau) for the URL
       * @param  {string} site This is the site (if available) to use
       * @param  {string} template A custom template to use in place of "sitepage" (which will be used otherwise)
       * @return {url} The URL built from the supplied arguments.
       */
      buildUrl: function alfresco_core_UrlUtilsMixin__buildUrl(page, site) {
         var tokens = {
            site: site
         };
         if (this.useAikauPages === true)
         {
            tokens.webscript = page;
            tokens.pageid = "dp";
         }
         else
         {
            tokens.pageid = page;
         }
         var url = this.uriTemplate(this.sitePageTemplate || "sitepage", tokens);
         return url;
      },

      /**
       * Generate User Profile link
       *
       * @instance
       * @param {object} oUser Object literal container user data
       * @return {String} HTML mark-up for user profile link
       */
      generateUserLink: function alfresco_core_UrlUtilsMixin__generateUserLink(oUser) {
         if (oUser.isDeleted === true)
         {
            return "<span>" + this.message("details.user.deleted", this.encodeHTML(oUser.userName)) + "</span>";
         }
         return this.userProfileLink(oUser.userName, lang.trim(oUser.firstName + " " + oUser.lastName));
      },

      /**
       *
       * @instance
       * @param {string} userName User Name
       * @param {string} fullName Full display name. "userName" used if this param is empty or not supplied
       * @param {string} linkAttr Optional attributes to add to the <a> tag, e.g. "class"
       * @param {boolean} disableLink Optional attribute instructing the link to be disabled (ie returning a span element rather than an a href element)
       * @return {string} The populated HTML Link
       */
      userProfileLink: function alfresco_core_UrlUtilsMixin__userProfileLink(userName, fullName, linkAttr, disableLink) {
         if (!ObjectTypeUtils.isString(userName) || userName.length === 0)
         {
            return "";
         }

         var html = this.encodeHTML(ObjectTypeUtils.isString(fullName) && fullName.length > 0 ? fullName : userName),
               template = AlfConstants.URI_TEMPLATES.userprofilepage,
               uri = "";

         // If the "userprofilepage" template doesn't exist or is empty, we'll just return the user's fullName || userName
         if (disableLink || ObjectTypeUtils.isUndefined(template) || template.length === 0)
         {
            return "<span>" + html + "</span>";
         }

         // Generate the link
         uri = this.uriTemplate("userprofilepage", {
            userid: userName
         });

         return "<a href=\"" + uri + "\" " + (linkAttr || "") + ">" + html + "</a>";
      },

      /**
       * Returns a URL to a site page.
       * If no Site ID is supplied, generates a link to the non-site page.
       *
       * @instance
       * @param {string} pageURI Page ID and and QueryString parameters the page might need, e.g.
       * <pre>
       *    "folder-details?nodeRef=" + nodeRef
       * </pre>
       * @param {object} obj The object literal containing the token values to substitute within the template
       * @returns {string} The populated URL
       */
      siteURL: function alfresco_core_UrlUtilsMixin__siteURL(pageURI, obj) {
         var target = obj || {};
         var source = {
            pageid: pageURI
         };
         return this.uriTemplate("sitepage", jquery.extend(true, target, source));
      },

      /**
       * This function attempts to find a URI template that has been configured for the Surf application.
       * If a template that matches the supplied "templateId" argument is found then the 
       * [renderUriTemplate]{@link module:alfresco/core/UrlUtilsMixin#renderUriTemplate} function will be called
       * to perform the actual rendering.
       * 
       * @instance
       * @param {string} templateId The id of the template to render a URI for
       * @param {object} obj An object that provides subtitution tokens for the URI template
       * @param {boolean} absolute
       */
      uriTemplate: function alfresco_core_UrlUtilsMixin__uriTemplate(templateId, obj, absolute) {
         // Check we know about the templateId
         if (!(templateId in AlfConstants.URI_TEMPLATES))
         {
            return null;
         }
         return this.renderUriTemplate(AlfConstants.URI_TEMPLATES[templateId], obj, absolute);
      },

      /**
       * This function renders a URI based on a supplied template ensuring that token substitution is performed
       * (using tokens supplied in the "obj" argument). This function does have some specific code to handle
       * site templates that are provided where no site data is supplied in the object. However, unlike the version
       * of the code that this function was ported from (in alfresco.js in Share) there is no support for retrieving
       * the current site or context from the URL.
       * 
       * @instance
       * @param {string} template The template to render a URI from
       * @param {object} obj An object that provides subtitution tokens for the URI template
       * @param {boolean} absolute Indicates that the URI rendered should include protocol, host/port and application context
       * @returns {string} The rendered URI
       */
      renderUriTemplate: function alfresco_core_UrlUtilsMixin__renderUriTemplate(template, obj, absolute) {

         // If a site page was requested but no {siteid} given, then use the current site or remove the missing parameter
         // This code-block was ported from alfresco.js in Share and is really too share specific and could potentially
         // be rewritten in the future to validation to ensure that all substitution tokens are provided.
         if (template.indexOf("{site}") !== -1)
         {
            if (obj.hasOwnProperty("site") && ObjectTypeUtils.isValueSet(obj.site))
            {
               // No action required. Site exists in template and site is provided in object for substitution.
            }
            else
            {
               // Remove site part of template as site has not been provided.
               template = template.replace("/site/{site}", "");
            }
         }

         var uri = template,
             regExp = /^(http|https):\/\//;
         uri = lang.replace(uri, obj);
         if (!regExp.test(uri))
         {
            // Page context required
            uri = urlUtils.convertUrl(uri, urlTypes.PAGE_RELATIVE);
         }

         // Absolute URI needs current protocol and host
         if (absolute && (uri.indexOf(location.protocol + "//") !== 0))
         {
            // Don't use combinePaths in case the encoding is fragile
            if (uri.substring(0, 1) !== "/")
            {
               uri = "/" + uri;
            }
            uri = location.protocol + "//" + location.host + uri;
         }
         return uri;
      },

      /**
       * This function is required to support "legacy" action handling within Share.
       *
       * @instance
       * @param {Object} record The current node to generate actions URLs for.
       * @param {String} [siteId] The id of the current site, will be generated if missing from record.
       */
      getActionUrls: function alfresco_core_UrlUtilsMixin__getActionUrls(record, siteId) {
         var actionUrls = {},
             jsNode = record.node;
         if (jsNode)
         {
            var nodeRef = jsNode.isLink ? jsNode.linkedNode.nodeRef : jsNode.nodeRef,
                strNodeRef = nodeRef ? nodeRef.toString() : "",
                contentUrl = jsNode.contentURL,
                workingCopy = record.workingCopy || {},
                recordSiteId = (record.location && record.location.site) ? record.location.site.name : null;

            var site = {
               site: siteId || recordSiteId
            };
            try
            {
               actionUrls.downloadUrl = this.combinePaths(AlfConstants.PROXY_URI, contentUrl) + "?a=true";
               actionUrls.viewUrl =  this.combinePaths(AlfConstants.PROXY_URI, contentUrl) + "\" target=\"_blank";
               actionUrls.documentDetailsUrl = this.generatePageUrl("document-details?nodeRef=" + strNodeRef, site);
               actionUrls.folderDetailsUrl = this.generatePageUrl("folder-details?nodeRef=" + strNodeRef, site);
               actionUrls.editMetadataUrl = this.generatePageUrl("edit-metadata?nodeRef=" + strNodeRef, site);
               actionUrls.inlineEditUrl = this.generatePageUrl("inline-edit?nodeRef=" + strNodeRef, site);
               actionUrls.managePermissionsUrl = this.generatePageUrl("manage-permissions?nodeRef=" + strNodeRef, site);
               actionUrls.manageTranslationsUrl = this.generatePageUrl("manage-translations?nodeRef=" + strNodeRef, site);
               actionUrls.workingCopyUrl = this.generatePageUrl("document-details?nodeRef=" + (workingCopy.workingCopyNodeRef || strNodeRef), site);
               actionUrls.workingCopySourceUrl = this.generatePageUrl("document-details?nodeRef=" + (workingCopy.sourceNodeRef || strNodeRef), site);
               actionUrls.viewGoogleDocUrl = workingCopy.googleDocUrl + "\" target=\"_blank";
               actionUrls.cloudViewUrl = this.combinePaths(AlfConstants.URL_SERVICECONTEXT, "cloud/cloudUrl?nodeRef=" + strNodeRef);
               actionUrls.sourceRepositoryUrl = this.viewInSourceRepositoryURL(record, actionUrls) + "\" target=\"_blank";
            }
            catch (e)
            {
               this.alfLog("error", "The following error occurred generating action URLs", e, record, this);
            }
         }
         return actionUrls;
      },

      /**
       * Alias to [siteURL]{@link module:alfresco/core/UrlUtilsMixin#siteURL}
       *
       * @instance
       * @param {String} page
       * @param {Object[]} args
       */
      generatePageUrl: function alfresco_core_UrlUtilsMixin__generatePageUrl(page, args) {
         return this.siteURL(page, args);
      },

      /**
       * View in source Repository URL helper
       *
       * @instance
       * @param {Object} record Object literal representing the file or folder to be actioned
       * @param {Object} actionUrls Action urls for this record
       */
      viewInSourceRepositoryURL: function alfresco_core_UrlUtilsMixin__viewInSourceRepositoryURL(record, actionUrls, replicationUrlMapping) {
         if (record)
         {
            var node = record.node;
            var repoId = lang.getObject("location.repositoryId", false, record);
            var urlMapping = replicationUrlMapping;
            var siteUrl;

            if (!repoId || !urlMapping || !urlMapping[repoId])
            {
               return "#";
            }

            // Generate a URL to the relevant details page
            siteUrl = node.isContainer ? actionUrls.folderDetailsUrl : actionUrls.documentDetailsUrl;
            // Strip off this webapp's context as the mapped one might be different
            siteUrl = siteUrl.substring(AlfConstants.URL_CONTEXT.length);
            return this.combinePaths(urlMapping[repoId], "/", siteUrl);
         }
         else
         {
            return "#";
         }
      }
   });
});