Skip to content

Instantly share code, notes, and snippets.

@cheeaun
Created October 7, 2010 02:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save cheeaun/614464 to your computer and use it in GitHub Desktop.
Save cheeaun/614464 to your computer and use it in GitHub Desktop.
Facebook's TinyMCE code
function MceEditor() {}
MceEditor.prototype = {
init: function (b, c) {
this.canvasId = b.id;
this.settings = c;
var a = c.plugins;
if (a && a.search('AtD') !== -1) this.settings.atd_rpc_id = $('post_form_id').value;
if (this.is_visible || !this.settings.delay_initialization) this.startEditor();
},
startEditor: function () {
if (!this.settings) {
this.is_visible = true;
return;
}
if (!this.getEditor() && !this.loadingEditor) this.loadingEditor = new AsyncRequest().setURI('/ajax/load_tiny_mce.php').setData({
plugins: this.settings.plugins
}).setHandler(this._loadedTinyMCE.bind(this)).setOption('suppressErrorAlerts', true).send();
},
_loadedTinyMCE: function (c) {
this.settings = copy_properties(c.getPayload(), this.settings);
var b = this.settings.enabled_features || {},
a = b.Blockquote;
copy_properties(this.settings, {
mode: 'exact',
theme: 'facebook',
doctype: '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"' + ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',
valid_elements: 'strong/b,em/i,ol,ul,li,p' + (b.Blockquote ? ',blockquote' : '') + (b.Underline ? ',span[class]' : ''),
elements: this.canvasId,
paste_block_drop: true,
paste_text_sticky: true,
plugins: (this.settings.plugins + ',paste' || 'paste'),
setup: function (f) {
this.mceEditor = f;
var e = this.settings.plugins;
if (e && e.search('AtD') !== -1) Bootloader.loadComponents('text-editor-writing-tips', function () {
this.atd = new TextEditorWritingTips(this, this.settings.atd_typing_pause, this.settings.atd_max_pause);
}.bind(this));
if (this.pendingOnInit) {
for (var d = 0; d < this.pendingOnInit.length; ++d) this.pendingOnInit[d](f);
delete this.pendingOnInit;
}
f.onInit.add(function () {
if (this.pendingOnMceInit) {
var h = this.pendingOnMceInit.length,
g = 0;
for (; g < h; ++g) this.pendingOnMceInit[g]();
this.pendingOnMceInit = null;
}
}.bind(this));
}.bind(this)
});
if (!this.settings.pasteAsPlainText) this.settings.paste_preprocess = function (f, e) {
var d = e.content;
function g(h) {
h.forEach(function (i) {
d = d.replace(i[0], i[1]);
});
}
d = d.replace(/(<pre[^>]*>.*?<\/pre[^>]*>)/gi, function (h) {
h = h.replace(/(<[A-Za-z0-9]*[^>]*>)(.*?<br[^>]*>)/gi, function (i, j, k) {
return j + '<p>' + k + '</p>';
});
h = h.replace(/\s/gi, '&nbsp;');
return h;
});
g([
[/<(div|dl|dt|tr)[^>]*>/gi, '<p>'],
[/<\/(div|dl|dt|tr)[^>]*>/gi, '</p>'],
[/<\/t(d|able)[^>]*>/gi, '\t'],
[/<t(d|able)[^>]*>/gi, ''],
[/<br[^>]*>(\r|\n|\s)*<br[^>]*>/gi, '<p>&nbsp;</p>'],
[/<\/p[^>]*>(\r|\n|\s)*<br[^>]*>/gi, '</p><p>&nbsp;</p>']
]);
e.content = d;
};
if (this.settings.onleavemessage) onbeforeunloadRegister(function () {
var d = this.getEditor();
if (d && d.isDirty()) return this.settings.onleavemessage;
}.bind(this));
Bootloader.loadComponents('tinyMCE', function () {
tinyMCE.init(this.settings);
}.bind(this));
},
addListener: function (event, b) {
var c = event === 'onBlur';
var a = c ?
function () {
tinymce.dom.Event.add(this.mceEditor.getWin(), 'blur', b);
} : function () {
this.mceEditor[event].add(b);
};
this.runOnceAfterInit(a.bind(this), c);
},
runOnceAfterInit: function (b, a) {
if (this.mceEditor) {
b(this.mceEditor);
} else if (a) {
this.pendingOnMceInit = this.pendingOnMceInit || [];
this.pendingOnMceInit.push(b);
} else {
this.pendingOnInit = this.pendingOnInit || [];
this.pendingOnInit.push(b);
}
},
focus: function () {
if (this.mceEditor) tinyMCE.execCommand('mceFocus', false, this.canvasId);
return this;
},
getPlainText: function () {
if (this.mceEditor) return DOM.getText(this.mceEditor.contentDocument.body);
return '';
},
getEditor: function () {
return this.mceEditor;
},
setDirty: function (a) {
this.mceEditor && (this.mceEditor.isNotDirty = !a);
},
getContent: function (a) {
this.setDirty(false);
return this.mceEditor ? this.mceEditor.getContent() : '';
},
setContent: function (a) {
this.runOnceAfterInit(function () {
this.mceEditor.setContent(a);
}.bind(this), true);
},
save: function (a) {
this.runOnceAfterInit(function () {
this.mceEditor.save();
this.setDirty(false);
}.bind(this), true);
},
attachDialogButton: function (a) {
var a = a || Dialog.OK.name;
var b = Dialog.getCurrent();
if (b) a = b.getButtonElement(a);
this.attachButton(a);
},
attachButton: function (a) {
if (a) Event.listen(a, 'mousedown', this.save.bind(this));
}
};
function TextEditor() {
this.parent.construct(this);
}
TextEditor.extend('MceEditor');
TextEditor.prototype = {
init: function (c, a, d) {
this.parent.init(a, d);
this.root = c;
this.buttons = {};
var b = this.settings.enabled_features || {};
if (b.Bold) this.addButton('fbTextEditorBold', 'Bold');
if (b.Italic) this.addButton('fbTextEditorItalic', 'Italic');
if (b.UnorderedList) this.addButton('fbTextEditorUnorderedList', 'InsertUnorderedList');
if (b.OrderedList) this.addButton('fbTextEditorOrderedList', 'InsertOrderedList');
if (b.Underline) {
this.addButton('fbTextEditorUnderline', 'Underline');
this.addListener('onBeforeGetContent', this.setUnderlineClasses.bind(this));
this.addListener('onGetContent', this.unsetUnderlineClasses.bind(this));
}
if (b.Blockquote) this.addButton('fbTextEditorBlockquote', 'mceBlockquote');
Event.listen(DOM.find(this.root, 'div.fbTextEditorToolbar'), 'click', this.onMouseClickToolbar.bind(this));
this.addListener('onEvent', this.updateButtonStates.bind(this));
this.addListener('onChange', this.enableAllButtons.bind(this));
this.runOnceAfterInit(function () {
for (var e in this.buttons) Button.setEnabled(this.buttons[e].domElement, true);
}.bind(this));
this.destroyToken = Arbiter.subscribe('page_transition', this.destroy.bind(this), Arbiter.SUBSCRIBE_NEW);
},
destroy: function (a, b) {
if (a === "page_transition") {
var d = b.uri,
c = d.getQueryData();
if (c && c.keep_objects) return;
}
if (this.mceEditor) this.runOnceAfterInit(function (e) {
tinyMCE.execCommand('mceRemoveControl', false, this.mceEditor.id);
this.mceEditor = null;
}.bind(this));
Arbiter.unsubscribe(this.destroyToken);
},
onMouseClickToolbar: function (b) {
var c = Parent.byClass(b.getTarget(), 'fbEditorButton');
if (c) for (var a in this.buttons) if (CSS.hasClass(c, a)) {
this.onButtonClick(this.buttons[a].tinyMceCommand);
b.kill();
}
},
getRootNode: function () {
return this.root;
},
addButton: function (b, c) {
var a = DOM.scry(this.root, 'label.' + b)[0];
if (!a) return;
this.buttons[b] = {
domElement: a,
tinyMceCommand: c
};
},
updateButtonStates: function () {
for (var a in this.buttons) {
var b = this.buttons[a];
CSS.conditionClass(b.domElement, 'uiButtonDepressed', this.getEditor().queryCommandState(b.tinyMceCommand));
}
},
enableAllButtons: function () {
var b = DOM.scry(this.root, 'label.uiButtonDisabled');
for (var a = 0; a < b.length; a++) Button.setEnabled(b[a], true);
},
onButtonClick: function (a) {
this.getEditor().execCommand(a);
this.updateButtonStates();
},
setUnderlineClasses: function (c, d) {
if (d && d.save) {
var b = $A(c.getBody().getElementsByTagName('span')),
a = [];
b.forEach(function (e) {
if (e.style.textDecoration === "underline") {
CSS.addClass(e, 'fbUnderline');
a.push[e];
}
});
this.array_modified_spans = a;
}
},
unsetUnderlineClasses: function () {
if (this.array_modified_spans) {
this.array_modified_spans.forEach(function (a) {
CSS.removeClass(a, 'fbUnderline');
});
this.array_modified_spans = null;
}
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment