Skip to content

Commit ab1e33a

Browse files
authored
Merge pull request #11 from cybtachyon/feature/drupal-uploads
Feature/drupal uploads
2 parents 800455f + 0b06b9b commit ab1e33a

11 files changed

+803
-22
lines changed

js/jsoneditor.min.js.map

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

js/patternkit.jsoneditor.js

Lines changed: 237 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//@ sourceURL=patternkit.jsoneditor.js
1+
/*globals JSONEditor:false */
22
/**
33
* @file
44
* Provides Twig Pattern Library Editing Functionality.
@@ -13,13 +13,29 @@
1313
*/
1414

1515
(function ($, Drupal) {
16+
'use strict';
17+
1618
Drupal.behaviors.patternkitEditor = {
1719
attach: function (context, settings) {
20+
if (!window.JSONEditor) {
21+
return;
22+
}
23+
24+
// Ajax command response to allow updating Editor field values.
25+
Drupal.AjaxCommands.prototype.patternkitEditorUpdate = function(ajax, response, status) {
26+
window.patternkitEditor.getEditor(response.selector).setValue(response.value);
27+
};
28+
29+
// This forces Drupal to re-attach
30+
$(window).on('dialog:afterclose', function (e, dialog, $element) {
31+
Drupal.attachBehaviors($(':root'), settings);
32+
});
33+
1834
var $target = $('#editor-shadow-injection-target', context);
1935
$target.once('patternkit-editor').each(function () {
2036
var shadow = this.attachShadow({mode: 'open'});
21-
var theme_js = drupalSettings.patternkitEditor.themeJS;
22-
if (typeof theme_js == 'string') {
37+
var theme_js = settings.patternkitEditor.themeJS;
38+
if (typeof theme_js === 'string') {
2339
theme_js = [theme_js];
2440
}
2541
for (var i = 0; theme_js && i < theme_js.length; i++) {
@@ -28,33 +44,229 @@
2844
script_element.src = theme_js[i];
2945
document.getElementsByTagName('head')[0].appendChild(script_element);
3046
}
31-
if (drupalSettings.patternkitEditor.themeStylesheet) {
32-
var editor_dom = '<link rel="stylesheet" id="theme_stylesheet" href="' + drupalSettings.patternkitEditor.themeStylesheet + '">';
47+
var editor_dom = '';
48+
if (settings.patternkitEditor.themeStylesheet) {
49+
editor_dom = '<link rel="stylesheet" id="theme_stylesheet" href="' + settings.patternkitEditor.themeStylesheet + '">';
3350
}
3451
// @todo Re-eval with this shadow dom webfont bug: https://bugs.chromium.org/p/chromium/issues/detail?id=336876
35-
if (drupalSettings.patternkitEditor.iconStylesheet) {
52+
if (settings.patternkitEditor.iconStylesheet) {
3653
var icons_element = document.createElement('link');
3754
icons_element.rel = "stylesheet";
3855
icons_element.id = "icon_stylesheet";
39-
icons_element.href = drupalSettings.patternkitEditor.iconStylesheet;
56+
icons_element.href = settings.patternkitEditor.iconStylesheet;
4057
document.getElementsByTagName('head')[0].appendChild(icons_element);
41-
editor_dom += '<link rel="stylesheet" id="icon_stylesheet" href="' + drupalSettings.patternkitEditor.iconStylesheet + '">';
58+
editor_dom += '<link rel="stylesheet" id="icon_stylesheet" href="' + settings.patternkitEditor.iconStylesheet + '">';
4259
}
4360
editor_dom += '<div id="editor_holder"></div>';
4461
shadow.innerHTML += editor_dom;
4562

4663
var data = {};
47-
data.schema = JSON.parse(drupalSettings.patternkitEditor.schemaJson);
48-
data.starting = JSON.parse(drupalSettings.patternkitEditor.startingJson);
64+
data.schema = JSON.parse(settings.patternkitEditor.schemaJson);
65+
data.starting = JSON.parse(settings.patternkitEditor.startingJson);
4966

50-
JSONEditor.defaults.options.theme = drupalSettings.patternkitEditor.theme;
51-
JSONEditor.defaults.options.iconlib = drupalSettings.patternkitEditor.icons;
67+
JSONEditor.defaults.options.theme = settings.patternkitEditor.theme;
68+
JSONEditor.defaults.options.iconlib = settings.patternkitEditor.icons;
5269
JSONEditor.defaults.options.keep_oneof_values = false;
5370
JSONEditor.defaults.options.disable_edit_json = true;
5471
JSONEditor.defaults.options.disable_collapse = false;
5572
JSONEditor.defaults.options.collapse = false;
5673
JSONEditor.defaults.options.ajax = true;
5774

75+
// Drupal Image Editor.
76+
JSONEditor.defaults.editors.drupal_image = JSONEditor.AbstractEditor.extend({
77+
getNumColumns: function() {
78+
return 4;
79+
},
80+
build: function() {
81+
var self = this;
82+
this.title = this.header = this.label = this.theme.getFormInputLabel(this.getTitle(), this.isRequired());
83+
// Don't show uploader if this is readonly
84+
if(!this.schema.readOnly && !this.schema.readonly) {
85+
this.urlfield = this.theme.getFormInputField('text');
86+
this.button = this.getButton(this.path + '-media', 'upload', Drupal.t('Select/Upload Media'));
87+
// @todo: Add support for multiple file/image URL editors.
88+
var media_library_settings = 'media_library_opener_id=patternkit.opener.jsonlibrary' +
89+
'&' + encodeURIComponent('media_library_allowed_types[0]') + '=image' +
90+
'&media_library_selected_type=image' +
91+
'&media_library_remaining=1' +
92+
'&' + encodeURIComponent('media_library_opener_parameters[field_widget_id]') + '=' + this.path;
93+
94+
this.button.addEventListener('click', function(e) {
95+
e.preventDefault();
96+
e.stopPropagation();
97+
98+
this.dialog = Drupal.dialog($('#drupal-modal').append($('<span>', {id: 'patternkit_image_dialog_loading'})), { title: Drupal.t('Choose Image'), width: 900, height: 900 }).showModal();
99+
Drupal.ajax({ url: settings.patternkitEditor.imageUrl + '?' + media_library_settings, base: 'drupal-modal', wrapper: 'patternkit_image_dialog_loading' }).execute();
100+
});
101+
}
102+
103+
var description = this.schema.description;
104+
if (!description) {
105+
description = '';
106+
}
107+
108+
this.preview = this.theme.getFormInputDescription(description);
109+
this.container.appendChild(this.preview);
110+
111+
this.control = this.theme.getFormControl(this.label, this.urlfield||this.input, this.preview);
112+
this.container.appendChild(this.control);
113+
114+
if (this.button) {
115+
this.container.appendChild(this.button);
116+
}
117+
118+
window.requestAnimationFrame(function() {
119+
if (self.value) {
120+
var img = document.createElement('img');
121+
img.style.maxWidth = '100%';
122+
img.style.maxHeight = '100px';
123+
img.onload = function (event) {
124+
self.preview.appendChild(img);
125+
};
126+
img.onerror = function(error) {
127+
window.console.error('upload error', error);
128+
};
129+
img.src = self.container.querySelector('a').href;
130+
}
131+
});
132+
133+
},
134+
refreshPreview: function() {
135+
if (this.last_preview === this.preview_value) {
136+
return;
137+
}
138+
this.last_preview = this.preview_value;
139+
140+
this.preview.innerHTML = '';
141+
142+
if (!this.preview_value) {
143+
return;
144+
}
145+
146+
var self = this;
147+
148+
var mime = this.preview_value.match(/^data:([^;,]+)[;,]/);
149+
if (mime) {
150+
mime = mime[1];
151+
}
152+
else {
153+
mime = 'unknown';
154+
}
155+
156+
var file = this.urlfield.files[0];
157+
158+
this.preview.innerHTML = '<strong>Type:</strong> '+mime+', <strong>Size:</strong> '+file.size+' bytes';
159+
if(mime.substr(0,5)==="image") {
160+
this.preview.innerHTML += '<br>';
161+
var img = document.createElement('img');
162+
img.style.maxWidth = '100%';
163+
img.style.maxHeight = '100px';
164+
img.src = this.preview_value;
165+
this.preview.appendChild(img);
166+
}
167+
168+
this.preview.innerHTML += '<br>';
169+
var uploadButton = this.getButton('Upload', 'upload', 'Upload');
170+
this.preview.appendChild(uploadButton);
171+
uploadButton.addEventListener('click',function(event) {
172+
event.preventDefault();
173+
174+
uploadButton.setAttribute("disabled", "disabled");
175+
self.theme.removeInputError(self.uploader);
176+
177+
if (self.theme.getProgressBar) {
178+
self.progressBar = self.theme.getProgressBar();
179+
self.preview.appendChild(self.progressBar);
180+
}
181+
182+
self.jsoneditor.options.upload(self.path, file, {
183+
success: function(url) {
184+
self.setValue(url);
185+
186+
if (self.parent) {
187+
self.parent.onChildEditorChange(self);
188+
}
189+
else {
190+
self.jsoneditor.onChange();
191+
}
192+
193+
if (self.progressBar) {
194+
self.preview.removeChild(self.progressBar);
195+
}
196+
uploadButton.removeAttribute("disabled");
197+
},
198+
failure: function(error) {
199+
self.theme.addInputError(self.uploader, error);
200+
if (self.progressBar) {
201+
self.preview.removeChild(self.progressBar);
202+
}
203+
uploadButton.removeAttribute("disabled");
204+
},
205+
updateProgress: function(progress) {
206+
if (self.progressBar) {
207+
if (progress) {
208+
self.theme.updateProgressBar(self.progressBar, progress);
209+
}
210+
else {
211+
self.theme.updateProgressBarUnknown(self.progressBar);
212+
}
213+
}
214+
}
215+
});
216+
});
217+
218+
if(this.jsoneditor.options.auto_upload || this.schema.options.auto_upload) {
219+
uploadButton.dispatchEvent(new MouseEvent('click'));
220+
this.preview.removeChild(uploadButton);
221+
}
222+
},
223+
enable: function() {
224+
if(!this.always_disabled) {
225+
if(this.urlfield) {
226+
this.urlfield.disabled = false;
227+
}
228+
this._super();
229+
}
230+
},
231+
disable: function(always_disabled) {
232+
if(always_disabled) {
233+
this.always_disabled = true;
234+
}
235+
if(this.urlfield) {
236+
this.urlfield.disabled = true;
237+
}
238+
this._super();
239+
},
240+
setValue: function(val) {
241+
if(this.value !== val) {
242+
this.value = val;
243+
this.urlfield.value = this.value;
244+
this.onChange();
245+
}
246+
},
247+
destroy: function() {
248+
if(this.preview && this.preview.parentNode) {
249+
this.preview.parentNode.removeChild(this.preview);
250+
}
251+
if(this.title && this.title.parentNode) {
252+
this.title.parentNode.removeChild(this.title);
253+
}
254+
if(this.input && this.input.parentNode) {
255+
this.input.parentNode.removeChild(this.input);
256+
}
257+
if(this.urlfield && this.urlfield.parentNode) {
258+
this.urlfield.parentNode.removeChild(this.urlfield);
259+
}
260+
261+
this._super();
262+
}
263+
});
264+
JSONEditor.defaults.resolvers.unshift(function(schema) {
265+
if (schema.type === 'string' && schema.format === 'image') {
266+
return 'drupal_image';
267+
}
268+
});
269+
58270
// Override how references are resolved.
59271
JSONEditor.prototype._loadExternalRefs = function (schema, callback) {
60272
var self = this;
@@ -73,7 +285,7 @@
73285
waiting++;
74286

75287
var r = new XMLHttpRequest();
76-
var uri = drupalSettings.path.baseUrl + url + '/schema';
288+
var uri = settings.path.baseUrl + url + '/schema';
77289

78290
r.open("GET", uri, true);
79291
r.onreadystatechange = function () {
@@ -125,37 +337,41 @@
125337
if (typeof data.starting === 'object' && !$.isEmptyObject(data.starting)) {
126338
config.startval = data.starting;
127339
}
128-
var editor = new JSONEditor($target[0].shadowRoot.getElementById('editor_holder'), config);
340+
window.patternkitEditor = new JSONEditor($target[0].shadowRoot.getElementById('editor_holder'), config);
129341
JSONEditor.plugins.sceditor.emoticonsEnabled = false;
130342
var saveSchema = function () {
131-
$('#schema_instance_config').val(JSON.stringify(editor.getValue()));
343+
$('#schema_instance_config').val(JSON.stringify(window.patternkitEditor.getValue()));
132344
if (window.M) {
133345
window.M.updateTextFields();
134346
}
135347
};
136348

137-
editor.on('ready', function () {
349+
window.patternkitEditor.on('ready', function () {
138350
if (window.M) {
139351
window.M.updateTextFields();
140352
}
141353
});
142-
editor.on('change', saveSchema);
354+
window.patternkitEditor.on('change', saveSchema);
143355
$('[data-drupal-selector="edit-actions-submit"]').on('input', function (e) {
144356
saveSchema();
145357
});
146358
// Drupal triggers Ajax submit via input events.
147359
// This is before allowing other events, so we need to add a pre-hook
148360
// to trigger the editor update with latest field values.
149361
// @TODO Add handling for AJAX errors and re-attach.
362+
var beforeSubmitHandler = Drupal.Ajax.prototype.beforeSubmit;
150363
Drupal.Ajax.prototype.beforeSubmit = function(formValues, element, options) {
151-
editor.disable();
364+
if ( $(element).parents("#editor_holder").length !== 1 ) {
365+
return beforeSubmitHandler(formValues, element, options);
366+
}
367+
window.patternkitEditor.disable();
152368
saveSchema();
153369
for (var v = 0; v < formValues.length; v++) {
154-
if (formValues[v]['name'] === 'settings[instance_config]') {
155-
formValues[v]['value'] = JSON.stringify(editor.getValue());
370+
if (formValues[v].name === 'settings[instance_config]') {
371+
formValues[v].value = JSON.stringify(window.patternkitEditor.getValue());
156372
}
157373
}
158-
editor.destroy();
374+
window.patternkitEditor.destroy();
159375
};
160376
});
161377
}

0 commit comments

Comments
 (0)