generator-craftskeleton
Version:
Starterkit for Craft CMS 2.x (Multi-Environment Configs with HeartyConfig, Gulp, and Bower for Dependencie-Management) made by interpunkt. ag
763 lines (643 loc) • 23.1 kB
JavaScript
(function($){
//
// Due to how we're handling Matrix-SuperTable-Matrix, we need to load up a slightly modified MatrixInput.js
// see getParsedBlockHtml()
//
Craft.MatrixInputAlt = Garnish.Base.extend(
{
id: null,
blockTypes: null,
blockTypesByHandle: null,
inputNamePrefix: null,
inputIdPrefix: null,
maxBlocks: null,
showingAddBlockMenu: false,
addBlockBtnGroupWidth: null,
addBlockBtnContainerWidth: null,
$container: null,
$blockContainer: null,
$addBlockBtnContainer: null,
$addBlockBtnGroup: null,
$addBlockBtnGroupBtns: null,
blockSort: null,
blockSelect: null,
totalNewBlocks: 0,
init: function(id, blockTypes, inputNamePrefix, maxBlocks)
{
this.id = id
this.blockTypes = blockTypes;
this.inputNamePrefix = inputNamePrefix;
this.inputIdPrefix = Craft.formatInputId(this.inputNamePrefix);
this.maxBlocks = maxBlocks;
this.$container = $('#'+this.id);
this.$blockContainer = this.$container.children('.blocks');
this.$addBlockBtnContainer = this.$container.children('.buttons');
this.$addBlockBtnGroup = this.$addBlockBtnContainer.children('.btngroup');
this.$addBlockBtnGroupBtns = this.$addBlockBtnGroup.children('.btn');
this.$addBlockMenuBtn = this.$addBlockBtnContainer.children('.menubtn');
this.setNewBlockBtn();
this.blockTypesByHandle = {};
for (var i = 0; i < this.blockTypes.length; i++)
{
var blockType = this.blockTypes[i];
this.blockTypesByHandle[blockType.handle] = blockType;
}
var $blocks = this.$blockContainer.children(),
collapsedBlocks = Craft.MatrixInputAlt.getCollapsedBlockIds();
this.blockSort = new Garnish.DragSort($blocks, {
handle: '> .actions > .move',
axis: 'y',
filter: $.proxy(function()
{
// Only return all the selected items if the target item is selected
if (this.blockSort.$targetItem.hasClass('sel'))
{
return this.blockSelect.getSelectedItems();
}
else
{
return this.blockSort.$targetItem;
}
}, this),
collapseDraggees: true,
magnetStrength: 4,
helperLagBase: 1.5,
helperOpacity: 0.9,
onSortChange: $.proxy(function() {
this.blockSelect.resetItemOrder();
}, this)
});
this.blockSelect = new Garnish.Select(this.$blockContainer, $blocks, {
multi: true,
vertical: true,
handle: '> .checkbox, > .titlebar',
checkboxMode: true
});
for (var i = 0; i < $blocks.length; i++)
{
var $block = $($blocks[i]),
id = $block.data('id');
// Is this a new block?
var newMatch = (typeof id == 'string' && id.match(/new(\d+)/));
if (newMatch && newMatch[1] > this.totalNewBlocks)
{
this.totalNewBlocks = parseInt(newMatch[1]);
}
var block = new MatrixBlock(this, $block);
if (block.id && $.inArray(''+block.id, collapsedBlocks) != -1)
{
block.collapse();
}
}
this.addListener(this.$addBlockBtnGroupBtns, 'click', function(ev)
{
var type = $(ev.target).data('type');
this.addBlock(type);
});
new Garnish.MenuBtn(this.$addBlockMenuBtn,
{
onOptionSelect: $.proxy(function(option)
{
var type = $(option).data('type');
this.addBlock(type);
}, this)
});
this.updateAddBlockBtn();
this.addListener(this.$container, 'resize', 'setNewBlockBtn');
this.addListener(this.$container, 'showNewBlockBtn', 'showNewBlockBtn');
},
// CRAWF - An added event handler to allow Super Table field to trigger the 'responsive'
// add block button. setNewBlockBtn is a little overkill and unperformant...
showNewBlockBtn: function() {
this.$addBlockBtnGroup.addClass('hidden');
this.$addBlockMenuBtn.removeClass('hidden');
this.showingAddBlockMenu = true;
},
setNewBlockBtn: function()
{
// Do we know what the button group width is yet?
if (!this.addBlockBtnGroupWidth)
{
this.addBlockBtnGroupWidth = this.$addBlockBtnGroup.outerWidth(true);
if (!this.addBlockBtnGroupWidth)
{
return;
}
}
// Only check if the container width has resized
if (this.addBlockBtnContainerWidth !== (this.addBlockBtnContainerWidth = this.$addBlockBtnContainer.outerWidth(true)))
{
if (this.addBlockBtnGroupWidth > this.addBlockBtnContainerWidth)
{
if (!this.showingAddBlockMenu)
{
this.$addBlockBtnGroup.addClass('hidden');
this.$addBlockMenuBtn.removeClass('hidden');
this.showingAddBlockMenu = true;
}
}
else
{
if (this.showingAddBlockMenu)
{
this.$addBlockMenuBtn.addClass('hidden');
this.$addBlockBtnGroup.removeClass('hidden');
this.showingAddBlockMenu = false;
// Because Safari is awesome
if (navigator.userAgent.indexOf('Safari') !== -1)
{
Garnish.requestAnimationFrame($.proxy(function() {
this.$addBlockBtnGroup.css('opacity', 0.99);
Garnish.requestAnimationFrame($.proxy(function() {
this.$addBlockBtnGroup.css('opacity', '');
}, this));
}, this));
}
}
}
}
},
canAddMoreBlocks: function()
{
return (!this.maxBlocks || this.$blockContainer.children().length < this.maxBlocks);
},
updateAddBlockBtn: function()
{
if (this.canAddMoreBlocks())
{
this.$addBlockBtnGroup.removeClass('disabled');
this.$addBlockMenuBtn.removeClass('disabled');
}
else
{
this.$addBlockBtnGroup.addClass('disabled');
this.$addBlockMenuBtn.addClass('disabled');
}
},
addBlock: function(type, $insertBefore)
{
if (!this.canAddMoreBlocks())
{
return;
}
this.totalNewBlocks++;
var id = 'new'+this.totalNewBlocks;
var html =
'<div class="matrixblock" data-id="'+id+'">' +
'<input type="hidden" name="'+this.inputNamePrefix+'['+id+'][type]" value="'+type+'"/>' +
'<input type="hidden" name="'+this.inputNamePrefix+'['+id+'][enabled]" value="1"/>' +
'<div class="titlebar">' +
'<div class="blocktype">'+this.getBlockTypeByHandle(type).name+'</div>' +
'<div class="preview"></div>' +
'</div>' +
'<div class="checkbox" title="'+Craft.t('Select')+'"></div>' +
'<div class="actions">' +
'<div class="status off" title="'+Craft.t('Disabled')+'"></div>' +
'<a class="settings icon menubtn" title="'+Craft.t('Actions')+'" role="button"></a> ' +
'<div class="menu">' +
'<ul class="padded">' +
'<li><a data-icon="collapse" data-action="collapse">'+Craft.t('Collapse')+'</a></li>' +
'<li class="hidden"><a data-icon="expand" data-action="expand">'+Craft.t('Expand')+'</a></li>' +
'<li><a data-icon="disabled" data-action="disable">'+Craft.t('Disable')+'</a></li>' +
'<li class="hidden"><a data-icon="enabled" data-action="enable">'+Craft.t('Enable')+'</a></li>' +
'</ul>' +
'<hr class="padded"/>' +
'<ul class="padded">';
for (var i = 0; i < this.blockTypes.length; i++)
{
var blockType = this.blockTypes[i];
html += '<li><a data-icon="+" data-action="add" data-type="'+blockType.handle+'">'+Craft.t('Add {type} above', { type: blockType.name })+'</a></li>';
}
html +=
'</ul>' +
'<hr class="padded"/>' +
'<ul class="padded">' +
'<li><a data-icon="remove" data-action="delete">'+Craft.t('Delete')+'</a></li>' +
'</ul>' +
'</div>' +
'<a class="move icon" title="'+Craft.t('Reorder')+'" role="button"></a> ' +
'</div>' +
'</div>';
var $block = $(html);
if ($insertBefore)
{
$block.insertBefore($insertBefore);
}
else
{
$block.appendTo(this.$blockContainer);
}
var $fieldsContainer = $('<div class="fields"/>').appendTo($block),
bodyHtml = this.getParsedBlockHtml(this.blockTypesByHandle[type].bodyHtml, id),
footHtml = this.getParsedBlockHtml(this.blockTypesByHandle[type].footHtml, id);
$(bodyHtml).appendTo($fieldsContainer);
// Animate the block into position
$block.css(this.getHiddenBlockCss($block)).velocity({
opacity: 1,
'margin-bottom': 10
}, 'fast', $.proxy(function()
{
$block.css('margin-bottom', '');
Garnish.$bod.append(footHtml);
Craft.initUiElements($fieldsContainer);
new MatrixBlock(this, $block);
this.blockSort.addItems($block);
this.blockSelect.addItems($block);
this.updateAddBlockBtn();
Garnish.requestAnimationFrame(function()
{
// Scroll to the block
Garnish.scrollContainerToElement($block);
});
}, this));
},
getBlockTypeByHandle: function(handle)
{
for (var i = 0; i < this.blockTypes.length; i++)
{
if (this.blockTypes[i].handle == handle)
{
return this.blockTypes[i];
}
}
},
collapseSelectedBlocks: function()
{
this.callOnSelectedBlocks('collapse');
},
expandSelectedBlocks: function()
{
this.callOnSelectedBlocks('expand');
},
disableSelectedBlocks: function()
{
this.callOnSelectedBlocks('disable');
},
enableSelectedBlocks: function()
{
this.callOnSelectedBlocks('enable');
},
deleteSelectedBlocks: function()
{
this.callOnSelectedBlocks('selfDestruct');
},
callOnSelectedBlocks: function(fn)
{
for (var i = 0; i < this.blockSelect.$selectedItems.length; i++)
{
this.blockSelect.$selectedItems.eq(i).data('block')[fn]();
}
},
getHiddenBlockCss: function($block)
{
return {
opacity: 0,
marginBottom: -($block.outerHeight())
};
},
getParsedBlockHtml: function(html, id)
{
if (typeof html == 'string')
{
// CRAWF
return html.replace(/__BLOCK2__/g, id);
}
else
{
return '';
}
}
},
{
collapsedBlockStorageKey: 'Craft-'+Craft.siteUid+'.MatrixInputAlt.collapsedBlocks',
getCollapsedBlockIds: function()
{
if (typeof localStorage[Craft.MatrixInputAlt.collapsedBlockStorageKey] == 'string')
{
return Craft.filterArray(localStorage[Craft.MatrixInputAlt.collapsedBlockStorageKey].split(','));
}
else
{
return [];
}
},
setCollapsedBlockIds: function(ids)
{
localStorage[Craft.MatrixInputAlt.collapsedBlockStorageKey] = ids.join(',');
},
rememberCollapsedBlockId: function(id)
{
if (typeof Storage !== 'undefined')
{
var collapsedBlocks = Craft.MatrixInputAlt.getCollapsedBlockIds();
if ($.inArray(''+id, collapsedBlocks) == -1)
{
collapsedBlocks.push(id);
Craft.MatrixInputAlt.setCollapsedBlockIds(collapsedBlocks);
}
}
},
forgetCollapsedBlockId: function(id)
{
if (typeof Storage !== 'undefined')
{
var collapsedBlocks = Craft.MatrixInputAlt.getCollapsedBlockIds(),
collapsedBlocksIndex = $.inArray(''+id, collapsedBlocks);
if (collapsedBlocksIndex != -1)
{
collapsedBlocks.splice(collapsedBlocksIndex, 1);
Craft.MatrixInputAlt.setCollapsedBlockIds(collapsedBlocks);
}
}
}
});
var MatrixBlock = Garnish.Base.extend(
{
matrix: null,
$container: null,
$titlebar: null,
$fieldsContainer: null,
$previewContainer: null,
$actionMenu: null,
$collapsedInput: null,
isNew: null,
id: null,
collapsed: false,
init: function(matrix, $container)
{
this.matrix = matrix;
this.$container = $container;
this.$titlebar = $container.children('.titlebar');
this.$previewContainer = this.$titlebar.children('.preview');
this.$fieldsContainer = $container.children('.fields');
this.$container.data('block', this);
this.id = this.$container.data('id');
this.isNew = (!this.id || (typeof this.id == 'string' && this.id.substr(0, 3) == 'new'));
var $menuBtn = this.$container.find('> .actions > .settings'),
menuBtn = new Garnish.MenuBtn($menuBtn);
this.$actionMenu = menuBtn.menu.$container;
menuBtn.menu.settings.onOptionSelect = $.proxy(this, 'onMenuOptionSelect');
// Was this block already collapsed?
if (Garnish.hasAttr(this.$container, 'data-collapsed'))
{
this.collapse();
}
this.addListener(this.$titlebar, 'dblclick', function(ev)
{
ev.preventDefault();
this.toggle();
});
},
toggle: function()
{
if (this.collapsed)
{
this.expand();
}
else
{
this.collapse(true);
}
},
collapse: function(animate)
{
if (this.collapsed)
{
return;
}
this.$container.addClass('collapsed');
var previewHtml = '',
$fields = this.$fieldsContainer.children();
for (var i = 0; i < $fields.length; i++)
{
var $field = $($fields[i]),
$inputs = $field.children('.input').find('select,input[type!="hidden"],textarea,.label'),
inputPreviewText = '';
for (var j = 0; j < $inputs.length; j++)
{
var $input = $($inputs[j]);
if ($input.hasClass('label'))
{
var $maybeLightswitchContainer = $input.parent().parent();
if ($maybeLightswitchContainer.hasClass('lightswitch') && (
($maybeLightswitchContainer.hasClass('on') && $input.hasClass('off')) ||
(!$maybeLightswitchContainer.hasClass('on') && $input.hasClass('on'))
))
{
continue;
}
var value = $input.text();
}
else
{
var value = Craft.getText(Garnish.getInputPostVal($input));
}
if (value instanceof Array)
{
value = value.join(', ');
}
if (value)
{
value = Craft.trim(value);
if (value)
{
if (inputPreviewText)
{
inputPreviewText += ', ';
}
inputPreviewText += value;
}
}
}
if (inputPreviewText)
{
previewHtml += (previewHtml ? ' <span>|</span> ' : '') + inputPreviewText;
}
}
this.$previewContainer.html(previewHtml);
this.$fieldsContainer.velocity('stop');
this.$container.velocity('stop');
if (animate)
{
this.$fieldsContainer.velocity('fadeOut', { duration: 'fast' });
this.$container.velocity({ height: 17 }, 'fast');
}
else
{
this.$previewContainer.show();
this.$fieldsContainer.hide();
this.$container.css({ height: 17 });
}
setTimeout($.proxy(function() {
this.$actionMenu.find('a[data-action=collapse]:first').parent().addClass('hidden');
this.$actionMenu.find('a[data-action=expand]:first').parent().removeClass('hidden');
}, this), 200);
// Remember that?
if (!this.isNew)
{
Craft.MatrixInputAlt.rememberCollapsedBlockId(this.id);
}
else
{
if (!this.$collapsedInput)
{
this.$collapsedInput = $('<input type="hidden" name="'+this.matrix.inputNamePrefix+'['+this.id+'][collapsed]" value="1"/>').appendTo(this.$container);
}
else
{
this.$collapsedInput.val('1');
}
}
this.collapsed = true;
},
expand: function()
{
if (!this.collapsed)
{
return;
}
this.$container.removeClass('collapsed');
this.$fieldsContainer.velocity('stop');
this.$container.velocity('stop');
var collapsedContainerHeight = this.$container.height();
this.$container.height('auto');
this.$fieldsContainer.show();
var expandedContainerHeight = this.$container.height();
this.$container.height(collapsedContainerHeight);
this.$fieldsContainer.hide().velocity('fadeIn', { duration: 'fast' });
this.$container.velocity({ height: expandedContainerHeight }, 'fast', $.proxy(function() {
this.$previewContainer.html('');
this.$container.height('auto');
}, this));
setTimeout($.proxy(function() {
this.$actionMenu.find('a[data-action=collapse]:first').parent().removeClass('hidden');
this.$actionMenu.find('a[data-action=expand]:first').parent().addClass('hidden');
}, this), 200);
// Remember that?
if (!this.isNew && typeof Storage !== 'undefined')
{
var collapsedBlocks = Craft.MatrixInputAlt.getCollapsedBlockIds(),
collapsedBlocksIndex = $.inArray(''+this.id, collapsedBlocks);
if (collapsedBlocksIndex != -1)
{
collapsedBlocks.splice(collapsedBlocksIndex, 1);
Craft.MatrixInputAlt.setCollapsedBlockIds(collapsedBlocks);
}
}
if (!this.isNew)
{
Craft.MatrixInputAlt.forgetCollapsedBlockId(this.id);
}
else if (this.$collapsedInput)
{
this.$collapsedInput.val('');
}
this.collapsed = false;
},
disable: function()
{
this.$container.children('input[name$="[enabled]"]:first').val('');
this.$container.addClass('disabled');
setTimeout($.proxy(function() {
this.$actionMenu.find('a[data-action=disable]:first').parent().addClass('hidden');
this.$actionMenu.find('a[data-action=enable]:first').parent().removeClass('hidden');
}, this), 200);
this.collapse(true);
},
enable: function()
{
this.$container.children('input[name$="[enabled]"]:first').val('1');
this.$container.removeClass('disabled');
setTimeout($.proxy(function() {
this.$actionMenu.find('a[data-action=disable]:first').parent().removeClass('hidden');
this.$actionMenu.find('a[data-action=enable]:first').parent().addClass('hidden');
}, this), 200);
},
onMenuOptionSelect: function(option)
{
var batchAction = (this.matrix.blockSelect.totalSelected > 1 && this.matrix.blockSelect.isSelected(this.$container)),
$option = $(option);
switch ($option.data('action'))
{
case 'collapse':
{
if (batchAction)
{
this.matrix.collapseSelectedBlocks();
}
else
{
this.collapse(true);
}
break;
}
case 'expand':
{
if (batchAction)
{
this.matrix.expandSelectedBlocks();
}
else
{
this.expand();
}
break;
}
case 'disable':
{
if (batchAction)
{
this.matrix.disableSelectedBlocks();
}
else
{
this.disable();
}
break;
}
case 'enable':
{
if (batchAction)
{
this.matrix.enableSelectedBlocks();
}
else
{
this.enable();
this.expand();
}
break;
}
case 'add':
{
var type = $option.data('type');
this.matrix.addBlock(type, this.$container);
break;
}
case 'delete':
{
if (batchAction)
{
if (confirm(Craft.t('Are you sure you want to delete the selected blocks?')))
{
this.matrix.deleteSelectedBlocks();
}
}
else
{
this.selfDestruct();
}
break;
}
}
},
selfDestruct: function()
{
this.$container.velocity(this.matrix.getHiddenBlockCss(this.$container), 'fast', $.proxy(function()
{
this.$container.remove();
this.matrix.updateAddBlockBtn();
}, this));
}
});
})(jQuery);