-
-
Notifications
You must be signed in to change notification settings - Fork 57
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[RFC] Rewrite the picker implementation #950
Conversation
Please revert the naming and namespace changes. Otherwise it is impossible to understand the changes. |
@@ -24,6 +33,7 @@ setTimeout(function() { | |||
} | |||
editor.on('focus', function(){ Backend.getScrollOffset(); }); | |||
}, | |||
file_browser_callback_types: <?= json_encode($pickerTypes) ?>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The whole logic needs to be moved to the DataContainer
class, so we can use $this->pickerTypes
in the templates.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is tinyMCE initialized by DataContainer ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed in 1f24de0
@@ -510,7 +514,19 @@ protected function row($strPalette=null) | |||
} | |||
} | |||
|
|||
$objWidget->wizard = $wizard; | |||
if ($wizard != '') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How is this change related to the picker?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It hides the picker icon and spacing if the dcaPicker is not supported (due to permissions etc.)
src/Resources/public/core.js
Outdated
@@ -898,7 +898,7 @@ var Backend = | |||
var opt = options || {}, | |||
maxWidth = (window.getSize().x - 20).toInt(), | |||
maxHeight = (window.getSize().y - 192).toInt(); | |||
if (!opt.id) opt.id = 'tl_select'; | |||
if (!opt.id) opt.id = 'tl_listing'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You must not change this, because it is not backwards compatible with the old PageTree
and FileTree
widgets.
src/Picker/PickerBuilder.php
Outdated
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function createFromJson($json) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would actually add createFromUrlValue()
and saveForUrlValue()
or something like this. You can keep the others if you like but this would allow us using gzencode()
etc. in these methods (or anything else in the future) to transparently and backwards compatible improve the size of the content :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
implemented in a25b132, including Gzip compression
{ | ||
$arrRoot = $this->eliminateNestedPages($arrRoot); | ||
} | ||
$arrRoot = array_intersect($arrRoot, $this->Database->getChildRecords($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['root'], 'tl_page')); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be $this->strTable
not tl_page
right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in 368b144
@@ -224,8 +226,23 @@ public function alertsAction() | |||
*/ | |||
public function pickerAction(Request $request) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we have some extended description in the docblock here? :) Handles the picker redirect.
does not really help a lot.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Improved in 9e53148
* @param FactoryInterface $menuFactory | ||
* @param TokenStorageInterface $tokenStorage | ||
*/ | ||
public function __construct(FactoryInterface $menuFactory, TokenStorageInterface $tokenStorage) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer having setter injection for the TokenStorageInterface
because getUser()
is absolutely optional for an AbstractPickerProvider
. I think we should have setTokenStorage()
and getTokenStorage()
. The getUser()
already considers the null
case anyway :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this makes sense.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed in 37b9d7c
namespace Contao\CoreBundle\Picker; | ||
|
||
/** | ||
* Interface for DCA picker providers. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would like to have more description here. Use this if .....
or something. This would help very much.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Improved in 9e53148
src/Picker/PickerConfig.php
Outdated
* | ||
* @return string | ||
*/ | ||
public function urlEncode($gzip = true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would name this $compress = true
. Who cares if this is gzip.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Improved in 9e53148
|
||
if (isset($arrFilter['files']) && $arrFilter['files'] === false) | ||
if (is_array($attributes)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer a null
check as there can only be array or null.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Improved in 9e53148
{ | ||
$attributes = parent::initPicker($picker); | ||
|
||
if (is_array($attributes)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check for null
here and do an early return please. I hate these 5-level nestings 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Improved in 9e53148
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function convertDcaValue(PickerConfig $config, $value) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are actually converting the picked value here, aren't we?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're converting the value from DC/database to the one we can pick.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still prefer convertValue()
or convertPickedValue()
. 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You know the method is (only) part of the DcaPickerProviderInterface
, right? That's why I named the methods so they are specific to the DCA, if we ever later add similar features for something else…
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just think that convertPickedValue()
is better understandable for everyone implementing the interface. convertDcaValue()
sounds like the load_callback
of the field is executed to convert the DCA value. 😉
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, first, all the Dca
parts in the method names are unnecessary in my opinion, because the class already has Dca
in it.
But second, the first two methods actually read data from the DCA, so using Dca
in the method name is kind of correct. The third method, however, reads user input, so …
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mean the interface does?
The convertDcaValue
does not really read user input, it's basically a save_callback on the DCA value before it is rendered as a picker radio/checkbox value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Of course it reads user input. The user picks page ID 12, submits the value and gets back {{link_url::12}}
.
Again, I think that convertPickedValue()
is much better understandable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is not correct. There is no Ajax request anymore, the values are converted before the user selects them in the picker. This also results in an instant update of the field value, contrary to the previous implementation which took seconds to update 😉
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, why don't you say that right away? Then convertDcaValue
is actually fine. 😄
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function jsonSerialize() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The method says JSON serialize but it returns an array?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's how the \JsonSerializable
interface works 😉
src/Picker/PickerConfig.php
Outdated
*/ | ||
public function urlEncode($gzip = true) | ||
{ | ||
$data = json_encode($this); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are you encoding $this
here? Should it be $this->jsonSerialize()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's how the \JsonSerializable
interface works 😉
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is actually because json_encode()
can handle objects and not because of the interface. 😉
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well json_encode
will realize the object implements \JsonSerializable
and uses that method…
src/Picker/PickerInterface.php
Outdated
* | ||
* @return PickerProviderInterface|null | ||
*/ | ||
public function getCurrentProvider(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer getProvider()
here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It returns the currently active provider (based on the value).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then I prefer getActiveProvider()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's named after isCurrent
, which is based on KnpMenu
(as described below). Still wanna change it?
src/Picker/PickerInterface.php
Outdated
* | ||
* @return string | ||
*/ | ||
public function getCurrentUrl(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer getUrl()
here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It returns the URL for the current provider (based on the value).
* | ||
* @return bool | ||
*/ | ||
public function isCurrent(PickerConfig $config); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer isActive()
here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've named this after the current
variable of the KnpMenu
…
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, ok. We should either say current
or active
everywhere for consistency. So getCurrentProvider()
, getCurrentUrl()
, isCurrent()
etc. or getActiveProvider()
, getActiveUrl()
, isActive()
etc.
I prefer the latter, but as long as it is consistent, I can live with it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, sort of agree. We name it active most of the time in Contao. But we cannot change KnpMenu
, and the isCurrent()
method is also called in https://github.com/aschempp/contao-core-bundle/blob/37b9d7caa43b196d8b234d59440c1b09f3842e06/src/Picker/AbstractPickerProvider.php#L64 to determine the current menu item…
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just use "current" everywhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 so nothing to change 😎
|
||
// Deprecated since Contao 4.0, to be removed in Contao 5.0 | ||
$objTemplate->language = \Backend::getTinyMceLanguage(); | ||
|
||
$updateMode = $objTemplate->parse(); | ||
|
||
unset($file, $type); | ||
unset($file, $type, $pickerBuilder); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also unset $fileBrowserTypes
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added in 9e53148
$this->Template->main .= $this->getBackendModule(\Input::get('do')); | ||
$picker = null; | ||
|
||
if (isset($_GET['picker'])) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using isset($_GET)
cannot be "overwritten" via Input::setGet()
. I know that I have been doing it, too – maybe we should discuss it and be consistent?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As far as I know, this will work fine. Input::setGet
removes caches and adds the variable to $_GET
(see https://github.com/contao/core-bundle/blob/master/src/Resources/contao/library/Contao/Input.php#L326)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right. 👍
@@ -2667,7 +2662,7 @@ protected function generateTree($path, $intMargin, $mount=false, $blnProtected=t | |||
} | |||
} | |||
|
|||
if ($this->blnHideFiles) | |||
if (!$this->blnFiles && !$this->blnFilesOnly) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this really work without $this->strPickerField &&
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes it does, because $blnFiles
is initialized to true
and only set to false
on initPicker
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok.
@@ -94,7 +94,7 @@ | |||
|
|||
<?php if ($this->isPopup): ?> | |||
<script> | |||
if ($$('.tl_tree_checkbox,.tl_tree_radio').length > 0) { | |||
if ($$('.tl_tree_checkbox,.tl_tree_radio').length > 0 && !document.location.search.test('act=select')) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer to have this as an outer if condition:
if (!document.location.search.test('act=select')) {
if ($$('.tl_tree_checkbox,.tl_tree_radio').length > 0)) {
// …
} else {
// …
}
}
Otherwise the else condition would still be evaluated in "edit multiple" mode.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That would mean the buttons are not disabled when in select mode, which is not what we want, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Of course. Don't know what I was thinking. 😄
Already looking very good! Thank you very much @aschempp. |
Actually merged in 874076d. |
As discussed in several issues, the current picker implementation does not really work. Here's my rewrite to support all current features and some more!
TODO: