From 09af1d9a8c4cb5e9dea883f211e68c10b9603051 Mon Sep 17 00:00:00 2001 From: trendschau Date: Wed, 27 May 2020 19:48:22 +0200 Subject: [PATCH 1/2] update feature branch --- composer.lock | 20 +++++++++---------- readme.md | 6 +++--- themes/typemill/languages/{ => admin}/de.yaml | 0 themes/typemill/languages/{ => admin}/en.yaml | 0 themes/typemill/languages/{ => admin}/fr.yaml | 0 themes/typemill/languages/{ => admin}/it.yaml | 0 themes/typemill/languages/{ => admin}/nl.yaml | 0 themes/typemill/languages/{ => admin}/ru.yaml | 0 themes/typemill/languages/user/en.yaml | 1 + themes/typemill/languages/user/it.yaml | 1 + 10 files changed, 15 insertions(+), 13 deletions(-) rename themes/typemill/languages/{ => admin}/de.yaml (100%) rename themes/typemill/languages/{ => admin}/en.yaml (100%) rename themes/typemill/languages/{ => admin}/fr.yaml (100%) rename themes/typemill/languages/{ => admin}/it.yaml (100%) rename themes/typemill/languages/{ => admin}/nl.yaml (100%) rename themes/typemill/languages/{ => admin}/ru.yaml (100%) create mode 100644 themes/typemill/languages/user/en.yaml create mode 100644 themes/typemill/languages/user/it.yaml diff --git a/composer.lock b/composer.lock index 7976cb3..ad03965 100644 --- a/composer.lock +++ b/composer.lock @@ -686,16 +686,16 @@ }, { "name": "symfony/polyfill-ctype", - "version": "v1.15.0", + "version": "v1.17.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "4719fa9c18b0464d399f1a63bf624b42b6fa8d14" + "reference": "e94c8b1bbe2bc77507a1056cdb06451c75b427f9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/4719fa9c18b0464d399f1a63bf624b42b6fa8d14", - "reference": "4719fa9c18b0464d399f1a63bf624b42b6fa8d14", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/e94c8b1bbe2bc77507a1056cdb06451c75b427f9", + "reference": "e94c8b1bbe2bc77507a1056cdb06451c75b427f9", "shasum": "" }, "require": { @@ -707,7 +707,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.15-dev" + "dev-master": "1.17-dev" } }, "autoload": { @@ -740,7 +740,7 @@ "polyfill", "portable" ], - "time": "2020-02-27T09:26:54+00:00" + "time": "2020-05-12T16:14:59+00:00" }, { "name": "symfony/yaml", @@ -862,12 +862,12 @@ "source": { "type": "git", "url": "https://github.com/vlucas/valitron.git", - "reference": "43e9393009220353445dc5cbe6da1442d71d87ab" + "reference": "4af076d19f3cd4fd61f560cba115316834c7fe81" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vlucas/valitron/zipball/43e9393009220353445dc5cbe6da1442d71d87ab", - "reference": "43e9393009220353445dc5cbe6da1442d71d87ab", + "url": "https://api.github.com/repos/vlucas/valitron/zipball/4af076d19f3cd4fd61f560cba115316834c7fe81", + "reference": "4af076d19f3cd4fd61f560cba115316834c7fe81", "shasum": "" }, "require": { @@ -903,7 +903,7 @@ "validation", "validator" ], - "time": "2020-03-05T19:31:19+00:00" + "time": "2020-05-14T14:50:07+00:00" } ], "packages-dev": [], diff --git a/readme.md b/readme.md index 20f738a..f003ad8 100644 --- a/readme.md +++ b/readme.md @@ -78,15 +78,15 @@ TYPEMILL is published under MIT licence. Please check the licence of the include ## Contributors & Supporters -* [Severo Juliano](https://github.com/iusvar) manages the internationalization i18n. +* [Severo Iuliano](https://github.com/iusvar) manages the internationalization i18n. * [Eziquel Bruni](https://github.com/EzequielBruni) edits the typemill documentation. * [Ricky](https://github.com/rbertram90) developed the discard functionality. * [vodaris](https://www.vodaris.de) sponsored the development of the search plugin. * Translations: * Dutch: [svanlaere](https://github.com/svanlaere) - * French: [Olivier Crouzet]https://github.com/oliviercrouzet + * French: [Olivier Crouzet](https://github.com/oliviercrouzet) * German: [trendschau](https://github.com/trendschau) - * Italian: [Severo Juliano](https://github.com/iusvar) + * Italian: [Severo Iuliano](https://github.com/iusvar) * Russian: [Hide-me](https://github.com/hide-me) ## How to Contribute diff --git a/themes/typemill/languages/de.yaml b/themes/typemill/languages/admin/de.yaml similarity index 100% rename from themes/typemill/languages/de.yaml rename to themes/typemill/languages/admin/de.yaml diff --git a/themes/typemill/languages/en.yaml b/themes/typemill/languages/admin/en.yaml similarity index 100% rename from themes/typemill/languages/en.yaml rename to themes/typemill/languages/admin/en.yaml diff --git a/themes/typemill/languages/fr.yaml b/themes/typemill/languages/admin/fr.yaml similarity index 100% rename from themes/typemill/languages/fr.yaml rename to themes/typemill/languages/admin/fr.yaml diff --git a/themes/typemill/languages/it.yaml b/themes/typemill/languages/admin/it.yaml similarity index 100% rename from themes/typemill/languages/it.yaml rename to themes/typemill/languages/admin/it.yaml diff --git a/themes/typemill/languages/nl.yaml b/themes/typemill/languages/admin/nl.yaml similarity index 100% rename from themes/typemill/languages/nl.yaml rename to themes/typemill/languages/admin/nl.yaml diff --git a/themes/typemill/languages/ru.yaml b/themes/typemill/languages/admin/ru.yaml similarity index 100% rename from themes/typemill/languages/ru.yaml rename to themes/typemill/languages/admin/ru.yaml diff --git a/themes/typemill/languages/user/en.yaml b/themes/typemill/languages/user/en.yaml new file mode 100644 index 0000000..33806a3 --- /dev/null +++ b/themes/typemill/languages/user/en.yaml @@ -0,0 +1 @@ +# English diff --git a/themes/typemill/languages/user/it.yaml b/themes/typemill/languages/user/it.yaml new file mode 100644 index 0000000..5cef266 --- /dev/null +++ b/themes/typemill/languages/user/it.yaml @@ -0,0 +1 @@ +# Italiano From b41ca0a3a14ee1ff01c67764594cdc8b53de7e1b Mon Sep 17 00:00:00 2001 From: trendschau Date: Fri, 5 Jun 2020 08:27:31 +0200 Subject: [PATCH 2/2] Version 1.3.7: Image Field for Themes and Plugins --- content/index.md | 2 +- system/Controllers/SettingsController.php | 102 +++++++++++++--- system/Models/Fields.php | 2 +- system/Models/Folder.php | 4 +- system/Models/Validation.php | 10 ++ system/author/css/style.css | 4 +- system/author/editor/publish-controller.twig | 6 +- system/author/js/typemillutils.js | 66 ++++++++++- system/author/languages/de.yaml | 1 + system/author/layouts/layout.twig | 6 +- system/author/partials/fields.twig | 116 ++++++++++++------- system/author/partials/form.twig | 2 +- system/author/settings/plugins.twig | 2 +- system/author/settings/themes.twig | 2 +- 14 files changed, 252 insertions(+), 73 deletions(-) diff --git a/content/index.md b/content/index.md index ffdee6e..0d8f3d5 100644 --- a/content/index.md +++ b/content/index.md @@ -1,4 +1,4 @@ # Typemill -*Typemill is a user-friendly and lightweight open source CMS for publishing text-works like prose, lyrics, manuals, documentations, studies and more. Just download and start.* +Typemill is a user-friendly and lightweight open source CMS for publishing text-works like prose, lyrics, manuals, documentations, studies and more. Just download and start. diff --git a/system/Controllers/SettingsController.php b/system/Controllers/SettingsController.php index 0e66c71..cf426aa 100644 --- a/system/Controllers/SettingsController.php +++ b/system/Controllers/SettingsController.php @@ -172,7 +172,7 @@ class SettingsController extends Controller public function showThemes($request, $response, $args) { - $userSettings = $this->c->get('settings'); + $userSettings = $this->c->get('settings'); $themes = $this->getThemes(); $themedata = array(); $fieldsModel = new Fields(); @@ -332,7 +332,7 @@ class SettingsController extends Controller $userInput = isset($params[$themeName]) ? $params[$themeName] : false; $validate = new Validation(); $themeSettings = \Typemill\Settings::getObjectSettings('themes', $themeName); - + if(isset($themeSettings['settings']['images'])) { # get the default settings @@ -375,12 +375,23 @@ class SettingsController extends Controller if($userInput) { - /* validate the user-input */ - $this->validateInput('themes', $themeName, $userInput, $validate); - + # validate the user-input and return image-fields if they are defined + $imageFields = $this->validateInput('themes', $themeName, $userInput, $validate); + /* set user input as theme settings */ $userSettings['themes'][$themeName] = $userInput; } + + # handle images + $images = $request->getUploadedFiles(); + + if(!isset($_SESSION['errors']) && isset($images[$themeName])) + { + $userInput = $this->saveImages($imageFields, $userInput, $userSettings, $images[$themeName]); + + # set user input as theme settings + $userSettings['themes'][$themeName] = $userInput; + } /* check for errors and redirect to path, if errors found */ if(isset($_SESSION['errors'])) @@ -428,11 +439,22 @@ class SettingsController extends Controller else { /* validate the user-input */ - $this->validateInput('plugins', $pluginName, $userInput[$pluginName], $validate); + $imageFields = $this->validateInput('plugins', $pluginName, $userInput[$pluginName], $validate); /* use the input data */ $pluginSettings[$pluginName] = $userInput[$pluginName]; } + + # handle images + $images = $request->getUploadedFiles(); + + if(!isset($_SESSION['errors']) && isset($images[$pluginName])) + { + $userInput[$pluginName] = $this->saveImages($imageFields, $userInput[$pluginName], $userSettings, $images[$pluginName]); + + # set user input as theme settings + $pluginSettings[$pluginName] = $userInput[$pluginName]; + } /* deactivate the plugin, if there is no active flag */ if(!isset($userInput[$pluginName]['active'])) @@ -465,6 +487,9 @@ class SettingsController extends Controller /* fetch the original settings from the folder (plugin or theme) to get the field definitions */ $originalSettings = \Typemill\Settings::getObjectSettings($objectType, $objectName); + # images get special treatment + $imageFieldDefinitions = array(); + if(isset($originalSettings['forms']['fields'])) { /* flaten the multi-dimensional array with fieldsets to a one-dimensional array */ @@ -509,6 +534,12 @@ class SettingsController extends Controller { /* validate user input for this field */ $validate->objectField($fieldName, $fieldValue, $objectName, $fieldDefinition, $skiprequired); + + if($fieldDefinition['type'] == 'image') + { + # we want to return all images-fields for further processing + $imageFieldDefinitions[$fieldName] = $fieldDefinition; + } } if(!$fieldDefinition && $fieldName != 'active') { @@ -516,6 +547,45 @@ class SettingsController extends Controller } } } + + return $imageFieldDefinitions; + } + + protected function saveImages($imageFields, $userInput, $userSettings, $files) + { + + # initiate image processor with standard image sizes + $processImages = new ProcessImage($userSettings['images']); + + if(!$processImages->checkFolders()) + { + $this->c->flash->addMessage('error', 'Please make sure that your media folder exists and is writable.'); + return false; + } + + foreach($imageFields as $fieldName => $imageField) + { + if(isset($userInput[$fieldName])) + { + # handle single input with single file upload + $image = $files[$fieldName]; + + if($image->getError() === UPLOAD_ERR_OK) + { + # not the most elegant, but createImage expects a base64-encoded string. + $imageContent = $image->getStream()->getContents(); + $imageData = base64_encode($imageContent); + $imageSrc = 'data: ' . $image->getClientMediaType() . ';base64,' . $imageData; + + if($processImages->createImage($imageSrc, $image->getClientFilename(), $userSettings['images'], $overwrite = NULL)) + { + # returns image path to media library + $userInput[$fieldName] = $processImages->publishImage(); + } + } + } + } + return $userInput; } /*********************** @@ -751,13 +821,13 @@ class SettingsController extends Controller private function getLanguages() { - return array( - 'en' => 'English', - 'ru' => 'Russian', - 'nl' => 'Dutch, Flemish', - 'de' => 'German', - 'it' => 'Italian', - 'fr' => 'French', - ); - } -} + return array( + 'en' => 'English', + 'ru' => 'Russian', + 'nl' => 'Dutch, Flemish', + 'de' => 'German', + 'it' => 'Italian', + 'fr' => 'French', + ); + } +} diff --git a/system/Models/Fields.php b/system/Models/Fields.php index a304e75..c38a8db 100644 --- a/system/Models/Fields.php +++ b/system/Models/Fields.php @@ -86,7 +86,7 @@ class Fields } else { - $field->unsetAttribute('chhecked'); + $field->unsetAttribute('checked'); } } else diff --git a/system/Models/Folder.php b/system/Models/Folder.php index 587438f..0dcaeda 100644 --- a/system/Models/Folder.php +++ b/system/Models/Folder.php @@ -506,7 +506,9 @@ class Folder { # if it is the first round, create an empty array if(!$i){ $i = 0; $breadcrumb = array();} - + + if(!$searchArray){ return $breadcrumb;} + while($i < count($searchArray)) { if(!isset($content[$searchArray[$i]])){ return false; } diff --git a/system/Models/Validation.php b/system/Models/Validation.php index 14f8b2c..84b0554 100644 --- a/system/Models/Validation.php +++ b/system/Models/Validation.php @@ -27,6 +27,15 @@ class Validation return false; }, 'invalid values'); + Validator::addRule('image_types', function($field, $value, array $params, array $fields) use ($user) + { + $allowed = ['jpg', 'jpeg', 'png']; + $pathinfo = pathinfo($value); + $extension = strtolower($pathinfo['extension']); + if(array_search($extension, $allowed)){ return true; } + return false; + }, 'only jpg, jpeg, png allowed'); + Validator::addRule('userAvailable', function($field, $value, array $params, array $fields) use ($user) { $userdata = $user->getUser($value); @@ -434,6 +443,7 @@ class Validation case "image": $v->rule('noHTML', $fieldName); $v->rule('lengthMax', $fieldName, 1000); + $v->rule('image_types', $fieldName); break; default: $v->rule('lengthMax', $fieldName, 1000); diff --git a/system/author/css/style.css b/system/author/css/style.css index 2adabc7..6d2a3b8 100644 --- a/system/author/css/style.css +++ b/system/author/css/style.css @@ -1114,7 +1114,7 @@ ul.cardInfo{ border: 0px; } .cardFields.open{ - max-height: 5000px; + max-height: 20000px; transition: max-height 0.5s ease-in; overflow: hidden; border: 1px; @@ -2490,6 +2490,8 @@ footer a:focus, footer a:hover, footer a:active } .blox .TOC li:before{ color: #bbb; } +.mbfix{ margin-bottom: 0px!important; } + @media only screen and (min-width: 600px) { section{ diff --git a/system/author/editor/publish-controller.twig b/system/author/editor/publish-controller.twig index 10bfaf5..ea6186a 100644 --- a/system/author/editor/publish-controller.twig +++ b/system/author/editor/publish-controller.twig @@ -1,3 +1,5 @@ +{% set itemurl = (item.urlRelWoF == '/') ? '' : item.urlRelWoF %} +
${ errors.message }
@@ -5,8 +7,8 @@ diff --git a/system/author/js/typemillutils.js b/system/author/js/typemillutils.js index a317bcd..f0891fc 100644 --- a/system/author/js/typemillutils.js +++ b/system/author/js/typemillutils.js @@ -5,6 +5,7 @@ let typemillUtilities = { { this.youtubeItems = document.querySelectorAll( ".youtube" ); }, + addYoutubePlayButtons: function(){ if(this.youtubeItems) { @@ -24,12 +25,13 @@ let typemillUtilities = { youtubePlaybutton.classList.add("play-video"); youtubePlaybutton.value = "Play"; - element.parentNode.appendChild(youtubePlaybutton); + element.parentNode.appendChild(youtubePlaybutton); }, - listenToYoutube: function(){ + listenToClick: function(){ document.addEventListener('click', function (event) { + /* listen to youtube */ if (event.target.matches('.play-video')) { var youtubeID = event.target.parentNode.getElementsByClassName('youtube')[0].id; @@ -49,12 +51,66 @@ let typemillUtilities = { videocontainer.innerHTML = ""; videocontainer.appendChild( iframe ); } + + if (event.target.matches('.function-delete-img')) { + + event.preventDefault(); + event.stopPropagation(); + + var imgUploadField = event.target.closest(".img-upload"); + var imgSrc = imgUploadField.getElementsByClassName("function-img-src")[0]; + imgSrc.src = ''; + var imgUrl = imgUploadField.getElementsByClassName("function-img-url")[0]; + imgUrl.value = ''; + + } + + }, true); + }, + + listenToChange: function() + { + document.addEventListener('change', function (changeevent) { + + /* listen to youtube */ + if (changeevent.target.matches('.function-img-file')) { + + if(changeevent.target.files.length > 0) + { + let imageFile = changeevent.target.files[0]; + let size = imageFile.size / 1024 / 1024; + + if (!imageFile.type.match('image.*')) + { + // publishController.errors.message = "Only images are allowed."; + } + else if (size > this.maxsize) + { + // publishController.errors.message = "The maximal size of images is " + this.maxsize + " MB"; + } + else + { + let reader = new FileReader(); + reader.readAsDataURL(imageFile); + reader.onload = function(fileevent) + { + var imgUploadField = changeevent.target.closest(".img-upload"); + var imgSrc = imgUploadField.getElementsByClassName("function-img-src")[0]; + imgSrc.src = fileevent.target.result; + var imgUrl = imgUploadField.getElementsByClassName("function-img-url")[0]; + imgUrl.value = imageFile.name; + } + } + } + } + }, true); }, start: function(){ this.setYoutubeItems(); - this.addYoutubePlayButtons(); - this.listenToYoutube(); - }, + this.addYoutubePlayButtons(); + this.listenToClick(); + this.listenToChange(); + }, }; \ No newline at end of file diff --git a/system/author/languages/de.yaml b/system/author/languages/de.yaml index 52d3abb..f287005 100644 --- a/system/author/languages/de.yaml +++ b/system/author/languages/de.yaml @@ -167,6 +167,7 @@ ULIST: ulist UNKNOWN: Unbekannt UPDATE_USER: Nutzer aktualisieren UPLOAD_FILE: Datei hochladen +UPLOAD_AN_IMAGE: Bild hochladen UPLOAD: hochladen USE_2_TO_20_CHARACTERS: 2 bis 20 Anschläge erlaubt. USE_2_TO_40_CHARACTERS: 2 to 40 Anschläge erlaubt. diff --git a/system/author/layouts/layout.twig b/system/author/layouts/layout.twig index aacdd68..06ef3a3 100644 --- a/system/author/layouts/layout.twig +++ b/system/author/layouts/layout.twig @@ -56,7 +56,11 @@
- + + + \ No newline at end of file diff --git a/system/author/partials/fields.twig b/system/author/partials/fields.twig index 4ad22c6..3123f9f 100644 --- a/system/author/partials/fields.twig +++ b/system/author/partials/fields.twig @@ -5,67 +5,99 @@ {% if field.help %}
?{{__(field.help|slice(0,100))}}
{% endif %} - {% if field.type == 'textarea' %} + {% if field.type == 'image' %} +
+
+
+ +
+
+
+
+ +
{{ __('Upload an image') }}
+
+
+ +
+ + +
+
+ {% if errors[itemName][field.name] %} +
{{ errors[itemName][field.name] | first }}
+ {% endif %} - + {% if field.description %}
{{ __(field.description) }}
{% endif %} - {% elseif field.type == 'paragraph' %} - - {{ markdown(field.getContent()) }} +
+
- {% elseif field.type == 'checkbox' %} + {% else %} + + {% if field.type == 'textarea' %} + + + + {% elseif field.type == 'paragraph' %} - + {{ markdown(field.getContent()) }} - {% elseif field.type == 'checkboxlist' %} - - {% set options = field.getOptions() %} - - {% for value,label in options %} - - + {% endfor %} - - {% elseif field.type == 'radio' %} + {% elseif field.type == 'select' %} - {% set options = field.getOptions() %} + {% set options = field.getOptions() %} - {% for value,label in options %} + + + {% elseif field.type == 'radio' %} + + {% set options = field.getOptions() %} + + {% for value,label in options %} + + + + {% endfor %} - + {% else %} - {% endfor %} + + + {% endif %} + + {% if field.description %}
{{ __(field.description) }}
{% endif %} - {% else %} + {% if errors[itemName][field.name] %} + {{ errors[itemName][field.name] | first }} + {% endif %} - - - {% endif %} - - {% if field.description %}
{{ __(field.description) }}
{% endif %} - - {% if errors[itemName][field.name] %} - {{ errors[itemName][field.name] | first }} {% endif %} \ No newline at end of file diff --git a/system/author/partials/form.twig b/system/author/partials/form.twig index f7742c1..da95e6a 100644 --- a/system/author/partials/form.twig +++ b/system/author/partials/form.twig @@ -3,7 +3,7 @@ {% endif %} -
+
diff --git a/system/author/settings/plugins.twig b/system/author/settings/plugins.twig index b1d13e0..55034b0 100644 --- a/system/author/settings/plugins.twig +++ b/system/author/settings/plugins.twig @@ -6,7 +6,7 @@
- +
diff --git a/system/author/settings/themes.twig b/system/author/settings/themes.twig index 1f51092..69b165f 100644 --- a/system/author/settings/themes.twig +++ b/system/author/settings/themes.twig @@ -15,7 +15,7 @@ {% for themeName, theme in themes %} - +