596 lines
12 KiB
JavaScript
596 lines
12 KiB
JavaScript
cdb.admin.overlays.Code = cdb.core.View.extend({
|
|
|
|
className: "code overlay",
|
|
|
|
template_name: 'table/views/overlays/code',
|
|
|
|
events: {
|
|
|
|
"mouseup": "_onMouseUp",
|
|
"mousedown": "_onMouseDown",
|
|
|
|
"mouseenter .text": "_onMouseEnter",
|
|
"mouseleave .text": "_onMouseLeave",
|
|
|
|
"click .close": "_close",
|
|
"click .content": "_click",
|
|
"dblclick .content": "_dblClick",
|
|
|
|
"keyup .text": "_onKeyUp",
|
|
"click .text": "_killEvent",
|
|
"paste .text": "_onPaste"
|
|
|
|
},
|
|
|
|
initialize: function() {
|
|
|
|
_.bindAll(this, "_click", "_close", "_dblClick", "_onChangeMode", "_onKeyDown", "_putOnTop");
|
|
|
|
// Bind ESC key
|
|
$(document).bind('keydown', this._onKeyDown);
|
|
|
|
this.template = this.getTemplate(this.template_name);
|
|
|
|
this._setupModels();
|
|
|
|
},
|
|
|
|
_killEvent: function(e) {
|
|
|
|
e && e.preventDefault();
|
|
e && e.stopPropagation();
|
|
|
|
},
|
|
|
|
// Setup the internal and custom model
|
|
_setupModels: function() {
|
|
|
|
var extra = this.model.get("extra");
|
|
|
|
this.model.set({ text: extra.text }, { silent: true });
|
|
|
|
// Binding
|
|
this.model.bind('change:text', this._setText, this);
|
|
this.model.bind('change:style', this._applyStyle, this);
|
|
this.model.bind('change:display', this._onChangeDisplay, this);
|
|
this.model.bind('change:extra', this._onChangeExtra, this);
|
|
|
|
// Internal model to store the editing state
|
|
this.editModel = new cdb.core.Model({ mode: "" });
|
|
this.editModel.bind('change:mode', this._onChangeMode, this);
|
|
|
|
this.add_related_model(this.editModel);
|
|
|
|
},
|
|
|
|
// Element events
|
|
_onKeyUp: function(e) {
|
|
|
|
var self = this;
|
|
|
|
var temp = "";
|
|
var domString = "";
|
|
|
|
if (this.timeout) clearTimeout(this.timeout);
|
|
if (this.keyUpTimeout) clearTimeout(this.keyUpTimeout);
|
|
if (this.savingTimeout) clearTimeout(this.savingTimeout);
|
|
|
|
var value = this.$text.html();
|
|
|
|
if (cdb.Utils.stripHTML(value) == "") {
|
|
|
|
this.keyUpTimeout = setTimeout(function() {
|
|
|
|
self.model.set({ text: "" }, { silent: true });
|
|
self._close();
|
|
|
|
}, 600);
|
|
|
|
} else {
|
|
|
|
this.model.set({ text: value }, { silent: true });
|
|
|
|
if (!this.$el.hasClass("hover") && this.$text.text()) {
|
|
this.savingTimeout = setTimeout(function() {
|
|
|
|
self._disableEditingMode();
|
|
|
|
}, 500);
|
|
}
|
|
}
|
|
|
|
},
|
|
|
|
_dblClick: function(e) {
|
|
|
|
this._killEvent(e);
|
|
|
|
},
|
|
|
|
_click: function(e) {
|
|
|
|
this._killEvent(e);
|
|
|
|
this._putOnTop();
|
|
|
|
var isLink = e.target.hasAttribute("href");
|
|
|
|
if (!isLink) {
|
|
cdb.god.trigger("closeDialogs");
|
|
}
|
|
|
|
},
|
|
|
|
_onKeyDown: function(e) {
|
|
|
|
if (e.keyCode === 27) {
|
|
this.editModel.set("mode", "");
|
|
}
|
|
|
|
},
|
|
|
|
_onPaste: function(e) {
|
|
|
|
var self = this;
|
|
|
|
setTimeout(function() {
|
|
|
|
var text = cdb.Utils.stripHTML(self.model.get("text"));
|
|
self.model.set("text", text)
|
|
|
|
}, 200);
|
|
|
|
},
|
|
|
|
_onMouseUp: function(e) {
|
|
|
|
// Prevents entering in the edit mode when clicking the edit button
|
|
if (!$(e.target).parents(".overlay_text").length && !$(e.target).hasClass("overlay_text")) {
|
|
return;
|
|
}
|
|
|
|
cdb.god.trigger("closeDialogs");
|
|
|
|
var extra = this.model.get("extra");
|
|
|
|
var x = this.model.get("x");
|
|
var y = this.model.get("y");
|
|
|
|
var oldX = this.$el.position().left;
|
|
var oldY = this.$el.position().top;
|
|
|
|
var portraitDirection = extra.portraitDirection;
|
|
var landscapeDirection = extra.landscapeDirection;
|
|
|
|
if (y == 0 && portraitDirection == "bottom") oldY = y;
|
|
if (x == 0 && landscapeDirection == "right") oldX = x;
|
|
|
|
// If we didn't move the overlay
|
|
if (oldX === x && y === oldY || x == 0 && landscapeDirection == "right" && y === oldY || y == 0 && portraitDirection == "bottom" && oldX === x) {
|
|
|
|
this.dropdown.hide();
|
|
this.editModel.set("mode", "editable");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
var x = this.$el.position().left;
|
|
var y = this.$el.position().top;
|
|
|
|
// Default positions
|
|
extra.portraitDirection = "top";
|
|
extra.landscapeDirection = "left";
|
|
|
|
// Let's see where did we put our overlay…
|
|
var rightSticked = x + this.$el.width() >= $(".cartodb-map").width();
|
|
var bottomSticked = y + this.$el.height() >= $(".cartodb-map").height();
|
|
|
|
if (bottomSticked) { // we sticked the overlay to the bottom of the screen
|
|
|
|
y = 0;
|
|
|
|
this.$el.css({ bottom: 0, top: "auto" });
|
|
|
|
extra.portraitDirection = "bottom";
|
|
|
|
}
|
|
|
|
if (rightSticked) { // we sticked the overlay to the right side
|
|
|
|
x = 0;
|
|
|
|
this.$el.css({ right: 0, left: "auto" });
|
|
|
|
extra.landscapeDirection = "right";
|
|
|
|
}
|
|
|
|
this.model.set({ extra: extra }, { silent: true});
|
|
this.model.set({ x: x, y: y });
|
|
|
|
this.model.save();
|
|
|
|
},
|
|
|
|
_onMouseDown: function() { },
|
|
|
|
_onMouseEnter: function() {
|
|
|
|
this.$el.addClass("hover");
|
|
if (this.editModel.get("mode") == "editable") {
|
|
if (this.timeout) clearTimeout(this.timeout);
|
|
}
|
|
|
|
},
|
|
|
|
_onMouseLeave: function() {
|
|
this.$el.removeClass("hover");
|
|
|
|
var self = this;
|
|
|
|
if (this.editModel.get("mode") == "editable") {
|
|
|
|
this.timeout = setTimeout(function() {
|
|
|
|
self.editModel.set("mode", "");
|
|
|
|
}, 250);
|
|
}
|
|
|
|
},
|
|
|
|
show: function(animated) {
|
|
|
|
this.$el.show();
|
|
|
|
if (true) this.$el.addClass('animated bounceIn');
|
|
|
|
},
|
|
|
|
hide: function(callback) {
|
|
|
|
var self = this;
|
|
|
|
this.$el
|
|
.removeClass('animated bounceIn')
|
|
.addClass('animated bounceOut');
|
|
|
|
callback && callback();
|
|
|
|
// Give it some time to complete the animation
|
|
setTimeout(function() {
|
|
self.clean();
|
|
}, 550);
|
|
|
|
},
|
|
|
|
_close: function(e) {
|
|
|
|
this._killEvent(e);
|
|
|
|
var self = this;
|
|
|
|
this.dropdown.hide();
|
|
this.dropdown.clean();
|
|
|
|
this.hide(function() {
|
|
self.trigger("remove", self);
|
|
});
|
|
|
|
},
|
|
|
|
_onChangeDisplay: function() {
|
|
|
|
var display = this.model.get("display");
|
|
|
|
if (display) {
|
|
this.show();
|
|
} else {
|
|
this.$el.hide();
|
|
}
|
|
|
|
},
|
|
|
|
_onChangeExtra: function() {
|
|
|
|
var extra = this.model.get("extra");
|
|
extra.text = this.model.get("text");
|
|
|
|
this.model.set({ extra: extra }, { silent: true });
|
|
|
|
},
|
|
|
|
/*
|
|
* Applies style to the content of the widget
|
|
*/
|
|
|
|
_applyStyle: function() {
|
|
|
|
var style = this.model.get("style");
|
|
|
|
var boxColor = style["box-color"];
|
|
var boxOpacity = style["box-opacity"];
|
|
var boxWidth = style["box-width"];
|
|
var fontFamily = style["font-family-name"];
|
|
|
|
this.$text.css(style);
|
|
this.$text.css("font-size", style["font-size"] + "px");
|
|
|
|
var rgbaCol = 'rgba(' + parseInt(boxColor.slice(-6,-4),16)
|
|
+ ',' + parseInt(boxColor.slice(-4,-2),16)
|
|
+ ',' + parseInt(boxColor.slice(-2),16)
|
|
+', ' + boxOpacity + ' )';
|
|
|
|
this.$el.css("background-color", rgbaCol);
|
|
this.$el.css("max-width", boxWidth);
|
|
|
|
var fontFamilyClass = "";
|
|
|
|
if (fontFamily == "Droid Sans") fontFamilyClass = "droid";
|
|
else if (fontFamily == "Vollkorn") fontFamilyClass = "vollkorn";
|
|
else if (fontFamily == "Open Sans") fontFamilyClass = "open_sans";
|
|
else if (fontFamily == "Roboto") fontFamilyClass = "roboto";
|
|
|
|
this.$el.css("width", "auto");
|
|
|
|
this.$el
|
|
.removeClass("droid")
|
|
.removeClass("vollkorn")
|
|
.removeClass("roboto")
|
|
.removeClass("open_sans");
|
|
|
|
this.$el.addClass(fontFamilyClass);
|
|
|
|
},
|
|
|
|
_onChangeMode: function() {
|
|
|
|
var mode = this.editModel.get("mode");
|
|
|
|
if (mode == "editable") {
|
|
|
|
this._enableEditingMode();
|
|
|
|
} else {
|
|
|
|
this._disableEditingMode();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
_enableEditingMode: function() {
|
|
|
|
var text = this.model.get("text");
|
|
|
|
this.$el
|
|
.addClass("editable")
|
|
.addClass("disabled");
|
|
|
|
this.$text.attr("contenteditable", true).focus();
|
|
|
|
this.$el.css("width", "auto");
|
|
|
|
var self = this;
|
|
|
|
setTimeout(function() {
|
|
self.$text.html(text);
|
|
}, 100)
|
|
|
|
},
|
|
|
|
_disableEditingMode: function() {
|
|
|
|
var text = this._transformToMarkdown(this.model.get("text"));
|
|
|
|
this.editModel.set("mode", "");
|
|
|
|
if (text) {
|
|
|
|
this.$text.html(text);
|
|
|
|
this.$el
|
|
.removeClass("editable")
|
|
.removeClass("disabled");
|
|
|
|
this.$text.attr("contenteditable", false);
|
|
this.$el.css("width", "auto");
|
|
|
|
var self = this;
|
|
|
|
setTimeout(function() {
|
|
var width = self.$el.width();
|
|
self.$el.css("width", width);
|
|
}, 300);
|
|
|
|
this.model.save();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
_setText: function() {
|
|
|
|
var text = this.model.get("text");
|
|
var rendered_text = this._transformToMarkdown(text);
|
|
|
|
var extra = this.model.get("extra");
|
|
|
|
extra.text = text;
|
|
extra.rendered_text = rendered_text
|
|
|
|
this.model.set({ extra: extra }, { silent: true });
|
|
|
|
if (rendered_text) this.$text.html(rendered_text);
|
|
|
|
},
|
|
|
|
_transformToMarkdown: function(text) {
|
|
|
|
console.log(text)
|
|
//return "code" + "<script>" + text + "</script>";
|
|
return "code";
|
|
|
|
},
|
|
|
|
_addDropdown: function() {
|
|
|
|
var device = this.model.get("device");
|
|
var horizontal_offset = 26;
|
|
var vertical_offset = 24;
|
|
|
|
if (device === "mobile") {
|
|
vertical_offset -= $("header").height() + 12;
|
|
}
|
|
|
|
this.dropdown = new cdb.admin.WidgetPropertiesDropdown({
|
|
tick: "left",
|
|
target: this.$el.find(".edit"),
|
|
model: this.model,
|
|
offset_mode: device === 'mobile' ? "offset" : "position",
|
|
horizontal_position: "left",
|
|
horizontal_offset: horizontal_offset,
|
|
vertical_offset: vertical_offset,
|
|
template_base: 'table/views/overlays/properties_dropdown',
|
|
form_data: [{
|
|
name: 'Text Align',
|
|
form: {
|
|
'text-align': { type: 'text_align', value: 'left' },
|
|
}
|
|
}, {
|
|
name: 'Text Style',
|
|
form: {
|
|
'font-size': { type: 'simple_number', value: 12, min: 5, max: 50, inc: 2 },
|
|
'color': { type: 'color', value: '#FFF' },
|
|
}
|
|
|
|
}, {
|
|
name: 'Font',
|
|
form: {
|
|
'font-family-name': {
|
|
type: 'select',
|
|
value: "Helvetica",
|
|
extra: ["Helvetica", "Droid Sans", "Vollkorn", "Roboto", "Open Sans"]
|
|
}
|
|
}
|
|
}, {
|
|
|
|
name: 'Box Style',
|
|
form: {
|
|
'box-color': { type: 'color', value: '#000' },
|
|
'box-opacity': { type: 'simple_opacity', value: .7, min:0, max:1, inc: .1 },
|
|
}
|
|
|
|
}, {
|
|
name: 'Max Width',
|
|
form: {
|
|
'box-width': { type: 'simple_number', value: 300, min: 50, max: 2000, inc: 10 },
|
|
}
|
|
|
|
}]
|
|
});
|
|
|
|
this._bindDropdown();
|
|
|
|
var self = this;
|
|
|
|
this.dropdown.on("saved", function() {
|
|
self.dropdown.move(true);
|
|
});
|
|
|
|
if (this.model.get("device") == "mobile") {
|
|
$(".map").append(this.dropdown.render().el);
|
|
} else {
|
|
this.$el.append(this.dropdown.render().el);
|
|
}
|
|
|
|
},
|
|
|
|
_bindDropdown: function() {
|
|
|
|
this.dropdown.bind("onDropdownShown", function() {
|
|
this.$el.addClass("open");
|
|
|
|
this._putOnTop();
|
|
|
|
}, this);
|
|
|
|
this.dropdown.bind("onDropdownHidden", function() {
|
|
this.$el.removeClass("open");
|
|
}, this);
|
|
|
|
cdb.god.bind("closeDialogs", this.dropdown.hide, this.dropdown);
|
|
|
|
},
|
|
|
|
_putOnTop: function() {
|
|
|
|
$(".overlay").css("z-index", 999);
|
|
this.$el.css("z-index", 2001);
|
|
|
|
},
|
|
|
|
_place: function() {
|
|
|
|
var landscapeDirection = this.model.get("extra").landscapeDirection;
|
|
var portraitDirection = this.model.get("extra").portraitDirection;
|
|
|
|
if (portraitDirection == 'bottom') {
|
|
|
|
this.$el.offset({
|
|
top: this.model.get("y")
|
|
});
|
|
|
|
this.$el.css({
|
|
top: "auto",
|
|
bottom: this.model.get("y")
|
|
});
|
|
|
|
} else {
|
|
this.$el.offset({
|
|
top: this.model.get("y")
|
|
});
|
|
}
|
|
|
|
if (landscapeDirection == 'right') {
|
|
|
|
this.$el.offset({
|
|
left: this.model.get("x")
|
|
});
|
|
|
|
this.$el.css({
|
|
left: "auto",
|
|
right: this.model.get("x")
|
|
});
|
|
|
|
} else {
|
|
this.$el.offset({
|
|
left: this.model.get("x")
|
|
});
|
|
}
|
|
|
|
},
|
|
|
|
render: function() {
|
|
|
|
this._place();
|
|
|
|
this.$el.append(this.template(this.model.attributes));
|
|
|
|
this.$text = this.$el.find(".content div.text");
|
|
|
|
var text = this._transformToMarkdown(this.model.get("text"));
|
|
|
|
this.$text.html(text);
|
|
|
|
this._applyStyle();
|
|
this._onChangeExtra();
|
|
this._addDropdown();
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
});
|