Sindbad~EG File Manager

Current Path : /var/www/html/taet.readinessglobal.com/wp-content/plugins/tockify-events-calendar/js/src/
Upload File :
Current File : /var/www/html/taet.readinessglobal.com/wp-content/plugins/tockify-events-calendar/js/src/block.jsx

// import gutenberg-supplied react elements
// noinspection NpmUsedModulesInstalled
import {__} from 'wp.i18n';
// noinspection NpmUsedModulesInstalled
import {registerBlockType} from 'wp.blocks';
// noinspection NpmUsedModulesInstalled
import {
  Button,
  ExternalLink,
  PanelBody,
  PanelRow,
  RangeControl,
  ResizableBox,
  SelectControl,
  Toolbar
} from 'wp.components';
// noinspection NpmUsedModulesInstalled
import {select} from 'wp.data';
// noinspection NpmUsedModulesInstalled
import {Component, Fragment, render} from 'wp.element';
// noinspection NpmUsedModulesInstalled
import {BlockAlignmentToolbar, BlockControls, InspectorAdvancedControls, InspectorControls} from './compat';


// https://react-select.com
import CreatableSelect from 'react-select/creatable';
import classnames from 'classnames';

import './tockifyBlocks.scss';
import {TockifyIcon} from './icon';
import {openFullScreen} from "./overlay";
import {updateCalendarSelect} from "./styler";
import {attributesDescriptor, getCoreEmbedCode, getEmbedCode} from "./versions/v2";
import * as v1 from "./versions/v1";

/* load any translations */
//setLocaleData(window['tockify_gutenberg'].localeData, 'tockify-events-calendar');

/**
 * @param align - gutenberg alignment value
 * @returns boolean whether or not to support resizing for this align value
 */
const getResizable = align => {
  const {isViewportMatch} = select('core/viewport');
  const isLargeViewport = isViewportMatch('>= large');
  return align && ['wide', 'full'].indexOf(align) === -1 && isLargeViewport;
};

/**
 * helper - reloads calendar after delay in case of dom render slowness (who knows where this will run).
 * @param ms - how long to wait
 * @returns
 */
const loadDeclaredAfter = ms => setTimeout(() => window._tkf.loadDeclaredCalendars(), ms);

/**
 * merges modified attributes into properties without breaking immutability
 * @param props
 * @param modifiedAttrs
 */
const mergeAttrs = (props, modifiedAttrs) => {
  const attributes = Object.assign({}, props.attributes, modifiedAttrs);
  return Object.assign({}, props, {attributes});
};

// Note: to use localhost embed you also need to change URL in scripts.php
const tkfBase = "https://tockify.com";
const apiBase = tkfBase;

let calOptions = [];
let tagOptions = [];
let calControl;

/**
 * get our calendars (if tockify cookie is set)
 */
const updateCalendars = () => {
  fetch(apiBase + '/api2/calendars?client=wp', {credentials: 'include'}).then(response => {
    response.json().then(json => {
      const calOpts = [];
      json.filter(cal => cal.status.name === 'online')
        .forEach(cal => calOpts.push({
          label: cal.name,
          value: cal.name,
          usingFreePlan: cal.effectiveFeatureLevel === 0,
          canonicalHost: cal.effectiveFeatureLevel === 200 ? cal.canonicalHost : ''
        }));
      calOpts.push({label: 'Tockify Demo', value: 'spirited'});
      calOptions = calOpts;

      if (calControl) {
        calControl.setCalOptions(calOpts);
      }
    });
  }).catch(e => {
    console.log("fetch calendars failed", e);
  });
};

// get available calendars early, so we know default calendar when editor is rendered
updateCalendars();


class CalControl extends Component {
  constructor(props) {
    super(props);
    this.state = {};
    calControl = this;
  }

  componentDidMount = () => {
    updateCalendars();
  };

  setCalOptions = (calOpts) => {
    this.setState({calOpts});
  };

  render = () => {
    const {
      attributes: className, calName, onChange
    } = this.props;
    const calOpts = this.state.calOpts || [];

    return <CreatableSelect
        isClearable
        className={'wp_tkf_calendar_select ' + className}
        placeholder='Calendar short name'
        defaultValue={
          calName ? calOpts.find(c => c.value === calName) || {label: calName, value: calName} : undefined
        }
        onChange={onChange}
        options={calOpts}
        formatCreateLabel={val => 'Use short name: ' + val}
        isValidNewOption={input => input.match(/^[\w\d.]+$/)}
        noOptionsMessage={() => 'Invalid short code'}
        onMenuOpen={() => updateCalendars()}
    />
  }
}

let tagControl;
let extrasControl;

const updateTagOptions = (calendar, clear) => {
  if (tagControl) {
    tagControl.fetchTagOptions(calendar, clear);
  }

  if (clear && extrasControl) {
    extrasControl.select.select.clearValue();
  }
};

/**
 * stateful wrapper around tag control to ensure it updates when tag options change
 */
class TagControl extends Component {
  constructor(props) {
    super(props);
    this.state = {tagOptions};
    tagControl = this;
  }

  componentDidMount = () => {
    this.fetchTagOptions(this.props.attributes.calendar);
  };

  creatableRef = undefined;

  fetchTagOptions = (calendar, clear) => {
    fetch(apiBase + '/api/tagoptions/' + calendar + '?client=wp').then(response => {
      response.json().then(json => {
        tagOptions = [];
        json.tags.forEach(t => {
          tagOptions.push({value: t.text, label: t.text});
        });
        this.setState({tagOptions});

        if (clear && this.creatableRef) {
          this.creatableRef.select.select.clearValue();
        }
      })
    }).catch(e => {
      console.log("fetch tagoptions failed", e);
    });
  };

  render = () => {
    const {
      attributes: {tags}, tockifyBlock, className
    } = this.props;
    const tagOpts = this.state.tagOptions;

    return <CreatableSelect
      ref={ref => { this.creatableRef = ref; }}
      isClearable
      isMulti
      className={className}
      defaultValue={tags ? tags.map(t => ({value: t, label: t})) : undefined}
      options={tagOpts}
      onChange={tagv => {
        tagv = tagv || []
        tockifyBlock.updatePreviewWith(this.props, {tags: tagv.length > 0 ? tagv.map(t => t.value) : undefined})
      } }
      placeholder='Enter or select tags..'
      noOptionsMessage={() => 'No pre-defined tags'}
      formatCreateLabel={val => "Add tag: " + val}
    />
  }
}

/**
 * Tockify Gutenberg Block
 */
class TockifyBlock extends Component {
  title = __('Tockify Calendar', 'tockify-events-calendar');
  icon = TockifyIcon;
  category = 'widgets';
  attributes = attributesDescriptor;
  keywords = [__('calendar'), __('event'), __('events')];

  /**
   * Updates the Tockify calendar preview outside of the Gutenberg/React lifecycle.
   */
  updatePreview = (props, e) => {
    if (e) e.preventDefault();

    const {setAttributes, clientId} = props;
    const tmpcal = props.attributes.tmpcal;

    if (tmpcal) {
      const blockScope = document.querySelector('[data-block="' + clientId + '"]');
      const previewEl = blockScope.querySelector('.wp_tkf_preview');

      if (previewEl) {
        while (previewEl.firstChild) {
          previewEl.removeChild(previewEl.firstChild);
        }

        const el = getCoreEmbedCode(mergeAttrs(props, {calendar: tmpcal}), true);
        setTimeout(() => {
          const newDiv = document.createElement('div');
          previewEl.appendChild(newDiv);
          render(el, newDiv);
          [50, 100, 300, 500, 1000, 1500, 2000].forEach(loadDeclaredAfter);
        }, 10);
      }

      setAttributes({calendar: tmpcal});
    }
  };

  openOverlay = (url, props, e) => {
    if (e) e.preventDefault();
    openFullScreen({url});
  };

  /**
   * helper to update the preview with new attributes and setAttributes (avoids races)
   */
  updatePreviewWith = (props, attrs, e) => {
    if (e) e.preventDefault();
    const {setAttributes} = props;
    setAttributes(attrs);
    setTimeout(() => this.updatePreview(mergeAttrs(props, attrs)), 100);
  };

  // noinspection JSUnusedGlobalSymbols
  /**
   * used by Built in Align Toolbar
   * @param attributes
   * @returns {{"data-align": *, "data-resized": boolean}}
   */
  getEditWrapperProps = (attributes) => {
    const {align, width} = attributes;
    if ('left' === align || 'center' === align || 'right' === align || 'wide' === align || 'full' === align) {
      return {'data-align': align, 'data-resized': !!width};
    }
  };

  /**
   *
   * @param props
   * @returns Editor form and preview DOM nodes.
   */
  renderEditor = (props) => {

    //so the preview comes back when you edit visually
    loadDeclaredAfter(200);

    const {
      attributes: {calendar, tmpcal, extras},
      setAttributes
    } = props;

    let usingFreePlan;
    let calname;
    if (typeof tmpcal !== 'undefined') {
      calname = tmpcal;

      const calOption = calOptions.find(c => c.value === calname);

      usingFreePlan = calOption && calOption.usingFreePlan;

      const canonicalHost = calOption ? calOption.canonicalHost : undefined;

      if (canonicalHost) {
        if (!extras || !extras.find(e => e.startsWith('canonicalHost='))) {
          const newExtras = extras ? [...extras] : [];
          newExtras.push('canonicalHost=https://' + canonicalHost);
          setAttributes({extras: newExtras});
          if (extrasControl) {
            extrasControl.select.select.setValue(newExtras.map(t => ({value: t, label: t})));
          }
        }
      }
    } else {
      calname = calendar;
      setAttributes({tmpcal: calname});
      updateTagOptions(calname);

      if (!calname) {
        if (calOptions.length > 1) {
          calname = calOptions[0].value;
          usingFreePlan = !!calOptions.find(c => c.value === calname && c.usingFreePlan)
        }
        setTimeout(() => {
          if (calOptions.length > 1) {
            calname = calOptions[0].value;
            this.updatePreviewWith(props, {calendar: calname, tmpcal: calname});
            updateTagOptions(calname);
          }
        }, 100);
      }
    }

    setTimeout(() => updateCalendarSelect('Calendar short name'), 100);

    const calChanged = (calendar) => {
      const cal = calendar ? calendar.value : '';
      this.updatePreviewWith(props, {calendar: cal, tmpcal: cal, tags: undefined, extras: undefined, maxEvents: 0});
      updateTagOptions(cal, true);
      setTimeout(() => updateCalendarSelect('Calendar short name'), 100);
    };

    // noinspection JSXNamespaceValidation
    return (<Fragment>
      <form onSubmit={e => this.updatePreview(props, e)}>
        <div style={{width: "40px", height: "40px", display: 'inline-block'}}>{TockifyIcon}</div>
        <CalControl
          {...props}
          className='wp_tkf_calendar_select'
          calName={calname}
          onChange={calChanged}
        />
      </form>

      {!calendar && <div className='wp_tkf_accountMessage'>You need a Tockify Calendar to use this block.&nbsp;
        <ExternalLink href={tkfBase}>You can get one here</ExternalLink></div>}

      {usingFreePlan && <div className='wp_tkf_accountMessage'>You are using the free version of Tockify.&nbsp;
        <ExternalLink href={tkfBase + '/i/site/paidPlanPicker'}>Upgrade</ExternalLink> to get all the features.
      </div>
      }

      {calname &&
      <div className='wp_tkf_preview'>
        <div> {
          getCoreEmbedCode(props, true)
        } </div>
      </div>}

    </Fragment>)
  };

  //editor view
  edit = (props) => {
    const {
      attributes: {view, align, component, width, calendar, maxEvents, extras},
      isSelected, toggleSelection
    } = props;

    const handleClassName = 'wp_tkf_resizable-box__handle';

    const isResizable = getResizable(align);

    const loggedIn = !!calOptions.find(co => co.value === calendar);

    const site = tkfBase + (loggedIn ? '/' : '/i/site/login?next=');
    const customizer = component === 'mini' ? 'upcomingCustomizer' : 'customizer';
    const editLink = calendar && `${site}e/${calendar}`;
    const customizeLink = calendar && `${site}i/${customizer}/${calendar}`;

    return (<Fragment>
        <BlockControls>
          <Toolbar>
            <BlockAlignmentToolbar
              value={align}
              onChange={newAlign => {
                 // newAlign = newAlign || 'wide';
                 const newIsResizable = getResizable(newAlign);
                 const attrMods = {align: newAlign};
                 if (newIsResizable !== isResizable) {
                   attrMods.width = newIsResizable ? 400 : undefined
                 }
                 this.updatePreviewWith(props, attrMods)
              }}
            />
          </Toolbar>
        </BlockControls>
        <InspectorControls>
          <PanelBody>

            <SelectControl
              label={__('Calendar Style:')}
              className={'wp_tkf_inspector_select'}
              value={component}
              onChange={(component) => {
                this.updatePreviewWith(props, {component, view: undefined});
              }}
              options={[
                {value: 'calendar', label: 'Full Calendar'},
                {value: 'mini', label: 'Mini Calendar'}
              ]}
            />

            {(component === 'calendar') && (
              <PanelRow>
                <SelectControl
                  label={__('Full Calendar Layout:')}
                  className='wp_tkf_inspector_select'
                  value={view}
                  onChange={(view) => {
                    this.updatePreviewWith(props, {view})
                  }}
                  options={[
                    {value: '', label: 'Default From Theme'},
                    {value: 'pinboard', label: 'Pinboard'},
                    {value: 'agenda', label: 'Agenda'},
                    {value: 'monthly', label: 'Monthly'},
                  ]}
                />
              </PanelRow>
            )}
            {(component === 'mini') && (
              <PanelRow>
                <SelectControl
                  label={__('Mini Calendar Layout:')}
                  className='wp_tkf_inspector_select'
                  value={view}
                  onChange={(view) => {
                  const attrs = {view};
                  if (!view) attrs.maxEvents = 0;
                  this.updatePreviewWith(props, attrs)
                }}
                  options={[
                  {value: '', label: 'Default From Theme'},
                  {value: 'both', label: 'Monthly and Agenda'},
                  {value: 'monthly', label: 'Monthly Only'},
                  {value: 'agenda', label: 'Agenda Only'}
                ]}
                />
              </PanelRow>
            )}

            {(component === 'mini') && (view === 'both' || view === 'agenda') && (
              <RangeControl
                label={__('Maximum events to show')}
                value={maxEvents || 3}
                onChange={ maxEvents => this.updatePreviewWith(props, {maxEvents})}
                min={ 1 }
                max={ 30 }
              />
            )}

            <label className='wp_tkf_name_label'>{__('Only show events with these tags:')}</label>
            <PanelRow className='wp_tkf_tag_select'>
              <TagControl
                {...props}
                className='wp_tkf_inspector_select'
                tockifyBlock={this}
              />
            </PanelRow>

            { calendar && calendar !== 'spirited' &&
            <PanelRow>
              <ExternalLink href={editLink}>Edit Calendar</ExternalLink>
            </PanelRow>}
            { calendar && calendar !== 'spirited' &&
            <PanelRow>
              <ExternalLink href={customizeLink}>Customize Calendar</ExternalLink>
            </PanelRow>}
            { // leave space for tags dropdown
              calendar && calendar === 'spirited' &&
              <div style={{height: '50px'}}/>
            }

            { false && calendar !== 'spirited' &&
            <PanelRow>
              <Button wype="button" isLarge isDefault
                      onClick={(e) => this.openOverlay(editLink, props, e)}>Edit Events</Button>
              <Button wype="button" isLarge isDefault
                      onClick={(e) => this.openOverlay(customizeLink, props, e)}>Customize Calendar</Button>
            </PanelRow>
            }

          </PanelBody>
        </InspectorControls>

        <InspectorAdvancedControls>
          <label className='wp_tkf_name_label'>{__('Extra Embed Attributes')}</label>
          <PanelRow className='wp_tkf_tag_select'>
            <CreatableSelect
              className='wp_tkf_inspector_select'
              ref={ref => { extrasControl = ref; }}
              isClearable
              isMulti
              defaultValue={extras ? extras.map(t => ({value: t, label: t})) : undefined}
              options={[]}
              onChange={extrav => {
                extrav = extrav || []
                this.updatePreviewWith(props, {extras: extrav.length > 0 ? extrav.map(t => t.value) : undefined})
              } }
              placeholder='Enter Attributes'
              formatCreateLabel={val => "Add attribute: " + val}
              isValidNewOption={input => input.match(/^[\w\d-]+=\S/)}
              noOptionsMessage={() => 'Enter name=value'}
            />
          </PanelRow>
        </InspectorAdvancedControls>

        <div className='wp_tkf_edit'>
          {
            isResizable && (
              <ResizableBox
                className={classnames( 'wp_tkf__resize-container', {'is-selected': isSelected} )}
                handleStyles={{}}
                handleClasses={{
                  top: classnames( handleClassName ),
                  right: classnames( handleClassName ),
                  bottom: classnames( handleClassName ),
                  left: classnames( handleClassName ),
                }}
                size={{ width }}
                //minHeight="50"
                minWidth='240'
                enable={{
                  top: false,
                  right: align !== 'right',
                  bottom: false,
                  left: align !== 'left',
                  topRight: false,
                  bottomRight: false,
                  bottomLeft: false,
                  topLeft: false,
                }}
                onResizeStop={(event, direction, elt, delta) => {
                  this.updatePreviewWith(props, {width: parseInt(width + delta.width, 10)});
                  toggleSelection(true);
                }}
                onResizeStart={() => {
                  toggleSelection(false);
                }}
              >
                {this.renderEditor(props)}
              </ResizableBox>)}
          {!isResizable && this.renderEditor(props)}
        </div>
      </Fragment>
    )
  };

  save = (props) => getEmbedCode(props);

  // Gutenberg saves block attributes in HTML comments.
  // It compares the saved output with save(props) from the current block version.
  // If they differ, it assumes the block is deprecated, and tries calling the deprecated save() functions.
  /*
   <!-- wp:tockify/tockify-events-calendar {"view":"pinboard","calendar":"wibble"} -->
   <div><div data-tockify-component="calendar" data-tockify-calendar="wibble" data-tockify-view="pinboard"></div></div>
   <!-- /wp:tockify/tockify-events-calendar -->
   */

  // https://wordpress.org/gutenberg/handbook/designers-developers/developers/block-api/block-deprecation/
  deprecated = [
    {
      attributes: v1.attributesDescriptor,
      save: (props) => {
        console.info("V1 save:", props); // info NOT removed by webpack
        return v1.getEmbedCode(props);
      }
    }
  ]
}

registerBlockType('tockify/tockify-events-calendar', new TockifyBlock());


Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists