Skip to content

Commit abb4daf

Browse files
sandershihackerDerekTBrown
authored andcommitted
Search Functionality Complete #37 (#139)
* Updated Schemas * Load Screen * Loading Screen * publish subscribe and dynamic explore page * deleted swap file * publish subscribe * template fixes * added start for reactive publication * template issue * . * . * course_records publish * course_records reactively publish * revert meteor update * publish subscribe and lineheight for searchpage icons * fixed indentation and removed test file * indentation * indentation * Accounts page and fixed random erro * toolbar for mobile devices * toolbar * account.html fixes * Toolbar made responsive * Responsive toolbar fixes * created userlist component * course_records course_id validation * indentation * markdown * import changes * validation addition * Forms Module Deprecated Warning. Issue #110 * indentation * Use routerLink * api changes (#126) * issue 32 fixed * removed swp * fixed nconf issues * issue 82, 84 fixes * fixed #82 * isse #77 * fixed tests * fixed files * fixed tests master * fixed comment * moved validator * removed duplicate file * fixed tests, removed duplicate underscore, publish * changes * fixed methods.ts import * fixed issues w methods * fixes * minor fixes * A * api changes * fixed api * comments * minor changes * minor fixes * method implementations (#127) * issue 32 fixed * removed swp * fixed nconf issues * issue 82, 84 fixes * fixed #82 * isse #77 * fixed tests * fixed files * fixed tests master * fixed comment * moved validator * removed duplicate file * fixed tests, removed duplicate underscore, publish * changes * fixed methods.ts import * fixed issues w methods * fixes * minor fixes * A * api changes * fixed api * comments * minor changes * minor fixes * method implementations * course pages now uses Child Routing * deleted LabData class * school name * search function
1 parent ad66c07 commit abb4daf

File tree

12 files changed

+190
-176
lines changed

12 files changed

+190
-176
lines changed
Lines changed: 44 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,45 @@
11
<div class="tuxlab-searchview">
2-
<div class="md-whiteframe-5dp course-search-list">
3-
4-
<h2 id="search-string">Search Results</h2>
5-
6-
<div class="selector">
7-
<button md-button (click)="prevPage()" class="right">
8-
<md-icon fontIcon="tuxicon-left"></md-icon>
9-
Prev
10-
</button>
11-
<span [innerHTML]="getCurrentInfo()"></span>
12-
<button md-button (click)="nextPage()" class="right">
13-
Next
14-
<md-icon fontIcon="tuxicon-right"></md-icon>
15-
</button>
16-
</div>
17-
18-
<hr>
19-
<md-data-table layout-fill>
20-
<thead>
21-
<tr>
22-
<th class="md-text-cell">Course Number</th>
23-
<th class="md-text-cell">Course Name</th>
24-
<th>Instructor</th>
25-
</tr>
26-
</thead>
27-
<tbody>
28-
<tr *ngFor="let course of pagedCourses">
29-
<td class="md-text-cell">{{ course.course_number }}</td>
30-
<td class="md-text-cell">{{ course.course_name }}</td>
31-
<td>{{ course.instructor_name }}</td>
32-
</tr>
33-
</tbody>
34-
</md-data-table>
35-
<hr>
36-
37-
<div class="selector">
38-
<button md-button (click)="prevPage()" class="right">
39-
<md-icon fontIcon="tuxicon-left"></md-icon>
40-
Prev
41-
</button>
42-
<span [innerHTML]="getCurrentInfo()"></span>
43-
<button md-button (click)="nextPage()" class="right">
44-
Next
45-
<md-icon fontIcon="tuxicon-right"></md-icon>
46-
</button>
47-
</div>
48-
49-
</div>
50-
</div>
2+
<div class="md-whiteframe-5dp course-search-list">
3+
<h2 id="search-string">Search Results for '{{ searchQuery }}'</h2>
4+
<div class="selector">
5+
<button md-button (click)="prevPage()" class="right">
6+
<md-icon fontIcon="tuxicon-left"></md-icon>
7+
Prev
8+
</button>
9+
<span [innerHTML]="getCurrentInfo()"></span>
10+
<button md-button (click)="nextPage()" class="right">
11+
Next
12+
<md-icon fontIcon="tuxicon-right"></md-icon>
13+
</button>
14+
</div>
15+
<hr>
16+
<md-data-table layout-fill>
17+
<thead>
18+
<tr>
19+
<th class="md-text-cell">Course Number</th>
20+
<th class="md-text-cell">Course Name</th>
21+
<th>Instructor</th>
22+
</tr>
23+
</thead>
24+
<tbody>
25+
<tr *ngFor="let course of searchResults">
26+
<td class="md-text-cell">{{ course.course_number }}</td>
27+
<td class="md-text-cell">{{ course.course_name }}</td>
28+
<td>{{ course.instructor_ids }}</td>
29+
</tr>
30+
</tbody>
31+
</md-data-table>
32+
<hr>
33+
<div class="selector">
34+
<button md-button (click)="prevPage()" class="right">
35+
<md-icon fontIcon="tuxicon-left"></md-icon>
36+
Prev
37+
</button>
38+
<span [innerHTML]="getCurrentInfo()"></span>
39+
<button md-button (click)="nextPage()" class="right">
40+
Next
41+
<md-icon fontIcon="tuxicon-right"></md-icon>
42+
</button>
43+
</div>
44+
</div>
45+
</div>

client/imports/ui/components/explore/search.ts

Lines changed: 63 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import 'zone.js/dist/zone';
66

77
// Angular Imports
8-
import { Component, ViewEncapsulation, provide } from '@angular/core';
8+
import { Component, ViewEncapsulation, provide, Input } from '@angular/core';
99
import { bootstrap } from 'angular2-meteor-auto-bootstrap';
1010
import { APP_BASE_HREF, FORM_DIRECTIVES } from '@angular/common';
1111
import { HTTP_PROVIDERS } from '@angular/http';
@@ -39,83 +39,67 @@
3939

4040
// Export Explore Class
4141
export class SearchView extends MeteorComponent {
42+
@Input() searchQuery;
43+
@Input() searchResults;
44+
@Input() courseCount;
45+
@Input() currentPage;
46+
resultsPerPage = 15;
47+
constructor(mdIconRegistry: MdIconRegistry) {
48+
super();
49+
// Create Icon Font
50+
mdIconRegistry.registerFontClassAlias('tux', 'tuxicon');
51+
mdIconRegistry.setDefaultFontSetClass('tuxicon');
52+
}
4253

43-
courses: Array<any> = [];
44-
pagination = {
45-
currentPage: 1,
46-
itemsPerPage: 15,
47-
totalItems: this.courses.length
48-
};
49-
pagedCourses: Array<any> = [];
50-
51-
constructor(mdIconRegistry: MdIconRegistry) {
52-
super();
53-
54-
// Create Icon Font
55-
mdIconRegistry.registerFontClassAlias('tux', 'tuxicon');
56-
mdIconRegistry.setDefaultFontSetClass('tuxicon');
57-
58-
// Subscribe Courses Database
59-
//this.getCourses();
60-
this.subscribe('all-courses', () => {
61-
this.courses = courses.find().fetch();
62-
this.pagination.totalItems = this.courses.length;
63-
this.refreshCourses();
64-
}, true);
65-
}
66-
67-
// Refresh Courses List
68-
refreshCourses() {
69-
let start = (this.pagination.currentPage - 1) * this.pagination.itemsPerPage;
70-
let end = start + this.pagination.itemsPerPage;
71-
this.pagedCourses = this.courses.slice(start, end);
72-
}
73-
74-
// Display the infomation of current state of pagination
75-
getCurrentInfo() {
76-
// This is the number of the first item on the current page
77-
let start = (this.pagination.currentPage - 1) * this.pagination.itemsPerPage + 1;
78-
79-
// Set the end number to be the number of the last item on the page
80-
// Check in case there are less than itemsPerPage items on the page
81-
let end = 0;
82-
if ((start + this.pagination.itemsPerPage - 1) > this.pagination.totalItems) {
83-
end = this.pagination.totalItems;
84-
}
85-
else {
86-
end = start + this.pagination.itemsPerPage - 1;
87-
}
88-
89-
return start.toString() + "-" + end.toString() + " of " + this.pagination.totalItems.toString();
90-
}
91-
92-
// Go to next page function
93-
nextPage() {
94-
95-
// Get the current page
96-
let currentPage = this.pagination.currentPage;
97-
98-
// Get the last possible page
99-
let lastPage = Math.ceil(this.pagination.totalItems / this.pagination.itemsPerPage);
100-
101-
// Check if the current page is the last page
102-
if (currentPage !== lastPage) {
103-
this.pagination.currentPage ++;
104-
this.refreshCourses();
105-
}
106-
}
107-
108-
// Go to previous page function
109-
prevPage() {
110-
111-
// Get the current page
112-
let currentPage = this.pagination.currentPage;
113-
114-
// Check if the current page is the first page
115-
if (currentPage !== 1) {
116-
this.pagination.currentPage --;
117-
this.refreshCourses();
118-
}
119-
}
120-
}
54+
// Go to next page function
55+
nextPage() {
56+
let self = this;
57+
if (this.currentPage * this.resultsPerPage < this.courseCount) {
58+
this.currentPage++;
59+
Meteor.call('search_courses', this.searchQuery, this.resultsPerPage, this.currentPage, function(error, result) {
60+
if(error) {
61+
console.log(error);
62+
}
63+
else {
64+
self.searchResults = result.course_results;
65+
}
66+
});
67+
}
68+
}
12169

70+
// Go to previous page function
71+
prevPage() {
72+
let self = this;
73+
if(this.currentPage > 1) {
74+
this.currentPage--;
75+
Meteor.call('search_courses', this.searchQuery, this.resultsPerPage, this.currentPage, function(error, result) {
76+
if(error) {
77+
console.log(error);
78+
}
79+
else {
80+
self.searchResults = result.course_results;
81+
}
82+
});
83+
}
84+
}
85+
86+
getCurrentInfo() {
87+
var first = ((this.currentPage - 1) * this.resultsPerPage + 1);
88+
var last;
89+
if((first + this.resultsPerPage - 1) > this.courseCount) {
90+
last = this.courseCount;
91+
}
92+
else {
93+
last = first + this.resultsPerPage - 1;
94+
}
95+
if(first > last) {
96+
this.currentPage = 1;
97+
first = 1;
98+
}
99+
if(this.courseCount === 0) {
100+
first = 0;
101+
}
102+
return first + "-" + last + " of " + this.courseCount;
103+
}
104+
105+
}

client/imports/ui/pages/account/account.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<img src="{{ user.profile.picture }}">
66
</div>
77
<div class="account-display-name">
8-
<h2>{{ user.profile.name }}</h2>
8+
<h2>{{ user.profile.nickname }}</h2>
99
<p>{{ user.profile.school }}</p>
1010
<p>{{ user.profile.email }}</p>
1111
</div>

client/imports/ui/pages/course/mainview.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@
5656
// Create Icon Font
5757
mdIconRegistry.registerFontClassAlias('tux', 'tuxicon');
5858
mdIconRegistry.setDefaultFontSetClass('tuxicon');
59-
6059
// Subscribe to courses database and set current course
6160
this.subscribe('user-courses', this.courseNumber, () => {
6261
this.course = courses.findOne({ course_number: this.courseNumber });

client/imports/ui/pages/explore/explore.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,6 @@
2929

3030
<!-- Search View -->
3131
<div id="search-view">
32-
<tuxlab-searchview></tuxlab-searchview>
32+
<tuxlab-searchview [searchQuery]="searchQuery" [searchResults]="searchResults" [courseCount]="courseCount" [currentPage]="currentPage"></tuxlab-searchview>
3333
</div>
3434
</div>

client/imports/ui/pages/explore/explore.ts

Lines changed: 46 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import 'zone.js/dist/zone';
66

77
// Angular Imports
8-
import { Component, ViewEncapsulation, provide } from '@angular/core';
8+
import { Component, ViewEncapsulation, provide, Input } from '@angular/core';
99
import { bootstrap } from 'angular2-meteor-auto-bootstrap';
1010
import { APP_BASE_HREF } from '@angular/common';
1111
import { HTTP_PROVIDERS } from '@angular/http';
@@ -48,35 +48,50 @@
4848

4949
// Export Explore Class
5050
export default class Explore extends MeteorComponent {
51+
searchQuery: string;
52+
searchResults: Array<Object>;
53+
courseCount: number;
54+
resultsPerPage = 15;
55+
currentPage = 1;
56+
57+
constructor(mdIconRegistry: MdIconRegistry) {
58+
super();
59+
// Create Icon Font
60+
mdIconRegistry.registerFontClassAlias('tux', 'tuxicon');
61+
mdIconRegistry.setDefaultFontSetClass('tuxicon');
62+
}
5163

52-
constructor(mdIconRegistry: MdIconRegistry) {
53-
super();
54-
// Create Icon Font
55-
mdIconRegistry.registerFontClassAlias('tux', 'tuxicon');
56-
mdIconRegistry.setDefaultFontSetClass('tuxicon');
64+
// Find Course
65+
findCourse() {
66+
let searchQuery = (<HTMLInputElement>document.getElementById('search-input')).value;
67+
if (searchQuery !== '') {
68+
69+
// Switch view
70+
document.getElementById('explore-view').style.display = 'none';
71+
document.getElementById('search-view').style.display = 'block';
72+
document.getElementById('search-input').blur();
73+
74+
this.searchQuery = searchQuery;
75+
var self = this;
76+
this.currentPage = 1
77+
Meteor.call('search_courses', this.searchQuery, this.resultsPerPage, this.currentPage, function(err, res) {
78+
if(err) {
79+
console.log(err);
80+
}
81+
else {
82+
self.searchResults = res.course_results;
83+
self.courseCount = res.course_count;
84+
}
85+
});
86+
}
87+
else {
88+
document.getElementById('explore-view').style.display = 'block';
89+
document.getElementById('search-view').style.display = 'none';
90+
}
91+
}
5792

58-
// Set maximum width to full width for search bar
59-
document.getElementById('tux-content').style.maxWidth = "100%";
60-
}
61-
62-
// Find Course
63-
findCourse() {
64-
let searchQuery = (<HTMLInputElement>document.getElementById('search-input')).value;
65-
if (searchQuery !== '') {
66-
document.getElementById('explore-view').style.display = 'none';
67-
document.getElementById('search-view').style.display = 'block';
68-
document.getElementById('search-input').blur();
69-
document.getElementById('search-string').innerHTML = "Search Results for \'" + searchQuery + "\'";
70-
}
71-
else {
72-
document.getElementById('explore-view').style.display = 'block';
73-
document.getElementById('search-view').style.display = 'none';
74-
}
75-
}
76-
77-
// Search icon button
78-
searchFocus() {
79-
document.getElementById('search-input').focus();
80-
}
81-
82-
}
93+
// Search icon button
94+
searchFocus() {
95+
document.getElementById('search-input').focus();
96+
}
97+
}

collections/courses.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,14 +114,14 @@ courses.allow({
114114
// Check if userId indeed corresponds to a user in the database
115115
let user = Meteor.users.findOne(this.userId);
116116
if (typeof user !== "undefined") {
117-
117+
118118
// Get course ids of courses that the student is enroled in
119119
let studentCourseIds = (_.unzip((<any>user).roles.student))[0];
120120
if (typeof studentCourseIds !== "undefined") {
121121

122122
// Concatenate with the courseIds that the instructor is teaching
123123
let course_ids = studentCourseIds.concat((<any>user).roles.instructor);
124-
124+
125125
// Publish matching courses
126126
return courses.find({ _id: { $in:course_ids } });
127127
}

collections/labs.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,12 +99,10 @@ labs.allow({
9999
/* LAB VALIDATOR */
100100
if(Meteor.isServer){
101101
var validateLab : any = require('../server/imports/lab/checkLab.js');
102-
103102
Meteor.startup(function(){
104103
var LabValidator = function(userid, doc, fieldNames?, modifier?, options?){
105104
if (typeof fieldNames === "undefined"){
106105
if(!(doc.course_id && doc.file && //check for lab fields
107-
108106
Roles.isInstructorFor(doc.course_id,userid))){//check for instructor authorization
109107
return false;
110108
}

0 commit comments

Comments
 (0)