Ver código fonte

foundation of clickable internal links

Adam Shaw 9 anos atrás
pai
commit
188975080d

+ 8 - 0
src/Calendar.js

@@ -544,6 +544,14 @@ function Calendar_constructor(element, overrides) {
 	function initialRender() {
 		element.addClass('fc');
 
+		// event delegation for nav links
+		element.on('click', 'a[data-fc-goto]', function(ev) {
+			var anchorEl = $(this);
+			var gotoOptions = anchorEl.data('fc-goto'); // will automatically parse JSON
+
+			zoomTo(t.moment(gotoOptions.date), gotoOptions.type);
+		});
+
 		// called immediately, and upon option change
 		t.bindOption('theme', function(theme) {
 			tm = theme ? 'ui' : 'fc'; // affects a larger scope

+ 4 - 3
src/agenda/AgendaView.js

@@ -467,9 +467,10 @@ var agendaTimeGridMethods = {
 
 			return '' +
 				'<th class="fc-axis fc-week-number ' + view.widgetHeaderClass + '" ' + view.axisStyleAttr() + '>' +
-					'<span>' + // needed for matchCellWidths
-						htmlEscape(weekText) +
-					'</span>' +
+					view.buildGotoAnchorHtml( // aside from link, important for matchCellWidths
+						{ date: this.start, type: 'week', forceOff: this.colCnt === 1  },
+						htmlEscape(weekText) // inner HTML
+					) +
 				'</th>';
 		}
 		else {

+ 5 - 3
src/basic/BasicView.js

@@ -372,13 +372,15 @@ var basicDayGridMethods = {
 	// Generates the HTML that will go before content-skeleton cells that display the day/week numbers
 	renderNumberIntroHtml: function(row) {
 		var view = this.view;
+		var weekStart = this.getCellDate(row, 0);
 
 		if (view.colWeekNumbersVisible) {
 			return '' +
 				'<td class="fc-week-number" ' + view.weekNumberStyleAttr() + '>' +
-					'<span>' + // needed for matchCellWidths
-						this.getCellDate(row, 0).format('w') +
-					'</span>' +
+					view.buildGotoAnchorHtml( // aside from link, important for matchCellWidths
+						{ date: weekStart, type: 'week', forceOff: this.colCnt === 1 },
+						weekStart.format('w') // inner HTML
+					) +
 				'</td>';
 		}
 

+ 22 - 15
src/common/DayGrid.js

@@ -139,6 +139,7 @@ var DayGrid = FC.DayGrid = Grid.extend(DayTableMixin, {
 	// Generates the HTML for the <td>s of the "number" row in the DayGrid's content skeleton.
 	// The number row will only exist if either day numbers or week numbers are turned on.
 	renderNumberCellHtml: function(date) {
+		var html = '';
 		var classes;
 		var weekCalcFirstDoW;
 
@@ -164,21 +165,27 @@ var DayGrid = FC.DayGrid = Grid.extend(DayTableMixin, {
 			}
 		}
 
-		return '' +
-			'<td class="' + classes.join(' ') + '" data-date="' + date.format() + '">' +
-				((this.view.cellWeekNumbersVisible && (date.day() == weekCalcFirstDoW)) ?
-					'<span class="fc-week-number">' +
-						date.format('w') +
-					'</span>' :
-					''
-					) +
-				(this.view.dayNumbersVisible ?
-					'<span class="fc-day-number">' +
-						date.date() +
-					'</span>' :
-					''
-					) +
-			'</td>';
+		html += '<td class="' + classes.join(' ') + '" data-date="' + date.format() + '">';
+
+		if (this.view.cellWeekNumbersVisible && (date.day() == weekCalcFirstDoW)) {
+			html += this.view.buildGotoAnchorHtml(
+				{ date: date, type: 'week' },
+				{ 'class': 'fc-week-number' },
+				date.format('w') // inner HTML
+			);
+		}
+
+		if (this.view.dayNumbersVisible) {
+			html += this.view.buildGotoAnchorHtml(
+				date,
+				{ 'class': 'fc-day-number' },
+				date.date() // inner HTML
+			);
+		}
+
+		html += '</td>';
+
+		return html;
 	},
 
 

+ 7 - 3
src/common/DayTableMixin.js

@@ -297,7 +297,7 @@ var DayTableMixin = FC.DayTableMixin = {
 
 		return '' +
 			'<th class="fc-day-header ' + view.widgetHeaderClass + ' fc-' + dayIDs[date.day()] + '"' +
-				(this.rowCnt == 1 ?
+				(this.rowCnt === 1 ?
 					' data-date="' + date.format('YYYY-MM-DD') + '"' :
 					'') +
 				(colspan > 1 ?
@@ -306,8 +306,12 @@ var DayTableMixin = FC.DayTableMixin = {
 				(otherAttrs ?
 					' ' + otherAttrs :
 					'') +
-			'>' +
-				htmlEscape(date.format(this.colHeadFormat)) +
+				'>' +
+				// don't make a link if the heading could represent multiple days, or if there's only one day (forceOff)
+				view.buildGotoAnchorHtml(
+					{ date: date, forceOff: this.rowCnt > 1 || this.colCnt === 1 },
+					htmlEscape(date.format(this.colHeadFormat)) // inner HTML
+				) +
 			'</th>';
 	},
 

+ 51 - 0
src/common/View.js

@@ -240,6 +240,57 @@ var View = FC.View = Class.extend(EmitterMixin, ListenerMixin, {
 	},
 
 
+	/* Navigation
+	------------------------------------------------------------------------------------------------------------------*/
+
+
+	// Generates HTML for an anchor to another view into the calendar.
+	// Will either generate an <a> tag or a non-clickable <span> tag, depending on enabled settings.
+	// `gotoOptions` can either be a moment input, or an object with the form:
+	// { date, type, forceOff }
+	// `type` is a view-type like "day" or "week". default value is "day".
+	// `attrs` and `innerHtml` are use to generate the rest of the HTML tag.
+	buildGotoAnchorHtml: function(gotoOptions, attrs, innerHtml) {
+		var date, type, forceOff;
+		var finalOptions;
+
+		if ($.isPlainObject(gotoOptions)) {
+			date = gotoOptions.date;
+			type = gotoOptions.type;
+			forceOff = gotoOptions.forceOff;
+		}
+		else {
+			date = gotoOptions; // a single moment input
+		}
+		date = FC.moment(date); // if a string, parse it
+
+		finalOptions = { // for serialization into the link
+			date: date.format('YYYY-MM-DD'),
+			type: type || 'day'
+		};
+
+		if (typeof attrs === 'string') {
+			innerHtml = attrs;
+			attrs = null;
+		}
+
+		attrs = attrs ? ' ' + attrsToStr(attrs) : ''; // will have a leading space
+		innerHtml = innerHtml || '';
+
+		if (!forceOff && this.opt('navLinks')) {
+			return '<a' + attrs +
+				' data-fc-goto="' + htmlEscape(JSON.stringify(finalOptions)) + '">' +
+				innerHtml +
+				'</a>';
+		}
+		else {
+			return '<span' + attrs + '>' +
+				innerHtml +
+				'</span>';
+		}
+	},
+
+
 	/* Rendering
 	------------------------------------------------------------------------------------------------------------------*/
 

+ 12 - 0
src/common/common.css

@@ -391,6 +391,18 @@ hr.fc-divider {
 }
 
 
+/* Internal Nav Links
+--------------------------------------------------------------------------------------------------*/
+
+a[data-fc-goto] {
+	cursor: pointer;
+}
+
+a[data-fc-goto]:hover {
+	text-decoration: underline;
+}
+
+
 /* Fake Table Rows
 --------------------------------------------------------------------------------------------------*/
 

+ 14 - 9
src/list/ListView.js

@@ -170,20 +170,25 @@ var ListViewGrid = Grid.extend({
 
 	// generates the HTML for the day headers that live amongst the event rows
 	dayHeaderHtml: function(dayDate) {
-		var mainFormat = this.view.opt('listDayFormat');
-		var altFormat = this.view.opt('listDayAltFormat');
+		var view = this.view;
+		var mainFormat = view.opt('listDayFormat');
+		var altFormat = view.opt('listDayAltFormat');
 
 		return '<tr class="fc-list-heading">' +
-			'<td class="' + this.view.widgetHeaderClass + '" colspan="3">' +
+			'<td class="' + view.widgetHeaderClass + '" colspan="3">' +
 				(mainFormat ?
-					'<span class="fc-list-heading-main">' +
-						htmlEscape(dayDate.format(mainFormat)) +
-					'</span>' :
+					view.buildGotoAnchorHtml(
+						dayDate,
+						{ 'class': 'fc-list-heading-main' },
+						htmlEscape(dayDate.format(mainFormat)) // inner HTML
+					) :
 					'') +
 				(altFormat ?
-					'<span class="fc-list-heading-alt">' +
-						htmlEscape(dayDate.format(altFormat)) +
-					'</span>' :
+					view.buildGotoAnchorHtml(
+						dayDate,
+						{ 'class': 'fc-list-heading-alt' },
+						htmlEscape(dayDate.format(altFormat)) // inner HTML
+					) :
 					'') +
 			'</td>' +
 		'</tr>';

+ 15 - 0
src/util.js

@@ -850,6 +850,21 @@ function cssToStr(cssProps) {
 }
 
 
+// Given an object hash of HTML attribute names to values,
+// generates a string that can be injected between < > in HTML
+function attrsToStr(attrs) {
+	var parts = [];
+
+	$.each(attrs, function(name, val) {
+		if (val != null) {
+			parts.push(name + '="' + htmlEscape(val) + '"');
+		}
+	});
+
+	return parts.join(' ');
+}
+
+
 function capitaliseFirstLetter(str) {
 	return str.charAt(0).toUpperCase() + str.slice(1);
 }