ProShell v2.0
Dashboard
Server Info
Server: 158.106.128.192
PHP: 8.2.33
home
planet5
public_html
bansibaba.com
wp-includes
2026-09-16 12:25:38
Editing: sortable-list.jsx
Cancel
Save Changes
// External Dependencies import React, { PureComponent } from 'react'; import classnames from 'classnames'; import { Motion, spring } from 'react-motion'; import map from 'lodash/map'; import forEach from 'lodash/forEach'; import assign from 'lodash/assign'; import isUndefined from 'lodash/isUndefined'; import isNumber from 'lodash/isNumber'; import isEmpty from 'lodash/isEmpty'; import $ from 'jquery'; import set from 'lodash/set'; import get from 'lodash/get'; import has from 'lodash/has'; import noop from 'lodash/noop'; import defaults from 'lodash/defaults'; import clone from 'lodash/clone'; import ReactTooltip from 'react-tooltip'; // Internal Dependencies import { ETCoreButtonGroup, ETCoreButton, ETCoreInput } from '..'; import ETCoreIcon from '../../icon/icon'; import ETCoreSortableListItem from './sortable-list-item'; import ETDragDropContextWrapper from '../../hoc/drag-drop-context'; import Constants from '../../../constants/controls'; import './sortable-list.scss'; class ETCoreSortableList extends PureComponent { static defaultProps = { onEditingLink: noop, _onAddItem: noop, animation: true, linkSettingsShowIcon: true, }; nextDragID = -1; constructor(props) { super(props); let items = JSON.parse(this.props.value || '[]'); if (0 === items.length && ! this.props.allowEmpty) { const field_type = get(this.props, 'module.props.module.props.attrs.field_type', false); const checked = get(this.props, 'module.props.module.props.attrs.checkbox_checked', 'off'); let value = ''; if ('checkbox' === field_type) { value = get(this.props, 'module.props.module.props.attrs.field_title', ''); } items = [ { value, checked: 'on' === checked ? 1 : 0, dragID: this._nextDragID(), } ]; this.focusItemInput(); } else { forEach(items, item => item.dragID = this._nextDragID()); } this.state = { items: JSON.stringify(items), editing_link: false, }; this.emitChange(); } componentDidUpdate(prevProps) { const { value } = this.props; // update value in state when value changed (via props) by another component if (prevProps.value !== value && ! this.userUpdate) { this.setState({ items: value }); } this.userUpdate = false; ReactTooltip.rebuild(); } _nextDragID = () => this.nextDragID++; addItem(index, event, resetValue) { if (event) { event.preventDefault(); } const value = this.state.items || '[]'; const items = JSON.parse(value); const itemValue = items.length && false !== index && !resetValue ? items[index] : {}; const dragID = this._nextDragID(); const checked = 0; if (false !== index) { items.splice(index + 1, 0, { ...itemValue, dragID }); } else { items.push({ value: '', checked, dragID, }); } this.userUpdate = true; this.setState({ items: JSON.stringify(items) }); this.emitChange(); if (isNumber(index)) { this.focusItemInput(index + 1); this.props._onAddItem(index + 1); } else { this.focusItemInput(); this.props._onAddItem(items.length - 1); } } emitChange = () => setTimeout(() => this.props._onChange(this.props.name, this.state.items), 0); focusItemInput = index => { setTimeout(() => { const itemInputs = this.itemsList.querySelectorAll('.et-core-control-sortable-list__row input'); if (0 === itemInputs.length) { return; } if (false === index || isUndefined(index)) { index = itemInputs.length - 1; } const inputToFocus = itemInputs[index]; inputToFocus.focus(); }); }; moveItem = (sourceIndex, targetIndex) => { const items = JSON.parse(this.state.items); const sourceItem = items[sourceIndex]; items[sourceIndex] = items[targetIndex]; items[targetIndex] = sourceItem; this.userUpdate = true; this.setState({ items: JSON.stringify(items) }); this.emitChange(); }; editItem(index, event) { event.preventDefault(); this.props._onAddItem(index); } onChangeLinkSettings = (setting, value) => { const items = JSON.parse(this.state.items); set(items, setting, value); this.userUpdate = true; this.setState({ items: JSON.stringify(items) }); this.emitChange(); }; removeItem(index, event) { event.preventDefault(); let value = this.state.items || '[]'; let items = JSON.parse(value); items.splice(index, 1); if (0 === items.length && ! this.props.allowEmpty) { items = [ { value: '', checked: 0, dragID: 0, } ]; } this.userUpdate = true; this.setState({ items: JSON.stringify(items) }); this.emitChange(); } showLinkSettings(index, event) { if (! event.target) { // Closing Modal index = false; if (Constants.SORTABLE_LIST_LINK_SETTINGS_CLOSE === event.props.buttonName) { // Discard Changes let value = this.state.items || '[]'; let items = JSON.parse(value); items[this.state.editing_link] = this.link_settings_backup; this.setState({ items: JSON.stringify(items) }); this.emitChange(); } } else { // Opening Modal event.preventDefault(); let value = this.state.items || '[]'; let items = JSON.parse(value); this.link_settings_backup = clone(items[index]); defaults(this.link_settings_backup, {link_url: '', link_text: ''}); } const $body = (ET_Builder && ET_Builder.Frames.top.jQuery('body')) || jQuery('body'); $body.toggleClass('et-core-control-sortable-list-editing-link', false !== index); this.setState({ editing_link: index }); this.props.onEditingLink(false !== index); } updateItems(index, item, isChecked, event) { event.preventDefault(); let isClick = 'click' === event.type; let value = this.state.items || '[]'; let items = JSON.parse(value); let itemValue = isClick ? item.value : event.target.value; let isCheckbox = ! isUndefined(this.props.checkbox) && true === this.props.checkbox; if (isEmpty(items)) { items.push(item); } if (isClick && ! isCheckbox) { forEach(items, item => item.checked = 0); } assign(items[index], { value: itemValue, checked: isChecked ? 1 : 0, }); this.userUpdate = true; this.setState({ items: JSON.stringify(items) }); this.emitChange(); } _renderAddNewItemButton() { const addNewItem = this.addItem.bind(this, false, false); const defaultStyle = { size: 0, opacity: 0 }; const style = { size: spring(1, { stiffness: 300, damping: 20 }), opacity: spring(1, { stiffness: 300, damping: 20 }), }; return ( <span className='et-fb-item-button-wrap--add'> <Motion defaultStyle={defaultStyle} style={style}> {interpolatingStyles => { const style = { opacity: interpolatingStyles.opacity, transform: `scale( ${interpolatingStyles.size} )`, }; return ( <ETCoreButton round style={style} tooltip={this.props.tooltip} _onClick={addNewItem}> <ETCoreIcon size="14" icon="add" color="#FFFFFF"/> </ETCoreButton> ) }} </Motion> <label className="et-fb-form__label">{this.props.buttonLabel}</label> </span> ); } _renderItems() { let value = this.state.items || '[]'; let items = JSON.parse(value); let isRadio = ! isUndefined(this.props.radio) && true === this.props.radio; let isCheckbox = ! isUndefined(this.props.checkbox) && true === this.props.checkbox; let right_actions = this.props.right_actions; if (this.props.readonly && has(this, 'props.right_actions_readonly')) { right_actions = this.props.right_actions_readonly; } else if (this.props.readonly && ! right_actions) { right_actions = 'move'; } else if (! right_actions) { right_actions = 'move|copy|delete'; } return map(items, (item, key) => { let isChecked = 1 === item.checked; let itemClasses = classnames({ 'et-core-control-sortable-list__row': true, 'et-core-control-sortable-list__row--radio': isRadio, 'et-core-control-sortable-list__row--checkbox': isCheckbox, }); let checkClasses = classnames({ 'et-core-control-sortable-list__check': true, 'et-core-control-sortable-list--checked': isChecked, }); const onCheck = this.updateItems.bind(this, key, item, ! isChecked); const onChange = this.updateItems.bind(this, key, item, isChecked); const addItem = this.addItem.bind(this, key); const addNewItem = this.addItem.bind(this, key, false, true); const removeItem = this.removeItem.bind(this, key); const editItem = this.editItem.bind(this, key); const showLinkSettings = this.showLinkSettings.bind(this, key); const value = get(item, 'value', ''); const fieldId = get(item, 'field_id', ''); const fieldTitle = '' === get(item, 'field_title', '') ? fieldId : get(item, 'field_title', ''); const processedValue = '' === value ? fieldTitle : value; return ( <ETCoreSortableListItem classes={itemClasses} key={item.dragID} id={item.dragID} index={key} moveItem={this.moveItem} isCheckbox={isCheckbox} isRadio={isRadio} checkClasses={checkClasses} onCheck={onCheck} onChange={onChange} onAdd={addNewItem} onCopy={addItem} onDelete={removeItem} onSetting={editItem} onLink={showLinkSettings} value={processedValue} useInput={this.props.useInput || ! this.props.readonly} readonly={this.props.readonly} left_actions={this.props.left_actions} right_actions={right_actions} /> ); }); } _renderLinkSettings() { let value = this.state.items || '[]'; let items = JSON.parse(value); if (! items[this.state.editing_link]) { return false; } const item = items[this.state.editing_link]; const onClick = this.showLinkSettings.bind(this, this.state.editing_link); const defaultStyle = { size: .5, opacity: 0, }; const style = { size: this.props.animation ? spring(1, { stiffness: 300, damping: 20 }) : 1, opacity: this.props.animation ? spring(1, { stiffness: 300, damping: 20 }) : 1, }; return ( <Motion defaultStyle={defaultStyle} style={style}> {interpolatingStyles => <div className="et-core-control-sortable-list__link-settings" style={{opacity: interpolatingStyles.opacity, transform: `scale( ${interpolatingStyles.size} )`}}> <h4>{this.props.labels.link_settings}</h4> <div> <p className="et-fb-form__label">{this.props.labels.link_url}</p> <ETCoreInput className="et-fb-settings-option-input et-fb-settings-option-input--block" type="text" name={`${this.state.editing_link}.link_url`} value={item.link_url} _onChange={this.onChangeLinkSettings} /> </div> <div> <p className="et-fb-form__label">{this.props.labels.link_text}</p> <ETCoreInput className="et-fb-settings-option-input et-fb-settings-option-input--block" type="text" name={`${this.state.editing_link}.link_text`} value={item.link_text} _onChange={this.onChangeLinkSettings} /> </div> <ETCoreButtonGroup block> <ETCoreButton block danger buttonName={Constants.SORTABLE_LIST_LINK_SETTINGS_CLOSE} tooltip={this.props.labels.link_cancel} _onClick={onClick} > {this.props.linkSettingsShowIcon ? <ETCoreIcon icon="exit" color="#FFFFFF"/> : null} {this.props.linkSettingsShowIcon ? null : this.props.labels.link_cancel} </ETCoreButton> <ETCoreButton block success buttonName={Constants.SORTABLE_LIST_LINK_SETTINGS_SAVE} tooltip={this.props.labels.link_save} _onClick={onClick} > {this.props.linkSettingsShowIcon ? <ETCoreIcon icon="check" color="#FFFFFF"/> : null} {this.props.linkSettingsShowIcon ? null : this.props.labels.link_save} </ETCoreButton> </ETCoreButtonGroup> </div> } </Motion> ); } render() { let additional_attrs = this.props.additional_attrs ? this.props.additional_attrs : {}; let id = this.props.id; if (! id) { id = `et-fb-${this.props.name}`; } const editing_link = false !== this.state.editing_link; return ( <ETDragDropContextWrapper> <div className="et-core-control-sortable-list" ref={list => this.itemsList = list}> {this._renderItems()} {editing_link && this._renderLinkSettings()} <textarea value={this.state.items} name={this.props.name} id={id} onChange={noop} {...additional_attrs} /> {this.props.useAddNewButton && this._renderAddNewItemButton()} </div> </ETDragDropContextWrapper> ); } } export default ETCoreSortableList;
Upload Files
Cancel
Upload
Create New
Cancel
Create
Change Permissions
Cancel
Save
Change Date
Cancel
Save
Rename Item
Cancel
Save
Confirm Delete
Are you sure you want to delete the selected items?
Cancel
Delete