Files
interblue.pl/modules/x13allegro/views/js/jquery.grideditor.js
2024-10-25 14:16:28 +02:00

650 lines
23 KiB
JavaScript

(function( $ ){
$.fn.gridEditor = function( options ) {
var self = this;
var grideditor = self.data('grideditor');
var MAX_ROWS = 100;
var MAX_IMAGES = 16;
/** Methods **/
if (arguments[0] == 'getHtml') {
if (grideditor) {
grideditor.deinit(true);
var html = self.html();
grideditor.init(true);
return html;
} else {
return self.html();
}
}
/** Initialize plugin */
self.each(function(baseIndex, baseElem) {
baseElem = $(baseElem);
var settings = $.extend({
'custom_filter' : '',
'content_types' : ['tinymce'],
'source_textarea' : ''
}, options);
// Elems
var canvas,
mainControls,
addRowGroup,
htmlTextArea
;
var colClasses = ['col-md-'];
var curColClassIndex = 0; // Index of the column class we are manipulating currently
var curMaxImage = 0;
var curMaxRow = 0;
var imageSelectorOptions = '<option value="product_image" selected="selected">{product_image}</option>' +
'<option value="manufacturer_image">{manufacturer_image}</option>';
var imageSelector;
additionalImages = $.parseJSON(additionalImages);
var additionalImagesNumber = x13allegro_template_images_nb || 5;
for (var i = 0; i < additionalImagesNumber; i++) {
imageSelectorOptions += '<option value="additional_image_' + (i+1) + '" ' +
(typeof additionalImages[i] !== 'undefined' && additionalImages[i] ? '' : 'disabled="disabled"') +
'>{additional_image_' + (i+1) + '}</option>';
}
imageSelector = '<select class="ge-select-image" name="image_selector">' + imageSelectorOptions + '</select>';
var imagePlaceholder =
'<div class="ge-image-placeholder">' +
'<div class="ge-image-placeholder-inner">' +
'<span class="glyphicon glyphicon-image"></span>' +
'<span class="ge-image-selector" data-selector="product_image" data-number="0">{product_image}</span>' + imageSelector +
'</div>' +
'</div>';
// Copy html to sourceElement if a source textarea is given
if (settings.source_textarea) {
var sourceEl = $(settings.source_textarea);
sourceEl.addClass('ge-html-output');
htmlTextArea = sourceEl;
if (sourceEl.val()) {
baseElem.html(sourceEl.val());
}
}
// Wrap content if it is non-bootstrap
if (baseElem.children().length && !baseElem.find('div.row').length) {
var children = baseElem.children();
var newRow = $('<div class="row"><div class="col-md-12"/></div>').appendTo(baseElem);
newRow.find('.col-md-12').append(children);
}
setup();
init();
function setup() {
/* Setup canvas */
canvas = baseElem.addClass('ge-canvas');
if (typeof htmlTextArea === 'undefined' || !htmlTextArea.length) {
htmlTextArea = $('<textarea class="ge-html-output"/>').insertBefore(canvas);
}
/* Create main controls*/
mainControls = $('<div class="ge-mainControls" />').insertBefore(htmlTextArea);
var wrapper = $('<div class="ge-wrapper ge-top" />').appendTo(mainControls);
// Add row
addRowGroup = $('<div class="btn-group" />').appendTo(wrapper);
var btn = $('<a class="btn btn-default" />')
.attr('title', 'Dodaj nowy wiersz')
.on('click', function() {
if (curMaxRow < MAX_ROWS) {
++curMaxRow;
var row = createRow().appendTo(canvas);
init();
row.find('.ge-default').trigger('click');
}
else {
showErrorMessage('Osiągnięto maksymalną liczbę wierszy na opis oferty.');
}
})
.appendTo(addRowGroup)
;
btn.append('<span class="glyphicon glyphicon-plus-sign"/>');
btn.append('<span>Dodaj nowy wiersz</span>');
if (!settings.source_textarea.val().trim().length) {
btn.trigger('click');
}
// Make controls fixed on scroll
var $window = $(window);
$window.on('scroll', function(e) {
if (
$window.scrollTop() > mainControls.offset().top &&
$window.scrollTop() < canvas.offset().top + canvas.height()
) {
if (wrapper.hasClass('ge-top')) {
wrapper
.css({
left: wrapper.offset().left,
width: wrapper.outerWidth()
})
.removeClass('ge-top')
.addClass('ge-fixed')
;
}
} else {
if (wrapper.hasClass('ge-fixed')) {
wrapper
.css({ left: '', width: '' })
.removeClass('ge-fixed')
.addClass('ge-top')
;
}
}
});
/* Init RTE on click */
canvas.on('click', '.ge-content', function(e) {
var rte = getRTE($(this).data('ge-content-type'));
if (rte) {
rte.init(settings, $(this));
}
});
canvas.on('change', 'select[name="image_selector"]', function () {
var val = $(this).val();
var oldVal = $(this).parent().find('.ge-image-selector').attr('data-selector');
if (val !== 'product_image' && canvas.find('.ge-image-selector[data-selector="' + val + '"]').length > 0) {
var duplicateEl = canvas.find('.ge-image-selector[data-selector="' + val + '"]').eq(0);
duplicateEl.data('selector', oldVal).attr('data-selector', oldVal).text('{'+ oldVal +'}');
duplicateEl.parent().find('select[name="image_selector"]').val(oldVal);
}
$(this).parent().find('.ge-image-selector').data('selector', val).attr('data-selector', val).text('{'+ val +'}');
});
}
function reset(callback) {
deinit(true);
init(true);
calcImages();
callback();
}
function init(reset) {
runFilter(true);
canvas.addClass('ge-editing');
addAllColClasses();
//wrapContent();
if (typeof reset === 'undefined') {
createRowControls();
initImageSelectors();
}
makeSortable();
switchLayout(curColClassIndex);
}
function deinit(reset) {
canvas.removeClass('ge-editing');
var contents = canvas.find('.ge-content').each(function() {
var content = $(this);
getRTE(content.data('ge-content-type')).deinit(settings, content);
});
if (typeof reset === 'undefined') {
canvas.find('.ge-tools-drawer').remove();
}
removeSortable();
runFilter();
}
function createRowControls() {
canvas.find('.row').each(function() {
var row = $(this);
var activeBtn = false;
if (row.find('> .ge-tools-drawer').length) {
activeBtn = row.find('> .ge-tools-drawer > a.active').index();
row.find('> .ge-tools-drawer').remove();
}
var drawer = $('<div class="ge-tools-drawer" />').prependTo(row);
createTool(drawer, 'Usuń wiersz', 'pull-right', 'glyphicon-trash', function() {
if (window.confirm('Delete row?')) {
row.slideUp(function() {
--curMaxRow;
row.remove();
});
}
});
createTool(drawer, 'Przenieś', 'ge-move pull-right', 'glyphicon-move');
createTool(drawer, 'Tekst', 'ge-default', 'glyphicon-text', function()
{
var el = $(this);
if (!el.hasClass('active'))
{
row.find('.ge-tools-drawer a').removeClass('active');
row.find('.column').remove();
row.append(createColumn(12));
reset(function() {
el.addClass('active');
});
}
});
createTool(drawer, 'Zdjęcie', '', 'glyphicon-image', function()
{
var el = $(this);
if (!el.hasClass('active'))
{
row.find('.ge-tools-drawer a').removeClass('active');
row.find('.column').remove();
row.append(createColumn(12, true));
reset(function() {
el.addClass('active');
});
}
});
createTool(drawer, 'Tekst i zdjęcie', '', 'glyphicon-text-image', function()
{
var el = $(this);
if (!el.hasClass('active'))
{
row.find('.ge-tools-drawer a').removeClass('active');
row.find('.column').remove();
row.append(createColumn(6)).append(createColumn(6, true));
reset(function() {
el.addClass('active');
});
}
});
createTool(drawer, 'Zdjęcie i tekst', '', 'glyphicon-image-text', function()
{
var el = $(this);
if (!el.hasClass('active'))
{
row.find('.ge-tools-drawer a').removeClass('active');
row.find('.column').remove();
row.append(createColumn(6, true)).append(createColumn(6));
reset(function() {
el.addClass('active');
});
}
});
createTool(drawer, 'Dwa zdjęcia', '', 'glyphicon-image-image', function()
{
var el = $(this);
if (!el.hasClass('active'))
{
row.find('.ge-tools-drawer a').removeClass('active');
row.find('.column').remove();
row.append(createColumn(6, true)).append(createColumn(6, true));
reset(function() {
el.addClass('active');
});
}
});
if (activeBtn) {
row.find('> .ge-tools-drawer > a').eq(activeBtn).addClass('active');
}
});
}
function createTool(drawer, title, className, iconClass, eventHandlers) {
var tool = $('<a title="' + title + '" class="' + className + '"><span class="glyphicon ' + iconClass + '"></span></a>')
.appendTo(drawer)
;
if (typeof eventHandlers == 'function') {
tool.on('click', eventHandlers);
}
if (typeof eventHandlers == 'object') {
$.each(eventHandlers, function(name, func) {
tool.on(name, func);
});
}
}
function createDetails(container, cssClasses) {
var detailsDiv = $('<div class="ge-details" />');
$('<input class="ge-id" />')
.attr('placeholder', 'id')
.val(container.attr('id'))
.attr('title', 'Set a unique identifier')
.appendTo(detailsDiv)
;
var classGroup = $('<div class="btn-group" />').appendTo(detailsDiv);
cssClasses.forEach(function(rowClass) {
var btn = $('<a class="btn btn-xs btn-default" />')
.html(rowClass.label)
.attr('title', rowClass.title ? rowClass.title : 'Toggle "' + rowClass.label + '" styling')
.toggleClass('active btn-primary', container.hasClass(rowClass.cssClass))
.on('click', function() {
btn.toggleClass('active btn-primary');
container.toggleClass(rowClass.cssClass, btn.hasClass('active'));
})
.appendTo(classGroup)
;
});
return detailsDiv;
}
function addAllColClasses() {
canvas.find('.column, div[class*="col-"]').each(function() {
var col = $(this);
var size = 2;
var sizes = getColSizes(col);
if (sizes.length) {
size = sizes[0].size;
}
var elemClass = col.attr('class');
colClasses.forEach(function(colClass) {
if (elemClass.indexOf(colClass) == -1) {
col.addClass(colClass + size);
}
});
col.addClass('column');
});
}
/**
* Return the column size for colClass, or a size from a different
* class if it was not found.
* Returns null if no size whatsoever was found.
*/
function getColSize(col, colClass) {
var sizes = getColSizes(col);
for (var i = 0; i < sizes.length; i++) {
if (sizes[i].colClass == colClass) {
return sizes[i].size;
}
}
if (sizes.length) {
return sizes[0].size;
}
return null;
}
function getColSizes(col) {
var result = [];
colClasses.forEach(function(colClass) {
var re = new RegExp(colClass + '(\\d+)', 'i');
if (re.test(col.attr('class'))) {
result.push({
colClass: colClass,
size: parseInt(re.exec(col.attr('class'))[1])
});
}
});
return result;
}
function setColSize(col, colClass, size) {
var re = new RegExp('(' + colClass + '(\\d+))', 'i');
var reResult = re.exec(col.attr('class'));
if (reResult && parseInt(reResult[2]) !== size) {
col.switchClass(reResult[1], colClass + size, 50);
} else {
col.addClass(colClass + size);
}
}
function makeSortable() {
canvas.find('.row').sortable({
items: '> .column',
connectWith: '.ge-canvas .row',
handle: '> .ge-tools-drawer .ge-move',
start: sortStart,
helper: 'clone'
});
canvas.add(canvas.find('.column')).sortable({
items: '> .row, > .ge-content',
connectsWith: '.ge-canvas, .ge-canvas .column',
handle: '> .ge-tools-drawer .ge-move',
start: sortStart,
helper: 'clone'
});
function sortStart(e, ui) {
ui.placeholder.css({ height: ui.item.outerHeight()});
}
}
function removeSortable() {
canvas.add(canvas.find('.column')).add(canvas.find('.row')).sortable('destroy');
}
function createRow() {
return $('<div class="row" />');
}
function createColumn(size, image) {
var column = $('<div/>').addClass(colClasses.map(function(c) { return c + size; }).join(' '));
if (typeof image !== 'undefined' && image) {
column.append(imagePlaceholder);
} else {
column.append(createDefaultContentWrapper().html(
getRTE(settings.content_types[0]).initialContent)
);
}
return column;
}
function calcImages()
{
curMaxImage = 0;
canvas.find('.row').each(function(index, row) {
$(row).find('.column').each(function(index, col)
{
var image = $(col).find('.ge-image-placeholder');
if (image.length)
{
++curMaxImage;
if (curMaxImage > MAX_IMAGES) {
showErrorMessage('Osiągnięto maksymalną ilość zdjęć na opis oferty.');
$(row).find('a.ge-default').trigger('click');
} else {
image.find('.ge-image-selector').data('number', curMaxImage).attr('data-number', curMaxImage);
}
}
});
});
}
/**
* Run custom content filter on init and deinit
*/
function runFilter(isInit) {
if (settings.custom_filter.length) {
$.each(settings.custom_filter, function(key, func) {
if (typeof func == 'string') {
func = window[func];
}
func(canvas, isInit);
});
}
}
/**
* Wrap column content in <div class="ge-content"> where neccesary
*/
function wrapContent() {
canvas.find('.column').each(function() {
var col = $(this);
var contents = $();
col.children().each(function() {
var child = $(this);
if (child.is('.row, .ge-tools-drawer, .ge-content, .ge-image-placeholder')) {
doWrap(contents);
} else {
contents = contents.add(child);
}
});
doWrap(contents);
});
}
function doWrap(contents) {
if (contents.length) {
var container = createDefaultContentWrapper().insertAfter(contents.last());
contents.appendTo(container);
contents = $();
}
}
function createDefaultContentWrapper() {
return $('<div/>')
.addClass('ge-content ge-content-type-' + settings.content_types[0])
.attr('data-ge-content-type', settings.content_types[0])
;
}
function initImageSelectors() {
canvas.find('.column .ge-image-placeholder').each(function(index, image)
{
if (typeof $(image).find('.ge-image-selector').attr('data-selector') === 'undefined') {
$(image).find('.ge-image-selector').data('selector', 'product_image').attr('data-selector', 'product_image').text('{product_image}');
}
if ($(image).find('select[name="image_selector"]').length == 0) {
$(image).find('.ge-image-selector').after(imageSelector);
}
// change disabled selector
var val = $(image).find('.ge-image-selector').attr('data-selector');
if ($(image).find('select[name="image_selector"] option[value="' + val + '"]').attr('disabled')) {
val = 'product_image';
}
$(image).find('select[name="image_selector"]').val(val);
});
calcImages();
}
function switchLayout(colClassIndex) {
curColClassIndex = colClassIndex;
var layoutClasses = ['ge-layout-desktop', 'ge-layout-tablet', 'ge-layout-phone'];
layoutClasses.forEach(function(cssClass, i) {
canvas.toggleClass(cssClass, i == colClassIndex);
});
}
function getRTE(type) {
return $.fn.gridEditor.RTEs[type];
}
function clamp(input, min, max) {
return Math.min(max, Math.max(min, input));
}
baseElem.data('grideditor', {
init: init,
deinit: deinit
});
});
return self;
};
$.fn.gridEditor.RTEs = {};
})( jQuery );
(function() {
$.fn.gridEditor.RTEs.tinymce = {
init: function(settings, contentAreas) {
if (!window.tinymce) {
console.error('tinyMCE not available! Make sure you loaded the tinyMCE js file.');
}
if (!contentAreas.tinymce) {
console.error('tinyMCE jquery integration not available! Make sure you loaded the jquery integration plugin.');
}
var self = this;
contentAreas.each(function() {
var contentArea = $(this);
if (!contentArea.hasClass('active')) {
if (contentArea.html() == self.initialContent) {
contentArea.html('');
}
contentArea.addClass('active');
var configuration = $.extend(
{},
(settings.tinymce && settings.tinymce.config ? settings.tinymce.config : {}),
{
inline: true,
oninit: function(editor) {
// Bring focus to text field
$('#' + editor.settings.id).focus();
// Call original oninit function, if one was passed in the config
var callback;
try {
callback = settings.tinymce.config.oninit;
} catch (err) {
// No callback passed
}
if (callback) {
callback.call(this);
}
}
}
);
var tiny = contentArea.tinymce(configuration);
}
});
},
deinit: function(settings, contentAreas) {
contentAreas.filter('.active').each(function() {
var contentArea = $(this);
var tiny = contentArea.tinymce();
if (tiny) {
tiny.remove();
}
contentArea
.removeClass('active')
.removeAttr('id')
.removeAttr('style')
.removeAttr('spellcheck')
;
});
},
initialContent: '<p>Dodaj tekst...</p>'
};
})();