maj+ header

This commit is contained in:
2018-08-22 14:46:33 +02:00
parent 28c9e9d76f
commit 3fc62ab1f1
443 changed files with 24198 additions and 6201 deletions
+18
View File
@@ -0,0 +1,18 @@
# EditorConfig is awesome: http://EditorConfig.org
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*]
charset = utf-8
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
indent_style = space
indent_size = 4
# 2 space indentation
[*.yaml, *.yml]
indent_style = space
indent_size = 2
+14
View File
@@ -0,0 +1,14 @@
themes/grav/.sass-cache
.DS_Store
# Node Modules
**/node_modules/**
themes/grav/js/admin.js
themes/grav/js/vendor.js
themes/grav/js/*.map
/.idea
tests/_output/*
tests/_support/_generated/*
tests/cache/*
tests/error.log
+12
View File
@@ -1,6 +1,18 @@
# v1.8.8
## 08/17/2018
1. [](#improved)
* Added support for textarea value type in `array` field
* Added some new lang strings for Grav 1.5.0
1. [](#bugfix)
* Support params and querystring in login redirect
* Added field name nesting with tab field
# v1.8.7
## 07/31/2018
1. [](#improved)
* Support URI Params and Query attributes in Login redirect
1. [](#bugfix)
* Fix for deleting 'extra' media files [grav#2100](https://githubcom/getgrav/grav/issues/2100)
+1 -1
View File
@@ -1,5 +1,5 @@
name: Admin Panel
version: 1.8.7
version: 1.8.8
description: Adds an advanced administration panel to manage your site
icon: empire
author:
+15
View File
@@ -0,0 +1,15 @@
{
"project":"grav-plugin-admin",
"platforms":{
"grav":{
"nodes":{
"plugin":[
{
"source":"/",
"destination":"/user/plugins/admin"
}
]
}
}
}
}
+5 -1
View File
@@ -719,4 +719,8 @@ PLUGIN_ADMIN:
OPEN_NEW_TAB: "Open in new tab"
PAGEMEDIA_RESIZER: "> The following settings apply to images uploaded through the page media. Resize Width / Height will automatically resize down and proportionally an image if exceeds the limits set in the inputs. Resolution min and max values define the size ranges for uploaded images. Set the fields to 0 to prevent any manipulation."
SESSION_INITIALIZE: "Initialize Session"
SESSION_INITIALIZE_HELP: "Makes Grav to start a session. This feature is needed to make any user interaction to work, such as login, forms etc. Admin plugin isn't affected by this setting."
SESSION_INITIALIZE_HELP: "Makes Grav to start a session. This feature is needed to make any user interaction to work, such as login, forms etc. Admin plugin isn't affected by this setting."
STRICT_YAML_COMPAT: "YAML Compatibility"
STRICT_YAML_COMPAT_HELP: "Falls back to Symfony 2.4 YAML parser if Native or 3.4 parser fails"
STRICT_TWIG_COMPAT: "Twig Compatibility"
STRICT_TWIG_COMPAT_HELP: "Enables deprecated Twig autoescape setting. When disabled, |raw filter is required to output HTML as Twig will autoescape output"
@@ -28,6 +28,10 @@ class Template {
return this.container.find('[data-grav-array-mode="value_only"]:first').length || false;
}
isTextArea() {
return this.container.data('grav-array-textarea') || false;
}
shouldBeDisabled() {
// check for toggleables, if field is toggleable and it's not enabled, render disabled
let toggle = this.container.closest('.form-field').find('[data-grav-field="toggleable"] input[type="checkbox"]');
@@ -35,20 +39,22 @@ class Template {
}
getNewRow() {
let tpl = '';
let tpl = '';const value = this.isTextArea()
? `<textarea ${this.shouldBeDisabled() ? 'disabled="disabled"' : ''} data-grav-array-type="value" name="" placeholder="${this.getValuePlaceholder()}"></textarea>`
: `<input ${this.shouldBeDisabled() ? 'disabled="disabled"' : ''} data-grav-array-type="value" type="text" name="" value="" placeholder="${this.getValuePlaceholder()}" />`;
if (this.isValueOnly()) {
tpl += `
<div class="form-row array-field-value_only" data-grav-array-type="row">
<span data-grav-array-action="sort" class="fa fa-bars"></span>
<input ${this.shouldBeDisabled() ? 'disabled="disabled"' : ''} data-grav-array-type="value" type="text" value="" placeholder="${this.getValuePlaceholder()}" />
${value}
`;
} else {
tpl += `
<div class="form-row" data-grav-array-type="row">
<span data-grav-array-action="sort" class="fa fa-bars"></span>
<input ${this.shouldBeDisabled() ? 'disabled="disabled"' : ''} data-grav-array-type="key" type="text" value="" placeholder="${this.getKeyPlaceholder()}" />
<input ${this.shouldBeDisabled() ? 'disabled="disabled"' : ''} data-grav-array-type="value" type="text" name="" value="" placeholder="${this.getValuePlaceholder()}" />
${value}
`;
}
View File
+1 -1
View File
@@ -1,3 +1,3 @@
@import url("https://fonts.googleapis.com/css?family=Roboto:300,400,500|Inconsolata:400,700|&subset=latin-ext");body,h5,h6,.badge,.note,.grav-mdeditor-preview,input,select,textarea,button,.selectize-input{font-family:"Roboto","Helvetica","Tahoma","Geneva","Arial",sans-serif}h1,h2,h3,h4,.form-tabs>label,.label{font-family:"Josefin Slab","Helvetica","Tahoma","Geneva","Arial",sans-serif}code,kbd,pre,samp,body .CodeMirror{font-family:"Inconsolata","Monaco","Consolas","Lucida Console",monospace !important}
/*# sourceMappingURL=../css-compiled/fonts.css.map */
/*# sourceMappingURL=fonts.css.map */
@@ -1,11 +1 @@
{
"version": 3,
"file": "../scss/fonts.css",
"sources": [
"../scss/fonts.scss",
"../hdr0",
"../scss/configuration/fonts/_support.scss"
],
"mappings": "AE+DA,OAAO,CAAC,uGAAI,CAtBR,AAAA,IAAI,CAAE,AAAA,EAAE,CAAE,AAAA,EAAE,CACZ,AAAA,MAAM,CAAE,AAAA,KAAK,CAAE,AAAA,sBAAsB,CACrC,AAAA,KAAK,CAAE,AAAA,MAAM,CAAE,AAAA,QAAQ,CAAE,AAAA,MAAM,CAAE,AAAA,gBAAgB,AAAC,CAC9C,WAAW,CAAE,QAAU,CAAE,WAAW,CAAE,QAAQ,CAAE,QAAQ,CAAE,OAAO,CAAE,UAAU,CAChF,AAID,AAAA,EAAE,CAAE,AAAA,EAAE,CAAE,AAAA,EAAE,CAAE,AAAA,EAAE,CACd,AAAa,UAAH,CAAG,KAAK,CAAE,AAAA,MAAM,AAAC,CACvB,WAAW,CAAE,cAAU,CAAE,WAAW,CAAE,QAAQ,CAAE,QAAQ,CAAE,OAAO,CAAE,UAAU,CAChF,AAID,AAAA,IAAI,CAAE,AAAA,GAAG,CAAE,AAAA,GAAG,CAAE,AAAA,IAAI,CACpB,AAAK,IAAD,CAAC,WAAW,AAAC,CACb,WAAW,CAAE,aAAU,CAAE,QAAQ,CAAE,UAAU,CAAE,gBAAgB,CAAE,SAAS,CAAC,UAAU,CACxF",
"names": []
}
{"version":3,"file":"fonts.css","sources":["fonts.scss","configuration/fonts/_support.scss"],"sourcesContent":["$fonts-header: 'Josefin Slab' !default;\n$fonts-default: 'Roboto' !default;\n$fonts-mono: 'Inconsolata' !default;\n\n$font-definitions: (\n Josefin+Slab: 400,\n Roboto: '300,400,500',\n Inconsolata: '400,700'\n);\n\n@import \"configuration/fonts/support\";\n\n\n\n\n","@function str-replace($string, $search, $replace: '') {\n $index: str-index($string, $search);\n\n @if $index {\n @return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace);\n }\n\n @return $string;\n}\n\n@function admin-font-faces($fonts) {\n $url: \"https://fonts.googleapis.com/css?family=\";\n $nb: 0;\n\n @each $fontname, $weights in $fonts {\n\n @if $fontname == $fonts-default or\n $fontname == $fonts-header or\n $fontname == $fonts-mono {\n\n $nb: $nb + 1;\n $nb-word: 0;\n\n $fontname: str-replace(\"#{$fontname}\", \" \", \"+\");\n\n $url: $url + $fontname;\n\n @if $weights != null {\n $url: $url + \":\" + $weights;\n }\n\n @if $nb < 3 {\n $url: $url + \"|\";\n }\n }\n }\n\n @return $url + \"&subset=latin-ext\";\n}\n\n@mixin body-fonts($font) {\n body, h5, h6,\n .badge, .note, .grav-mdeditor-preview,\n input, select, textarea, button, .selectize-input {\n font-family: \"#{$font}\", \"Helvetica\", \"Tahoma\", \"Geneva\", \"Arial\", sans-serif;\n }\n}\n\n@mixin header-fonts($font) {\n h1, h2, h3, h4,\n .form-tabs > label, .label {\n font-family: \"#{$font}\", \"Helvetica\", \"Tahoma\", \"Geneva\", \"Arial\", sans-serif;\n }\n}\n\n@mixin mono-fonts($font) {\n code, kbd, pre, samp,\n body .CodeMirror {\n font-family: \"#{$font}\", \"Monaco\", \"Consolas\", \"Lucida Console\", monospace !important;\n }\n}\n$font-url: admin-font-faces($font-definitions);\n\n@import url(\"#{$font-url}\");\n\n@include body-fonts($fonts-default);\n\n@include header-fonts($fonts-header);\n\n@include mono-fonts($fonts-mono);\n\n\n\n\n\n"],"names":[],"mappings":"AC+DA,OAAO,CAAC,uGAAI,CAtBR,AAAA,IAAI,CAAE,AAAA,EAAE,CAAE,AAAA,EAAE,CACZ,AAAA,MAAM,CAAE,AAAA,KAAK,CAAE,AAAA,sBAAsB,CACrC,AAAA,KAAK,CAAE,AAAA,MAAM,CAAE,AAAA,QAAQ,CAAE,AAAA,MAAM,CAAE,AAAA,gBAAgB,AAAC,CAC9C,WAAW,CAAE,QAAU,CAAE,WAAW,CAAE,QAAQ,CAAE,QAAQ,CAAE,OAAO,CAAE,UAAU,CAChF,AAID,AAAA,EAAE,CAAE,AAAA,EAAE,CAAE,AAAA,EAAE,CAAE,AAAA,EAAE,CACd,AAAa,UAAH,CAAG,KAAK,CAAE,AAAA,MAAM,AAAC,CACvB,WAAW,CAAE,cAAU,CAAE,WAAW,CAAE,QAAQ,CAAE,QAAQ,CAAE,OAAO,CAAE,UAAU,CAChF,AAID,AAAA,IAAI,CAAE,AAAA,GAAG,CAAE,AAAA,GAAG,CAAE,AAAA,IAAI,CACpB,AAAK,IAAD,CAAC,WAAW,AAAC,CACb,WAAW,CAAE,aAAU,CAAE,QAAQ,CAAE,UAAU,CAAE,gBAAgB,CAAE,SAAS,CAAC,UAAU,CACxF"}
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
File diff suppressed because one or more lines are too long
@@ -1,3 +1,3 @@
body,h5,h6,.badge,.note,.grav-mdeditor-preview,input,select,textarea,button,.selectize-input,h1,h2,h3,h4,#admin-menu li,.form-tabs>label,.label,body .CodeMirror pre{font-family:"Helvetica Neue", "Helvetica", "Tahoma", "Geneva", "Arial", sans-serif}code,kbd,pre,samp{font-family:"Monaco", "Consolas", "Lucida Console", monospace}
/*# sourceMappingURL=../css-compiled/simple-fonts.css.map */
/*# sourceMappingURL=simple-fonts.css.map */
@@ -1,10 +1 @@
{
"version": 3,
"file": "../scss/simple-fonts.css",
"sources": [
"../scss/simple-fonts.scss",
"../hdr0"
],
"mappings": "AAAA,AAAA,IAAI,CAAE,AAAA,EAAE,CAAE,AAAA,EAAE,CACZ,AAAA,MAAM,CAAE,AAAA,KAAK,CAAE,AAAA,sBAAsB,CACrC,AAAA,KAAK,CAAE,AAAA,MAAM,CAAE,AAAA,QAAQ,CAAE,AAAA,MAAM,CAAE,AAAA,gBAAgB,CACjD,AAAA,EAAE,CAAE,AAAA,EAAE,CAAE,AAAA,EAAE,CAAE,AAAA,EAAE,CACd,AAAY,WAAD,CAAC,EAAE,CAAE,AAAa,UAAH,CAAG,KAAK,CAAE,AAAA,MAAM,CAC1C,AAAiB,IAAb,CAAC,WAAW,CAAC,GAAG,AAAC,CACjB,WAAW,CAAE,sEAAuE,CACvF,AACD,AAAA,IAAI,CAAE,AAAA,GAAG,CAAE,AAAA,GAAG,CAAE,AAAA,IAAI,AAAE,CAClB,WAAW,CAAE,iDAAkD,CAClE",
"names": []
}
{"version":3,"file":"simple-fonts.css","sources":["simple-fonts.scss"],"sourcesContent":["body, h5, h6,\n.badge, .note, .grav-mdeditor-preview,\ninput, select, textarea, button, .selectize-input,\nh1, h2, h3, h4,\n#admin-menu li, .form-tabs > label, .label,\nbody .CodeMirror pre {\n font-family: \"Helvetica Neue\", \"Helvetica\", \"Tahoma\", \"Geneva\", \"Arial\", sans-serif;\n}\ncode, kbd, pre, samp {\n font-family: \"Monaco\", \"Consolas\", \"Lucida Console\", monospace;\n}\n\n"],"names":[],"mappings":"AAAA,AAAA,IAAI,CAAE,AAAA,EAAE,CAAE,AAAA,EAAE,CACZ,AAAA,MAAM,CAAE,AAAA,KAAK,CAAE,AAAA,sBAAsB,CACrC,AAAA,KAAK,CAAE,AAAA,MAAM,CAAE,AAAA,QAAQ,CAAE,AAAA,MAAM,CAAE,AAAA,gBAAgB,CACjD,AAAA,EAAE,CAAE,AAAA,EAAE,CAAE,AAAA,EAAE,CAAE,AAAA,EAAE,CACd,AAAY,WAAD,CAAC,EAAE,CAAE,AAAa,UAAH,CAAG,KAAK,CAAE,AAAA,MAAM,CAC1C,AAAiB,IAAb,CAAC,WAAW,CAAC,GAAG,AAAC,CACjB,WAAW,CAAE,sEAAsE,CACtF,AACD,AAAA,IAAI,CAAE,AAAA,GAAG,CAAE,AAAA,GAAG,CAAE,AAAA,IAAI,AAAE,CAClB,WAAW,CAAE,iDAAiD,CACjE"}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
View File
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
View File
@@ -4,38 +4,47 @@
data-grav-array-name="{{ (scope ~ field.name)|fieldName }}"
data-grav-array-keyname="{{ field.placeholder_key|e|tu }}"
data-grav-array-valuename="{{ field.placeholder_value|e|tu }}"
data-grav-array-textarea="{{ field.value_type == 'textarea' }}"
{{ parent() }}
{% endblock %}
{% macro renderer(key, text, field, scope) %}
{% if text is not iterable %}
<div class="form-row{% if field.value_only %} array-field-value_only{% endif %}"
data-grav-array-type="row">
<span data-grav-array-action="sort" class="fa fa-bars"></span>
{% if field.value_only != true %}
{% if key == '0' and text == '' %}
{% set key = '' %}
<div class="form-row{% if field.value_only %} array-field-value_only{% endif %}"
data-grav-array-type="row">
<span data-grav-array-action="sort" class="fa fa-bars"></span>
{% if field.value_only != true %}
{% if key == '0' and text == '' %}
{% set key = '' %}
{% endif %}
<input
data-grav-array-type="key"
type="text" value="{{ key }}"
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}
placeholder="{{ field.placeholder_key|e|tu }}" />
{% endif %}
<input
data-grav-array-type="key"
type="text" value="{{ key }}"
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}
placeholder="{{ field.placeholder_key|e|tu }}" />
{% endif %}
{% if field.value_type == 'textarea' %}
<textarea
data-grav-array-type="value"
name="{{ ((scope ~ field.name)|fieldName) ~ '[' ~ key ~ ']' }}"
placeholder="{{ field.placeholder_value|e|tu }}"
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}>{{ text }}</textarea>
{% else %}
<input
data-grav-array-type="value"
type="text"
name="{{ ((scope ~ field.name)|fieldName) ~ '[' ~ key ~ ']' }}"
placeholder="{{ field.placeholder_value|e|tu }}"
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}
value={% if text == 'true' %}true{% elseif text == 'false' %}false{% else %}"{{ text|join(', ')|e }}"{% endif %} />
{% endif %}
<input
data-grav-array-type="value"
type="text"
name="{{ ((scope ~ field.name)|fieldName) ~ '[' ~ key ~ ']' }}"
placeholder="{{ field.placeholder_value|e|tu }}"
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}
value={% if text == 'true' %}true{% elseif text == 'false' %}false{% else %}"{{ text|join(', ')|e }}"{% endif %} />
<span data-grav-array-action="rem" class="fa fa-minus"></span>
<span data-grav-array-action="add" class="fa fa-plus"></span>
</div>
<span data-grav-array-action="rem" class="fa fa-minus"></span>
<span data-grav-array-action="add" class="fa fa-plus"></span>
</div>
{% endif %}
{% endmacro %}
@@ -58,18 +67,26 @@
<div class="form-row" data-grav-array-type="row">
<span data-grav-array-action="sort" class="fa fa-bars"></span>
{% if field.value_only != true %}
<input
data-grav-array-type="key"
type="text"
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}
placeholder="{{ field.placeholder_key|e|tu }}" />
<input
data-grav-array-type="key"
type="text"
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}
placeholder="{{ field.placeholder_key|e|tu }}" />
{% endif %}
{% if field.value_type == 'textarea' %}
<textarea
data-grav-array-type="value"
name="{{ (scope ~ field.name)|fieldName }}"
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}
placeholder="{{ field.placeholder_value|e|tu }}"></textarea>
{% else %}
<input
data-grav-array-type="value"
type="text"
name="{{ (scope ~ field.name)|fieldName }}"
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}
placeholder="{{ field.placeholder_value|e|tu }}" />
{% endif %}
<input
data-grav-array-type="value"
type="text"
name="{{ (scope ~ field.name)|fieldName }}"
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}
placeholder="{{ field.placeholder_value|e|tu }}" />
<span data-grav-array-action="rem" class="fa fa-minus"></span>
<span data-grav-array-action="add" class="fa fa-plus"></span>
</div>
@@ -1,9 +1,13 @@
{% if field.fields %}
<div class="form-tab">
{% for field in field.fields %}
{% for childName, child in field.fields %}
{% if field.type %}
{% set value = field.name ? data.value(field.name) : data.toArray %}
{% include ["forms/fields/#{field.type}/#{field.type}.html.twig", 'forms/fields/text/text.html.twig'] %}
{%- if childName starts with '.' -%}
{% set child = child|merge({ name: field.name ~ childName }) %}
{% endif %}
{% set value = child.name ? data.value(child.name) : data.toArray %}
{% include ["forms/fields/#{child.type}/#{child.type}.html.twig", 'forms/fields/text/text.html.twig'] with { field: child, value: data.value(child.name) } %}
{% endif %}
{% endfor %}
</div>
View File
@@ -15,7 +15,7 @@
{% block integration %}{% endblock %}
{% set redirect = redirect ?: uri.path %}
{% set redirect = redirect ?: uri.path ~ uri.params ~ (uri.query ? '?' ~ uri.query : '') %}
<form method="post" action="{{ base_url_relative }}">
<div class="padding">
@@ -48,7 +48,7 @@
{% set gumroad_loaded = true %}
<script src="//gumroad.com/js/gumroad.js"></script>
{% endif %}
<a class="gumroad-button button" href="https://gum.co/{{ plugin.premium.product_permalink }}" target="_blank" data-gumroad-single-product="true"><i class="fa fa-shopping-cart"></i> {{ "Buy Now"|tu }}</a>
<a class="gumroad-button button" href="https://gum.co/{{ plugin.premium.permalink }}" target="_blank" data-gumroad-single-product="true"><i class="fa fa-shopping-cart"></i> {{ "Buy Now"|tu }}</a>
{% else %}
<a class="button" href="#" data-remodal-target="add-package" data-packages-slugs="{{ plugin.slug }}" data-plugin-action="start-package-installation"><i class="fa fa-plus"></i> {{ "PLUGIN_ADMIN.INSTALL_PLUGIN"|tu }}</a>
{% endif %}
@@ -52,7 +52,7 @@
{% set gumroad_loaded = true %}
<script src="//gumroad.com/js/gumroad.js"></script>
{% endif %}
<a class="gumroad-button button" href="https://gum.co/{{ plugin.premium.product_permalink }}" target="_blank" data-gumroad-single-product="true"><i class="fa fa-shopping-cart"></i> {{ "Buy Now"|tu }}</a>
<a class="gumroad-button button" href="https://gum.co/{{ plugin.premium.permalink }}" target="_blank" data-gumroad-single-product="true"><i class="fa fa-shopping-cart"></i> {{ "Buy Now"|tu }}</a>
{% else %}
<a class="button" href="#" data-remodal-target="add-package" data-packages-slugs="{{ plugin.slug }}" data-plugin-action="start-package-installation"><i class="fa fa-plus"></i> {{ "PLUGIN_ADMIN.INSTALL"|tu }}</a>
{% endif %}
View File
File diff suppressed because it is too large Load Diff
Vendored Executable → Regular
+1 -135
View File
@@ -1,135 +1 @@
#!/usr/bin/env php
<?php
require_once 'vendor/autoload.php';
use PicoFeed\Config\Config;
use PicoFeed\Reader\Favicon;
use PicoFeed\Scraper\Scraper;
use PicoFeed\Reader\Reader;
use PicoFeed\Logging\Logger;
use PicoFeed\PicoFeedException;
Logger::enable();
function get_feed($url, $disable_filtering = false)
{
try {
$reader = new Reader;
$resource = $reader->discover($url);
$parser = $reader->getParser(
$resource->getUrl(),
$resource->getContent(),
$resource->getEncoding()
);
if ($disable_filtering) {
$parser->disableContentFiltering();
}
return $parser->execute();
}
catch (PicoFeedException $e) {
echo 'Exception thrown ===> "'.$e->getMessage().'"'.PHP_EOL;
return false;
}
}
function get_item($feed, $item_id)
{
foreach ($feed->items as $item) {
if ($item->getId() === $item_id) {
echo $item;
echo "============= CONTENT ================\n";
echo $item->getContent();
echo "\n============= CONTENT ================\n";
break;
}
}
}
function dump_feed($url)
{
$feed = get_feed($url);
echo $feed;
}
function debug_feed($url)
{
get_feed($url);
print_r(Logger::getMessages());
}
function dump_item($url, $item_id)
{
$feed = get_feed($url);
if ($feed !== false) {
get_item($feed, $item_id);
}
}
function nofilter_item($url, $item_id)
{
$feed = get_feed($url, true);
if ($feed !== false) {
get_item($feed, $item_id);
}
}
function grabber($url)
{
$grabber = new Scraper(new Config);
$grabber->setUrl($url);
$grabber->execute();
print_r(Logger::getMessages());
echo "============= CONTENT ================\n";
echo $grabber->getRelevantContent().PHP_EOL;
echo "============= FILTERED ================\n";
echo $grabber->getFilteredContent().PHP_EOL;
}
function fetch_favicon($url)
{
$favicon = new Favicon();
echo $favicon->find($url) . PHP_EOL;
}
// Parse command line arguments
if ($argc === 4) {
switch ($argv[1]) {
case 'item':
dump_item($argv[2], $argv[3]);
die;
case 'nofilter':
nofilter_item($argv[2], $argv[3]);
die;
}
} else if ($argc === 3) {
switch ($argv[1]) {
case 'feed':
dump_feed($argv[2]);
die;
case 'debug':
debug_feed($argv[2]);
die;
case 'grabber':
grabber($argv[2]);
die;
case 'favicon':
fetch_favicon($argv[2]);
die;
}
}
printf("Usage:\n");
printf("%s feed <feed-url>\n", $argv[0]);
printf("%s debug <feed-url>\n", $argv[0]);
printf("%s item <feed-url> <item-id>\n", $argv[0]);
printf("%s nofilter <feed-url> <item-id>\n", $argv[0]);
printf("%s grabber <url>\n", $argv[0]);
printf("%s favicon <url>\n", $argv[0]);
../fguillot/picofeed/picofeed
View File
@@ -1,54 +0,0 @@
{
"name": "zendframework/zendxml",
"description": "Utility library for XML usage, best practices, and security in PHP",
"license": "BSD-3-Clause",
"keywords": [
"zf",
"zendframework",
"xml",
"security"
],
"support": {
"issues": "https://github.com/zendframework/ZendXml/issues",
"source": "https://github.com/zendframework/ZendXml",
"rss": "https://github.com/zendframework/ZendXml/releases.atom",
"chat": "https://zendframework-slack.herokuapp.com",
"forum": "https://discourse.zendframework.com/c/questions/components"
},
"require": {
"php": "^5.6 || ^7.0"
},
"require-dev": {
"zendframework/zend-coding-standard": "~1.0.0",
"phpunit/phpunit": "^5.7.27 || ^6.5.8 || ^7.1.4"
},
"autoload": {
"psr-4": {
"ZendXml\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"ZendXmlTest\\": "test/"
}
},
"config": {
"sort-packages": true
},
"extra": {
"branch-alias": {
"dev-master": "1.1.x-dev",
"dev-develop": "1.2.x-dev"
}
},
"scripts": {
"check": [
"@cs-check",
"@test"
],
"cs-check": "phpcs",
"cs-fix": "phpcbf",
"test": "phpunit --colors=always",
"test-coverage": "phpunit --colors=always --coverage-clover clover.xml"
}
}
+5
View File
@@ -0,0 +1,5 @@
# OS Generated
.DS_Store*
/.idea
node_modules
*.js.map
+15
View File
@@ -1,3 +1,18 @@
# v2.16.1
## 08/20/2018
1. [](#new)
* Fixed a regression issue with `file` & `array` field
# v2.16.0
## 08/20/2018
1. [](#new)
* Added new `form.keep_alive` option to keep session alive [#275](https://github.com/getgrav/grav-plugin-form/issues/275)
* Added `array` field for frontend use
1. [](#improved)
* Improving compatibility `autocomplete` spec [#274](https://github.com/getgrav/grav-plugin-form/pull/274)
# v2.15.1
## 06/20/2018
+194
View File
@@ -0,0 +1,194 @@
import $ from 'jquery';
import Sortable from 'sortablejs';
let body = $('body');
class Template {
constructor(container) {
this.container = $(container);
if (this.getName() === undefined) {
this.container = this.container.closest('[data-grav-array-name]');
}
}
getName() {
return this.container.data('grav-array-name') || '';
}
getKeyPlaceholder() {
return this.container.data('grav-array-keyname') || 'Key';
}
getValuePlaceholder() {
return this.container.data('grav-array-valuename') || 'Value';
}
isValueOnly() {
return this.container.find('[data-grav-array-mode="value_only"]:first').length || false;
}
isTextArea() {
return this.container.data('grav-array-textarea') || false;
}
shouldBeDisabled() {
// check for toggleables, if field is toggleable and it's not enabled, render disabled
let toggle = this.container.closest('.form-field').find('[data-grav-field="toggleable"] input[type="checkbox"]');
return toggle.length && toggle.is(':not(:checked)');
}
getNewRow() {
let tpl = '';
const value = this.isTextArea()
? `<textarea ${this.shouldBeDisabled() ? 'disabled="disabled"' : ''} data-grav-array-type="value" name="" placeholder="${this.getValuePlaceholder()}"></textarea>`
: `<input ${this.shouldBeDisabled() ? 'disabled="disabled"' : ''} data-grav-array-type="value" type="text" name="" value="" placeholder="${this.getValuePlaceholder()}" />`;
if (this.isValueOnly()) {
tpl += `
<div class="form-row array-field-value_only" data-grav-array-type="row">
<span data-grav-array-action="sort" class="fa fa-bars"></span>
${value}
`;
} else {
tpl += `
<div class="form-row" data-grav-array-type="row">
<span data-grav-array-action="sort" class="fa fa-bars"></span>
<input ${this.shouldBeDisabled() ? 'disabled="disabled"' : ''} data-grav-array-type="key" type="text" value="" placeholder="${this.getKeyPlaceholder()}" />
${value}
`;
}
tpl += `
<span data-grav-array-action="rem" class="fa fa-minus"></span>
<span data-grav-array-action="add" class="fa fa-plus"></span>
</div>`;
return tpl;
}
}
export default class ArrayField {
constructor() {
body.on('input', '[data-grav-array-type="key"], [data-grav-array-type="value"]', (event) => this.actionInput(event));
body.on('click touch', '[data-grav-array-action]:not([data-grav-array-action="sort"])', (event) => this.actionEvent(event));
this.arrays = $();
$('[data-grav-field="array"]').each((index, list) => this.addArray(list));
$('body').on('mutation._grav', this._onAddedNodes.bind(this));
}
addArray(list) {
list = $(list);
list.find('[data-grav-array-type="container"]').each((index, container) => {
container = $(container);
if (container.data('array-sort') || container[0].hasAttribute('data-array-nosort')) { return; }
container.data('array-sort', new Sortable(container.get(0), {
handle: '.fa-bars',
animation: 150
}));
});
}
actionInput(event) {
let element = $(event.target);
let type = element.data('grav-array-type');
this._setTemplate(element);
let template = element.data('array-template');
let keyElement = type === 'key' ? element : element.siblings('[data-grav-array-type="key"]:first');
let valueElement = type === 'value' ? element : element.siblings('[data-grav-array-type="value"]:first');
let escaped_name = !template.isValueOnly() ? keyElement.val() : this.getIndexFor(element);
escaped_name = escaped_name.toString().replace(/\[/g, '%5B').replace(/]/g, '%5D');
let name = `${template.getName()}[${escaped_name}]`;
valueElement.attr('name', !valueElement.val() ? template.getName() : name);
this.refreshNames(template);
}
actionEvent(event) {
event && event.preventDefault();
let element = $(event.target);
let action = element.data('grav-array-action');
let container = element.parents('[data-grav-array-type="container"]');
this._setTemplate(element);
this[`${action}Action`](element);
let siblings = container.find('> div');
container[siblings.length > 1 ? 'removeClass' : 'addClass']('one-child');
}
addAction(element) {
let template = element.data('array-template');
let row = element.closest('[data-grav-array-type="row"]');
row.after(template.getNewRow());
}
remAction(element) {
let template = element.data('array-template');
let row = element.closest('[data-grav-array-type="row"]');
let isLast = !row.siblings().length;
if (isLast) {
let newRow = $(template.getNewRow());
row.after(newRow);
newRow.find('[data-grav-array-type="value"]:last').attr('name', template.getName());
}
row.remove();
this.refreshNames(template);
}
refreshNames(template) {
if (!template.isValueOnly()) { return; }
let row = template.container.find('> div > [data-grav-array-type="row"]');
let inputs = row.find('[name]:not([name=""])');
inputs.each((index, input) => {
input = $(input);
let name = input.attr('name');
name = name.replace(/\[\d+\]$/, `[${index}]`);
input.attr('name', name);
});
if (!inputs.length) {
row.find('[data-grav-array-type="value"]').attr('name', template.getName());
}
}
getIndexFor(element) {
let template = element.data('array-template');
let row = element.closest('[data-grav-array-type="row"]');
return template.container.find(`${template.isValueOnly() ? '> div ' : ''} > [data-grav-array-type="row"]`).index(row);
}
_setTemplate(element) {
if (!element.data('array-template')) {
element.data('array-template', new Template(element.closest('[data-grav-array-name]')));
}
}
_onAddedNodes(event, target/* , record, instance */) {
let arrays = $(target).find('[data-grav-field="array"]');
if (!arrays.length) { return; }
arrays.each((index, list) => {
list = $(list);
if (!~this.arrays.index(list)) {
this.addArray(list);
}
});
}
}
export let Instance = new ArrayField();
+297
View File
@@ -0,0 +1,297 @@
import $ from 'jquery';
import Dropzone from 'dropzone';
import EXIF from 'exif-js';
import { config, translations } from 'grav-form';
// translations
const Dictionary = {
dictCancelUpload: translations.PLUGIN_FORM.DROPZONE_CANCEL_UPLOAD,
dictCancelUploadConfirmation: translations.PLUGIN_FORM.DROPZONE_CANCEL_UPLOAD_CONFIRMATION,
dictDefaultMessage: translations.PLUGIN_FORM.DROPZONE_DEFAULT_MESSAGE,
dictFallbackMessage: translations.PLUGIN_FORM.DROPZONE_FALLBACK_MESSAGE,
dictFallbackText: translations.PLUGIN_FORM.DROPZONE_FALLBACK_TEXT,
dictFileTooBig: translations.PLUGIN_FORM.DROPZONE_FILE_TOO_BIG,
dictInvalidFileType: translations.PLUGIN_FORM.DROPZONE_INVALID_FILE_TYPE,
dictMaxFilesExceeded: translations.PLUGIN_FORM.DROPZONE_MAX_FILES_EXCEEDED,
dictRemoveFile: translations.PLUGIN_FORM.DROPZONE_REMOVE_FILE,
dictRemoveFileConfirmation: translations.PLUGIN_FORM.DROPZONE_REMOVE_FILE_CONFIRMATION,
dictResponseError: translations.PLUGIN_FORM.DROPZONE_RESPONSE_ERROR
};
Dropzone.autoDiscover = false;
const DropzoneMediaConfig = {
createImageThumbnails: { thumbnailWidth: 150 },
addRemoveLinks: false,
dictDefaultMessage: Dictionary.dictDefaultMessage,
dictRemoveFileConfirmation: Dictionary.dictRemoveFileConfirmation,
previewTemplate: ''
};
window.EXIF = EXIF;
export default class FilesField {
constructor({ container = '.dropzone.files-upload', options = {} } = {}) {
this.container = $(container);
if (!this.container.length) { return; }
this.urls = {};
DropzoneMediaConfig.previewTemplate = $('#dropzone-template').html();
this.options = Object.assign({}, Dictionary, DropzoneMediaConfig, {
klass: this,
url: this.container.data('file-url-add') || config.current_url,
acceptedFiles: this.container.data('media-types'),
init: this.initDropzone
}, this.container.data('dropzone-options'), options);
this.dropzone = new Dropzone(container, this.options);
this.dropzone.on('complete', this.onDropzoneComplete.bind(this));
this.dropzone.on('success', this.onDropzoneSuccess.bind(this));
this.dropzone.on('removedfile', this.onDropzoneRemovedFile.bind(this));
this.dropzone.on('sending', this.onDropzoneSending.bind(this));
this.dropzone.on('error', this.onDropzoneError.bind(this));
}
initDropzone() {
let files = this.options.klass.container.find('[data-file]');
let dropzone = this;
if (!files.length) { return; }
files.each((index, file) => {
file = $(file);
let data = file.data('file');
let mock = {
name: data.name,
size: data.size,
type: data.type,
status: Dropzone.ADDED,
accepted: true,
url: this.options.url,
removeUrl: data.remove
};
dropzone.files.push(mock);
dropzone.options.addedfile.call(dropzone, mock);
if (mock.type.match(/^image\//)) dropzone.options.thumbnail.call(dropzone, mock, data.path);
file.remove();
});
}
getURI() {
return this.container.data('mediaUri') || '';
}
onDropzoneSending(file, xhr, formData) {
formData.append('__form-name__', this.container.closest('form').find('[name="__form-name__"]').val());
formData.append('__form-file-uploader__', 1);
formData.append('name', this.options.dotNotation);
formData.append('form-nonce', config.form_nonce);
formData.append('task', 'filesupload');
formData.append('uri', this.getURI());
}
onDropzoneSuccess(file, response, xhr) {
if (this.options.reloadPage) {
global.location.reload();
}
// store params for removing file from session before it gets saved
if (response.session) {
file.sessionParams = response.session;
file.removeUrl = this.options.url;
// Touch field value to force a mutation detection
const input = this.container.find('[name][type="hidden"]');
const value = input.val();
input.val(value + ' ');
}
return this.handleError({
file,
data: response,
mode: 'removeFile',
msg: `<p>${translations.PLUGIN_FORM.FILE_ERROR_UPLOAD} <strong>${file.name}</strong></p>
<pre>${response.message}</pre>`
});
}
onDropzoneComplete(file) {
if (!file.accepted && !file.rejected) {
let data = {
status: 'error',
message: `${translations.PLUGIN_FORM.FILE_UNSUPPORTED}: ${file.name.match(/\..+/).join('')}`
};
return this.handleError({
file,
data,
mode: 'removeFile',
msg: `<p>${translations.PLUGIN_FORM.FILE_ERROR_ADD} <strong>${file.name}</strong></p>
<pre>${data.message}</pre>`
});
}
if (this.options.reloadPage) {
global.location.reload();
}
}
onDropzoneRemovedFile(file, ...extra) {
if (!file.accepted || file.rejected) { return; }
let url = file.removeUrl || this.urls.delete || `${location.href}.json`;
let path = (url || '').match(/path:(.*)\//);
let data = new FormData();
data.append('filename', file.name);
data.append('__form-name__', this.container.closest('form').find('[name="__form-name__"]').val());
data.append('name', this.options.dotNotation);
data.append('form-nonce', config.form_nonce);
data.append('uri', this.getURI());
if (file.sessionParams) {
data.append('__form-file-remover__', '1');
data.append('session', file.sessionParams);
}
$.ajax({
url,
data,
method: 'POST',
contentType: false,
processData: false,
success: () => {
if (!path) { return; }
path = global.atob(path[1]);
let input = this.container.find('[name][type="hidden"]');
let data = JSON.parse(input.val() || '{}');
delete data[path];
input.val(JSON.stringify(data));
}
});
}
onDropzoneError(file, response, xhr) {
let message = xhr && response.error ? response.error.message : response;
$(file.previewElement).find('[data-dz-errormessage]').html(message);
return this.handleError({
file,
data: { status: 'error' },
msg: `<pre>${message}</pre>`
});
}
handleError(options) {
return true;
/* let { file, data, mode, msg } = options;
if (data.status !== 'error' && data.status !== 'unauthorized') { return; }
switch (mode) {
case 'addBack':
if (file instanceof File) {
this.dropzone.addFile.call(this.dropzone, file);
} else {
this.dropzone.files.push(file);
this.dropzone.options.addedfile.call(this.dropzone, file);
this.dropzone.options.thumbnail.call(this.dropzone, file, file.extras.url);
}
break;
case 'removeFile':
default:
if (~this.dropzone.files.indexOf(file)) {
file.rejected = true;
this.dropzone.removeFile.call(this.dropzone, file, { silent: true });
}
break;
}
let modal = $('[data-remodal-id="generic"]');
modal.find('.error-content').html(msg);
$.remodal.lookup[modal.data('remodal')].open(); */
}
}
export function UriToMarkdown(uri) {
uri = uri.replace(/@3x|@2x|@1x/, '');
uri = uri.replace(/\(/g, '%28');
uri = uri.replace(/\)/g, '%29');
return uri.match(/\.(jpe?g|png|gif|svg)$/i) ? `![](${uri})` : `[${decodeURI(uri)}](${uri})`;
}
let instances = [];
let cache = $();
const onAddedNodes = (event, target/* , record, instance */) => {
let files = $(target).find('.dropzone.files-upload');
if (!files.length) { return; }
files.each((index, file) => {
file = $(file);
if (!~cache.index(file)) {
addNode(file);
}
});
};
const addNode = (container) => {
container = $(container);
let input = container.find('input[type="file"]');
let settings = container.data('grav-file-settings') || {};
if (settings.accept && ~settings.accept.indexOf('*')) {
settings.accept = [''];
}
let options = {
url: container.data('file-url-add') || (container.closest('form').attr('action') || config.current_url) + '.json',
paramName: settings.paramName || 'file',
dotNotation: settings.name || 'file',
acceptedFiles: settings.accept ? settings.accept.join(',') : input.attr('accept') || container.data('media-types'),
maxFilesize: settings.filesize || 256,
maxFiles: settings.limit || null,
resizeWidth: settings.resizeWidth || null,
resizeHeight: settings.resizeHeight || null,
resizeQuality: settings.resizeQuality || null,
accept: function(file, done) {
const resolution = settings.resolution;
if (!resolution) return done();
setTimeout(() => {
let error = '';
if (resolution.min) {
Object.keys(resolution.min).forEach((attr) => {
if (file[attr] < resolution.min[attr]) {
error += translations.PLUGIN_FORM.RESOLUTION_MIN.replace(/{{attr}}/g, attr).replace(/{{min}}/g, resolution.min[attr]);
}
});
}
if (!(settings.resizeWidth || settings.resizeHeight)) {
if (resolution.max) {
Object.keys(resolution.max).forEach((attr) => {
if (file[attr] > resolution.max[attr]) {
error += translations.PLUGIN_FORM.RESOLUTION_MAX.replace(/{{attr}}/g, attr).replace(/{{max}}/g, resolution.max[attr]);
}
});
}
}
return done(error);
}, 50);
}
};
cache = cache.add(container);
container = container[0];
instances.push(new FilesField({ container, options }));
};
export let Instances = (() => {
$('.dropzone.files-upload').each((i, container) => addNode(container));
$('body').on('mutation._grav', onAddedNodes);
return instances;
})();
+4
View File
@@ -0,0 +1,4 @@
import FileInstances from './file';
import ArrayInstances from './array';
export default { FileInstances, ArrayInstances };
+3 -297
View File
@@ -1,298 +1,4 @@
import $ from 'jquery';
import Dropzone from 'dropzone';
import EXIF from 'exif-js';
import { config, translations } from 'grav-form';
// translations
const Dictionary = {
dictCancelUpload: translations.PLUGIN_FORM.DROPZONE_CANCEL_UPLOAD,
dictCancelUploadConfirmation: translations.PLUGIN_FORM.DROPZONE_CANCEL_UPLOAD_CONFIRMATION,
dictDefaultMessage: translations.PLUGIN_FORM.DROPZONE_DEFAULT_MESSAGE,
dictFallbackMessage: translations.PLUGIN_FORM.DROPZONE_FALLBACK_MESSAGE,
dictFallbackText: translations.PLUGIN_FORM.DROPZONE_FALLBACK_TEXT,
dictFileTooBig: translations.PLUGIN_FORM.DROPZONE_FILE_TOO_BIG,
dictInvalidFileType: translations.PLUGIN_FORM.DROPZONE_INVALID_FILE_TYPE,
dictMaxFilesExceeded: translations.PLUGIN_FORM.DROPZONE_MAX_FILES_EXCEEDED,
dictRemoveFile: translations.PLUGIN_FORM.DROPZONE_REMOVE_FILE,
dictRemoveFileConfirmation: translations.PLUGIN_FORM.DROPZONE_REMOVE_FILE_CONFIRMATION,
dictResponseError: translations.PLUGIN_FORM.DROPZONE_RESPONSE_ERROR
};
Dropzone.autoDiscover = false;
const DropzoneMediaConfig = {
createImageThumbnails: { thumbnailWidth: 150 },
addRemoveLinks: false,
dictDefaultMessage: Dictionary.dictDefaultMessage,
dictRemoveFileConfirmation: Dictionary.dictRemoveFileConfirmation,
previewTemplate: ''
};
window.EXIF = EXIF;
export default class FilesField {
constructor({ container = '.dropzone.files-upload', options = {} } = {}) {
this.container = $(container);
if (!this.container.length) { return; }
this.urls = {};
DropzoneMediaConfig.previewTemplate = $('#dropzone-template').html();
this.options = Object.assign({}, Dictionary, DropzoneMediaConfig, {
klass: this,
url: this.container.data('file-url-add') || config.current_url,
acceptedFiles: this.container.data('media-types'),
init: this.initDropzone
}, this.container.data('dropzone-options'), options);
this.dropzone = new Dropzone(container, this.options);
this.dropzone.on('complete', this.onDropzoneComplete.bind(this));
this.dropzone.on('success', this.onDropzoneSuccess.bind(this));
this.dropzone.on('removedfile', this.onDropzoneRemovedFile.bind(this));
this.dropzone.on('sending', this.onDropzoneSending.bind(this));
this.dropzone.on('error', this.onDropzoneError.bind(this));
}
initDropzone() {
let files = this.options.klass.container.find('[data-file]');
let dropzone = this;
if (!files.length) { return; }
files.each((index, file) => {
file = $(file);
let data = file.data('file');
let mock = {
name: data.name,
size: data.size,
type: data.type,
status: Dropzone.ADDED,
accepted: true,
url: this.options.url,
removeUrl: data.remove
};
dropzone.files.push(mock);
dropzone.options.addedfile.call(dropzone, mock);
if (mock.type.match(/^image\//)) dropzone.options.thumbnail.call(dropzone, mock, data.path);
file.remove();
});
}
getURI() {
return this.container.data('mediaUri') || '';
}
onDropzoneSending(file, xhr, formData) {
formData.append('__form-name__', this.container.closest('form').find('[name="__form-name__"]').val());
formData.append('__form-file-uploader__', 1);
formData.append('name', this.options.dotNotation);
formData.append('form-nonce', config.form_nonce);
formData.append('task', 'filesupload');
formData.append('uri', this.getURI());
}
onDropzoneSuccess(file, response, xhr) {
if (this.options.reloadPage) {
global.location.reload();
}
// store params for removing file from session before it gets saved
if (response.session) {
file.sessionParams = response.session;
file.removeUrl = this.options.url;
// Touch field value to force a mutation detection
const input = this.container.find('[name][type="hidden"]');
const value = input.val();
input.val(value + ' ');
}
return this.handleError({
file,
data: response,
mode: 'removeFile',
msg: `<p>${translations.PLUGIN_FORM.FILE_ERROR_UPLOAD} <strong>${file.name}</strong></p>
<pre>${response.message}</pre>`
});
}
onDropzoneComplete(file) {
if (!file.accepted && !file.rejected) {
let data = {
status: 'error',
message: `${translations.PLUGIN_FORM.FILE_UNSUPPORTED}: ${file.name.match(/\..+/).join('')}`
};
return this.handleError({
file,
data,
mode: 'removeFile',
msg: `<p>${translations.PLUGIN_FORM.FILE_ERROR_ADD} <strong>${file.name}</strong></p>
<pre>${data.message}</pre>`
});
}
if (this.options.reloadPage) {
global.location.reload();
}
}
onDropzoneRemovedFile(file, ...extra) {
if (!file.accepted || file.rejected) { return; }
let url = file.removeUrl || this.urls.delete || `${location.href}.json`;
let path = (url || '').match(/path:(.*)\//);
let data = new FormData();
data.append('filename', file.name);
data.append('__form-name__', this.container.closest('form').find('[name="__form-name__"]').val());
data.append('name', this.options.dotNotation);
data.append('form-nonce', config.form_nonce);
data.append('uri', this.getURI());
if (file.sessionParams) {
data.append('__form-file-remover__', '1');
data.append('session', file.sessionParams);
}
$.ajax({
url,
data,
method: 'POST',
contentType: false,
processData: false,
success: () => {
if (!path) { return; }
path = global.atob(path[1]);
let input = this.container.find('[name][type="hidden"]');
let data = JSON.parse(input.val() || '{}');
delete data[path];
input.val(JSON.stringify(data));
}
});
}
onDropzoneError(file, response, xhr) {
let message = xhr && response.error ? response.error.message : response;
$(file.previewElement).find('[data-dz-errormessage]').html(message);
return this.handleError({
file,
data: { status: 'error' },
msg: `<pre>${message}</pre>`
});
}
handleError(options) {
return true;
/* let { file, data, mode, msg } = options;
if (data.status !== 'error' && data.status !== 'unauthorized') { return; }
switch (mode) {
case 'addBack':
if (file instanceof File) {
this.dropzone.addFile.call(this.dropzone, file);
} else {
this.dropzone.files.push(file);
this.dropzone.options.addedfile.call(this.dropzone, file);
this.dropzone.options.thumbnail.call(this.dropzone, file, file.extras.url);
}
break;
case 'removeFile':
default:
if (~this.dropzone.files.indexOf(file)) {
file.rejected = true;
this.dropzone.removeFile.call(this.dropzone, file, { silent: true });
}
break;
}
let modal = $('[data-remodal-id="generic"]');
modal.find('.error-content').html(msg);
$.remodal.lookup[modal.data('remodal')].open(); */
}
}
export function UriToMarkdown(uri) {
uri = uri.replace(/@3x|@2x|@1x/, '');
uri = uri.replace(/\(/g, '%28');
uri = uri.replace(/\)/g, '%29');
return uri.match(/\.(jpe?g|png|gif|svg)$/i) ? `![](${uri})` : `[${decodeURI(uri)}](${uri})`;
}
let instances = [];
let cache = $();
const onAddedNodes = (event, target/* , record, instance */) => {
let files = $(target).find('.dropzone.files-upload');
if (!files.length) { return; }
files.each((index, file) => {
file = $(file);
if (!~cache.index(file)) {
addNode(file);
}
});
};
const addNode = (container) => {
container = $(container);
let input = container.find('input[type="file"]');
let settings = container.data('grav-file-settings') || {};
if (settings.accept && ~settings.accept.indexOf('*')) {
settings.accept = [''];
}
let options = {
url: container.data('file-url-add') || (container.closest('form').attr('action') || config.current_url) + '.json',
paramName: settings.paramName || 'file',
dotNotation: settings.name || 'file',
acceptedFiles: settings.accept ? settings.accept.join(',') : input.attr('accept') || container.data('media-types'),
maxFilesize: settings.filesize || 256,
maxFiles: settings.limit || null,
resizeWidth: settings.resizeWidth || null,
resizeHeight: settings.resizeHeight || null,
resizeQuality: settings.resizeQuality || null,
accept: function(file, done) {
const resolution = settings.resolution;
if (!resolution) return done();
setTimeout(() => {
let error = '';
if (resolution.min) {
Object.keys(resolution.min).forEach((attr) => {
if (file[attr] < resolution.min[attr]) {
error += translations.PLUGIN_FORM.RESOLUTION_MIN.replace(/{{attr}}/g, attr).replace(/{{min}}/g, resolution.min[attr]);
}
});
}
if (!(settings.resizeWidth || settings.resizeHeight)) {
if (resolution.max) {
Object.keys(resolution.max).forEach((attr) => {
if (file[attr] > resolution.max[attr]) {
error += translations.PLUGIN_FORM.RESOLUTION_MAX.replace(/{{attr}}/g, attr).replace(/{{max}}/g, resolution.max[attr]);
}
});
}
}
return done(error);
}, 50);
}
};
cache = cache.add(container);
container = container[0];
instances.push(new FilesField({ container, options }));
};
export let Instances = (() => {
$('.dropzone.files-upload').each((i, container) => addNode(container));
$('body').on('mutation._grav', onAddedNodes);
return instances;
})();
import Instances from './fields';
import './utils/keep-alive';
export { Instances };
+14
View File
@@ -0,0 +1,14 @@
import $ from 'jquery';
import { config } from 'grav-form';
const keepAlive = $('[data-grav-keepalive]');
if (keepAlive.length) {
const timeout = config.session_timeout / 1.5 * 1000;
setInterval(() => {
$.ajax({
url: `${config.base_url_relative}/task${config.param_sep}keep-alive`
});
}, timeout);
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
View File
+1 -1
View File
@@ -1,5 +1,5 @@
name: Form
version: 2.15.1
version: 2.16.1
description: Enables the forms handling
icon: check-square
author:
+8 -1
View File
@@ -402,7 +402,10 @@ class Form extends Iterator implements \Serializable
(array) $settings,
['name' => $post['name']]
);
// Allow plugins to adapt settings for a given post name
// Useful if schema retrieval is not an option, e.g. dynamically created forms
$grav->fireEvent('onFormUploadSettings', new Event(['settings' => &$settings, 'post' => $post]));
$upload = $this->normalizeFiles($_FILES['data'], $settings->name);
// Handle errors and breaks without proceeding further
@@ -699,6 +702,10 @@ class Form extends Iterator implements \Serializable
$queue = $session->getFlashObject('files-upload');
$queue = $queue[base64_encode($url)];
if (is_array($queue)) {
// Allow plugins to implement additional / alternative logic
// Add post to event data
$grav->fireEvent('onFormStoreUploads', new Event(['queue' => &$queue, 'form' => $this, 'post' => $post]));
foreach ($queue as $key => $files) {
foreach ($files as $destination => $file) {
if (!rename($file['tmp_name'], $destination)) {
+6
View File
@@ -94,6 +94,12 @@ class FormPlugin extends Plugin
'onTwigSiteVariables' => ['onTwigVariables', 0],
'onFormValidationProcessed' => ['onFormValidationProcessed', 0],
]);
// Mini Keep-Alive Logic
$task = $this->grav['uri']->param('task');
if ($task && $task === 'keep-alive') {
exit;
}
}
public function onGetPageTemplates(Event $event)
+15
View File
@@ -0,0 +1,15 @@
{
"project":"grav-plugin-form",
"platforms":{
"grav":{
"nodes":{
"plugin":[
{
"source":"/",
"destination":"/user/plugins/form"
}
]
}
}
}
}
+28 -21
View File
@@ -5,32 +5,39 @@
"repository": "https://github.com/getgrav/grav-plugin-form",
"main": "app/main.js",
"scripts": {
"watch": "webpack --watch --progress --colors --config webpack.conf.js",
"dev": "webpack --progress --colors --config webpack.conf.js",
"prod": "NODE_ENV=production webpack -p --config webpack.conf.js",
"test": "echo \"Error: no test specified\" && exit 1"
"watch": "NODE_ENV=development webpack --watch --progress --colors --mode development --config webpack.conf.js",
"dev": "NODE_ENV=development webpack --progress --colors --config webpack.conf.js",
"prod": "NODE_ENV=production webpack --mode production --config webpack.conf.js"
},
"author": "RocketTheme, LLC",
"author": "Team Grav",
"license": "MIT",
"dependencies": {
"dropzone": "^5.3.0",
"exif-js": "^2.3.0"
"exif-js": "^2.3.0",
"sortablejs": "^1.7.0"
},
"devDependencies": {
"babel-core": "^6.14.0",
"babel-loader": "^6.2.5",
"babel-polyfill": "^6.13.0",
"babel-preset-es2015": "^6.14.0",
"eslint": "^3.4.0",
"eslint-loader": "^1.5.0",
"exports-loader": "^0.6.3",
"gulp": "^3.9.1",
"gulp-sourcemaps": "^1.6.0",
"gulp-util": "^3.0.7",
"gulp-webpack": "^1.5.0",
"immutable": "^3.8.1",
"imports-loader": "^0.6.5",
"json-loader": "^0.5.4",
"webpack": "^1.13.2"
"babel-core": "^6.26.3",
"babel-eslint": "^8.2.6",
"babel-loader": "^7.1.5",
"babel-polyfill": "^6.26.0",
"babel-preset-es2015": "^6.24.1",
"babel-preset-stage-3": "^6.24.1",
"css-loader": "^1.0.0",
"eslint": "^5.2.0",
"eslint-loader": "^2.1.0",
"exports-loader": "^0.7.0",
"gulp": "latest",
"gulp-autoprefixer": "latest",
"gulp-clean-css": "^3.9.4",
"gulp-csscomb": "^3.0.8",
"gulp-rename": "^1.3.0",
"gulp-sass": "^4.0.1",
"gulp-sourcemaps": "^2.6.4",
"imports-loader": "^0.8.0",
"json-loader": "^0.5.7",
"style-loader": "^0.21.0",
"webpack": "^4.16.2",
"webpack-cli": "^3.1.0"
}
}
@@ -63,9 +63,9 @@
{% if autofocus %}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', 'new-password'] %}autocomplete="{{ field.autocomplete }}"{% endif %}
{% if field.autocomplete is defined %}autocomplete="{{ field.autocomplete }}"{% endif %}
{% if field.autocapitalize in ['off', 'characters', 'words', 'sentences'] %}autocapitalize="{{ field.autocapitalize }}"{% endif %}
{% if field.inputmode in ['none', 'text', 'decimal', 'numeric', 'tel', 'search', 'emaiil', 'url'] %}inputmode="{{ field.inputmode }}"{% endif %}
{% if field.inputmode in ['none', 'text', 'decimal', 'numeric', 'tel', 'search', 'email', 'url'] %}inputmode="{{ field.inputmode }}"{% endif %}
{% if field.spellcheck in ['true', 'false'] %}spellcheck="{{ field.spellcheck }}"{% endif %}
{% if field.attributes is defined %}
@@ -22,6 +22,22 @@
{% set action = base_url_relative ~ '/' ~ page.slug %}
{% endif %}
{% if form.keep_alive %}
{% do assets.addJs('plugin://form/assets/form.vendor.js', { 'loading': 'defer', 'group': 'bottom' }) %}
{% do assets.addJs('plugin://form/assets/form.min.js', { 'loading': 'defer', 'group': 'bottom' }) %}
{% endif %}
{% do assets.addInlineJs("
window.GravForm = window.GravForm || {};
window.GravForm.config = {
current_url: '" ~ uri.route(true) ~"',
base_url_relative: '" ~ base_url_relative ~ "',
param_sep: '"~ config.system.param_sep ~ "',
form_nonce: '" ~ form.getNonce ~ "',
session_timeout: " ~ config.system.session.timeout ~ "
};
window.GravForm.translations = jQuery.extend({}, window.GravForm.translations || {}, { PLUGIN_FORM: {} });
", { 'group': 'bottom' }) %}
<form name="{{ form.name }}"
action="{{ action | trim('/', 'right') }}"
method="{{ method }}"{{ multipart }}
@@ -30,14 +46,13 @@
class="{{ form_outer_classes }} {{ form.classes }}"
{% endblock %}
{% if form.novalidate %}novalidate{% endif %}
{% if form.keep_alive %}data-grav-keepalive="true"{% endif %}
>
{% block inner_markup_fields_start %}{% endblock %}
{% set data = data ?? form.data %}
{% for field in form.fields %}
{% if field.type == 'file' %}
{% do assets.addJs('plugin://form/assets/form.min.js') %}
{% endif %}
{% set value = form.value(field.name) %}
{% include "forms/fields/#{field.type}/#{field.type}.html.twig" ignore missing %}
{% endfor %}
@@ -0,0 +1,98 @@
{% extends "forms/field.html.twig" %}
{% do assets.addJs('plugin://form/assets/form.vendor.js', { 'loading': 'defer', 'group': 'bottom' }) %}
{% do assets.addJs('plugin://form/assets/form.min.js', { 'loading': 'defer', 'group': 'bottom' }) %}
{% block global_attributes %}
data-grav-array-name="{{ (scope ~ field.name)|fieldName }}"
data-grav-array-keyname="{{ field.placeholder_key|e|tu }}"
data-grav-array-valuename="{{ field.placeholder_value|e|tu }}"
data-grav-array-textarea="{{ field.value_type == 'textarea' }}"
{{ parent() }}
{% endblock %}
{% macro renderer(key, text, field, scope) %}
{% if text is not iterable %}
<div class="form-row{% if field.value_only %} array-field-value_only{% endif %}"
data-grav-array-type="row">
<span data-grav-array-action="sort" class="fa fa-bars"></span>
{% if field.value_only != true %}
{% if key == '0' and text == '' %}
{% set key = '' %}
{% endif %}
<input
data-grav-array-type="key"
type="text" value="{{ key }}"
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}
placeholder="{{ field.placeholder_key|e|tu }}" />
{% endif %}
{% if field.value_type == 'textarea' %}
<textarea
data-grav-array-type="value"
name="{{ ((scope ~ field.name)|fieldName) ~ '[' ~ key ~ ']' }}"
placeholder="{{ field.placeholder_value|e|tu }}"
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}>{{ text }}</textarea>
{% else %}
<input
data-grav-array-type="value"
type="text"
name="{{ ((scope ~ field.name)|fieldName) ~ '[' ~ key ~ ']' }}"
placeholder="{{ field.placeholder_value|e|tu }}"
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}
value={% if text == 'true' %}true{% elseif text == 'false' %}false{% else %}"{{ text|join(', ')|e }}"{% endif %} />
{% endif %}
<span data-grav-array-action="rem" class="fa fa-minus"></span>
<span data-grav-array-action="add" class="fa fa-plus"></span>
</div>
{% endif %}
{% endmacro %}
{% block input %}
{% import _self as array_field %}
<div class="{{ field.size }}" data-grav-array-type="container"{% if field.value_only %} data-grav-array-mode="value_only"{% endif %}{{ value|length <= 1 ? ' class="one-child"' : '' }}>
{% if value|length %}
{% for key, text in value -%}
{% if text is not iterable %}
{{ array_field.renderer(key, text, field, scope) }}
{% else %}
{# Backward compatibility for nested arrays (metas) which are not supported anymore #}
{% for subkey, subtext in text -%}
{{ array_field.renderer(key ~ '[' ~ subkey ~ ']', subtext, field, scope) }}
{% endfor %}
{% endif %}
{% endfor %}
{%- else -%}
{# Empty value, mock the entry field#}
<div class="form-row" data-grav-array-type="row">
<span data-grav-array-action="sort" class="fa fa-bars"></span>
{% if field.value_only != true %}
<input
data-grav-array-type="key"
type="text"
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}
placeholder="{{ field.placeholder_key|e|tu }}" />
{% endif %}
{% if field.value_type == 'textarea' %}
<textarea
data-grav-array-type="value"
name="{{ (scope ~ field.name)|fieldName }}"
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}
placeholder="{{ field.placeholder_value|e|tu }}"></textarea>
{% else %}
<input
data-grav-array-type="value"
type="text"
name="{{ (scope ~ field.name)|fieldName }}"
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}
placeholder="{{ field.placeholder_value|e|tu }}" />
{% endif %}
<span data-grav-array-action="rem" class="fa fa-minus"></span>
<span data-grav-array-action="add" class="fa fa-plus"></span>
</div>
{%- endif %}
</div>
{% endblock %}
@@ -81,32 +81,30 @@
</div>
{% do assets.addJs('jquery', 101) %}
{% do assets.addJs('plugin://form/assets/form.min.js', { 'group': 'bottom', 'loading': 'defer' }) %}
{% do assets.addCss('plugin://form/assets/dropzone.min.css', { 'group': 'form' }) %}
{% do assets.addJs('plugin://form/assets/form.vendor.js', { 'loading': 'defer', 'group': 'bottom' }) %}
{% do assets.addJs('plugin://form/assets/form.min.js', { 'loading': 'defer', 'group': 'bottom' }) %}
{% do assets.addCss('plugin://form/assets/dropzone.min.css', { 'group': 'form'}) %}
{{ assets.css('form')|raw }}
{% do assets.addInlineJs("
window.GravForm = window.GravForm || {};
window.GravForm.config = {
current_url: '" ~ uri.route(true) ~"',
base_url_relative: '" ~ base_url_relative ~ "',
param_sep: '"~ config.system.param_sep ~ "',
form_nonce: '" ~ form.getNonce ~ "',
};
window.GravForm.translations = {};
window.GravForm.translations['PLUGIN_FORM'] = {
'DROPZONE_CANCEL_UPLOAD': " ~ 'PLUGIN_FORM.DROPZONE_CANCEL_UPLOAD'|t|json_encode ~ ",
'DROPZONE_CANCEL_UPLOAD_CONFIRMATION': " ~ 'PLUGIN_FORM.DROPZONE_CANCEL_UPLOAD_CONFIRMATION'|t|json_encode ~ ",
'DROPZONE_DEFAULT_MESSAGE': " ~ 'PLUGIN_FORM.DROPZONE_DEFAULT_MESSAGE'|t|json_encode ~ ",
'DROPZONE_FALLBACK_MESSAGE': " ~ 'PLUGIN_FORM.DROPZONE_FALLBACK_MESSAGE'|t|json_encode ~ ",
'DROPZONE_FALLBACK_TEXT': " ~ 'PLUGIN_FORM.DROPZONE_FALLBACK_TEXT'|t|json_encode ~ ",
'DROPZONE_FILE_TOO_BIG': " ~ 'PLUGIN_FORM.DROPZONE_FILE_TOO_BIG'|t|json_encode ~ ",
'DROPZONE_INVALID_FILE_TYPE': " ~ 'PLUGIN_FORM.DROPZONE_INVALID_FILE_TYPE'|t|json_encode ~ ",
'DROPZONE_MAX_FILES_EXCEEDED': " ~ 'PLUGIN_FORM.DROPZONE_MAX_FILES_EXCEEDED'|t|json_encode ~ ",
'DROPZONE_REMOVE_FILE': " ~ 'PLUGIN_FORM.DROPZONE_REMOVE_FILE'|t|json_encode ~ ",
'DROPZONE_REMOVE_FILE_CONFIRMATION': " ~ 'PLUGIN_FORM.DROPZONE_REMOVE_FILE_CONFIRMATION'|t|json_encode ~ ",
'DROPZONE_RESPONSE_ERROR': " ~ 'PLUGIN_FORM.DROPZONE_RESPONSE_ERROR'|t|json_encode ~ ",
'RESOLUTION_MIN': " ~ 'PLUGIN_FORM.RESOLUTION_MIN'|t|json_encode ~ ",
'RESOLUTION_MAX': " ~ 'PLUGIN_FORM.RESOLUTION_MAX'|t|json_encode ~ "
};
window.GravForm = jQuery.extend({}, window.GravForm, {
translations: {
PLUGIN_FORM: {
'DROPZONE_CANCEL_UPLOAD': " ~ 'PLUGIN_FORM.DROPZONE_CANCEL_UPLOAD'|t|json_encode ~ ",
'DROPZONE_CANCEL_UPLOAD_CONFIRMATION': " ~ 'PLUGIN_FORM.DROPZONE_CANCEL_UPLOAD_CONFIRMATION'|t|json_encode ~ ",
'DROPZONE_DEFAULT_MESSAGE': " ~ 'PLUGIN_FORM.DROPZONE_DEFAULT_MESSAGE'|t|json_encode ~ ",
'DROPZONE_FALLBACK_MESSAGE': " ~ 'PLUGIN_FORM.DROPZONE_FALLBACK_MESSAGE'|t|json_encode ~ ",
'DROPZONE_FALLBACK_TEXT': " ~ 'PLUGIN_FORM.DROPZONE_FALLBACK_TEXT'|t|json_encode ~ ",
'DROPZONE_FILE_TOO_BIG': " ~ 'PLUGIN_FORM.DROPZONE_FILE_TOO_BIG'|t|json_encode ~ ",
'DROPZONE_INVALID_FILE_TYPE': " ~ 'PLUGIN_FORM.DROPZONE_INVALID_FILE_TYPE'|t|json_encode ~ ",
'DROPZONE_MAX_FILES_EXCEEDED': " ~ 'PLUGIN_FORM.DROPZONE_MAX_FILES_EXCEEDED'|t|json_encode ~ ",
'DROPZONE_REMOVE_FILE': " ~ 'PLUGIN_FORM.DROPZONE_REMOVE_FILE'|t|json_encode ~ ",
'DROPZONE_REMOVE_FILE_CONFIRMATION': " ~ 'PLUGIN_FORM.DROPZONE_REMOVE_FILE_CONFIRMATION'|t|json_encode ~ ",
'DROPZONE_RESPONSE_ERROR': " ~ 'PLUGIN_FORM.DROPZONE_RESPONSE_ERROR'|t|json_encode ~ ",
'RESOLUTION_MIN': " ~ 'PLUGIN_FORM.RESOLUTION_MIN'|t|json_encode ~ ",
'RESOLUTION_MAX': " ~ 'PLUGIN_FORM.RESOLUTION_MAX'|t|json_encode ~ "
}
}
});
", { 'group': 'bottom' }) %}
{% endblock %}
+60 -18
View File
@@ -1,23 +1,65 @@
var webpack = require('webpack'),
path = require('path'),
exec = require('child_process').execSync,
pwd = exec('pwd').toString();
path = require('path'),
UglifyJsPlugin = require('uglifyjs-webpack-plugin'),
isProd = process.env.NODE_ENV === 'production';
module.exports = {
entry: {
app: './app/main.js'
},
externals: {
jquery: 'jQuery',
'grav-form': 'GravForm'
},
module: {
preLoaders: [
{ test: /\.json$/, loader: 'json' },
{ test: /\.js$/, loader: 'eslint', exclude: /node_modules/ }
entry: {
site: './app/main.js'
},
devtool: isProd ? false : 'eval-source-map',
target: 'web',
output: {
path: path.resolve(__dirname, 'assets'),
filename: 'form.min.js',
chunkFilename: 'form.vendor.js'
},
optimization: {
minimize: isProd,
minimizer: [
new UglifyJsPlugin({
uglifyOptions: {
compress: {
drop_console: true
},
dead_code: true
}
})
],
splitChunks: {
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: 1,
name: 'vendor',
enforce: true,
chunks: 'all'
}
}
}
},
plugins: [
new webpack.ProvidePlugin({
'fetch': 'imports-loader?this=>global!exports-loader?global.fetch!whatwg-fetch'
})
],
loaders: [
{ test: /\.js$/, loader: 'babel', exclude: /node_modules/, query: { presets: ['es2015'] } }
]
}
externals: {
jquery: 'jQuery',
'grav-form': 'GravForm'
},
module: {
rules: [
{ enforce: 'pre', test: /\.json$/, loader: 'json-loader' },
{ enforce: 'pre', test: /\.js$/, loader: 'eslint-loader', exclude: /node_modules/ },
{ test: /\.css$/, loader: 'style-loader!css-loader' },
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/,
query: {
presets: ['es2015', 'stage-3']
}
}
]
}
};
File diff suppressed because it is too large Load Diff