michelson/dante-stories

View on GitHub
app/javascript/components/NewEditor.js

Summary

Maintainability
B
5 hrs
Test Coverage
import React from 'react';
import ReactDOM from "react-dom";
import Dante from 'Dante2'


import {DanteImagePopoverConfig} from 'Dante2/package/es/components/popovers/image.js'
import {DanteAnchorPopoverConfig} from 'Dante2/package/es/components/popovers/link.js'
import {DanteInlineTooltipConfig} from 'Dante2/package/es/components/popovers/addButton.js' //'Dante2/package/es/components/popovers/addButton.js'
import {DanteTooltipConfig} from 'Dante2/package/es/components/popovers/toolTip.js' //'Dante2/package/es/components/popovers/toolTip.js'
import {ImageBlockConfig} from 'Dante2/package/es/components/blocks/image.js'
import {EmbedBlockConfig} from 'Dante2/package/es/components/blocks/embed.js'
import {VideoBlockConfig} from 'Dante2/package/es/components/blocks/video.js'
import {PlaceholderBlockConfig} from 'Dante2/package/es/components/blocks/placeholder.js'
import {VideoRecorderBlockConfig} from 'Dante2/package/es/components/blocks/videoRecorder'
import {CodeBlockConfig} from 'Dante2/package/es/components/blocks/code'
import Prism from 'prismjs';
import {PrismDraftDecorator} from 'Dante2/package/es/components/decorators/prism'

import Link from 'Dante2/package/es/components/decorators/link'
import findEntities from 'Dante2/package/es/utils/find_entities'

import { CompositeDecorator } from 'draft-js'
import MultiDecorator from 'draft-js-multidecorators'



export default class NewEditor extends React.Component {


  saveMethod = (context, editorContent)=>{

    const text = context.getTextFromEditor(editorContent)    
    if(text === ""){
      return
    }

    $('[data-behavior="editor-message"]').text('Saving...');
     $.ajax({
        url: '/api' + $('.editor-form').attr('action'),
        dataType: "script",
        method: $('input[name="_method"]').val() || "POST",
        data: {
          post: {
            //title: $('#post_title').val(),
            body: JSON.stringify(editorContent),
            plain: context.getTextFromEditor(editorContent),
            all_tags: $('#post_all_tags').val()
          }
        },
        success: function() { 
          console.log('autosave successful'); 
        }
      });
  }

  tooltipsConfig = ()=>{
    return [ DanteImagePopoverConfig(),
             DanteAnchorPopoverConfig(),
             DanteInlineTooltipConfig(),
             DanteTooltipConfig()
            ]
  }

  decorators = (context)=>{
    return (context)=> {
      return new MultiDecorator([
        PrismDraftDecorator({
          prism: Prism,
          defaultSyntax: 'javascript'
        }),
        new CompositeDecorator(
          [{
            strategy: findEntities.bind(null, 'LINK', context),
            component: Link
          } ]
        )
      ])
      }
  }

  widgetsConfig = ()=>{
    return [ CodeBlockConfig(),
            ImageBlockConfig({
                options: {
                  upload_url: $('.editor-form').attr('action') + '/uploads',
                  image_caption_placeholder: "type a caption (optional)"
                }
            }), 
             EmbedBlockConfig({ options: {
                                      placeholder: "put an external link",
                                      endpoint: "/oembed?url="
                                    } 
                              }),
             VideoBlockConfig({ breakOnContinuous: true,
                                options: {
                                    placeholder: "put an external video link",
                                    endpoint: "/oembed?url=",
                                    caption: 'optional caption'
                                  } 
                                }),
             PlaceholderBlockConfig(),
             VideoRecorderBlockConfig({
                options: {
                  seconds_to_record: 20000,
                  upload_url: $('.editor-form').attr('action') + '/uploads',
                }
             })
           ]
  }

  // use this in case you want to convert
  /*
  save_handler = (context, content, cb)=>{
  
    const exportedStyles = context.editor.styleExporter(context.editor.getEditorState())

    let convertOptions = {

      styleToHTML: (style) => {
        if (style === 'BOLD') {
          return <b/>;
        }
        if (style === 'ITALIC') {
          return <i/>;
        }
        if (style.includes("CUSTOM")){
          const s = exportedStyles[style].style
          return <span style={s} />
        }
      },
      blockToHTML: (block, oo) => {
       
        if (block.type === "unstyled"){
          return <p class="graf graf--p"/>
        }
        if (block.type === "header-one"){
          return <h1 class="graf graf--h2"/>
        }
        if (block.type === "header-two"){
          return <h2 class="graf graf--h3"/>
        }
        if (block.type === "header-three"){
          return <h3 class="graf graf--h4"/>
        }
        if (block.type === "blockquote"){
          return <blockquote class="graf graf--blockquote"/>
        }
        if (block.type === "button" || block.type === "unsubscribe_button"){
          const {href, buttonStyle, containerStyle, label} = block.data
          return {start: `<div style="width: 100%; margin: 18px 0px 47px 0px">
                          <div 
                            style="${styleString(containerStyle)}">
                            <a href="${href}"
                              className="btn"
                              ref="btn"
                              style="${styleString(buttonStyle)}">`,
                  end: `</a>
                    </div>
                  </div>`}
        }
        if (block.type === "card"){
          return {
            start: `<div class="graf graf--figure">
                    <div style="width: 100%; height: 100px; margin: 18px 0px 47px">
                      <div class="signature">
                        <div>
                          <a href="#" contenteditable="false">
                            <img src="${block.data.image}">
                            <div></div>
                          </a>
                        </div>
                        <div class="text" 
                          style="color: rgb(153, 153, 153);
                                font-size: 12px; 
                                font-weight: bold">`,
                  end: `</div>
                      </div>
                    <div class="dante-clearfix"/>
                  </div>
                </div>`
          }
        }
        if (block.type === "jumbo"){
          return {
            start: `<div class="graf graf--jumbo">
                    <div class="jumbotron">
                      <h1>` ,
            end: `</h1>
                    </div>
                  </div>`
          }
        }
        if (block.type === "image"){
          const {width, height, ratio} = block.data.aspect_ratio
          const {url } = block.data
          return {
            start: `<figure class="graf graf--figure">
                    <div>
                      <div class="aspectRatioPlaceholder is-locked" style="max-width: 1000px; max-height: 723.558px;">
                        <div class="aspect-ratio-fill" 
                            style="padding-bottom: ${ratio}%;">
                        </div>

                        <img src="${url}" 
                          height=${height} 
                          width=${width} 
                          class="graf-image" 
                          contenteditable="false"
                        >
                      <div>
                    </div>

                    </div>
                    <figcaption class="imageCaption">
                      <span>
                        <span data-text="true">`,
            end: `</span>
                      </span>
                    </figcaption>
                    </div>
                  </figure>`
          }
        }
        if (block.type === "column"){
          return <div class={`graf graf--column ${block.data.className}`}/>
        }
        if (block.type === "footer"){
          
          return {
                  start:`<div class="graf graf--figure"><div ><hr/><p>`,
                  end: `</p></div></div>`
                }
        }

        if(block.type === "embed"){
          if(!block.data.embed_data)
            return

          let data = null

          // due to a bug in empbed component
          if(typeof(block.data.embed_data.toJS) === "function"){
            data = block.data.embed_data.toJS()  
          } else {
            data = block.data.embed_data
          }
          
          if( data ){
            return <div class="graf graf--mixtapeEmbed">
                    <span>
                      <a target="_blank" class="js-mixtapeImage mixtapeImage" 
                        href={block.data.provisory_text} 
                        style={{backgroundImage: `url(${data.images[0].url})` }}>
                      </a>
                      <a class="markup--anchor markup--mixtapeEmbed-anchor" 
                        target="_blank" 
                        href={block.data.provisory_text}>
                        <strong class="markup--strong markup--mixtapeEmbed-strong">
                          {data.title}
                        </strong>
                        <em class="markup--em markup--mixtapeEmbed-em">
                          {data.description}
                        </em>
                      </a>
                      {data.provider_url}
                    </span>
                  </div>
          } else{
            <p/>
          }
        }
        if ("atomic"){
          return <p/>
        }

        if (block.type === 'PARAGRAPH') {
          return <p />;
        }
      },
      entityToHTML: (entity, originalText) => {
        if (entity.type === 'LINK') {
          return <a href={entity.data.url}>{originalText}</a>;
        }
        return originalText;
      }
    }

    let html3 = convertToHTML(convertOptions)(context.editorState().getCurrentContent())
   
    const serialized = JSON.stringify(content)
    const plain = context.getTextFromEditor(content)

    console.log(html3)
    if(cb)
      cb(html3, plain, serialized)
  }*/


  componentDidMount(){
    // preload tags if its edit.
    var tag_string = $('[data-behavior="tags"]').data("tags");
    
    //if(tag_string){
      var tags = tag_string.length > 0 ? tag_string.split(', ') : ['Story', 'Music'];

      var my_taggle = new Taggle('js-taggle', {
        duplicateTagClass: 'bounce',
        tags: tags,
        preserveCase: true
      });      
    //}


    // FIXME: is there a better way to do this?
    $('[data-behavior="publish-button"').hover(function() {
      $('#post_all_tags').val(my_taggle.getTagValues());
    });

    $("#post_picture").change(function(){
      const readURL = function(input) {
        if (input.files && input.files[0]) {
          var reader = new FileReader();
          reader.onload = function (e) {
            $('#image_preview').attr('src', e.target.result);
          }
          reader.readAsDataURL(input.files[0]);
        }
      }

      readURL(this);

      $('#existing-img-previewer').addClass('hidden');
      $('.picture_upload').addClass('active');
      $('.file-upload-previewer').removeClass('hidden');
    });

    /*** Form submit ***/
    $('[data-behavior="publish-button"]').on('click', function() {
      $('.editor-form').submit();
    });

    $('.inlineTooltip-button').on('click', (e)=>{
      e.preventDefault()
    })

    $('.publish-dropdown').on('click', function(e) {
      e.stopPropagation();
    });

  }

  initialContent = ()=>{
    return this.props.content ? JSON.parse(this.props.content) : null
  }

  render(){

    return <Dante data_storage= {
                    {
                      url: $('.editor-form').attr('action'),
                      save_handler: this.saveMethod
                    }

                  }
                  content={this.initialContent()}
                  tooltips={this.tooltipsConfig()}
                  widgets={this.widgetsConfig()}
                  decorators={ (context)=> {
                    return new MultiDecorator([
                      PrismDraftDecorator({prism: Prism }),
                      new CompositeDecorator(
                        [{
                          strategy: findEntities.bind(null, 'LINK', context),
                          component: Link
                        } ]
                      )
                    ])
                    }
                  }
            />
  }
}