Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented block hierarchy feature #2

Merged
merged 20 commits into from
Apr 6, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
0be65b8
Fixed issue where Neo field wouldn't show in modals
benjamminf Apr 2, 2016
11f8bc3
Added child block checkbox list to template
benjamminf Apr 2, 2016
ecdc05c
Child block checkboxes now add/remove auto
benjamminf Apr 3, 2016
e0a726e
Child block checkboxes now order by sort order
benjamminf Apr 3, 2016
ecb7b40
Adding child block types now will check if all is
benjamminf Apr 3, 2016
c7e1c2e
Added ability to get/set child checkbox states
benjamminf Apr 3, 2016
0219fc2
Fixed bug with main section changing size
benjamminf Apr 3, 2016
454684f
Use handle for child block values instead of id
benjamminf Apr 3, 2016
00ae1b9
Ensure handle change is triggered with generator
benjamminf Apr 3, 2016
b159c3b
Fixed issue loading child blocks on existing types
benjamminf Apr 3, 2016
6019c85
Child block types now save and show on fontend
benjamminf Apr 3, 2016
923b481
Child block buttons now show on input blocks
benjamminf Apr 3, 2016
5fbd862
Child blocks can now be added on input
benjamminf Apr 6, 2016
8e371fa
Odd level blocks now coloured differently
benjamminf Apr 6, 2016
bd54f90
Block level data now stored as input
benjamminf Apr 6, 2016
305c2f6
Block levels now load after saving
benjamminf Apr 6, 2016
e61d8b1
Fixed bug with adding blocks above nested ones
benjamminf Apr 6, 2016
ed5474c
Button states now update across all parent blocks
benjamminf Apr 6, 2016
b4f307d
Selected blocks now includes child blocks
benjamminf Apr 6, 2016
958c264
Child blocks now hide when collapsed
benjamminf Apr 6, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion neo/elementtypes/Neo_BlockElementType.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ public function defineCriteriaAttributes()
'fieldId' => AttributeType::Number,
'order' => array(AttributeType::String, 'default' => 'neoblocks.sortOrder'),
'collapsed' => array(AttributeType::String, 'default' => 'neoblocks.collapsed'),
'level' => array(AttributeType::String, 'default' => 'neoblocks.level'),
'ownerId' => AttributeType::Number,
'ownerLocale' => AttributeType::Locale,
'type' => AttributeType::Mixed,
Expand All @@ -75,7 +76,7 @@ public function defineCriteriaAttributes()
public function modifyElementsQuery(DbCommand $query, ElementCriteriaModel $criteria)
{
$query
->addSelect('neoblocks.fieldId, neoblocks.ownerId, neoblocks.ownerLocale, neoblocks.typeId, neoblocks.sortOrder, neoblocks.collapsed')
->addSelect('neoblocks.fieldId, neoblocks.ownerId, neoblocks.ownerLocale, neoblocks.typeId, neoblocks.sortOrder, neoblocks.collapsed, neoblocks.level')
->join('neoblocks neoblocks', 'neoblocks.id = elements.id');

if ($criteria->fieldId)
Expand Down
33 changes: 20 additions & 13 deletions neo/fieldtypes/NeoFieldType.php
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ public function getSettingsHtml()
'name' => $blockType->name,
'handle' => $blockType->handle,
'maxBlocks' => $blockType->maxBlocks,
'childBlocks' => $blockType->childBlocks,
'errors' => $blockType->getErrors(),
'fieldLayout' => $jsFieldLayout,
);
Expand Down Expand Up @@ -145,12 +146,13 @@ public function prepSettings($settings)
foreach($settings['blockTypes'] as $blockTypeId => $blockTypeSettings)
{
$blockType = new Neo_BlockTypeModel();
$blockType->id = $blockTypeId;
$blockType->fieldId = $this->model->id;
$blockType->name = $blockTypeSettings['name'];
$blockType->handle = $blockTypeSettings['handle'];
$blockType->maxBlocks = $blockTypeSettings['maxBlocks'];
$blockType->sortOrder = $blockTypeSettings['sortOrder'];
$blockType->id = $blockTypeId;
$blockType->fieldId = $this->model->id;
$blockType->name = $blockTypeSettings['name'];
$blockType->handle = $blockTypeSettings['handle'];
$blockType->maxBlocks = $blockTypeSettings['maxBlocks'];
$blockType->sortOrder = $blockTypeSettings['sortOrder'];
$blockType->childBlocks = $blockTypeSettings['childBlocks'];

if(!empty($blockTypeSettings['fieldLayout']))
{
Expand Down Expand Up @@ -344,12 +346,13 @@ public function getInputHtml($name, $value)
foreach($settings->getBlockTypes() as $blockType)
{
$blockTypeInfo[] = array(
'id' => $blockType->id,
'sortOrder' => $blockType->sortOrder,
'handle' => $blockType->handle,
'name' => Craft::t($blockType->name),
'maxBlocks' => $blockType->maxBlocks,
'tabs' => $this->_getBlockTypeHtml($blockType, null, $name),
'id' => $blockType->id,
'sortOrder' => $blockType->sortOrder,
'handle' => $blockType->handle,
'name' => Craft::t($blockType->name),
'maxBlocks' => $blockType->maxBlocks,
'childBlocks' => $blockType->childBlocks,
'tabs' => $this->_getBlockTypeHtml($blockType, null, $name),
);
}

Expand All @@ -371,6 +374,7 @@ public function getInputHtml($name, $value)
'sortOrder' => $block->sortOrder,
'collapsed' => (bool) $block->collapsed,
'enabled' => (bool) $block->enabled,
'level' => $block->level,
'tabs' => $this->_getBlockHtml($block, $name),
);
}
Expand Down Expand Up @@ -489,6 +493,7 @@ public function prepValueFromPost($data)
$block->setOwner($this->element);
$block->enabled = (isset($blockData['enabled']) ? (bool) $blockData['enabled'] : true);
$block->collapsed = (isset($blockData['collapsed']) ? (bool) $blockData['collapsed'] : false);
$block->level = (isset($blockData['level']) ? intval($blockData['level']) : 0);

// Set the content post location on the block if we can
$ownerContentPostLocation = $this->element->getContentPostLocation();
Expand Down Expand Up @@ -551,6 +556,8 @@ public function validate($blocks)
}
}

// TODO validate individual blocktype max blocks

if ($errors)
{
return $errors;
Expand Down Expand Up @@ -689,7 +696,7 @@ private function _getNamespaceDepth()
{
$namespace = craft()->templates->getNamespace();

return substr_count($namespace, '[') + 1;
return preg_match_all('/\\bfields\\b/', $namespace);
}

private function _getBlockTypeHtml(Neo_BlockTypeModel $blockType, Neo_BlockModel $block = null, $namespace = null)
Expand Down
1 change: 1 addition & 0 deletions neo/models/Neo_BlockTypeModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ protected function defineAttributes()
'name' => AttributeType::String,
'handle' => AttributeType::String,
'maxBlocks' => AttributeType::Number,
'childBlocks' => AttributeType::Mixed,
'sortOrder' => AttributeType::Number,
);
}
Expand Down
2 changes: 2 additions & 0 deletions neo/records/Neo_BlockRecord.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ public function defineIndexes()
array('columns' => array('typeId')),
array('columns' => array('sortOrder')),
array('columns' => array('collapsed')),
array('columns' => array('level')),
);
}

Expand All @@ -71,6 +72,7 @@ protected function defineAttributes()
return array(
'sortOrder' => AttributeType::SortOrder,
'collapsed' => AttributeType::Bool,
'level' => AttributeType::Number,
'ownerLocale' => AttributeType::Locale,
);
}
Expand Down
9 changes: 5 additions & 4 deletions neo/records/Neo_BlockTypeRecord.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,11 @@ public function rules()
protected function defineAttributes()
{
return array(
'name' => array(AttributeType::Name, 'required' => true),
'handle' => array(AttributeType::Handle, 'required' => true),
'maxBlocks' => array(AttributeType::Number, 'default' => 0),
'sortOrder' => AttributeType::SortOrder,
'name' => array(AttributeType::Name, 'required' => true),
'handle' => array(AttributeType::Handle, 'required' => true),
'maxBlocks' => array(AttributeType::Number, 'default' => 0),
'childBlocks' => AttributeType::Mixed,
'sortOrder' => AttributeType::SortOrder,
);
}
}
14 changes: 8 additions & 6 deletions neo/services/NeoService.php
Original file line number Diff line number Diff line change
Expand Up @@ -248,11 +248,12 @@ public function saveBlockType(Neo_BlockTypeModel $blockType, $validate = true)
}

// Set the basic info on the new block type record
$blockTypeRecord->fieldId = $blockType->fieldId;
$blockTypeRecord->name = $blockType->name;
$blockTypeRecord->handle = $blockType->handle;
$blockTypeRecord->sortOrder = $blockType->sortOrder;
$blockTypeRecord->maxBlocks = $blockType->maxBlocks;
$blockTypeRecord->fieldId = $blockType->fieldId;
$blockTypeRecord->name = $blockType->name;
$blockTypeRecord->handle = $blockType->handle;
$blockTypeRecord->sortOrder = $blockType->sortOrder;
$blockTypeRecord->maxBlocks = $blockType->maxBlocks;
$blockTypeRecord->childBlocks = $blockType->childBlocks;

// Save it, minus the field layout for now
$blockTypeRecord->save(false);
Expand Down Expand Up @@ -667,6 +668,7 @@ public function saveBlock(Neo_BlockModel $block, $validate = true)
$blockRecord->typeId = $block->typeId;
$blockRecord->sortOrder = $block->sortOrder;
$blockRecord->collapsed = $block->collapsed;
$blockRecord->level = $block->level;

$transaction = craft()->db->getCurrentTransaction() === null ? craft()->db->beginTransaction() : null;
try
Expand Down Expand Up @@ -882,7 +884,7 @@ public function requirePlugin($plugin)
private function _createBlockTypeQuery()
{
return craft()->db->createCommand()
->select('id, fieldId, fieldLayoutId, name, handle, maxBlocks, sortOrder')
->select('id, fieldId, fieldLayoutId, name, handle, maxBlocks, childBlocks, sortOrder')
->from('neoblocktypes')
->order('sortOrder');
}
Expand Down
151 changes: 150 additions & 1 deletion src/configurator/BlockTypeSettings.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import NS from '../namespace'
import Settings from './Settings'

import renderTemplate from './templates/blocktype_settings.twig'
import renderCheckbox from './templates/blocktype_settings_checkbox.twig'
import '../twig-extensions'

const _defaults = {
Expand All @@ -18,12 +19,14 @@ const _defaults = {
handle: '',
maxBlocks: 0,
childBlocks: null,
childBlockTypes: [],
errors: {}
}

export default Settings.extend({

_templateNs: [],
_childBlockTypes: [],

$sortOrderInput: new $,
$nameInput: new $,
Expand All @@ -35,6 +38,7 @@ export default Settings.extend({
settings = Object.assign({}, _defaults, settings)

this._templateNs = NS.parse(settings.namespace)
this._childBlockTypes = []
this._id = settings.id
this._errors = settings.errors

Expand All @@ -61,12 +65,24 @@ export default Settings.extend({
this.$nameInput = $neo.filter('[data-neo-bts="input.name"]')
this.$handleInput = $neo.filter('[data-neo-bts="input.handle"]')
this.$maxBlocksInput = $neo.filter('[data-neo-bts="input.maxBlocks"]')
this.$childBlocksInput = $neo.filter('[data-neo-bts="input.childBlocks"]')
this.$childBlocksContainer = $neo.filter('[data-neo-bts="container.childBlocks"]')
this.$deleteButton = $neo.filter('[data-neo-bts="button.delete"]')

this.$childBlocksInput.checkboxselect()

this._childBlocksSelect = this.$childBlocksInput.data('checkboxSelect')
this._handleGenerator = new Craft.HandleGenerator(this.$nameInput, this.$handleInput)

for(let blockType of settings.childBlockTypes)
{
this.addChildBlockType(blockType)
}

this.setChildBlocks(settings.childBlocks)

this.addListener(this.$nameInput, 'keyup change', () => this.setName(this.$nameInput.val()))
this.addListener(this.$handleInput, 'keyup change', () => this.setHandle(this.$handleInput.val()))
this.addListener(this.$handleInput, 'keyup change textchange', () => this.setHandle(this.$handleInput.val()))
this.addListener(this.$maxBlocksInput, 'keyup change', () => this.setMaxBlocks(this.$maxBlocksInput.val()))
this.addListener(this.$deleteButton, 'click', () => this.destroy())
},
Expand Down Expand Up @@ -141,6 +157,139 @@ export default Settings.extend({
oldValue: oldMaxBlocks,
newValue: this._maxBlocks
})
},

getChildBlocks()
{
const select = this._childBlocksSelect
const childBlocks = []

if(select.$all.prop('checked'))
{
return true
}

select.$options.each(function(index)
{
const $option = $(this)
childBlocks.push($option.prop('checked'))
})

return childBlocks
},

setChildBlocks(childBlocks)
{
const select = this._childBlocksSelect

if(childBlocks === true || childBlocks === '*')
{
select.$all.prop('checked', true)
select.onAllChange()
}
else if(Array.isArray(childBlocks))
{
select.$all.prop('checked', false)

for(let handle of childBlocks)
{
select.$options.filter(`[value="${handle}"]`).prop('checked', true)
}
}
else
{
select.$all.prop('checked', false)
select.$options.prop('checked', false)
}
},

addChildBlockType(blockType, index = -1)
{
if(!this._childBlockTypes.includes(blockType))
{
NS.enter(this._templateNs)

const settings = blockType.getSettings()
const $checkbox = $(renderCheckbox({
id: 'childBlock-' + settings.getId(),
name: 'childBlocks',
value: settings.getHandle(),
label: settings.getName()
}))

NS.leave()

if(index < 0 || index >= this._childBlockTypes.length)
{
this._childBlockTypes.push(blockType)
this.$childBlocksContainer.append($checkbox)
}
else
{
this._childBlockTypes.splice(index, 0, blockType)
$checkbox.insertAt(index, this.$childBlocksContainer)
}

const select = this._childBlocksSelect
const allChecked = select.$all.prop('checked')
select.$options = select.$options.add($checkbox.find('input'))
if(allChecked) select.onAllChange()

const eventNs = '.childBlock' + this.getId()
settings.on('change' + eventNs, e => this['@onChildBlockTypeChange'](e, blockType, $checkbox))
settings.on('destroy' + eventNs, e => this.removeChildBlockType(blockType))
}
},

removeChildBlockType(blockType)
{
const index = this._childBlockTypes.indexOf(blockType)
if(index >= 0)
{
this._childBlockTypes.splice(index, 1)

const settings = blockType.getSettings()
const $checkbox = this.$childBlocksContainer.children().eq(index)

$checkbox.remove()

const select = this._childBlocksSelect
select.$options = select.$options.remove($checkbox.find('input'))

const eventNs = '.childBlock' + this.getId()
settings.off(eventNs)
}
},

'@onChildBlockTypeChange'(e, blockType, $checkbox)
{
const settings = blockType.getSettings()

const $neo = $checkbox.find('[data-neo-btsc]')
const $input = $neo.filter('[data-neo-btsc="input"]')
const $labelText = $neo.filter('[data-neo-btsc="text.label"]')

switch(e.property)
{
case 'name':
$labelText.text(e.newValue)
break

case 'handle':
$input.val(e.newValue)
break;

case 'sortOrder':
const oldIndex = this._childBlockTypes.indexOf(blockType)
const newIndex = settings.getSortOrder() - 1

this._childBlockTypes.splice(oldIndex, 1)
this._childBlockTypes.splice(newIndex, 0, blockType)

$checkbox.insertAt(newIndex, this.$childBlocksContainer)

break
}
}
},
{
Expand Down
Loading