├── PREVIEW.gif
├── package.json
├── assets
├── css
│ └── list.css
└── js
│ └── list.js
├── template.php
├── README.md
├── LICENSE.txt
└── list.php
/PREVIEW.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TimOetting/kirby-list-field/HEAD/PREVIEW.gif
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "list",
3 | "description": "Kirby List Field",
4 | "author": "Tim Ötting",
5 | "version": "1.0",
6 | "type": "kirby-field",
7 | "license": "MIT"
8 | }
9 |
--------------------------------------------------------------------------------
/assets/css/list.css:
--------------------------------------------------------------------------------
1 | .list-field .list-item{
2 | margin-bottom: .5em;
3 | position: relative;
4 | }
5 |
6 | .list-field .list-item .sortable-handle{
7 | pointer-events: auto;
8 | cursor: move;
9 | }
--------------------------------------------------------------------------------
/template.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 |
12 | value() as $listItemValue): ?>
13 |
14 | inputField($listItemValue); ?>
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # List Field for Kirby CMS
2 |
3 | This is a custom list field for [Kirby](http://getkirby.com). It lets you write and sort a simple list of text inputs.
4 |
5 | Here is a blueprint example:
6 |
7 | fields:
8 | ...
9 | fruits:
10 | label: Give Me Fruits
11 | type: list
12 | placeholder: Add a new fruit
13 |
14 | Have a look at the resulting panel field:
15 |
16 | 
17 |
18 | The content will be YAML-structured. Inside the template, the field therefore has to be decoded as an array using $page->fruits()->yaml().
19 |
20 | ----
21 |
22 | Fruits:
23 |
24 | - Lemons
25 | - Apples
26 | - Banana
27 | - Oranges
28 |
29 | ## Setup
30 | Using git, go to the root folder of your Kirby project and run ``git clone https://github.com/TimOetting/kirby-list-field.git site/fields/list``. You can also just copy the content of this repository into ``site/fields/list``.
31 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Tim Ötting
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/list.php:
--------------------------------------------------------------------------------
1 | array(
11 | 'list.js'
12 | ),
13 | 'css' => array(
14 | 'list.css'
15 | )
16 | );
17 |
18 | public function inputField($value) {
19 |
20 | $input = new Brick('input', null);
21 | $input->addClass('input');
22 | $input->attr(array(
23 | 'type' => $this->type(),
24 | 'value' => $value,
25 | 'required' => $this->required(),
26 | 'name' => $this->name() . '[]',
27 | 'autocomplete' => $this->autocomplete() === false ? 'off' : 'on',
28 | 'autofocus' => $this->autofocus(),
29 | 'readonly' => $this->readonly(),
30 | 'disabled' => $this->disabled(),
31 | 'id' => $this->id()
32 | ));
33 |
34 | if(!is_array($value)) {
35 | $input->val($value, false);
36 | }
37 |
38 | if($this->readonly()) {
39 | $input->attr('tabindex', '-1');
40 | $input->addClass('input-is-readonly');
41 | }
42 |
43 | return $input;
44 |
45 | }
46 |
47 | public function item($value, $text) {
48 |
49 | $input = $this->input($value);
50 |
51 | $label = new Brick('input', $this->i18n($text));
52 | $label->addClass('input');
53 | $label->attr('data-focus', 'true');
54 | $label->prepend($input);
55 |
56 | if($this->readonly) {
57 | $label->addClass('input-is-readonly');
58 | }
59 |
60 | return $label;
61 |
62 | }
63 |
64 | public function content() {
65 |
66 | return tpl::load(__DIR__ . DS . 'template.php', array('field' => $this));
67 |
68 | }
69 |
70 | public function result() {
71 |
72 | $result = parent::result();
73 | return yaml::encode($result);
74 |
75 | }
76 |
77 | public function value() {
78 |
79 | $value = parent::value();
80 | return yaml::decode($value);
81 |
82 | }
83 |
84 | }
85 |
--------------------------------------------------------------------------------
/assets/js/list.js:
--------------------------------------------------------------------------------
1 | (function($) {
2 | var List = function(element) {
3 |
4 | $(element).on('input', '.add-input', function(e){
5 | var list = $(element).find('.list');
6 | var newListItemHtml = $(element).find('.list-item-template').html();
7 | list.append(newListItemHtml);
8 | var newListItem = list.find('.list-item').last();
9 | var newInput = newListItem.find('input');
10 | newInput.val($(e.target).val())
11 | $(e.target).val('')
12 | console.log(newInput.focus());
13 | })
14 |
15 | $(element).on('keydown', '.list .input', function(e){
16 | var listItem = $(e.target).parents('.list-item');
17 | var closestInput = (listItem.prev().length > 0) ? listItem.prev().find('input') : listItem.next().find('input')
18 | if(closestInput.length == 0){
19 | closestInput = $(element).find('.add-input');
20 | }
21 | if($(e.target).val() == '' && e.keyCode == 8){ //Backspace
22 | e.preventDefault();
23 | listItem.remove();
24 | setCursorToEnd(closestInput)
25 | }
26 | if(e.keyCode == 13){ //Enter
27 | e.preventDefault()
28 | $(element).find('.add-input').focus()
29 | }
30 | })
31 |
32 | $(element).on('focus', 'input', function(e){
33 | var list = $(element).find('.list');
34 | var listInputs = list.find('input');
35 | $.each(listInputs, function(i, input){
36 | if($(input).val() == ''){
37 | $(input).parent('.list-item').remove();
38 | }
39 | })
40 | })
41 |
42 | $(element).find('.list').sortable({
43 | handle: '.sortable-handle'
44 | });
45 |
46 | };
47 |
48 | var setCursorToEnd = function(element){
49 |
50 | var value = element.val();
51 | element.focus();
52 | element.val('')
53 | element.val(value)
54 |
55 | }
56 |
57 | $.fn.list = function() {
58 |
59 | return this.each(function() {
60 |
61 | if($(this).data('list')) {
62 | return $(this).data('list');
63 | } else {
64 | var list = new List(this);
65 | $(this).data('list', list);
66 | return list;
67 | }
68 |
69 | });
70 |
71 | };
72 |
73 | })(jQuery);
--------------------------------------------------------------------------------