Skip to content

Commit

Permalink
WIP: Refactor pat-relateditems so all logic goes outside the templa…
Browse files Browse the repository at this point in the history
…te. refs gh-1306
  • Loading branch information
frapell committed Apr 27, 2023
1 parent be3025c commit 792dbb7
Show file tree
Hide file tree
Showing 10 changed files with 229 additions and 107 deletions.
74 changes: 74 additions & 0 deletions src/core/utils.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import $ from "jquery";
import logging from "@patternslib/patternslib/src/core/logging";
import _ from "lodash";

const logger = logging.getLogger("core utils");

Expand Down Expand Up @@ -438,6 +439,78 @@ const resolveIcon = async function (name) {
}
};

/**
* This is for avoiding CSP issues with underscore's template
*
* More details: https://github.com/plone/mockup/issues/1306
*
* Implementation was taken from https://github.com/silvermine/undertemplate/blob/master/src/index.js
*
*/
var template = function (text, userSettings) {
const ESCAPE_ENTITIES = {
'&': '&',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#x27;', // eslint-disable-line quotes
'`': '&#x60;',
};

const DEFAULT_SETTINGS = {
escape: /<%-([\s\S]+?)%>/g,
interpolate: /<%=([\s\S]+?)%>/g,
};

let parts = [],
index = 0,
settings = _.defaults({}, userSettings, DEFAULT_SETTINGS),
regExpPattern, matcher;

regExpPattern = [
settings.escape.source,
settings.interpolate.source,
];
matcher = new RegExp(regExpPattern.join('|') + '|$', 'g');

text.replace(matcher, function(match, escape, interpolate, offset) {
parts.push(text.slice(index, offset));
index = offset + match.length;

if (escape) {
parts.push(function(data) {
return escapeHTML(getValue(escape, data));
});
} else if (interpolate) {
parts.push(getValue.bind(null, interpolate));
}
});

return function(data) {
return _.reduce(parts, function(str, part) {
return str + (_.isFunction(part) ? part(data) : part);
}, '');
};

function escapeHTML(str) {
let pattern = '(?:' + _.keys(ESCAPE_ENTITIES).join('|') + ')',
testRegExp = new RegExp(pattern),
replaceRegExp = new RegExp(pattern, 'g');

if (testRegExp.test(str)) {
return str.replace(replaceRegExp, function(match) {
return ESCAPE_ENTITIES[match];
});
}

return str;
}

function getValue(path, data) {
return _.get(data, _.trim(path), '');
}
}

export default {
bool: bool,
escapeHTML: escapeHTML,
Expand All @@ -453,4 +526,5 @@ export default {
resolveIcon: resolveIcon,
setId: setId,
storage: storage,
template: template,
};
124 changes: 109 additions & 15 deletions src/pat/relateditems/relateditems.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ export default Base.extend({
resultTemplateSelector: null,
selectionTemplateSelector: null,
toolbarTemplateSelector: null,
toolbarNotAutoTemplateSelector: null,
toolbarRecentlyUsedTemplateSelector: null,
toolbarFavoritesTemplateSelector: null,
toolbarUploadTemplateSelector: null,

// needed
multiple: true,
Expand Down Expand Up @@ -114,7 +118,7 @@ export default Base.extend({
one_level_up: _t("Go one level up"),
});
options._item = item;
return _.template(template)(options);
return utils.template(template)(options);
},

setAjax() {
Expand Down Expand Up @@ -230,9 +234,9 @@ export default Base.extend({

async renderToolbar() {
const path = this.currentPath;
let html;

const parts = path.split("/");
let html = "";
let itemPath = "";
let itemsHtml = "";
for (const part of parts) {
Expand All @@ -255,30 +259,67 @@ export default Base.extend({
let recentlyUsedHtml = "";
if (this.options.recentlyUsed) {
const recentlyUsed = this.recentlyUsed(true); // filter out only those items which can actually be selected
for (const item of recentlyUsed.reverse()) {
for (let item of recentlyUsed.reverse()) {
// reverse to get newest first.
if (item['imgsrc'] === undefined) {
item['imgsrc'] = '';
}

if (item['getURL'] && (item['getIcon'] || item['portal_type'] === "Image")){
item['imgsrc'] = '<img src="' + item['getURL'] + '/@@images/image/tile">'
}

var klass = [
'pat-relateditems-recentlyused-title',
item['portal_type'] ? ' contenttype-' + item['portal_type'].toLowerCase() : '',
item['review_state'] ? ' state-' + item['review_state'] : ''
]

item['itemclass'] = klass.join(' ')

recentlyUsedHtml =
recentlyUsedHtml + this.applyTemplate("recentlyused", item);
}
}

html = this.applyTemplate("toolbar", {
if (this.options.mode !=='auto'){
html += this.applyTemplate('toolbarNotAuto', {
searchModeClass: (this.options.mode=='search') ? 'btn-primary':'btn-default',
searchModeText: _t('Search'),
browseModeClass: (this.options.mode=='browse') ? 'btn-primary':'btn-default',
browseModeText: _t('Browse'),
});
}

html += this.applyTemplate("toolbar", {
items: itemsHtml,
favItems: favoritesHtml,
favText: _t("Favorites"),
searchText: _t("Current path:"),
searchModeText: _t("Search"),
browseModeText: _t("Browse"),
recentlyUsedItems: recentlyUsedHtml,
recentlyUsedText: _t("Recently Used"),
icon_root: await utils.resolveIcon("house-fill"),
icon_recently_used: await utils.resolveIcon("grid-fill"),
icon_favorites: await utils.resolveIcon("star-fill"),
icon_upload: await utils.resolveIcon("cloud-arrow-up"),
upload: this.options.upload,
upload_text: _t("Upload"),
});

if (recentlyUsedHtml != "") {
html += this.applyTemplate('toolbarRecentlyUsed', {
recentlyUsedItems: recentlyUsedHtml,
recentlyUsedText: _t('Recently Used'),
icon_recently_used: await utils.resolveIcon("grid-fill"),
});
}

if (this.options.favorites.length > 0){
html += this.applyTemplate('toolbarFavorites', {
favItems: favoritesHtml,
favText: _t('Favorites'),
icon_favorites: await utils.resolveIcon("star-fill"),
});
}

if (this.options.upload){
html += this.applyTemplate('toolbarUpload', {
icon_upload: await utils.resolveIcon("cloud-arrow-up"),
upload_text: _t("Upload"),
});
}

this.$toolbar.html(html);

// unbind mouseup event from select2 to override the behavior:
Expand Down Expand Up @@ -512,6 +553,9 @@ export default Base.extend({
this.resultTemplate = (await import("./templates/result.xml")).default; // prettier-ignore
this.selectionTemplate = (await import("./templates/selection.xml")).default; // prettier-ignore
this.toolbarTemplate = (await import("./templates/toolbar.xml")).default; // prettier-ignore
this.toolbarNotAutoTemplate = (await import("./templates/toolbar_not_auto.xml")).default; // prettier-ignore
this.toolbarRecentlyUsedTemplate = (await import("./templates/toolbar_recently_used.xml")).default; // prettier-ignore
this.toolbarFavoritesTemplate = (await import("./templates/toolbar_favorites.xml")).default; // prettier-ignore

this.browsing = this.options.mode !== "search";

Expand Down Expand Up @@ -542,6 +586,13 @@ export default Base.extend({
},
item
);
if (item['imgsrc'] === undefined) {
item['imgsrc'] = '';
}

if (item['getURL'] && (item['getIcon'] || item['portal_type'] === "Image")){
item['imgsrc'] = '<div class="pat-relateditems-item-image"><img src="' + item['getURL'] + '/@@images/image/thumb"></div>'
}

// activate petterns on the result set.
const $selection = $(this.applyTemplate("selection", item));
Expand Down Expand Up @@ -569,6 +620,8 @@ export default Base.extend({
item = $.extend(
true,
{
one_level_up: _t("Go one level up"),
open_folder: _t("Open folder"),
Title: "",
getIcon: "",
getURL: "",
Expand All @@ -577,9 +630,16 @@ export default Base.extend({
iconLevelUp: icon_level_up,
iconLevelDown: icon_level_down,
path: "",
result_path: "",
portal_type: "",
review_state: "",
selectable: false,
div_class: 'pat-relateditems-result',
span_title_class: '',
not_one_level_up_open_a: '',
not_one_level_up_close_a: '',
browse_folder_a: '',
append_if_image: '',
},
item
);
Expand All @@ -588,6 +648,40 @@ export default Base.extend({
// do not allow already selected items to be selected again.
item.selectable = false;
}

if (item['oneLevelUp']) {
item['div_class'] += ' one-level-up';
item['result_path'] = item['currentPath'];
} else {
let klass = [
'pat-relateditems-result-select',
item['selectable'] ? 'selectable' : ''
]
item['not_one_level_up_open_a'] += '<a class="' + klass.join(' ') + '" data-path="' + item['path'] + '">';
item['not_one_level_up_close_a'] += '</a>';
item['result_path'] = item['path'];
}

let klass = [
'pat-relateditems-result-title',
item['portal_type'] ? 'contenttype-' + item['portal_type'].toLowerCase() : '',
item['review_state'] ? 'state-' + item['review_state'] : ''
]
item['span_title_class'] = klass.join(' ')

if (item['is_folderish']){
item['browse_folder_a'] = '<a class="pat-relateditems-result-browse" data-path="' +
item['path'] + '" title="'+ (item['oneLevelUp'] ? item['one_level_up'] : item['open_folder']) +
'">'+ (item['oneLevelUp'] ? item['iconLevelUp'] : item['iconLevelDown']) + '</a>';
}

if (item['getURL'] && (item['getIcon'] || item['portal_type'] === "Image")) {
item['append_if_image'] += item['not_one_level_up_open_a'];
item['append_if_image'] += '<div class="pat-relateditems-result-image"><img src="'+
item['getURL'] + '/@@images/image/thumb" /></div>';
item['append_if_image'] += item['not_one_level_up_close_a']
}

const result = $(this.applyTemplate("result", item));

$(".pat-relateditems-result-select", result).on("click", (event) => {
Expand Down
12 changes: 2 additions & 10 deletions src/pat/relateditems/templates/recentlyused.xml
Original file line number Diff line number Diff line change
@@ -1,15 +1,7 @@
<li class="pat-relateditems-recentlyused dropdown-item">
<a class="pat-relateditems-recentlyused-select" data-uid="<%- UID %>">
<span
class="pat-relateditems-recentlyused-title <%- portal_type ? 'contenttype-' + portal_type.toLowerCase() : '' %> <%- review_state ? 'state-' + review_state : '' %>"
title="<%- portal_type %>">
<%- Title %>
</span>
<span class="<%- itemclass %>" title="<%- portal_type %>"><%- Title %></span>
<span class="pat-relateditems-recentlyused-path"><%- path %></span>
<% if (getURL && (getIcon || portal_type === "Image")) { %>
<span class="pat-relateditems-recentlyused-image">
<img src="<%- getURL %>/@@images/image/tile" />
</span>
<% } %>
<span class="pat-relateditems-recentlyused-image"><%= imgsrc %></span>
</a>
</li>
41 changes: 9 additions & 32 deletions src/pat/relateditems/templates/result.xml
Original file line number Diff line number Diff line change
@@ -1,41 +1,18 @@
<div class="pat-relateditems-result <%- oneLevelUp ? 'one-level-up' : '' %>">
<div class="<%- div_class %>">
<div class="pat-relateditems-result-browse-wrapper">
<% if (!oneLevelUp) { %>
<a
class="pat-relateditems-result-select<%- selectable ? ' selectable' : '' %><%- oneLevelUp ? ' one-level-up' : '' %>"
data-path="<%- path %>">
<% } %>
<%= not_one_level_up_open_a %>

<div class="pat-relateditems-result-info">
<span
class="pat-relateditems-result-title <%- portal_type ? 'contenttype-' + portal_type.toLowerCase() : '' %> <%- review_state ? 'state-' + review_state : '' %>"
class="<%- span_title_class %>"
title="<%- portal_type %>">
<%- Title %>
</span>
<span class="pat-relateditems-result-path"><%- oneLevelUp ? currentPath : path %></span>
<span class="pat-relateditems-result-path"><%- result_path %></span>
</div>
<% if (is_folderish) { %>
<a
class="pat-relateditems-result-browse"
data-path="<%- path %>"
title="<%- oneLevelUp ? one_level_up : open_folder %>">
<%= oneLevelUp ? iconLevelUp : iconLevelDown %>
</a>
<% } %>
<% if (!oneLevelUp) { %>
</a>
<% } %>
<%= browse_folder_a %>
<%= not_one_level_up_close_a %>

</div>
<% if (getURL && (getIcon || portal_type === "Image")) { %>
<% if (!oneLevelUp) { %>
<a
class="pat-relateditems-result-select<%- selectable ? ' selectable' : '' %><%- oneLevelUp ? ' one-level-up' : '' %>"
data-path="<%- path %>">
<% } %>
<div class="pat-relateditems-result-image">
<img src="<%- getURL %>/@@images/image/thumb" />
</div>
<% if (!oneLevelUp) { %>
</a>
<% } %>
<% } %>
<%= append_if_image %>
</div>
6 changes: 1 addition & 5 deletions src/pat/relateditems/templates/selection.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,5 @@
</span>
<span class="pat-relateditems-item-path"><%- path %></span>
</div>
<% if (getURL && (getIcon || portal_type === "Image")) { %>
<div class="pat-relateditems-item-image">
<img src="<%- getURL %>/@@images/image/thumb" />
</div>
<% } %>
<%= imgsrc %>
</div>
Loading

0 comments on commit 792dbb7

Please sign in to comment.