Merge branch 'develop' into feature/admin-gpm-dependencies

This commit is contained in:
Flavio Copes
2016-03-15 18:06:34 +01:00
parent 0dc477e227
commit f6debf1dcc
20 changed files with 1075 additions and 48 deletions

View File

@@ -535,6 +535,9 @@ class AdminPlugin extends Plugin
'tabs' => [
'input@' => false
],
'key' => [
'input@' => false
],
'list' => [
'array' => true
]

View File

@@ -0,0 +1,32 @@
title: PLUGIN_ADMIN.MEDIA
form:
validation: loose
fields:
'':
name: media
type: list
label: Media Types
key: extension
sort: false
fields:
.extension:
type: key
label: File Extension
.type:
type: text
label: Type
.thumb:
type: text
label: Thumb
.mime:
type: text
label: Mime Type
.image:
type: textarea
yaml: true
label: Image options
validate:
type: yaml

View File

@@ -5,7 +5,6 @@ form:
fields:
- name: username
type: text
placeholder: Username
placeholder: PLUGIN_ADMIN.USERNAME
autofocus: true
---

View File

@@ -9,12 +9,10 @@ form:
fields:
- name: username
type: text
placeholder: Username
placeholder: PLUGIN_ADMIN.USERNAME
autofocus: true
- name: password
type: password
placeholder: Password
placeholder: PLUGIN_ADMIN.PASSWORD
---

View File

@@ -5,10 +5,10 @@ form:
fields:
- name: username
type: text
placeholder: Username
placeholder: PLUGIN_ADMIN.USERNAME
autofocus: true
- name: password
type: password
placeholder: Password
placeholder: PLUGIN_ADMIN.PASSWORD
---

View File

@@ -5,13 +5,12 @@ form:
fields:
- name: username
type: text
placeholder: Username
placeholder: PLUGIN_ADMIN.USERNAME
readonly: true
- name: password
type: password
placeholder: Password
placeholder: PLUGIN_ADMIN.PASSWORD
autofocus: true
- name: token
type: hidden
---

View File

@@ -20,7 +20,7 @@ export default class CollectionsField {
list.find('[data-collection-holder]').each((index, container) => {
container = $(container);
if (container.data('collection-sort')) { return; }
if (container.data('collection-sort') || container[0].hasAttribute('data-collection-nosort')) { return; }
container.data('collection-sort', new Sortable(container.get(0), {
forceFallback: false,
@@ -38,13 +38,9 @@ export default class CollectionsField {
list.find('> [data-collection-holder]').append(template);
this.reindex(list);
// button.data('key-index', keyIndex + 1);
// process markdown editors
/* var field = template.find('[name]').filter('textarea');
if (field.length && field.data('grav-mdeditor') && typeof MDEditors !== 'undefined') {
MDEditors.add(field);
}*/
// refresh toggleables in a list
$('[data-grav-field="toggleable"] input[type="checkbox"]').trigger('change');
}
removeItem(event) {
@@ -65,7 +61,7 @@ export default class CollectionsField {
item = $(item);
item.attr('data-collection-key', index);
['name', 'data-grav-field-name', 'id', 'for'].forEach((prop) => {
['name', 'data-grav-field-name', 'for', 'id'].forEach((prop) => {
item.find('[' + prop + ']').each(function() {
let element = $(this);
let indexes = [];

View File

@@ -0,0 +1,570 @@
import $ from 'jquery';
import clamp from 'mout/math/clamp';
import bind from 'mout/function/bind';
import { rgbstr2hex, hsb2hex, hex2hsb, hex2rgb, parseHex } from '../../utils/colors';
const isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
const body = $('body');
const MOUSEDOWN = 'mousedown touchstart MSPointerDown pointerdown';
const MOUSEMOVE = 'mousemove touchmove MSPointerMove pointermove';
const MOUSEUP = 'mouseup touchend MSPointerUp pointerup';
const FOCUSIN = isFirefox ? 'focus' : 'focusin';
export default class ColorpickerField {
constructor(selector) {
this.selector = selector;
this.field = $(this.selector);
this.options = Object.assign({}, this.field.data('grav-colorpicker'));
this.built = false;
this.attach();
if (this.options.update) {
this.field.on('change._grav_colorpicker', (event, field, hex, opacity) => {
let backgroundColor = hex;
let rgb = hex2rgb(hex);
if (opacity < 1) {
backgroundColor = 'rgba(' + rgb.r + ', ' + rgb.g + ', ' + rgb.b + ', ' + opacity + ')';
}
let target = field.closest(this.options.update);
if (!target.lenght) {
target = field.siblings(this.options.update);
}
target.css({ backgroundColor });
});
}
}
attach() {
body.on(FOCUSIN, this.selector, (event) => this.show(event, event.currentTarget));
body.on(MOUSEDOWN, '.g-colorpicker i', this.bound('iconClick'));
body.on('keydown', this.selector, (event) => {
switch (event.keyCode) {
case 9: // tab
this.hide();
break;
case 13: // enter
case 27: // esc
this.hide();
event.currentTarget.blur();
break;
}
return true;
});
// Update on keyup
body.on('keyup', this.selector, (event) => {
this.updateFromInput(true, event.currentTarget);
return true;
});
// Update on paste
body.on('paste', this.selector, (event) => {
setTimeout(() => this.updateFromInput(true, event.currentTarget), 1);
});
}
show(event, target) {
target = $(target);
if (!this.built) {
this.build();
}
this.element = target;
this.reposition();
this.wrapper.addClass('cp-visible');
this.updateFromInput();
let mainContainer = $('#admin-main .content-wrapper').data('scrollbar').getViewElement();
this.wrapper.on(MOUSEDOWN, '.cp-grid, .cp-slider, .cp-opacity-slider', this.bound('bodyDown'));
body.on(MOUSEMOVE, this.bound('bodyMove'));
body.on(MOUSEDOWN, this.bound('bodyClick'));
body.on(MOUSEUP, this.bound('targetReset'));
$(mainContainer).on('scroll', this.bound('reposition'));
}
hide() {
if (!this.built) { return; }
this.wrapper.removeClass('cp-visible');
let mainContainer = $('#admin-main .content-wrapper').data('scrollbar').getViewElement();
this.wrapper.undelegate(MOUSEDOWN, '.cp-grid, .cp-slider, .cp-opacity-slider', this.bound('bodyDown'));
body.off(MOUSEMOVE, this.bound('bodyMove'));
body.off(MOUSEDOWN, this.bound('bodyClick'));
body.off(MOUSEUP, this.bound('targetReset'));
$(mainContainer).off('scroll', this.bound('reposition'));
}
build() {
this.wrapper = $('<div class="cp-wrapper cp-with-opacity cp-mode-hue" />');
this.slider = $('<div class="cp-slider cp-sprite" />').appendTo(this.wrapper).append($('<div class="cp-picker" />'));
this.opacitySlider = $('<div class="cp-opacity-slider cp-sprite" />').appendTo(this.wrapper).append($('<div class="cp-picker" />'));
this.grid = $('<div class="cp-grid cp-sprite" />').appendTo(this.wrapper).append($('<div class="cp-grid-inner" />')).append($('<div class="cp-picker" />'));
$('<div />').appendTo(this.grid.find('.cp-picker'));
let tabs = $('<div class="cp-tabs" />').appendTo(this.wrapper);
this.tabs = {
hue: $('<div class="cp-tab-hue active" />').text('HUE').appendTo(tabs),
brightness: $('<div class="cp-tab-brightness" />').text('BRI').appendTo(tabs),
saturation: $('<div class="cp-tab-saturation" />').text('SAT').appendTo(tabs),
wheel: $('<div class="cp-tab-wheel" />').text('WHEEL').appendTo(tabs),
transparent: $('<div class="cp-tab-transp" />').text('TRANSPARENT').appendTo(tabs)
};
tabs.on(MOUSEDOWN, '> div', (event) => {
let element = $(event.currentTarget);
if (element.is(this.tabs.transparent)) {
let sliderHeight = this.opacitySlider.height();
this.opacity = 0;
this.opacitySlider.find('.cp-picker').css({ 'top': clamp(sliderHeight - (sliderHeight * this.opacity), 0, sliderHeight) });
this.move(this.opacitySlider, { manualOpacity: true });
return;
}
let active = tabs.find('.active');
let mode = active.attr('class').replace(/\s|active|cp-tab-/g, '');
let newMode = element.attr('class').replace(/\s|active|cp-tab-/g, '');
this.wrapper.removeClass('cp-mode-' + mode).addClass('cp-mode-' + newMode);
active.removeClass('active');
element.addClass('active');
this.mode = newMode;
this.updateFromInput();
});
this.wrapper.appendTo('.content-wrapper');
this.built = true;
this.mode = 'hue';
}
reposition() {
let offset = this.element[0].getBoundingClientRect();
let ct = $('.content-wrapper')[0].getBoundingClientRect();
this.wrapper.css({
top: offset.top + offset.height - ct.top,
left: offset.left - ct.left
});
}
iconClick(event, element) {
event && event.preventDefault();
let input = $(event.currentTarget).siblings('input');
input.focus();
this.show(event, input);
}
bodyMove(event) {
event && event.preventDefault();
if (this.target) { this.move(this.target, event); }
}
bodyClick(event) {
let target = $(event.target);
if (!target.closest('.cp-wrapper').length && !target.is(this.selector)) {
this.hide();
}
}
bodyDown(event) {
event && event.preventDefault();
this.target = $(event.currentTarget);
this.move(this.target, event, true);
}
targetReset(event) {
event && event.preventDefault();
this.target = null;
}
move(target, event) {
let input = this.element;
let picker = target.find('.cp-picker');
let clientRect = target[0].getBoundingClientRect();
let offsetX = clientRect.left + window.scrollX;
let offsetY = clientRect.top + window.scrollY;
let x = Math.round((event ? event.pageX : 0) - offsetX);
let y = Math.round((event ? event.pageY : 0) - offsetY);
let wx;
let wy;
let r;
let phi;
// Touch support
if (event && event.changedTouches) {
x = (event.changedTouches ? event.changedTouches[0].pageX : 0) - offsetX;
y = (event.changedTouches ? event.changedTouches[0].pageY : 0) - offsetY;
}
if (event && event.manualOpacity) {
y = clientRect.height;
}
// Constrain picker to its container
if (x < 0) x = 0;
if (y < 0) y = 0;
if (x > clientRect.width) x = clientRect.width;
if (y > clientRect.height) y = clientRect.height;
// Constrain color wheel values to the wheel
if (target.parent('.cp-mode-wheel').length && picker.parent('.cp-grid').length) {
wx = 75 - x;
wy = 75 - y;
r = Math.sqrt(wx * wx + wy * wy);
phi = Math.atan2(wy, wx);
if (phi < 0) phi += Math.PI * 2;
if (r > 75) {
x = 75 - (75 * Math.cos(phi));
y = 75 - (75 * Math.sin(phi));
}
x = Math.round(x);
y = Math.round(y);
}
// Move the picker
if (target.hasClass('cp-grid')) {
picker.css({
top: y,
left: x
});
this.updateFromPicker(input, target);
} else {
picker.css({
top: y
});
this.updateFromPicker(input, target);
}
}
updateFromInput(dontFireEvent, element) {
element = element ? $(element) : this.element;
let value = element.val();
let opacity = value.replace(/\s/g, '').match(/^rgba?\([0-9]{1,3},[0-9]{1,3},[0-9]{1,3},(.+)\)/);
let hex;
let hsb;
value = rgbstr2hex(value) || value;
opacity = opacity ? clamp(opacity[1], 0, 1) : 1;
if (!(hex = parseHex(value))) { hex = '#ffffff'; }
hsb = hex2hsb(hex);
if (this.built) {
// opacity
this.opacity = opacity;
var sliderHeight = this.opacitySlider.height();
this.opacitySlider.find('.cp-picker').css({ 'top': clamp(sliderHeight - (sliderHeight * this.opacity), 0, sliderHeight) });
// bg color
let gridHeight = this.grid.height();
let gridWidth = this.grid.width();
let r;
let phi;
let x;
let y;
sliderHeight = this.slider.height();
switch (this.mode) {
case 'wheel':
// Set grid position
r = clamp(Math.ceil(hsb.s * 0.75), 0, gridHeight / 2);
phi = hsb.h * Math.PI / 180;
x = clamp(75 - Math.cos(phi) * r, 0, gridWidth);
y = clamp(75 - Math.sin(phi) * r, 0, gridHeight);
this.grid.css({ backgroundColor: 'transparent' }).find('.cp-picker').css({
top: y,
left: x
});
// Set slider position
y = 150 - (hsb.b / (100 / gridHeight));
if (hex === '') y = 0;
this.slider.find('.cp-picker').css({ top: y });
// Update panel color
this.slider.css({
backgroundColor: hsb2hex({
h: hsb.h,
s: hsb.s,
b: 100
})
});
break;
case 'saturation':
// Set grid position
x = clamp((5 * hsb.h) / 12, 0, 150);
y = clamp(gridHeight - Math.ceil(hsb.b / (100 / gridHeight)), 0, gridHeight);
this.grid.find('.cp-picker').css({
top: y,
left: x
});
// Set slider position
y = clamp(sliderHeight - (hsb.s * (sliderHeight / 100)), 0, sliderHeight);
this.slider.find('.cp-picker').css({ top: y });
// Update UI
this.slider.css({
backgroundColor: hsb2hex({
h: hsb.h,
s: 100,
b: hsb.b
})
});
this.grid.find('.cp-grid-inner').css({ opacity: hsb.s / 100 });
break;
case 'brightness':
// Set grid position
x = clamp((5 * hsb.h) / 12, 0, 150);
y = clamp(gridHeight - Math.ceil(hsb.s / (100 / gridHeight)), 0, gridHeight);
this.grid.find('.cp-picker').css({
top: y,
left: x
});
// Set slider position
y = clamp(sliderHeight - (hsb.b * (sliderHeight / 100)), 0, sliderHeight);
this.slider.find('.cp-picker').css({ top: y });
// Update UI
this.slider.css({
backgroundColor: hsb2hex({
h: hsb.h,
s: hsb.s,
b: 100
})
});
this.grid.find('.cp-grid-inner').css({ opacity: 1 - (hsb.b / 100) });
break;
case 'hue':
default:
// Set grid position
x = clamp(Math.ceil(hsb.s / (100 / gridWidth)), 0, gridWidth);
y = clamp(gridHeight - Math.ceil(hsb.b / (100 / gridHeight)), 0, gridHeight);
this.grid.find('.cp-picker').css({
top: y,
left: x
});
// Set slider position
y = clamp(sliderHeight - (hsb.h / (360 / sliderHeight)), 0, sliderHeight);
this.slider.find('.cp-picker').css({ top: y });
// Update panel color
this.grid.css({
backgroundColor: hsb2hex({
h: hsb.h,
s: 100,
b: 100
})
});
break;
}
}
if (!dontFireEvent) { element.val(this.getValue(hex)); }
this.element.trigger('change._grav_colorpicker', [element, hex, opacity]);
}
updateFromPicker(input, target) {
var getCoords = function(picker, container) {
var left, top;
if (!picker.length || !container) return null;
left = picker[0].getBoundingClientRect().left;
top = picker[0].getBoundingClientRect().top;
return {
x: left - container[0].getBoundingClientRect().left + (picker[0].offsetWidth / 2),
y: top - container[0].getBoundingClientRect().top + (picker[0].offsetHeight / 2)
};
};
let hex;
let hue;
let saturation;
let brightness;
let x;
let y;
let r;
let phi;
// Panel objects
let grid = this.wrapper.find('.cp-grid');
let slider = this.wrapper.find('.cp-slider');
let opacitySlider = this.wrapper.find('.cp-opacity-slider');
// Picker objects
let gridPicker = grid.find('.cp-picker');
let sliderPicker = slider.find('.cp-picker');
let opacityPicker = opacitySlider.find('.cp-picker');
// Picker positions
let gridPos = getCoords(gridPicker, grid);
let sliderPos = getCoords(sliderPicker, slider);
let opacityPos = getCoords(opacityPicker, opacitySlider);
// Sizes
let gridWidth = grid[0].getBoundingClientRect().width;
let gridHeight = grid[0].getBoundingClientRect().height;
let sliderHeight = slider[0].getBoundingClientRect().height;
let opacitySliderHeight = opacitySlider[0].getBoundingClientRect().height;
let value = this.element.val();
value = rgbstr2hex(value) || value;
if (!(hex = parseHex(value))) { hex = '#ffffff'; }
// Handle colors
if (target.hasClass('cp-grid') || target.hasClass('cp-slider')) {
// Determine HSB values
switch (this.mode) {
case 'wheel':
// Calculate hue, saturation, and brightness
x = (gridWidth / 2) - gridPos.x;
y = (gridHeight / 2) - gridPos.y;
r = Math.sqrt(x * x + y * y);
phi = Math.atan2(y, x);
if (phi < 0) phi += Math.PI * 2;
if (r > 75) {
r = 75;
gridPos.x = 69 - (75 * Math.cos(phi));
gridPos.y = 69 - (75 * Math.sin(phi));
}
saturation = clamp(r / 0.75, 0, 100);
hue = clamp(phi * 180 / Math.PI, 0, 360);
brightness = clamp(100 - Math.floor(sliderPos.y * (100 / sliderHeight)), 0, 100);
hex = hsb2hex({
h: hue,
s: saturation,
b: brightness
});
// Update UI
slider.css({
backgroundColor: hsb2hex({
h: hue,
s: saturation,
b: 100
})
});
break;
case 'saturation':
// Calculate hue, saturation, and brightness
hue = clamp(parseInt(gridPos.x * (360 / gridWidth), 10), 0, 360);
saturation = clamp(100 - Math.floor(sliderPos.y * (100 / sliderHeight)), 0, 100);
brightness = clamp(100 - Math.floor(gridPos.y * (100 / gridHeight)), 0, 100);
hex = hsb2hex({
h: hue,
s: saturation,
b: brightness
});
// Update UI
slider.css({
backgroundColor: hsb2hex({
h: hue,
s: 100,
b: brightness
})
});
grid.find('.cp-grid-inner').css({ opacity: saturation / 100 });
break;
case 'brightness':
// Calculate hue, saturation, and brightness
hue = clamp(parseInt(gridPos.x * (360 / gridWidth), 10), 0, 360);
saturation = clamp(100 - Math.floor(gridPos.y * (100 / gridHeight)), 0, 100);
brightness = clamp(100 - Math.floor(sliderPos.y * (100 / sliderHeight)), 0, 100);
hex = hsb2hex({
h: hue,
s: saturation,
b: brightness
});
// Update UI
slider.css({
backgroundColor: hsb2hex({
h: hue,
s: saturation,
b: 100
})
});
grid.find('.cp-grid-inner').css({ opacity: 1 - (brightness / 100) });
break;
default:
// Calculate hue, saturation, and brightness
hue = clamp(360 - parseInt(sliderPos.y * (360 / sliderHeight), 10), 0, 360);
saturation = clamp(Math.floor(gridPos.x * (100 / gridWidth)), 0, 100);
brightness = clamp(100 - Math.floor(gridPos.y * (100 / gridHeight)), 0, 100);
hex = hsb2hex({
h: hue,
s: saturation,
b: brightness
});
// Update UI
grid.css({
backgroundColor: hsb2hex({
h: hue,
s: 100,
b: 100
})
});
break;
}
}
// Handle opacity
if (target.hasClass('cp-opacity-slider')) {
this.opacity = parseFloat(1 - (opacityPos.y / opacitySliderHeight)).toFixed(2);
}
// Adjust case
input.val(this.getValue(hex));
// Handle change event
this.element.trigger('change._grav_colorpicker', [this.element, hex, this.opacity]);
}
getValue(hex) {
if (this.opacity === 1) { return hex; }
let rgb = hex2rgb(hex);
return 'rgba(' + rgb.r + ', ' + rgb.g + ', ' + rgb.b + ', ' + this.opacity + ')';
}
bound(name) {
let bound = this._bound || (this._bound = {});
return bound[name] || (bound[name] = bind(this[name], this));
}
}
export let Instance = new ColorpickerField('[data-grav-colorpicker]');

View File

@@ -3,7 +3,7 @@ import ArrayField, { Instance as ArrayFieldInstance } from './array';
import CollectionsField, { Instance as CollectionsFieldInstance } from './collections';
import DateTimeField, { Instance as DateTimeFieldInstance } from './datetime';
import EditorField, { Instance as EditorFieldInstance } from './editor';
// import ColorpickerField, { Instance as ColorpickerFieldInstance } from './colorpicker';
import ColorpickerField, { Instance as ColorpickerFieldInstance } from './colorpicker';
export default {
SelectizeField: {
@@ -25,9 +25,9 @@ export default {
EditorField: {
EditorField,
Instance: EditorFieldInstance
},
ColorpickerField: {
ColorpickerField,
Instance: ColorpickerFieldInstance
}
// ColorpickerField: {
// ColorpickerField,
// Instance: ColorpickerFieldInstance
// }
};

View File

@@ -20,6 +20,13 @@ export default class Form {
}
}); */
// clear out any `noform` field from its name
this.form.on('submit', () => {
$('.no-form').attr('name', null);
return true;
});
this._attachShortcuts();
this._attachToggleables();
this._attachDisabledFields();
@@ -52,7 +59,7 @@ export default class Form {
this.form.on('change', query, (event) => {
let toggle = $(event.target);
let enabled = toggle.is(':checked');
let parent = toggle.parents('.form-field');
let parent = toggle.closest('.form-field');
let label = parent.find('label.toggleable');
let fields = parent.find('.form-data');
let inputs = fields.find('input, select, textarea');
@@ -82,8 +89,7 @@ export default class Form {
});
this.form.on('mousedown', query.join(', '), (event) => {
let target = $(event.target);
let input = target;
let input = $(event.target);
let isFor = input.prop('for');
let isSelectize = (input.hasClass('selectize-control') || input.parents('.selectize-control')).length;

View File

@@ -0,0 +1,152 @@
// Parses a string and returns a valid hex string when possible
// parseHex('#fff') => '#ffffff'
export const parseHex = (string) => {
string = string.replace(/[^A-F0-9]/ig, '');
if (string.length !== 3 && string.length !== 6) return '';
if (string.length === 3) {
string = string[0] + string[0] + string[1] + string[1] + string[2] + string[2];
}
return '#' + string.toLowerCase();
};
// Converts an HSB object to an RGB object
// hsb2rgb({h: 0, s: 0, b: 100}) => {r: 255, g: 255, b: 255}
export const hsb2rgb = (hsb) => {
let rgb = {};
let h = Math.round(hsb.h);
let s = Math.round(hsb.s * 255 / 100);
let v = Math.round(hsb.b * 255 / 100);
if (s === 0) {
rgb.r = rgb.g = rgb.b = v;
} else {
var t1 = v;
var t2 = (255 - s) * v / 255;
var t3 = (t1 - t2) * (h % 60) / 60;
if (h === 360) h = 0;
if (h < 60) {
rgb.r = t1;
rgb.b = t2;
rgb.g = t2 + t3;
} else if (h < 120) {
rgb.g = t1;
rgb.b = t2;
rgb.r = t1 - t3;
} else if (h < 180) {
rgb.g = t1;
rgb.r = t2;
rgb.b = t2 + t3;
} else if (h < 240) {
rgb.b = t1;
rgb.r = t2;
rgb.g = t1 - t3;
} else if (h < 300) {
rgb.b = t1;
rgb.g = t2;
rgb.r = t2 + t3;
} else if (h < 360) {
rgb.r = t1;
rgb.g = t2;
rgb.b = t1 - t3;
} else {
rgb.r = 0;
rgb.g = 0;
rgb.b = 0;
}
}
return {
r: Math.round(rgb.r),
g: Math.round(rgb.g),
b: Math.round(rgb.b)
};
};
// Converts an RGB object to a HEX string
// rgb2hex({r: 255, g: 255, b: 255}) => #ffffff
export const rgb2hex = (rgb) => {
var hex = [
rgb.r.toString(16),
rgb.g.toString(16),
rgb.b.toString(16)
];
hex.forEach((val, nr) => {
if (val.length === 1) hex[nr] = '0' + val;
});
return '#' + hex.join('');
};
// Converts and RGB(a) string to a HEX string
// rgbstr2hex('rgba(255, 255, 255, 0.5)') => #ffffff
export const rgbstr2hex = (rgb) => {
rgb = rgb.match(/^rgba?[\s+]?\([\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?/i);
return (rgb && rgb.length === 4) ? '#' +
('0' + parseInt(rgb[1], 10).toString(16)).slice(-2) +
('0' + parseInt(rgb[2], 10).toString(16)).slice(-2) +
('0' + parseInt(rgb[3], 10).toString(16)).slice(-2) : '';
};
// Converts an HSB object to a HEX string
// hsb2hex({h: 0, s: 0, b: 100}) => #ffffff
export const hsb2hex = (hsb) => {
return rgb2hex(hsb2rgb(hsb));
};
// Converts a HEX string to an HSB object
// hex2hsb('#ffffff') => {h: 0, s: 0, b: 100}
export const hex2hsb = (hex) => {
let hsb = rgb2hsb(hex2rgb(hex));
if (hsb.s === 0) hsb.h = 360;
return hsb;
};
// Converts an RGB object to an HSB object
// rgb2hsb({r: 255, g: 255, b: 255}) => {h: 0, s: 0, b: 100}
export const rgb2hsb = (rgb) => {
let hsb = {
h: 0,
s: 0,
b: 0
};
let min = Math.min(rgb.r, rgb.g, rgb.b);
let max = Math.max(rgb.r, rgb.g, rgb.b);
let delta = max - min;
hsb.b = max;
hsb.s = max !== 0 ? 255 * delta / max : 0;
if (hsb.s !== 0) {
if (rgb.r === max) {
hsb.h = (rgb.g - rgb.b) / delta;
} else if (rgb.g === max) {
hsb.h = 2 + (rgb.b - rgb.r) / delta;
} else {
hsb.h = 4 + (rgb.r - rgb.g) / delta;
}
} else {
hsb.h = -1;
}
hsb.h *= 60;
if (hsb.h < 0) {
hsb.h += 360;
}
hsb.s *= 100 / 255;
hsb.b *= 100 / 255;
return hsb;
};
// Converts a HEX string to an RGB object
// hex2rgb('#ffffff') => {r: 255, g: 255, b: 255}
export const hex2rgb = (hex) => {
hex = parseInt(((hex.indexOf('#') > -1) ? hex.substring(1) : hex), 16);
return {
/* jshint ignore:start */
r: hex >> 16,
g: (hex & 0x00FF00) >> 8,
b: (hex & 0x0000FF)
/* jshint ignore:end */
};
};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -24,6 +24,7 @@
"gemini-scrollbar": "^1.3.2",
"immutable": "^3.7.6",
"js-yaml": "^3.5.3",
"mout": "^0.12.0",
"remodal": "^1.0.6",
"selectize": "^0.12.1",
"sortablejs": "^1.4.2",

View File

@@ -2,3 +2,4 @@
@import "toggle-switch";
@import "datetimepicker";
@import "scrollbars";
@import "colorpicker";

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,26 @@
{% extends "forms/field.html.twig" %}
{% block input %}
<div class="form-input-wrapper {{ field.size }}">
<input
type="text"
value="{{ value|e('html_attr')|join(', ') }}"
data-list-key="{{ scope|fieldName }}"
{% block input_attributes %}
{% if field.classes is defined %}class="{{ field.classes }}" {% endif %}
{% if field.id is defined %}id="{{ field.id|e }}" {% endif %}
{% if field.style is defined %}style="{{ field.style|e }}" {% endif %}
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}
{% if field.placeholder %}placeholder="{{ field.placeholder }}"{% endif %}
{% if field.autofocus in ['on', 'true', 1] %}autofocus="autofocus"{% endif %}
{% if field.novalidate in ['on', 'true', 1] %}novalidate="novalidate"{% endif %}
{% if field.readonly in ['on', 'true', 1] %}readonly="readonly"{% endif %}
{% if field.autocomplete in ['on', 'off'] %}autocomplete="{{ field.autocomplete }}"{% endif %}
{% if field.validate.required in ['on', 'true', 1] %}required="required"{% endif %}
{% if field.validate.pattern %}pattern="{{ field.validate.pattern }}"{% endif %}
{% if field.validate.message %}title="{{ field.validate.message|e|t }}"
{% elseif field.title is defined %}title="{{ field.title|e|t }}" {% endif %}
{% endblock %}
/>
</div>
{% endblock %}

View File

@@ -2,6 +2,7 @@
{% set name = scope ~ field.name %}
{% set btnLabel = field.btnLabel is defined ? field.btnLabel : "PLUGIN_ADMIN.ADD_ITEM" %}
<div class="form-field grid pure-g">
<div class="form-label block size-1-4 pure-u-1-4">
<label>
@@ -15,10 +16,13 @@
</div>
<div class="form-data block size-3-4 pure-u-3-4">
<div class="form-list-wrapper {{ field.size }}" data-type="collection">
<ul data-collection-holder="{{ name }}">
<ul data-collection-holder="{{ name }}"
{% if field.sort is same as(false) %}
data-collection-nosort
{% endif %}>
{% if field.fields %}
{% for key, val in value %}
{% set itemName = name ~ '.' ~ key %}
{% set itemName = name ? name ~ '.' ~ key : key %}
<li data-collection-item="{{ itemName }}" data-collection-key="{{ key }}">
{% for childName, child in field.fields %}
{% if childName starts with '.' %}
@@ -34,7 +38,7 @@
{% if child.type == 'key' %}
{%
include 'forms/fields/text/text.html.twig'
include 'forms/fields/key/key.html.twig'
with { field: child, value: key }
%}
{% elseif child.type %}
@@ -47,8 +51,10 @@
{% endif %}
{% endfor %}
<div class="item-actions">
{% if field.sort is not same as(false) %}
<i class="fa fa-bars"></i>
<br />
{% endif %}
<i class="fa fa-trash-o" data-action="delete"></i>
</div>
</li>
@@ -59,10 +65,10 @@
<button class="button" type="button" data-action="add"><i class="fa fa-plus"></i> {{ btnLabel|e|tu }}</button>
</div>
{%- set itemName = name ? name ~ '.*' : '*' -%}
<div style="display: none;" data-collection-template="new" data-collection-template-html="{%- filter replace({' ': ' ', '\n': ' '})|e('html_attr') -%}
<li data-collection-item="{{ name ~ '.*' }}">
<li data-collection-item="{{ itemName }}">
{%- if field.fields -%}
{%- set itemName = name ~ '.*' -%}
{%- for childName, child in field.fields -%}
{%- if childName starts with '.' -%}
{%- set childKey = childName|trim('.') -%}
@@ -75,7 +81,7 @@
{%- if child.type == 'key' -%}
{%-
include 'forms/fields/text/text.html.twig'
include 'forms/fields/key/key.html.twig'
with { field: child, value: null }
-%}
{%- elseif child.type -%}
@@ -88,8 +94,10 @@
{%- endif -%}
{%- endfor %}
<div class="item-actions">
{% if field.sort is not same as(false) %}
<i class="fa fa-bars"></i>
<br />
{% endif %}
<i class="fa fa-trash-o" data-action="delete"></i>
</div>
{%- endif -%}

View File

@@ -10,7 +10,7 @@
<form id="{{ form_id }}" method="post" data-grav-form="{{ form_id }}" data-grav-keepalive="true"{{ multipart }}>
{% for field in blueprints.fields %}
{% if field.type %}
{% set value = data.value(field.name) %}
{% set value = field.name ? data.value(field.name) : data.toArray %}
<div class="block block-{{ field.type }}">
{% include ["forms/fields/#{field.type}/#{field.type}.html.twig", 'forms/fields/text/text.html.twig'] %}