Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix link command 98 #106

Merged
merged 1 commit into from
Sep 1, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 2 additions & 28 deletions src/js/commands/bold.js
Original file line number Diff line number Diff line change
@@ -1,36 +1,10 @@
import TextFormatCommand from './text-format';
import {
any
} from '../utils/array-utils';

export default class BoldCommand extends TextFormatCommand {
constructor(editor) {
super({
super(editor, {
tag: 'strong',
name: 'bold',
button: '<i class="ck-icon-bold"></i>'
});
this.editor = editor;
const { builder } = this.editor;
this.markup = builder.createMarkup('strong');
}
exec() {
let markerRange = this.editor.cursor.offsets;
if (!markerRange.headSection || !markerRange.tailSection) {
return;
}
let markers = this.editor.run((postEditor) => {
return postEditor.applyMarkupToMarkers(markerRange, this.markup);
});
this.editor.selectMarkers(markers);
}
unexec() {
let markerRange = this.editor.cursor.offsets;
let markers = this.editor.run((postEditor) => {
return postEditor.removeMarkupFromMarkers(markerRange, this.markup);
});
this.editor.selectMarkers(markers);
}
isActive() {
return any(this.editor.activeMarkers, m => m.hasMarkup(this.markup));
}
}
14 changes: 3 additions & 11 deletions src/js/commands/format-block.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,13 @@
import TextFormatCommand from './text-format';
import {
any
} from '../utils/array-utils';
import { any } from '../utils/array-utils';

class FormatBlockCommand extends TextFormatCommand {
constructor(editor, options={}) {
super(options);
this.editor = editor;
super(editor, options);
}

isActive() {
const editor = this.editor;
const activeSections = editor.activeSections;

return any(activeSections, section => {
return any(this.mappedTags, t => section.tagName === t);
});
return any(this.editor.activeSections, s => s.tagName === this.tag);
}

exec() {
Expand Down
29 changes: 2 additions & 27 deletions src/js/commands/italic.js
Original file line number Diff line number Diff line change
@@ -1,36 +1,11 @@
import TextFormatCommand from './text-format';
import {
any
} from '../utils/array-utils';

export default class ItalicCommand extends TextFormatCommand {
constructor(editor) {
super({
super(editor, {
tag: 'em',
name: 'italic',
button: '<i class="ck-icon-italic"></i>'
});
this.editor = editor;
const { builder } = this.editor;
this.markup = builder.createMarkup('em');
}
exec() {
let markerRange = this.editor.cursor.offsets;
if (!markerRange.headSection || !markerRange.tailSection) {
return;
}
let markers = this.editor.run((postEditor) => {
return postEditor.applyMarkupToMarkers(markerRange, this.markup);
});
this.editor.selectMarkers(markers);
}
unexec() {
let markerRange = this.editor.cursor.offsets;
let markers = this.editor.run((postEditor) => {
return postEditor.removeMarkupFromMarkers(markerRange, this.markup);
});
this.editor.selectMarkers(markers);
}
isActive() {
return any(this.editor.activeMarkers, m => m.hasMarkup(this.markup));
}
}
72 changes: 40 additions & 32 deletions src/js/commands/link.js
Original file line number Diff line number Diff line change
@@ -1,38 +1,46 @@
import TextFormatCommand from './text-format';
import Prompt from '../views/prompt';
import { getSelectionTagName } from '../utils/selection-utils';
import { inherit } from 'content-kit-utils';

var RegExpHttp = /^https?:\/\//i;

function LinkCommand() {
TextFormatCommand.call(this, {
name: 'link',
tag: 'a',
action: 'createLink',
removeAction: 'unlink',
button: '<i class="ck-icon-link"></i>',
prompt: new Prompt({
command: this,
placeholder: 'Enter a url, press return...'
})
});
}
inherit(LinkCommand, TextFormatCommand);
import { any } from 'content-kit-editor/utils/array-utils';

export default class LinkCommand extends TextFormatCommand {
constructor(editor) {
super(editor, {
name: 'link',
tag: 'a',
button: '<i class="ck-icon-link"></i>'
});
}

LinkCommand.prototype.exec = function(url) {
if (!url) {
return LinkCommand._super.prototype.unexec.call(this);
isActive() {
return any(this.editor.activeMarkers, m => m.hasMarkup(this.tag));
}

if(this.tag === getSelectionTagName()) {
this.unexec();
} else {
if (!RegExpHttp.test(url)) {
url = 'http://' + url;
}
LinkCommand._super.prototype.exec.call(this, url);
exec(url) {
const range = this.editor.cursor.offsets;

let markers = this.editor.run(postEditor => {
const markup = postEditor.builder.createMarkup('a', ['href', url]);
return postEditor.applyMarkupToMarkers(range, markup);
});

if (markers.length) {
let lastMarker = markers[markers.length - 1];
this.editor.cursor.moveToMarker(lastMarker, lastMarker.length);
} /* else {
// FIXME should handle the case when linking creating no new markers
// this.editor.cursor.moveToSection(range.head.section);
} */
}
};

export default LinkCommand;
unexec() {
const range = this.editor.cursor.offsets;

const markers = this.editor.run(postEditor => {
return postEditor.removeMarkupFromMarkers(
range,
markup => markup.hasTag('a')
);
});

this.editor.selectMarkers(markers);
}
}
3 changes: 1 addition & 2 deletions src/js/commands/list.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import TextFormatCommand from './text-format';

export default class ListCommand extends TextFormatCommand {
constructor(editor, options) {
super(options);
this.editor = editor;
super(editor, options);
}

isActive() {
Expand Down
38 changes: 26 additions & 12 deletions src/js/commands/text-format.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,37 @@
import Command from './base';
import { any } from '../utils/array-utils';

export default class TextFormatCommand extends Command {
constructor(options={}) {
constructor(editor, options={}) {
super(options);

this.editor = editor;
this.tag = options.tag;
this.mappedTags = options.mappedTags || [];
if (this.tag) {
this.mappedTags.push(this.tag);
}
this.action = options.action || this.name;
this.removeAction = options.removeAction || this.action;
}

exec(value) {
document.execCommand(this.action, false, value || null);
get markup() {
if (this._markup) { return this._markup; }
const { builder } = this.editor;
this._markup = builder.createMarkup(this.tag);
return this._markup;
}

isActive() {
return any(this.editor.activeMarkers, m => m.hasMarkup(this.markup));
}

exec() {
const range = this.editor.cursor.offsets;
const markers = this.editor.run((postEditor) => {
return postEditor.applyMarkupToMarkers(range, this.markup);
});
this.editor.selectMarkers(markers);
}

unexec(value) {
document.execCommand(this.removeAction, false, value || null);
unexec() {
const range = this.editor.cursor.offsets;
const markers = this.editor.run((postEditor) => {
return postEditor.removeMarkupFromMarkers(range, this.markup);
});
this.editor.selectMarkers(markers);
}
}
40 changes: 10 additions & 30 deletions src/js/editor/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import EmbedIntent from '../views/embed-intent';
import PostEditor from './post';

import ReversibleToolbarButton from '../views/reversible-toolbar-button';
import ReversiblePromptButton from '../views/reversible-prompt-button';
import BoldCommand from '../commands/bold';
import ItalicCommand from '../commands/italic';
import LinkCommand from '../commands/link';
Expand Down Expand Up @@ -54,10 +55,6 @@ const defaults = {
// causing the stickyToolbar to accidentally be auto-activated
// in tests
stickyToolbar: false, // !!('ontouchstart' in window),
textFormatCommands: [
new LinkCommand()
],
autoTypingCommands: [],
cards: [],
cardOptions: {},
unknownCardHandler: () => {
Expand Down Expand Up @@ -89,25 +86,6 @@ function bindContentEditableTypingListeners(editor) {
});
}

function bindAutoTypingListeners(editor) {
// Watch typing patterns for auto format commands (e.g. lists '- ', '1. ')
editor.addEventListener(editor.element, 'keyup', function(e) {
var commands = editor.autoTypingCommands;
var count = commands && commands.length;
var selection, i;

if (count) {
selection = window.getSelection();
for (i = 0; i < count; i++) {
if (commands[i].checkAutoFormat(selection.anchorNode)) {
e.stopPropagation();
return;
}
}
}
});
}

function bindSelectionEvent(editor) {
/**
* The following events/sequences can create a selection and are handled:
Expand Down Expand Up @@ -193,12 +171,16 @@ function makeButtons(editor) {
const italicCommand = new ItalicCommand(editor);
const italicButton = new ReversibleToolbarButton(italicCommand, editor);

const linkCommand = new LinkCommand(editor);
const linkButton = new ReversiblePromptButton(linkCommand, editor);

return [
headingButton,
subheadingButton,
quoteButton,
boldButton,
italicButton
italicButton,
linkButton
];
}

Expand Down Expand Up @@ -292,23 +274,21 @@ class Editor {
clearChildNodes(element);

bindContentEditableTypingListeners(this);
bindAutoTypingListeners(this);
bindDragAndDrop(this);
bindSelectionEvent(this);
bindKeyListeners(this);
this.addEventListener(element, 'input', () => this.handleInput());

this._initEmbedCommands();

this.addView(new TextFormatToolbar({
this.toolbar = new TextFormatToolbar({
editor: this,
rootElement: element,
// FIXME -- eventually all the commands should migrate to being buttons
// that can be added
commands: this.textFormatCommands,
commands: [],
buttons: makeButtons(this),
sticky: this.stickyToolbar
}));
});
this.addView(this.toolbar);

this.addView(new Tooltip({
rootElement: element,
Expand Down
4 changes: 2 additions & 2 deletions src/js/editor/post.js
Original file line number Diff line number Diff line change
Expand Up @@ -610,10 +610,10 @@ class PostEditor {
* @return {Array} of markers that are inside the split
* @public
*/
removeMarkupFromMarkers(markerRange, markup) {
removeMarkupFromMarkers(markerRange, markupOrMarkupCallback) {
const markers = this.splitMarkers(markerRange);
markers.forEach(marker => {
marker.removeMarkup(markup);
marker.removeMarkup(markupOrMarkupCallback);
marker.section.renderNode.markDirty();
});

Expand Down
21 changes: 19 additions & 2 deletions src/js/models/marker.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import {
} from '../utils/dom-utils';
import {
detect,
commonItemLength
commonItemLength,
forEach,
filter
} from 'content-kit-editor/utils/array-utils';
import LinkedItem from "content-kit-editor/utils/linked-item";

Expand Down Expand Up @@ -50,7 +52,22 @@ const Marker = class Marker extends LinkedItem {
this.markups.push(markup);
}

removeMarkup(markup) {
removeMarkup(markupOrMarkupCallback) {
let callback;
if (typeof markupOrMarkupCallback === 'function') {
callback = markupOrMarkupCallback;
} else {
let markup = markupOrMarkupCallback;
callback = (_markup) => _markup === markup;
}

forEach(
filter(this.markups, callback),
m => this._removeMarkup(m)
);
}

_removeMarkup(markup) {
const index = this.markups.indexOf(markup);
if (index !== -1) {
this.markups.splice(index, 1);
Expand Down
5 changes: 5 additions & 0 deletions src/js/models/markup.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ class Markup {
}
}

hasTag(tagName) {
tagName = normalizeTagName(tagName);
return this.tagName === tagName;
}

static isValidElement(element) {
let tagName = normalizeTagName(element.tagName);
return VALID_MARKUP_TAGNAMES.indexOf(tagName) !== -1;
Expand Down
Loading