-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit c1c7954
Showing
7 changed files
with
439 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
/* Field wrapper: */ | ||
.relationship-field { | ||
display: flex; | ||
flex-wrap: wrap; | ||
border: 1px solid #ddd; | ||
background-color: white; | ||
} | ||
|
||
/* Default styling for both lists: */ | ||
.relationship-list { | ||
flex: 1 0 200px; | ||
overflow-x: hidden; | ||
overflow-y: scroll; | ||
-webkit-overflow-scrolling: touch; | ||
height: 13em; | ||
margin: 0; | ||
padding: 0.5em; | ||
border: 1px solid #ddd; | ||
background-color: white; | ||
list-style: none; | ||
} | ||
|
||
/* The list with all unselected items should be hidden: */ | ||
.relationship-list--unselected { | ||
display: none; | ||
} | ||
|
||
/* Reset native button styles: */ | ||
.relationship-list button { | ||
border: none; | ||
background: none; | ||
margin: 0; | ||
padding: 0; | ||
color: inherit; | ||
} | ||
|
||
.relationship-list button:not([disabled]) { | ||
cursor: pointer; | ||
} | ||
|
||
/* Default styling for all list items: */ | ||
.relationship-list--available button, | ||
.relationship-list--selected li { | ||
position: relative; | ||
padding: 5px 2em 5px 7px; | ||
white-space: nowrap; | ||
overflow: hidden; | ||
text-overflow: ellipsis; | ||
} | ||
|
||
/* List with available items: */ | ||
.relationship-list--available { | ||
background-color: #f7f7f7; | ||
} | ||
|
||
.relationship-list--available button { | ||
display: block; | ||
width: 100%; | ||
text-align: left; | ||
} | ||
|
||
.relationship-list--available button:not([disabled]):hover, | ||
.relationship-list--available button:not([disabled]):focus { | ||
background-color: rgba(0, 0, 0, 0.075); | ||
} | ||
|
||
.relationship-list--available button[disabled] { | ||
color: #777; | ||
} | ||
|
||
.relationship-list--available .icon-add { | ||
position: absolute; | ||
right: 0.5em; | ||
} | ||
|
||
.relationship-list--available button[disabled] .icon-add { | ||
display: none; | ||
} | ||
|
||
/* Selected list items: */ | ||
.relationship-list--selected li { | ||
padding-right: 2em; | ||
cursor: move; | ||
} | ||
|
||
.relationship-list--selected li input[type="checkbox"] { | ||
display: none; | ||
} | ||
|
||
/* List item during sorting: */ | ||
.relationship-list--selected li.ui-sortable-helper { | ||
background-color: white; | ||
border-radius: 2px; | ||
box-shadow: 0px 5px 20px rgba(0, 0, 0, 0.1); | ||
transition: box-shadow 150ms ease-out; | ||
} | ||
|
||
/* Placeholder item when sorting: */ | ||
.relationship-list--selected li.ui-sortable-placeholder { | ||
background-color: rgba(0, 0, 0, 0.025); | ||
} | ||
|
||
/* Delete icon: */ | ||
.relationship-list--selected li .icon-delete { | ||
position: absolute; | ||
right: 0.5em; | ||
} | ||
|
||
/* Sort icon: */ | ||
.relationship-list--selected li .icon-left { | ||
color: #ccc; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
(function($) { | ||
|
||
var Relationship = function(field) { | ||
|
||
// Get references to the item lists: | ||
var $list_available = $(field).find('.relationship-list--available'); | ||
var $list_selected = $(field).find('.relationship-list--selected'); | ||
var $list_unselected = $(field).find('.relationship-list--unselected'); | ||
|
||
/** | ||
* Add an item to the selection on click: | ||
*/ | ||
$list_available.on('click', 'button:not([disabled])', function(event) { | ||
event.preventDefault(); | ||
|
||
// Clicked item should be disabled: | ||
$(this).prop('disabled', true); | ||
|
||
// Get key of clicked item: | ||
var key = $(this).data('key'); | ||
|
||
// Find item in unselected list: | ||
var $selected_item = $list_unselected.find('li[data-key="' + key + '"]'); | ||
|
||
// Move the selected item to the end of the selected list: | ||
$selected_item.appendTo($list_selected); | ||
|
||
// Set the checkbox as checked: | ||
$selected_item.find('input').prop('checked', true); | ||
|
||
// Notify Kirby that some changes are made: | ||
$selected_item.find('input').trigger('change'); | ||
|
||
// Scroll to bottom of the list to show the new item: | ||
$list_selected.stop().delay(20).animate({ | ||
scrollTop: $list_selected[0].scrollHeight | ||
}, { | ||
duration: 600 | ||
}); | ||
}); | ||
|
||
/** | ||
* Remove a selected item on click: | ||
*/ | ||
$list_selected.on('click', 'button', function(event) { | ||
event.preventDefault(); | ||
|
||
// Get a reference of the item to be removed from the selection: | ||
var $selected_item = $(this).closest('li'); | ||
|
||
// Move the selected item to the unselected list: | ||
$selected_item.appendTo($list_unselected); | ||
|
||
// Set the checkbox as unchecked: | ||
$selected_item.find('input').prop('checked', false); | ||
|
||
// Notify Kirby that some changes are made: | ||
$selected_item.find('input').trigger('change'); | ||
|
||
// Get the key of the selected item: | ||
var key = $selected_item.data('key'); | ||
|
||
// Make the selected item available again in the available list: | ||
$list_available.find('button[data-key="' + key + '"]').prop('disabled', false); | ||
}); | ||
|
||
/** | ||
* Make the list sortable using jQuery Sortable library | ||
* Docs: http://api.jqueryui.com/sortable | ||
*/ | ||
$list_selected.sortable({ | ||
revert: 100, | ||
placeholder: 'ui-sortable-placeholder', | ||
forcePlaceholderSize: true, | ||
update: function(event, ui) { | ||
// Notify Kirby that some changes are made: | ||
ui.item.find('input').trigger('change'); | ||
} | ||
}); | ||
}; | ||
|
||
/** | ||
* Initialize the field: | ||
*/ | ||
$.fn.relationship = function() { | ||
return this.each(function() { | ||
if ($(this).data('relationship')) { | ||
return $(this); | ||
} else { | ||
var relationship = new Relationship(this); | ||
$(this).data('relationship', relationship); | ||
return $(this); | ||
} | ||
}); | ||
}; | ||
|
||
})(jQuery); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# Changelog | ||
|
||
## 1.0.0 (2017-08-11) | ||
- Initial version |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
{ | ||
"name": "relationship", | ||
"description": "Sortable multiselect field for Kirby 2 CMS", | ||
"author": "Ola Christensson <ola.christensson@grandpublic.se>", | ||
"version": "1.0.0", | ||
"type": "kirby-field", | ||
"license": "MIT", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/olach/kirby-relationship" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
# Kirby Relationship field | ||
|
||
The Relationship field allows you to select and sort multiple items from a list. Think of it as a sortable multiselect field or a sortable checkboxes field. | ||
|
||
![relationship-field-demo](https://user-images.githubusercontent.com/1300644/29208814-e1f92692-7e8b-11e7-857f-b646853d3ed8.gif) | ||
|
||
## Requirements | ||
This field has been tested with Kirby 2.5+, but it should probably work with earlier versions too. | ||
|
||
## Installation | ||
### Manually | ||
[Download the files](https://github.com/olach/kirby-relationship/archive/master.zip) and place them inside `site/fields/relationship/`. | ||
|
||
### With Kirby CLI | ||
Kirby's [command line interface](https://github.com/getkirby/cli) makes the installation really simple: | ||
|
||
$ kirby plugin:install olach/kirby-relationship | ||
|
||
Updating is also easy: | ||
|
||
$ kirby plugin:update olach/kirby-relationship | ||
|
||
## Usage | ||
The field is an extension of the [Checkboxes field](https://getkirby.com/docs/cheatsheet/panel-fields/checkboxes). All options of that field apply to this field too. The data is saved as a comma separated string, which means that this field is interchangeable with the Checkboxes field. | ||
|
||
### Example with predefined options | ||
#### Blueprint | ||
|
||
```yaml | ||
countries: | ||
label: Countries | ||
type: relationship | ||
options: | ||
sweden: Sweden | ||
norway: Norway | ||
denmark: Denmark | ||
finland: Finland | ||
iceland: Iceland | ||
germany: Germany | ||
france: France | ||
spain: Spain | ||
portugal: Portugal | ||
``` | ||
#### Template | ||
```php | ||
<ul> | ||
<?php foreach ($page->countries()->split() as $country): ?> | ||
<li><?= $country ?></li> | ||
<?php endforeach ?> | ||
</ul> | ||
``` | ||
|
||
### Example with related pages | ||
#### Blueprint | ||
|
||
```yaml | ||
related: | ||
label: Related articles | ||
type: relationship | ||
options: query | ||
query: | ||
fetch: siblings | ||
``` | ||
#### Template | ||
```php | ||
<h2>Related articles</h2> | ||
<ul> | ||
<?php foreach ($page->related()->pages(',') as $related): ?> | ||
<li> | ||
<a href="<?php echo $related->url() ?>"> | ||
<?= $related->title() ?> | ||
</a> | ||
</li> | ||
<?php endforeach ?> | ||
</ul> | ||
``` | ||
|
||
## Extra features | ||
|
||
### Controller: | ||
This field is extended with an option to use a user specified function to have even more control of the options that will be loaded. The idea is taken from the [Controlled List plugin](https://github.com/rasteiner/controlledlist). | ||
|
||
#### Example | ||
Create a simple plugin that lets you choose from the panel users. | ||
|
||
`site/plugins/myplugin/myplugin.php`: | ||
|
||
```php | ||
class MyPlugin { | ||
static function userlist($field) { | ||
$kirby = kirby(); | ||
$site = $kirby->site(); | ||
$users = $site->users(); | ||
|
||
$result = array(); | ||
|
||
foreach ($users as $user) { | ||
$result[$user->username] = $user->firstName() . ' ' . $user->lastName(); | ||
} | ||
|
||
return $result; | ||
} | ||
} | ||
``` | ||
|
||
In your blueprint: | ||
|
||
```yaml | ||
users: | ||
label: Users | ||
type: relationship | ||
controller: MyPlugin::userlist | ||
``` | ||
## Version history | ||
You can find the version history in the [changelog](changelog.md). | ||
## License | ||
[MIT License](http://www.opensource.org/licenses/mit-license.php) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
<?php | ||
|
||
class RelationshipField extends CheckboxesField { | ||
|
||
public $controller; | ||
|
||
static public $assets = array( | ||
'js' => array( | ||
'relationship.js' | ||
), | ||
'css' => array( | ||
'relationship.css' | ||
) | ||
); | ||
|
||
/** | ||
* This field can load a user specified function if set in the blueprint. | ||
*/ | ||
public function options() { | ||
if ($this->controller()) { | ||
return call_user_func($this->controller(), $this); | ||
} else { | ||
return parent::options(); | ||
} | ||
} | ||
|
||
/** | ||
* Use a template file to build all html. | ||
*/ | ||
public function content() { | ||
return tpl::load(__DIR__ . DS . 'template.php', array('field' => $this)); | ||
} | ||
|
||
} |
Oops, something went wrong.