Server IP : 80.87.202.40 / Your IP : 216.73.216.169 Web Server : Apache System : Linux rospirotorg.ru 5.14.0-539.el9.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Dec 5 22:26:13 UTC 2024 x86_64 User : bitrix ( 600) PHP Version : 8.2.27 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /home/bitrix/ext_www/ilovecveti.ru/bitrix/js/fileman/userfield/address_widget/src/view/ |
Upload File : |
import { Address as AddressEntity, AddressStringConverter, AddressType, ControlMode, Format } from 'location.core'; import { Address as AddressWidget, AutocompleteFeature, Factory, State } from 'location.widget'; import { Dom, Event, Loc, Tag, Text } from 'main.core'; import { EventEmitter } from 'main.core.events'; import type { EditEntryProps } from './editentryprops'; export class EditEntry extends EventEmitter { #widget: AddressWidget; #nodes: { name: string, node: Element } = {}; #wrapper: Element; #address: AddressEntity = null; #fieldName: string; #fieldFormName: string; #showMap: boolean = true; #enableRemoveButton: boolean = false; #isCompactMode: boolean = false; #initialAddressId: ?number = null; #areDetailsShown: boolean = false; #isLoading: boolean = false; #isDropdownLoading: boolean = false; #isDestroyed: boolean = false; #showDetailsToggle: boolean = true; static onRemoveInputButtonClickedEvent = 'onRemoveInputButtonClicked'; constructor(props: EditEntryProps) { super(); this.setEventNamespace('Fileman.EditEntry'); this.#wrapper = props.wrapper; this.#fieldName = props.fieldName; this.#fieldFormName = props.fieldFormName; this.#enableRemoveButton = props.enableRemoveButton; this.#initialAddressId = props.initialAddressId; this.#showMap = props.showMap; this.#showDetailsToggle = Boolean(props.showDetailsToggle ?? true); if (props.address) { this.#address = props.address; } if (props.isCompactMode) { this.#isCompactMode = props.isCompactMode; } } layout(): Element { const factory = new Factory(); this.#widget = factory.createAddressWidget({ address: this.#address, mode: ControlMode.edit, popupOptions: { offsetLeft: 14, }, popupBindOptions: { forceBindPosition: true, position: 'right', }, mapBehavior: 'auto', useFeatures: { fields: true, map: this.#showMap, autocomplete: true, }, }); this.#nodes.userInput = Tag.render`<input type="text" class="ui-ctl-element" />`; this.#nodes.fieldsContainer = Tag.render`<div class="location-fields-control-block"></div>`; if (this.#showDetailsToggle) { this.#nodes.detailsToggle = Tag.render`<span class="ui-link ui-link-secondary address-control-mode-switch">${Loc.getMessage( 'ADDRESS_USERFIELD_DETAILS')}</span>`; Event.bind(this.#nodes.detailsToggle, 'click', this.onDetailsToggleClick.bind(this)); } let inputValue = this.getInitialAddressFieldValue(); this.#nodes.fieldValueInput = Tag.render`<input type="hidden" name="${this.#fieldFormName}" value="${inputValue}" />`; this.#nodes.inputIcon = Tag.render`<button type="button" class="ui-ctl-after ui-ctl-icon-clear"></button>`; Event.bind(this.#nodes.inputIcon, 'click', this.onInputIconClick.bind(this)); this.#widget.subscribeOnAddressChangedEvent(this.onAddressChanged.bind(this)); this.#widget.subscribeOnStateChangedEvent(this.onWidgetStateChangedEvent.bind(this)); this.#widget.subscribeOnFeatureEvent(this.onFeatureEvent.bind(this)); this.#nodes.entryWrapper = Tag.render` <div class="edit-entry-input-wrapper"> <div class="fields address field-item edit ui-ctl ui-ctl-after-icon ${this.getUserInputSizeClass()}"> ${this.#nodes.userInput} ${this.#nodes.fieldsContainer} ${this.#nodes.inputIcon} </div> </div> `; // a workaround for bizproc conditionals; their conditionals popup seems to use the topmost <input>'s value const hiddenFormattedInputValue = this.#address ? this.getRawValueForHiddenFormattedInput(this.#address) : ''; this.#nodes.hiddenFormattedAddressInput = Tag.render`<input type="hidden" name="${this.#fieldName}_formatted" value="${hiddenFormattedInputValue}" />`; // a flag used to identify values set manually by the user const manualEditFlagNode = Tag.render`<input type="hidden" name="${this.#fieldName}_manual_edit" value="Y">`; this.#nodes.layout = Tag.render` <div class="edit-entry-layout-wrapper ${this.getLayoutSizeClass()}"> ${this.#getAddressControlSwitchContainer()} ${this.#nodes.hiddenFormattedAddressInput} ${this.#nodes.entryWrapper} ${manualEditFlagNode} </div> `; if (this.#enableRemoveButton) { Dom.append(this.getRemoveInputButton(this.#nodes.layout), this.#nodes.entryWrapper); } Dom.append(this.#nodes.fieldValueInput, this.#nodes.layout); this.#widget.render({ inputNode: this.#nodes.userInput, mapBindElement: this.#wrapper, controlWrapper: this.#nodes.layout, fieldsContainer: this.#nodes.fieldsContainer, }); return this.#nodes.layout; } #getAddressControlSwitchContainer(): ?HTMLElement { if (!this.#showDetailsToggle) { return null; } return Tag.render` <div class="address-control-mode-switch-wrapper"> ${this.#nodes.detailsToggle} </div> `; } getUserInputSizeClass(): string { return this.#isCompactMode ? 'ui-ctl-wd' : 'ui-ctl-w100'; } getLayoutSizeClass(): string { return this.#isCompactMode ? 'compact' : ''; } getRemoveInputButton(layout: Element) { const removeInputButton = Tag.render` <span class="uf-address-search-input-remove"></span> `; Event.bind(removeInputButton, 'click', (event) => { this.emit(EditEntry.onRemoveInputButtonClickedEvent); }); return removeInputButton; } destroy() { if (!this.#nodes.layout) { return; } if (this.#widget) { this.#widget.destroy(); } if (this.#address && this.#address.id > 0) { Dom.clean(this.#nodes.layout); const input = Tag.render`<input type="hidden" name="${this.#fieldFormName}" value="${this.#address.id}_del" />`; Dom.append(input, this.#nodes.layout); this.emitFieldChangedEvent(); } else { Dom.remove(this.#nodes.layout); } this.#isDestroyed = true; } isDestroyed(): boolean { return this.#isDestroyed; } onAddressChanged(event) { const initialAddressId = parseInt(this.#initialAddressId); /** @type {AddressEntity} */ const address = event.data.address; if (!address) { return; } // when we clear the input, the address' id becomes 0, and because of it a new address is created upon // saving. we can set the address's id to the old id to edit the old address instead if (initialAddressId && parseInt(address.id) !== initialAddressId) { address.id = initialAddressId; } this.#nodes.fieldValueInput.value = this.getChangedAddressFieldValue(address); this.#nodes.hiddenFormattedAddressInput.value = this.getRawValueForHiddenFormattedInput(address); this.emitFieldChangedEvent(); } onWidgetStateChangedEvent(event) { const state = event.data.state; this.#isLoading = (state === State.DATA_LOADING); this.refreshInputIcon(); } onFeatureEvent(event) { if (event.data.feature instanceof AutocompleteFeature) { this.#isDropdownLoading = (event.data.eventCode === AutocompleteFeature.searchStartedEvent); this.refreshInputIcon(); } } isInputLoading(): boolean { return this.#isLoading || this.#isDropdownLoading; } refreshInputIcon() { if (!this.#nodes.inputIcon) { return; } if (this.isInputLoading()) { Dom.removeClass(this.#nodes.inputIcon, 'ui-ctl-icon-clear'); Dom.addClass(this.#nodes.inputIcon, 'ui-ctl-icon-loader'); } else { Dom.removeClass(this.#nodes.inputIcon, 'ui-ctl-icon-loader'); Dom.addClass(this.#nodes.inputIcon, 'ui-ctl-icon-clear'); } } getInitialAddressFieldValue(): string { let inputValue = ''; if (this.#address?.id == 0) { if (this.#address.location) { // JSON has probably been passed as the component's value; we need to create a new address inputValue = Text.encode(this.#address.toJson()); } else { // for compatibility with the format used before the switch to location module's addresses inputValue = `${this.#address.getFieldValue(AddressType.ADDRESS_LINE_2)}|${this.#address.latitude};${this.#address.longitude}`; } } else if (this.#address?.id > 0) { inputValue = `${this.getFormattedAddress(this.#address)}|${this.#address.latitude};${this.#address.longitude}|${this.#address.id}`; } return inputValue; } getChangedAddressFieldValue(address: AddressEntity): string { return address.toJson(); } getFormattedAddress(address: AddressEntity): string { const format = new Format(JSON.parse(BX.message('LOCATION_WIDGET_DEFAULT_FORMAT'))); return address.toString(format, AddressStringConverter.STRATEGY_TYPE_TEMPLATE_COMMA) ?? ''; } getRawValueForHiddenFormattedInput(address: AddressEntity): string { const formattedAddress = this.getFormattedAddress(address); if ( (parseInt(address.latitude) !== 0 || parseInt(address.longitude) !== 0) && (address.latitude !== '' && address.longitude !== '') ) { return `${formattedAddress}|${address.latitude};${address.longitude}`; } return formattedAddress; } onInputIconClick() { if (this.isInputLoading()) { return; } this.#nodes.userInput.focus(); this.#widget.resetView(); this.#widget.address = null; if (this.#address && this.#address.id > 0) { this.#nodes.fieldValueInput.value = this.#address.id + '_del'; } else { this.#nodes.fieldValueInput.value = ''; } this.emitFieldChangedEvent(); } onDetailsToggleClick() { if (!this.#nodes.fieldsContainer || !this.#nodes.detailsToggle) { return; } const fieldsContainer = this.#nodes.fieldsContainer; const detailsToggle = this.#nodes.detailsToggle; if (this.#areDetailsShown && Dom.hasClass(fieldsContainer, 'visible')) { Dom.removeClass(fieldsContainer, 'visible'); detailsToggle.innerText = Loc.getMessage('ADDRESS_USERFIELD_DETAILS'); } else { Dom.addClass(fieldsContainer, 'visible'); detailsToggle.innerText = Loc.getMessage('ADDRESS_USERFIELD_NO_DETAILS'); } this.#areDetailsShown = !this.#areDetailsShown; } emitFieldChangedEvent() { BX.onCustomEvent(window, 'onUIEntityEditorUserFieldExternalChanged', [this.#fieldName]); BX.onCustomEvent(window, 'onCrmEntityEditorUserFieldExternalChanged', [this.#fieldName]); } }