diff --git a/CHANGELOG.md b/CHANGELOG.md index c2e45a1..e6c8656 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## 0.5 (30 Nov 2015) +* Query courses +* you can now query by field, building, gender, hours, days ... +* Better performance and speed. +* Shows a warning before loading a long list of courses. +* Style fixes. +* Bug fixes. + ## 0.2 (13 Sep 2015) * Added exam day * Added exam hour diff --git a/README.md b/README.md index e1329cd..957659b 100644 --- a/README.md +++ b/README.md @@ -12,22 +12,23 @@ This is what khayyamJS does: # Features * Responsive design using bootstrap and JQuery. * Modern view of the page, using no \ elements. +* Filtering the courses by field, gender, building, day and hour. * Shows each session in a very nice table. -* Uses no popups. (with the power of JQuery) +* Uses no pop-ups. (with the power of JQuery) * Shows Course requirements. # How to install -## Firefox: +## Mozilla Firefox: 1. Install [Greasmonkey](https://addons.mozilla.org/en-us/firefox/addon/greasemonkey/). 2. Navigate to khayyamJS.user.script on github and click on the "Raw" button and Install the script. Alternatively use this [link](khayyamJS.user.js?raw=true) and click install. -## Chrome: +## Chromium / Google Chrome: 1. Install [Tampermonkey](https://chrome.google.com/webstore/detail/tampermonkey/dhdgffkkebhmkfjojejmpbldmpobfkfo). 2. Navigate to khayyamJS.user.script on github and click on the "Raw" button and Install the script. Alternatively use this [link](khayyamJS.user.js?raw=true) and click install. # To do +* Display a warning when session closes. * Querying the courses. -* Filtering the courses. * Selecting the courses and previewing the time sheet. # How to help @@ -45,8 +46,10 @@ This is something I'm doing on my free time. Continuing to do so is mostly relat # امکانات * طراحی کاملا واکنش‌گرا (با استفاده از بوت‌استرپ و جی‌کوئری) * طراحی مدرن صفحه بدون استفاده از المان \ +* قابلیت فیلتر کردن کلاس‌ها بر اساس زمان، روز، رشته، جنسیت و ساختمان * نمایش ساعت کلاس در یک جدول زیبا * بدون نمایش پاپ‌آپ و نمایش تمام اطلاعات در یک صفحه. +* نمایش وابستگی‌های دروس. # نحوه‌ی نصب ## فایرفاکس @@ -58,9 +61,8 @@ This is something I'm doing on my free time. Continuing to do so is mostly relat 2. نمایش فایل khayyamJS.user.js در گیت‌هاب و کلیک بر روی دکمه‌ی Raw و نصب اسکریپت. همچنین می‌توانید از [این لینک](khayyamJS.user.js?raw=true) استفاده کنید. # امکانات آینده -* اضافه کردن امکان نمایش پیش‌نیاز/هم‌نیاز +* نمایش اخطار به هنگام بسته‌شدن میزکار و ورود دوباره. * جستجو در دروس -* فیلتر کردن دروس * انتخاب دورس و پیش‌نمایش جدول زمانی درس‌های انتخاب شده. # راه‌های کمک به پروژه: diff --git a/khayyamJS.user.js b/khayyamJS.user.js index 61e84bf..6013004 100644 --- a/khayyamJS.user.js +++ b/khayyamJS.user.js @@ -34,7 +34,7 @@ Github: https://github.com/tuxitop/khayyamJS // @namespace http://alimsvi.ir/ // @description changes the UI of the presented course list in the student portal of Khayyam university of Mashhad. // @include http://stu.khayyam.ac.ir/strcss/ShowPresentedCourses.php -// @version 0.2 +// @version 0.5 // @author Ali Mousavi // @require https://code.jquery.com/jquery-1.10.2.js // @require https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js @@ -42,6 +42,371 @@ Github: https://github.com/tuxitop/khayyamJS // ==/UserScript== +// define page class. +var Page = function() { + /* Main page class */ + + // private functions + var mkInfo = function() { + /* creates and returns an object with different arrays to use + in filters, etc. */ + var coursesArray = []; + var fieldsArray = []; + var bldgArray = []; + // loop through each table row. + $("tr").each(function(i, row) { + // find each column in the row and add it to courseColArray. + var courseColArray = []; + var columns = $(this).find("td"); + columns.each(function() { + courseColArray.push($(this).html()); + }); + // this if is because the header line doesn't have any "td"s + if (courseColArray.length) { + var course = new Course(i, courseColArray); + coursesArray.push(course); + // add fields if it's not added before + var field = course.degree + " " + course.field; + if ( fieldsArray.indexOf(field) === -1 ) { + fieldsArray.push(field); + } + // Add bldgs the same way as fields + if ( bldgArray.indexOf(course.bldg) === -1 ) { + bldgArray.push(course.bldg); + } + } + }); + return { + courses: coursesArray, + fields: fieldsArray, + bldgs: bldgArray + }; + }; + + // Public methods. + this.infoObj = mkInfo(); + this.courses = this.infoObj.courses; + this.fields = this.infoObj.fields; + this.bldgs = this.infoObj.bldgs; + this.filters = { + field: "all", + gender: "all", + bldg: "all", + weight: "all", + days: [0, 1, 2, 3, 4, 5], + hours: [0, 1, 2, 3, 4], + }; +}; +// create a prototype (this way I can have private methods) +Page.prototype.mkBody = function() { + // makes the page ready and creates the body of the page. + $("center").prevAll("script").remove(); + $("center, style, link").remove(); + + // add necessary styleseets. + $('head').append( + '' + + '' + + '' + + '' + ); + + //navbar + $("body").append( + '' + ); + $(".navbar-nav").data("size", "big"); + $(window).scroll(function(event) { + if ( $(document).scrollTop() ) { + if ( $(".navbar-nav").data("size") === "big" ) { + $(".navbar-nav li a, .navbar-brand").animate({"padding": "3px 15px 0 15px", "height": "30px"}); + $(".navbar-nav").data("size", "small"); + } + } + else if ( $(".navbar-nav").data("size") === "small" ) { + $(".navbar-nav li a, .navbar-brand").animate({"padding": "15px 15px 10px 15px", "height": "50px"}); + $(".navbar-nav").data("size", "big"); + } + }); + $('#about-link').click(function(event) { + event.preventDefault(); + $('#about-container').slideToggle(); + $('#about-link').toggleClass('clicked'); + }); + + // the jumbotron + $("body").append( + '
' + + '
' + + '

فهرست درس‌های ارایه شده

' + + '
' + + '
'); + + // Filter Section + // Loop to create options for field select. + var fieldOptions = ""; + this.fields.map(function(current) { + fieldOptions += ""; + }); + // Loop to create options for building select. + var bldgOptions = ""; + this.bldgs.map(function(current) { + bldgOptions += ""; + }); + $("body").append( + '
' + + '
' + + '
' + + '

فیلتر کلاس‌ها:

' + + '
' + + '
رشته:
' + + '' + + '
جنسیت:
' + + '' + + '
ساختمان:
' + + '' + + '
واحد:
' + + '' + + '
' + + '
' + + '
روز:
' + + '' + + '' + + '' + + '' + + '' + + '' + + '
' + + '
' + + '
ساعت:
' + + '' + + '' + + '' + + '' + + '' + + '
' + + '
' + + '
' + + '
' + ); + + // filter actions: + $("#field-select").change(function() { + app.filters.field = $(this).val(); + app.createCourseTable(); + }); + $("#gender-select").change(function() { + app.filters.gender = $(this).val(); + app.createCourseTable(); + }); + $("#bldg-select").change(function() { + app.filters.bldg = $(this).val(); + app.createCourseTable(); + }); + $("#weight-select").change(function() { + app.filters.weight = $(this).val(); + app.createCourseTable(); + }); + $("input:checkbox[name='hour']").change(function() { + var selected_hours = []; + $("input:checkbox[name='hour']:checked").each(function(index, el) { + selected_hours.push(parseInt($(this).val())); + }); + app.filters.hours = selected_hours; + app.createCourseTable(); + }); + $("input:checkbox[name='day']").change(function() { + var selected_days = []; + $("input:checkbox[name='day']:checked").each(function(index, el) { + selected_days.push(parseInt($(this).val())); + }); + app.filters.days = selected_days; + app.createCourseTable(); + }); + + // courses list + $("body").append( + '
' + + '
' + + '

با توجه به تعداد زیاد کلاس‌ها، بهتر است نتایج را از طریق فیلترها محدود کنید.

' + + '
برای نمایش کلیه کلاس‌ها روی دکمه‌ی زیر کلیک کنید و توجه کنید که این کار ممکن است زمان‌بر باشد.
' + + 'نمایش کلاس‌ها بدون فیلتر' + + '
' + + '
' + ); + // course table button action: + $('#course-table-btn').click(function() { + app.createCourseTable(); + }); + + // footer + $("body").append(''); +}; +Page.prototype.isValid = function(course) { + // function to check if course is valid according to the selected filters. + + var valid = true; // for some weired reason it doesn't work with returning false. + // test field + if ( app.filters.field !== 'all' ) { + var current_field = course.degree + " " + course.field; + if ( current_field.trim() !== app.filters.field.trim() ) { + valid = false; + } + } + // test gender + if ( app.filters.gender !== 'all') { + if (course.getGender()[0] != app.filters.gender) { + valid = false; + } + } + // test building + if ( app.filters.bldg !== 'all') { + if (course.bldg != app.filters.bldg) { + valid = false; + } + } + // test building + if ( app.filters.weight !== 'all') { + if (course.weight[0] != app.filters.weight) { + valid = false; + } + } + // test hours + if (app.filters.hours.length < 5) { + var sessions = course.getSessionsArray(); + sessions.forEach(function(current_session) { + if ( app.filters.hours.indexOf(current_session.hourCode) === -1) { + valid = false; + } + }); + } + // test days + if (app.filters.days.length < 6) { + var sessions = course.getSessionsArray(); + sessions.forEach(function(current_session) { + if ( app.filters.days.indexOf(current_session.dayCode) === -1) { + valid = false; + } + }); + } + return valid; +}; +Page.prototype.createCourseTable = function() { + // Removes the old table and creates a new one, applying the filters. + $(".course-list").children().remove(); + this.courses.forEach(function(current_course) { + if ( app.isValid(current_course) === true ) { + current_course.addToPage(); + } + }); + $('.course-header').click(function() { + $(this).next().slideToggle(); + $(this).find(".fa-chevron-left").toggleClass("fa-rotate-270"); + }); +}; + + // define a course class. var Course = function(index, courseColArray) { /* the first element is the row index in html class and @@ -52,7 +417,7 @@ var Course = function(index, courseColArray) { this.index = index; this.id = "course-" + this.index; this.stGroupID = courseColArray[2]; - this.title = courseColArray[3]; + this.title = courseColArray[3].replace(/ي/g, "ی"); this.weight = courseColArray[4]; this.stSigned = courseColArray[5]; this.stCapacity = courseColArray[6]; @@ -60,21 +425,20 @@ var Course = function(index, courseColArray) { this.stVacancyPercent = (this.stVacancy / this.stCapacity) * 100; this.faculty = courseColArray[7]; this.teacherID = courseColArray[8]; - this.teacher = courseColArray[9]; + this.teacher = courseColArray[9].replace(/ي/g, "ی"); // courseColArray 1 consists of specs that should be extracted differently. // the regular expressions to extract different parts of specs. var re_specs = /(.+)<\/body>/g; var re_courseID = /(\d+)<\/a>/g; - var re_field = /رشته (مهندسی )?(.*?) دوره/; + var re_field = /رشته (مهندسی)? *?(.*?)دوره/; var re_degree = /مقطع:<\/b> (.*?)
/g; var re_bldg = /,ساختمان ?(\d)\)/g; var re_exam = /امتحان روز:<\/b> ?(.*?) ?ساعت ?(\d+)/g; - this.specs = re_specs.exec(courseColArray[1])[1]; this.courseID = re_courseID.exec(courseColArray[1])[1]; - this.field = re_field.exec(courseColArray[1])[2]; - this.degree = re_degree.exec(courseColArray[1])[1]; + this.field = re_field.exec(courseColArray[1])[2].trim(); + this.degree = re_degree.exec(courseColArray[1])[1].trim(); this.examDay = "-"; this.examHour = "-"; if ( (examMatch = re_exam.exec(courseColArray[1])) !== null) { @@ -92,7 +456,6 @@ var Course = function(index, courseColArray) { this.sessionsArray = this.getSessionsArray(); this.reqsArray = this.getReqsArray(); }; - Course.prototype.addToPage = function () { // make the list. $(".course-list").append('
' + @@ -298,7 +661,8 @@ Course.prototype.getGender = function() { returns array of [genderCode, genderIcon, genderName] code is 0 for male, 1 for female, 2 for both. */ - var re_gender = /قابل انتخاب برای دانشجویان:<\/b> ((مرد)?( و )?(زن)?) /g; + var re_gender = /قابل انتخاب برای دانشجویان:<\/b> ((مرد)?( و )?(زن)?)( | | )/g; + var reMatch = re_gender.exec(this.specs); var code, icon; if (reMatch[2]) { @@ -324,157 +688,11 @@ Course.prototype.bldgHTML = function() { this.bldg + '
'; }; - -var mkCourseArray = function() { - /* creates and returns a courses array function. should only be called once - at the beggining */ - var coursesArray = []; - // loop through each table row. - $("tr").each(function(i, row) { - // find each column in the row and add it to courseColArray. - var courseColArray = []; - var columns = $(this).find("td"); - columns.each(function() { - courseColArray.push($(this).html()); - }); - // this if is because the header line doesn't have any "td"s - if (courseColArray.length) { - coursesArray.push(new Course(i, courseColArray)); - } - }); - return coursesArray; -}; - - -var createBody = function() { - // makes the page ready and creates the body of the page. - $("center").prevAll("script").remove(); - $("center, style, link").remove(); - - // add necessary styleseets. - $('head').append( - '' + - '' + - '' + - '' - ); - - //navbar - $("body").append( - '' - ); - $(".navbar-nav").data("size", "big"); - $(window).scroll(function(event) { - if ( $(document).scrollTop() ) { - if ( $(".navbar-nav").data("size") === "big" ) { - $(".navbar-nav li a, .navbar-brand").animate({"padding": "3px 15px 0 15px", "height": "30px"}); - $(".navbar-nav").data("size", "small"); - } - } - else if ( $(".navbar-nav").data("size") === "small" ) { - $(".navbar-nav li a, .navbar-brand").animate({"padding": "15px 15px 10px 15px", "height": "50px"}); - $(".navbar-nav").data("size", "big"); - } - }); - $('#about-link').click(function(event) { - event.preventDefault(); - $('#about-container').slideToggle(); - $('#about-link').toggleClass('clicked'); - }); - - // the jumbotron - $("body").append( - '
' + - '
' + - '

فهرست درس‌های ارایه شده

' + - '
' + - '
'); - - // Filter Part - $("body").append( - '
' + - '
' + - '
' + - '

فیلتر درس‌ها:

' + - '
' + - '
رشته:
' + - '' + - '
' + - '
' + - '
' + - '
' - ); - - // coures list - $("body").append('
'); - - // footer - $("body").append(''); -}; - - $(document).ready(function(){ - var coursesArray = mkCourseArray(); - createBody(); - coursesArray.forEach(function(current_course) { - current_course.addToPage(); - }); - $('.course-header').click(function() { - $(this).next().slideToggle(); - $(this).find(".fa-chevron-left").toggleClass("fa-rotate-270"); - }); + app = new Page(); + // var coursesArray = app.courses; + app.mkBody(); + if (app.courses.length <= 150) { + app.createCourseTable(); + } }); diff --git a/screenshots/screenshot-khayyamJS.png b/screenshots/screenshot-khayyamJS.png index 31ca671..1c400eb 100644 Binary files a/screenshots/screenshot-khayyamJS.png and b/screenshots/screenshot-khayyamJS.png differ diff --git a/style.css b/style.css index 64e40fb..0fb27db 100644 --- a/style.css +++ b/style.css @@ -25,6 +25,8 @@ This is the style used with KhayyamJS. Author: Ali Mousavi (ali.mousavi@gmail.com) github: https://github.com/tuxitop/khayyamJS +Last Updated: Nov 30th, 2015 +version: 0.5 */ @import url(http://fonts.googleapis.com/earlyaccess/droidarabicnaskh.css); @@ -87,6 +89,11 @@ body { color: #000; } +.query-panel .row { + margin-left: 0; + margin-right: 0; +} + .query-title { font-size: 18px; margin: 5px 0; @@ -97,6 +104,21 @@ body { padding: 3px 12px; } +label { + margin-top: 8px; + padding-right: 2px !important; + padding-left: 10px !important; +} + +input[type=checkbox] { + margin: 4px 4px 0; +} + +.panel-warn { + background-color: #D9E5F5; + padding-bottom: 10px; +} + .fa-male { color: blue; } @@ -120,6 +142,10 @@ body { background-color: #FFF; } +.panel-default:nth-of-type(odd) > .panel-body { + background-color: whitesmoke; +} + .course-specs { display: none; }