Skip to content

Commit 3998d5a

Browse files
committed
add clientlibs for allowing author to import paragraphs using dialog.
1 parent 8966f42 commit 3998d5a

File tree

5 files changed

+341
-0
lines changed

5 files changed

+341
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
3+
jcr:primaryType="sling:Folder"/>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
3+
jcr:primaryType="sling:Folder"/>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<jcr:root xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
3+
jcr:primaryType="cq:ClientLibraryFolder"
4+
categories="[core.wcm.components.contentfragment.v1.dialog]"/>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#base=js
2+
import-content.js
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,329 @@
1+
(function(window, $, channel, Granite, Coral) {
2+
"use strict";
3+
4+
// class of the edit dialog content
5+
var CLASS_EDIT_DIALOG = "cmp-contentfragment__editor";
6+
7+
// field selectors
8+
var SELECTOR_FRAGMENT_PATH = "[name='./fragmentPath']";
9+
var SELECTOR_ELEMENT_NAMES_CONTAINER = "[data-element-names-container='true']";
10+
var SELECTOR_ELEMENT_NAMES = "[data-granite-coral-multifield-name='./elementNames']";
11+
var SELECTOR_SINGLE_TEXT_ELEMENT = "[data-single-text-selector='true']";
12+
var SELECTOR_VARIATION_NAME = "[name='./variationName']";
13+
var SELECTOR_DISPLAY_MODE_RADIO_GROUP = "[data-display-mode-radio-group='true']";
14+
var SELECTOR_DISPLAY_MODE_CHECKED = "[name='./displayMode']:checked";
15+
var SELECTOR_PARAGRAPH_CONTENT_IMPORT_CONTROLS = ".cmp-contentfragment__editor-paragraph-content-import";
16+
var SELECTOR_PARAGRAPH_IMPORT_ACTION = ".js-contentfragment-importassets";
17+
var SELECTOR_PARAGRAPH_IMPORT_ACTION_INFO = ".paragraphcontentimportinfo";
18+
19+
// mode in which only one multiline text element could be selected for display
20+
var SINGLE_TEXT_DISPLAY_MODE = "singleText";
21+
22+
// ui helper
23+
var ui = $(window).adaptTo("foundation-ui");
24+
25+
// dialog texts
26+
var confirmationDialogTitle = Granite.I18n.get("Warning");
27+
var confirmationDialogMessage = Granite.I18n.get("Please confirm replacing the current content fragment and its configuration");
28+
var confirmationDialogCancel = Granite.I18n.get("Cancel");
29+
var confirmationDialogConfirm = Granite.I18n.get("Confirm");
30+
var errorDialogTitle = Granite.I18n.get("Error");
31+
var errorDialogMessage = Granite.I18n.get("Failed to load the elements of the selected content fragment");
32+
33+
// the fragment path field (foundation autocomplete)
34+
var fragmentPath;
35+
36+
// the paragraph controls (field set)
37+
var contentImportControls;
38+
// the tab containing paragraph control
39+
var contentImportControlsTab;
40+
41+
// keeps track of the current fragment path
42+
var currentFragmentPath;
43+
44+
var editDialog;
45+
46+
var elementsController;
47+
48+
var importAssetsAction;
49+
var importAssetsActionInfo;
50+
51+
/**
52+
* A class which encapsulates the logic related to element selectors and variation name selector.
53+
*/
54+
var ElementsController = function() {
55+
this._updateFields();
56+
};
57+
58+
/**
59+
* Updates the member fields of this class according to current dom of dialog.
60+
*/
61+
ElementsController.prototype._updateFields = function() {
62+
this.elementImportContentAction = editDialog.querySelector(SELECTOR_PARAGRAPH_IMPORT_ACTION);
63+
this.singleTextSelector = editDialog.querySelector(SELECTOR_SINGLE_TEXT_ELEMENT);
64+
};
65+
66+
/**
67+
* Disable all the fields of this controller.
68+
*/
69+
ElementsController.prototype.toggleFields = function() {
70+
console.log(["this.singleTextSelector",this.singleTextSelector]);
71+
if (this.singleTextSelector == null) {
72+
this.disableFields();
73+
} else if (this.singleTextSelector.value === "") {
74+
this.disableFields();
75+
} else {
76+
this.enableFields();
77+
}
78+
};
79+
80+
/**
81+
* Disable all the fields of this controller.
82+
*/
83+
ElementsController.prototype.disableFields = function() {
84+
if (this.elementImportContentAction && this.singleTextSelector.value === "") {
85+
this.elementImportContentAction.setAttribute("disabled", "");
86+
}
87+
};
88+
89+
/**
90+
* Enable all the fields of this controller.
91+
*/
92+
ElementsController.prototype.enableFields = function() {
93+
if (this.elementImportContentAction && this.singleTextSelector.value !== "") {
94+
this.elementImportContentAction.removeAttribute("disabled");
95+
}
96+
};
97+
98+
/**
99+
* Resets all the fields of this controller.
100+
*/
101+
ElementsController.prototype.resetFields = function() {
102+
};
103+
104+
/**
105+
* Creates an http request object for retrieving fragment's element names or variation names and returns it.
106+
*
107+
* @param {String} displayMode - displayMode parameter for element name request. Should be "singleText" or "multi"
108+
* @param {String} type - type of request. It can have the following values -
109+
* 1. "variation" for getting variation names
110+
* 2. "elements" for getting element names
111+
* @returns {Object} the resulting request
112+
*/
113+
ElementsController.prototype.prepareRequest = function(displayMode, type) {
114+
if (typeof displayMode === "undefined") {
115+
displayMode = editDialog.querySelector(SELECTOR_DISPLAY_MODE_CHECKED).value;
116+
}
117+
var data = {
118+
fragmentPath: fragmentPath.value,
119+
displayMode: displayMode
120+
};
121+
var url;
122+
if (type === "variation") {
123+
url = Granite.HTTP.externalize(this.variationNamePath) + ".html";
124+
} else if (type === "elements") {
125+
url = Granite.HTTP.externalize(this.elementsContainerPath) + ".html";
126+
}
127+
var request = $.get({
128+
url: url,
129+
data: data
130+
});
131+
return request;
132+
};
133+
134+
/**
135+
* Retrieve element names and update the current element names with the retrieved data.
136+
*
137+
* @param {String} displayMode - selected display mode of the component
138+
*/
139+
ElementsController.prototype.fetchAndUpdateElementsHTML = function(displayMode) {
140+
var elementNamesRequest = this.prepareRequest(displayMode, "elements");
141+
var self = this;
142+
// wait for requests to load
143+
$.when(elementNamesRequest).then(function(result) {
144+
self._updateElementsHTML(result);
145+
}, function() {
146+
// display error dialog if one of the requests failed
147+
ui.prompt(errorDialogTitle, errorDialogMessage, "error");
148+
});
149+
};
150+
151+
/**
152+
* Updates inner html of element container.
153+
*
154+
* @param {String} html - outerHTML value for elementNamesContainer
155+
*/
156+
ElementsController.prototype._updateElementsHTML = function(html) {
157+
//this.elementNamesContainer.innerHTML = $(html)[0].innerHTML;
158+
this._updateFields();
159+
};
160+
161+
/**
162+
* Updates dom of element container with the passed dom. If the passed dom is multifield, the current multifield
163+
* template would be replaced with the dom's template otherwise the dom would used as the new singleTextSelector
164+
* member.
165+
*
166+
* @param {HTMLElement} dom - new dom
167+
*/
168+
ElementsController.prototype._updateElementsDOM = function(dom) {
169+
if (dom.tagName === "CORAL-MULTIFIELD") {
170+
// replace the element names multifield's template
171+
this.elementNames.template = dom.template;
172+
} else {
173+
dom.value = this.singleTextSelector.value;
174+
this.singleTextSelector.parentNode.replaceChild(dom, this.singleTextSelector);
175+
this.singleTextSelector = dom;
176+
this.singleTextSelector.removeAttribute("disabled");
177+
}
178+
this._updateFields();
179+
};
180+
181+
/**
182+
* Updates dom of variation name select dropdown.
183+
*
184+
* @param {HTMLElement} dom - dom for variation name dropdown
185+
*/
186+
ElementsController.prototype._updateVariationDOM = function(dom) {
187+
// replace the variation name select, keeping its value
188+
dom.value = this.variationName.value;
189+
this.variationName.parentNode.replaceChild(dom, this.variationName);
190+
this.variationName = dom;
191+
this.variationName.removeAttribute("disabled");
192+
this._updateFields();
193+
};
194+
195+
/**
196+
* Executes after the fragment path has changed. Shows a confirmation dialog to the user if the current
197+
* configuration is to be reset and updates the fields to reflect the newly selected content fragment.
198+
*/
199+
function onFragmentPathChange() {
200+
console.log(["onFragmentPathChange",fragmentPath]);
201+
202+
// if the fragment was reset (i.e. the fragment path was deleted)
203+
if (!fragmentPath.value) {
204+
currentFragmentPath = fragmentPath.value;
205+
elementsController.disableFields();
206+
} else {
207+
console.log(["onFragmentPathChange",fragmentPath]);
208+
currentFragmentPath = fragmentPath.value;
209+
elementsController.enableFields();
210+
}
211+
212+
213+
}
214+
215+
/**
216+
* Compares two arrays containing select items, returning true if the arrays have the same size and all contained
217+
* items have the same value and label.
218+
*
219+
* @param {Array} a1 - first array to compare
220+
* @param {Array} a2 - second array to compare
221+
* @returns {Boolean} true if both arrays are equal, false otherwise
222+
*/
223+
function itemsAreEqual(a1, a2) {
224+
// verify that the arrays have the same length
225+
if (a1.length !== a2.length) {
226+
return false;
227+
}
228+
for (var i = 0; i < a1.length; i++) {
229+
var item1 = a1[i];
230+
var item2 = a2[i];
231+
if (item1.attributes.value.value !== item2.attributes.value.value ||
232+
item1.textContent !== item2.textContent) {
233+
// the values or labels of the current items didn't match
234+
return false;
235+
}
236+
}
237+
return true;
238+
}
239+
240+
// Toggles the display of paragraph control tab depending on display mode
241+
function updateParagraphImportTabState() {
242+
243+
var displayMode = editDialog.querySelector(SELECTOR_DISPLAY_MODE_CHECKED).value;
244+
if (displayMode === SINGLE_TEXT_DISPLAY_MODE) {
245+
contentImportControlsTab.hidden = false;
246+
updateParagraphImportState();
247+
} else {
248+
contentImportControlsTab.hidden = true;
249+
}
250+
251+
}
252+
253+
// Toggles the display of paragraph control tab depending on display mode
254+
function updateParagraphImportState() {
255+
elementsController._updateFields();
256+
elementsController.toggleFields();
257+
}
258+
259+
/**
260+
* Initializes the dialog after it has loaded.
261+
*/
262+
channel.on("foundation-contentloaded", function(e) {
263+
if (e.target.getElementsByClassName(CLASS_EDIT_DIALOG).length > 0) {
264+
Coral.commons.ready(e.target, function(dialog) {
265+
initialize(dialog);
266+
});
267+
}
268+
});
269+
270+
271+
function initialize(dialog) {
272+
// get path of component being edited
273+
editDialog = dialog;
274+
// get the fields
275+
fragmentPath = dialog.querySelector(SELECTOR_FRAGMENT_PATH);
276+
277+
contentImportControls = dialog.querySelector(SELECTOR_PARAGRAPH_CONTENT_IMPORT_CONTROLS);
278+
//get Content Import tab
279+
contentImportControlsTab = dialog.querySelector("coral-tabview").tabList.items.getAll()[2];
280+
// paragraphControlsTab = dialog.querySelector("coral-tabview").tabList.items.getAll()[2];
281+
282+
importAssetsAction = dialog.querySelector(SELECTOR_PARAGRAPH_IMPORT_ACTION);
283+
importAssetsActionInfo = dialog.querySelector(SELECTOR_PARAGRAPH_IMPORT_ACTION_INFO);
284+
285+
console.log(["fragmentPath",fragmentPath]);
286+
console.log(["contentImportControls",contentImportControls]);
287+
console.log(["contentImportControlsTab",contentImportControlsTab]);
288+
console.log(["importAssetsAction",importAssetsAction]);
289+
console.log(["importAssetsActionInfo",importAssetsActionInfo]);
290+
291+
292+
// initialize state variables
293+
currentFragmentPath = fragmentPath.value;
294+
elementsController = new ElementsController();
295+
296+
console.log(["importAssetsActionInfo",elementsController.singleTextSelector]);
297+
298+
// disable add button and variation name if no content fragment is currently set
299+
if (!currentFragmentPath) {
300+
elementsController.disableFields();
301+
}
302+
// register change listener
303+
$(fragmentPath).on("foundation-field-change", onFragmentPathChange);
304+
305+
//update state when Single Element is updated
306+
$(document).on("change", SELECTOR_SINGLE_TEXT_ELEMENT, updateParagraphImportState);
307+
308+
//update state when Single or Multiple is changed
309+
var $radioGroup = $(dialog).find(SELECTOR_DISPLAY_MODE_RADIO_GROUP);
310+
$radioGroup.on("change", function(e) {
311+
updateParagraphImportTabState();
312+
});
313+
314+
//when activated allow asset import
315+
if (importAssetsAction) {
316+
317+
$(document).on("click", ".js-contentfragment-importassets", function (e) {
318+
console.log("import assets.");
319+
});
320+
321+
console.log("activated on: "+ importAssetsAction);
322+
}
323+
324+
console.log("aemdesign content fragment dialog extension loaded")
325+
326+
}
327+
328+
329+
})(window, jQuery, jQuery(document), Granite, Coral);

0 commit comments

Comments
 (0)