// The following are instance methods and variables
var Note = Class.create({
initialize: function(id, is_new, raw_body) {
if (Note.debug) {
console.debug("Note#initialize (id=%d)", id)
}
this.id = id
this.is_new = is_new
this.document_observers = [];
// Cache the elements
this.elements = {
box: $('note-box-' + this.id),
corner: $('note-corner-' + this.id),
body: $('note-body-' + this.id),
image: $('image')
}
// Cache the dimensions
this.fullsize = {
left: this.elements.box.offsetLeft,
top: this.elements.box.offsetTop,
width: this.elements.box.clientWidth,
height: this.elements.box.clientHeight
}
// Store the original values (in case the user clicks Cancel)
this.old = {
raw_body: raw_body,
formatted_body: this.elements.body.innerHTML
}
for (p in this.fullsize) {
this.old[p] = this.fullsize[p]
}
// Make the note translucent
if (is_new) {
this.elements.box.setOpacity(0.2)
} else {
this.elements.box.setOpacity(0.5)
}
if (is_new && raw_body == '') {
this.bodyfit = true
this.elements.body.style.height = "100px"
}
// Attach the event listeners
this.elements.box.observe("mousedown", this.dragStart.bindAsEventListener(this))
this.elements.box.observe("mouseout", this.bodyHideTimer.bindAsEventListener(this))
this.elements.box.observe("mouseover", this.bodyShow.bindAsEventListener(this))
this.elements.corner.observe("mousedown", this.resizeStart.bindAsEventListener(this))
this.elements.body.observe("mouseover", this.bodyShow.bindAsEventListener(this))
this.elements.body.observe("mouseout", this.bodyHideTimer.bindAsEventListener(this))
this.elements.body.observe("click", this.showEditBox.bindAsEventListener(this))
this.adjustScale()
if (Note.drag_created) {
var t = this,
C,
called = false
B = function(e) {
if (called) {
C()
} else {
called = true
t._resize(e.pageX, e.pageY)
}
}
C = function() {
jQuery(document).unbind('mousemove', B)
}
jQuery(document).bind('mousemove', B)
}
},
// Returns the raw text value of this note
textValue: function() {
if (Note.debug) {
console.debug("Note#textValue (id=%d)", this.id)
}
return this.old.raw_body.strip()
},
// Removes the edit box
hideEditBox: function(e) {
if (Note.debug) {
console.debug("Note#hideEditBox (id=%d)", this.id)
}
var editBox = $('edit-box')
if (editBox != null) {
var boxid = editBox.noteid
$("edit-box").stopObserving()
$("note-save-" + boxid).stopObserving()
$("note-cancel-" + boxid).stopObserving()
$("note-remove-" + boxid).stopObserving()
$("note-history-" + boxid).stopObserving()
$("edit-box").remove()
}
},
// Shows the edit box
showEditBox: function(e) {
if (Note.debug) {
console.debug("Note#showEditBox (id=%d)", this.id)
}
this.hideEditBox(e)
var insertionPosition = Note.getInsertionPosition()
var top = insertionPosition[0]
var left = insertionPosition[1]
var html = ""
html += '
'
$("note-container").insert({bottom: html})
$('edit-box').noteid = this.id
$("edit-box").observe("mousedown", this.editDragStart.bindAsEventListener(this))
$("note-save-" + this.id).observe("click", this.save.bindAsEventListener(this))
$("note-cancel-" + this.id).observe("click", this.cancel.bindAsEventListener(this))
$("note-remove-" + this.id).observe("click", this.remove.bindAsEventListener(this))
$("note-history-" + this.id).observe("click", this.history.bindAsEventListener(this))
$("edit-box-text").focus()
Note.active_note = this
Note.bindEditShortcuts()
},
// Shows the body text for the note
bodyShow: function(e) {
if (Note.debug) {
console.debug("Note#bodyShow (id=%d)", this.id)
}
if (this.dragging) {
return
}
if (this.hideTimer) {
clearTimeout(this.hideTimer)
this.hideTimer = null
}
if (Note.noteShowingBody == this) {
return
}
if (Note.noteShowingBody) {
Note.noteShowingBody.bodyHide()
}
Note.noteShowingBody = this
if (Note.zindex >= 9) {
/* don't use more than 10 layers (+1 for the body, which will always be above all notes) */
Note.zindex = 0
for (var i=0; i< Note.all.length; ++i) {
Note.all[i].elements.box.style.zIndex = 0
}
}
this.elements.box.style.zIndex = ++Note.zindex
this.elements.body.style.zIndex = 10
this.elements.body.style.top = 0 + "px"
this.elements.body.style.left = 0 + "px"
var dw = document.documentElement.scrollWidth
this.elements.body.style.visibility = "hidden"
this.elements.body.style.display = "block"
if (!this.bodyfit) {
this.elements.body.style.height = "auto"
this.elements.body.style.minWidth = "140px"
var w = null, h = null, lo = null, hi = null, x = null, last = null
w = this.elements.body.offsetWidth
h = this.elements.body.offsetHeight
if (w/h < 1.6180339887) {
/* for tall notes (lots of text), find more pleasant proportions */
lo = 140, hi = 400
do {
last = w
x = (lo+hi)/2
this.elements.body.style.minWidth = x + "px"
w = this.elements.body.offsetWidth
h = this.elements.body.offsetHeight
if (w/h < 1.6180339887) lo = x
else hi = x
} while ((lo < hi) && (w > last))
} else if (this.elements.body.scrollWidth <= this.elements.body.clientWidth) {
/* for short notes (often a single line), make the box no wider than necessary */
// scroll test necessary for Firefox
lo = 20, hi = w
do {
x = (lo+hi)/2
this.elements.body.style.minWidth = x + "px"
if (this.elements.body.offsetHeight > h) lo = x
else hi = x
} while ((hi - lo) > 4)
if (this.elements.body.offsetHeight > h)
this.elements.body.style.minWidth = hi + "px"
}
if (Prototype.Browser.IE) {
// IE7 adds scrollbars if the box is too small, obscuring the text
if (this.elements.body.offsetHeight < 35) {
this.elements.body.style.minHeight = "35px"
}
if (this.elements.body.offsetWidth < 47) {
this.elements.body.style.minWidth = "47px"
}
}
this.bodyfit = true
}
this.elements.body.style.top = (this.elements.box.offsetTop + this.elements.box.clientHeight + 5) + "px"
// keep the box within the document's width
var l = 0, e = this.elements.box
do { l += e.offsetLeft } while (e = e.offsetParent)
l += this.elements.body.offsetWidth + 10 - dw
if (l > 0)
this.elements.body.style.left = this.elements.box.offsetLeft - l + "px"
else
this.elements.body.style.left = this.elements.box.offsetLeft + "px"
this.elements.body.style.visibility = "visible"
},
// Creates a timer that will hide the body text for the note
bodyHideTimer: function(e) {
if (Note.debug) {
console.debug("Note#bodyHideTimer (id=%d)", this.id)
}
this.hideTimer = setTimeout(this.bodyHide.bindAsEventListener(this), 250)
},
// Hides the body text for the note
bodyHide: function(e) {
if (Note.debug) {
console.debug("Note#bodyHide (id=%d)", this.id)
}
this.elements.body.hide()
if (Note.noteShowingBody == this) {
Note.noteShowingBody = null
}
},
addDocumentObserver: function(name, func)
{
document.observe(name, func);
this.document_observers.push([name, func]);
},
clearDocumentObservers: function(name, handler)
{
for(var i = 0; i < this.document_observers.length; ++i)
{
var observer = this.document_observers[i];
document.stopObserving(observer[0], observer[1]);
}
this.document_observers = [];
},
// Start dragging the note
dragStart: function(e) {
if (Note.debug) {
console.debug("Note#dragStart (id=%d)", this.id)
}
this.addDocumentObserver("mousemove", this.drag.bindAsEventListener(this))
this.addDocumentObserver("mouseup", this.dragStop.bindAsEventListener(this))
this.addDocumentObserver("selectstart", function() {return false})
this.cursorStartX = e.pointerX()
this.cursorStartY = e.pointerY()
this.boxStartX = this.elements.box.offsetLeft
this.boxStartY = this.elements.box.offsetTop
this.boundsX = new ClipRange(5, this.elements.image.clientWidth - this.elements.box.clientWidth - 5)
this.boundsY = new ClipRange(5, this.elements.image.clientHeight - this.elements.box.clientHeight - 5)
this.dragging = true
this.bodyHide()
},
// Stop dragging the note
dragStop: function(e) {
if (Note.debug) {
console.debug("Note#dragStop (id=%d)", this.id)
}
this.clearDocumentObservers()
this.cursorStartX = null
this.cursorStartY = null
this.boxStartX = null
this.boxStartY = null
this.boundsX = null
this.boundsY = null
this.dragging = false
this.bodyShow()
},
ratio: function() {
return this.elements.image.width / this.elements.image.getAttribute("large_width")
// var ratio = this.elements.image.width / this.elements.image.getAttribute("large_width")
// if (this.elements.image.scale_factor != null)
// ratio *= this.elements.image.scale_factor;
// return ratio
},
// Scale the notes for when the image gets resized
adjustScale: function() {
if (Note.debug) {
console.debug("Note#adjustScale (id=%d)", this.id)
}
var ratio = this.ratio()
for (p in this.fullsize) {
this.elements.box.style[p] = this.fullsize[p] * ratio + 'px'
}
},
// Update the note's position as it gets dragged
drag: function(e) {
var left = this.boxStartX + e.pointerX() - this.cursorStartX
var top = this.boxStartY + e.pointerY() - this.cursorStartY
left = this.boundsX.clip(left)
top = this.boundsY.clip(top)
this.elements.box.style.left = left + 'px'
this.elements.box.style.top = top + 'px'
var ratio = this.ratio()
this.fullsize.left = left / ratio
this.fullsize.top = top / ratio
e.stop()
},
// Start dragging the edit box
editDragStart: function(e) {
if (Note.debug) {
console.debug("Note#editDragStart (id=%d)", this.id)
}
var node = e.element().nodeName
if (node != 'FORM' && node != 'DIV') {
return
}
this.addDocumentObserver("mousemove", this.editDrag.bindAsEventListener(this))
this.addDocumentObserver("mouseup", this.editDragStop.bindAsEventListener(this))
this.addDocumentObserver("selectstart", function() {return false})
this.elements.editBox = $('edit-box');
this.cursorStartX = e.pointerX()
this.cursorStartY = e.pointerY()
this.editStartX = this.elements.editBox.offsetLeft
this.editStartY = this.elements.editBox.offsetTop
this.dragging = true
},
// Stop dragging the edit box
editDragStop: function(e) {
if (Note.debug) {
console.debug("Note#editDragStop (id=%d)", this.id)
}
this.clearDocumentObservers()
this.cursorStartX = null
this.cursorStartY = null
this.editStartX = null
this.editStartY = null
this.dragging = false
},
// Update the edit box's position as it gets dragged
editDrag: function(e) {
var left = this.editStartX + e.pointerX() - this.cursorStartX
var top = this.editStartY + e.pointerY() - this.cursorStartY
this.elements.editBox.style.left = left + 'px'
this.elements.editBox.style.top = top + 'px'
e.stop()
},
_resize: function(cursorX, cursorY) {
if (Note.debug) {
console.debug("Note#_resize (id=%d)", this.id)
}
this.cursorStartX = cursorX
this.cursorStartY = cursorY
this.boxStartWidth = this.elements.box.clientWidth
this.boxStartHeight = this.elements.box.clientHeight
this.boxStartX = this.elements.box.offsetLeft
this.boxStartY = this.elements.box.offsetTop
this.boundsX = new ClipRange(10, this.elements.image.clientWidth - this.boxStartX - 5)
this.boundsY = new ClipRange(10, this.elements.image.clientHeight - this.boxStartY - 5)
this.dragging = true
this.clearDocumentObservers()
this.addDocumentObserver("mousemove", this.resize.bindAsEventListener(this))
this.addDocumentObserver("mouseup", this.resizeStop.bindAsEventListener(this))
this.bodyHide()
},
// Start resizing the note
resizeStart: function(e) {
e.stop()
this._resize(e.pointerX(), e.pointerY())
},
// Stop resizing teh note
resizeStop: function(e) {
if (Note.debug) {
console.debug("Note#resizeStop (id=%d)", this.id)
}
this.clearDocumentObservers()
this.boxCursorStartX = null
this.boxCursorStartY = null
this.boxStartWidth = null
this.boxStartHeight = null
this.boxStartX = null
this.boxStartY = null
this.boundsX = null
this.boundsY = null
this.dragging = false
e.stop()
if (Note.drag_created) {
this.old.width = this.fullsize.width
this.old.height = this.fullsize.height
// Note.toggled_create = false
Note.drag_created = false
this.showEditBox({})
}
},
// Update the note's dimensions as it gets resized
resize: function(e) {
if (Note.debug) {
console.debug("Note#resize (id=%d)", this.id)
}
var width = this.boxStartWidth + e.pointerX() - this.cursorStartX
var height = this.boxStartHeight + e.pointerY() - this.cursorStartY
width = this.boundsX.clip(width)
height = this.boundsY.clip(height)
this.elements.box.style.width = width + "px"
this.elements.box.style.height = height + "px"
var ratio = this.ratio()
this.fullsize.width = width / ratio
this.fullsize.height = height / ratio
e.stop()
},
// Save the note to the database
save: function(e) {
if (Note.debug) {
console.debug("Note#save (id=%d)", this.id)
}
var note = this
for (p in this.fullsize) {
this.old[p] = this.fullsize[p]
}
this.old.raw_body = $('edit-box-text').value
this.old.formatted_body = this.textValue()
// FIXME: this is not quite how the note will look (filtered elems, ...). the user won't input a