Initial commit
This commit is contained in:
commit
65e0da7e11
1397 changed files with 596542 additions and 0 deletions
|
|
@ -0,0 +1,12 @@
|
|||
.modules-layout__preview {
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.modules-layout__preview:empty {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.modules-layout__preview--bottom {
|
||||
border-bottom: none;
|
||||
border-top: 1px solid #ddd;
|
||||
}
|
||||
3
site/OFF_plugins/sortable/fields/modules/controller.php
Normal file
3
site/OFF_plugins/sortable/fields/modules/controller.php
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<?php
|
||||
|
||||
class ModulesFieldController extends LukasKleinschmidt\Sortable\Controllers\Field {}
|
||||
31
site/OFF_plugins/sortable/fields/modules/modules.php
Normal file
31
site/OFF_plugins/sortable/fields/modules/modules.php
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
class ModulesField extends SortableField {
|
||||
|
||||
public $add = true;
|
||||
public $copy = true;
|
||||
public $paste = true;
|
||||
public $layout = 'module';
|
||||
public $variant = 'modules';
|
||||
public $actions = array(
|
||||
'edit',
|
||||
'duplicate',
|
||||
'delete',
|
||||
'toggle',
|
||||
);
|
||||
|
||||
static public $assets = array(
|
||||
'css' => array(
|
||||
'modules.css',
|
||||
),
|
||||
);
|
||||
|
||||
public function parent() {
|
||||
return Kirby\Modules\Settings::parentUid();
|
||||
}
|
||||
|
||||
public function prefix() {
|
||||
return Kirby\Modules\Settings::templatePrefix();
|
||||
}
|
||||
|
||||
}
|
||||
164
site/OFF_plugins/sortable/fields/modules/readme.md
Normal file
164
site/OFF_plugins/sortable/fields/modules/readme.md
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
# Kirby Modules Field
|
||||
|
||||
This field extends the `sortable` field and adds some presets and features to help you manage your modules.
|
||||
To use this field you have to install the [modules-plugin](https://github.com/getkirby-plugins/modules-plugin).
|
||||
|
||||
### Some of the features
|
||||
- Preset `parent` and `prefix` to match those set by the modules-plugin
|
||||
- Adds a [preview](#preview) if provided
|
||||
|
||||

|
||||
|
||||
## Blueprint
|
||||
|
||||
After installing the plugin, you can use the new field type `modules`.
|
||||
This blueprint shows all available options and their defaults.
|
||||
|
||||
```yml
|
||||
fields:
|
||||
title:
|
||||
label: Title
|
||||
type: text
|
||||
|
||||
modules:
|
||||
label: Modules
|
||||
type: modules
|
||||
|
||||
add: true
|
||||
copy: true
|
||||
paste: true
|
||||
limit: false
|
||||
variant: modules
|
||||
|
||||
actions:
|
||||
- edit
|
||||
- duplicate
|
||||
- delete
|
||||
- toggle
|
||||
|
||||
options:
|
||||
preview: true
|
||||
limit: false
|
||||
edit: true
|
||||
duplicate: true
|
||||
delete: true
|
||||
toggle: true
|
||||
...
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
The following examples show and explain some of the possible settings.
|
||||
|
||||
### Preview
|
||||
|
||||
A preview is a normal PHP file with the HTML and PHP code that defines your preview. The preview has access to the following variables:
|
||||
|
||||
- `$page` is the page on which the module appears
|
||||
- `$module` is the module subpage, which you can use to access the fields from your module blueprint as well as module files
|
||||
- `$moduleName` is the name of the module such as text or gallery
|
||||
|
||||
The preview file must be in the same folder as the module itself.
|
||||
The module directory looks something like this:
|
||||
|
||||
```
|
||||
site/modules/
|
||||
gallery/
|
||||
gallery.html.php
|
||||
gallery.yml
|
||||
|
||||
# The preview file
|
||||
gallery.preview.php
|
||||
...
|
||||
```
|
||||
|
||||
### Preview options
|
||||
|
||||
Previews are enabled by default. Set `preview` to `false` to disable the preview.
|
||||
It is also possible to change the position in the module.
|
||||
|
||||
```yml
|
||||
options:
|
||||
# Render the preview at the bottom
|
||||
preview: bottom
|
||||
|
||||
# Or at the top
|
||||
preview: top
|
||||
preview: true
|
||||
```
|
||||
|
||||
|
||||
### Limit the number of visible modules
|
||||
|
||||
```yml
|
||||
modules_field:
|
||||
label: Modules
|
||||
type: modules
|
||||
|
||||
# Allow 3 visible modules overall
|
||||
limit: 3
|
||||
|
||||
# Template specific option
|
||||
options:
|
||||
module.gallery:
|
||||
# Allow only 1 visible gallery module
|
||||
limit: 1
|
||||
```
|
||||
|
||||

|
||||
|
||||
### Is it a module or a section?
|
||||
|
||||
Change the naming.
|
||||
|
||||
```yml
|
||||
# Modules is fine
|
||||
variant: modules
|
||||
|
||||
# Nah sections it is
|
||||
variant: sections
|
||||
```
|
||||
|
||||
### Changing actions
|
||||
|
||||
To change the actions or remove an action completely from the modules, you must specify the `actions` array in the blueprint.
|
||||
|
||||
```yml
|
||||
# Default
|
||||
actions:
|
||||
- edit
|
||||
- duplicate
|
||||
- delete
|
||||
- toggle
|
||||
```
|
||||
|
||||

|
||||
|
||||
```yml
|
||||
actions:
|
||||
- edit
|
||||
- toggle
|
||||
```
|
||||
|
||||

|
||||
|
||||
### Disabling an action
|
||||
|
||||
```yml
|
||||
options:
|
||||
edit: false
|
||||
duplicate: false
|
||||
delete: true
|
||||
toggle: true
|
||||
|
||||
# Template specific options
|
||||
module.gallery:
|
||||
edit: true
|
||||
duplicate: true
|
||||
```
|
||||
|
||||

|
||||
|
||||
## Requirements
|
||||
|
||||
- [Kirby Modules Plugin](https://github.com/getkirby-plugins/modules-plugin) 1.3+
|
||||
32
site/OFF_plugins/sortable/fields/modules/template.php
Normal file
32
site/OFF_plugins/sortable/fields/modules/template.php
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
<label class="label">
|
||||
<?= $field->label(); ?>
|
||||
<?= $field->counter(); ?>
|
||||
<?php if($field->add()) echo $field->action('add'); ?>
|
||||
</label>
|
||||
|
||||
<?php if($field->entries()->count()): ?>
|
||||
<?= $field->layouts(); ?>
|
||||
<?php else: ?>
|
||||
<div class="sortable__empty">
|
||||
<?php
|
||||
echo $field->l('field.sortable.empty');
|
||||
if($field->add()) {
|
||||
echo $field->action('add', ['label' => $field->l('field.sortable.add.first'), 'icon' => '', 'class' => '']);
|
||||
if($field->paste()) {
|
||||
echo $field->l('field.sortable.or');
|
||||
echo $field->action('paste', ['label' => $field->l('field.sortable.paste.first'), 'icon' => '', 'class' => '']);
|
||||
}
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="sortable__navigation">
|
||||
<?php
|
||||
if($field->copy()) echo $field->action('copy');
|
||||
if($field->add()) {
|
||||
if($field->paste()) echo $field->action('paste');
|
||||
echo $field->action('add');
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
44
site/OFF_plugins/sortable/fields/options/options.php
Normal file
44
site/OFF_plugins/sortable/fields/options/options.php
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
class OptionsField extends CheckboxesField {
|
||||
|
||||
public function input() {
|
||||
|
||||
$value = func_get_arg(0);
|
||||
$data = func_get_arg(1);
|
||||
|
||||
$input = parent::input($value);
|
||||
|
||||
if(!$this->error) {
|
||||
$input->attr('checked', v::accepted($this->value()) || v::accepted($data->checked()));
|
||||
}
|
||||
|
||||
if($data->readonly()) {
|
||||
$input->attr('disabled', true);
|
||||
$input->attr('readonly', true);
|
||||
$input->addClass('input-is-readonly');
|
||||
}
|
||||
|
||||
return $input;
|
||||
|
||||
}
|
||||
|
||||
public function item($value, $data) {
|
||||
|
||||
$data = new Obj($data);
|
||||
$input = $this->input($value, $data);
|
||||
|
||||
$label = new Brick('label', '<span>' . $this->i18n($data->label()) . '</span>');
|
||||
$label->addClass('input input-with-checkbox');
|
||||
$label->attr('data-focus', 'true');
|
||||
$label->prepend($input);
|
||||
|
||||
if($data->readonly()) {
|
||||
$label->addClass('input-is-readonly');
|
||||
}
|
||||
|
||||
return $label;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
39
site/OFF_plugins/sortable/fields/redirect/readme.md
Normal file
39
site/OFF_plugins/sortable/fields/redirect/readme.md
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
# Kirby Redirect Field
|
||||
|
||||
This field redirects a user to the parent of the currently visited panel page.
|
||||
Useful for pages that act like a container.
|
||||
|
||||
## Blueprint
|
||||
```yml
|
||||
fields:
|
||||
title:
|
||||
label: Title
|
||||
type: text
|
||||
|
||||
redirect:
|
||||
label: Redirect
|
||||
type: redirect
|
||||
...
|
||||
```
|
||||
|
||||
## Redirect to a specific page
|
||||
|
||||
Redirect to `panel/projects/project-a/edit`.
|
||||
When the page is not found you will get redirected to the dashboard.
|
||||
|
||||
```yml
|
||||
redirect:
|
||||
label: Redirect
|
||||
type: redirect
|
||||
|
||||
redirect: projects/project-a
|
||||
```
|
||||
|
||||
## Hide pages
|
||||
There are several ways to hide pages in the panel. The easyiest way would be to set `hide: true` in the pages [blueprint](https://getkirby.com/docs/panel/blueprints/page-settings#hide-page). This would hide a page in the sidebar. To get rid of the breadcrumb link you can put something like this to your [custom panel css](https://getkirby.com/docs/developer-guide/panel/css).
|
||||
|
||||
```css
|
||||
.breadcrumb-link[title="your-page-title"] {
|
||||
display: none;
|
||||
}
|
||||
```
|
||||
25
site/OFF_plugins/sortable/fields/redirect/redirect.php
Normal file
25
site/OFF_plugins/sortable/fields/redirect/redirect.php
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
class RedirectField extends BaseField {
|
||||
|
||||
public $redirect;
|
||||
|
||||
public function template() {
|
||||
|
||||
$redirect = $this->redirect();
|
||||
|
||||
if(is_null($redirect)) {
|
||||
return go(purl($this->page()->parent(), 'edit'));
|
||||
}
|
||||
|
||||
$page = panel()->page($redirect);
|
||||
|
||||
if(is_null($page)) {
|
||||
return go(purl());
|
||||
}
|
||||
|
||||
return go(purl($page));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,173 @@
|
|||
/* TEMP: until https://github.com/getkirby/panel/pull/986 is resolved */
|
||||
.form-blueprint-home > fieldset {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
@-moz-document url-prefix() {
|
||||
.form-blueprint-home > fieldset {
|
||||
display: table-cell;
|
||||
}
|
||||
}
|
||||
|
||||
.sortable__counter {
|
||||
padding-left: 0.25em;
|
||||
font-size: 0.8em;
|
||||
font-weight: 400;
|
||||
color: #bbb;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.sortable__empty {
|
||||
background: #ddd;
|
||||
padding: 1.5em;
|
||||
}
|
||||
|
||||
.sortable__empty a {
|
||||
border-bottom: 2px solid #bbb;
|
||||
margin: 0 0.25em;
|
||||
}
|
||||
|
||||
.sortable__empty a:hover {
|
||||
border-color: #000;
|
||||
}
|
||||
|
||||
.sortable__empty a:first-child {
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
|
||||
.sortable__navigation {
|
||||
padding-top: 0.5em;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.sortable__action {
|
||||
color: #777;
|
||||
font-weight: 400;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
|
||||
.sortable__action .icon,
|
||||
.sortable__action:hover {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.sortable__action--add {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.sortable__action:nth-child(n+2) {
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
.sortable__action.is-disabled {
|
||||
pointer-events: none;
|
||||
color: #c9c9c9;
|
||||
}
|
||||
|
||||
.sortable__layout {
|
||||
margin-bottom: 0.25em;
|
||||
}
|
||||
|
||||
.sortable-layout a,
|
||||
.sortable-layout button,
|
||||
.sortable__action.is-disabled .icon {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.sortable-layout {
|
||||
background: #fff;
|
||||
border: 2px solid #ddd;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.sortable-layout .icon {
|
||||
vertical-align: -5%;
|
||||
}
|
||||
|
||||
.sortable-layout .icon:not(.icon-left) {
|
||||
width: 1.28571em;
|
||||
}
|
||||
|
||||
.sortable-layout__icon {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.sortable-layout__counter {
|
||||
padding-left: 0.25em;
|
||||
font-size: 0.8em;
|
||||
color: #bbb;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.sortable-layout [data-handle] {
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
.sortable-layout__navigation {
|
||||
min-height: 44px;
|
||||
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-flex-flow: row nowrap;
|
||||
-ms-flex-flow: row nowrap;
|
||||
flex-flow: row nowrap;
|
||||
}
|
||||
|
||||
.sortable-layout__icon,
|
||||
.sortable-layout__action,
|
||||
.sortable-layout__title {
|
||||
padding: 0.6em;
|
||||
white-space: nowrap;
|
||||
line-height: 1.5em;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.sortable-layout__title {
|
||||
-webkit-flex: 1 0 0%;
|
||||
-ms-flex: 1 0 0%;
|
||||
flex: 1 0 0%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
padding-left: 0.35em;
|
||||
}
|
||||
|
||||
.sortable-layout[data-visible=false] .sortable-layout__icon,
|
||||
.sortable-layout[data-visible=false] .sortable-layout__title {
|
||||
color: #c9c9c9;
|
||||
}
|
||||
|
||||
.sortable-layout__action {
|
||||
-webkit-flex: 0 0 auto;
|
||||
-ms-flex: 0 0 auto;
|
||||
flex: 0 0 auto;
|
||||
border: none;
|
||||
//border-left: 1px solid #efefef;
|
||||
background: 0 0;
|
||||
cursor: pointer;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.sortable-layout__action.is-disabled {
|
||||
pointer-events: none;
|
||||
color: #c9c9c9;
|
||||
}
|
||||
|
||||
.sortable-placeholder {
|
||||
width: 25%;
|
||||
height: 25%;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.sortable__grid {
|
||||
width: 33%; display: inline-block; vertical-align: middle;
|
||||
}
|
||||
|
||||
.sortable__grid .sortable-layout__icon {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.sortable__action--copy, .sortable__action--paste {
|
||||
display: none;
|
||||
}
|
||||
207
site/OFF_plugins/sortable/fields/sortable/assets/js/sortable.js
Normal file
207
site/OFF_plugins/sortable/fields/sortable/assets/js/sortable.js
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
(function($) {
|
||||
|
||||
var Sort = function(element) {
|
||||
var self = this;
|
||||
|
||||
this.element = $(element);
|
||||
this.container = $('.sortable__container', element);
|
||||
this.api = this.element.data('api');
|
||||
|
||||
this.container._sortable({
|
||||
handle: '[data-handle]',
|
||||
placeholder: "sortable-placeholder",
|
||||
start: function(event, ui) {
|
||||
self.container._sortable('refreshPositions');
|
||||
self.blur();
|
||||
},
|
||||
update: function(event, ui) {
|
||||
var to = self.container.children().index(ui.item) + 1;
|
||||
var uid = ui.item.data('uid');
|
||||
var action = [self.api, uid, to, 'sort'].join('/');
|
||||
|
||||
// disable sorting because a reload is expected
|
||||
self.disable();
|
||||
|
||||
$.post(action, self.reload.bind(self));
|
||||
}
|
||||
});
|
||||
|
||||
this.element.on('click', '[data-action]', function(event) {
|
||||
var element = $(this);
|
||||
var action = element.data('action') || element.attr('href');
|
||||
|
||||
$.post(action, self.reload.bind(self));
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
// setup extended field script
|
||||
var key = this.element.data('field-extended');
|
||||
if(key != 'sortable' && this.element[key]) this.element[key]();
|
||||
};
|
||||
|
||||
Sort.prototype.blur = function() {
|
||||
$('.form input:focus, .form select:focus, .form textarea:focus').blur();
|
||||
app.content.focus.forget();
|
||||
}
|
||||
|
||||
Sort.prototype.disable = function() {
|
||||
this.container._sortable('disable');
|
||||
}
|
||||
|
||||
Sort.prototype.reload = function() {
|
||||
this.disable();
|
||||
app.content.reload();
|
||||
}
|
||||
|
||||
|
||||
// Fixing scrollbar jumping issue
|
||||
// http://stackoverflow.com/questions/1735372/jquery-sortable-list-scroll-bar-jumps-up-when-sorting
|
||||
if (typeof($.ui._sortable) === 'undefined') {
|
||||
$.widget('ui._sortable', $.ui.sortable, {
|
||||
_mouseStart: function(event, overrideHandle, noActivation) {
|
||||
var i, body,
|
||||
o = this.options;
|
||||
|
||||
this.currentContainer = this;
|
||||
|
||||
//We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture
|
||||
this.refreshPositions();
|
||||
|
||||
//Create and append the visible helper
|
||||
this.helper = this._createHelper(event);
|
||||
|
||||
//Cache the helper size
|
||||
this._cacheHelperProportions();
|
||||
|
||||
/*
|
||||
* - Position generation -
|
||||
* This block generates everything position related - it's the core of draggables.
|
||||
*/
|
||||
|
||||
//Cache the margins of the original element
|
||||
this._cacheMargins();
|
||||
|
||||
//Get the next scrolling parent
|
||||
this.scrollParent = this.helper.scrollParent();
|
||||
|
||||
//The element's absolute position on the page minus margins
|
||||
this.offset = this.currentItem.offset();
|
||||
this.offset = {
|
||||
top: this.offset.top - this.margins.top,
|
||||
left: this.offset.left - this.margins.left
|
||||
};
|
||||
|
||||
$.extend(this.offset, {
|
||||
click: { //Where the click happened, relative to the element
|
||||
left: event.pageX - this.offset.left,
|
||||
top: event.pageY - this.offset.top
|
||||
},
|
||||
parent: this._getParentOffset(),
|
||||
relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
|
||||
});
|
||||
|
||||
//Create the placeholder
|
||||
this._createPlaceholder();
|
||||
|
||||
// Only after we got the offset, we can change the helper's position to absolute
|
||||
this.helper.css("position", "absolute");
|
||||
this.cssPosition = this.helper.css("position");
|
||||
|
||||
//Generate the original position
|
||||
this.originalPosition = this._generatePosition(event);
|
||||
this.originalPageX = event.pageX;
|
||||
this.originalPageY = event.pageY;
|
||||
|
||||
//Adjust the mouse offset relative to the helper if "cursorAt" is supplied
|
||||
(o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
|
||||
|
||||
//Cache the former DOM position
|
||||
this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] };
|
||||
|
||||
//If the helper is not the original, hide the original so it's not playing any role during the drag, won't cause anything bad this way
|
||||
if(this.helper[0] !== this.currentItem[0]) {
|
||||
this.currentItem.hide();
|
||||
}
|
||||
|
||||
//Set a containment if given in the options
|
||||
if(o.containment) {
|
||||
this._setContainment();
|
||||
}
|
||||
|
||||
if( o.cursor && o.cursor !== "auto" ) { // cursor option
|
||||
body = this.document.find( "body" );
|
||||
|
||||
// support: IE
|
||||
this.storedCursor = body.css( "cursor" );
|
||||
body.css( "cursor", o.cursor );
|
||||
|
||||
this.storedStylesheet = $( "<style>*{ cursor: "+o.cursor+" !important; }</style>" ).appendTo( body );
|
||||
}
|
||||
|
||||
if(o.opacity) { // opacity option
|
||||
if (this.helper.css("opacity")) {
|
||||
this._storedOpacity = this.helper.css("opacity");
|
||||
}
|
||||
this.helper.css("opacity", o.opacity);
|
||||
}
|
||||
|
||||
if(o.zIndex) { // zIndex option
|
||||
if (this.helper.css("zIndex")) {
|
||||
this._storedZIndex = this.helper.css("zIndex");
|
||||
}
|
||||
this.helper.css("zIndex", o.zIndex);
|
||||
}
|
||||
|
||||
//Prepare scrolling
|
||||
if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") {
|
||||
this.overflowOffset = this.scrollParent.offset();
|
||||
}
|
||||
|
||||
//Call callbacks
|
||||
this._trigger("start", event, this._uiHash());
|
||||
|
||||
//Recache the helper size
|
||||
if(!this._preserveHelperProportions) {
|
||||
this._cacheHelperProportions();
|
||||
}
|
||||
|
||||
|
||||
//Post "activate" events to possible containers
|
||||
if( !noActivation ) {
|
||||
for ( i = this.containers.length - 1; i >= 0; i-- ) {
|
||||
this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) );
|
||||
}
|
||||
}
|
||||
|
||||
//Prepare possible droppables
|
||||
if($.ui.ddmanager) {
|
||||
$.ui.ddmanager.current = this;
|
||||
}
|
||||
|
||||
if ($.ui.ddmanager && !o.dropBehaviour) {
|
||||
$.ui.ddmanager.prepareOffsets(this, event);
|
||||
}
|
||||
|
||||
this.dragging = true;
|
||||
|
||||
this.helper.addClass("ui-sortable-helper");
|
||||
this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$.fn.sort = function() {
|
||||
return this.each(function() {
|
||||
if ($(this).data('sort')) {
|
||||
return $(this);
|
||||
} else {
|
||||
var sort = new Sort(this);
|
||||
$(this).data('sort', sort);
|
||||
return $(this);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
})(jQuery);
|
||||
3
site/OFF_plugins/sortable/fields/sortable/controller.php
Normal file
3
site/OFF_plugins/sortable/fields/sortable/controller.php
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<?php
|
||||
|
||||
class SortableFieldController extends LukasKleinschmidt\Sortable\Controllers\Field {}
|
||||
315
site/OFF_plugins/sortable/fields/sortable/sortable.php
Normal file
315
site/OFF_plugins/sortable/fields/sortable/sortable.php
Normal file
|
|
@ -0,0 +1,315 @@
|
|||
<?php
|
||||
|
||||
use LukasKleinschmidt\Sortable;
|
||||
|
||||
// Load all registerd classes
|
||||
sortable()->load();
|
||||
|
||||
class SortableField extends InputField {
|
||||
|
||||
public $limit = false;
|
||||
public $parent = null;
|
||||
public $prefix = null;
|
||||
public $layout = 'base';
|
||||
public $variant = null;
|
||||
public $options = array();
|
||||
|
||||
// Caches
|
||||
protected $entries;
|
||||
protected $defaults;
|
||||
protected $origin;
|
||||
|
||||
static public $assets = array(
|
||||
'js' => array(
|
||||
'sortable.js',
|
||||
),
|
||||
'css' => array(
|
||||
'sortable.css',
|
||||
),
|
||||
);
|
||||
|
||||
public function routes() {
|
||||
return array(
|
||||
array(
|
||||
'pattern' => 'action/(:any)/(:all?)',
|
||||
'method' => 'POST|GET',
|
||||
'action' => 'forAction',
|
||||
'filter' => 'auth',
|
||||
),
|
||||
array(
|
||||
'pattern' => '(:all)/(:all)/sort',
|
||||
'method' => 'POST|GET',
|
||||
'action' => 'sort',
|
||||
'filter' => 'auth',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
public function parent() {
|
||||
return $this->i18n($this->parent);
|
||||
}
|
||||
|
||||
public function action($type, $data = array()) {
|
||||
|
||||
$data = a::update($data, array(
|
||||
'field' => $this,
|
||||
'parent' => $this->origin(),
|
||||
));
|
||||
|
||||
return sortable::action($type, $data);
|
||||
|
||||
}
|
||||
|
||||
public function layout($type, $data = array()) {
|
||||
|
||||
$data = a::update($data, array(
|
||||
'field' => $this,
|
||||
'parent' => $this->origin(),
|
||||
));
|
||||
|
||||
return sortable::layout($type, $data);
|
||||
|
||||
}
|
||||
|
||||
public function layouts() {
|
||||
|
||||
$layouts = new Brick('div');
|
||||
$layouts->addClass('sortable__container');
|
||||
|
||||
$numVisible = 0;
|
||||
$num = 0;
|
||||
|
||||
foreach($this->entries() as $page) {
|
||||
|
||||
if($page->isVisible()) $numVisible++;
|
||||
$num++;
|
||||
|
||||
$data = a::update($this->options($page)->toArray(), array(
|
||||
'numVisible' => $numVisible,
|
||||
'page' => $page,
|
||||
'num' => $num,
|
||||
));
|
||||
|
||||
$layout = $this->layout($this->layout, $data);
|
||||
$layouts->append($layout);
|
||||
|
||||
}
|
||||
|
||||
return $layouts;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get translation
|
||||
*
|
||||
* @param string $key
|
||||
* @param string $variant
|
||||
* @return string
|
||||
*/
|
||||
public function l($key, $variant = null) {
|
||||
|
||||
if(is_null($variant)) {
|
||||
$variant = $this->variant();
|
||||
}
|
||||
|
||||
return sortable()->translation($key, $variant);
|
||||
|
||||
}
|
||||
|
||||
public function input() {
|
||||
|
||||
$value = func_get_arg(0);
|
||||
$input = parent::input();
|
||||
$input->attr(array(
|
||||
'id' => $value,
|
||||
'name' => $this->name() . '[]',
|
||||
'type' => 'hidden',
|
||||
'value' => $value,
|
||||
'required' => false,
|
||||
'autocomplete' => false,
|
||||
));
|
||||
|
||||
return $input;
|
||||
|
||||
}
|
||||
|
||||
public function defaults() {
|
||||
|
||||
// Return from cache if possible
|
||||
if(!is_null($this->defaults)) {
|
||||
return $this->defaults;
|
||||
}
|
||||
|
||||
if(!$this->options) {
|
||||
return $this->defaults = array();
|
||||
}
|
||||
|
||||
// Available templates
|
||||
$templates = $this->origin()->blueprint()->pages()->template()->pluck('name');
|
||||
|
||||
// Remove template specific options from the defaults
|
||||
$defaults = array();
|
||||
|
||||
foreach($this->options as $key => $value) {
|
||||
if(in_array($key, $templates)) continue;
|
||||
$defaults[$key] = $value;
|
||||
}
|
||||
|
||||
return $this->defaults = $defaults;
|
||||
|
||||
}
|
||||
|
||||
public function options($template) {
|
||||
|
||||
if(is_a($template, 'Page')) {
|
||||
$template = $template->intendedTemplate();
|
||||
}
|
||||
|
||||
// Get entry specific options
|
||||
$options = a::get($this->options, $template, array());
|
||||
|
||||
return new Obj(a::update($this->defaults(), $options));
|
||||
|
||||
}
|
||||
|
||||
public function content() {
|
||||
|
||||
$template = $this->root() . DS . 'template.php';
|
||||
|
||||
if(!is_file($template)) {
|
||||
$template = __DIR__ . DS . 'template.php';
|
||||
}
|
||||
|
||||
$content = new Brick('div');
|
||||
|
||||
// Sort namespace is used because otherwise there
|
||||
// would be a collision with the jquery sortable plugin
|
||||
$content->attr('data-field', 'sort');
|
||||
$content->attr('data-field-extended', $this->type());
|
||||
$content->attr('data-api', $this->url());
|
||||
$content->addClass('sortable');
|
||||
$content->append(tpl::load($template, array('field' => $this)));
|
||||
|
||||
return $content;
|
||||
|
||||
}
|
||||
|
||||
public function origin() {
|
||||
|
||||
// Return from cache if possible
|
||||
if($this->origin) {
|
||||
return $this->origin;
|
||||
}
|
||||
|
||||
$origin = $this->page();
|
||||
|
||||
if($this->parent()) {
|
||||
$origin = $origin->find($this->parent());
|
||||
}
|
||||
|
||||
if(!is_a($origin, 'Page')) {
|
||||
throw new Exception('The parent page could not be found');
|
||||
}
|
||||
|
||||
return $this->origin = $origin;
|
||||
|
||||
}
|
||||
|
||||
public function entries() {
|
||||
|
||||
// Return from cache if possible
|
||||
if(!is_null($this->entries)) {
|
||||
return $this->entries;
|
||||
}
|
||||
|
||||
$entries = $this->origin()->children();
|
||||
|
||||
// Filter the entries
|
||||
if($entries->count() && $this->prefix()) {
|
||||
$entries = $entries->filter(function($page) {
|
||||
return str::startsWith($page->intendedTemplate(), $this->prefix());
|
||||
});
|
||||
}
|
||||
|
||||
// Sort entries
|
||||
if($entries->count() && $this->value()) {
|
||||
$i = 0;
|
||||
|
||||
$order = a::merge(array_flip($this->value()), array_flip($entries->pluck('uid')));
|
||||
$order = array_map(function($value) use(&$i) {
|
||||
return $i++;
|
||||
}, $order);
|
||||
|
||||
$entries = $entries->find(array_flip($order));
|
||||
}
|
||||
|
||||
// Always return a collection
|
||||
if(is_a($entries, 'Page')) {
|
||||
$page = $entries;
|
||||
$entries = new Children($this->origin());
|
||||
|
||||
$entries->data[$page->id()] = $page;
|
||||
}
|
||||
|
||||
return $this->entries = $entries;
|
||||
|
||||
}
|
||||
|
||||
public function counter() {
|
||||
|
||||
if($this->limit()) {
|
||||
|
||||
$counter = new Brick('span');
|
||||
$counter->addClass('sortable__counter');
|
||||
$counter->append('( ' . $this->entries()->published()->count() . ' / ' . $this->limit() . ' )');
|
||||
|
||||
return $counter;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function label() {
|
||||
return $this->i18n($this->label);
|
||||
}
|
||||
|
||||
public function validate() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function value() {
|
||||
|
||||
$value = parent::value();
|
||||
if(is_array($value)) {
|
||||
return $value;
|
||||
} else {
|
||||
return str::split($value, ',');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function result() {
|
||||
|
||||
$result = parent::result();
|
||||
return is_array($result) ? implode(', ', $result) : '';
|
||||
|
||||
}
|
||||
|
||||
public function url($action = null) {
|
||||
|
||||
$url = purl($this->model(), 'field/' . $this->name() . '/' . $this->type());
|
||||
|
||||
if(is_null($action)) {
|
||||
return $url;
|
||||
}
|
||||
|
||||
return $url . '/action/' . $action;
|
||||
|
||||
}
|
||||
|
||||
public function template() {
|
||||
return $this->element()
|
||||
->append($this->content())
|
||||
->append($this->help());
|
||||
}
|
||||
|
||||
}
|
||||
22
site/OFF_plugins/sortable/fields/sortable/template.php
Normal file
22
site/OFF_plugins/sortable/fields/sortable/template.php
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<label class="label">
|
||||
<?= $field->label(); ?>
|
||||
<?= $field->counter(); ?>
|
||||
<!-- <?= $field->action('add'); ?> -->
|
||||
</label>
|
||||
|
||||
<?php if($field->entries()->count()): ?>
|
||||
<?= $field->layouts(); ?>
|
||||
<?php else: ?>
|
||||
<!-- <div class="sortable__empty">
|
||||
<?= $field->l('field.sortable.empty'); ?>
|
||||
<?= $field->action('add', ['label' => $field->l('field.sortable.add.first'), 'icon' => '', 'class' => '']); ?>
|
||||
<?= $field->l('field.sortable.or'); ?>
|
||||
<?= $field->action('paste', ['label' => $field->l('field.sortable.paste.first'), 'icon' => '', 'class' => '']); ?>
|
||||
</div> -->
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- <div class="sortable__navigation">
|
||||
<?= $field->action('copy'); ?>
|
||||
<?= $field->action('paste'); ?>
|
||||
<?= $field->action('add'); ?>
|
||||
</div> -->
|
||||
Loading…
Add table
Add a link
Reference in a new issue