// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
// MIT License. See license.txt
/* Inspired from: http://github.com/mindmup/bootstrap-wysiwyg */
// todo
// make it inline friendly
bsEditor = Class.extend({
init: function(options) {
this.options = $.extend(options || {}, this.default_options);
if(this.options.editor) {
this.setup_editor(this.options.editor);
this.setup_fixed_toolbar();
} else if(this.options.parent) {
this.wrapper = $("
<\/div>| )*$/, '');
// remove custom typography (use CSS!)
if(this.options.remove_typography) {
html = html.replace(/(font-family|font-size|line-height):[^;]*;/g, '');
html = html.replace(/<[^>]*(font=['"][^'"]*['"])>/g, function(a,b) { return a.replace(b, ''); });
html = html.replace(/\s*style\s*=\s*["']\s*["']/g, '');
return html;
}
},
init_file_drops: function () {
var me = this;
this.editor.on('dragenter dragover', false)
.on('drop', function (e) {
var dataTransfer = e.originalEvent.dataTransfer;
e.stopPropagation();
e.preventDefault();
if (dataTransfer && dataTransfer.files && dataTransfer.files.length > 0) {
me.insert_files(dataTransfer.files);
}
});
},
insert_files: function (files) {
var me = this;
this.editor.focus();
$.each(files, function (i, file) {
if (/^image\//.test(file.type)) {
me.get_image(file, function(image_url) {
me.toolbar.execCommand('insertimage', image_url);
})
}
});
},
get_image: function (fileobj, callback) {
var freader = new FileReader(),
me = this;
freader.onload = function() {
var dataurl = freader.result;
// add filename to dataurl
var parts = dataurl.split(",");
parts[0] += ";filename=" + fileobj.name;
dataurl = parts[0] + ',' + parts[1];
if(me.options.max_file_size) {
if(dataurl.length > (me.options.max_file_size * 1024 * 1024 * 1.4)) {
bs_get_modal("Upload Error", "Max file size (" + me.options.max_file_size + "M) exceeded.").modal("show");
throw "file size exceeded";
}
}
callback(dataurl);
}
freader.readAsDataURL(fileobj);
},
get_value: function() {
return this.clean_html()
},
set_input: function(value) {
if(this.options.field && this.options.field.inside_change_event)
return;
this.editor.html(value==null ? "" : value);
}
})
bsEditorToolbar = Class.extend({
init: function(options, parent, editor) {
this.options = options;
this.editor = editor;
this.inline = !!parent;
this.options.toolbar_style = $.extend((this.inline ? this.inline_style : this.fixed_style),
this.options.toolbar_style || {});
this.make(parent);
this.toolbar.css(this.options.toolbar_style);
this.setup_image_button();
this.bind_events();
//this.bind_touch();
},
fixed_style: {
position: "fixed",
top: "0px",
padding: "5px",
width: "100%",
height: "45px",
"background-color": "black",
display: "none"
},
inline_style: {
padding: "5px",
},
make: function(parent) {
if(!parent)
parent = $("body");
if(!parent.find(".wn-editor-toolbar").length) {
this.toolbar = $('
\
').prependTo(parent);
if(this.inline) {
this.toolbar.find("[data-action]").remove();
} else {
this.toolbar.find(".btn-toolbar").addClass("container");
}
}
},
setup_image_button: function() {
// magic-overlay
var me = this;
this.file_input = this.toolbar.find('input[type="file"]')
.css({
'opacity':0,
'position':'absolute',
'left':0,
'width':0,
'height':0
});
this.toolbar.find(".btn-insert-img").on("click", function() {
me.file_input.trigger("click");
})
},
show: function() {
var me = this;
this.toolbar.toggle(true);
if(!this.inline) {
$("body").animate({"padding-top": this.toolbar.outerHeight() }, {
complete: function() { me.toolbar.css("z-index", 1001); }
});
}
},
hide: function(action) {
if(!this.editor)
return;
var me = this;
this.toolbar.css("z-index", 0);
if(!this.inline) {
$("body").animate({"padding-top": 0 }, {complete: function() {
me.toolbar.toggle(false);
}});
}
this.editor && this.editor.attr('contenteditable', false).data("object").onhide(action);
this.editor = null;
},
bind_events: function () {
var me = this;
// standard button events
this.toolbar.find('a[data-' + me.options.command_role + ']').click(function () {
me.restore_selection();
me.editor.focus();
me.execCommand($(this).data(me.options.command_role));
me.save_selection();
// close dropdown
if(me.toolbar.find("ul.dropdown-menu:visible").length)
me.toolbar.find('[data-toggle="dropdown"]').dropdown("toggle");
return false;
});
this.toolbar.find('[data-toggle=dropdown]').click(function() { me.restore_selection() });
// link
this.toolbar.find(".btn-add-link").on("click", function() {
if(!window.bs_link_editor) {
window.bs_link_editor = new bsLinkEditor(me);
}
window.bs_link_editor.show();
})
// file event
this.toolbar.find('input[type=file][data-' + me.options.command_role + ']').change(function () {
me.restore_selection();
if (this.type === 'file' && this.files && this.files.length > 0) {
me.editor.data("object").insert_files(this.files);
}
me.save_selection();
this.value = '';
return false;
});
// save
this.toolbar.find("[data-action='Save']").on("click", function() {
me.hide("Save");
})
// cancel
this.toolbar.find("[data-action='Cancel']").on("click", function() {
me.hide("Cancel");
})
// edit html
this.toolbar.find(".btn-html").on("click", function() {
if(!window.bs_html_editor)
window.bs_html_editor = new bsHTMLEditor();
window.bs_html_editor.show(me.editor);
})
},
update: function () {
var me = this;
if (this.toolbar) {
$(this.toolbar).find('.btn[data-' + this.options.command_role + ']').each(function () {
var command = $(this).data(me.options.command_role);
if (document.queryCommandState(command)) {
$(this).addClass(me.options.active_toolbar_class);
} else {
$(this).removeClass(me.options.active_toolbar_class);
}
});
}
},
execCommand: function (commandWithArgs, valueArg) {
var commandArr = commandWithArgs.split(' '),
command = commandArr.shift(),
args = commandArr.join(' ') + (valueArg || '');
document.execCommand(command, 0, args);
this.update();
},
get_current_range: function () {
var sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount) {
return sel.getRangeAt(0);
}
},
save_selection: function () {
this.selected_range = this.get_current_range();
},
restore_selection: function () {
var selection = window.getSelection();
if (this.selected_range) {
selection.removeAllRanges();
selection.addRange(this.selected_range);
}
},
mark_selection: function (input, color) {
this.restore_selection();
document.execCommand('hiliteColor', 0, color || 'transparent');
this.save_selection();
input.data(this.options.selection_marker, color);
},
// bind_touch: function() {
// var me = this;
// $(window).bind('touchend', function (e) {
// var isInside = (me.editor.is(e.target) || me.editor.has(e.target).length > 0),
// current_range = me.get_current_range(),
// clear = current_range && (current_range.startContainer === current_range.endContainer && current_range.startOffset === current_range.endOffset);
// if (!clear || isInside) {
// me.save_selection();
// me.update();
// }
// });
// }
});
bsHTMLEditor = Class.extend({
init: function() {
var me = this;
this.modal = bs_get_modal("
Edit HTML", '
\
');
this.modal.addClass("wn-ignore-click");
this.modal.find(".btn-primary").on("click", function() {
var html = me.modal.find("textarea").val();
$.each(me.editor.dataurls, function(key, val) {
html = html.replace(key, val);
});
var editor = me.editor.data("object")
editor.set_input(html)
editor.options.change && editor.options.change(editor.clean_html());
me.modal.modal("hide");
});
},
show: function(editor) {
var me = this;
this.editor = editor;
this.modal.modal("show")
var html = me.editor.html();
// pack dataurls so that html display is faster
this.editor.dataurls = {}
html = html.replace(/

Insert Link", '
\
\
\
\
\
\
');
this.modal.addClass("wn-ignore-click");
this.modal.find(".btn-primary").on("click", function() {
me.toolbar.restore_selection();
var url = me.modal.find("input[type=text]").val();
var selection = me.toolbar.selected_range.toString();
if(url) {
if(me.modal.find("input[type=checkbox]:checked").length) {
var html = "
" + selection + "";
document.execCommand("insertHTML", false, html);
} else {
document.execCommand("CreateLink", false, url);
}
}
me.modal.modal("hide");
return false;
});
},
show: function() {
this.modal.find("input[type=text]").val("");
this.modal.modal("show");
}
});
bs_get_modal = wn.get_modal;