mirror of
https://github.com/wassname/fullcalendar.git
synced 2026-08-02 12:40:14 +08:00
merged refactor148, resolved conflicts
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
|
||||
function CoordinateGrid(buildFunc) {
|
||||
|
||||
var t = this;
|
||||
var rows;
|
||||
var cols;
|
||||
|
||||
t.build = function() {
|
||||
rows = [];
|
||||
cols = [];
|
||||
buildFunc(rows, cols);
|
||||
};
|
||||
|
||||
t.cell = function(x, y) {
|
||||
var rowCnt = rows.length;
|
||||
var colCnt = cols.length;
|
||||
var i, r=-1, c=-1;
|
||||
for (i=0; i<rowCnt; i++) {
|
||||
if (y >= rows[i][0] && y < rows[i][1]) {
|
||||
r = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (i=0; i<colCnt; i++) {
|
||||
if (x >= cols[i][0] && x < cols[i][1]) {
|
||||
c = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (r>=0 && c>=0) ? { row:r, col:c } : null;
|
||||
};
|
||||
|
||||
t.rect = function(row0, col0, row1, col1, originElement) { // row1,col1 is inclusive
|
||||
var origin = originElement.offset();
|
||||
return {
|
||||
top: rows[row0][0] - origin.top,
|
||||
left: cols[col0][0] - origin.left,
|
||||
width: cols[col1][1] - cols[col0][0],
|
||||
height: rows[row1][1] - rows[row0][0]
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
|
||||
function DayEventRenderer() {
|
||||
var t = this;
|
||||
|
||||
|
||||
// exports
|
||||
t.renderDaySegs = renderDaySegs;
|
||||
t.resizableDayEvent = resizableDayEvent;
|
||||
|
||||
|
||||
// imports
|
||||
var opt = t.opt;
|
||||
var trigger = t.trigger;
|
||||
var reportEventElement = t.reportEventElement;
|
||||
var showEvents = t.showEvents;
|
||||
var hideEvents = t.hideEvents;
|
||||
var eventResize = t.eventResize;
|
||||
var getRowCnt = t.getRowCnt;
|
||||
var getColCnt = t.getColCnt;
|
||||
var getColWidth = t.getColWidth;
|
||||
var allDayTR = t.allDayTR;
|
||||
var allDayBounds = t.allDayBounds;
|
||||
var colContentLeft = t.colContentLeft;
|
||||
var colContentRight = t.colContentRight;
|
||||
var dayOfWeekCol = t.dayOfWeekCol;
|
||||
var getDaySegmentContainer = t.getDaySegmentContainer;
|
||||
var bindDaySeg = t.bindDaySeg; //TODO: streamline this
|
||||
var formatDates = t.calendar.formatDates;
|
||||
|
||||
|
||||
|
||||
/* Rendering
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
function renderDaySegs(segs, modifiedEventId) {
|
||||
|
||||
var rtl=opt('isRTL'),
|
||||
i, segCnt=segs.length, seg,
|
||||
event,
|
||||
className,
|
||||
left, right,
|
||||
html='',
|
||||
eventElements,
|
||||
eventElement,
|
||||
triggerRes,
|
||||
hsideCache={},
|
||||
vmarginCache={},
|
||||
key, val,
|
||||
rowI, top, levelI, levelHeight,
|
||||
rowDivs=[],
|
||||
rowDivTops=[],
|
||||
bounds = allDayBounds(),
|
||||
minLeft = bounds.left,
|
||||
maxLeft = bounds.right,
|
||||
rowCnt = getRowCnt(),
|
||||
colCnt = getColCnt(),
|
||||
segmentContainer = getDaySegmentContainer();
|
||||
|
||||
// calculate desired position/dimensions, create html
|
||||
for (i=0; i<segCnt; i++) {
|
||||
seg = segs[i];
|
||||
event = seg.event;
|
||||
className = 'fc-event fc-event-hori ';
|
||||
if (rtl) {
|
||||
if (seg.isStart) {
|
||||
className += 'fc-corner-right ';
|
||||
}
|
||||
if (seg.isEnd) {
|
||||
className += 'fc-corner-left ';
|
||||
}
|
||||
left = seg.isEnd ? colContentLeft(dayOfWeekCol(seg.end.getDay()-1)) : minLeft;
|
||||
right = seg.isStart ? colContentRight(dayOfWeekCol(seg.start.getDay())) : maxLeft;
|
||||
}else{
|
||||
if (seg.isStart) {
|
||||
className += 'fc-corner-left ';
|
||||
}
|
||||
if (seg.isEnd) {
|
||||
className += 'fc-corner-right ';
|
||||
}
|
||||
left = seg.isStart ? colContentLeft(dayOfWeekCol(seg.start.getDay())) : minLeft;
|
||||
right = seg.isEnd ? colContentRight(dayOfWeekCol(seg.end.getDay()-1)) : maxLeft;
|
||||
}
|
||||
html +=
|
||||
"<div class='" + className + event.className.join(' ') + "' style='position:absolute;z-index:8;left:"+left+"px'>" +
|
||||
"<a" + (event.url ? " href='" + htmlEscape(event.url) + "'" : '') + ">" +
|
||||
(!event.allDay && seg.isStart ?
|
||||
"<span class='fc-event-time'>" +
|
||||
htmlEscape(formatDates(event.start, event.end, opt('timeFormat'))) +
|
||||
"</span>"
|
||||
:'') +
|
||||
"<span class='fc-event-title'>" + htmlEscape(event.title) + "</span>" +
|
||||
"</a>" +
|
||||
((event.editable || event.editable === undefined && opt('editable')) && !opt('disableResizing') && $.fn.resizable ?
|
||||
"<div class='ui-resizable-handle ui-resizable-" + (rtl ? 'w' : 'e') + "'></div>"
|
||||
: '') +
|
||||
"</div>";
|
||||
seg.left = left;
|
||||
seg.outerWidth = right - left;
|
||||
}
|
||||
segmentContainer[0].innerHTML = html; // faster than html()
|
||||
eventElements = segmentContainer.children();
|
||||
|
||||
// retrieve elements, run through eventRender callback, bind handlers
|
||||
for (i=0; i<segCnt; i++) {
|
||||
seg = segs[i];
|
||||
eventElement = $(eventElements[i]); // faster than eq()
|
||||
event = seg.event;
|
||||
triggerRes = trigger('eventRender', event, event, eventElement);
|
||||
if (triggerRes === false) {
|
||||
eventElement.remove();
|
||||
}else{
|
||||
if (triggerRes && triggerRes !== true) {
|
||||
eventElement.remove();
|
||||
eventElement = $(triggerRes)
|
||||
.css({
|
||||
position: 'absolute',
|
||||
left: seg.left
|
||||
})
|
||||
.appendTo(segmentContainer);
|
||||
}
|
||||
seg.element = eventElement;
|
||||
if (event._id === modifiedEventId) {
|
||||
bindDaySeg(event, eventElement, seg);
|
||||
}else{
|
||||
eventElement[0]._fci = i; // for lazySegBind
|
||||
}
|
||||
reportEventElement(event, eventElement);
|
||||
}
|
||||
}
|
||||
|
||||
lazySegBind(segmentContainer, segs, bindDaySeg);
|
||||
|
||||
// record event horizontal sides
|
||||
for (i=0; i<segCnt; i++) {
|
||||
seg = segs[i];
|
||||
if (eventElement = seg.element) {
|
||||
val = hsideCache[key = seg.key = cssKey(eventElement[0])];
|
||||
seg.hsides = val === undefined ? (hsideCache[key] = hsides(eventElement[0], true)) : val;
|
||||
}
|
||||
}
|
||||
|
||||
// set event widths
|
||||
for (i=0; i<segCnt; i++) {
|
||||
seg = segs[i];
|
||||
if (eventElement = seg.element) {
|
||||
eventElement[0].style.width = seg.outerWidth - seg.hsides + 'px';
|
||||
}
|
||||
}
|
||||
|
||||
// record event heights
|
||||
for (i=0; i<segCnt; i++) {
|
||||
seg = segs[i];
|
||||
if (eventElement = seg.element) {
|
||||
val = vmarginCache[key = seg.key];
|
||||
seg.outerHeight = eventElement[0].offsetHeight + (
|
||||
val === undefined ? (vmarginCache[key] = vmargins(eventElement[0])) : val
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// set row heights, calculate event tops (in relation to row top)
|
||||
for (i=0, rowI=0; rowI<rowCnt; rowI++) {
|
||||
top = levelI = levelHeight = 0;
|
||||
while (i<segCnt && (seg = segs[i]).row == rowI) {
|
||||
if (seg.level != levelI) {
|
||||
top += levelHeight;
|
||||
levelHeight = 0;
|
||||
levelI++;
|
||||
}
|
||||
levelHeight = Math.max(levelHeight, seg.outerHeight||0);
|
||||
seg.top = top;
|
||||
i++;
|
||||
}
|
||||
rowDivs[rowI] = allDayTR(rowI).find('td:first div.fc-day-content > div') // optimal selector?
|
||||
.height(top + levelHeight);
|
||||
}
|
||||
|
||||
// calculate row tops
|
||||
for (rowI=0; rowI<rowCnt; rowI++) {
|
||||
rowDivTops[rowI] = rowDivs[rowI][0].offsetTop;
|
||||
}
|
||||
|
||||
// set event tops
|
||||
for (i=0; i<segCnt; i++) {
|
||||
seg = segs[i];
|
||||
if (eventElement = seg.element) {
|
||||
eventElement[0].style.top = rowDivTops[seg.row] + seg.top + 'px';
|
||||
event = seg.event;
|
||||
trigger('eventAfterRender', event, event, eventElement);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Resizing
|
||||
-----------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
function resizableDayEvent(event, eventElement) {
|
||||
if (!opt('disableResizing') && eventElement.resizable) {
|
||||
var colWidth = getColWidth();
|
||||
eventElement.resizable({
|
||||
handles: opt('isRTL') ? {w:'div.ui-resizable-w'} : {e:'div.ui-resizable-e'},
|
||||
grid: colWidth,
|
||||
minWidth: colWidth/2, // need this or else IE throws errors when too small
|
||||
containment: t.element.parent().parent(), // the main element...
|
||||
// ... a fix. wouldn't allow extending to last column in agenda views (jq ui bug?)
|
||||
start: function(ev, ui) {
|
||||
eventElement.css('z-index', 9);
|
||||
hideEvents(event, eventElement);
|
||||
trigger('eventResizeStart', this, event, ev, ui);
|
||||
},
|
||||
stop: function(ev, ui) {
|
||||
trigger('eventResizeStop', this, event, ev, ui);
|
||||
// ui.size.width wasn't working with grid correctly, use .width()
|
||||
var dayDelta = Math.round((eventElement.width() - ui.originalSize.width) / colWidth);
|
||||
if (dayDelta) {
|
||||
eventResize(this, event, dayDelta, 0, ev, ui);
|
||||
}else{
|
||||
eventElement.css('z-index', 8);
|
||||
showEvents(event, eventElement);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
|
||||
function HorizontalPositionCache(getElement) {
|
||||
|
||||
var t = this,
|
||||
elements = {},
|
||||
lefts = {},
|
||||
rights = {};
|
||||
|
||||
function e(i) {
|
||||
return elements[i] = elements[i] || getElement(i);
|
||||
}
|
||||
|
||||
t.left = function(i) {
|
||||
return lefts[i] = lefts[i] === undefined ? e(i).position().left : lefts[i];
|
||||
};
|
||||
|
||||
t.right = function(i) {
|
||||
return rights[i] = rights[i] === undefined ? t.left(i) + e(i).width() : rights[i];
|
||||
};
|
||||
|
||||
t.clear = function() {
|
||||
elements = {};
|
||||
lefts = {};
|
||||
rights = {};
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
|
||||
function HoverListener(coordinateGrid) {
|
||||
|
||||
|
||||
var t = this;
|
||||
var bindType;
|
||||
var change;
|
||||
var firstCell;
|
||||
var cell;
|
||||
|
||||
|
||||
t.start = function(_change, ev, _bindType) {
|
||||
change = _change;
|
||||
firstCell = cell = null;
|
||||
coordinateGrid.build();
|
||||
mouse(ev);
|
||||
bindType = _bindType || 'mousemove';
|
||||
$(document).bind(bindType, mouse);
|
||||
};
|
||||
|
||||
|
||||
function mouse(ev) {
|
||||
var newCell = coordinateGrid.cell(ev.pageX, ev.pageY);
|
||||
if (!newCell != !cell || newCell && (newCell.row != cell.row || newCell.col != cell.col)) {
|
||||
if (newCell) {
|
||||
if (!firstCell) {
|
||||
firstCell = newCell;
|
||||
}
|
||||
change(newCell, firstCell, newCell.row-firstCell.row, newCell.col-firstCell.col);
|
||||
}else{
|
||||
change(newCell, firstCell);
|
||||
}
|
||||
cell = newCell;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
t.stop = function() {
|
||||
$(document).unbind(bindType, mouse);
|
||||
return cell;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
|
||||
function OverlayManager() {
|
||||
var t = this;
|
||||
|
||||
|
||||
// exports
|
||||
t.renderOverlay = renderOverlay;
|
||||
t.clearOverlays = clearOverlays;
|
||||
|
||||
|
||||
// locals
|
||||
var usedOverlays = [];
|
||||
var unusedOverlays = [];
|
||||
|
||||
|
||||
function renderOverlay(rect, parent) {
|
||||
var e = unusedOverlays.shift();
|
||||
if (!e) {
|
||||
e = $("<div class='fc-cell-overlay' style='position:absolute;z-index:3'/>");
|
||||
}
|
||||
if (e[0].parentNode != parent[0]) {
|
||||
e.appendTo(parent);
|
||||
}
|
||||
usedOverlays.push(e.css(rect).show());
|
||||
return e;
|
||||
}
|
||||
|
||||
|
||||
function clearOverlays() {
|
||||
var e;
|
||||
while (e = usedOverlays.shift()) {
|
||||
unusedOverlays.push(e.hide().unbind());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
|
||||
//BUG: unselect needs to be triggered when events are dragged+dropped
|
||||
|
||||
function SelectionManager() {
|
||||
var t = this;
|
||||
|
||||
|
||||
// exports
|
||||
t.select = select;
|
||||
t.unselect = unselect;
|
||||
t.reportSelection = reportSelection;
|
||||
t.daySelectionMousedown = daySelectionMousedown;
|
||||
|
||||
|
||||
// imports
|
||||
var opt = t.opt;
|
||||
var trigger = t.trigger;
|
||||
var defaultSelectionEnd = t.defaultSelectionEnd;
|
||||
var renderSelection = t.renderSelection;
|
||||
var clearSelection = t.clearSelection;
|
||||
|
||||
|
||||
// locals
|
||||
var selected = false;
|
||||
|
||||
|
||||
|
||||
// unselectAuto
|
||||
if (opt('selectable') && opt('unselectAuto')) {
|
||||
$(document).mousedown(function(ev) {
|
||||
var ignore = opt('unselectCancel');
|
||||
if (ignore) {
|
||||
if ($(ev.target).parents(ignore).length) { // could be optimized to stop after first match
|
||||
return;
|
||||
}
|
||||
}
|
||||
unselect(ev);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function select(startDate, endDate, allDay) {
|
||||
unselect();
|
||||
if (!endDate) {
|
||||
endDate = defaultSelectionEnd(startDate, allDay);
|
||||
}
|
||||
renderSelection(startDate, endDate, allDay);
|
||||
reportSelection(startDate, endDate, allDay);
|
||||
}
|
||||
|
||||
|
||||
function unselect(ev) {
|
||||
if (selected) {
|
||||
selected = false;
|
||||
clearSelection();
|
||||
trigger('unselect', null, ev);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function reportSelection(startDate, endDate, allDay, ev) {
|
||||
selected = true;
|
||||
trigger('select', null, startDate, endDate, allDay, ev);
|
||||
}
|
||||
|
||||
|
||||
function daySelectionMousedown(ev) { // not really a generic manager method, oh well
|
||||
var cellDate = t.cellDate;
|
||||
var cellIsAllDay = t.cellIsAllDay;
|
||||
var hoverListener = t.getHoverListener();
|
||||
if (opt('selectable')) {
|
||||
unselect(ev);
|
||||
var _mousedownElement = this;
|
||||
var dates;
|
||||
hoverListener.start(function(cell, origCell) { // TODO: maybe put cellDate/cellIsAllDay info in cell
|
||||
clearSelection();
|
||||
if (cell && cellIsAllDay(cell)) {
|
||||
dates = [ cellDate(origCell), cellDate(cell) ].sort(cmp);
|
||||
renderSelection(dates[0], dates[1], true);
|
||||
}else{
|
||||
dates = null;
|
||||
}
|
||||
}, ev);
|
||||
$(document).one('mouseup', function(ev) {
|
||||
hoverListener.stop();
|
||||
if (dates) {
|
||||
if (+dates[0] == +dates[1]) {
|
||||
trigger('dayClick', _mousedownElement, dates[0], true, ev);
|
||||
// BUG: _mousedownElement will sometimes be the overlay
|
||||
}
|
||||
reportSelection(dates[0], dates[1], true, ev);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
|
||||
|
||||
function View(element, calendar, viewName) {
|
||||
var t = this;
|
||||
|
||||
|
||||
// exports
|
||||
t.element = element;
|
||||
t.calendar = calendar;
|
||||
t.name = viewName;
|
||||
t.opt = opt;
|
||||
t.trigger = trigger;
|
||||
t.reportEvents = reportEvents;
|
||||
t.clearEventData = clearEventData;
|
||||
t.eventEnd = eventEnd;
|
||||
t.reportEventElement = reportEventElement;
|
||||
t.eventElementHandlers = eventElementHandlers;
|
||||
t.showEvents = showEvents;
|
||||
t.hideEvents = hideEvents;
|
||||
t.eventDrop = eventDrop;
|
||||
t.eventResize = eventResize;
|
||||
// t.title
|
||||
// t.start, t.end
|
||||
// t.visStart, t.visEnd
|
||||
// t.eventsChanged // todo: maybe report to calendar instead
|
||||
|
||||
|
||||
// imports
|
||||
var defaultEventEnd = t.defaultEventEnd;
|
||||
var normalizeEvent = calendar.normalizeEvent; // in EventManager
|
||||
var rerenderEvents = calendar.rerenderEvents;
|
||||
|
||||
|
||||
// locals
|
||||
var eventsByID = {};
|
||||
var eventElements = [];
|
||||
var eventElementsByID = {};
|
||||
var options = calendar.options;
|
||||
|
||||
|
||||
|
||||
function opt(name, viewNameOverride) {
|
||||
var v = options[name];
|
||||
if (typeof v == 'object') {
|
||||
return smartProperty(v, viewNameOverride || viewName);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
function trigger(name, thisObj) {
|
||||
return calendar.trigger.apply(
|
||||
calendar,
|
||||
[name, thisObj || t].concat(Array.prototype.slice.call(arguments, 2), [t])
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Event Data
|
||||
------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
// report when view receives new events
|
||||
function reportEvents(events) { // events are already normalized at this point
|
||||
eventsByID = {};
|
||||
var i, len=events.length, event;
|
||||
for (i=0; i<len; i++) {
|
||||
event = events[i];
|
||||
if (eventsByID[event._id]) {
|
||||
eventsByID[event._id].push(event);
|
||||
}else{
|
||||
eventsByID[event._id] = [event];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function clearEventData() { // todo: rename to clearReportedEvents or something
|
||||
eventElements = [];
|
||||
eventElementsByID = {};
|
||||
}
|
||||
|
||||
|
||||
// returns a Date object for an event's end
|
||||
function eventEnd(event) {
|
||||
return event.end ? cloneDate(event.end) : defaultEventEnd(event);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Event Elements
|
||||
------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
// report when view creates an element for an event
|
||||
function reportEventElement(event, element) {
|
||||
eventElements.push(element);
|
||||
if (eventElementsByID[event._id]) {
|
||||
eventElementsByID[event._id].push(element);
|
||||
}else{
|
||||
eventElementsByID[event._id] = [element];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// attaches eventClick, eventMouseover, eventMouseout
|
||||
function eventElementHandlers(event, eventElement) {
|
||||
eventElement
|
||||
.click(function(ev) {
|
||||
if (!eventElement.hasClass('ui-draggable-dragging') &&
|
||||
!eventElement.hasClass('ui-resizable-resizing')) {
|
||||
return trigger('eventClick', this, event, ev);
|
||||
}
|
||||
})
|
||||
.hover(
|
||||
function(ev) {
|
||||
trigger('eventMouseover', this, event, ev);
|
||||
},
|
||||
function(ev) {
|
||||
trigger('eventMouseout', this, event, ev);
|
||||
}
|
||||
);
|
||||
// TODO: don't fire eventMouseover/eventMouseout *while* dragging is occuring (on subject element)
|
||||
// TODO: same for resizing
|
||||
}
|
||||
|
||||
|
||||
function showEvents(event, exceptElement) {
|
||||
eachEventElement(event, exceptElement, 'show');
|
||||
}
|
||||
|
||||
|
||||
function hideEvents(event, exceptElement) {
|
||||
eachEventElement(event, exceptElement, 'hide');
|
||||
}
|
||||
|
||||
|
||||
function eachEventElement(event, exceptElement, funcName) {
|
||||
var elements = eventElementsByID[event._id],
|
||||
i, len = elements.length;
|
||||
for (i=0; i<len; i++) {
|
||||
if (elements[i][0] != exceptElement[0]) {
|
||||
elements[i][funcName]();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Event Modification Reporting
|
||||
---------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
function eventDrop(e, event, dayDelta, minuteDelta, allDay, ev, ui) {
|
||||
var oldAllDay = event.allDay;
|
||||
var eventId = event._id;
|
||||
moveEvents(eventsByID[eventId], dayDelta, minuteDelta, allDay);
|
||||
trigger('eventDrop', e, event, dayDelta, minuteDelta, allDay, function() {
|
||||
// TODO: investigate cases where this inverse technique might not work
|
||||
moveEvents(eventsByID[eventId], -dayDelta, -minuteDelta, oldAllDay);
|
||||
rerenderEvents();
|
||||
}, ev, ui);
|
||||
t.eventsChanged = true;
|
||||
rerenderEvents(eventId);
|
||||
}
|
||||
|
||||
|
||||
function eventResize(e, event, dayDelta, minuteDelta, ev, ui) {
|
||||
var eventId = event._id;
|
||||
elongateEvents(eventsByID[eventId], dayDelta, minuteDelta);
|
||||
trigger('eventResize', e, event, dayDelta, minuteDelta, function() {
|
||||
// TODO: investigate cases where this inverse technique might not work
|
||||
elongateEvents(eventsByID[eventId], -dayDelta, -minuteDelta);
|
||||
rerenderEvents();
|
||||
}, ev, ui);
|
||||
t.eventsChanged = true;
|
||||
rerenderEvents(eventId);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Event Modification Math
|
||||
---------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
function moveEvents(events, dayDelta, minuteDelta, allDay) {
|
||||
minuteDelta = minuteDelta || 0;
|
||||
for (var e, len=events.length, i=0; i<len; i++) {
|
||||
e = events[i];
|
||||
if (allDay !== undefined) {
|
||||
e.allDay = allDay;
|
||||
}
|
||||
addMinutes(addDays(e.start, dayDelta, true), minuteDelta);
|
||||
if (e.end) {
|
||||
e.end = addMinutes(addDays(e.end, dayDelta, true), minuteDelta);
|
||||
}
|
||||
normalizeEvent(e, options);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function elongateEvents(events, dayDelta, minuteDelta) {
|
||||
minuteDelta = minuteDelta || 0;
|
||||
for (var e, len=events.length, i=0; i<len; i++) {
|
||||
e = events[i];
|
||||
e.end = addMinutes(addDays(eventEnd(e), dayDelta, true), minuteDelta);
|
||||
normalizeEvent(e, options);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
|
||||
|
||||
/* Global Event Styles
|
||||
------------------------------------------------------------------------*/
|
||||
|
||||
.fc-event,
|
||||
.fc-agenda .fc-event-time,
|
||||
.fc-event a {
|
||||
border-style: solid;
|
||||
border-color: #36c; /* default BORDER color (probably the same as background-color) */
|
||||
background-color: #36c; /* default BACKGROUND color */
|
||||
color: #fff; /* default TEXT color */
|
||||
}
|
||||
|
||||
/* Use the 'className' CalEvent property and the following
|
||||
* example CSS to change event color on a per-event basis:
|
||||
*
|
||||
* .myclass,
|
||||
* .fc-agenda .myclass .fc-event-time,
|
||||
* .myclass a {
|
||||
* background-color: black;
|
||||
* border-color: black;
|
||||
* color: red;
|
||||
* }
|
||||
*/
|
||||
|
||||
.fc-event {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.fc-event a {
|
||||
overflow: hidden;
|
||||
font-size: .85em;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.fc-event-editable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.fc-event-time,
|
||||
.fc-event-title {
|
||||
padding: 0 1px;
|
||||
}
|
||||
|
||||
/* for fake rounded corners */
|
||||
|
||||
.fc-event a {
|
||||
display: block;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* right-to-left */
|
||||
|
||||
.fc-rtl .fc-event a {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* resizable */
|
||||
|
||||
.fc .ui-resizable-handle {
|
||||
display: block;
|
||||
position: absolute;
|
||||
z-index: 99999;
|
||||
border: 0 !important; /* important overrides pre jquery ui 1.7 styles */
|
||||
background: url(data:image/gif;base64,AAAA) !important; /* hover fix for IE */
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Horizontal Events
|
||||
------------------------------------------------------------------------*/
|
||||
|
||||
.fc-event-hori {
|
||||
border-width: 1px 0;
|
||||
margin-bottom: 1px;
|
||||
}
|
||||
|
||||
.fc-event-hori a {
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
/* for fake rounded corners */
|
||||
|
||||
.fc-content .fc-corner-left {
|
||||
margin-left: 1px;
|
||||
}
|
||||
|
||||
.fc-content .fc-corner-left a {
|
||||
margin-left: -1px;
|
||||
border-left-width: 1px;
|
||||
}
|
||||
|
||||
.fc-content .fc-corner-right {
|
||||
margin-right: 1px;
|
||||
}
|
||||
|
||||
.fc-content .fc-corner-right a {
|
||||
margin-right: -1px;
|
||||
border-right-width: 1px;
|
||||
}
|
||||
|
||||
/* resizable */
|
||||
|
||||
.fc-event-hori .ui-resizable-e {
|
||||
top: 0 !important; /* importants override pre jquery ui 1.7 styles */
|
||||
right: -3px !important;
|
||||
width: 7px !important;
|
||||
height: 100% !important;
|
||||
cursor: e-resize;
|
||||
}
|
||||
|
||||
.fc-event-hori .ui-resizable-w {
|
||||
top: 0 !important;
|
||||
left: -3px !important;
|
||||
width: 7px !important;
|
||||
height: 100% !important;
|
||||
cursor: w-resize;
|
||||
}
|
||||
|
||||
.fc-event-hori .ui-resizable-handle {
|
||||
_padding-bottom: 14px; /* IE6 had 0 height */
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,362 @@
|
||||
|
||||
|
||||
fc.addDays = addDays;
|
||||
fc.cloneDate = cloneDate;
|
||||
fc.parseDate = parseDate;
|
||||
fc.parseISO8601 = parseISO8601;
|
||||
fc.parseTime = parseTime;
|
||||
fc.formatDate = formatDate;
|
||||
fc.formatDates = formatDates;
|
||||
|
||||
|
||||
|
||||
/* Date Math
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
var dayIDs = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'],
|
||||
DAY_MS = 86400000,
|
||||
HOUR_MS = 3600000,
|
||||
MINUTE_MS = 60000;
|
||||
|
||||
|
||||
function addYears(d, n, keepTime) {
|
||||
d.setFullYear(d.getFullYear() + n);
|
||||
if (!keepTime) {
|
||||
clearTime(d);
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
function addMonths(d, n, keepTime) { // prevents day overflow/underflow
|
||||
if (+d) { // prevent infinite looping on invalid dates
|
||||
var m = d.getMonth() + n,
|
||||
check = cloneDate(d);
|
||||
check.setDate(1);
|
||||
check.setMonth(m);
|
||||
d.setMonth(m);
|
||||
if (!keepTime) {
|
||||
clearTime(d);
|
||||
}
|
||||
while (d.getMonth() != check.getMonth()) {
|
||||
d.setDate(d.getDate() + (d < check ? 1 : -1));
|
||||
}
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
function addDays(d, n, keepTime) { // deals with daylight savings
|
||||
if (+d) {
|
||||
var dd = d.getDate() + n,
|
||||
check = cloneDate(d);
|
||||
check.setHours(9); // set to middle of day
|
||||
check.setDate(dd);
|
||||
d.setDate(dd);
|
||||
if (!keepTime) {
|
||||
clearTime(d);
|
||||
}
|
||||
fixDate(d, check);
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
function fixDate(d, check) { // force d to be on check's YMD, for daylight savings purposes
|
||||
if (+d) { // prevent infinite looping on invalid dates
|
||||
while (d.getDate() != check.getDate()) {
|
||||
d.setTime(+d + (d < check ? 1 : -1) * HOUR_MS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function addMinutes(d, n) {
|
||||
d.setMinutes(d.getMinutes() + n);
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
function clearTime(d) {
|
||||
d.setHours(0);
|
||||
d.setMinutes(0);
|
||||
d.setSeconds(0);
|
||||
d.setMilliseconds(0);
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
function cloneDate(d, dontKeepTime) {
|
||||
if (dontKeepTime) {
|
||||
return clearTime(new Date(+d));
|
||||
}
|
||||
return new Date(+d);
|
||||
}
|
||||
|
||||
|
||||
function zeroDate() { // returns a Date with time 00:00:00 and dateOfMonth=1
|
||||
var i=0, d;
|
||||
do {
|
||||
d = new Date(1970, i++, 1);
|
||||
} while (d.getHours()); // != 0
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
function skipWeekend(date, inc, excl) {
|
||||
inc = inc || 1;
|
||||
while (!date.getDay() || (excl && date.getDay()==1 || !excl && date.getDay()==6)) {
|
||||
addDays(date, inc);
|
||||
}
|
||||
return date;
|
||||
}
|
||||
|
||||
|
||||
function dayDiff(d1, d2) { // d1 - d2
|
||||
return Math.round((cloneDate(d1, true) - cloneDate(d2, true)) / DAY_MS);
|
||||
}
|
||||
|
||||
|
||||
function setYMD(date, y, m, d) {
|
||||
if (y !== undefined && y != date.getFullYear()) {
|
||||
date.setDate(1);
|
||||
date.setMonth(0);
|
||||
date.setFullYear(y);
|
||||
}
|
||||
if (m !== undefined && m != date.getMonth()) {
|
||||
date.setDate(1);
|
||||
date.setMonth(m);
|
||||
}
|
||||
if (d !== undefined) {
|
||||
date.setDate(d);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Date Parsing
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
function parseDate(s, ignoreTimezone) {
|
||||
if (typeof s == 'object') { // already a Date object
|
||||
return s;
|
||||
}
|
||||
if (typeof s == 'number') { // a UNIX timestamp
|
||||
return new Date(s * 1000);
|
||||
}
|
||||
if (typeof s == 'string') {
|
||||
if (s.match(/^\d+$/)) { // a UNIX timestamp
|
||||
return new Date(parseInt(s) * 1000);
|
||||
}
|
||||
if (ignoreTimezone === undefined) {
|
||||
ignoreTimezone = true;
|
||||
}
|
||||
return parseISO8601(s, ignoreTimezone) || (s ? new Date(s) : null);
|
||||
}
|
||||
// TODO: never return invalid dates (like from new Date(<string>)), return null instead
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
function parseISO8601(s, ignoreTimezone) {
|
||||
// derived from http://delete.me.uk/2005/03/iso8601.html
|
||||
// TODO: for a know glitch/feature, read tests/issue_206_parseDate_dst.html
|
||||
var m = s.match(/^([0-9]{4})(-([0-9]{2})(-([0-9]{2})([T ]([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?$/);
|
||||
if (!m) {
|
||||
return null;
|
||||
}
|
||||
var date = new Date(m[1], 0, 1), offset = 0;
|
||||
if (ignoreTimezone) {
|
||||
if (m[3]) {
|
||||
date.setMonth(m[3] - 1);
|
||||
}
|
||||
if (m[5]) {
|
||||
date.setDate(m[5]);
|
||||
}
|
||||
if (m[7]) {
|
||||
date.setHours(m[7]);
|
||||
}
|
||||
if (m[8]) {
|
||||
date.setMinutes(m[8]);
|
||||
}
|
||||
if (m[10]) {
|
||||
date.setSeconds(m[10]);
|
||||
}
|
||||
if (m[12]) {
|
||||
date.setMilliseconds(Number("0." + m[12]) * 1000);
|
||||
}
|
||||
}else{
|
||||
date.setUTCFullYear(m[1]);
|
||||
if (m[3]) {
|
||||
date.setUTCMonth(m[3] - 1);
|
||||
}
|
||||
if (m[5]) {
|
||||
date.setUTCDate(m[5]);
|
||||
}
|
||||
if (m[7]) {
|
||||
date.setUTCHours(m[7]);
|
||||
}
|
||||
if (m[8]) {
|
||||
date.setUTCMinutes(m[8]);
|
||||
}
|
||||
if (m[10]) {
|
||||
date.setUTCSeconds(m[10]);
|
||||
}
|
||||
if (m[12]) {
|
||||
date.setUTCMilliseconds(Number("0." + m[12]) * 1000);
|
||||
}
|
||||
if (m[14]) {
|
||||
offset = Number(m[16]) * 60 + Number(m[17]);
|
||||
offset *= m[15] == '-' ? 1 : -1;
|
||||
}
|
||||
date = new Date(+date + (offset * 60 * 1000));
|
||||
}
|
||||
return date;
|
||||
}
|
||||
|
||||
|
||||
function parseTime(s) { // returns minutes since start of day
|
||||
if (typeof s == 'number') { // an hour
|
||||
return s * 60;
|
||||
}
|
||||
if (typeof s == 'object') { // a Date object
|
||||
return s.getHours() * 60 + s.getMinutes();
|
||||
}
|
||||
var m = s.match(/(\d+)(?::(\d+))?\s*(\w+)?/);
|
||||
if (m) {
|
||||
var h = parseInt(m[1]);
|
||||
if (m[3]) {
|
||||
h %= 12;
|
||||
if (m[3].toLowerCase().charAt(0) == 'p') {
|
||||
h += 12;
|
||||
}
|
||||
}
|
||||
return h * 60 + (m[2] ? parseInt(m[2]) : 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Date Formatting
|
||||
-----------------------------------------------------------------------------*/
|
||||
// TODO: use same function formatDate(date, [date2], format, [options])
|
||||
|
||||
|
||||
function formatDate(date, format, options) {
|
||||
return formatDates(date, null, format, options);
|
||||
}
|
||||
|
||||
|
||||
function formatDates(date1, date2, format, options) {
|
||||
options = options || defaults;
|
||||
var date = date1,
|
||||
otherDate = date2,
|
||||
i, len = format.length, c,
|
||||
i2, formatter,
|
||||
res = '';
|
||||
for (i=0; i<len; i++) {
|
||||
c = format.charAt(i);
|
||||
if (c == "'") {
|
||||
for (i2=i+1; i2<len; i2++) {
|
||||
if (format.charAt(i2) == "'") {
|
||||
if (date) {
|
||||
if (i2 == i+1) {
|
||||
res += "'";
|
||||
}else{
|
||||
res += format.substring(i+1, i2);
|
||||
}
|
||||
i = i2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (c == '(') {
|
||||
for (i2=i+1; i2<len; i2++) {
|
||||
if (format.charAt(i2) == ')') {
|
||||
var subres = formatDate(date, format.substring(i+1, i2), options);
|
||||
if (parseInt(subres.replace(/\D/, ''))) {
|
||||
res += subres;
|
||||
}
|
||||
i = i2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (c == '[') {
|
||||
for (i2=i+1; i2<len; i2++) {
|
||||
if (format.charAt(i2) == ']') {
|
||||
var subformat = format.substring(i+1, i2);
|
||||
var subres = formatDate(date, subformat, options);
|
||||
if (subres != formatDate(otherDate, subformat, options)) {
|
||||
res += subres;
|
||||
}
|
||||
i = i2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (c == '{') {
|
||||
date = date2;
|
||||
otherDate = date1;
|
||||
}
|
||||
else if (c == '}') {
|
||||
date = date1;
|
||||
otherDate = date2;
|
||||
}
|
||||
else {
|
||||
for (i2=len; i2>i; i2--) {
|
||||
if (formatter = dateFormatters[format.substring(i, i2)]) {
|
||||
if (date) {
|
||||
res += formatter(date, options);
|
||||
}
|
||||
i = i2 - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i2 == i) {
|
||||
if (date) {
|
||||
res += c;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
};
|
||||
|
||||
|
||||
var dateFormatters = {
|
||||
s : function(d) { return d.getSeconds() },
|
||||
ss : function(d) { return zeroPad(d.getSeconds()) },
|
||||
m : function(d) { return d.getMinutes() },
|
||||
mm : function(d) { return zeroPad(d.getMinutes()) },
|
||||
h : function(d) { return d.getHours() % 12 || 12 },
|
||||
hh : function(d) { return zeroPad(d.getHours() % 12 || 12) },
|
||||
H : function(d) { return d.getHours() },
|
||||
HH : function(d) { return zeroPad(d.getHours()) },
|
||||
d : function(d) { return d.getDate() },
|
||||
dd : function(d) { return zeroPad(d.getDate()) },
|
||||
ddd : function(d,o) { return o.dayNamesShort[d.getDay()] },
|
||||
dddd: function(d,o) { return o.dayNames[d.getDay()] },
|
||||
M : function(d) { return d.getMonth() + 1 },
|
||||
MM : function(d) { return zeroPad(d.getMonth() + 1) },
|
||||
MMM : function(d,o) { return o.monthNamesShort[d.getMonth()] },
|
||||
MMMM: function(d,o) { return o.monthNames[d.getMonth()] },
|
||||
yy : function(d) { return (d.getFullYear()+'').substring(2) },
|
||||
yyyy: function(d) { return d.getFullYear() },
|
||||
t : function(d) { return d.getHours() < 12 ? 'a' : 'p' },
|
||||
tt : function(d) { return d.getHours() < 12 ? 'am' : 'pm' },
|
||||
T : function(d) { return d.getHours() < 12 ? 'A' : 'P' },
|
||||
TT : function(d) { return d.getHours() < 12 ? 'AM' : 'PM' },
|
||||
u : function(d) { return formatDate(d, "yyyy-MM-dd'T'HH:mm:ss'Z'") },
|
||||
S : function(d) {
|
||||
var date = d.getDate();
|
||||
if (date > 10 && date < 20) {
|
||||
return 'th';
|
||||
}
|
||||
return ['st', 'nd', 'rd'][date%10-1] || 'th';
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,285 @@
|
||||
|
||||
|
||||
/* Event Date Math
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
function exclEndDay(event) {
|
||||
if (event.end) {
|
||||
return _exclEndDay(event.end, event.allDay);
|
||||
}else{
|
||||
return addDays(cloneDate(event.start), 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function _exclEndDay(end, allDay) {
|
||||
end = cloneDate(end);
|
||||
return allDay || end.getHours() || end.getMinutes() ? addDays(end, 1) : clearTime(end);
|
||||
}
|
||||
|
||||
|
||||
function segCmp(a, b) {
|
||||
return (b.msLength - a.msLength) * 100 + (a.event.start - b.event.start);
|
||||
}
|
||||
|
||||
|
||||
function segsCollide(seg1, seg2) {
|
||||
return seg1.end > seg2.start && seg1.start < seg2.end;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Event Sorting
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
// event rendering utilities
|
||||
function sliceSegs(events, visEventEnds, start, end) {
|
||||
var segs = [],
|
||||
i, len=events.length, event,
|
||||
eventStart, eventEnd,
|
||||
segStart, segEnd,
|
||||
isStart, isEnd;
|
||||
for (i=0; i<len; i++) {
|
||||
event = events[i];
|
||||
eventStart = event.start;
|
||||
eventEnd = visEventEnds[i];
|
||||
if (eventEnd > start && eventStart < end) {
|
||||
if (eventStart < start) {
|
||||
segStart = cloneDate(start);
|
||||
isStart = false;
|
||||
}else{
|
||||
segStart = eventStart;
|
||||
isStart = true;
|
||||
}
|
||||
if (eventEnd > end) {
|
||||
segEnd = cloneDate(end);
|
||||
isEnd = false;
|
||||
}else{
|
||||
segEnd = eventEnd;
|
||||
isEnd = true;
|
||||
}
|
||||
segs.push({
|
||||
event: event,
|
||||
start: segStart,
|
||||
end: segEnd,
|
||||
isStart: isStart,
|
||||
isEnd: isEnd,
|
||||
msLength: segEnd - segStart
|
||||
});
|
||||
}
|
||||
}
|
||||
return segs.sort(segCmp);
|
||||
}
|
||||
|
||||
|
||||
// event rendering calculation utilities
|
||||
function stackSegs(segs) {
|
||||
var levels = [],
|
||||
i, len = segs.length, seg,
|
||||
j, collide, k;
|
||||
for (i=0; i<len; i++) {
|
||||
seg = segs[i];
|
||||
j = 0; // the level index where seg should belong
|
||||
while (true) {
|
||||
collide = false;
|
||||
if (levels[j]) {
|
||||
for (k=0; k<levels[j].length; k++) {
|
||||
if (segsCollide(levels[j][k], seg)) {
|
||||
collide = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (collide) {
|
||||
j++;
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (levels[j]) {
|
||||
levels[j].push(seg);
|
||||
}else{
|
||||
levels[j] = [seg];
|
||||
}
|
||||
}
|
||||
return levels;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Event Element Binding
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
function lazySegBind(container, segs, bindHandlers) {
|
||||
container.unbind('mouseover').mouseover(function(ev) {
|
||||
var parent=ev.target, e,
|
||||
i, seg;
|
||||
while (parent != this) {
|
||||
e = parent;
|
||||
parent = parent.parentNode;
|
||||
}
|
||||
if ((i = e._fci) !== undefined) {
|
||||
e._fci = undefined;
|
||||
seg = segs[i];
|
||||
bindHandlers(seg.event, seg.element, seg);
|
||||
$(ev.target).trigger(ev);
|
||||
}
|
||||
ev.stopPropagation();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Element Dimensions
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
function setOuterWidth(element, width, includeMargins) {
|
||||
element.each(function(i, _element) {
|
||||
_element.style.width = width - hsides(_element, includeMargins) + 'px';
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function setOuterHeight(element, height, includeMargins) {
|
||||
element.each(function(i, _element) {
|
||||
_element.style.height = height - vsides(_element, includeMargins) + 'px';
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function hsides(_element, includeMargins) {
|
||||
return (parseFloat($.curCSS(_element, 'paddingLeft', true)) || 0) +
|
||||
(parseFloat($.curCSS(_element, 'paddingRight', true)) || 0) +
|
||||
(parseFloat($.curCSS(_element, 'borderLeftWidth', true)) || 0) +
|
||||
(parseFloat($.curCSS(_element, 'borderRightWidth', true)) || 0) +
|
||||
(includeMargins ? hmargins(_element) : 0);
|
||||
}
|
||||
|
||||
|
||||
function hmargins(_element) {
|
||||
return (parseFloat($.curCSS(_element, 'marginLeft', true)) || 0) +
|
||||
(parseFloat($.curCSS(_element, 'marginRight', true)) || 0);
|
||||
}
|
||||
|
||||
|
||||
function vsides(_element, includeMargins) {
|
||||
return (parseFloat($.curCSS(_element, 'paddingTop', true)) || 0) +
|
||||
(parseFloat($.curCSS(_element, 'paddingBottom', true)) || 0) +
|
||||
(parseFloat($.curCSS(_element, 'borderTopWidth', true)) || 0) +
|
||||
(parseFloat($.curCSS(_element, 'borderBottomWidth', true)) || 0) +
|
||||
(includeMargins ? vmargins(_element) : 0);
|
||||
}
|
||||
|
||||
|
||||
function vmargins(_element) {
|
||||
return (parseFloat($.curCSS(_element, 'marginTop', true)) || 0) +
|
||||
(parseFloat($.curCSS(_element, 'marginBottom', true)) || 0);
|
||||
}
|
||||
|
||||
|
||||
function setMinHeight(element, h) {
|
||||
h = typeof h == 'number' ? h + 'px' : h;
|
||||
element[0].style.cssText += ';min-height:' + h + ';_height:' + h;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Position Calculation
|
||||
-----------------------------------------------------------------------------*/
|
||||
// nasty bugs in opera 9.25
|
||||
// position()'s top returning incorrectly with TR/TD or elements within TD
|
||||
|
||||
var topBug;
|
||||
|
||||
function topCorrect(tr) { // tr/th/td or anything else
|
||||
if (topBug !== false) {
|
||||
var cell;
|
||||
if (tr.is('th,td')) {
|
||||
tr = (cell = tr).parent();
|
||||
}
|
||||
if (topBug === undefined && tr.is('tr')) {
|
||||
topBug = tr.position().top != tr.children().position().top;
|
||||
}
|
||||
if (topBug) {
|
||||
return tr.parent().position().top + (cell ? tr.position().top - cell.position().top : 0);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Misc Utils
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
//TODO: arraySlice
|
||||
//TODO: isFunction, grep ?
|
||||
|
||||
|
||||
function noop() { }
|
||||
|
||||
|
||||
function cmp(a, b) {
|
||||
return a - b;
|
||||
}
|
||||
|
||||
|
||||
function zeroPad(n) {
|
||||
return (n < 10 ? '0' : '') + n;
|
||||
}
|
||||
|
||||
|
||||
function smartProperty(obj, name) { // get a camel-cased/namespaced property of an object
|
||||
if (obj[name] !== undefined) {
|
||||
return obj[name];
|
||||
}
|
||||
var parts = name.split(/(?=[A-Z])/),
|
||||
i=parts.length-1, res;
|
||||
for (; i>=0; i--) {
|
||||
res = obj[parts[i].toLowerCase()];
|
||||
if (res !== undefined) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
return obj[''];
|
||||
}
|
||||
|
||||
|
||||
function htmlEscape(s) {
|
||||
return s.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/'/g, ''')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/\n/g, '<br />');
|
||||
}
|
||||
|
||||
|
||||
function cssKey(_element) {
|
||||
return _element.id + '/' + _element.className + '/' + _element.style.cssText.replace(/(^|;)\s*(top|left|width|height)\s*:[^;]*/ig, '');
|
||||
}
|
||||
|
||||
|
||||
function disableTextSelection(element) {
|
||||
element
|
||||
.attr('unselectable', 'on')
|
||||
.css('MozUserSelect', 'none')
|
||||
.bind('selectstart.ui', function() { return false; });
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
function enableTextSelection(element) {
|
||||
element
|
||||
.attr('unselectable', 'off')
|
||||
.css('MozUserSelect', '')
|
||||
.unbind('selectstart.ui');
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
Reference in New Issue
Block a user