@plone/volto 14.2.1 → 14.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +33 -0
- package/README.md +1 -1
- package/locales/ca/LC_MESSAGES/volto.po +5 -0
- package/locales/ca.json +1 -1
- package/locales/de/LC_MESSAGES/volto.po +5 -0
- package/locales/de.json +1 -1
- package/locales/en/LC_MESSAGES/volto.po +5 -0
- package/locales/en.json +1 -1
- package/locales/es/LC_MESSAGES/volto.po +5 -0
- package/locales/es.json +1 -1
- package/locales/eu/LC_MESSAGES/volto.po +5 -0
- package/locales/eu.json +1 -1
- package/locales/fr/LC_MESSAGES/volto.po +5 -0
- package/locales/fr.json +1 -1
- package/locales/it/LC_MESSAGES/volto.po +5 -0
- package/locales/it.json +1 -1
- package/locales/ja/LC_MESSAGES/volto.po +5 -0
- package/locales/ja.json +1 -1
- package/locales/nl/LC_MESSAGES/volto.po +5 -0
- package/locales/nl.json +1 -1
- package/locales/pt/LC_MESSAGES/volto.po +5 -0
- package/locales/pt.json +1 -1
- package/locales/pt_BR/LC_MESSAGES/volto.po +5 -0
- package/locales/pt_BR.json +1 -1
- package/locales/ro/LC_MESSAGES/volto.po +5 -0
- package/locales/ro.json +1 -1
- package/locales/volto.pot +6 -1
- package/package.json +3 -3
- package/src/components/manage/Add/Add.jsx +14 -0
- package/src/components/manage/Contents/Contents.jsx +225 -220
- package/src/components/manage/Widgets/DatetimeWidget.jsx +2 -2
- package/src/components/manage/Widgets/FormFieldWrapper.jsx +14 -1
- package/src/components/theme/Anontools/Anontools.jsx +1 -1
- package/src/express-middleware/files.js +2 -3
- package/src/express-middleware/images.js +2 -4
- package/src/helpers/Api/APIResourceWithAuth.js +1 -7
- package/src/helpers/Content/Content.js +16 -0
- package/src/helpers/Content/Content.test.js +20 -1
- package/src/helpers/FormValidation/FormValidation.js +1 -1
- package/src/helpers/index.js +1 -0
- package/src/server.jsx +28 -0
- package/theme/themes/pastanaga/extras/contents.less +12 -0
- package/theme/themes/pastanaga/extras/widgets.less +12 -0
|
@@ -1491,236 +1491,241 @@ class Contents extends Component {
|
|
|
1491
1491
|
</Dropdown.Menu>
|
|
1492
1492
|
</Dropdown>
|
|
1493
1493
|
</Segment>
|
|
1494
|
-
<
|
|
1495
|
-
<Table
|
|
1496
|
-
<Table.
|
|
1497
|
-
<Table.
|
|
1498
|
-
<
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
icon={
|
|
1506
|
-
<Icon
|
|
1507
|
-
name={configurationSVG}
|
|
1508
|
-
size="24px"
|
|
1509
|
-
color="#826a6a"
|
|
1510
|
-
className="configuration-svg"
|
|
1511
|
-
/>
|
|
1512
|
-
}
|
|
1513
|
-
>
|
|
1514
|
-
<Dropdown.Menu>
|
|
1515
|
-
<Dropdown.Header
|
|
1516
|
-
content={this.props.intl.formatMessage(
|
|
1517
|
-
messages.rearrangeBy,
|
|
1518
|
-
)}
|
|
1519
|
-
/>
|
|
1520
|
-
{map(
|
|
1521
|
-
[
|
|
1522
|
-
'id',
|
|
1523
|
-
'sortable_title',
|
|
1524
|
-
'EffectiveDate',
|
|
1525
|
-
'CreationDate',
|
|
1526
|
-
'ModificationDate',
|
|
1527
|
-
'portal_type',
|
|
1528
|
-
],
|
|
1529
|
-
(index) => (
|
|
1530
|
-
<Dropdown.Item
|
|
1531
|
-
key={index}
|
|
1532
|
-
className={`sort_${index} icon-align`}
|
|
1533
|
-
>
|
|
1534
|
-
<Icon name={downKeySVG} size="24px" />
|
|
1535
|
-
<FormattedMessage
|
|
1536
|
-
id={Indexes[index].label}
|
|
1537
|
-
/>
|
|
1538
|
-
<Dropdown.Menu>
|
|
1539
|
-
<Dropdown.Item
|
|
1540
|
-
onClick={this.onSortItems}
|
|
1541
|
-
value={`${Indexes[index].sort_on}|ascending`}
|
|
1542
|
-
className={`sort_${Indexes[index].sort_on}_ascending icon-align`}
|
|
1543
|
-
>
|
|
1544
|
-
<Icon
|
|
1545
|
-
name={sortDownSVG}
|
|
1546
|
-
size="24px"
|
|
1547
|
-
/>{' '}
|
|
1548
|
-
<FormattedMessage
|
|
1549
|
-
id="Ascending"
|
|
1550
|
-
defaultMessage="Ascending"
|
|
1551
|
-
/>
|
|
1552
|
-
</Dropdown.Item>
|
|
1553
|
-
<Dropdown.Item
|
|
1554
|
-
onClick={this.onSortItems}
|
|
1555
|
-
value={`${Indexes[index].sort_on}|descending`}
|
|
1556
|
-
className={`sort_${Indexes[index].sort_on}_descending icon-align`}
|
|
1557
|
-
>
|
|
1558
|
-
<Icon
|
|
1559
|
-
name={sortUpSVG}
|
|
1560
|
-
size="24px"
|
|
1561
|
-
/>{' '}
|
|
1562
|
-
<FormattedMessage
|
|
1563
|
-
id="Descending"
|
|
1564
|
-
defaultMessage="Descending"
|
|
1565
|
-
/>
|
|
1566
|
-
</Dropdown.Item>
|
|
1567
|
-
</Dropdown.Menu>
|
|
1568
|
-
</Dropdown.Item>
|
|
1569
|
-
),
|
|
1494
|
+
<div className="contents-table-wrapper">
|
|
1495
|
+
<Table selectable compact singleLine attached>
|
|
1496
|
+
<Table.Header>
|
|
1497
|
+
<Table.Row>
|
|
1498
|
+
<Table.HeaderCell>
|
|
1499
|
+
<Dropdown
|
|
1500
|
+
item
|
|
1501
|
+
upward={false}
|
|
1502
|
+
className="sort-icon"
|
|
1503
|
+
aria-label={this.props.intl.formatMessage(
|
|
1504
|
+
messages.sort,
|
|
1570
1505
|
)}
|
|
1571
|
-
|
|
1572
|
-
</Dropdown>
|
|
1573
|
-
</Table.HeaderCell>
|
|
1574
|
-
<Table.HeaderCell>
|
|
1575
|
-
<Dropdown
|
|
1576
|
-
upward={false}
|
|
1577
|
-
trigger={
|
|
1578
|
-
<Icon
|
|
1579
|
-
name={
|
|
1580
|
-
this.state.selected.length === 0
|
|
1581
|
-
? checkboxUncheckedSVG
|
|
1582
|
-
: this.state.selected.length ===
|
|
1583
|
-
this.state.items.length
|
|
1584
|
-
? checkboxCheckedSVG
|
|
1585
|
-
: checkboxIndeterminateSVG
|
|
1586
|
-
}
|
|
1587
|
-
color={
|
|
1588
|
-
this.state.selected.length > 0
|
|
1589
|
-
? '#007eb1'
|
|
1590
|
-
: '#826a6a'
|
|
1591
|
-
}
|
|
1592
|
-
size="24px"
|
|
1593
|
-
/>
|
|
1594
|
-
}
|
|
1595
|
-
icon={null}
|
|
1596
|
-
>
|
|
1597
|
-
<Dropdown.Menu>
|
|
1598
|
-
<Dropdown.Header
|
|
1599
|
-
content={this.props.intl.formatMessage(
|
|
1600
|
-
messages.select,
|
|
1601
|
-
)}
|
|
1602
|
-
/>
|
|
1603
|
-
<Dropdown.Item onClick={this.onSelectAll}>
|
|
1506
|
+
icon={
|
|
1604
1507
|
<Icon
|
|
1605
|
-
name={
|
|
1606
|
-
color="#007eb1"
|
|
1508
|
+
name={configurationSVG}
|
|
1607
1509
|
size="24px"
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
id="All"
|
|
1611
|
-
defaultMessage="All"
|
|
1510
|
+
color="#826a6a"
|
|
1511
|
+
className="configuration-svg"
|
|
1612
1512
|
/>
|
|
1613
|
-
|
|
1614
|
-
|
|
1513
|
+
}
|
|
1514
|
+
>
|
|
1515
|
+
<Dropdown.Menu>
|
|
1516
|
+
<Dropdown.Header
|
|
1517
|
+
content={this.props.intl.formatMessage(
|
|
1518
|
+
messages.rearrangeBy,
|
|
1519
|
+
)}
|
|
1520
|
+
/>
|
|
1521
|
+
{map(
|
|
1522
|
+
[
|
|
1523
|
+
'id',
|
|
1524
|
+
'sortable_title',
|
|
1525
|
+
'EffectiveDate',
|
|
1526
|
+
'CreationDate',
|
|
1527
|
+
'ModificationDate',
|
|
1528
|
+
'portal_type',
|
|
1529
|
+
],
|
|
1530
|
+
(index) => (
|
|
1531
|
+
<Dropdown.Item
|
|
1532
|
+
key={index}
|
|
1533
|
+
className={`sort_${index} icon-align`}
|
|
1534
|
+
>
|
|
1535
|
+
<Icon name={downKeySVG} size="24px" />
|
|
1536
|
+
<FormattedMessage
|
|
1537
|
+
id={Indexes[index].label}
|
|
1538
|
+
/>
|
|
1539
|
+
<Dropdown.Menu>
|
|
1540
|
+
<Dropdown.Item
|
|
1541
|
+
onClick={this.onSortItems}
|
|
1542
|
+
value={`${Indexes[index].sort_on}|ascending`}
|
|
1543
|
+
className={`sort_${Indexes[index].sort_on}_ascending icon-align`}
|
|
1544
|
+
>
|
|
1545
|
+
<Icon
|
|
1546
|
+
name={sortDownSVG}
|
|
1547
|
+
size="24px"
|
|
1548
|
+
/>{' '}
|
|
1549
|
+
<FormattedMessage
|
|
1550
|
+
id="Ascending"
|
|
1551
|
+
defaultMessage="Ascending"
|
|
1552
|
+
/>
|
|
1553
|
+
</Dropdown.Item>
|
|
1554
|
+
<Dropdown.Item
|
|
1555
|
+
onClick={this.onSortItems}
|
|
1556
|
+
value={`${Indexes[index].sort_on}|descending`}
|
|
1557
|
+
className={`sort_${Indexes[index].sort_on}_descending icon-align`}
|
|
1558
|
+
>
|
|
1559
|
+
<Icon
|
|
1560
|
+
name={sortUpSVG}
|
|
1561
|
+
size="24px"
|
|
1562
|
+
/>{' '}
|
|
1563
|
+
<FormattedMessage
|
|
1564
|
+
id="Descending"
|
|
1565
|
+
defaultMessage="Descending"
|
|
1566
|
+
/>
|
|
1567
|
+
</Dropdown.Item>
|
|
1568
|
+
</Dropdown.Menu>
|
|
1569
|
+
</Dropdown.Item>
|
|
1570
|
+
),
|
|
1571
|
+
)}
|
|
1572
|
+
</Dropdown.Menu>
|
|
1573
|
+
</Dropdown>
|
|
1574
|
+
</Table.HeaderCell>
|
|
1575
|
+
<Table.HeaderCell>
|
|
1576
|
+
<Dropdown
|
|
1577
|
+
upward={false}
|
|
1578
|
+
trigger={
|
|
1615
1579
|
<Icon
|
|
1616
|
-
name={
|
|
1580
|
+
name={
|
|
1581
|
+
this.state.selected.length === 0
|
|
1582
|
+
? checkboxUncheckedSVG
|
|
1583
|
+
: this.state.selected.length ===
|
|
1584
|
+
this.state.items.length
|
|
1585
|
+
? checkboxCheckedSVG
|
|
1586
|
+
: checkboxIndeterminateSVG
|
|
1587
|
+
}
|
|
1588
|
+
color={
|
|
1589
|
+
this.state.selected.length > 0
|
|
1590
|
+
? '#007eb1'
|
|
1591
|
+
: '#826a6a'
|
|
1592
|
+
}
|
|
1617
1593
|
size="24px"
|
|
1618
|
-
/>{' '}
|
|
1619
|
-
<FormattedMessage
|
|
1620
|
-
id="None"
|
|
1621
|
-
defaultMessage="None"
|
|
1622
1594
|
/>
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
{
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1595
|
+
}
|
|
1596
|
+
icon={null}
|
|
1597
|
+
>
|
|
1598
|
+
<Dropdown.Menu>
|
|
1599
|
+
<Dropdown.Header
|
|
1600
|
+
content={this.props.intl.formatMessage(
|
|
1601
|
+
messages.select,
|
|
1602
|
+
)}
|
|
1603
|
+
/>
|
|
1604
|
+
<Dropdown.Item onClick={this.onSelectAll}>
|
|
1605
|
+
<Icon
|
|
1606
|
+
name={checkboxCheckedSVG}
|
|
1607
|
+
color="#007eb1"
|
|
1608
|
+
size="24px"
|
|
1609
|
+
/>{' '}
|
|
1610
|
+
<FormattedMessage
|
|
1611
|
+
id="All"
|
|
1612
|
+
defaultMessage="All"
|
|
1613
|
+
/>
|
|
1614
|
+
</Dropdown.Item>
|
|
1615
|
+
<Dropdown.Item onClick={this.onSelectNone}>
|
|
1616
|
+
<Icon
|
|
1617
|
+
name={checkboxUncheckedSVG}
|
|
1618
|
+
size="24px"
|
|
1619
|
+
/>{' '}
|
|
1620
|
+
<FormattedMessage
|
|
1621
|
+
id="None"
|
|
1622
|
+
defaultMessage="None"
|
|
1623
|
+
/>
|
|
1624
|
+
</Dropdown.Item>
|
|
1625
|
+
<Dropdown.Divider />
|
|
1626
|
+
<Dropdown.Header
|
|
1627
|
+
content={this.props.intl.formatMessage(
|
|
1628
|
+
messages.selected,
|
|
1629
|
+
{ count: this.state.selected.length },
|
|
1630
|
+
)}
|
|
1631
|
+
/>
|
|
1632
|
+
<Input
|
|
1633
|
+
icon={<Icon name={zoomSVG} size="24px" />}
|
|
1634
|
+
iconPosition="left"
|
|
1635
|
+
className="search"
|
|
1636
|
+
placeholder={this.props.intl.formatMessage(
|
|
1637
|
+
messages.filter,
|
|
1638
|
+
)}
|
|
1639
|
+
onChange={this.onChangeSelected}
|
|
1640
|
+
onClick={(e) => {
|
|
1641
|
+
e.preventDefault();
|
|
1642
|
+
e.stopPropagation();
|
|
1643
|
+
}}
|
|
1644
|
+
/>
|
|
1645
|
+
<Dropdown.Menu scrolling>
|
|
1646
|
+
{map(filteredItems, (item) => (
|
|
1647
|
+
<Dropdown.Item
|
|
1648
|
+
key={item}
|
|
1649
|
+
value={item}
|
|
1650
|
+
onClick={this.onDeselect}
|
|
1651
|
+
>
|
|
1652
|
+
<Icon
|
|
1653
|
+
name={deleteSVG}
|
|
1654
|
+
color="#e40166"
|
|
1655
|
+
size="24px"
|
|
1656
|
+
/>{' '}
|
|
1657
|
+
{this.getFieldById(item, 'title')}
|
|
1658
|
+
</Dropdown.Item>
|
|
1659
|
+
))}
|
|
1660
|
+
</Dropdown.Menu>
|
|
1659
1661
|
</Dropdown.Menu>
|
|
1660
|
-
</Dropdown
|
|
1661
|
-
</
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1662
|
+
</Dropdown>
|
|
1663
|
+
</Table.HeaderCell>
|
|
1664
|
+
<Table.HeaderCell
|
|
1665
|
+
width={Math.ceil(
|
|
1666
|
+
16 / this.state.index.selectedCount,
|
|
1667
|
+
)}
|
|
1668
|
+
>
|
|
1669
|
+
<FormattedMessage
|
|
1670
|
+
id="Title"
|
|
1671
|
+
defaultMessage="Title"
|
|
1672
|
+
/>
|
|
1673
|
+
</Table.HeaderCell>
|
|
1674
|
+
{map(
|
|
1675
|
+
this.state.index.order,
|
|
1676
|
+
(index, order) =>
|
|
1677
|
+
this.state.index.values[index].selected && (
|
|
1678
|
+
<ContentsIndexHeader
|
|
1679
|
+
key={index}
|
|
1680
|
+
width={Math.ceil(
|
|
1681
|
+
16 / this.state.index.selectedCount,
|
|
1682
|
+
)}
|
|
1683
|
+
label={
|
|
1684
|
+
this.state.index.values[index].label
|
|
1685
|
+
}
|
|
1686
|
+
order={order}
|
|
1687
|
+
onOrderIndex={this.onOrderIndex}
|
|
1688
|
+
/>
|
|
1689
|
+
),
|
|
1666
1690
|
)}
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1691
|
+
<Table.HeaderCell textAlign="right">
|
|
1692
|
+
<FormattedMessage
|
|
1693
|
+
id="Actions"
|
|
1694
|
+
defaultMessage="Actions"
|
|
1695
|
+
/>
|
|
1696
|
+
</Table.HeaderCell>
|
|
1697
|
+
</Table.Row>
|
|
1698
|
+
</Table.Header>
|
|
1699
|
+
<Table.Body>
|
|
1700
|
+
{this.state.items.map((item, order) => (
|
|
1701
|
+
<ContentsItem
|
|
1702
|
+
key={item['@id']}
|
|
1703
|
+
item={item}
|
|
1704
|
+
order={order}
|
|
1705
|
+
selected={
|
|
1706
|
+
indexOf(this.state.selected, item['@id']) !==
|
|
1707
|
+
-1
|
|
1708
|
+
}
|
|
1709
|
+
onClick={this.onSelect}
|
|
1710
|
+
indexes={filter(
|
|
1711
|
+
map(this.state.index.order, (index) => ({
|
|
1712
|
+
id: index,
|
|
1713
|
+
type: this.state.index.values[index].type,
|
|
1714
|
+
})),
|
|
1715
|
+
(index) =>
|
|
1716
|
+
this.state.index.values[index.id].selected,
|
|
1717
|
+
)}
|
|
1718
|
+
onCut={this.cut}
|
|
1719
|
+
onCopy={this.copy}
|
|
1720
|
+
onDelete={this.delete}
|
|
1721
|
+
onOrderItem={this.onOrderItem}
|
|
1722
|
+
onMoveToTop={this.onMoveToTop}
|
|
1723
|
+
onMoveToBottom={this.onMoveToBottom}
|
|
1692
1724
|
/>
|
|
1693
|
-
|
|
1694
|
-
</Table.
|
|
1695
|
-
</Table
|
|
1696
|
-
|
|
1697
|
-
{this.state.items.map((item, order) => (
|
|
1698
|
-
<ContentsItem
|
|
1699
|
-
key={item['@id']}
|
|
1700
|
-
item={item}
|
|
1701
|
-
order={order}
|
|
1702
|
-
selected={
|
|
1703
|
-
indexOf(this.state.selected, item['@id']) !== -1
|
|
1704
|
-
}
|
|
1705
|
-
onClick={this.onSelect}
|
|
1706
|
-
indexes={filter(
|
|
1707
|
-
map(this.state.index.order, (index) => ({
|
|
1708
|
-
id: index,
|
|
1709
|
-
type: this.state.index.values[index].type,
|
|
1710
|
-
})),
|
|
1711
|
-
(index) =>
|
|
1712
|
-
this.state.index.values[index.id].selected,
|
|
1713
|
-
)}
|
|
1714
|
-
onCut={this.cut}
|
|
1715
|
-
onCopy={this.copy}
|
|
1716
|
-
onDelete={this.delete}
|
|
1717
|
-
onOrderItem={this.onOrderItem}
|
|
1718
|
-
onMoveToTop={this.onMoveToTop}
|
|
1719
|
-
onMoveToBottom={this.onMoveToBottom}
|
|
1720
|
-
/>
|
|
1721
|
-
))}
|
|
1722
|
-
</Table.Body>
|
|
1723
|
-
</Table>
|
|
1725
|
+
))}
|
|
1726
|
+
</Table.Body>
|
|
1727
|
+
</Table>
|
|
1728
|
+
</div>
|
|
1724
1729
|
|
|
1725
1730
|
<div className="contents-pagination">
|
|
1726
1731
|
<Pagination
|
|
@@ -148,8 +148,8 @@ export class DatetimeWidgetComponent extends Component {
|
|
|
148
148
|
const moment = this.props.moment.default;
|
|
149
149
|
if (time) {
|
|
150
150
|
const base = (this.getInternalValue() || moment()).set({
|
|
151
|
-
hours: time
|
|
152
|
-
minutes: time
|
|
151
|
+
hours: time?.hours() ?? 0,
|
|
152
|
+
minutes: time?.minutes() ?? 0,
|
|
153
153
|
seconds: 0,
|
|
154
154
|
});
|
|
155
155
|
const dateValue = base.toISOString();
|
|
@@ -18,6 +18,10 @@ const messages = defineMessages({
|
|
|
18
18
|
id: 'Delete',
|
|
19
19
|
defaultMessage: 'Delete',
|
|
20
20
|
},
|
|
21
|
+
language_independent: {
|
|
22
|
+
id: 'Language independent field.',
|
|
23
|
+
defaultMessage: 'Language independent field.',
|
|
24
|
+
},
|
|
21
25
|
});
|
|
22
26
|
/**
|
|
23
27
|
* FormFieldWrapper component class.
|
|
@@ -85,6 +89,7 @@ class FormFieldWrapper extends Component {
|
|
|
85
89
|
onDelete,
|
|
86
90
|
intl,
|
|
87
91
|
noForInFieldLabel,
|
|
92
|
+
multilingual_options,
|
|
88
93
|
} = this.props;
|
|
89
94
|
const wdg = (
|
|
90
95
|
<>
|
|
@@ -107,6 +112,9 @@ class FormFieldWrapper extends Component {
|
|
|
107
112
|
description ? 'help' : '',
|
|
108
113
|
className,
|
|
109
114
|
`field-wrapper-${id}`,
|
|
115
|
+
multilingual_options?.language_independent
|
|
116
|
+
? 'language-independent-field'
|
|
117
|
+
: null,
|
|
110
118
|
)}
|
|
111
119
|
>
|
|
112
120
|
<Grid>
|
|
@@ -160,7 +168,12 @@ class FormFieldWrapper extends Component {
|
|
|
160
168
|
{description && (
|
|
161
169
|
<Grid.Row stretched>
|
|
162
170
|
<Grid.Column stretched width="12">
|
|
163
|
-
<p className="help">
|
|
171
|
+
<p className="help">
|
|
172
|
+
{this.props.multilingual_options
|
|
173
|
+
? `${intl.formatMessage(messages.language_independent)} `
|
|
174
|
+
: null}
|
|
175
|
+
{description}
|
|
176
|
+
</p>
|
|
164
177
|
</Grid.Column>
|
|
165
178
|
</Grid.Row>
|
|
166
179
|
)}
|
|
@@ -4,7 +4,6 @@ import { getAPIResourceWithAuth } from '@plone/volto/helpers';
|
|
|
4
4
|
const HEADERS = ['content-type', 'content-disposition', 'cache-control'];
|
|
5
5
|
|
|
6
6
|
function fileMiddleware(req, res, next) {
|
|
7
|
-
const { errorHandler } = req.app.locals;
|
|
8
7
|
getAPIResourceWithAuth(req)
|
|
9
8
|
.then((resource) => {
|
|
10
9
|
// Just forward the headers that we need
|
|
@@ -14,8 +13,8 @@ function fileMiddleware(req, res, next) {
|
|
|
14
13
|
}
|
|
15
14
|
});
|
|
16
15
|
res.send(resource.body);
|
|
17
|
-
}
|
|
18
|
-
.catch(
|
|
16
|
+
})
|
|
17
|
+
.catch(next);
|
|
19
18
|
}
|
|
20
19
|
|
|
21
20
|
export default function () {
|
|
@@ -4,7 +4,6 @@ import { getAPIResourceWithAuth } from '@plone/volto/helpers';
|
|
|
4
4
|
const HEADERS = ['content-type', 'content-disposition', 'cache-control'];
|
|
5
5
|
|
|
6
6
|
function imageMiddleware(req, res, next) {
|
|
7
|
-
const { errorHandler } = req.app.locals;
|
|
8
7
|
getAPIResourceWithAuth(req)
|
|
9
8
|
.then((resource) => {
|
|
10
9
|
// Just forward the headers that we need
|
|
@@ -13,10 +12,9 @@ function imageMiddleware(req, res, next) {
|
|
|
13
12
|
res.set(header, resource.headers[header]);
|
|
14
13
|
}
|
|
15
14
|
});
|
|
16
|
-
|
|
17
15
|
res.send(resource.body);
|
|
18
|
-
}
|
|
19
|
-
.catch(
|
|
16
|
+
})
|
|
17
|
+
.catch(next);
|
|
20
18
|
}
|
|
21
19
|
|
|
22
20
|
export default function () {
|
|
@@ -34,11 +34,5 @@ export const getAPIResourceWithAuth = (req) =>
|
|
|
34
34
|
if (authToken) {
|
|
35
35
|
request.set('Authorization', `Bearer ${authToken}`);
|
|
36
36
|
}
|
|
37
|
-
request.
|
|
38
|
-
if (error) {
|
|
39
|
-
reject(error);
|
|
40
|
-
} else {
|
|
41
|
-
resolve(res);
|
|
42
|
-
}
|
|
43
|
-
});
|
|
37
|
+
request.then(resolve).catch(reject);
|
|
44
38
|
});
|
|
@@ -63,3 +63,19 @@ export function getContentIcon(type, isFolderish) {
|
|
|
63
63
|
if (type in contentIcons) return contentIcons[type];
|
|
64
64
|
return isFolderish ? contentIcons.Folder : contentIcons.File;
|
|
65
65
|
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Get the language independent fields presents in a schema.
|
|
69
|
+
* @description Configurable in config
|
|
70
|
+
* @function getLanguageIndependentFields
|
|
71
|
+
* @param {string} schema content type JSON Schema serialization
|
|
72
|
+
* @returns {array} List of language independent fields
|
|
73
|
+
*/
|
|
74
|
+
export function getLanguageIndependentFields(schema) {
|
|
75
|
+
const { properties } = schema;
|
|
76
|
+
return Object.keys(properties).filter(
|
|
77
|
+
(field) =>
|
|
78
|
+
Object.keys(properties[field]).includes('multilingual_options') &&
|
|
79
|
+
properties[field]['multilingual_options']?.['language_independent'],
|
|
80
|
+
);
|
|
81
|
+
}
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
nestContent,
|
|
3
|
+
getContentIcon,
|
|
4
|
+
getLanguageIndependentFields,
|
|
5
|
+
} from './Content';
|
|
2
6
|
import contentExistingSVG from '@plone/volto/icons/content-existing.svg';
|
|
3
7
|
import linkSVG from '@plone/volto/icons/link.svg';
|
|
4
8
|
import calendarSVG from '@plone/volto/icons/calendar.svg';
|
|
@@ -77,4 +81,19 @@ describe('Content', () => {
|
|
|
77
81
|
expect(getContentIcon('Custom', false)).toBe(fileSVG);
|
|
78
82
|
});
|
|
79
83
|
});
|
|
84
|
+
|
|
85
|
+
describe('getLanguageIndependentFields', () => {
|
|
86
|
+
it('returns the language independenr field', () => {
|
|
87
|
+
const schema = {
|
|
88
|
+
properties: {
|
|
89
|
+
lif: {
|
|
90
|
+
multilingual_options: {
|
|
91
|
+
language_independent: true,
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
expect(getLanguageIndependentFields(schema)).toStrictEqual(['lif']);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
80
99
|
});
|
|
@@ -61,7 +61,7 @@ const widgetValidation = {
|
|
|
61
61
|
},
|
|
62
62
|
url: {
|
|
63
63
|
isValidURL: (urlValue, urlObj, intlFunc) => {
|
|
64
|
-
const urlRegex = /^(http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)?[a-z0-9]+([-.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)
|
|
64
|
+
const urlRegex = /^(http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)?[a-z0-9]+([-.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?|^((http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)?([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/gm;
|
|
65
65
|
const isValid = urlRegex.test(urlValue);
|
|
66
66
|
return !isValid ? intlFunc(messages.isValidURL) : null;
|
|
67
67
|
},
|