\
\
-
').prependTo("body");
}
@@ -239,85 +241,84 @@ wn.ui.EditorToolbar = Class.extend({
},
show: function() {
- $("body").animate({"padding-top": this.toolbar.outerHeight() });
+ var me = this;
this.toolbar.toggle(true);
+ $("body").animate({"padding-top": this.toolbar.outerHeight() }, {
+ complete: function() { me.toolbar.css("z-index", 1001); }
+ });
},
hide: function(action) {
- $("body").animate({"padding-top": 0 });
- this.toolbar.toggle(false);
- wn._current_editor.attr('contenteditable', false).data("object").onhide(action);
- wn._current_editor = null;
+ var me = this;
+ this.toolbar.css("z-index", 0);
+ $("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.commandRole + ']').click(function () {
- me.restoreSelection();
- wn._current_editor.focus();
- me.execCommand($(this).data(me.options.commandRole));
- me.saveSelection();
+ 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();
return false;
});
- this.toolbar.find('[data-toggle=dropdown]').click(function() { me.restoreSelection() });
+ this.toolbar.find('[data-toggle=dropdown]').click(function() { me.restore_selection() });
// link
- this.toolbar.find('input[type=text][data-' + this.options.commandRole + ']')
- .on('webkitspeechchange change', function () {
- var newValue = this.value; /* ugly but prevents fake double-calls due to selection restoration */
- this.value = '';
- me.restoreSelection();
- if (newValue) {
- wn._current_editor.focus();
- me.execCommand($(this).data(me.options.commandRole), newValue);
+ this.toolbar.find(".btn-add-link").on("click", function() {
+ if(!wn._link_editor) {
+ wn._link_editor = new wn.ui.LinkEditor();
}
- me.saveSelection();
- return false;
- }).on('focus', function () {
- var input = $(this);
- if (!input.data(me.options.selectionMarker)) {
- me.markSelection(input, me.options.selectionColor);
- input.focus();
- }
- }).on('blur', function () {
- var input = $(this);
- if (input.data(me.options.selectionMarker)) {
- me.markSelection(input, false);
- }
- });
+ wn._link_editor.show();
+ })
// file event
- this.toolbar.find('input[type=file][data-' + me.options.commandRole + ']').change(function () {
- me.restoreSelection();
+ 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) {
- wn._current_editor.data("object").insert_files(this.files);
+ me.editor.data("object").insert_files(this.files);
}
- me.saveSelection();
+ me.save_selection();
this.value = '';
return false;
});
- // cancel
+ // 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(!wn._html_editor)
+ wn._html_editor = new wn.ui.HTMLEditor();
+
+ wn._html_editor.show(me.editor);
+ })
},
update: function () {
var me = this;
- if (this.options.activeToolbarClass) {
- $(this.options.toolbarSelector).find('.btn[data-' + this.options.commandRole + ']').each(function () {
- var command = $(this).data(me.options.commandRole);
+ if (this.options.active_toolbar_class) {
+ $(this.options.toolbar_selector).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.activeToolbarClass);
+ $(this).addClass(me.options.active_toolbar_class);
} else {
- $(this).removeClass(me.options.activeToolbarClass);
+ $(this).removeClass(me.options.active_toolbar_class);
}
});
}
@@ -331,42 +332,119 @@ wn.ui.EditorToolbar = Class.extend({
this.update();
},
- getCurrentRange: function () {
+ get_current_range: function () {
var sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount) {
return sel.getRangeAt(0);
}
},
- saveSelection: function () {
- this.selectedRange = this.getCurrentRange();
+ save_selection: function () {
+ this.selected_range = this.get_current_range();
+ this.selected_html = this.get_current_html();
},
- restoreSelection: function () {
+ get_current_html: function() {
+ var html = "";
+ if (typeof window.getSelection != "undefined") {
+ var sel = window.getSelection();
+ if (sel.rangeCount) {
+ var container = document.createElement("div");
+ for (var i = 0, len = sel.rangeCount; i < len; ++i) {
+ container.appendChild(sel.getRangeAt(i).cloneContents());
+ }
+ html = container.innerHTML;
+ }
+ } else if (typeof document.selection != "undefined") {
+ if (document.selection.type == "Text") {
+ html = document.selection.createRange().htmlText;
+ }
+ }
+ return html;
+ },
+
+ restore_selection: function () {
var selection = window.getSelection();
- if (this.selectedRange) {
+ if (this.selected_range) {
selection.removeAllRanges();
- selection.addRange(this.selectedRange);
+ selection.addRange(this.selected_range);
}
},
- markSelection: function (input, color) {
- this.restoreSelection();
+ mark_selection: function (input, color) {
+ this.restore_selection();
document.execCommand('hiliteColor', 0, color || 'transparent');
- this.saveSelection();
- input.data(this.options.selectionMarker, color);
+ this.save_selection();
+ input.data(this.options.selection_marker, color);
},
bind_touch: function() {
var me = this;
$(window).bind('touchend', function (e) {
- var isInside = (wn._current_editor.is(e.target) || wn._current_editor.has(e.target).length > 0),
- currentRange = me.getCurrentRange(),
- clear = currentRange && (currentRange.startContainer === currentRange.endContainer && currentRange.startOffset === currentRange.endOffset);
+ 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.saveSelection();
+ me.save_selection();
me.update();
}
});
- }
+ }
+});
+
+wn.ui.HTMLEditor = Class.extend({
+ init: function() {
+ var me = this;
+ this.modal = wn.get_modal("Edit HTML", '
\
+
');
+ this.modal.addClass("wn-ignore-click");
+ this.modal.find(".btn-primary").on("click", function() {
+ me.editor.html(me.modal.find("textarea").val());
+ me.modal.modal("hide");
+ });
+ },
+ show: function(editor) {
+ var me = this;
+ this.editor = editor;
+ this.modal.modal("show")
+ this.modal.find("textarea").html(html_beautify(me.editor.html()));
+ }
+});
+
+wn.ui.LinkEditor = Class.extend({
+ init: function() {
+ var me = this;
+ this.modal = wn.get_modal("Edit HTML", '
\
+ \
+
\
+
\
+ \
+
\
+
');
+
+ this.modal.addClass("wn-ignore-click");
+ this.modal.find(".btn-primary").on("click", function() {
+ wn._editor_toolbar.restore_selection();
+ var url = me.modal.find("input[type=text]").val();
+ var selection = wn._editor_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");
+ }
})
\ No newline at end of file
diff --git a/public/js/wn/website/web_page_editable.js b/public/js/wn/website/web_page_editable.js
deleted file mode 100644
index af9132e0a6..0000000000
--- a/public/js/wn/website/web_page_editable.js
+++ /dev/null
@@ -1,33 +0,0 @@
-$(function() {
- $('
').appendTo($("footer.container"))
- $(".editable-button").click(function() {
- if(window.editable) {
- $(".web-page-content").attr("contentEditable", false).removeClass("web-page-editable");
- window.editable = false;
- $(this).html("Edit");
- var html = $(".web-page-content").html() || "";
- 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, '');
- $(".web-page-content").html(html);
-
- wn.call({
- type: "POST",
- method: "webnotes.client.set_value",
- args: {
- doctype:"Web Page",
- name: window.name,
- fieldname: "main_section",
- value: html
- },
- callback: function(r) {
- wn.msgprint(r.exc ? "Error" : "Saved");
- }
- });
- } else {
- $(".web-page-content").attr("contentEditable", true).addClass("web-page-editable").focus();
- $(this).html("Save");
- window.editable = true;
- }
- });
-})
diff --git a/webnotes/model/bean.py b/webnotes/model/bean.py
index b4b6d58490..f16f2ce995 100644
--- a/webnotes/model/bean.py
+++ b/webnotes/model/bean.py
@@ -238,45 +238,6 @@ class Bean:
self.make_controller()
return getattr(self.controller, method, None)
- def save_main(self):
- try:
- self.doc.save(check_links = False, ignore_fields = self.ignore_fields)
- except NameError, e:
- webnotes.msgprint('%s "%s" already exists' % (self.doc.doctype, self.doc.name))
-
- # prompt if cancelled
- if webnotes.conn.get_value(self.doc.doctype, self.doc.name, 'docstatus')==2:
- webnotes.msgprint('[%s "%s" has been cancelled]' % (self.doc.doctype, self.doc.name))
- webnotes.errprint(webnotes.utils.getTraceback())
- raise e
-
- def save_children(self):
- child_map = {}
- for d in self.doclist[1:]:
- if d.fields.get("parent") or d.fields.get("parentfield"):
- d.parent = self.doc.name # rename if reqd
- d.parenttype = self.doc.doctype
-
- d.save(check_links=False, ignore_fields = self.ignore_fields)
-
- child_map.setdefault(d.doctype, []).append(d.name)
-
- # delete all children in database that are not in the child_map
-
- # get all children types
- tablefields = webnotes.model.meta.get_table_fields(self.doc.doctype)
-
- for dt in tablefields:
- if dt[0] not in self.ignore_children_type:
- cnames = child_map.get(dt[0]) or []
- if cnames:
- webnotes.conn.sql("""delete from `tab%s` where parent=%s and parenttype=%s and
- name not in (%s)""" % (dt[0], '%s', '%s', ','.join(['%s'] * len(cnames))),
- tuple([self.doc.name, self.doc.doctype] + cnames))
- else:
- webnotes.conn.sql("""delete from `tab%s` where parent=%s and parenttype=%s""" \
- % (dt[0], '%s', '%s'), (self.doc.name, self.doc.doctype))
-
def insert(self):
self.doc.fields["__islocal"] = 1
@@ -379,6 +340,46 @@ class Bean:
self.no_permission_to(_("Update"))
return self
+
+ def save_main(self):
+ try:
+ self.doc.save(check_links = False, ignore_fields = self.ignore_fields)
+ self.extract_images_from_text_editor()
+ except NameError, e:
+ webnotes.msgprint('%s "%s" already exists' % (self.doc.doctype, self.doc.name))
+
+ # prompt if cancelled
+ if webnotes.conn.get_value(self.doc.doctype, self.doc.name, 'docstatus')==2:
+ webnotes.msgprint('[%s "%s" has been cancelled]' % (self.doc.doctype, self.doc.name))
+ webnotes.errprint(webnotes.utils.getTraceback())
+ raise e
+
+ def save_children(self):
+ child_map = {}
+ for d in self.doclist[1:]:
+ if d.fields.get("parent") or d.fields.get("parentfield"):
+ d.parent = self.doc.name # rename if reqd
+ d.parenttype = self.doc.doctype
+
+ d.save(check_links=False, ignore_fields = self.ignore_fields)
+
+ child_map.setdefault(d.doctype, []).append(d.name)
+
+ # delete all children in database that are not in the child_map
+
+ # get all children types
+ tablefields = webnotes.model.meta.get_table_fields(self.doc.doctype)
+
+ for dt in tablefields:
+ if dt[0] not in self.ignore_children_type:
+ cnames = child_map.get(dt[0]) or []
+ if cnames:
+ webnotes.conn.sql("""delete from `tab%s` where parent=%s and parenttype=%s and
+ name not in (%s)""" % (dt[0], '%s', '%s', ','.join(['%s'] * len(cnames))),
+ tuple([self.doc.name, self.doc.doctype] + cnames))
+ else:
+ webnotes.conn.sql("""delete from `tab%s` where parent=%s and parenttype=%s""" \
+ % (dt[0], '%s', '%s'), (self.doc.name, self.doc.doctype))
def delete(self):
webnotes.delete_doc(self.doc.doctype, self.doc.name)
@@ -426,6 +427,12 @@ class Bean:
doc.fields[df.fieldname] = flt(doc.fields.get(df.fieldname))
doc.docstatus = cint(doc.docstatus)
+
+ def extract_images_from_text_editor(self):
+ from webnotes.utils.file_manager import extract_images_from_html
+ self._files = []
+ for df in self.meta.get({"doctype": "DocField", "parent": self.doc.doctype, "fieldtype":"Text Editor"}):
+ extract_images_from_html(self.doc, df.fieldname)
def clone(source_wrapper):
""" make a clone of a document"""
diff --git a/webnotes/utils/file_manager.py b/webnotes/utils/file_manager.py
index d4b9caa181..787567fc4e 100644
--- a/webnotes/utils/file_manager.py
+++ b/webnotes/utils/file_manager.py
@@ -3,7 +3,7 @@
from __future__ import unicode_literals
import webnotes
-import os, base64
+import os, base64, re
from webnotes.utils import cstr, cint, get_site_path
from webnotes import _
from webnotes import conf
@@ -61,6 +61,25 @@ def get_uploaded_content():
webnotes.msgprint('No File')
return None, None
+def extract_images_from_html(doc, fieldname):
+ content = doc.get(fieldname)
+ webnotes.flags.has_dataurl = False
+
+ def _save_file(match):
+ data = match.group(1)
+ headers, content = data.split(",")
+ filename = headers.split("filename=")[-1]
+ filename = save_file(filename, content, doc.doctype, doc.name, decode=True).get("file_name")
+ if not webnotes.flags.has_dataurl:
+ webnotes.flags.has_dataurl = True
+
+ return '

-
diff --git a/website/js/website.js b/website/js/website.js
index 2f85e6ffde..25246a11d6 100644
--- a/website/js/website.js
+++ b/website/js/website.js
@@ -22,6 +22,18 @@ $.extend(wn, {
}
return parent;
},
+ require: function(url) {
+ $.ajax({
+ url: url + "?q=" + Math.floor(Math.random() * 1000),
+ async: false,
+ dataType: "text",
+ success: function(data) {
+ var el = document.createElement('script');
+ el.appendChild(document.createTextNode(data));
+ document.getElementsByTagName('head')[0].appendChild(el);
+ }
+ });
+ },
hide_message: function(text) {
$('.message-overlay').remove();
},