Example #1
0
 const onMousedown = DomEvent.bind(Element.fromDom(document), 'mousedown', function (evt) {
   Arr.each([ mothership, uiMothership ], function (ship) {
     ship.broadcastOn([ Channels.dismissPopups() ], {
       target: evt.target()
     });
   });
 });
Example #2
0
 editor.serializer.addNodeFilter('details', function (elms) {
   Arr.each(elms, function (details) {
     const open = details.attr('data-mce-open');
     details.attr('open', Type.isString(open) ? open : null);
     details.attr('data-mce-open', null);
   });
 });
Example #3
0
 const getStr = (sections: TestSection[]) => {
   const r = { };
   Arr.each(sections, (section) => {
     r[section.setting.key] = section.setting.value.getOr('{ default }');
   });
   return JSON.stringify(r, null, 2);
 };
Example #4
0
const removeTrailingBr = function (elm) {
  const allBrs = SelectorFilter.descendants(elm, 'br');
  const brs = Arr.filter(getLastChildren(elm).slice(-1), ElementType.isBr);
  if (allBrs.length === brs.length) {
    Arr.each(brs, Remove.remove);
  }
};
Example #5
0
const removeDataStyle = (table) => {
  const dataStyleCells = SelectorFilter.descendants(table, 'td[data-mce-style],th[data-mce-style]');
  Attr.remove(table, 'data-mce-style');
  Arr.each(dataStyleCells, function (cell) {
    Attr.remove(cell, 'data-mce-style');
  });
};
  const onNodeChange = Throttler.last(() => {
    const callbackMap = changeCallbacks.get();
    const annotations = Arr.sort(Obj.keys(callbackMap));
    Arr.each(annotations, (name) => {
      updateCallbacks(name, (data) => {
        const prev = data.previous.get();
        identify(editor, Option.some(name)).fold(
          () => {
            if (prev.isSome()) {
              // Changed from something to nothing.
              fireNoAnnotation(name);
              data.previous.set(Option.none());
            }
          },
          ({ uid, name, elements }) => {
            // Changed from a different annotation (or nothing)
            if (! prev.is(uid)) {
              fireCallbacks(name, uid, elements);
              data.previous.set(Option.some(uid));
            }
          }
        );

        return {
          previous: data.previous,
          listeners: data.listeners
        };
      });
    });
  }, 30);
Example #7
0
const hide = function (editor, body) {
  const nodeList = editor.dom.select(Data.selector, body);

  Arr.each(nodeList, function (node) {
    editor.dom.remove(node, 1);
  });
};
 editor.serializer.addNodeFilter('span', (spans) => {
   Arr.each(spans, (span) => {
     identifyParserNode(span).each((settings) => {
       if (settings.persistent === false) { span.unwrap(); }
     });
   });
 });
Example #9
0
  const resetTargets = () => {
    // Reset the targets
    targets.set(Thunk.cached(findTargets)());

    // Trigger change handlers
    Arr.each(changeHandlers.get(), (handler) => handler());
  };
Example #10
0
  Arr.each(SelectorFilter.descendants(table, 'tr'), (row) => {
    fireNewRow(editor, row.dom());

    Arr.each(SelectorFilter.descendants(row, 'th,td'), (cell) => {
      fireNewCell(editor, cell.dom());
    });
  });
Example #11
0
UnitTest.test('tinymce.plugins.paste.browser.NewlinesTest', function () {
  Theme();
  PastePlugin();

  // testing Newlines.isPlainText()
  const textCases = [
    {
      label: 'Basic Chrome markup (including span-wrapped tab)',
      content: '<div><span style="white-space:pre">  </span>a</div><div><br></div><div>b</div>',
      isText: true
    },
    {
      label: 'Case shouldn\'t matter',
      content: '<DIV>a</DIV><DIV><BR></DIV>',
      isText: true
    },
    {
      label: 'Support all BR types',
      content: '<br><br />',
      isText: true
    },
    {
      label: 'Basic IE markup',
      content: '<p>a</p><p><br></p><p>b</p>',
      isText: true
    },
    {
      label: 'White-space wrapper (Chrome)',
      content: '<div><span style="white-space: pre;"> </span>a</div>',
      isText: true
    },
    {
      label: 'White-space wrapper (Chrome) with additional styles',
      content: '<div><span style="white-space: pre; color: red;"> </span>a</div>',
      isText: false
    },
    {
      label: 'Allowed tag but with attributes qualifies string as not a plain text',
      content: '<br data-mce-bogus="all" />',
      isText: false
    }
  ];

  // only DIV,P,BR and SPAN[style="white-space:pre"] tags are allowed in "plain text" string
  Arr.each('a,abbr,address,article,aside,audio,b,bdi,bdo,blockquote,button,cite,code,del,details,dfn,dl,em,embed,fieldset,figure,footer,form,h1,h2,h3,h4,h5,h6,header,hgroup,hr,i,ins,label,menu,nav,noscript,object,ol,pre,q,s,script,section,select,small,strong,style,sub,sup,svg,table,textarea,time,u,ul,var,video,wbr'.split(','),
    function (tag) {
      const content = '<p>a</p><' + tag + '>b</' + tag + '><p>c<br>d</p>';
      textCases.push({
        label: tag.toUpperCase() + ' tag should qualify content (' + content + ') as not a plain text',
        content,
        isText: false
      });
    }
  );

  Obj.each(textCases, function (c) {
    Assertions.assertEq(c.label || 'Asserting: ' + c.content, c.isText, Newlines.isPlainText(c.content));
  });
});
Example #12
0
 const registerFormats = (customFormats: {name: string, format: StyleFormat}[]) => {
   Arr.each(customFormats, (fmt) => {
     // Only register the custom format with the editor, if it's not already registered
     if (!editor.formatter.has(fmt.name)) {
       editor.formatter.register(fmt.name, fmt.format);
     }
   });
 };
Example #13
0
const extractChildren = function (block) {
  const children = getChildrenUntilBlockBoundary(block);

  Arr.each(children, function (node) {
    Remove.remove(node);
  });

  return children;
};
Example #14
0
 const onMouseup = DomEvent.bind(Element.fromDom(document), 'mouseup', function (evt) {
 if (evt.raw().button === 0) {
   Arr.each([ mothership, uiMothership ], function (ship) {
     ship.broadcastOn([ Channels.mouseReleased() ], {
       target: evt.target()
     });
   });
 }
 });
Example #15
0
 const onContentMouseup = function (raw) {
   if (raw.button === 0) {
     Arr.each([ mothership, uiMothership ], function (ship) {
       ship.broadcastOn([ Channels.mouseReleased() ], {
         target: Element.fromDom(raw.target)
       });
     });
   }
 };
  const mAssertTargets = Step.stateful(function (targets, next, die) {
    Assertions.assertEq('Targets should be two since there are two editors', 2, targets.length);

    Arr.each(targets, function (target) {
      Assertions.assertEq('Target parent should not be null', true, target.parentNode !== null);
    });

    next({});
  });
Example #17
0
const listsIndentation = (editor: Editor, lists: Element[], indentation: Indentation) => {
  const entrySets: EntrySet[] = parseLists(lists, getItemSelection(editor));

  Arr.each(entrySets, (entrySet) => {
    indentSelectedEntries(entrySet.entries, indentation);
    InsertAll.before(entrySet.sourceList, composeEntries(editor, entrySet.entries));
    Remove.remove(entrySet.sourceList);
  });
};
Example #18
0
const filter = (nodeFilters: ParserFilter[], attributeFilters: ParserFilter[], node: Node): void => {
  const matches = findMatchingNodes(nodeFilters, attributeFilters, node);

  Arr.each(matches, (match: FilterMatch) => {
    Arr.each(match.filter.callbacks, (callback: ParserFilterCallback) => {
      callback(match.nodes, match.filter.name, {});
    });
  });
};
Example #19
0
      readBlobsAsDataUris(images).get((blobResults) => {
        if (rng) {
          editor.selection.setRng(rng);
        }

        Arr.each(blobResults, (result) => {
          pasteImage(editor, result);
        });
      });
Example #20
0
 Arr.each(entrySets, (entrySet) => {
   indentSelectedEntries(entrySet.entries, indentation);
   const composedLists = composeEntries(editor, entrySet.entries);
   Arr.each(composedLists, (composedList) => {
     fireListEvent(editor, indentation === Indentation.Indent ? ListAction.IndentList : ListAction.OutdentList, composedList.dom());
   });
   InsertAll.before(entrySet.sourceList, composedLists);
   Remove.remove(entrySet.sourceList);
 });
Example #21
0
UnitTest.test('SizeInputParsingTest', () => {
  const check = (expected: Result<Size, string>, text: string) => {
    const result = parseSize(text);
    expected.fold((err) => {
      result.fold((resultErr) => {
        assert.eq(err, resultErr);
      }, (resultValue) => {
        assert.fail('parseSize should have failed but succeeded with value:\n' + JSON.stringify(resultValue));
      });
    }, (value: Size) => {
      result.fold((resultErr) => {
        assert.fail('parseSize should have succeeded but failed with err: "' + resultErr + '"');
      }, (resultValue) => {
        assert.eq(value, resultValue);
      });
    });
  };

  check(Result.error(''), '');
  check(Result.error('px'), 'px');
  check(Result.error('a'), 'a');
  check(Result.error('blah'), 'blah');
  check(Result.error('1a'), '1a');
  // check negative numbers are not allowed
  check(Result.error('-1px'), '-1px');
  // check the empty unit
  check(Result.value(nuSize(1, '')), '1');
  // check various forms of padding
  check(Result.value(nuSize(1, 'px')), '1px');
  check(Result.value(nuSize(1, 'px')), '    1px');
  check(Result.value(nuSize(1, 'px')), '1px     ');
  check(Result.value(nuSize(1, 'px')), '    1px     ');
  check(Result.value(nuSize(1, 'px')), '    1    px     ');
  check(Result.value(nuSize(1.25, 'px')), '    1.25    px     ');
  // check that all units work
  Arr.each(units, (unit) => {
    check(Result.error(unit), unit);
    check(Result.value(nuSize(4, unit as SizeUnit)), '4' + unit);
  });

  const arbPad = Jsc.array(Jsc.elements(' \t'.split(''))).smap(
    function (arr) { return arr.join(''); },
    function (s) { return s.split(''); }
  );

  Jsc.property(
    'Valid size strings should be parseable',
    arbPad, Jsc.number(0, largeSensible), arbPad, Jsc.oneof(Jsc.elements(units)), arbPad,
    function (pad1: string, nonNegNumber: number, pad2: string, unit: SizeUnit, pad3: string) {
      const str = pad1 + nonNegNumber + pad2 + unit + pad3;
      const parsed = parseSize(str);
      const size = parsed.toOption().getOrNull();
      return Jsc.eq(nuSize(nonNegNumber, unit), size);
    }
  );
});
Example #22
0
  domParser.addNodeFilter('strike', function (nodes) {
    Arr.each(nodes, function (node) {
      const props = styles.parse(node.attr('style'));

      props['text-decoration'] = 'line-through';

      node.name = 'span';
      node.attr('style', styles.serialize(props));
    });
  });
Example #23
0
  const normalizeCss = (cssText: string) => {
    const css = DOMUtils.DOM.styles.parse(cssText);
    const newCss = {};

    Arr.each(Obj.keys(css).sort(), (key) => {
      newCss[key] = css[key];
    });

    return DOMUtils.DOM.styles.serialize(newCss);
  };
 htmlParser.addAttributeFilter('data-mce-type', function (nodes) {
   Arr.each(nodes, function (node) {
     if (node.attr('data-mce-type') === 'format-caret') {
       if (node.isEmpty(htmlParser.schema.getNonEmptyElements())) {
         node.remove();
       } else {
         node.unwrap();
       }
     }
   });
 });
Example #25
0
 const replaceUrlInUndoStack = function (targetUrl: string, replacementUrl: string) {
   Arr.each(editor.undoManager.data, function (level) {
     if (level.type === 'fragmented') {
       level.fragments = Arr.map(level.fragments, function (fragment) {
         return replaceImageUrl(fragment, targetUrl, replacementUrl);
       });
     } else {
       level.content = replaceImageUrl(level.content, targetUrl, replacementUrl);
     }
   });
 };
Example #26
0
      function () {
        removeEmptyRoot(rootNode, fromBlock);

        const position = CaretFinder.lastPositionIn(toBlock.dom());

        Arr.each(children, function (node) {
          Insert.append(toBlock, node);
        });

        return position;
      },
Example #27
0
const fromDom = function (tableElm) {
  const table = tableModel(Replication.shallow(tableElm), 0, []);

  Arr.each(SelectorFilter.descendants(tableElm, 'tr'), function (tr, y) {
    Arr.each(SelectorFilter.descendants(tr, 'td,th'), function (td, x) {
      fillout(table, skipCellsX(table, x, y), y, tr, td);
    });
  });

  return tableModel(table.element(), getWidth(table.rows()), table.rows());
};
Example #28
0
 const createComplex = function (item: HtmlItem | string): Node {
   if (Type.isString(item)) {
     return document.createTextNode(item);
   } else {
     const i = document.createElement(item.n);
     Arr.each(item.cs, (child) => {
       i.appendChild(createComplex(child));
     });
     return i;
   }
 };
const renderInsideInlineCaret = function (isInlineTarget, editor, caret, elms) {
  if (editor.selection.isCollapsed()) {
    const inlines = Arr.filter(elms, isInlineTarget);
    Arr.each(inlines, function (inline) {
      const pos = CaretPosition.fromRangeStart(editor.selection.getRng());
      BoundaryLocation.readLocation(isInlineTarget, editor.getBody(), pos).bind(function (location) {
        return renderCaretLocation(editor, caret, location);
      });
    });
  }
};
Example #30
0
const findAll = (editor: Editor, name: string): Record<string, Element[]> => {
  const body = Element.fromDom(editor.getBody());
  const markers = SelectorFilter.descendants(body, `[${Markings.dataAnnotation()}="${name}"]`);
  const directory: Record<string, Element[]> = { };
  Arr.each(markers, (m) => {
    const uid = Attr.get(m, Markings.dataAnnotationId());
    const nodesAlready = directory.hasOwnProperty(uid) ? directory[uid] : [ ];
    directory[uid] = nodesAlready.concat([ m ]);
  });
  return directory;
};