Skip to content

Commit

Permalink
NEW Allow developers to exclude LinkText field (#215)
Browse files Browse the repository at this point in the history
  • Loading branch information
GuySartorelli authored Feb 12, 2024
1 parent 5076ef1 commit 04ae65c
Show file tree
Hide file tree
Showing 10 changed files with 101 additions and 9 deletions.
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,24 @@ $fields->addFieldsToTab(
);
```

## Excluding the `LinkText` field

Sometimes you might want to have a link which doesn't have text, or for which you handle the text elsewhere. For example you might have a banner with a link, and you only want to use `LinkField` to control where the banner links to.

You can call the `setExcludeLinkTextField()` method to remove the `LinkText` field from the link modal for all links connected to that link field.

```php
$fields->addFieldsToTab(
'Root.Main',
[
MultiLinkField::create('LinkList')
->setExcludeLinkTextField(true),
Link::create('Link')
->setExcludeLinkTextField(true),
],
);
```

## Unversioned links

The `Link` model has the `Versioned` extension applied to it by default. If you wish for links to not be versioned, then remove the extension from the `Link` model in the projects `app/_config.php` file.
Expand Down
2 changes: 1 addition & 1 deletion client/dist/js/bundle.js

Large diffs are not rendered by default.

8 changes: 5 additions & 3 deletions client/src/components/LinkField/LinkField.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ const LinkField = ({
ownerID,
ownerClass,
ownerRelation,
excludeLinkTextField = false,
}) => {
const [data, setData] = useState({});
const [editingID, setEditingID] = useState(0);
Expand Down Expand Up @@ -260,14 +261,14 @@ const LinkField = ({
onDragStart={handleDragStart}
onDragEnd={handleDragEnd}
>
<SortableContext
<SortableContext
items={linkIDs}
strategy={verticalListSortingStrategy}
>
{links}
</SortableContext>
</DndContext>
</div>
</div>
}
return <div>{links}</div>
};
Expand Down Expand Up @@ -321,7 +322,7 @@ const LinkField = ({
const saveRecordFirstText = i18n._t('LinkField.SAVE_RECORD_FIRST', 'Cannot add links until the record has been saved');
const links = renderLinks();

return <LinkFieldContext.Provider value={{ ownerID, ownerClass, ownerRelation, actions, loading }}>
return <LinkFieldContext.Provider value={{ ownerID, ownerClass, ownerRelation, actions, loading, excludeLinkTextField }}>
<div className="link-field__container">
{ saveRecordFirst && <div className="link-field__save-record-first">{saveRecordFirstText}</div>}
{ loading && !isSorting && !saveRecordFirst && <Loading containerClass="link-field__loading"/> }
Expand Down Expand Up @@ -359,6 +360,7 @@ LinkField.propTypes = {
ownerID: PropTypes.number.isRequired,
ownerClass: PropTypes.string.isRequired,
ownerRelation: PropTypes.string.isRequired,
excludeLinkTextField: PropTypes.bool,
};

// redux actions loaded into props - used to get toast notifications
Expand Down
5 changes: 4 additions & 1 deletion client/src/components/LinkModal/LinkModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@ const buildSchemaUrl = (typeKey, linkID) => {
const parsedURL = url.parse(schemaUrl);
const parsedQs = qs.parse(parsedURL.query);
parsedQs.typeKey = typeKey;
const { ownerID, ownerClass, ownerRelation } = useContext(LinkFieldContext);
const { ownerID, ownerClass, ownerRelation, excludeLinkTextField } = useContext(LinkFieldContext);
parsedQs.ownerID = ownerID;
parsedQs.ownerClass = ownerClass;
parsedQs.ownerRelation = ownerRelation;
if (excludeLinkTextField) {
parsedQs.excludeLinkTextField = true;
}
for (const prop of ['href', 'path', 'pathname']) {
parsedURL[prop] = joinUrlPaths(parsedURL[prop], linkID.toString());
}
Expand Down
1 change: 1 addition & 0 deletions client/src/entwine/LinkField.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ jQuery.entwine('ss', ($) => {
ownerID: inputField.data('owner-id'),
ownerClass: inputField.data('owner-class'),
ownerRelation: inputField.data('owner-relation'),
excludeLinkTextField: inputField.data('exclude-linktext-field'),
onChange: this.handleChange.bind(this),
isMulti: this.data('is-multi') ?? false,
types: this.data('types') ?? {},
Expand Down
10 changes: 8 additions & 2 deletions src/Controllers/LinkFieldController.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@ public function linkForm(): Form
}
$operation = 'create';
}
return $this->createLinkForm($link, $operation);
$excludeLinkTextField = (bool) $this->getRequest()->getVar('excludeLinkTextField');
return $this->createLinkForm($link, $operation, $excludeLinkTextField);
}

/**
Expand Down Expand Up @@ -319,7 +320,7 @@ public function linkSort()
/**
* Create the Form used to content manage a Link in a modal
*/
private function createLinkForm(Link $link, string $operation): Form
private function createLinkForm(Link $link, string $operation, bool $excludeLinkTextField = false): Form
{
$id = $link->ID;

Expand All @@ -333,6 +334,11 @@ private function createLinkForm(Link $link, string $operation): Form
$ownerClassName = $owner->ClassName;
$ownerRelation = $this->getOwnerRelationFromRequest();

// Remove LinkText if appropriate
if ($excludeLinkTextField) {
$form->Fields()->removeByName('LinkText');
}

// Add hidden form fields for OwnerID, OwnerClass and OwnerRelation
if ($operation === 'create') {
$form->Fields()->push(HiddenField::create('OwnerID')->setValue($ownerID));
Expand Down
2 changes: 2 additions & 0 deletions src/Form/LinkField.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ protected function getDefaultAttributes(): array
$attributes['data-owner-id'] = $ownerFields['ID'];
$attributes['data-owner-class'] = $ownerFields['Class'];
$attributes['data-owner-relation'] = $ownerFields['Relation'];
$attributes['data-exclude-linktext-field'] = $this->getExcludeLinkTextField();
return $attributes;
}

Expand All @@ -62,6 +63,7 @@ public function getSchemaDataDefaults()
$data['ownerID'] = $ownerFields['ID'];
$data['ownerClass'] = $ownerFields['Class'];
$data['ownerRelation'] = $ownerFields['Relation'];
$data['excludeLinkTextField'] = $this->getExcludeLinkTextField();
return $data;
}

Expand Down
2 changes: 2 additions & 0 deletions src/Form/MultiLinkField.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public function getSchemaDataDefaults()
$data['ownerID'] = $ownerFields['ID'];
$data['ownerClass'] = $ownerFields['Class'];
$data['ownerRelation'] = $ownerFields['Relation'];
$data['excludeLinkTextField'] = $this->getExcludeLinkTextField();
return $data;
}

Expand All @@ -70,6 +71,7 @@ protected function getDefaultAttributes(): array
$attributes['data-owner-id'] = $ownerFields['ID'];
$attributes['data-owner-class'] = $ownerFields['Class'];
$attributes['data-owner-relation'] = $ownerFields['Relation'];
$attributes['data-exclude-linktext-field'] = $this->getExcludeLinkTextField();
return $attributes;
}

Expand Down
13 changes: 13 additions & 0 deletions src/Form/Traits/AllowedLinkClassesTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,19 @@ trait AllowedLinkClassesTrait
{
private array $allowed_types = [];

private bool $excludeLinkTextField = false;

public function setExcludeLinkTextField(bool $include): static
{
$this->excludeLinkTextField = $include;
return $this;
}

public function getExcludeLinkTextField(): bool
{
return $this->excludeLinkTextField;
}

/**
* Set allowed types for LinkField
* @param string[] $types
Expand Down
49 changes: 47 additions & 2 deletions tests/php/Controllers/LinkFieldControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@

namespace SilverStripe\LinkField\Tests\Controllers;

use SilverStripe\CMS\Model\SiteTree;
use ReflectionMethod;
use SilverStripe\Dev\FunctionalTest;
use SilverStripe\LinkField\Tests\Controllers\LinkFieldControllerTest\TestPhoneLink;
use SilverStripe\Core\Config\Config;
use SilverStripe\Security\SecurityToken;
use SilverStripe\Control\HTTPRequest;
use SilverStripe\Control\Session;
use SilverStripe\LinkField\Controllers\LinkFieldController;
use SilverStripe\LinkField\Tests\Models\LinkTest\LinkOwner;

class LinkFieldControllerTest extends FunctionalTest
Expand Down Expand Up @@ -156,6 +157,50 @@ public function provideLinkFormGetSchema(): array
];
}

/**
* @dataProvider provideExcludeLinkTextField
*/
public function testExcludeLinkTextField(bool $excludeLinkTextField): void
{
$owner = $this->getFixtureLinkOwner();
$itemID = $this->getID('existing');
$vars = [
'ownerID' => $owner->ID,
'ownerClass' => $owner->ClassName,
'ownerRelation' => 'Link',
];
if ($excludeLinkTextField) {
$vars['excludeLinkTextField'] = true;
}
// Build request and controller to get the scaffolded form
$request = new HTTPRequest('GET', 'linkForm/' . $itemID, getVars: $vars);
$request->setSession(new Session([]));
$controller = new LinkFieldController();
$reflectionFindAction = new ReflectionMethod($controller, 'findAction');
$reflectionFindAction->setAccessible(true);
$reflectionFindAction->invoke($controller, $request);
$controller->setRequest($request);
$form = $controller->linkForm();
// Check if the field is there or not
if ($excludeLinkTextField) {
$this->assertNull($form->Fields()->dataFieldByName('LinkText'));
} else {
$this->assertNotNull($form->Fields()->dataFieldByName('LinkText'));
}
}

public function provideExcludeLinkTextField(): array
{
return [
'exclude field' => [
'excludeLinkTextField' => true,
],
'dont exclude field' => [
'excludeLinkTextField' => false,
],
];
}

/**
* @dataProvider provideLinkFormPost
*/
Expand Down

0 comments on commit 04ae65c

Please sign in to comment.