How to customize the Document List in Alfresco? - alfresco

In the repository there be will different document lists.i.e there will be Data dictionary, user homes,Guest homes etc. when I change the view to "detailed view", it displays Favorite, like, comments links. where will I have to modify if I dont want to show them. Can you tell in which file i have to comment the code for not displaying those links. Thank you in Advance.

I wanted a "modular" answer to this question, this answer is to show how I handled this issue.
Context: Alfresco 4.2.f, project Maven from the org.alfresco.maven.archetype:alfresco-amp-archetype:1.1.1 archetype, I put everything in the embedded JAR when possible.
Create a module extension for share (see this blog for more details). Here is my extension file:
src/main/resources/alfresco/site-data/extensions/my-custom-extension.xml
<extension>
<modules>
<module>
<id>Main module of my custom extension</id>
<version>${project.version}</version>
<auto-deploy>true</auto-deploy>
<customizations>
<customization>
<!-- Order matters here! target before source, always! -->
<targetPackageRoot>org.alfresco</targetPackageRoot>
<sourcePackageRoot>my-custom.main</sourcePackageRoot>
</customization>
</customizations>
</module>
</modules>
</extension>
In the documentlibrary component of your module package, create this FTL in order to declare a javascript:
src/main/resources/alfresco/site-webscripts/my-custom/main/components/documentlibrary/documentlist-v2.get.html.ftl
<#-- Add a Javascript declaration -->
<#markup id="my-custom-js" target="js" action="after">
<#script type="text/javascript" group="documentlibrary"
src="${url.context}/res/my-custom/main/components/documentlibrary/documentlist.js"/>
</#>
In the resources (META-INF), under documentlibrary component, create the Javascript:
src/main/resources/META-INF/my-custom/main/components/documentlibrary/documentlist.js
YAHOO.lang.augmentObject(Alfresco.DocumentList.prototype, {
// Possible values: i18nLabel, lockBanner, syncFailed, syncTransientError
// date, size, name, version, description, tags, categories
myCustomDisabledRenderers: ["description", "version", "tags"],
// Possible values: favourites, likes, comments, quickShare
myCustomDisabledSocials: ["favourites", "comments", "likes", "quickShare"],
myCustomIsSocialDisabled: function(propertyName) {
return Alfresco.util.arrayContains(
this.myCustomDisabledSocials, propertyName);
},
myCustomIsRendererDisabled: function(propertyName) {
if (Alfresco.util.arrayContains(
this.myCustomDisabledRenderers, propertyName)) {
return true;
}
// Disable the social renderer when all the social features are
// disabled
if (propertyName === "social" && this.myCustomDisabledSocials.length == 4) {
return true;
}
return false;
},
/** Helper function to disable socials
* propertyName must be one of "favourites", "comments", "likes", "quickShare"
*/
myCustomDisableSocial: function(propertyName) {
if (!Alfresco.util.arrayContains(
this.myCustomDisabledSocials, propertyName)) {
this.myCustomDisabledSocials.push(propertyName);
}
},
// Custom registerRenderer for social features, originally defined in:
// webapps/share/components/documentlibrary/documentlist.js:2134
myCustomSocialRegisterRenderer: function(record) {
var jsNode = record.jsNode;
var html = "";
// Current usage of the separator variable allow to change the order
// of the different social features (the 'if' blocks below) without
// changing their content
var separator = "";
/* Favourite / Likes / Comments */
if (!this.myCustomIsSocialDisabled("favourites")) {
html += '<span class="item item-social' + separator + '">' +
Alfresco.DocumentList.generateFavourite(this, record) +
'</span>';
separator = " item-separator";
}
if (!this.myCustomIsSocialDisabled("likes")) {
html += '<span class="item item-social' + separator + '">' +
Alfresco.DocumentList.generateLikes(this, record) +
'</span>';
separator = " item-separator";
}
if (!this.myCustomIsSocialDisabled("comments") &&
jsNode.permissions.user.CreateChildren) {
html += '<span class="item item-social' + separator + '">' +
Alfresco.DocumentList.generateComments(this, record) +
'</span>';
separator = " item-separator";
}
if (!this.myCustomIsSocialDisabled("quickShare") && !record.node.isContainer &&
Alfresco.constants.QUICKSHARE_URL) {
html += '<span class="item' + separator + '">' +
Alfresco.DocumentList.generateQuickShare(this, record) +
'</span>';
separator = " item-separator";
}
return html;
},
// Overwrite registerRenderer which was originally defined in:
// webapps/share/components/documentlibrary/documentlist.js:1789
registerRenderer: function DL_registerRenderer(propertyName, renderer) {
if (Alfresco.util.isValueSet(propertyName) &&
Alfresco.util.isValueSet(renderer) &&
!this.myCustomIsRendererDisabled(propertyName)) {
if (propertyName === "social") {
this.renderers[propertyName] = this.myCustomSocialRegisterRenderer;
} else {
this.renderers[propertyName] = renderer;
}
return true;
}
return false;
}
}, true);
Then you can disable the links by updating myCustomDisabledRenderers and/or mySocialDisabledRenderers.
This way also allows you to create a module that disable (for example) the "comments on documents" or "likes on document" feature independently in only 6 easy steps!
Example, how to make a module that only disable comments on documents in 6 steps
Important: first remove the "comment disabling" from the documentlist.js of the main module.
myCustomDisabledSocials: ["favourites", "likes", "quickShare"],
Create a new module "my-custom.nocomment" with the same structure.
<extension>
<modules>
<module>
<id>Main module of my custom extension</id>
[...]
</module>
<module>
<id>No comment module of my custom extension</id>
<version>${project.version}</version>
<customizations>
<customization>
<targetPackageRoot>org.alfresco</targetPackageRoot>
<sourcePackageRoot>my-custom.nocomment</sourcePackageRoot>
</customization>
</customizations>
</module>
</modules>
</extension>
Add the FTL...
src/main/resources/alfresco/site-webscripts/my-custom/nocomment/components/documentlibrary/documentlist-v2.get.html.ftl
<#-- Add a Javascript declaration -->
<#markup id="my-custom-js" target="js" action="after">
<#script type="text/javascript" group="documentlibrary"
src="${url.context}/res/my-custom/nocomment/components/documentlibrary/documentlist.js"/>
</#>
then the Javascript...
src/main/resources/META-INF/my-custom/nocomment/components/documentlibrary/documentlist.js
Alfresco.DocumentList.prototype.myCustomDisableSocial("comment");
and then I'm happy, clap along if you feel like everything's just got smooth!
Notes:
The nocomment module depends on the main module.
It is important for the nocomment module to be loaded after the main module (in http://localhost:8080/share/page/modules/deploy).
In order for the nocomment module to be complete, you also need to disable comments from the document details page, see below.
Disable comments from the document details page
Even if, this one is documented elsewhere, I spent so much time searching around these few days that I feel like I need to be as comprehensive as possible.
src/main/resources/alfresco/site-data/extensions/my-custom-extension.xml
Add this to your my-custom.nocomment module declaration and you will get rid of the comments form and list from the document details page.
[...]
<module>
<id>No comment module of my custom extension</id>
[...]
<components>
<component>
<region-id>comments</region-id>
<source-id>document-details</source-id>
<scope>template</scope>
<sub-components>
<sub-component id="default">
<evaluations>
<evaluation id="guaranteedToHide">
<render>false</render>
</evaluation>
</evaluations>
</sub-component>
</sub-components>
</component>
</components>
</module>
[...]
src/main/resources/alfresco/site-webscripts/my-custom/nocomment/components/node-details/node-header.get.js
This is for disabling the button on the header of the document details page.
// Disable comments
for (var i = 0; i < model.widgets.length; i++) {
if (model.widgets[i].id == "NodeHeader") {
model.widgets[i].options.showComments = false;
}
}
// And since it does not work, disable comments this way too
model.showComments = "false";
Note: I did not test these snippets, they have been taken from my project after "anonymization" (basically renaming the module). Let me know if you find mistakes.

What you are looking for is more than likely generated by client-side JavaScript. You should use share-config-custom.xml to set Share to development mode, like this:
<alfresco-config>
<!-- Put Share Client in debug mode -->
<config replace="true">
<flags>
<client-debug>true</client-debug>
<client-debug-autologging>false</client-debug-autologging>
</flags>
</config>
</alfresco-config>
Then, use firebug or your browser's developer console to step through the client-side JavaScript. You should be able to find the point where the document library elements are rendered.
You can override Alfresco's client-side JavaScript components with your own components. Please put them in your own namespace to avoid collisions with Alfresco's.

I did it by commenting the {social} line in file share-documentlibrary-config.xml in share/src/alfresco/share-document-config
...
<metadata-templates>
<!-- Default (fallback) -->
<template id="default">
<line index="10" id="date">{date}{size}</line>
<line index="20" id="description" view="detailed">{description}</line>
<line index="30" id="tags" view="detailed">{tags}</line>
<line index="40" id="categories" view="detailed" evaluator="evaluator.doclib.metadata.hasCategories">{categories}</line> -->
<!-- <line index="50" id="social" view="detailed">{social}</line> -->
</template>
...
It works!

I'm not sure if I understand well your question - you're trying to hide some columns from particular view in alfresco explorer? If so, you need to edit /jsp/browse/browse.jsp file, but I think that's not a good idea. Maybe implementing your own NodePropertyResolver should be better way, have look at my older blogpost on this topic: http://www.shmoula.cz/adding-columns-to-custom-browse-jsp/

It looks like all of it is in: \opt\alfresco-4.0.d\tomcat\webapps\share\components\documentlibrary\documentlist.js
I think the trick is in this.registerRenderer("social"...) to return html before line 1981 (after favorites before likes) supposing you want to keep at least faorite

Related

NuxtServerInit: Add Google-Tag-Manager scripts to head an body

I use one nuxt instance to serve several domains with different languages. For each domain I use a different Google-Tag-Manager account.
Within nuxtServerInit I add to the store the hostname and also the Google-Tag-Manager ID.
Now I am looking for a way to add the Javascript snippets to my nuxt project.
This one needs to be in the head
<!-- Google Tag Manager -->
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXX);</script>
<!-- End Google Tag Manager -->
And that one at the beginning of the body
<!-- Google Tag Manager (noscript) -->
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-XXX"
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<!-- End Google Tag Manager (noscript) -->
My first idea is it to add this code programmatically to the document, but I don't know how.
Any suggestions or better idea to accomplish this?
I already tried to use the community solution. But it does not support different ID's.
Can anyone help implementing Nuxt.js Google Tag Manager with function based id
The main problem of this solution is the module which is used itself. A module is only called once but it needed to be something else to be called on each request.
This question is similar and helped me find the answer to this one.
Create a new plugin at plugins/gtm.js (or whatever you want to name it):
// plugins/gtm.js
let gtmKey;
// In this example I care about the page title but you can use other properties if you'd like
switch(document.title) {
case 'Title 1':
gtmKey = 'GTM-XXXXXX1';
break;
case 'Title 2':
gtmKey = 'GTM-XXXXXX2';
break;
default:
break;
}
export default () => {
if (!gtmKey) { // In case I have other pages not in the switch statement above
return;
}
/*
** Include Google Tag Manager
*/
(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer', gtmKey);
}
Then load it in from nuxt.config.js:
// nuxt.config.js
export default {
...
plugins: [{ src: '~/plugins/gtm.js', mode: 'client' }],
...
}
Note 1: I don't really like how I've hardcoded the titles into this plugin since an update of the title on one of my pages could break this without me knowing. Suggestions here are welcome.
Note 2: My eslint was complaining about no semicolon before the core GTM closure (just before the (function...) so I actually just disabled eslint for this whole file with // eslint-disable. You could just disable it for the line.

How to implement routing in polymer 3 using app-route

I was stuck with implementing routing in polymer 3. I followed the basic guide provided on app-route documentation. But on loading the web page., I don't see any component getting loaded. I checked in shadow DOM and don't see any DOM getting rendered. Not sure what I`m missing. Here is the code.
static get properties() {
return {
page:{
type: String,
reflectToAttribute: true,
observer: '_pageChanged'
}
};
}
_pageChanged(currentPage, oldPage){
console.log('CURRENT - ', currentPage);
console.log('OLD - ', oldPage);
switch(currentPage){
case 'home':
import('./home-comp.js').then()
break;
case 'about':
import('./about-comp.js').then()
break;
case 'contact':
import('./contact-comp.js').then()
break;
default:
this.page = 'home';
}
}
<app-route
route="{{route}}"
pattern="/:page"
data="{{routeData}}"
tail="{{subroute}}">
</app-route>
<home-comp name="home"></home-comp>
<about-comp name="about"></about-comp>
<contact-comp name="contact"></contact-comp>
I don`t see lot of documentation on Polymer 3 available for checking on issues. After going through Polymer default sample web application, shop., I came across some proper solution. I would like to share it with community for any any one in need of help for same.
You need to have
app-route: for implementation of routing
Iron pages: Basically page switcher to load required component on demand
In app-route.,
/* observer: Its a simple observer (basically a watch which holds current value & old value) that triggers whenever data changed in page property. We read the observer and calls a function to grab its earlier */
static get properties() {
return {
page:{
type: String,
reflectToAttribute: true,
observer: '_pageChanged'
}
};
}
_pageChanged(currentPage, oldPage){
console.log('CURRENT - ', currentPage);
console.log('OLD - ', oldPage);
switch(currentPage){
case 'home':
import('./home-comp.js').then()
break;
case 'about':
import('./about-comp.js').then()
break;
case 'contact':
import('./contact-comp.js').then()
break;
default:
this.page = 'home';
}
}
<!-- pattern: reads the href property., hence set the page (pattern="/:page") property in static get property to read its data -->
<app-route route="{{route}}" pattern="/:page" data="{{routeData}}" tail="{{subroute}}"></app-route>
<ul>
<li>
Home
</li>
<li>
About
</li>
<li>
Contact
</li>
</ul>
But for first time loading., page property doe not hold any value and throws undefined.
Hence we can use complex observer to observe such changes
static get observers(){
return ['_routerChanged(routeData.page)'];
}
_routerChanged(page){
console.log('CHANGED PAGE - ', page);
this.page = page || 'home';
}
Changed route data does not load the components unless we have iron-pages. Its basically a component switcher/loader on demand. Wrap all component in main-app under <iron-pages>
<!-- selected: Data binding helps to get changed page value -->
<!-- attr-for-selected: It reads value of name attr defined in each component & matches with selected value and triggers page switch -->
<!-- fallback-selection: for 404., page/component not found handling -->
<iron-pages selected="[[page]]" attr-for-selected="name" selected-attribute="visible" fallback-selection="404">
<home-comp name="home"></home-comp>
<about-comp name="about"></about-comp>
<contact-comp name="contact"></contact-comp>
</iron-pages>
Here is the complete guide for routing implementation in polymer 3 using app-route. Hope this helps click here

Create a new kind of site Alfresco 5.2

I'm trying to create a new type of site. When I'm creating a new one, only appears 1 type in the select: "Collaboration Site". I wish to add more options. For example "Custom Site", and for that site having predefined pages and dashboard. I've got a solution for this but it's modifying presets.xml and share-header.get.js files. I want to do the same by adding my own files, not editing existent files.
Thanks in advance.
You are correct to want to avoid touching out-of-the-box files that came with your Alfresco distribution. You can add new site presets through the standard extension mechanisms.
For example, you should be able to put a presets.xml file in web-extension/site-data/presets that describes your presets. It sounds like you already have an example of what that should look like.
Then, under web-extension/site-webscripts/org/alfresco/modules you can add create-site.get.js which has something like:
var sitePresets = [
{id: "site-dashboard", name: msg.get("title.collaborationSite")},
{id: "some-new-preset", name: msg.get("title.somePreset")}
];
model.sitePresets = sitePresets;
Note that this has changed slightly depending on which version of Alfresco you are using. For example, in 5.2, I don't believe you need to override create-site.get.js as shown above. Instead, you can use a Share extension module. Create a file called presets.xml in web-extension/site-data/extensions:
<extensions>
<modules>
<module>
<id>Additional Site Presets</id>
<version>1.0</version>
<auto-deploy>true</auto-deploy>
<evaluator type="default.extensibility.evaluator"/>
<customizations>
<customization>
<targetPackageRoot>org.alfresco</targetPackageRoot>
<sourcePackageRoot>com.someco.presets</sourcePackageRoot>
</customization>
<customization>
<targetPackageRoot>org.alfresco.share.pages</targetPackageRoot>
<sourcePackageRoot>com.someco.presets</sourcePackageRoot>
<alwaysApply>
<webscript>share-header</webscript>
</alwaysApply>
</customization>
</customizations>
</module>
</modules>
</extension>
With that extension in place you also have to override share-header.get.js. To do that, create a file with that name under web-extension/site-webscripts/com/someco/presets/share/header with this content:
var siteService = widgetUtils.findObject(model.jsonModel, "id", "SITE_SERVICE");
if (siteService && siteService.config)
{
siteService.config.additionalSitePresets = [
{ value: "some-site-preset", label: msg.get("title.someSite") }
];
}
This should add the new "some-site-preset" to the list you see when you create a new site in 5.2.

How to hide create site link for particular user

I am on Alfresco 4.2e Community Edition.I am able to restrict site creation for a particular group by modifying the following files.
In public-services-security-context.xml
org.alfresco.service.cmr.site.SiteService.createSite=ACL_METHOD.ROLE_ADMINISTRATOR,ACL_METHOD.GROUP_SITECREATORS
In sites.get.js and mysites.get.js I added this
var createSiteVisible = userHasGroup(user.name, 'SITECREATORS');
model.createSiteVisible = createSiteVisible;
function userHasGroup(username, group) {
var result = remote.call("/api/people/" + stringUtils.urlEncode(username) + "?groups=true");
if (result.status == 200 && result != "{}")
{
var user = eval('(' + result + ')');
var groups = new Array();
groups = user.groups;
var mygroups = "";
for (i=0; i<groups.length; i++)
{
if (groups[i].itemName == "GROUP_"+group || groups[i].itemName == "GROUP_ALFRESCO_ADMINISTRATORS"){
return true; // found group
}else{
mygroup = mygroups+groups[i].displayName;
}
}
return false;
}
else return false;
}
In my-sites.get.html.ftl and sites.get.html.ftl I modified the condition as
<#if createSiteVisible>
<span class="align-right yui-button-align">
<#if showCreateSite>
<span class="first-child">
<a href="#" id="${id}-createSite-button" class="theme-color-1">
<img src="${url.context}/res/components/images/site-16.png" style="vertical-align: text-bottom" />
${msg("link.createSite")}</a>
</span>
</#if>
</span>
</#if>
User is not able to create site now.But still I am getting create site link in header menu. How to hide create site for the users.
!user.isAdmin refers to admin user. What is the java script to refer a group?. Thank you
Here is a version that removes the link from the header, the dashlet, AND the welcome dashlet (don't forget about that one). Plus, it changes the underlying permissions to prevent circumventing the UI. In my version I restrict the create site capability to members of a "Site Creators" group.
I found a work around for this. First I hided the Create Site from header for everyone except admin. I added the following files.
I created file in shared/classes/alfresco/web-extension/site-data/extension/remove-create-site-extension.xml and typed
<extension>
<modules>
<module>
<id>Remove create site menu option for non admin users</id>
<version>1.0</version>
<customizations>
<customization>
<targetPackageRoot>org.alfresco.share.header</targetPackageRoot>
<sourcePackageRoot>ingen.header</sourcePackageRoot>
</customization>
<customization>
<targetPackageRoot>org.alfresco.components.dashlets</targetPackageRoot>
<sourcePackageRoot>ingen.dashlets</sourcePackageRoot>
</customization>
</customizations>
</module>
</modules>
</extension>
Then I created file in shared/classes/alfresco/web-extension/site-webscripts/ingen/header/share-header.get.js and added
//Find the "Sites" menu...
var sitesMenu = widgetUtils.findObject(model.jsonModel, "id", "HEADER_SITES_MENU");
if (sitesMenu != null) {
if (!user.isAdmin) {
sitesMenu.config.showCreateSite = false;
}
}
Then I created file shared/classes/alfresco/web-extension/site-webscripts/ingen/dashlets/my-sites.get.js
if (!user.isAdmin) {
model.showCreateSite = false;
}

Excluding bootstrap from specific routes in Meteor

I was hoping anyone could give some input on this,
I'm creating a meteor app in which I would like to use bootstrap to creating the admin environment, but have the visitor facing side using custom css. When I add the bootstrap package to my app using meteor it's available on every page, is there a way to restrict the loading of bootstrap to routes that are in '/admin' ?
When you add bootstrap package it's not possible. You can, however, add bootstrap csses to public directory and then load them in a header subtemplate that will only be rendered when you're in the dashboard.
EDIT
But then how would you go about creating seperate head templates?
Easy:
<head>
...
{{> adminHeader}}
...
</head>
<template name="adminHeader">
{{#if adminPage}}
... // Put links to bootstrap here
{{/if}}
</template>
Template.adminHeader.adminPage = function() {
return Session.get('adminPage');
}
Meteor.router.add({
'/admin': function() {
Session.set('adminPage', true);
...
}
});
DISCLAIMER: I am unsure of a 'meteor way' to do this, so here is how I would do it with plain JS.
jQuery
$("link[href='bootstrap.css']").remove();
JS - Credit to javascriptkit
function removejscssfile(filename, filetype){
var targetelement=(filetype=="js")? "script" : (filetype=="css")? "link" : "none" //determine element type to create nodelist from
var targetattr=(filetype=="js")? "src" : (filetype=="css")? "href" : "none" //determine corresponding attribute to test for
var allsuspects=document.getElementsByTagName(targetelement)
for (var i=allsuspects.length; i>=0; i--){ //search backwards within nodelist for matching elements to remove
if (allsuspects[i] && allsuspects[i].getAttribute(targetattr)!=null && allsuspects[i].getAttribute(targetattr).indexOf(filename)!=-1)
allsuspects[i].parentNode.removeChild(allsuspects[i]) //remove element by calling parentNode.removeChild()
}
}
removejscssfile("bootstrap.css", "css")
However, doing that would complete remove it from the page. I am not sure whether meteor would then try to readd it when a user goes to another page. If that does not automatically get readded, then you have an issue of bootstrap not being included when someone goes from the admin section to the main site, which would break the look of the site.
The way I would get around that would be to disable and enable the stylesheets:
Meteor.autorun(function(){
if(Session.get('nobootstrap')){
$("link[href='bootstrap.css']").disabled = true;
}else{
$("link[href='bootstrap.css']").disabled = false;
}
});
There my be other bootstrap resources which may need to be removed, take a look at what your page is loading.
To use jQuery in the same way but for the javascript files, remember to change link to script and href to src
From my tests, Meteor does not automatically re-add the files once they have been removed so you would need to find some way of re-adding them dynamically if you want the same user to be able to go back and forth between the main site and the admin site. Or simply if the http referrer to the main site is from the admin, force reload the page and then the bootstrap resources will load and everything will look pretty.
P.s. make sure you get the href correct for the jQuery version
If somebody is interested in including any js/css files, I've written a helper for it:
if (Meteor.isClient) {
// dynamic js / css include helper from public folder
Handlebars.registerHelper("INCLUDE_FILES", function(files) {
if (files != undefined) {
var array = files.split(',');
array.forEach(function(entity){
var regex = /(?:\.([^.]+))?$/;
var extension = regex.exec(entity)[1];
if(extension == "js"){
$('head').append('<script src="' + entity + '" data-dynamicJsCss type="text/javascript" ></script>');
} else if (extension == "css"){
$('head').append('<link href="' + entity + '" data-dynamicJsCss type="text/css" rel="stylesheet" />');
};
});
}
});
Router.onStop(function(){
$("[data-dynamicJsCss]").remove();
});
}
Then simply use:
{{INCLUDE_FILES '/css/html5reset.css, /js/test.js'}}
in any of your loaded templates :)

Resources