export default function insertAtomicBlock(editorState, data) {

  var contentState = editorState.getCurrentContent();
  var selectionState = editorState.getSelection();

  var afterRemoval = Modifier.removeRange(
    contentState,
    selectionState,
    'backward'
  );

  var targetSelection = afterRemoval.getSelectionAfter();
  var afterSplit = Modifier.splitBlock(afterRemoval, targetSelection);
  var insertionTarget = afterSplit.getSelectionAfter();

  var asMedia = Modifier.setBlockType(afterSplit, insertionTarget, 'atomic')

  var entityKey = Entity.create(
    'TOKEN',
    'IMMUTABLE',
    data,
  );

  var charData = CharacterMetadata.create({entity: entityKey});

  var fragmentArray = [
    new ContentBlock({
      key: genKey(),
      type: 'atomic',
      text: data.text || ' ',
      characterList: List(Repeat(charData, (data.text || ' ').length)),
      data,
    }),
    new ContentBlock({
      key: genKey(),
      type: 'unstyled',
      text: '',
      characterList: List(),
    }),
  ];

  var fragment = BlockMapBuilder.createFromArray(fragmentArray);

  var withMedia = Modifier.replaceWithFragment(
    asMedia,
    insertionTarget,
    fragment
  );

  var newContent = withMedia.merge({
    selectionBefore: selectionState,
    selectionAfter: withMedia.getSelectionAfter().set('hasFocus', true),
  });

  var editorState = EditorState.push(editorState, newContent, 'insert-fragment')

  return editorState
}
Ejemplo n.º 2
0
function insertDataBlock(editorState, data) {
  const contentState = editorState.getCurrentContent();
  const selectionState = editorState.getSelection();

  const afterRemoval = Modifier.removeRange(
    contentState,
    selectionState,
    "backward"
  );

  const targetSelection = afterRemoval.getSelectionAfter();
  const afterSplit = Modifier.splitBlock(afterRemoval, targetSelection);
  const insertionTarget = afterSplit.getSelectionAfter();

  const asAtomicBlock = Modifier.setBlockType(
    afterSplit,
    insertionTarget,
    "atomic"
  );

  const block = new ContentBlock({
    key: genKey(),
    type: "atomic",
    text: "",
    characterList: List(),
    data: new Map(data)
  });

  const fragmentArray = [
    block,
    new ContentBlock({
      key: genKey(),
      type: "unstyled",
      text: "",
      characterList: List()
    })
  ];

  const fragment = BlockMapBuilder.createFromArray(fragmentArray);

  const withAtomicBlock = Modifier.replaceWithFragment(
    asAtomicBlock,
    insertionTarget,
    fragment
  );

  const newContent = withAtomicBlock.merge({
    selectionBefore: selectionState,
    selectionAfter: withAtomicBlock.getSelectionAfter().set("hasFocus", true)
  });

  return EditorState.push(editorState, newContent, "insert-fragment");
}
Ejemplo n.º 3
0
function importFromProcess() {
    let imageEntityKey = Entity.create('image', 'IMMUTABLE', {
        imgData: {
            img: '//a.amap.com/lbs/static/md/process.png',
            url: '',
            newPage: false,
            width: 332
        }
    })
    let imageCharacterList = List('-'.split('').map(function () {
        return CharacterMetadata.create({
            entity: imageEntityKey
        })
    }))
    let imageBlock = new ContentBlock({
        key: genKey(),
        type: 'atomic',
        depth: 0,
        text: '-',
        characterList: imageCharacterList
    })
    let entityKey = Entity.create('button', 'MUTABLE', {
        data: {
            newPage: false,
            type: 'white',
            url: '/dev',
            width: 158,
            height: 38
        }
    })
    let text = '获取API Key'
    let characterList = List(text.split('').map(function () {
        return CharacterMetadata.create({
            entity: entityKey
        })
    }))
    let unstyledBlock = new ContentBlock({
            key: genKey(),
            type: 'unstyled',
            depth: 0,
            text,
            characterList
        }
    )
    return [
        imageBlock,
        unstyledBlock
    ]
}
Ejemplo n.º 4
0
function importFromImg($img) {
    let newPage = false
    let url = ''
    if ($img[0].nodeName === 'A') {
        url = $img.attr('href').replace(/http:\/\/replace\.lbs\.amap\.com\//g, '')
        newPage = $img.attr('target') === '_blank'
        $img = $img.find('img')

    }
    if ($img.attr('alt') === 'iframe') {
        let $iframe = $(`<iframe src="${$img.attr('src')}"></iframe>`)
        return importFromRawHTML($iframe)
    } else {
        let imageEntityKey = Entity.create('image', 'IMMUTABLE', {
            imgData: {
                img: $img.attr('src'),
                url,
                newPage,
                width: parseInt($img.attr('width') || $img.css('width')) || ''
            }
        })
        let imageCharacterList = List('-'.split('').map(function () {
            return CharacterMetadata.create({
                entity: imageEntityKey
            })
        }))
        return new ContentBlock({
            key: genKey(),
            type: 'atomic',
            depth: 0,
            text: '-',
            characterList: imageCharacterList
        })
    }
}
Ejemplo n.º 5
0
function importFromMDTab($tabs) {
    let tabs = []
    $tabs.find('.lbs_tabs > a').each(function () {
        let tab = {
            title: $(this).text().trim(),
        }
        tab.editorState = importFromHTML($tabs.find('.lbs_tab_content').eq($(this).index()).html())
        tabs.push(tab)
    })
    let entityKey = Entity.create('tab', 'IMMUTABLE', {
        tabData: {
            tabs
        }
    })
    let characterList = List('-'.split('').map(function () {
        return CharacterMetadata.create({
            entity: entityKey
        })
    }))
    return [new ContentBlock({
            key: genKey(),
            type: 'atomic',
            depth: 0,
            text: '-',
            characterList
        }
    )]
}
Ejemplo n.º 6
0
function importFromDemoCenter($div) {
    let tabs = []
    $div.find('.md-demo-code-header a').each(function (i,) {
        tabs.push({
            title: $(this).text().trim(),
            content: getCodeText($div.find('.md-demo-code-content-item pre').eq(i))
        })
    })
    let entityKey = Entity.create('code-tab', '"IMMUTABLE"', {
        codeTabData: {
            tabType: 'simple',
            tabs
        }
    })
    let characterList = List('-'.split('').map(function () {
        return CharacterMetadata.create({
            entity: entityKey
        })
    }))
    return new ContentBlock({
        key: genKey(),
        type: 'atomic',
        depth: 0,
        text: '-',
        characterList
    })

}
Ejemplo n.º 7
0
function importFromH2($h2) {
    let id = $h2.attr('id')
    let anchor = id && id.split(':')[1]
    if (!anchor) {
        anchor = ''
    }
    let text = $h2.text()
    let entityKey = Entity.create('h2', 'MUTABLE', {
        data: {
            anchor
        }
    })
    let characterList = List(text.split('').map(function () {
        return CharacterMetadata.create({
            entity: entityKey
        })
    }))
    return new ContentBlock({
        key: genKey(),
        type: 'header-two',
        depth: 0,
        text,
        characterList
    })
}
Ejemplo n.º 8
0
function importFromTry($left, $middle, $right) {
    let middleHTML = $('<div></div>').append($middle).html()
    let leftEditorState = importFromHTML(middleHTML)
    $right.children().first().remove()
    let rightHTML = $right.html()
    let rightEditorState = importFromHTML(rightHTML)
    console.log(exportToRaw(rightEditorState))
    let entityKey = Entity.create('layout', '"IMMUTABLE"', {
        layoutData: {
            scale: 6,
            leftEditorState,
            rightEditorState
        }
    })
    let characterList = List('-'.split('').map(function () {
        return CharacterMetadata.create({
            entity: entityKey
        })
    }))
    return new ContentBlock({
        key: genKey(),
        type: 'atomic',
        depth: 0,
        text: '-',
        characterList
    })
}
Ejemplo n.º 9
0
function importFromTab($oc, $swift) {

    let entityKey = Entity.create('code-tab', '"IMMUTABLE"', {
        codeTabData: {
            tabType: 'simple',
            tabs: [
                {
                    title: 'Objective-C',
                    content: getCodeText($oc.find('pre'))
                },
                {
                    title: 'Swift',
                    content: getCodeText($swift.find('pre'))
                }
            ]
        }
    })
    let characterList = List('-'.split('').map(function () {
        return CharacterMetadata.create({
            entity: entityKey
        })
    }))
    return [new ContentBlock({
        key: genKey(),
        type: 'atomic',
        depth: 0,
        text: '-',
        characterList
    })]
}
 this.blockList.forEach((block) => {
   let {text, characterMeta} = concatFragments(block.textFragments);
   let includeEmptyBlock = false;
   // If the block contains only a soft break then don't discard the block,
   // but discard the soft break.
   if (text === SOFT_BREAK_PLACEHOLDER) {
     includeEmptyBlock = true;
     text = '';
   }
   if (block.tagName === 'pre') {
     ({text, characterMeta} = trimLeadingNewline(text, characterMeta));
   } else {
     ({text, characterMeta} = collapseWhiteSpace(text, characterMeta));
   }
   // Previously we were using a placeholder for soft breaks. Now that we
   // have collapsed whitespace we can change it back to normal line breaks.
   text = text.split(SOFT_BREAK_PLACEHOLDER).join('\n');
   // Discard empty blocks (unless otherwise specified).
   if (text.length || includeEmptyBlock) {
     contentBlocks.push(
       new ContentBlock({
         key: genKey(),
         text: text,
         type: block.type,
         characterList: characterMeta.toList(),
         depth: block.depth,
       })
     );
   }
 });
Ejemplo n.º 11
0
    (textBlock, ii) => {
      // Make absolutely certain that our text is acceptable.
      textBlock = sanitizeDraftText(textBlock);
      var end = start + textBlock.length;
      var inlines = nullthrows(chunk).inlines.slice(start, end);
      var entities = nullthrows(chunk).entities.slice(start, end);
      var characterList = List(
        inlines.map((style, ii) => {
          var data = {style, entity: null};
          if (entities[ii]) {
            data.entity = entities[ii];
          }
          return CharacterMetadata.create(data);
        })
      );
      start = end + 1;

      return new ContentBlock({
        key: genKey(),
        type: nullthrows(chunk).blocks[ii].type,
        depth: nullthrows(chunk).blocks[ii].depth,
        text: textBlock,
        characterList,
      });
    }
Ejemplo n.º 12
0
export function condenseBlocks (editorState, blocks, options) {
  blocks = blocks || editorState.getCurrentContent().getBlocksAsArray()
  let text = List()
  let characterList = List()

  // Gather all the text/characterList and concat them
  blocks.forEach((block) => {
    // Atomic blocks should be ignored (stripped)
    if (block.getType() !== 'atomic') {
      text = text.push(replaceNewlines(block.getText()))
      characterList = characterList.concat(block.getCharacterList())
    }
  })

  // Strip entities?
  if (options.stripEntities) {
    characterList = characterList.map(stripEntityFromCharacterMetadata)
  }

  // Create a new content block
  const contentBlock = new ContentBlock({
    key: genKey(),
    text: text.join(''),
    type: 'unstyled',
    characterList: characterList,
    depth: 0,
  })

  // Update the editor state with the compressed version
  const newContentState = ContentState.createFromBlockArray([contentBlock])
  // Create the new state as an undoable action
  editorState = EditorState.push(editorState, newContentState, 'remove-range')
  // Move the selection to the end
  return EditorState.moveFocusToEnd(editorState)
}
Ejemplo n.º 13
0
const createContentBlock = (blockData = {}) => {
  const { key, type, text, data, inlineStyles, entityData } = blockData;

  let blockSpec = {
    type: type !== null && type !== undefined ? type : 'unstyled',
    text: text !== null && text !== undefined ? text : '',
    key: key !== null && key !== undefined ? key : genKey(),
  };

  if (data) {
    blockSpec.data = fromJS(data);
  }

  if (inlineStyles || entityData) {
    let entityKey;
    if (entityData) {
      const { type, mutability, data } = entityData;
      entityKey = Entity.create(type, mutability, data);
    } else {
      entityKey = null;
    }
    const style = OrderedSet(inlineStyles || []);
    const charData = CharacterMetadata.applyEntity(
      CharacterMetadata.create({ style, entityKey }),
      entityKey,
    );
    blockSpec.characterList = List(Repeat(charData, text.length));
  }
  return new ContentBlock(blockSpec);
};
 const blockMap = content.getBlockMap().toList().reduce((orderedMap, block, i, list) => {
   if (block.getType() === ATOMIC) {
     const next = list.get(i + 1);
     if (!next || next.getType() === ATOMIC) {
       const key = genKey();
       return orderedMap.set(block.getKey(), block).set(key, new ContentBlock({ key }));
     }
   }
   return orderedMap.set(block.getKey(), block);
 }, OrderedMap());
Ejemplo n.º 15
0
export default (editorState) => {
  const newEditorState = editorState;
  const contentState = newEditorState.getCurrentContent();
  const selectionState = newEditorState.getSelection();
  const currentBlock = contentState.getBlockForKey(selectionState.getFocusKey());

  /**
   * Draft Convert converts html to blocks and sets the block's text to
   * it's innerHTML. This isn't configurable so to prevent this text
   * being inserted when creating a new line we remove the block and create a
   * new block with empty text.
   */
  const contentStateAfterRemoval = removeBlock(contentState, currentBlock.getKey());

  const fragmentArray = [
    new ContentBlock({
      key: genKey(),
      type: currentBlock.getType(),
      text: ' ',
      characterList: currentBlock.getCharacterList(),
    }),
    new ContentBlock({
      key: genKey(),
      type: 'unstyled',
      text: '',
      characterList: List(),
    }),
  ];

  const fragment = BlockMapBuilder.createFromArray(fragmentArray);

  const withUnstyledBlock = Modifier.replaceWithFragment(
    contentStateAfterRemoval,
    selectionState,
    fragment,
  );

  return EditorState.forceSelection(
    EditorState.push(newEditorState, withUnstyledBlock, 'insert-fragment'),
    withUnstyledBlock.getSelectionAfter(),
  );
};
const getBlock = (text, entityRanges = [], entityMap = {}) => {
  const contentState = convertFromRaw({
    blocks: [{
      key: genKey(),
      text,
      type: 'unstyled',
      depth: 0,
      inlineStyleRanges: [],
      entityRanges,
    }],
    entityMap,
  });
  return contentState.getFirstBlock();
};
Ejemplo n.º 17
0
  componentWillMount() {
    this.key = genKey();

    // This a really nasty way of attaching & releasing the key related functions.
    // It assumes that the keyFunctions object will not loose its reference and
    // by this we can replace inner parameters spread over different modules.
    // This better be some registering & unregistering logic. PRs are welcome :)
    this.props.callbacks.onDownArrow = this.onDownArrow;
    this.props.callbacks.onUpArrow = this.onUpArrow;
    this.props.callbacks.onEscape = this.onEscape;
    this.props.callbacks.handleReturn = this.commitSelection;
    this.props.callbacks.onTab = this.onTab;
    this.props.callbacks.onChange = this.onEditorStateChange;
    this.props.ariaProps.ariaActiveDescendantID = `mention-option-${this.key}-${this.state.focusedOptionIndex}`;
    this.props.ariaProps.ariaOwneeID = `mentions-list-${this.key}`;
  }
Ejemplo n.º 18
0
export default function importFromHTML(html, meta, print) {
    let $html = $(html)
    $html.find('a').each(function () {
        if ($(this).text() === '亲手试一试') {
            $(this).attr('target', '_blank')
            $(this).attr('href', $(this).attr('href').replace(/^http:\/\/lbs.amap.com/, ''))
            $(this).addClass('try')
        }
    })
    html = $('<div></div>').append($html).html()
    html = html.replace(/\[jsdemo_loader\]([^"]+)/, function ($0, $1) {
        return `/fn/jsdemo_loader/?url=${encodeURIComponent($1)}`
    })
    html = html.replace(/(<a[^>]*href="(?!http))([^"]+"[^>]*>)/g, '$1http://replace.lbs.amap.com/$2')
    let blocks = getBlocks(html, meta)

    if (blocks.length) {
        let characterList = List('-'.split('').map(function () {
            return CharacterMetadata.create({
                entity: null
            })
        }))
        if (blocks[blocks.length - 1].getType() === 'atomic') {
            blocks.push(new ContentBlock({
                key: genKey(),
                type: 'unstyled',
                depth: 0,
                text: ' ',
                characterList
            }))
        }
        const contentState = ContentState.createFromBlockArray(blocks);
        let rawContentSTate = convertToRaw(contentState)
        let editorState = createEditorState(rawContentSTate)
        if (print) {
            let html = exportToHTML(editorState)
            console.log(html)
            // document.body.innerHTML = html
            console.log(exportToRaw(editorState))
        }
        return editorState
    } else {
        return createEditorState()
    }
    // $(document.body).append(exportToHTML(editorState))

}
 it('should not match entities', () => {
   const key = genKey();
   whitespaceStrategy(getBlock(
     '@the walking dead tv the white house',
     [{
       key,
       offset: 20,
       length: 15,
     }],
     {
       [key]: {
         type: 'mention',
         mutability: 'IMMUTABLE',
         data: {},
       },
     },
   ), callback);
   expect(callback.callCount).to.equal(1);
   expect(callback.lastCall.args).to.deep.equal([0, 20]);
 });
 this.blockList.forEach((block) => {
   let {text, characterMeta} = concatFragments(block.textFragments);
   // If this block contains only a soft linebreak then don't discard it
   let includeEmptyBlock = (text === '\r');
   if (block.tagName === 'pre') {
     ({text, characterMeta} = trimLeadingNewline(text, characterMeta));
   } else {
     ({text, characterMeta} = collapseWhiteSpace(text, characterMeta));
   }
   // Discard empty blocks (unless otherwise specified).
   if (text.length || includeEmptyBlock) {
     contentBlocks.push(
       new ContentBlock({
         key: genKey(),
         text: text,
         type: block.type,
         characterList: characterMeta.toList(),
         depth: block.depth,
       })
     );
   }
 });
Ejemplo n.º 21
0
function importFromRawHTML($raw) {
    let html = $raw[0].outerHTML
    html = restoreUrl(html)
    let entityKey = Entity.create('html', 'IMMUTABLE', {
        htmlData: {
            html
        }
    })
    let characterList = List('-'.split('').map(function () {
        return CharacterMetadata.create({
            entity: entityKey
        })
    }))
    let block = new ContentBlock({
            key: genKey(),
            type: 'atomic',
            depth: 0,
            text: '-',
            characterList
        }
    )
    return block
}
Ejemplo n.º 22
0
export default function insertBlockAfter(
  editorState: EditorState,
  blockKey: string,
  newType: string,
): EditorState {
  let content = editorState.getCurrentContent();
  let blockMap = content.getBlockMap();
  let block = blockMap.get(blockKey);
  let blocksBefore = blockMap.toSeq().takeUntil((v) => (v === block));
  let blocksAfter = blockMap.toSeq().skipUntil((v) => (v === block)).rest();
  let newBlockKey = genKey();
  let newBlock = new ContentBlock({
    key: newBlockKey,
    type: newType,
    text: '',
    characterList: block.getCharacterList().slice(0, 0),
    depth: 0,
  });
  let newBlockMap = blocksBefore.concat(
    [[blockKey, block], [newBlockKey, newBlock]],
    blocksAfter,
  ).toOrderedMap();
  let selection = editorState.getSelection();
  let newContent = content.merge({
    blockMap: newBlockMap,
    selectionBefore: selection,
    selectionAfter: selection.merge({
      anchorKey: newBlockKey,
      anchorOffset: 0,
      focusKey: newBlockKey,
      focusOffset: 0,
      isBackward: false,
    }),
  });
  return EditorState.push(editorState, newContent, 'split-block');
}
  styleStack: Array<StyleSet>;
  entityStack: Array<?Entity>;
  depth: number;
};

type ElementStyles = {[tagName: string]: Style};

type Options = {
  elementStyles?: ElementStyles;
};

const NO_STYLE = OrderedSet();
const NO_ENTITY = null;

const EMPTY_BLOCK = new ContentBlock({
  key: genKey(),
  text: '',
  type: BLOCK_TYPE.UNSTYLED,
  characterList: List(),
  depth: 0,
});

const LINE_BREAKS = /(\r\n|\r|\n)/g;
// We use `\r` because that character is always stripped from source (normalized
// to `\n`), so it's safe to assume it will only appear in the text content when
// we put it there as a placeholder.
const SOFT_BREAK_PLACEHOLDER = '\r';
const ZERO_WIDTH_SPACE = '\u200B';

// Map element attributes to entity data.
const ELEM_ATTR_MAP = {
Ejemplo n.º 24
0
 componentWillMount() {
   this.key = genKey();
   this.props.callbacks.onChange = this.onEditorStateChange;
 }
Ejemplo n.º 25
0
/**
 * Single Line Plugin
 * @param  {Object} options Per-instance options to override the defaults
 * @return {Object} Compatible draft-js-editor-plugin object
 */
function singleLinePlugin (options = {}) {
  options = Object.assign({}, defaultOptions, options)

  return {
    /**
     * Return a compatible blockRenderMap
     *
     * NOTE: Needs to be explicitly applied, the plugin system doesn’t do
     * anything with this at the moment.
     *
     * @type {ImmutableMap}
     */
    blockRenderMap: Map({
      'unstyled': {
        element: 'div',
      },
    }),

    /**
     * onChange
     *
     * Condense multiple blocks into a single block and (optionally) strip all
     * entities from the content of that block.
     *
     * @param  {EditorState} editorState The current state of the editor
     * @return {EditorState} A new editor state
     */
    onChange (editorState) {
      const blocks = editorState.getCurrentContent().getBlocksAsArray()

      // If we have more than one block, compress them
      if (blocks.length > 1) {
        editorState = condenseBlocks(editorState, blocks, options)
      } else {
        // We only have one content block
        let contentBlock = blocks[0]
        let text = contentBlock.getText()
        let characterList = contentBlock.getCharacterList()
        let hasEntitiesToStrip = options.stripEntities && characterListhasEntities(characterList)

        if (NEWLINE_REGEX.test(text) || hasEntitiesToStrip) {
          // Replace the text stripped of its newlines. Note that we replace
          // one '\n' with one ' ' so we don't need to modify the characterList
          text = replaceNewlines(text)

          // Strip entities?
          if (options.stripEntities) {
            characterList = characterList.map(stripEntityFromCharacterMetadata)
          }

          // Create a new content block based on the old one
          contentBlock = new ContentBlock({
            key: genKey(),
            text: text,
            type: 'unstyled',
            characterList: characterList,
            depth: 0,
          })

          // Update the editor state with the compressed version
          // const selection = editorState.getSelection()
          const newContentState = ContentState.createFromBlockArray([contentBlock])

          // Create the new state as an undoable action
          editorState = EditorState.push(editorState, newContentState, 'insert-characters')
        }
      }

      return editorState
    },

    /**
     * Stop new lines being inserted by always handling the return
     *
     * @param  {KeyboardEvent} e Synthetic keyboard event from draftjs
     * @return {String} Did we handle the return or not? (pro-trip: yes, we did)
     */
    handleReturn (e) {
      return 'handled'
    },
  }
}
function insertAtomicBlockWithoutEmptyLines(editorState, entityKey, character) {
    var selectionState = editorState.getSelection();
    var target = getInsertionTarget(editorState.getCurrentContent(), selectionState);
    var asAtomicBlock = Modifier.setBlockType(target.contentState, target.selectionState, 'atomic');
    var charData = CharacterMetadata.create({entity: entityKey});
    var fragmentArray = [];

    if (asAtomicBlock.getFirstBlock().getKey() === target.selectionState.getAnchorKey()) {
        fragmentArray.push(new ContentBlock({
            key: genKey(),
            type: 'unstyled',
            text: '',
            characterList: List(),
        }));
    }


    fragmentArray.push(new ContentBlock({
        key: genKey(),
        type: 'atomic',
        text: character,
        characterList: List(Repeat(charData, character.length)),
    }));

    if (
        // check if atomic is the last block in the editor
        asAtomicBlock.getLastBlock().getKey() === target.selectionState.getAnchorKey()
        ||
        // check if cursor is not at the end of the block
        target.selectionState.getFocusOffset()
        !== target.contentState.getBlockForKey(target.selectionState.getFocusKey()).getText().length
    ) {
        fragmentArray.push(new ContentBlock({
            key: genKey(),
            type: 'unstyled',
            text: '',
            characterList: List(),
        }));
    }

    var fragment = BlockMapBuilder.createFromArray(fragmentArray);

    const customData = getAllCustomDataFromEditor(editorState);

    var withAtomicBlock = Modifier.replaceWithFragment(asAtomicBlock, target.selectionState, fragment);

    var newContent = withAtomicBlock.merge({
        selectionBefore: selectionState,
        selectionAfter: withAtomicBlock.getSelectionAfter().set('hasFocus', true),
    });

    const {block: blockKeyForEntity} = newContent.getBlocksAsArray()
        .map((b) => ({entity: b.getEntityAt(0), block: b.getKey()}))
        .find((b) => b.entity === entityKey);

    let newEditorState = EditorState.push(editorState, newContent, 'insert-fragment');

    // for the first block recover the initial block data because on replaceWithFragment the block data is
    // replaced with the data from pasted fragment
    newEditorState = setAllCustomDataForEditor(newEditorState, customData);

    newEditorState = EditorState.push(editorState, newEditorState.getCurrentContent(), 'insert-fragment');

    return {
        editorState: newEditorState,
        blockKey: blockKeyForEntity,
    };
}
Ejemplo n.º 27
0
function importFromSingleP($p, meta) {
    let html = $p.html()
    let blocks = []
    if (html.trim() === '===process===') {
        blocks = importFromProcess()
    } else if (html.trim() === '===js===') {
        let list
        let phoneType = meta.summary_phone_type ? meta.summary_phone_type[0] : 'iphone'
        let contentList
        try {
            list = JSON.parse(meta.summary_subway ? meta.summary_subway[0] : meta.summary_phone[0])
            contentList = JSON.parse(meta.summary_code[0])
        } catch (e) {
            blocks = []
            return []
        }
        let entityKey = Entity.create('code-tab', '"IMMUTABLE"', {
            codeTabData: {
                phoneType,
                tabType: 'vertical',
                mediaType: 'video',
                tabs: list.map((item, i) => {
                    return {
                        title: item.title,
                        video: item.src,
                        content: escapeHTML(contentList[i])
                    }
                }),
            }
        })
        let characterList = List('-'.split('').map(function () {
            return CharacterMetadata.create({
                entity: entityKey
            })
        }))
        let buttonText = '下载完整示例代码'
        let buttonEntityKey = Entity.create('button', 'MUTABLE', {
            data: {
                newPage: meta.summary_phone_type,
                type: 'white',
                url: meta.more_url,
                width: 180,
                height: 40,
                class: 'iconfont btn-download-icon'
            }
        })
        let buttonCharacterList = List(buttonText.split('').map(function () {
            return CharacterMetadata.create({
                entity: buttonEntityKey
            })
        }))
        let buttonBlock = new ContentBlock({
            key: genKey(),
            type: 'unstyled',
            depth: 0,
            text: buttonText,
            characterList: buttonCharacterList
        })
        let h2EntityKey = Entity.create('h2', 'MUTABLE', {
            data: {
                anchor: ''
            }
        })
        let h2Text = '功能介绍与体验'
        let h2CharacterList = List(h2Text.split('').map(function () {
            return CharacterMetadata.create({
                entity: h2EntityKey
            })
        }))
        let h2Block = new ContentBlock({
            key: genKey(),
            type: 'header-two',
            depth: 0,
            text: h2Text,
            characterList: h2CharacterList
        })
        blocks = [
            h2Block,
            new ContentBlock({
                key: genKey(),
                type: 'atomic',
                depth: 0,
                text: '-',
                characterList
            }),
            buttonBlock
        ]
    } else {
        // html = html.replace(/\[jsdemo_loader\]([^"]+)/, function ($0, $1) {
        //     return `/fn/jsdemo_loader/?url=${encodeURIComponent($1)}`
        // })
        // html = html.replace(/(<a[^>]*href=")([^"]+"[^>]*>)/, '$1http://replace.lbs.amap.com$2')
        blocks = convertFromHTML(html)
    }
    return blocks
}
Ejemplo n.º 28
0
function importFromTable($table) {
    let rowCount = $table.find('tr').length
    let columnCount = 0
    $table.find('tr').first().find('td,th').each(function () {
        columnCount += parseInt($(this).attr('colspan') || 1)
    })
    let width = $table.attr('width') || $table.css('width')
    if (width !== '100%') {
        width = parseInt(width)
    }
    if (!width) {
        width = '100%'
    }
    let meta = {
        'class': $table.attr('class'),
        width
    }
    let data = []
    for (let i = 0; i < rowCount; ++i) {
        let row = []
        for (let j = 0; j < columnCount; ++j) {
            row.push({
                style: {},
                rowspan: 1,
                colspan: 1,
                contentState: convertToRaw(ContentState.createFromText(''))
            })
        }
        data.push(row)
    }
    let rowMeta = []
    $table.find('tr').each(function (rowIndex) {
        let rowData = data[rowIndex].filter(item => !item.invalid)
        let currentRowColumnIndex = 0
        let startValidColumnIndex = 0
        data[rowIndex].some((item, i) => {
            if (!item.invalid) {
                startValidColumnIndex = i
                return true
            }
        })
        $(this).find('th,td').each(function () {
            if ($(this)[0].nodeName === 'th') {
                rowMeta[rowIndex] = rowMeta[rowIndex] || {title: true}
            }
            let rowspan = parseInt($(this).attr('rowspan')) || 1
            let colspan = parseInt($(this).attr('colspan')) || 1
            //这里不能使用rowData[currentRowColumnIndex]={}的方式赋值
            let cellHTML = $(this).html()
            // let contentState = convertToRaw(ContentState.createFromBlockArray(convertFromHTML(cellHTML)))

            // if ($(cellHTML).length === 0) {
            //     debugger
            if (cellHTML.indexOf('<p>') === -1) {
                cellHTML = `<p>${cellHTML}</p>`
            }
            // }
            let editorState = importFromHTML(cellHTML, {})
            let contentState = convertToRaw(editorState.getCurrentContent())
            rowData[currentRowColumnIndex].rowspan = Math.min(rowspan, rowCount - rowIndex)
            rowData[currentRowColumnIndex].colspan = Math.min(colspan, columnCount - currentRowColumnIndex)
            rowData[currentRowColumnIndex].contentState = contentState
            rowData[currentRowColumnIndex].style = {
                whiteSpace: $(this).css('white-space')
            }
            for (let i = 0; i < rowspan; ++i) {
                for (let j = 0; j < colspan; ++j) {
                    if (i === 0 && j === 0) {
                        continue
                    }
                    let columnIndex = startValidColumnIndex + currentRowColumnIndex + j
                    //此单元格是无效的,只是填充需要
                    // if (data[rowIndex + i]) {
                    if (data[rowIndex + i] && data[rowIndex + i][columnIndex]) {
                        data[rowIndex + i][columnIndex].invalid = true
                        data[rowIndex + i][columnIndex].validCell = {
                            rowIndex,
                            columnIndex: startValidColumnIndex + currentRowColumnIndex
                        }
                    }
                    // }
                }
            }
            currentRowColumnIndex += colspan
        })
    })
    for (let j = 0; j < columnCount; ++j) {
        let validColumn = false
        for (let i = 0; i < rowCount; ++i) {
            if (!data[i][j].invalid) {
                validColumn = true
                break
            }
        }
        if (!validColumn) {
            let columnListHandled = []
            for (let i = 0; i < rowCount; ++i) {
                let cell = data[i][j]
                if (!columnListHandled.some((item) => {
                        return item.rowIndex == cell.validCell.rowIndex && item.columnIndex === cell.validCell.columnIndex
                    })) {
                    data[cell.validCell.rowIndex][cell.validCell.columnIndex].colspan -= 1
                    if (data[cell.validCell.rowIndex][cell.validCell.columnIndex].colspan < 1) {
                        debugger
                    }
                    columnListHandled.push(cell.validCell)
                }
            }
            deleteColumn(j)
            j--
        }
    }

    function deleteColumn(columnIndex) {
        let finalData = []
        for (let i = 0; i < rowCount; ++i) {
            let newRow = [
                ...data[i].slice(0, columnIndex),
                ...data[i].slice(columnIndex + 1)
            ]
            finalData.push(newRow)
        }
        columnCount -= 1
        data = finalData
    }

    // $table.find('tr').each(function () {
    //     let row = []
    //     $(this).find('td,th').each(function () {
    //         let cellHTML = $(this).html()
    //         let contentState = convertToRaw(ContentState.createFromBlockArray(convertFromHTML(cellHTML)))
    //         row.push({
    //             colspan: parseInt($(this).attr('colspan') || 1),
    //             rowspan: parseInt($(this).attr('rowspan') || 1),
    //             contentState,
    //             style: {
    //                 whiteSpace: $(this).css('white-space')
    //             }
    //         })
    //     })
    //     data.push(row)
    // })
    // for (let i = 0; i < rowCount; ++i) {
    //     for (let j = 0; j < columnCount; ++j) {
    //         if (!data[i][j]) {
    //             data[i][j] = {
    //                 colspan: 1,
    //                 rowspan: 1,
    //                 contentState: convertToRaw(ContentState.createFromText('')),
    //                 style: {},
    //                 value: ''
    //             }
    //         }
    //     }
    // }
    let tableData = {
        rowCount,
        columnCount,
        data,
        meta
    }
    let entityKey = Entity.create('table', 'IMMUTABLE', {
        tableData
    })
    let oneChar = CharacterMetadata.create({
        entity: entityKey
    })
    let characterList = List([oneChar])
    return [new ContentBlock({
        key: genKey(),
        type: 'atomic',
        depth: 0,
        text: '-',
        characterList
    })]
    // } catch (e) {
    //     return []
    // }
}
Ejemplo n.º 29
0
/**
 * Block Breakout Plugin
 *
 * By default draft carries the current block type over to the next line when
 * you press return, which is an undesired behaviour for _some_ of the default
 * block types (headers mostly).
 *
 * This plugin adds behaviour to the editor to "break out" of certain block
 * types if the user presses `return` at the start or end of the block.
 *
 * @param {Array} options.breakoutBlocks An array containing the names of the
 * various block-types to break out from.
 *
 * @return {Object} Object defining the draft-js API methods
 */
export default function blockBreakoutPlugin (options = {}) {
  const breakoutBlockType = options.breakoutBlockType || defaults.breakoutBlockType
  const breakoutBlocks = options.breakoutBlocks || defaults.breakoutBlocks
  const doubleBreakoutBlocks = options.doubleBreakoutBlocks || defaults.doubleBreakoutBlocks

  return {
    handleReturn (e, editorState, { setEditorState }) {
      const currentBlockType = RichUtils.getCurrentBlockType(editorState)
      const isSingleBreakoutBlock = breakoutBlocks.indexOf(currentBlockType) > -1
      const isDoubleBreakoutBlock = doubleBreakoutBlocks.indexOf(currentBlockType) > -1

      // Does the current block type match a type we care about?
      if (isSingleBreakoutBlock || isDoubleBreakoutBlock) {
        const selection = editorState.getSelection()

        // Check if the selection is collapsed
        if (selection.isCollapsed()) {
          const contentState = editorState.getCurrentContent()
          const currentBlock = contentState.getBlockForKey(selection.getEndKey())
          const endOffset = selection.getEndOffset()
          const atEndOfBlock = (endOffset === currentBlock.getLength())
          const atStartOfBlock = (endOffset === 0)

          // Check we’re at the start/end of the current block
          if ((atEndOfBlock && isSingleBreakoutBlock) || (atStartOfBlock && isSingleBreakoutBlock) || (atStartOfBlock && !currentBlock.getLength())) {
            const emptyBlockKey = genKey()
            const emptyBlock = new ContentBlock({
              key: emptyBlockKey,
              text: '',
              type: breakoutBlockType,
              characterList: List(),
              depth: 0,
            })
            const blockMap = contentState.getBlockMap()
            // Split the blocks
            const blocksBefore = blockMap.toSeq().takeUntil(function (v) {
              return v === currentBlock
            })

            const blocksAfter = blockMap.toSeq().skipUntil(function (v) {
              return v === currentBlock
            }).rest()

            let augmentedBlocks
            let focusKey
            // Choose which order to apply the augmented blocks in depending
            // on whether we’re at the start or the end
            if (atEndOfBlock) {
              if (isDoubleBreakoutBlock) {
                // Discard Current as it was blank
                augmentedBlocks = [
                  [emptyBlockKey, emptyBlock],
                ]
              } else {
                // Current first, empty block afterwards
                augmentedBlocks = [
                  [currentBlock.getKey(), currentBlock],
                  [emptyBlockKey, emptyBlock],
                ]
              }
              focusKey = emptyBlockKey
            } else {
              // Empty first, current block afterwards
              augmentedBlocks = [
                [emptyBlockKey, emptyBlock],
                [currentBlock.getKey(), currentBlock],
              ]
              focusKey = currentBlock.getKey()
            }
            // Join back together with the current + new block
            const newBlocks = blocksBefore.concat(augmentedBlocks, blocksAfter).toOrderedMap()
            const newContentState = contentState.merge({
              blockMap: newBlocks,
              selectionBefore: selection,
              selectionAfter: selection.merge({
                anchorKey: focusKey,
                anchorOffset: 0,
                focusKey: focusKey,
                focusOffset: 0,
                isBackward: false,
              }),
            })
            // Set the state
            setEditorState(
              EditorState.push(editorState, newContentState, 'split-block')
            )
            return 'handled'
          }
        }
      }
      return 'not-handled'
    },
  }
}
Ejemplo n.º 30
0
export default (editorState: Object, stickerId: any) => {
  const currentContentState = editorState.getCurrentContent();
  const currentSelectionState = editorState.getSelection();

  // in case text is selected it is removed and then the sticker is appended
  const afterRemovalContentState = Modifier.removeRange(
    currentContentState,
    currentSelectionState,
    'backward'
  );

  // deciding on the postion to split the text
  const targetSelection = afterRemovalContentState.getSelectionAfter();
  const blockKeyForTarget = targetSelection.get('focusKey');
  const block = currentContentState.getBlockForKey(blockKeyForTarget);
  let insertionTargetSelection;
  let insertionTargetBlock;

  // In case there are no characters or entity or the selection is at the start it
  // is safe to insert the sticker in the current block.
  // Otherwise a new block is created (the sticker is always its own block)
  const isEmptyBlock = block.getLength() === 0 && block.getEntityAt(0) === null;
  const selectedFromStart = currentSelectionState.getStartOffset() === 0;
  if (isEmptyBlock || selectedFromStart) {
    insertionTargetSelection = targetSelection;
    insertionTargetBlock = afterRemovalContentState;
  } else {
    // the only way to insert a new seems to be by splitting an existing in to two
    insertionTargetBlock = Modifier.splitBlock(afterRemovalContentState, targetSelection);

    // the position to insert our blocks
    insertionTargetSelection = insertionTargetBlock.getSelectionAfter();
  }

  // TODO not sure why we need it …
  const newContentStateAfterSplit = Modifier.setBlockType(insertionTargetBlock, insertionTargetSelection, 'sticker');

  // creating a new ContentBlock including the entity with data
  const contentStateWithEntity = newContentStateAfterSplit.createEntity(
    'sticker', 'IMMUTABLE', { id: stickerId }
  );
  const entityKey = contentStateWithEntity.getLastCreatedEntityKey();
  const charDataOfSticker = CharacterMetadata.create({ entity: entityKey });

  const fragmentArray = [
    new ContentBlock({
      key: genKey(),
      type: 'sticker',
      text: ' ',
      characterList: List(Repeat(charDataOfSticker, 1)), // eslint-disable-line new-cap
    }),

    // new contentblock so we can continue wrting right away after inserting the sticker
    new ContentBlock({
      key: genKey(),
      type: 'unstyled',
      text: '',
      characterList: List(), // eslint-disable-line new-cap
    }),
  ];

  // create fragment containing the two content blocks
  const fragment = BlockMapBuilder.createFromArray(fragmentArray);

  // replace the contentblock we reserved for our insert
  const contentStateWithSticker = Modifier.replaceWithFragment(
    newContentStateAfterSplit,
    insertionTargetSelection,
    fragment
  );

  // update editor state with our new state including the sticker
  const newState = EditorState.push(
    editorState,
    contentStateWithSticker,
    'insert-sticker'
  );
  return EditorState.forceSelection(newState, contentStateWithSticker.getSelectionAfter());
};