// 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 += '
' html += '
' html += '' html += '' html += '' html += '' html += '' // MI: Add Markdown notice. html += '
' html += 'Markdown is used for formatting. More info' 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