Skip to content

Commit

Permalink
feat: add support for Anchors, File links and better UX in the CMS.
Browse files Browse the repository at this point in the history
  • Loading branch information
wilr committed Jan 5, 2024
1 parent 347cc65 commit 09a192b
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 10 deletions.
6 changes: 6 additions & 0 deletions _config/menumanager.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
Name: menumanager
---
SilverStripe\Admin\LeftAndMain:
extra_requirements_javascript:
- 'heyday/silverstripe-menumanager:client/menu-manager.js'
90 changes: 90 additions & 0 deletions client/menu-manager.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
(function () {
const MenuManager = function (element) {
const type = element.querySelectorAll("[name=LinkType]");

const pageField = element.querySelector(
"#Form_ItemEditForm_PageID_Holder"
);
const fileField = element.querySelector(
"#Form_ItemEditForm_File_Holder"
);
const linkField = element.querySelector(
"#Form_ItemEditForm_Link_Holder"
);

const anchorField = element.querySelector(
"#Form_ItemEditForm_Anchor_Holder"
);

type.forEach((input) => {
input.addEventListener("change", (event) => {
const value = event.target.value;
if (value == "internal") {
if (pageField) pageField.style.display = "flex";
if (linkField) linkField.style.display = "none";
if (fileField) fileField.style.display = "none";
if (anchorField) anchorField.style.display = "flex";
} else if (value == "external") {
if (pageField) pageField.style.display = "none";
if (linkField) linkField.style.display = "flex";
if (fileField) fileField.style.display = "none";
if (anchorField) anchorField.style.display = "flex";
} else if (value == "file") {
if (pageField) pageField.style.display = "none";
if (linkField) linkField.style.display = "none";
if (fileField) fileField.style.display = "flex";
if (anchorField) anchorField.style.display = "none";
} else {
if (pageField) pageField.style.display = "none";
if (linkField) linkField.style.display = "none";
if (fileField) fileField.style.display = "none";
if (anchorField) anchorField.style.display = "none";
}
});
});

// set the initial state
type.forEach((input) => {
if (input.checked) {
input.dispatchEvent(new Event("change"));
}
});
};

const startObserving = (domNode, classToLookFor, callback) => {
const observer = new MutationObserver((mutations) => {
mutations.forEach(function (mutation) {
const elementAdded = document.body.querySelector(
"." + classToLookFor + ":not(.menu-manager-loaded)"
);

if (elementAdded) {
elementAdded.classList.add("menu-manager-loaded");

callback(elementAdded);
}
});
});

observer.observe(domNode, {
childList: true,
attributes: true,
characterData: true,
subtree: true,
});

return observer;
};

// if menu-manager-tabset already exists in the markup, add the menu manager
// functionality to it
const menuManagerTabset = document.querySelector(".menu-manager-tabset");

if (menuManagerTabset) {
new MenuManager(menuManagerTabset);
}

startObserving(document.body, "menu-manager-tabset", (element) => {
new MenuManager(element);
});
})();
10 changes: 6 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@
"description": "Allows complex menu management to be handled through the CMS when a simple tree structure is not enough.",
"license": "MIT",
"require": {
"silverstripe/framework": "^5",
"silverstripe/admin": "^2.0.0-beta1",
"symbiote/silverstripe-gridfieldextensions": "^4.0.0-beta1"
"silverstripe/cms": "^5",
"symbiote/silverstripe-gridfieldextensions": "^4.0"
},
"require-dev": {
"squizlabs/php_codesniffer": "^3.7.2"
Expand All @@ -17,7 +16,10 @@
}
},
"extra": {
"dev-main": "4.0.x-dev"
"dev-main": "4.0.x-dev",
"expose": [
"client/"
]
},
"minimum-stability": "dev",
"prefer-stable": true,
Expand Down
58 changes: 52 additions & 6 deletions src/MenuItem.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@

namespace Heyday\MenuManager;

use SilverStripe\AssetAdmin\Forms\UploadField;
use SilverStripe\Assets\File;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\Forms\CheckboxField;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\OptionsetField;
use SilverStripe\Forms\TabSet;
use SilverStripe\Forms\TextField;
use SilverStripe\Forms\TreeDropdownField;
Expand All @@ -26,15 +29,17 @@ class MenuItem extends DataObject implements PermissionProvider
'MenuTitle' => 'Varchar(255)',
'Link' => 'Text',
'Sort' => 'Int',
'IsNewWindow' => 'Boolean'
'IsNewWindow' => 'Boolean',
'Anchor' => 'Varchar(255)',
];

/**
* @var array
*/
private static array $has_one = [
'Page' => SiteTree::class, // page the MenuItem refers to
'MenuSet' => MenuSet::class, // parent MenuSet
'MenuSet' => MenuSet::class,
'File' => File::class,
];

/**
Expand Down Expand Up @@ -136,11 +141,12 @@ public function canView($member = null): bool
*/
public function getCMSFields(): FieldList
{
$fields = FieldList::create(TabSet::create('Root'));
$fields = FieldList::create(TabSet::create('Root')->addExtraClass('menu-manager-tabset'));

$fields->addFieldsToTab(
'Root.main',
'Root.Main',
[
OptionsetField::create("LinkType", "", $this->getLinkTypes(), $this->getLinkType()),
TextField::create(
'MenuTitle',
_t(__CLASS__ . '.DB_MenuTitle', 'Link Label')
Expand All @@ -161,7 +167,6 @@ public function getCMSFields(): FieldList
'Leave blank if you wish to manually specify the URL below.'
)
),

TextField::create(
'Link',
_t(__CLASS__ . '.DB_Link', 'URL')
Expand All @@ -171,11 +176,15 @@ public function getCMSFields(): FieldList
'Enter a full URL to link to another website.'
)
),

TextField::create('Anchor', _t(__CLASS__ . '.DB_Anchor', 'Anchor')),
CheckboxField::create(
'IsNewWindow',
_t(__CLASS__ . '.DB_IsNewWindow', 'Open in a new window?')
),
UploadField::create(
'File',
_t(__CLASS__ . '.DB_File', 'File')
)->setFolderName('Uploads/menu-items'),
]
);

Expand Down Expand Up @@ -228,6 +237,7 @@ public function getTitle(): string
return $this->MenuTitle;
}


/**
* Checks to see if a page has been chosen and if so sets Link to null
* This means that used in conjunction with the __get method above
Expand All @@ -241,8 +251,30 @@ public function onBeforeWrite()
if ($this->PageID != 0) {
$this->Link = null;
}

if ($this->Anchor) {
// strip out any leading #s
$this->Anchor = preg_replace('/^#/', '', $this->Anchor);
}
}


public function getLinkType(): string
{
if ($this->FileID && $this->FileID > 0) {
$type = 'file';
} elseif ($this->PageID && $this->PageID > 0 || !$this->Link || $this->Link == '/') {
$type = 'internal';
} else {
$type = 'external';
}

$this->invokeWithExtensions('updateLinkType', $type);

return $type;
}


public function summaryFields()
{
return [
Expand All @@ -252,4 +284,18 @@ public function summaryFields()
'IsNewWindowNice' => _t(__CLASS__ . '.NewTab', 'Opens in a new tab?'),
];
}


public function getLinkTypes(): array
{
$types = [
'internal' => _t(__CLASS__ .'.INTERNAL', 'Link to an internal page'),
'external' => _t(__CLASS__ .'.EXTERNAL', 'Link to an external page, email or phone number'),
'file' => _t(__CLASS__ .'.FILE', 'Link to a file'),
];

$this->invokeWithExtensions('updateLinkTypes', $types);

return $types;
}
}

0 comments on commit 09a192b

Please sign in to comment.