SlideShare a Scribd company logo
SWAD, an Open
Learning Management System
Including timeline implementation
Antonio Cañas
University of Granada (UGR)
@acanasvargas acanas@ugr.es acanas@openswad.org
https://openswad.org/ @openswad
SWAD, an Open
Learning Management System
Including timeline implementation
Antonio Cañas
University of Granada (UGR)
@acanasvargas acanas@ugr.es acanas@openswad.org
https://openswad.org/ @openswad
1
1
Antonio Cañas et al.
May 27, 2022, Granada, Spain
May 27, 2022, Granada, Spain
Contents
●
History
●
Summary of features
●
swad.ugr.es
●
Figures
●
Keys to success
●
OpenSWAD
●
Project
●
Advertising
●
Figures
●
Free software
●
Implementation
●
Timeline
●
Notes & publications
●
Database
●
Getting publications
●
Showing publications
●
Layout
●
Inserting links
●
Future goals and tasks
●
Conclusions
●
About us
History
“The best time to plant a tree was 20 years ago.
The second best time is now.”
Chinese proverb
History
“The best time to plant a tree was 20 years ago.
The second best time is now.”
Chinese proverb
History
●
LMS in 2022: a very broad offer
●
Hundreds of LMS
●
proprietary / free software
●
expensive / free of charge
●
installable on the client's servers / accessible in the cloud
History
524
History
1071
...but in 1999 not so many available → we started to develop our own system:
Sistema Web de Apoyo a la Docencia
(Web System for Teaching Support)
⬇
Social Workspace At a Distance
https://swad.ugr.es/ https://openswad.org/
A web platform to manage courses, students and teachers,
with functions to support teaching and learning.
History
Dpt.ATC: 1999-2003
1º TIP: 2003-2004
2º TIP: 2005-2006
3º TIP: 2006-2008
V.L.Center:2008-2016
Free Software: 2010...
UNA.py: 2012-2014
OpenSWAD: 2012…
Dpt.ATC: 2016...
History
openswad.org
2012...
ugr.es CEVUG
2008-2016
ugr.es TIPs
2003-2008
ugr.es ATC
1999-2003
una.py
2012-2015
ugr.es ATC
2016...
23 years of development and use
free software
2010...
Summary of features
“swad: a bunch, a grouping
of a number of similar things”
.
https://www.thefreedictionary.com/swad
Summary of features
“swad: a bunch, a grouping
of a number of similar things”
.
https://www.thefreedictionary.com/swad
Summary of features
This is how it looks.
Some parts of its appearance,
such as colors or icons, are customizable
Summary of features
Free software · 9 languages · Responsive design · Android app
· Face-to-face or blended learning
Hierarchical organization: System · Countries · Institutions
(universities, companies) · Centers (faculties, schools) ·
Degrees · Courses · Group types · Groups
10 available roles: Unknown · Guest · User · Student · Non-
editing teacher · Teacher · Degree admin · Center admin ·
Institution admin · System admin
Summary of features
Social network · Calendar · Notifications · Course
information · Syllabus · Documents · Shared files ·
Portfolio · Grades · Assignments · Projects · Exam
announcements · Quizzes · Exams · Games · Surveys ·
Groups · Lists of students and teachers · Attendance
control using QR codes · Forums · Notices · Messaging
system · Statistics · Agenda · Preferences
All features in https://github.com/acanas/swad-core/wiki/UserGuide.en
swad.ugr.es: Figures
“What goes up,
must come down”
“What goes up”, The Alan Parsons Project - British rock band
swad.ugr.es: Figures
“What goes up,
must come down”
“What goes up”, The Alan Parsons Project - British rock band
485 million
clicks (page views)
389
million
(80%)
students
26
million
(5%)
teachers
69
million
(14%)
others
1
million
(<1%)
admin.
swad.ugr.es: Figures (Jan 2005 May
→ 2022)
199,794
users have used the platform
174,879
(88%)
as students
3933
(2%)
as teachers
36,479
(18%)
as guests
133
(<1%)
as admin.
swad.ugr.es: Figures (Jan 2005 May
→ 2022)
2,0million
messages sent
21,4million
messages received
swad.ugr.es: Figures (Jan 2005 May
→ 2022)
155,950
current users
129,589
(83%)
students
3651
(2%)
teachers
23,171
(15%)
guests
119
(<1%)
admin.
swad.ugr.es: Figures (May 2022)
...from 1108institutions
ugr
115,780
(74%)
from UGR
11,351
(7%)
from other institutions
28,819
(18%)
unknown
538
degrees
7654
courses
swad.ugr.es: Figures (May 2022)
835,619 (1.9 TB)
files
47,349
test questions
1403
forums
26 million
times answered
66,589
posts
swad.ugr.es: Figures (May 2022)
swad.ugr.es: Figures (Oct 1999 May 2022)
→
7654 courses
5104 with students
swad.ugr.es: Figures (Oct 1999 May 2022)
→
3651 teachers
swad.ugr.es: Figures (Oct 1999 May 2022)
→
129,589 students
swad.ugr.es: Figures (2005 2021)
→
real users / academic year
swad.ugr.es: Figures (Jan 2005 May 2022)
→
page views / week
swad.ugr.es: Figures (Jan 2005 May 2022)
→
users / week
swad.ugr.es:
keys to success
“Want your users to fall in love with your designs?
Fall in love with your users.”
Dana Chisnell - Designer and usability researcher
swad.ugr.es:
keys to success
“Want your users to fall in love with your designs?
Fall in love with your users.”
Dana Chisnell - Designer and usability researcher
swad.ugr.es: Keys to success
●
#1: Platform open to the entire University since 2004
I Meeting of SWAD Users
swad.ugr.es: Keys to success
●
#2: Teacher training
swad.ugr.es: Keys to success
●
#3: User support: thousands of queries answered
Thank you for your help and efficiency...
and for having designed a computer invention that really works,
which reconciles me with the new technologies...
●
#4: Developed according to the users’ requests
swad.ugr.es: Keys to success
A user wants the platform
to congratulate him
on his birthday...
Days later a new feature
congratulates users
for their birthdays.
swad.ugr.es: Keys to success
●
#5: Strengths of the tool
●
Functionality and usability
●
Simplicity
●
It has what most teachers asked
●
Reliability and safety
●
It consumes few resources
●
It works 24 hours, fast and almost without failures
OpenSWAD: Project
“A planet is the cradle of mind,
but one cannot live in a cradle forever.”
Konstantin Tsiolkovski - Russian physicist
OpenSWAD: Project
“A planet is the cradle of mind,
but one cannot live in a cradle forever.”
Konstantin Tsiolkovski - Russian physicist
OpenSWAD: Project
●
SWAD outside the UGR after release
●
Little diffusion
●
Difficult to reach the target audience (need for advertising)
●
Absence of simple installation
●
Many competitors
●
Many LMS, some of them very widespread
●
Released as free software too late (2010)
●
A lot of work, small team
●
Conclusion
●
Very few (two or three) installations
OpenSWAD: Project
●
OpenSWAD.org is an installation in the cloud of the SWAD educational
platform, offered free of charge for any country by the OpenSWAD
Association (non-profit organization, independent of the UGR)
●
OpenSWAD.org is available since 2012, but it did not start growing until
2015, when we decided to carry out advertising campaigns
OpenSWAD: Project
●
Why “Open”?
●
Free software
●
So open source
●
Open and free for everyone
●
Open design and interaction
●
You can access many features (hierarchy, courses, teachers, statistics) even if you are not logged in
●
Open content allowed
●
Upload, mark as public and choose license
●
Anyone could access, even without log in
OpenSWAD: Project
Steps for internationalization:
1. Code independent from the institution (100%)
2. Translation to 9 languages (90%)
3. ISO 8601 format for date-times (100%)
4. Dates-hours independent of location (100%)
5. Calendars independent of location (100%)
6. Weeks starting on Monday or Sunday (100%)
7. Floating point / comma format (10%)
OpenSWAD: Advertising
“Doing business without advertising is like winking at
a girl in the dark. You know what you are doing, but
nobody else does.”
Steuart Henderson Britt - American professor of marketing
OpenSWAD: Advertising
“Doing business without advertising is like winking at
a girl in the dark. You know what you are doing, but
nobody else does.”
Steuart Henderson Britt - American professor of marketing
OpenSWAD.org: Advertising
2,600,000 ad impressions on Twitter and Facebook
2,600,000 ad impressions on Twitter and Facebook
2600 filled in their data (50%)
2600 filled in their data (50%)
260 created center, degree, course (10%)
260 created center, degree, course (10%)
130,000 clicked link (5%)
130,000 clicked link (5%)
5200 created account (
5200 created account (4%
4%)
)
130 enrolled in course (50%)
130 enrolled in course (50%)
65 created course content (50%)
65 created course content (50%)
13 used with students (20%, 5 per million)
13 used with students (20%, 5 per million)
Example: Feb. 2015 March 2016
→
Conversion funnel
OpenSWAD.org: Advertising
Cost Dates Days Cost/day Impressions Clicks Cost/click
Twitter 4650.29€ Feb 12, 2015
Sep 25, 2017
956 4.86 € 14,042,284 50,119 €0.108
Facebook 2400.84€ Sep 26, 2015
Sep 25, 2017
730 3.29 € 12,858,591 192,833 €0.012
AdWords 1255.93€ Feb 16, 2017
Sep 25, 2017
221 5.68 € 392,298 15,046 €0.083
Total 8307.06€ Feb 12, 2015
Sep 25, 2017
956 8.69 € 27,293,173 257,998 €0.032
Courses Teachers Students Total users
Courses or users with real use 528 385 1657 18 411
Cost per course or user €15,73 €21,58 €5,01 €0,45
Cost of advertising (2015 2017)
→
OpenSWAD.org: Advertising
Cost Dates Days Impresiones Clicks Page views Users New
accounts
New
courses
Twitter €66.20 Sep 6 -
Sep 24,
2017
7
€9.46 /
day
271,072
€0.00024 /
impression
734
€0.09 /
click
14 632
€0.0045 /
page view
342
€0.19 /
user
186
€0.36 / new
account
10
€6.62 / new
course
Facebook €109.66 Sep 7 -
Sep 25,
2017
7
€15.66 /
day
148,206
€0.00074 /
impression
3780
€0.03 /
click
33 087
€0.0033 /
page view
274
€0.40 /
user
114
€0.96 / new
account
12
€9.14 / new
course
AdWords €65.83 Sep 5 -
Sep 23,
2017
7
€9.40 /
day
13,210
€0.00498 /
impression
808
€0.08 /
click
11 169
€0.0060 /
page view
243
€0.27 /
user
94
€0.70 / new
account
7
€9.40 / new
course
Total €241.69 Sep 5 -
Sep 25,
2017
21
€11.51 /
day
432,488
€0.00056 /
impression
5322
€0.05 /
click
58 888
€0.0041 /
page view
859
€0.28 /
user
394
€0.61 / new
account
29
€8.33 / new
course
Conversion comparison (2017)
OpenSWAD: Figures
“Y si no me quieres ver, ya sabes que
seguro que hay alguien que querrá.”
“Volverás”, Niños Mutantes – Spanish indie rock band
OpenSWAD: Figures
“Y si no me quieres ver, ya sabes que
seguro que hay alguien que querrá.”
“Volverás”, Niños Mutantes – Spanish indie rock band
5,5million
clicks (page views)
1,628,546
(30%)
students
855,078
(16%)
teachers
2,709,476
(49%)
others
322,654
(6%)
admin.
OpenSWAD: Jan 2014 May 2022
→
34,803
current users
5639
(16%)
students
1949
(6%)
teachers
27,549
(79%)
guests
150
(<1%)
admin.
OpenSWAD: May 2022
from 152
countries
from 2173
institutions
23,593
institutions
2642
centers
2968
degrees
4553
courses
OpenSWAD: May 2022
First countries in OpenSWAD according to number of users
First countries in OpenSWAD according to number of users
OpenSWAD: Users / country
34,803 users
from 152 countries
OpenSWAD: Users / country
●
A report on OpenSWAD was even broadcast on a Latin American TV channel
OpenSWAD in Atomun, Telesur TV (Venezuela), July 2017
OpenSWAD: Users / institution
Users from 2173 institutions
OpenSWAD: Users / month 2014 2022
→
Advertisements
OpenSWAD: Teachers / month 2014 2022
→
Advertisements
OpenSWAD: Students / month 2014 2022
→
Advertisements
Free software
“You're frozen
When your heart's not open”
“Frozen”, Madonna - American singer-songwriter
Free software
“You're frozen
When your heart's not open”
“Frozen”, Madonna - American singer-songwriter
Free software
January 21, 2010
Free Software Office of the University of Granada
Free software
●
Steps to release the core:
1. Code (names, comments) in English (100%)
2. Code independent from the UGR (100%)
3. Translation to 9 languages (90%)
4. Add AGPL headers to files (100%)
5. Publish the source code (100%) https://openswad.org/source/
6. Publish the installation procedure (100%) https://openswad.org/install/
7. Use git version control system (100%)
8. Upload to GitHub (100%) https://github.com/acanas/swad-core
9. Desirable: automate installation (20%)
Free software
●
Because it facilitates collaborative development
Fourth Hackathon of free software projects of the UGR, 2012. Photo: A. Cañas
Free software
●
Because it encourages better programming
@psicobyte_ explains the benefits of free software. Photo: A. Cañas
Free software
●
Because it improves the code quality
Hackathon of SWADroid and SWAD, 2013. Photo: A. Cañas
Free software
●
Because it provides freedom and security to users
https://www.gnu.org/philosophy/
Implementation
“Every step that you take
Could be your biggest mistake
It could bend or it could break
That's the risk that you take”
“What If”, Coldplay - British rock band
Implementation
“Every step that you take
Could be your biggest mistake
It could bend or it could break
That's the risk that you take”
“What If”, Coldplay - British rock band
How much work is behind?
swad-core SWADroid
Affero GPL v3 license
https://github.com/acanas/swad-core
GPL v3 license
https://github.com/Amab/SWADroid
364,503
C code lines
144
MySQL tables
60,761
Java code lines
17K
downloads
95 person-years
estimated effort*
14 person-years
estimated effort*
$5,239,555
estimated cost*
$793,894
estimated cost*
Other modules and more info: https://openswad.org/source
* According to the COCOMO model in Open Hub
The core
●
Written from scratch in C
(compiled, not interpreted)
✔Advantages:
●
+ speed
●
- memory
●
Functional even in a Raspberry Pi
●
+ stability of source code over time
✘Disadvantages:
●
absence of specialized library functions for the web
2nd: 2004-2006
Pentium 4 HT
RAM 2 GiB
2 HD 160 GB
Fedora 3
3rd: 2007-2008
Core 2 Duo
RAM 4 GiB
2 HD 500 GB
Fedora 6
4th: 2009-2010
Core 2 Quad
RAM 4 GiB
2 HD 146 GB
2 HD 1 TB
Fedora 10
5th: 2011-2016
2 Xeon Quad
RAM 24 GiB
4 HD 146 GB
4 HD 500 GB
CentOS 5.7
1st: 1999-2003
Shared server
Former servers at the UGR
Current server at the UGR (6th: 2016-2022)
●
HP Proliant DL160 G9, 2 Xeon with 6 cores, RAM 32 GiB
4 HD 146 GB
SAS 15000 rpm
RAID 1+0 (292 GB)
SO CentOS 7.2
MySQL database
4 HD 1 TB
SAS 7200 rpm
RAID 5 (3 TB)
Web files
( /var/www )
Plugins
●
It is possible to develop add-ons (plugins) that run on:
●
other servers
●
mobile devices. Example: SWADroid
●
The plugins interact with the swad core through an API:
https://openswad.org/api/
Photographs of users
●
Our own automatic system for detecting faces and
improving the quality of photos, trained with 90K photos
Up to 400K times per day
Up to 2000 times / minute (30 times / second)
Log
“click”
logged access
HTML5
server
database
swad-core
144 database tables.
The largest is the one
used to store the access log.
Database
Log table
●
It allows analyzing a lot of information:
●
By role
●
By user
●
By action performed
●
By qualification
●
By subject
●
By dates
●
...
UGR: 485 million registered hits since 2005
Log table
Pages per minute
(averaged during an academic year)
teachers
students
Log table
Matches of the Soccer World Cup 2010
You can even see the rest in the match
Log table
Peak: students choosing groups
Page views per minute
Log table
●
What if we convert every click into a sound?
●
At 1 am:
http://swad.ugr.es/stat/clicks/clicks_1am.wav
●
At 1 pm:
http://swad.ugr.es/stat/clicks/clicks_1pm.wav
●
Peak (students choosing groups):
http://swad.ugr.es/stat/clicks/clicks_grupos.wav
Timeline:
Notes & Publications
“You think you know when you learn, are more sure
when you can write, even more when you can teach,
but certain when you can program.”
Alan Perlis - Computer scientist and professor
Timeline:
Notes & Publications
“You think you know when you learn, are more sure
when you can write, even more when you can teach,
but certain when you can program.”
Alan Perlis - Computer scientist and professor
Timeline: Notes & Publications
●
Timeline: set of publications
●
from a user
●
global
●
Only me
●
Followed users
●
All users
typedef enum
{
Tml_Usr_TIMELINE_USR,
Tml_Usr_TIMELINE_GBL,
} Tml_Usr_UsrOrGbl_t;
typedef enum
{
Usr_WHO_UNKNOWN,
Usr_WHO_ME,
Usr_WHO_SELECTED, // Not applicable to timeline
Usr_WHO_FOLLOWED,
Usr_WHO_ALL,
} Usr_Who_t;
Timeline: Notes & Publications
●
Publication: · original note (25393, 76% of 33504)
· shared note ( 1425, 4% of 33504)
· comment to a note ( 6686, 20% of 33504)
typedef enum
{
Tml_Pub_UNKNOWN = 0,
Tml_Pub_ORIGINAL_NOTE = 1,
Tml_Pub_SHARED_NOTE = 2,
Tml_Pub_COMMENT_TO_NOTE = 3,
} TmlPub_Type_t;
struct TmlPub_Publication
{
long PubCod; // Publication code
long NotCod; // Note code
long PublisherCod; // Sharer or writer of the publication
TmlPub_Type_t Type; // Original note, shared note, comment
struct TmlPub_Publication *Next; // Used for chained list
};
*swad.ugr.es, may 2022
Timeline: Notes & Publications
●
Note: timeline post ( 4755, 19% of 25393)
public file ( 66, <1% of 25393)
call for exam ( 2807, 11% of 25393)
notice (17480, 69% of 25393)
forum post ( 285, 1% of 25393)
*swad.ugr.es, may 2022
Timeline: Notes & Publications
typedef enum
{
TmlNot_UNKNOWN = 0,
/* Start tab */
TmlNot_POST = 10, // Post written directly in timeline
/* Institution tab */
TmlNot_INS_DOC_PUB_FILE = 1, // Public file in documents of institution
TmlNot_INS_SHA_PUB_FILE = 2, // Public file in shared files of institution
/* Center tab */
TmlNot_CTR_DOC_PUB_FILE = 3, // Public file in documents of center
TmlNot_CTR_SHA_PUB_FILE = 4, // Public file in shared files of center
/* Degree tab */
TmlNot_DEG_DOC_PUB_FILE = 5, // Public file in documents of degree
TmlNot_DEG_SHA_PUB_FILE = 6, // Public file in shared files of degree
/* Course tab */
TmlNot_CRS_DOC_PUB_FILE = 7, // Public file in documents of course
TmlNot_CRS_SHA_PUB_FILE = 8, // Public file in shared files of course
/* Assessment tab */
TmlNot_CALL_FOR_EXAM = 9, // Call for exam in a course
/* Users tab */
/* Messages tab */
TmlNot_NOTICE = 12, // A public notice in a course
TmlNot_FORUM_POST = 11, // Post in global/swad forums
/* Analytics tab */
/* Profile tab */
} TmlNot_Type_t;
Timeline: Notes & Publications
struct TmlNot_Note
{
long NotCod; // Unique code/identifier for each note
TmlNot_Type_t Type; // Timeline post, public file,
// call for exam, notice, forum post...
long UsrCod; // Publisher
long HieCod; // Hierarchy code
// (institution/center/degree/course)
long Cod; // Code of file, forum post,
// notice, timeline post...
bool Unavailable; // File, forum post, notice...
// unavailable (removed)
time_t DateTimeUTC; // Date-time of publication in UTC time
unsigned NumShared; // Number of times (users)
// this note has been shared
unsigned NumFavs; // Number of times (users)
// this note has been favourited
};
Timeline: Notes & Publications
__________________
|@author |
| Note |
|__________________|
|@author |
| Comment 1 |
|______________|
|@author |
| Comment 2 |
|______________|
| |
| ... |
|______________|
|@author |
| Comment n |
|______________|
●
A note can have comments attached to it:
Timeline: Notes & Publications
_tml_pubs______ _tml_comments
| | | |
| Publication p |---------->| Comment c |-----+
| (comment) | | (to note 2) | |
|_______________| |_____________| |
| | | | |
· ... · · ... · |
· ... · · ... · |
|_______________| |_____________| |
| | | | |
|Publication i+4|---------->| Comment 1 |---+ |
| (comment) | | (to note n) | | |
|_______________| |_____________| | |
| | (6686) | |
|Publication i+3|-- | |
|(original note)|  | |
|_______________|  _tml_notes_____ | | _cfe_exams_____
| |  | | | | | |
|Publication i+2|-- ---->| Note n |<-+ | | Call for exam | (5649)
|(original note)|  |(exam announc.)|-(2807)->|_______________|
|_______________|  |_______________| 11% __brw_files____
| |  | | | | |
|Publication i+1|-- ---->| Note n-1 |-(66)--->| Public file | (1561098)
|(original note)|  | (public file) | <1% |_______________|
|_______________|  |_______________| | _not_notices___
| |  | | | | |
| Publication i |-- ---->| Note n-2 |-(17480)>| Notice | (15219)
|(original note)|  | (notice) | 69% |_______________|
|_______________|  |_______________| | __tml_posts____
| |  | | | | |
· ... · ---->| Note n-3 |-(4755)->| Post s |
· ... · | (tl. post) | 19% | |
|_______________| |_______________| | |_______________|
| | | | | | |
| Publication 3 | · ... · | · ... · (4755)
| (shared note) |--- · ... · | · ... ·
|_______________|  |_______________| | |_______________|
| |  | | | | |
| Publication 2 | ---->| Note 2 |<---+ | Post 1 |
|(original note)|--------->| (tl. post) |-------->| |
|_______________| |_______________| |_______________|
| | | | _for_posts_____
| Publication 1 |--------->| Note 1 | | |
|(original note)| | (forum post) |-(285)-->| Forum post | (66612)
|_______________| |_______________| 1% |_______________|
(33504) (25393)
timeline posts
public files
calls for exams
notices
forum posts
notes
comments
publications *swad.ugr.es, may 2022
Timeline: Database
“Don't forget to put the WHERE
in the DELETE FROM.”
Jorge Rubira Santos - Entrepreneur and Youtuber
Timeline: Database
“Don't forget to put the WHERE
in the DELETE FROM.”
Jorge Rubira Santos - Entrepreneur and Youtuber
144 database tables.
7 for timeline.
Timeline: Database
Timeline: Database
mysql> SHOW TABLES LIKE 'tml_%';
+------------------------+
| Tables_in_swad (tml_%) |
+------------------------+
| tml_comments |
| tml_comments_fav |
| tml_notes |
| tml_notes_fav |
| tml_posts |
| tml_pubs |
| tml_timelines |
+------------------------+
7 rows in set (0.00 sec)
Timeline: Database
mysql> DESCRIBE tml_pubs;
+--------------+----------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+----------+------+-----+---------+----------------+
| PubCod | bigint | NO | PRI | NULL | auto_increment |
| NotCod | bigint | NO | MUL | NULL | |
| PublisherCod | int | NO | MUL | NULL | |
| PubType | tinyint | NO | MUL | NULL | |
| TimePublish | datetime | NO | MUL | NULL | |
+--------------+----------+------+-----+---------+----------------+
Timeline: Database
mysql> DESCRIBE tml_notes;
+-------------+---------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------------+------+-----+---------+----------------+
| NotCod | bigint | NO | PRI | NULL | auto_increment |
| NoteType | tinyint | NO | MUL | NULL | |
| Cod | int | NO | | -1 | |
| UsrCod | int | NO | MUL | NULL | |
| HieCod | int | NO | | -1 | |
| Unavailable | enum('N','Y') | NO | | N | |
| TimeNote | datetime | NO | MUL | NULL | |
+-------------+---------------+------+-----+---------+----------------+
mysql> DESCRIBE tml_notes_fav;
+---------+----------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+----------+------+-----+---------+----------------+
| FavCod | bigint | NO | PRI | NULL | auto_increment |
| NotCod | bigint | NO | MUL | NULL | |
| UsrCod | int | NO | MUL | NULL | |
| TimeFav | datetime | NO | | NULL | |
+---------+----------+------+-----+---------+----------------+
Timeline: Database
mysql> DESCRIBE tml_comments;
+--------+----------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+----------+------+-----+---------+-------+
| PubCod | bigint | NO | PRI | NULL | |
| Txt | longtext | NO | MUL | NULL | |
| MedCod | int | NO | MUL | -1 | |
+--------+----------+------+-----+---------+-------+
mysql> DESCRIBE tml_comments_fav;
+---------+----------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+----------+------+-----+---------+----------------+
| FavCod | bigint | NO | PRI | NULL | auto_increment |
| PubCod | bigint | NO | MUL | NULL | |
| UsrCod | int | NO | MUL | NULL | |
| TimeFav | datetime | NO | | NULL | |
+---------+----------+------+-----+---------+----------------+
Timeline: Database
mysql> DESCRIBE tml_posts;
+--------+----------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------+----------+------+-----+---------+----------------+
| PstCod | int | NO | PRI | NULL | auto_increment |
| Txt | longtext | NO | MUL | NULL | |
| MedCod | int | NO | MUL | -1 | |
+--------+----------+------+-----+---------+----------------+
mysql> DESCRIBE cfe_exams;
+-------------+---------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------------+------+-----+---------+----------------+
| ExaCod | int | NO | PRI | NULL | auto_increment |
| ... | ... | ... | ... | ... | ... |
mysql> DESCRIBE brw_files;
+-----------------+---------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+---------------+------+-----+---------+----------------+
| FilCod | int | NO | PRI | NULL | auto_increment |
| ... | ... | ... | ... | ... | ... |
mysql> DESCRIBE not_notices;
+-----------+----------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+----------+------+-----+---------+----------------+
| NotCod | int | NO | PRI | NULL | auto_increment |
| ... | ... | ... | ... | ... | ... |
mysql> DESCRIBE for_posts;
+-----------+----------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+----------+------+-----+---------+----------------+
| PstCod | int | NO | PRI | NULL | auto_increment |
| ... | ... | ... | ... | ... | ... |
Timeline: Database
mysql> DESCRIBE tml_timelines;
+-----------+----------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+----------+------+-----+---------+-------+
| SessionId | char(43) | NO | PRI | NULL | |
| NotCod | bigint | NO | PRI | NULL | |
+-----------+----------+------+-----+---------+-------+
mysql> DESCRIBE tml_tmp_timeline;
+--------+--------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+--------+------+-----+---------+-------+
| NotCod | bigint | NO | PRI | NULL | NULL |
+--------+--------+------+-----+---------+-------+
What is being displayed on the screens of each of the users
What is being displayed on the current user's screen
Timeline:
Getting publications
“When I wrote this code, only God and I understood
what I did. Now only God knows.”
Unknown source
Timeline:
Getting publications
“When I wrote this code, only God and I understood
what I did. Now only God knows.”
Unknown source
Timeline: Getting publications
●
Our algorithm:
●
Select publications one by one in a loop
●
In each iteration:
●
Get the most recent publication (original, shared or comment)
checking that its note is not already retrieved
●
After getting a publication, save its note code to not get it again.
SELECT PubCod
FROM tml_pubs
WHERE NotCod NOT IN
(SELECT NotCod
FROM tml_tmp_timeline)
ORDER BY PubCod DESC
LIMIT 1;
Timeline: Getting publications
●
Slower alternative (may need seconds for large tables):
●
Get the maximum PubCod, i.e more recent publication (original, shared or commment),
of every set of publications corresponding to the same note:
SELECT MAX(PubCod) AS NewestPubCod
FROM tml_pubs
GROUP BY NotCod
ORDER BY NewestPubCod DESC
LIMIT 10;
Timeline: Getting publications
●
Restricting publications to mine and those I follow:
CREATE TEMPORARY TABLE fol_tmp_me_and_followed
(UsrCod INT NOT NULL,
UNIQUE INDEX(UsrCod)) ENGINE=MEMORY
SELECT my_usr_cod AS UsrCod
UNION
SELECT FollowedCod AS UsrCod
FROM usr_follow
WHERE FollowerCod=my_usr_cod;
------------------------------
SELECT tml_pubs.PubCod,
tml_pubs.NotCod,
tml_pubs.PublisherCod,
tml_pubs.PubType
FROM tml_pubs,
fol_tmp_me_and_followed
WHERE tml_pubs.PublisherCod=fol_tmp_me_and_followed.UsrCod
AND tml_pubs.NotCod NOT IN
(SELECT NotCod
FROM tml_tmp_timeline)
ORDER BY PubCod DESC
LIMIT 1;
mysql> DESCRIBE usr_follow;
+-------------+----------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+----------+------+-----+---------+-------+
| FollowerCod | int | NO | PRI | NULL | |
| FollowedCod | int | NO | PRI | NULL | |
| FollowTime | datetime | NO | MUL | NULL | |
+-------------+----------+------+-----+---------+-------+
Timeline: Getting publications
●
Three types of timeline updates
_ ______________________
/ |______________________|
New < |______________________|
_|______________________|
_|_See_new_activity_(3)_|
/ |______________________|
| |______________________|
Recent < |______________________|
| |______________________|
_|______________________|
_|_______See_more_______|
/ |______________________|
| |______________________|
Old < |______________________|
| |______________________|
_|______________________|
typedef enum
{
Tml_GET_NEW_PUBS, // automatically
// from time
// to time (AJAX)
Tml_GET_REC_PUBS, // user clicks
// on menu
// or after
// editing
// timeline
Tml_GET_OLD_PUBS, // user clicks
// on bottom
// link (AJAX)
} Tml_WhatToGet_t;
Timeline: Getting publications
tml_pubs
_____
|_____|11
|_____|10
_|_____| 9 <-- RangePubsToGet.Top
Get / |_____| 8
pubs | |_____| 7
from < |_____| 6
this | |_____| 5
range _|_____| 4
|_____| 3 <-- RangePubsToGet.Bottom
|_____| 2
|_____| 1
0
Timeline: Getting publications
case Tml_GET_REC_PUBS: // Get some limited recent publications
/* First query to get initial timeline shown
==> no notes yet in current timeline table */
RangePubsToGet->Top = 0;
/* _ _____ 0 <-- RangePubsToGet.Top = +infinite
/ |_____| 8
Get | |_____| 7
pubs < |_____| 6
from | |_____| 5
all | |_____| 4
range . |_____| 3
. |_____| 2
. |_____| 1
0 <-- RangePubsToGet.Bottom = -infinite */
RangePubsToGet->Bottom = 0;
Timeline: Getting publications
case Tml_GET_NEW_PUBS: // Get the publications (without limit)
// newer than last pub. code
/* Via AJAX automatically from time to time */
RangePubsToGet->Top = 0;
/* _ _____ 0 <-- RangePubsToGet.Top = +infinite
Get / |_____|11
these < |_____|10
pubs _|_____| 9
/ |_____| 8 <-- RangePubsToGet.Bottom = last pub. code
Pubs | |_____| 7
already < |_____| 6
shown | |_____| 5
| |_____| 4
. |_____| .
. |_____| .
. |_____| .
*/
RangePubsToGet->Bottom = Tml_DB_GetPubCodFromSession (Tml_Pub_LAST);
Timeline: Getting publications
case Tml_GET_OLD_PUBS: // Get some limited publications
// older than first pub. code
/* Via AJAX when I click in link to get old publications */
RangePubsToGet->Top = Tml_DB_GetPubCodFromSession (Tml_Pub_FIRST);
/* _____
. |_____| .
. |_____| .
. |_____| .
Pubs | |_____| 8
already < |_____| 7
shown | |_____| 6
| |_____| 5
Get _|_____| 4 <-- RangePubsToGet.Top = first pub. code
pubs / |_____| 3
from < |_____| 2
this _|_____| 1
rage 0 <-- RangePubsToGet.Bottom = -infinite */
RangePubsToGet->Bottom = 0;
Timeline: Getting publications
●
Restricting publications to range:
SELECT tml_pubs.PubCod,
tml_pubs.NotCod,
tml_pubs.PublisherCod,
tml_pubs.PubType
FROM tml_pubs,
fol_tmp_me_and_followed
WHERE tml_pubs.PublisherCod=fol_tmp_me_and_followed.UsrCod
AND tml_pubs.PubCod>bottom // if type == Tml_GET_REC_PUBS
AND tml_pubs.PubCod<top // updated every iteration
// to last pub. code got
AND tml_pubs.NotCod NOT IN
(SELECT NotCod
FROM tml_tmp_timeline)
ORDER BY PubCod DESC
LIMIT 1;
Timeline: Getting publications
Timeline->Pubs.Top Pub #0
______ ______ Pub #1
|______|------>|______| ______ Pub #2
|______| -> |______| ______ Pub #3
|______| / |______| ->|______| ______
|______| / |______| / |______| ->|______|
|_Next_|-- |______| / |______| // |______|
more recent |_Next_|-- |______| // |______|
______ |_Next_|--/ |______|
|______|---------------------------------------------- |_NULL_|
older
Timeline->Pubs.Bottom
●
After getting the publications, the result is a chained list:
Timeline:
Showing publications
“There is beauty when something works
and works intuitively.”
Jonathan Paul Ive - Designer
Timeline:
Showing publications
“There is beauty when something works
and works intuitively.”
Jonathan Paul Ive - Designer
Timeline: Showing publications
_____
/ |_____| just_now_timeline_list (Posts retrieved automatically
| |_____| via AJAX from time to time.
| |_____| They are transferred inmediately
| | to new_timeline_list.)
Hidden < __v__
| |_____| new_timeline_list (Posts retrieved but hidden.
| |_____| When user clicks to view them,
| |_____| the most recent of each note is
 |_____| is transferred
| to visible timeline_list.)
See new activity (0)
__v__
/ |_____| timeline_list (Posts visible on page)
| |_____|
Visible | |_____|
on < |_____|
page | |_____|
| |_____|
 |_____|
^
See more
__|__
/ |_____| old_timeline_list (Posts just retrieved via AJAX
| |_____| when user clicks "see more".
| |_____| They are transferred inmediately
Hidden < |_____| to timeline_list.)
| |_____|
| |_____|
 |_____|
<ul id="just_now_timeline_list" ...>
</ul>
<ul id="new_timeline_list" ...>
</ul>
<div id="view_new_container" ...
style="display:none;">
<a href="" ...
onclick="moveNewTimelineToTimeline();
return false;">
See new activity
(<span id="view_new_count">
0
</span>)
</a>
</div>
<ul id="timeline_list" ...>
visible timeline
</ul>
<div id="view_old_container" ...>
<a href="" ...
onclick="...
refreshOldTimeline();
return false;">
...
See more
</a>
</div>
<ul id="old_timeline_list" ...>
</ul>
Timeline: Showing publications
<head>
...
<script type="text/javascript" ...>
var delayNewTml = Cfg_TIME_TO_REFRESH_TIMELINE; // 2000 ms
function init() {
ActionAJAX = "SWAD_URL";
...
setTimeout('refreshNewTimeline()',delayNewTL);
...
}
</script>
<script type="text/javascript" ...>
var refreshParamIdSes = "ses=...";
var refreshParamNxtActNewPub = "act=...";
var refreshParamWho = "Who=...";
</script>
...
</head>
<body onload="init();">
...
</body>
●
Automatic refresh via AJAX every 2 s → 3 s → 4 s...
_____
/ |_____| just_now_timeline_list
| |_____|
| |_____|
| |
Hidden < __v__
| |_____| new_timeline_list
| |_____|
| |_____|
 |_____|
|
See new activity (0)
__v__
/ |_____| timeline_list
| |_____|
Visible | |_____|
on < |_____|
page | |_____|
| |_____|
 |_____|
^
See more
__|__
/ |_____| old_timeline_list
| |_____|
| |_____|
Hidden < |_____|
| |_____|
| |_____|
 |_____|
Timeline: Showing publications
var objXMLHttpReqNewTml = false;
function refreshNewTimeline () {
objXMLHttpReqNewTml = AJAXCreateObject(); // new XMLHttpRequest()
if (objXMLHttpReqNewTml) {
var RefreshParams = refreshParamNxtActNewPub + '&' +
refreshParamIdSes + '&' +
refreshParamWho;
objXMLHttpReqNewTml.onreadystatechange = readNewTimelineData;
objXMLHttpReqNewTml.open('POST',ActionAJAX,true);
objXMLHttpReqNewTml.setRequestHeader('Content-Type',
'application/x-www-form-urlencoded');
objXMLHttpReqNewTml.send(RefreshParams);
}
}
_____
/ |_____| just_now_timeline_list
| |_____|
| |_____|
| |
Hidden < __v__
| |_____| new_timeline_list
| |_____|
| |_____|
 |_____|
|
See new activity (0)
__v__
/ |_____| timeline_list
| |_____|
Visible | |_____|
on < |_____|
page | |_____|
| |_____|
 |_____|
^
See more
__|__
/ |_____| old_timeline_list
| |_____|
| |_____|
Hidden < |_____|
| |_____|
| |_____|
 |_____|
Timeline: Showing publications
function readNewTimelineData () {
if (objXMLHttpReqNewTml.readyState == 4) // Check if data have been received
if (objXMLHttpReqNewTml.status == 200) {
// Access to UL for just now timeline
var justNowTimeline = document.getElementById('just_now_timeline_list');
if (justNowTimeline) {
// Update list of publications in just now timeline
justNowTimeline.innerHTML = objXMLHttpReqNewTml.responseText;
var numNotesJustGot = justNowTimeline.childNodes.length;
if (numNotesJustGot) {// New notes received
// Scripts in timeline got via AJAX not executed ==> execute them
evalScriptsInElem (justNowTimeline);
// Process maths
MathJax.typeset();
...
_____
/ |_____| just_now_timeline_list
| |_____|
| |_____|
| |
Hidden < __v__
| |_____| new_timeline_list
| |_____|
| |_____|
 |_____|
|
See new activity (0)
__v__
/ |_____| timeline_list
| |_____|
Visible | |_____|
on < |_____|
page | |_____|
| |_____|
 |_____|
^
See more
__|__
/ |_____| old_timeline_list
| |_____|
| |_____|
Hidden < |_____|
| |_____|
| |_____|
 |_____|
Timeline: Showing publications
...
// Move all the LI elements (notes) in UL 'just_now_timeline_list'
// ...to the top of UL 'new_timeline_list'
var newTimeline = document.getElementById('new_timeline_list');
for (var i=0; i<numNotesJustGot; i++) {
// Move node from just now timeline to new timeline
newTimeline.insertBefore(justNowTimeline.lastChild,
newTimeline.firstChild);
newTimeline.firstChild.className += " Tml_NEW_PUB";
}
// Update number of notes in new timeline
var viewNewCount = document.getElementById('view_new_count');
viewNewCount.innerHTML = newTimeline.childNodes.length;
// Unhide message with number of notes if hidden
var viewNewContainer = document.getElementById('view_new_container');
viewNewContainer.style.display = '';
}
}
// Global delay variable is set initially in swad-core
delayNewTml += 1000; // Increase one second on each call
setTimeout('refreshNewTimeline()',delayNewTml);
}
}
_____
/ |_____| just_now_timeline_list
| |_____|
| |_____|
| |
Hidden < __v__
| |_____| new_timeline_list
| |_____|
| |_____|
 |_____|
|
See new activity (0)
__v__
/ |_____| timeline_list
| |_____|
Visible | |_____|
on < |_____|
page | |_____|
| |_____|
 |_____|
^
See more
__|__
/ |_____| old_timeline_list
| |_____|
| |_____|
Hidden < |_____|
| |_____|
| |_____|
 |_____|
_____
/ |_____| just_now_timeline_list
| |_____|
| |_____|
| |
Hidden < __v__
| |_____| new_timeline_list
| |_____|
| |_____|
 |_____|
|
See new activity (0)
__v__
/ |_____| timeline_list
| |_____|
Visible | |_____|
on < |_____|
page | |_____|
| |_____|
 |_____|
^
See more
__|__
/ |_____| old_timeline_list
| |_____|
| |_____|
Hidden < |_____|
| |_____|
| |_____|
 |_____|
Timeline: Showing publications
function moveNewTimelineToTimeline () {
// Move the LI elements (notes) in UL 'new_timeline_list'...
// ...to the top of UL 'timeline_list', only if not repeated before
var newTimeline = document.getElementById('new_timeline_list');
var numNewNotes = newTimeline.childNodes.length;
if (numNewNotes) {
var timeline = document.getElementById("timeline_list");
for (var i=1; i<=numNewNotes; i++) {
// Check if the last child (the oldest) in the new timeline...
// ...is the last ocurrence of the note
var mostRecentOcurrenceOfNote = true;
var lastChildIndex = numNewNotes - i;
var noteCode = newTimeline.lastChild.dataset.noteCode;
for (var j=0; j<lastChildIndex; j++)
if (newTimeline.childNodes[j].dataset.noteCode == noteCode) {
mostRecentOcurrenceOfNote = false;
break;
}
...
●
User clicks "See new activity" → View new pubs.
Timeline: Showing publications
...
// Move or remove node from new timeline
if (mostRecentOcurrenceOfNote) {
// Move node from new timeline to timeline
timeline.insertBefore(newTimeline.lastChild,timeline.firstChild);
timeline.firstChild.className += " Tml_NEW_PUB";
}
else
// Remove last child (because is repeated in more recent pubs)
newTimeline.removeChild(newTimeline.lastChild);
}
}
// Reset number of new publications after moving
var viewNewCount = document.getElementById('view_new_count');
viewNewCount.innerHTML = 0;
// Hide link to view new publications after moving
var viewNewContainer = document.getElementById('view_new_container');
viewNewContainer.style.display = 'none';
}
_____
/ |_____| just_now_timeline_list
| |_____|
| |_____|
| |
Hidden < __v__
| |_____| new_timeline_list
| |_____|
| |_____|
 |_____|
|
See new activity (0)
__v__
/ |_____| timeline_list
| |_____|
Visible | |_____|
on < |_____|
page | |_____|
| |_____|
 |_____|
^
See more
__|__
/ |_____| old_timeline_list
| |_____|
| |_____|
Hidden < |_____|
| |_____|
| |_____|
 |_____|
_____
/ |_____| just_now_timeline_list
| |_____|
| |_____|
| |
Hidden < __v__
| |_____| new_timeline_list
| |_____|
| |_____|
 |_____|
|
See new activity (0)
__v__
/ |_____| timeline_list
| |_____|
Visible | |_____|
on < |_____|
page | |_____|
| |_____|
 |_____|
^
See more
__|__
/ |_____| old_timeline_list
| |_____|
| |_____|
Hidden < |_____|
| |_____|
| |_____|
 |_____|
Timeline: Showing publications
var objXMLHttpReqOldTml = false;
function refreshOldTimeline () {
objXMLHttpReqOldTml = AJAXCreateObject (); // new XMLHttpRequest()
if (objXMLHttpReqOldTml) {
var refreshParams = refreshParamNxtActOldPub + '&' +
refreshParamIdSes;
if (typeof refreshParamUsr !== 'undefined') {
if (refreshParamUsr.length)
refreshParams += '&' + refreshParamUsr;
}
if (typeof refreshParamWho !== 'undefined') {
if (refreshParamWho.length)
refreshParams += '&' + refreshParamWho;
}
objXMLHttpReqOldTml.onreadystatechange = readOldTimelineData;
objXMLHttpReqOldTml.open('POST',actionAJAX,true);
objXMLHttpReqOldTml.setRequestHeader('Content-Type',
'application/x-www-form-urlencoded');
objXMLHttpReqOldTml.send(refreshParams);
}
}
●
User clicks "See more..." → View old pubs.
Timeline: Showing publications
function readOldTimelineData () {
if (objXMLHttpReqOldTml.readyState == 4) // Check if data have been received
if (objXMLHttpReqOldTml.status == 200) {
// Access to UL with the old timeline
var oldTimeline = document.getElementById('old_timeline_list');
if (oldTimeline) {
// Fill list of publications in old timeline
oldTimeline.innerHTML = objXMLHttpReqOldTml.responseText;
var countOldTimeline = oldTimeline.childNodes.length;
if (countOldTimeline) {
// Scripts in timeline got via AJAX not executed ==> execute them
evalScriptsInElem (oldTimeline);
// Process maths
MathJax.typeset();
// Move all the LI elements in UL 'old_timeline_list'
// to the bottom of UL 'timeline_list'
var timeline = document.getElementById("timeline_list");
for (var i=0; i<countOldTimeline; i++)
timeline.appendChild(oldTimeline.firstChild);
...
_____
/ |_____| just_now_timeline_list
| |_____|
| |_____|
| |
Hidden < __v__
| |_____| new_timeline_list
| |_____|
| |_____|
 |_____|
|
See new activity (0)
__v__
/ |_____| timeline_list
| |_____|
Visible | |_____|
on < |_____|
page | |_____|
| |_____|
 |_____|
^
See more
__|__
/ |_____| old_timeline_list
| |_____|
| |_____|
Hidden < |_____|
| |_____|
| |_____|
 |_____|
Timeline: Showing publications
...
// There may be more publications
// Unhide icon to be hidden on click
document.getElementById('get_old_timeline').style.display = '';
// Hide icon to be shown on click
document.getElementById('getting_old_timeline').style.display = 'none';
}
else // No old publications retrieved, so we have reached the oldest pub.
// Hide container with link to get old publications
document.getElementById("view_old_pubs_container").style.display = 'none';
}
}
}
_____
/ |_____| just_now_timeline_list
| |_____|
| |_____|
| |
Hidden < __v__
| |_____| new_timeline_list
| |_____|
| |_____|
 |_____|
|
See new activity (0)
__v__
/ |_____| timeline_list
| |_____|
Visible | |_____|
on < |_____|
page | |_____|
| |_____|
 |_____|
^
See more
__|__
/ |_____| old_timeline_list
| |_____|
| |_____|
Hidden < |_____|
| |_____|
| |_____|
 |_____|
Timeline: Layout
“Don't make me think.”
Steve Krug - User Experience professional
Timeline: Layout
“Don't make me think.”
Steve Krug - User Experience professional
Timeline: Layout
___________________________________________
| | 
| Top message: | > top message
|___________________________________________| /
| _____ | | |  
|| | | Author's name | Date-time | | |
||Auth.| |______________________|___________| | |
||photo| | | | author's |
||_____| | | > name, time |
| | Note | | and content |
| | content | | |
| | | | |
| |__________________________________| / |
| | | | |  |
| | Favs | Shared |Remove| | > note
| |_____________|_____________|______| | |
|________| | | |
| | List | | buttons |
| Comment| of | > and |
| icon | comments | | comments |
|________|__________________________________| | |
| | | |
| Form to write new comment | | |
|__________________________________| / /
Timeline: Layout
●
Top message
<div class="Tml_TOP_CONT Tml_TOP_PUBLISHER Tml_WIDTH">
<form method="post" action="https://openswad.org/en" id="form_..." ...>
<input type="hidden" name="act" value="1402">
<input type="hidden" name="ses" value="...">
<input type="hidden" name="OtherUsrCod" value="...">
<button type="submit" title="Another user's profile"
class="BT_LINK Tml_TOP_PUBLISHER">
user name
</button>
</form>
has shared:
</div>
Timeline: Layout
___________________________________________
| | 
| Top message: | > top message
|___________________________________________| /
| _____ | | |  
|| | | Author's name | Date-time | | |
||Auth.| |______________________|___________| | |
||photo| | | | author's |
||_____| | | > name, time |
| | Note | | and content |
| | content | | |
| | | | |
| |__________________________________| / |
| | | | |  |
| | Favs | Shared |Remove| | > note
| |_____________|_____________|______| | |
|________| | | |
| | List | | buttons |
| Comment| of | > and |
| icon | comments | | comments |
|________|__________________________________| | |
| | | |
| Form to write new comment | | |
|__________________________________| / /
Timeline: Layout
●
Photo
<div class="Tml_LEFT_PHOTO">
<form method="post" action="https://openswad.org/en" id="form_..." ...>
<input type="hidden" name="act" value="1402">
<input type="hidden" name="ses" value="...">
<input type="hidden" name="OtherUsrCod" value="...">
<button type="submit" class="BT_LINK">
<img src="user-photo.jpg" alt="" title="username" class="PHOTO45x60"
onmouseover="zoom(this,'user-photo.jpg','id_...');" onmouseout="noZoom();">
<div id="id_..." class="NOT_SHOWN">
<div class="ZOOM_TXT_LINE DAT_N_BOLD">first name<br>last name</div>
<div class="ZOOM_TXT_LINE DAT_SMALL_N">@nickname</div>
<div class="ZOOM_TXT_LINE DAT_SMALL">institution&nbsp;(country)</div>
<div class="ZOOM_TXT_LINE DAT_SMALL">
<div class="ZOOM_DEG" style="background-image:url('user-icon.svg');">degree</div>
</div>
<div class="ZOOM_TXT_LINE">
<span class="DAT_N_BOLD">1</span><span class="DAT_SMALL">&nbsp;Following&nbsp;</span>
<span class="DAT_N_BOLD">1</span><span class="DAT_SMALL">&nbsp;Followers</span>
</div>
</div>
</button>
</form>
</div>
Photo
caption
Timeline: Layout
___________________________________________
| | 
| Top message: | > top message
|___________________________________________| /
| _____ | | |  
|| | | Author's name | Date-time | | |
||Auth.| |______________________|___________| | |
||photo| | | | author's |
||_____| | | > name, time |
| | Note | | and content |
| | content | | |
| | | | |
| |__________________________________| / |
| | | | |  |
| | Favs | Shared |Remove| | > note
| |_____________|_____________|______| | |
|________| | | |
| | List | | buttons |
| Comment| of | > and |
| icon | comments | | comments |
|________|__________________________________| | |
| | | |
| Form to write new comment | | |
|__________________________________| / /
Timeline: Layout
●
Author's name, date-time and note content
<div class="Tml_RIGHT_CONT Tml_RIGHT_WIDTH">
<form method="post" action="https://openswad.org/en" id="form_..." ...>
<input type="hidden" name="act" value="1402">
<input type="hidden" name="ses" value="...">
<input type="hidden" name="OtherUsrCod" value="...">
<button type="submit" title="My public profile"
class="BT_LINK Tml_RIGHT_AUTHOR Tml_RIGHT_AUTHOR_WIDTH DAT_N_BOLD">
user name
</button>
</form>
<div id="id_..." class="Tml_RIGHT_TIME DAT_LIGHT">date,&nbsp;time</div>
<script type="text/javascript">
writeLocalDateHMSFromUTC ('id_...',unix-time,1,',&nbsp;',3,true,true,false,0x6);
</script>
<div class="Tml_TXT">
post content
</div>
</div>
Timeline: Layout
function writeLocalDateHMSFromUTC (id,TimeUTC,DateFormat,
Separator,Language,
WriteToday,WriteDateOnSameDay,
WriteWeekDay,WriteHMS) {
// HMS: Hour, Minutes, Seconds
var today = new Date();
var todayYea = today.getFullYear ();
var todayMon = today.getMonth () + 1;
var todayDay = today.getDate ();
var d = new Date();
var WriteDate;
var Yea,Mon,Day;
var DayOfWeek;
var Hou,Min,Sec;
var StrDat;
var StrMon;
var StrDay;
var StrHou;
var StrMin;
var StrSec;
d.setTime (TimeUTC * 1000);
Yea = d.getFullYear ();
Mon = d.getMonth () + 1;
Day = d.getDate ();
if (WriteDateOnSameDay)
WriteDate = true;
// Check to see if the last date has been initialized
else if (typeof writeLocalDateHMSFromUTC.lastd == 'undefined')
// lastd: static variable to remember date for the next call
// Not initialized
WriteDate = true;
else
WriteDate = (Yea !=
writeLocalDateHMSFromUTC.lastd.getFullYear () ||
Mon !=
writeLocalDateHMSFromUTC.lastd.getMonth () + 1 ||
Day !=
writeLocalDateHMSFromUTC.lastd.getDate ());
// Update last date for the next call
writeLocalDateHMSFromUTC.lastd = d;
/* Set date */
StrDat = '';
if (WriteDate) {
WriteToday = WriteToday && (Yea == todayYea &&
Mon == todayMon &&
Day == todayDay); // Date is today
if (WriteToday)
StrDat = txtToday[Language];
else
switch (DateFormat) {
case 0: // Dat_FORMAT_YYYY_MM_DD
StrMon = ((Mon < 10) ? '0' : '') + Mon;
StrDay = ((Day < 10) ? '0' : '') + Day;
StrDat = Yea.toString () + '-' +
StrMon + '-' +
StrDay;
break;
case 1: // Dat_FORMAT_DD_MONTH_YYYY
StrDat = Day.toString () + '&nbsp;' +
MonthsShort[Mon - 1] + '&nbsp;' +
Yea.toString ();
break;
case 2: // Dat_FORMAT_MONTH_DD_YYYY
StrDat = MonthsShort[Mon - 1] + '&nbsp;' +
Day.toString() + ',&nbsp;' +
Yea.toString ();
break;
default:
break;
}
if (WriteWeekDay) {
DayOfWeek = d.getDay ();
DayOfWeek = (DayOfWeek == 0) ? 6 : DayOfWeek - 1;
StrDat += Separator + DAYS[DayOfWeek];
}
StrDat += Separator;
}
/* Set HH:MM:SS */
StrHou = '';
StrMin = '';
StrSec = '';
if (WriteHMS & (1<<2)) {
// Bit 2 on => Write hour
Hou = d.getHours();
StrHou = ((Hou < 10) ? '0' : '') +
Hou;
if (WriteHMS & (1<<1)) {
// Bits 2,1 on => Write minutes
Min = d.getMinutes ();
StrMin = ((Min < 10) ? ':0' : ':') +
Min;
if (WriteHMS & 1) {
// Bits 2,1,0 on => Write seconds
Sec = d.getSeconds ();
StrSec = ((Sec < 10) ? ':0' : ':') +
Sec;
}
}
}
/* Write date and time */
document.getElementById (id).innerHTML = StrDat +
StrHou +
StrMin +
StrSec;
}
Timeline: Layout
___________________________________________
| | 
| Top message: | > top message
|___________________________________________| /
| _____ | | |  
|| | | Author's name | Date-time | | |
||Auth.| |______________________|___________| | |
||photo| | | | author's |
||_____| | | > name, time |
| | Note | | and content |
| | content | | |
| | | | |
| |__________________________________| / |
| | | | |  |
| | Favs | Shared |Remove| | > note
| |_____________|_____________|______| | |
|________| | | |
| | List | | buttons |
| Comment| of | > and |
| icon | comments | | comments |
|________|__________________________________| | |
| | | |
| Form to write new comment | | |
|__________________________________| / /
Timeline: Layout
___________________________________________________________________________
| div which content will be updated (parent of parent of form) |
| _____________________ _______ _____________________________________ |
| | div (parent of form)| | div | | div for users | |
| | _________________ | | for | | ______ ______ ______ ______ | |
| | | this form | | | num. | | | | | | | | | form | | |
| | | _____________ | | | of | | | user | | user | | user | | to | | |
| | | | | | | | users | | | 1 | | 2 | | 3 | | show | | |
| | | |_____________| | | | | | | | | | | | | all | | |
| | |_________________| | | | | |______| |______| |______| |______| | |
| |_____________________| |_______| |_____________________________________| |
|___________________________________________________________________________|
typedef enum
{
Tml_Usr_SHOW_FEW_USRS, // Show a few first favers/sharers
Tml_Usr_SHOW_ALL_USRS, // Show all favers/sharers
} Tml_Usr_HowManyUsrs_t;
Timeline: Layout
●
Favourite
<div class="Tml_BOTTOM_RIGHT Tml_RIGHT_WIDTH">
<div class="Tml_FOOT Tml_RIGHT_WIDTH">
<div id="fav_not_..." class="Tml_FAV_NOT Tml_FAV_NOT_WIDTH">
<div class="Tml_ICO">
<form method="post" action="https://openswad.org/en" id="form_..."
onsubmit="updateDivFaversSharers (this,'act=1512"
"&amp;ses=session&amp;NotCod=note-code');"
"return false;" ...>
<input type="image" src="...fav-icon.svg"
alt="Fav" title="Fav"
class="CONTEXT_OPT ICO_HIGHLIGHT CONTEXT_ICO_16x16">
</form>
</div>
<div class="Tml_NUM_USRS">&nbsp;0</div>
<div class="Tml_USRS"></div>
</div>
Timeline: Layout
●
Share
<div id="sha_not_..." class="Tml_SHA_NOT Tml_SHA_NOT_WIDTH">
<div class="Tml_ICO">
<form method="post" action="https://openswad.org/en" id="form_..."
onsubmit="updateDivFaversSharers (this,'act=1495"
"&amp;ses=session&amp;NotCod=note-code');"
"return false;" ...>
<input type="image" src="...share-icon.svg"
alt="Share" title="Share"
class="CONTEXT_OPT ICO_HIGHLIGHT CONTEXT_ICO_16x16">
</form>
</div>
<div class="Tml_NUM_USRS">&nbsp;0</div>
<div class="Tml_USRS"></div>
</div>
Timeline: Layout
●
Show all users
<div id="fav_not_..." class="Tml_FAV_NOT Tml_FAV_NOT_WIDTH">
<div class="Tml_ICO">fav icon</div>
<div class="Tml_NUM_USRS">number of users</div>
<div class="Tml_USRS">
<div class="Tml_SHARER">user</div>
...
<div class="Tml_SHARER">user</div>
<form method="post" action="https://openswad.org/en" id="form_..."
onsubmit="updateDivFaversSharers (this,'act=1767"
"&amp;ses=session&amp;NotCod=note-code');"
" return false;" ...>
<input type="image" src="...ellipsis-h.svg"
alt="View all" title="View all"
class="CONTEXT_OPT ICO_HIGHLIGHT CONTEXT_ICO_16x16">
</form>
</div>
</div>
Timeline: Layout
function updateDivFaversSharers (form,Params) {
var id = form.parentNode.parentNode.id;
var objXMLHttp = AJAXCreateObject ();
if (objXMLHttp) {
/* Send request to server */
objXMLHttp.onreadystatechange = function () {
if (objXMLHttp.readyState == 4) // Check if data have been received
if (objXMLHttp.status == 200)
if (id) {
var div = document.getElementById (id); // Access to DIV
if (div)
div.innerHTML = objXMLHttp.responseText; // Update DIV content
}
};
objXMLHttp.open ('POST',actionAJAX,true);
objXMLHttp.setRequestHeader ('Content-Type','application/x-www-form-urlencoded');
objXMLHttp.send (Params);
}
}
Timeline: Layout
___________________________________________
| | 
| Top message: | > top message
|___________________________________________| /
| _____ | | |  
|| | | Author's name | Date-time | | |
||Auth.| |______________________|___________| | |
||photo| | | | author's |
||_____| | | > name, time |
| | Note | | and content |
| | content | | |
| | | | |
| |__________________________________| / |
| | | | |  |
| | Favs | Shared |Remove| | > note
| |_____________|_____________|______| | |
|________| | | |
| | List | | buttons |
| Comment| of | > and |
| icon | comments | | comments |
|________|__________________________________| | |
| | | |
| Form to write new comment | | |
|__________________________________| / /
Timeline: Layout
●
Remove
<div class="Tml_REM">
<form method="post" action="https://openswad.org/en" id="form_..." ...>
<input type="hidden" name="act" value="1494">
<input type="hidden" name="ses" value="session">
<input type="hidden" name="Who" value="4">
<input type="hidden" name="NotCod" value="note-code">
<input type="image" src="remove-icon.svg" alt="Remove" title="Remove"
class="CONTEXT_OPT ICO_HIGHLIGHT CONTEXT_ICO_16x16">
</form>
</div>
</div>
</div>
Timeline: Layout
___________________________________________
| | 
| Top message: | > top message
|___________________________________________| /
| _____ | | |  
|| | | Author's name | Date-time | | |
||Auth.| |______________________|___________| | |
||photo| | | | author's |
||_____| | | > name, time |
| | Note | | and content |
| | content | | |
| | | | |
| |__________________________________| / |
| | | | |  |
| | Favs | Shared |Remove| | > note
| |_____________|_____________|______| | |
|________| | | |
| | List | | buttons |
| Comment| of | > and |
| icon | comments | | comments |
|________|__________________________________| | |
| | | |
| Form to write new comment | | |
|__________________________________| / /
Timeline: Layout
●
Comment icon
<div class="Tml_BOTTOM_LEFT">
<div id="id_..._ico" class="Tml_ICO_COM_OFF">
<a href="" onclick="toggleNewComment ('id_...');return false;">
<img src="comment-icon.svg" alt="Comment" title="Comment"
class="CONTEXT_ICO_16x16">
</a>
</div>
</div>
function toggleNewComment (id) {
var iconDiv = document.getElementById (id + '_ico');
iconDiv.className = (iconDiv.className == 'Tml_ICO_COM_OFF') ? 'Tml_ICO_COM_ON' :'Tml_ICO_COM_OFF';
toggleDisplay(id);
} function toggleDisplay (elementID) {
var element = document.getElementById (elementID);
var stl;
if (element) {
stl = element.style;
stl.display = (stl.display === 'none') ? '' : 'none';
}
}
Timeline: Layout
●
New comment
<div id="id_..." class="Tml_FORM_NEW_COM Tml_RIGHT_WIDTH" style="">
<div class="Tml_COM_PHOTO">...</div>
<div class="Tml_COM_CONT Tml_COMM_WIDTH">
<form method="post" action="https://openswad.org/en" id="..."
enctype="multipart/form-data" ...>
<input type="hidden" name="act" value="1503">
<input type="hidden" name="ses" value="session">
<input type="hidden" name="Who" value="4">
<input type="hidden" name="NotCod" value="note code">
<textarea name="Txt" rows="6" maxlength="1000" placeholder="New comment…"
class="Tml_COM_TEXTAREA Tml_COMM_WIDTH"
onfocus="expandTextarea (this,'id_...','6');">
</textarea>
<div id="id_..." style="">
<div class="HELP_EDIT">...</div>
<div class="MED_UPLOADER">...</div>
<button type="submit" class="BT_SUBMIT_INLINE BT_CREATE">Post</button>
</div>
</form>
</div>
</div>
function expandTextarea (textareaElem,idButton,rows) {
textareaElem.rows = rows;
document.getElementById (idButton).style.display = '';
}
Timeline: Layout
___________________________________________
| | 
| Top message: | > top message
|___________________________________________| /
| _____ | | |  
|| | | Author's name | Date-time | | |
||Auth.| |______________________|___________| | |
||photo| | | | author's |
||_____| | | > name, time |
| | Note | | and content |
| | content | | |
| | | | |
| |__________________________________| / |
| | | | |  |
| | Favs | Shared |Remove| | > note
| |_____________|_____________|______| | |
|________| | | |
| | List | | buttons |
| Comment| of | > and |
| icon | comments | | comments |
|________|__________________________________| | |
| | | |
| Form to write new comment | | |
|__________________________________| / /
Timeline: Layout
___________________________________________
| _____ | | |  
|| | | Author's name | Date-time | | |
||Auth.| |______________________|___________| | |
||photo| | | | author's |
||_____| | | > name, time |
| | Comment | | and content > comment
| | content | | |
| | | | |
| |__________________________________| / |
| | | |  |
| | Favs |Remove| > buttons |
|________|___________________________|______| / /
●
Layout and code similar to those described for the notes.
Timeline: Layout
Before clicking "See prev..." --> After clicking "See prev..."
_________________________________ _________________________________
| div con_<id> | | div con_<id> |
| (hidden) | | (visible) |
| _____________________________ | | _____________________________ |
| | v See only the latest | | | | v See only the latest | |
| |_________(contract)__________| | | |_________(contract)__________| |
|_________________________________| |_________________________________|
_________________________________ _________________________________
| div <id> | | div <id> updated |
| which content | | _____________________________ |
| will be updated via AJAX | | | ul com_<id> | |
| (parent of parent of form) | | | _________________________ | |
| | | | | li (comment 1) | | |
| | | | |_________________________| | |
| | | | | ... | | |
| | | | |_________________________| | |
| | | | | li (comment n) | | |
| | --> | | |_________________________| | |
| | | |_____________________________| |
| _____________________________ | | _____________________________ |
| | div exp_<id> | | | | div exp_<id> | |
| | (visible) | | | | (hidden) | |
| | _________________________ | | | | | |
| | | form | | | | | | |
| | | _____________________ | | | | | _____________________ | |
| | | | ^ See prev.comments | | | | | | | ^ See prev.comments | | |
| | | |_______(expand)______| | | | | | |_______(expand)______| | |
| | |_________________________| | | | | | |
| |_____________________________| | | |_____________________________| |
|_________________________________| |_________________________________|
_________________________________ _________________________________
| ul | | ul |
| _________________________ | | _________________________ |
| | li (comment n+1) | | | | li (comment n+1) | |
| |_________________________| | | |_________________________| |
| | ... | | | | ... | |
| |_________________________| | | |_________________________| |
| | li (comment m) | | | | li (comment m) | |
| |_________________________| | | |_________________________| |
|_________________________________| |_________________________________|
●
Only the last comments are displayed.
●
Only the last comments are displayed.
Timeline: Layout
Before clicking "See prev..." --> After clicking "See prev..."
_________________________________ _________________________________
| div con_<id> | | div con_<id> |
| (hidden) | | (visible) |
| _____________________________ | | _____________________________ |
| | v See only the latest | | | | v See only the latest | |
| |_________(contract)__________| | | |_________(contract)__________| |
|_________________________________| |_________________________________|
_________________________________ _________________________________
| div <id> | | div <id> updated |
| which content | | _____________________________ |
| will be updated via AJAX | | | ul com_<id> | |
| (parent of parent of form) | | | _________________________ | |
| | | | | li (comment 1) | | |
| | | | |_________________________| | |
| | | | | ... | | |
| | | | |_________________________| | |
| | | | | li (comment n) | | |
| | --> | | |_________________________| | |
| | | |_____________________________| |
| _____________________________ | | _____________________________ |
| | div exp_<id> | | | | div exp_<id> | |
| | (visible) | | | | (hidden) | |
| | _________________________ | | | | | |
| | | form | | | | | | |
| | | _____________________ | | | | | _____________________ | |
| | | | ^ See prev.comments | | | | | | | ^ See prev.comments | | |
| | | |_______(expand)______| | | | | | |_______(expand)______| | |
| | |_________________________| | | | | | |
| |_____________________________| | | |_____________________________| |
|_________________________________| |_________________________________|
_________________________________ _________________________________
| ul | | ul |
| _________________________ | | _________________________ |
| | li (comment n+1) | | | | li (comment n+1) | |
| |_________________________| | | |_________________________| |
| | ... | | | | ... | |
| |_________________________| | | |_________________________| |
| | li (comment m) | | | | li (comment m) | |
| |_________________________| | | |_________________________| |
|_________________________________| |_________________________________|
●
Only the last comments are displayed.
●
You can click on "See previous".
●
Only the last comments are displayed.
●
You can click on "See previous".
Timeline: Layout
Before clicking "See prev..." --> After clicking "See prev..."
_________________________________ _________________________________
| div con_<id> | | div con_<id> |
| (hidden) | | (visible) |
| _____________________________ | | _____________________________ |
| | v See only the latest | | | | v See only the latest | |
| |_________(contract)__________| | | |_________(contract)__________| |
|_________________________________| |_________________________________|
_________________________________ _________________________________
| div <id> | | div <id> updated |
| which content | | _____________________________ |
| will be updated via AJAX | | | ul com_<id> | |
| (parent of parent of form) | | | _________________________ | |
| | | | | li (comment 1) | | |
| | | | |_________________________| | |
| | | | | ... | | |
| | | | |_________________________| | |
| | | | | li (comment n) | | |
| | --> | | |_________________________| | |
| | | |_____________________________| |
| _____________________________ | | _____________________________ |
| | div exp_<id> | | | | div exp_<id> | |
| | (visible) | | | | (hidden) | |
| | _________________________ | | | | | |
| | | form | | | | | | |
| | | _____________________ | | | | | _____________________ | |
| | | | ^ See prev.comments | | | | | | | ^ See prev.comments | | |
| | | |_______(expand)______| | | | | | |_______(expand)______| | |
| | |_________________________| | | | | | |
| |_____________________________| | | |_____________________________| |
|_________________________________| |_________________________________|
_________________________________ _________________________________
| ul | | ul |
| _________________________ | | _________________________ |
| | li (comment n+1) | | | | li (comment n+1) | |
| |_________________________| | | |_________________________| |
| | ... | | | | ... | |
| |_________________________| | | |_________________________| |
| | li (comment m) | | | | li (comment m) | |
| |_________________________| | | |_________________________| |
|_________________________________| |_________________________________|
●
Only the last comments are displayed.
●
You can click on "See previous".
●
Previous comments are retrieved via
AJAX.
●
Only the last comments are displayed.
●
You can click on "See previous".
●
Previous comments are retrieved via
AJAX.
Timeline: Layout
Before clicking "See prev..." --> After clicking "See prev..."
_________________________________ _________________________________
| div con_<id> | | div con_<id> |
| (hidden) | | (visible) |
| _____________________________ | | _____________________________ |
| | v See only the latest | | | | v See only the latest | |
| |_________(contract)__________| | | |_________(contract)__________| |
|_________________________________| |_________________________________|
_________________________________ _________________________________
| div <id> | | div <id> updated |
| which content | | _____________________________ |
| will be updated via AJAX | | | ul com_<id> | |
| (parent of parent of form) | | | _________________________ | |
| | | | | li (comment 1) | | |
| | | | |_________________________| | |
| | | | | ... | | |
| | | | |_________________________| | |
| | | | | li (comment n) | | |
| | --> | | |_________________________| | |
| | | |_____________________________| |
| _____________________________ | | _____________________________ |
| | div exp_<id> | | | | div exp_<id> | |
| | (visible) | | | | (hidden) | |
| | _________________________ | | | | | |
| | | form | | | | | | |
| | | _____________________ | | | | | _____________________ | |
| | | | ^ See prev.comments | | | | | | | ^ See prev.comments | | |
| | | |_______(expand)______| | | | | | |_______(expand)______| | |
| | |_________________________| | | | | | |
| |_____________________________| | | |_____________________________| |
|_________________________________| |_________________________________|
_________________________________ _________________________________
| ul | | ul |
| _________________________ | | _________________________ |
| | li (comment n+1) | | | | li (comment n+1) | |
| |_________________________| | | |_________________________| |
| | ... | | | | ... | |
| |_________________________| | | |_________________________| |
| | li (comment m) | | | | li (comment m) | |
| |_________________________| | | |_________________________| |
|_________________________________| |_________________________________|
●
Only the last comments are displayed.
●
You can click on "See previous".
●
Previous comments are retrieved via
AJAX.
●
"See previous" is hidden.
●
Only the last comments are displayed.
●
You can click on "See previous".
●
Previous comments are retrieved via
AJAX.
●
"See previous" is hidden.
Timeline: Layout
Before clicking "See prev..." --> After clicking "See prev..."
_________________________________ _________________________________
| div con_<id> | | div con_<id> |
| (hidden) | | (visible) |
| _____________________________ | | _____________________________ |
| | v See only the latest | | | | v See only the latest | |
| |_________(contract)__________| | | |_________(contract)__________| |
|_________________________________| |_________________________________|
_________________________________ _________________________________
| div <id> | | div <id> updated |
| which content | | _____________________________ |
| will be updated via AJAX | | | ul com_<id> | |
| (parent of parent of form) | | | _________________________ | |
| | | | | li (comment 1) | | |
| | | | |_________________________| | |
| | | | | ... | | |
| | | | |_________________________| | |
| | | | | li (comment n) | | |
| | --> | | |_________________________| | |
| | | |_____________________________| |
| _____________________________ | | _____________________________ |
| | div exp_<id> | | | | div exp_<id> | |
| | (visible) | | | | (hidden) | |
| | _________________________ | | | | | |
| | | form | | | | | | |
| | | _____________________ | | | | | _____________________ | |
| | | | ^ See prev.comments | | | | | | | ^ See prev.comments | | |
| | | |_______(expand)______| | | | | | |_______(expand)______| | |
| | |_________________________| | | | | | |
| |_____________________________| | | |_____________________________| |
|_________________________________| |_________________________________|
_________________________________ _________________________________
| ul | | ul |
| _________________________ | | _________________________ |
| | li (comment n+1) | | | | li (comment n+1) | |
| |_________________________| | | |_________________________| |
| | ... | | | | ... | |
| |_________________________| | | |_________________________| |
| | li (comment m) | | | | li (comment m) | |
| |_________________________| | | |_________________________| |
|_________________________________| |_________________________________|
●
Only the last comments are displayed.
●
You can click on "See previous".
●
Previous comments are retrieved via
AJAX.
●
"See previous" is hidden.
●
"See only the last" is unhidden.
●
Only the last comments are displayed.
●
You can click on "See previous".
●
Previous comments are retrieved via
AJAX.
●
"See previous" is hidden.
●
"See only the last" is unhidden.
Timeline: Layout
Before clicking "See prev..." --> After clicking "See prev..."
_________________________________ _________________________________
| div con_<id> | | div con_<id> |
| (hidden) | | (visible) |
| _____________________________ | | _____________________________ |
| | v See only the latest | | | | v See only the latest | |
| |_________(contract)__________| | | |_________(contract)__________| |
|_________________________________| |_________________________________|
_________________________________ _________________________________
| div <id> | | div <id> updated |
| which content | | _____________________________ |
| will be updated via AJAX | | | ul com_<id> | |
| (parent of parent of form) | | | _________________________ | |
| | | | | li (comment 1) | | |
| | | | |_________________________| | |
| | | | | ... | | |
| | | | |_________________________| | |
| | | | | li (comment n) | | |
| | --> | | |_________________________| | |
| | | |_____________________________| |
| _____________________________ | | _____________________________ |
| | div exp_<id> | | | | div exp_<id> | |
| | (visible) | | | | (hidden) | |
| | _________________________ | | | | | |
| | | form | | | | | | |
| | | _____________________ | | | | | _____________________ | |
| | | | ^ See prev.comments | | | | | | | ^ See prev.comments | | |
| | | |_______(expand)______| | | | | | |_______(expand)______| | |
| | |_________________________| | | | | | |
| |_____________________________| | | |_____________________________| |
|_________________________________| |_________________________________|
_________________________________ _________________________________
| ul | | ul |
| _________________________ | | _________________________ |
| | li (comment n+1) | | | | li (comment n+1) | |
| |_________________________| | | |_________________________| |
| | ... | | | | ... | |
| |_________________________| | | |_________________________| |
| | li (comment m) | | | | li (comment m) | |
| |_________________________| | | |_________________________| |
|_________________________________| |_________________________________|
●
Only the last comments are displayed.
●
You can click on "See previous".
●
Previous comments are retrieved via
AJAX.
●
"See previous" is hidden.
●
"See only the last" is unhidden.
●
From now on no AJAX is needed,
sections are hidden / unhidden using
JavaScript.
●
Only the last comments are displayed.
●
You can click on "See previous".
●
Previous comments are retrieved via
AJAX.
●
"See previous" is hidden.
●
"See only the last" is unhidden.
●
From now on no AJAX is needed,
sections are hidden / unhidden using
JavaScript.
Timeline: Layout
<div class="MED_UPLOADER">
<div id="id_..._med_ico">
<a href="" onclick="mediaActivateMediaUploader('id_...');"
"return false;">
<img src="...paperclip.svg" alt="Multimedia"
title="Multimedia" class="ICO_HIGHLIGHT ICOx16">
</a>
</div>
<div id="id_..._med_upl" style="display:none;">
<div class="FRAME_CONT">
<div class="FRAME">
<div class="FRAME_ICO">
<div class="FRAME_ICO_RIGHT">
help-link
</div>
</div>
<div class="FRAME_TITLE FRAME_TITLE_SMALL">
Multimedia
</div>
<input type="hidden" name="MedAct" value="2">
_container_____________________________________________
| _<id>_med_ico |
| |____Clip_____| |
| |
| _container <id>_med_upl_(initially hidden)_________ |
| | _box___________________________________________ | |
| | | ? | | |
| | | Multimedia | | |
| | | | | |
| | | _prefs_container___________________ | | |
| | | | _pref_container_________________ | | | |
| | | | | _______ _______ _______ | | | | |
| | | | | | Image/| |YouTube| | Embed | | | | | |
| | | | | |_video_| |_______| |_______| | | | | |
| | | | |_______________________________| | | | |
| | | |___________________________________| | | |
| | | _file_container____________________________ | | |
| | | | ___________ | | | |
| | | | |_Browse..._| No file selected. | | | |
| | | |___________________________________________| | | |
| | | _URL_container_____________________________ | | |
| | | | _______________________________________ | | | |
| | | | |_Link__________________________________| | | | |
| | | |___________________________________________| | | |
| | | _title_container___________________________ | | |
| | | | _______________________________________ | | | |
| | | | |_Title/attribution_____________________| | | | |
| | | |___________________________________________| | | |
| | |_______________________________________________| | |
| |___________________________________________________| |
|_______________________________________________________|
function mediaActivateMediaUploader (id) {
document.getElementById (id + '_med_ico').style.display = 'none';
document.getElementById (id + '_med_upl').style.display = '';
}
Timeline: Layout
<div class="PREF_CONTS">
<div class="PREF_CONT">
<div id="id_..._ico_upl" class="PREF_OFF">
<a href="" onclick="mediaClickOnActivateUpload('id_...');"
"return false;">
<img src="...photo-video.svg" alt="Image/video"
title="Image/video" class="ICO_HIGHLIGHT ICOx16">
</a>
</div>
<div id="id_..._ico_you" class="PREF_OFF">
<a href="" onclick="mediaClickOnActivateYoutube('id_...');"
"return false;">
<img src="...youtube-brands.svg" alt="YouTube"
title="YouTube" class="ICO_HIGHLIGHT ICOx16">
</a>
</div>
<div id="id_..._ico_emb" class="PREF_OFF">
<a href="" onclick="mediaClickOnActivateEmbed('id_...');"
"return false;">
<img src="...code.svg" alt="Embed"
title="Embed" class="ICO_HIGHLIGHT ICOx16">
</a>
</div>
</div>
</div>
_container_____________________________________________
| _<id>_med_ico |
| |____Clip_____| |
| |
| _container <id>_med_upl_(initially hidden)_________ |
| | _box___________________________________________ | |
| | | ? | | |
| | | Multimedia | | |
| | | | | |
| | | _prefs_container___________________ | | |
| | | | _pref_container_________________ | | | |
| | | | | _______ _______ _______ | | | | |
| | | | | | Image/| |YouTube| | Embed | | | | | |
| | | | | |_video_| |_______| |_______| | | | | |
| | | | |_______________________________| | | | |
| | | |___________________________________| | | |
| | | _file_container____________________________ | | |
| | | | ___________ | | | |
| | | | |_Browse..._| No file selected. | | | |
| | | |___________________________________________| | | |
| | | _URL_container_____________________________ | | |
| | | | _______________________________________ | | | |
| | | | |_Link__________________________________| | | | |
| | | |___________________________________________| | | |
| | | _title_container___________________________ | | |
| | | | _______________________________________ | | | |
| | | | |_Title/attribution_____________________| | | | |
| | | |___________________________________________| | | |
| | |_______________________________________________| | |
| |___________________________________________________| |
|_______________________________________________________|
_container_____________________________________________
| _<id>_med_ico |
| |____Clip_____| |
| |
| _container <id>_med_upl_(initially hidden)_________ |
| | _box___________________________________________ | |
| | | ? | | |
| | | Multimedia | | |
| | | | | |
| | | _prefs_container___________________ | | |
| | | | _pref_container_________________ | | | |
| | | | | _______ _______ _______ | | | | |
| | | | | | Image/| |YouTube| | Embed | | | | | |
| | | | | |_video_| |_______| |_______| | | | | |
| | | | |_______________________________| | | | |
| | | |___________________________________| | | |
| | | _file_container____________________________ | | |
| | | | ___________ | | | |
| | | | |_Browse..._| No file selected. | | | |
| | | |___________________________________________| | | |
| | | _URL_container_____________________________ | | |
| | | | _______________________________________ | | | |
| | | | |_Link__________________________________| | | | |
| | | |___________________________________________| | | |
| | | _title_container___________________________ | | |
| | | | _______________________________________ | | | |
| | | | |_Title/attribution_____________________| | | | |
| | | |___________________________________________| | | |
| | |_______________________________________________| | |
| |___________________________________________________| |
|_______________________________________________________|
Timeline: Layout
<input type="hidden" id="id_..._par_upl" name="MedFrm"
value="1" disabled>
<input type="hidden" id="id_..._par_you" name="MedFrm"
value="2" disabled>
<input type="hidden" id="id_..._par_emb" name="MedFrm"
value="3" disabled>
<div>
<input type="file" name="MedFil" accept="image/,video/"
id="id_..._fil" class="Tml_MED_INPUT_WIDTH"
style="display:none;" disabled>
</div>
<div>
<input type="url" name="MedURL" maxlength="255" value=""
id="id_..._url" class="Tml_MED_INPUT_WIDTH"
placeholder="Link" style="display:none;" disabled>
</div>
<div>
<input type="text" name="MedTit" maxlength="127" value=""
id="id_..._tit" class="Tml_MED_INPUT_WIDTH"
placeholder="Title/attribution"
style="display:none;" disabled>
</div>
</div>
</div>
</div>
</div>
</div>
Timeline: Layout
_container_____________________________________________
| _<id>_med_ico |
| |____Clip_____| |
| |
| _container <id>_med_upl_(initially hidden)_________ |
| | _box___________________________________________ | |
| | | ? | | |
| | | Multimedia | | |
| | | | | |
| | | _prefs_container___________________ | | |
| | | | _pref_container_________________ | | | |
| | | | | _______ _______ _______ | | | | |
| | | | | | Image/| |YouTube| | Embed | | | | | |
| | | | | |_video_| |_______| |_______| | | | | |
| | | | |_______________________________| | | | |
| | | |___________________________________| | | |
| | | _file_container____________________________ | | |
| | | | ___________ | | | |
| | | | |_Browse..._| No file selected. | | | |
| | | |___________________________________________| | | |
| | | _URL_container_____________________________ | | |
| | | | _______________________________________ | | | |
| | | | |_Link__________________________________| | | | |
| | | |___________________________________________| | | |
| | | _title_container___________________________ | | |
| | | | _______________________________________ | | | |
| | | | |_Title/attribution_____________________| | | | |
| | | |___________________________________________| | | |
| | |_______________________________________________| | |
| |___________________________________________________| |
|_______________________________________________________|
function mediaClickOnActivateUpload (id) {
var par_upl = document.getElementById (id + '_par_upl');
if (par_upl.disabled) { // Click on highlighted icon
// par_upl already got
var par_you = document.getElementById (id + '_par_you');
var par_emb = document.getElementById (id + '_par_emb');
var ico_upl = document.getElementById (id + '_ico_upl');
var ico_you = document.getElementById (id + '_ico_you');
var ico_emb = document.getElementById (id + '_ico_emb');
var fil = document.getElementById (id + '_fil');
var url = document.getElementById (id + '_url');
var tit = document.getElementById (id + '_tit');
// Enable upload, disable others
par_upl.disabled = false; // Enable upload
par_you.disabled = true; // Disable youtube
par_emb.disabled = true; // Disable embed
ico_upl.className = 'PREF_ON'; // Highlighted upload icon
ico_you.className = 'PREF_OFF'; // Normal youtube icon
ico_emb.className = 'PREF_OFF'; // Normal embed icon
fil.style.display = ''; // Show file input
fil.disabled = false; // Enable file input
url.style.display = ''; // Show URL input
url.disabled = false; // Enable URL input
tit.style.display = ''; // Show title input
tit.disabled = false; // Enable title input
}
else // Click on shadowed icon
mediaDisableAll (id);
}
Timeline: Inserting links
“The C language combines
all the power of assembly language
with all the ease-of-use of assembly language.”
Mark Pearce - Freelance consultant and developer
Timeline: Inserting links
“The C language combines
all the power of assembly language
with all the ease-of-use of assembly language.”
Mark Pearce - Freelance consultant and developer
Timeline: Inserting links
●
1. Parse string creating a list of links (URLs or nicknames)
●
Hi @admin, can I use https://openswad.org for free?
______ ______ ______ ______
|______|<-- -->|______|<-- -->|______|<-- -->|______|<--- LastLink
|______| / |______| / |______| / |______|
|______| / |______| / |______| / |______|
|_NULL_| / ---|_Prev_| / ---|_Prev_| / ---|_Prev_|
|_Next_|-- |_Next_|-- |_Next_|-- |_NULL_|
struct ALn_Link
{
ALn_LinkType_t Type; // URL or nickname?
struct ALn_Substring URLorNick; // Link text
struct ALn_Substring NickAnchor[3]; // Pointer to anchors if nick
size_t LengthAddedUpToHere; // Total length of extra HTML code...
// ...added up to this link (included)
struct ALn_Link *Prev; // Pointer to previous link
struct ALn_Link *Next; // Pointer to next link
};
struct ALn_Substring
{
// Pointer to
// the first
// char of
// substring
char *Str;
// Length of
// the substring
size_t Len;
};
Timeline: Inserting links
●
2. For each link in the list, going back from last to first:
●
1 Move forward the text after the link
●
2 Copy the 3rd part of the anchor
●
3 Move forward the link
_______________________________
|H|i|_|@|a|d|m|i|n|,|_|c|a|n|...|
| | | | | | | | | | | | | | |
| | | | | | | | | ___________________________________________1____
| | |            
| | | ______________________________3____ | | | | | |
| | |             | | | | | |
| | | ______5____ | | | | | | | | | | | |
| | |       | | | | | | | | | | | |
| | | 6 | | | | | | 4 | | | | | | 2 | | | | | |
v v v anchor#1 v v v v v v anchor#2 v v v v v v anchor#3 v v v v v v
___________________________________________________________________________
|H|i|_|<|_|_|_|_|@|a|d|m|i|n|_|_|_|_|>|@|a|d|m|i|n|<|_|_|_|_|>|,|_|c|a|n|...|
●
4 Copy the 2nd part of the anchor
●
5 Copy the link into the anchor
●
6 Copy the 1st part of the anchor
Future goals and tasks
“The dream of yesterday is the hope of today
and the reality of tomorrow.”
Robert H. Goddard - Engineer, professor, physicist and inventor
Future goals and tasks
“The dream of yesterday is the hope of today
and the reality of tomorrow.”
Robert H. Goddard - Engineer, professor, physicist and inventor
Future goals and tasks
●
Objective 1: Incorporate new functionalities in the platform and improve some
of the existing ones for its integration with gamification, geolocation and EDM
Objective 1 tasks
T1.1 Instructional design + planning T1.5 Improved test exams 
T1.2 Monitoring + activity reports T1.6 Scanning homework with the mobile
T1.3 Collaborative edition (wiki) T1.7 Integrated grades
T1.4 Improved schedule + calendar T1.8 Enhanced forums + chat + messages
Future goals and tasks
●
Objective 2: Integration of gamification based on typical game elements in the
functionalities of the web platform and the mobile app
Objective 2 tasks
T2.1 ARS integrated (interactive games with remote control) 
T2.2 Scores + badges in global and course functionalities
T2.3 Karma in timeline, forums and files
T2.4 Progress bars in user profiles and courses
Future goals and tasks
●
Objective 3: Integration of indoor geolocation to improve the location of users
in institutional dependencies and attendance control
Objective 3 tasks
T3.1 Database + location prototype  T3.5 Possible improvements
•
Alerts about friends that are close
•
Display location on map
•
QR to check-in
•
Store history for activity reports and
recommendations
T3.2 SWAD API functions 
T3.3 Integration in SWADroid 
T3.4 Add gamification
Future goals and tasks
●
Objective 4: Integrate Educational Data Mining techniques to improve student
assessment, identify study tips, and offer alerts to students and teachers
Objective 4 tasks
T4.1 Study state of the art of EDM (lines of research, articles)
T4.2 Study algorithms + software tools
T4.3 Off-platform experiments (predict + recommend + alert)
T4.4 Select algorithms and integrate them into the platform
Future goals and tasks
●
Objective 5: Analyze educational changes in motivation and
participation, results, and degree of use and satisfaction
after the improvements
Objective 5 tasks
T5.1 Interviews with users prior to the improvement
T5.2 Acquire reference data prior to improvement
T5.3 Measure indicators after improvement: performance, use, motivation ...
T5.4 Disseminate partial and final results
Conclusions
“We are free, we can be wide open"
“Analyse”, The Cranberries - Irish rock band
Conclusions
“We are free, we can be wide open"
“Analyse”, The Cranberries - Irish rock band
Conclusions
●
We have developed and used an educational platform for 23 years at UGR
(Spain)
●
It’s a fast tool that consumes very few computing resources, making it
suitable for low-cost installations
Conclusions
●
It had a great growth between 2005 and 2015
●
In 2015 it was almost used by the entire UGR (≈60K students)
●
In total, it has been used by 200,000 users at UGR
Conclusions
●
Since 2010 it’s free software, so anyone can install it (and improve it)
●
Since 2012 it is freely available in the cloud for everyone, in the portal
OpenSWAD.org
●
Of course, you can try it at https://openswad.org/
Conclusions
●
Since 2016 its use at UGR has decreased due to institutional support to
another official platform
●
However, we have continued working on the improvement of the platform
●
We will continue its upgrade with gamification, geolocation and data
mining, among other features
About us
“When they ask me when a program will be ready,
I answer: it depends on how much you work on it.”
Richard M. Stallman - Free software activist and programmer
About us
“When they ask me when a program will be ready,
I answer: it depends on how much you work on it.”
Richard M. Stallman - Free software activist and programmer
About us
●
Recent programmers:
●
Antonio Cañas Vargas (swad-core, servers, management, courses)
●
Daniel J. Calandria Hernández (photo processing, chat)
●
Juan Miguel Boyero Corral (SWADroid)
●
Bate Ye (iSWAD)
●
Javier Bueno López (SWADroid)
●
Adrián Lara Roldán (iSWAD)
●
Jesús Mesa González (photo processing)
●
Sergio Díaz Rueda (SWADroid)
(green = free software)
About us
●
Former programmers (I):
●
Jesús Álvarez Martín (photo processing)
●
Alberto E. Rodrigo Gámiz (photo processing)
●
Ana Belén Cara Carmona (chat & whiteboard)
●
Carlos Moreno Muñoz (chat & whiteboard)
About us
●
Former programmers (II):
●
Antonio Manuel Aguilera Malagón (SWADroid)
●
Helena Rodríguez Gijón (SWADroid)
●
José Antonio Guerrero Avilés (SWADroid)
●
Alejandro Alcalde Barros (SWADroid)
●
Rubén Martín Hidalgo (SWADroid)
●
Miguel Ángel Cerrailo Valle (Triswados, app Android)
●
Raúl Álvarez Hinojosa (iSWAD)
About us
●
Programmers of modules that were not used:
●
Andrés Ramón Masegosa Aredondo (photo processing)
●
Raúl Jiménez Benítez (chat)
●
María Beatriz Medina Yáñez (whiteboard)
●
Raquel Cazalilla Sáez (chat & whiteboard)
●
Emiliano Luis Rincón Vallejos (rich text editor)
●
Diego Montesinos Hervás (iSWAD)
●
Lucas Ortiz Velasco (SWADMyPage)
●
David Medina Godoy (SWADE, rich text editor)
●
Marta Muñoz López (SWAD2Moodle)
About us
●
Translators:
●
Antonio Cañas Vargas (CA,DE,EN,ES,FR,GN,IT,PL,PT)
●
Joan Lluís Díaz Rodríguez (CA)
●
Rafael Barranco Droege (DE)
●
Giuseppe Antonio Pagin, Antonella Grande, Francisco Manuel Herrero Pérez, Nicola
Comunale Rizzo (IT)
●
Wojtek Kieca, Tomasz Olechowski, Mateusz Stanko (PL)
About us
●
Contributors (I):
●
Javier Fernández Baldomero (forums, papers)
●
Antonio F. Díaz García (servers)
●
Eva Martínez Ortigosa (administration, papers)
●
Francisco Illeras García (servers)
●
Alberto Prieto Espinosa (papers)
●
Mancia Anguita López (papers)
●
Eduardo Ros Vidal (papers)
About us
●
Contributors (II):
●
Francisco A. Ocaña Lara (FAQ, papers)
●
Adrián Gómez Anaya (WikiSwad)
●
Paloma Marín Arraiza (video tutorials)
●
technicians and scholars from the Virtual Learning Center
●
150 degree administrators
●
...and many more
SWAD timeline

More Related Content

Similar to SWAD timeline

DSC GCOE, Nagpur intro session
DSC GCOE, Nagpur intro sessionDSC GCOE, Nagpur intro session
DSC GCOE, Nagpur intro session
DSCGCOEN
 
Development of a learning diary for a MOOC platform
Development of a learning diary for a MOOC platformDevelopment of a learning diary for a MOOC platform
Development of a learning diary for a MOOC platform
Educational Technology
 
Google summer of code with drupal
Google summer of code with drupalGoogle summer of code with drupal
Google summer of code with drupal
Naveen Valecha
 
Google Solution Challenge 2023
Google Solution Challenge 2023Google Solution Challenge 2023
Google Solution Challenge 2023
Sehar477968
 
Dashboards voor learning analytics
Dashboards voor learning analyticsDashboards voor learning analytics
Dashboards voor learning analytics
SURF Events
 
Info Session 2023-24.pptx
Info Session 2023-24.pptxInfo Session 2023-24.pptx
Info Session 2023-24.pptx
ShwetaEvangeline1
 
Info Session 2023-24.pptx
Info Session 2023-24.pptxInfo Session 2023-24.pptx
Info Session 2023-24.pptx
ShwetaEvangeline
 
Info-Session-Slides.pptx
Info-Session-Slides.pptxInfo-Session-Slides.pptx
Info-Session-Slides.pptx
ZilvinasAleksa
 
Orientation pdf_merged.pdf
Orientation pdf_merged.pdfOrientation pdf_merged.pdf
Orientation pdf_merged.pdf
DSCIITPatna
 
Fostering pre-university student participation in OSGeo through the Google Co...
Fostering pre-university student participation in OSGeo through the Google Co...Fostering pre-university student participation in OSGeo through the Google Co...
Fostering pre-university student participation in OSGeo through the Google Co...
Jeff McKenna
 
GDSC_Introduction.pptx
GDSC_Introduction.pptxGDSC_Introduction.pptx
GDSC_Introduction.pptx
SachinMishra53046
 
DSC Aswan University info session
DSC Aswan University info sessionDSC Aswan University info session
DSC Aswan University info session
AhmedHany131
 
Open Source Portal and Mobile Solutions
Open Source Portal and Mobile SolutionsOpen Source Portal and Mobile Solutions
Open Source Portal and Mobile Solutions
Aaron Grant
 
Academic Innovation Data Showcase 2-14-19
Academic Innovation Data Showcase 2-14-19Academic Innovation Data Showcase 2-14-19
Academic Innovation Data Showcase 2-14-19
umichiganai
 
Cooperation Menu for Universities and Researchers in Latvia | Accenture
Cooperation Menu for Universities and Researchers in Latvia | AccentureCooperation Menu for Universities and Researchers in Latvia | Accenture
Cooperation Menu for Universities and Researchers in Latvia | Accenture
accenture
 
Better Software, Better Practices, Better Research
Better Software, Better Practices, Better ResearchBetter Software, Better Practices, Better Research
Better Software, Better Practices, Better Research
Shoaib Sufi
 
GDSC Orientation 2023
GDSC Orientation 2023GDSC Orientation 2023
GDSC Orientation 2023
AnayPund
 
Intro Event.pdf
Intro Event.pdfIntro Event.pdf
Intro Event.pdf
GDSCSoton
 
GDSC IIIT Vadodara Intro Session.pptx
GDSC IIIT Vadodara Intro Session.pptxGDSC IIIT Vadodara Intro Session.pptx
GDSC IIIT Vadodara Intro Session.pptx
VedVekhande
 
VII Jornadas eMadrid "Education in exponential times". "Open Analytics in an ...
VII Jornadas eMadrid "Education in exponential times". "Open Analytics in an ...VII Jornadas eMadrid "Education in exponential times". "Open Analytics in an ...
VII Jornadas eMadrid "Education in exponential times". "Open Analytics in an ...
eMadrid network
 

Similar to SWAD timeline (20)

DSC GCOE, Nagpur intro session
DSC GCOE, Nagpur intro sessionDSC GCOE, Nagpur intro session
DSC GCOE, Nagpur intro session
 
Development of a learning diary for a MOOC platform
Development of a learning diary for a MOOC platformDevelopment of a learning diary for a MOOC platform
Development of a learning diary for a MOOC platform
 
Google summer of code with drupal
Google summer of code with drupalGoogle summer of code with drupal
Google summer of code with drupal
 
Google Solution Challenge 2023
Google Solution Challenge 2023Google Solution Challenge 2023
Google Solution Challenge 2023
 
Dashboards voor learning analytics
Dashboards voor learning analyticsDashboards voor learning analytics
Dashboards voor learning analytics
 
Info Session 2023-24.pptx
Info Session 2023-24.pptxInfo Session 2023-24.pptx
Info Session 2023-24.pptx
 
Info Session 2023-24.pptx
Info Session 2023-24.pptxInfo Session 2023-24.pptx
Info Session 2023-24.pptx
 
Info-Session-Slides.pptx
Info-Session-Slides.pptxInfo-Session-Slides.pptx
Info-Session-Slides.pptx
 
Orientation pdf_merged.pdf
Orientation pdf_merged.pdfOrientation pdf_merged.pdf
Orientation pdf_merged.pdf
 
Fostering pre-university student participation in OSGeo through the Google Co...
Fostering pre-university student participation in OSGeo through the Google Co...Fostering pre-university student participation in OSGeo through the Google Co...
Fostering pre-university student participation in OSGeo through the Google Co...
 
GDSC_Introduction.pptx
GDSC_Introduction.pptxGDSC_Introduction.pptx
GDSC_Introduction.pptx
 
DSC Aswan University info session
DSC Aswan University info sessionDSC Aswan University info session
DSC Aswan University info session
 
Open Source Portal and Mobile Solutions
Open Source Portal and Mobile SolutionsOpen Source Portal and Mobile Solutions
Open Source Portal and Mobile Solutions
 
Academic Innovation Data Showcase 2-14-19
Academic Innovation Data Showcase 2-14-19Academic Innovation Data Showcase 2-14-19
Academic Innovation Data Showcase 2-14-19
 
Cooperation Menu for Universities and Researchers in Latvia | Accenture
Cooperation Menu for Universities and Researchers in Latvia | AccentureCooperation Menu for Universities and Researchers in Latvia | Accenture
Cooperation Menu for Universities and Researchers in Latvia | Accenture
 
Better Software, Better Practices, Better Research
Better Software, Better Practices, Better ResearchBetter Software, Better Practices, Better Research
Better Software, Better Practices, Better Research
 
GDSC Orientation 2023
GDSC Orientation 2023GDSC Orientation 2023
GDSC Orientation 2023
 
Intro Event.pdf
Intro Event.pdfIntro Event.pdf
Intro Event.pdf
 
GDSC IIIT Vadodara Intro Session.pptx
GDSC IIIT Vadodara Intro Session.pptxGDSC IIIT Vadodara Intro Session.pptx
GDSC IIIT Vadodara Intro Session.pptx
 
VII Jornadas eMadrid "Education in exponential times". "Open Analytics in an ...
VII Jornadas eMadrid "Education in exponential times". "Open Analytics in an ...VII Jornadas eMadrid "Education in exponential times". "Open Analytics in an ...
VII Jornadas eMadrid "Education in exponential times". "Open Analytics in an ...
 

Recently uploaded

Artificia Intellicence and XPath Extension Functions
Artificia Intellicence and XPath Extension FunctionsArtificia Intellicence and XPath Extension Functions
Artificia Intellicence and XPath Extension Functions
Octavian Nadolu
 
OpenMetadata Community Meeting - 5th June 2024
OpenMetadata Community Meeting - 5th June 2024OpenMetadata Community Meeting - 5th June 2024
OpenMetadata Community Meeting - 5th June 2024
OpenMetadata
 
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
Crescat
 
Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Need for Speed: Removing speed bumps from your Symfony projects ⚡️Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Łukasz Chruściel
 
Oracle Database 19c New Features for DBAs and Developers.pptx
Oracle Database 19c New Features for DBAs and Developers.pptxOracle Database 19c New Features for DBAs and Developers.pptx
Oracle Database 19c New Features for DBAs and Developers.pptx
Remote DBA Services
 
Microservice Teams - How the cloud changes the way we work
Microservice Teams - How the cloud changes the way we workMicroservice Teams - How the cloud changes the way we work
Microservice Teams - How the cloud changes the way we work
Sven Peters
 
Graspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code AnalysisGraspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code Analysis
Aftab Hussain
 
AI Fusion Buddy Review: Brand New, Groundbreaking Gemini-Powered AI App
AI Fusion Buddy Review: Brand New, Groundbreaking Gemini-Powered AI AppAI Fusion Buddy Review: Brand New, Groundbreaking Gemini-Powered AI App
AI Fusion Buddy Review: Brand New, Groundbreaking Gemini-Powered AI App
Google
 
Neo4j - Product Vision and Knowledge Graphs - GraphSummit Paris
Neo4j - Product Vision and Knowledge Graphs - GraphSummit ParisNeo4j - Product Vision and Knowledge Graphs - GraphSummit Paris
Neo4j - Product Vision and Knowledge Graphs - GraphSummit Paris
Neo4j
 
8 Best Automated Android App Testing Tool and Framework in 2024.pdf
8 Best Automated Android App Testing Tool and Framework in 2024.pdf8 Best Automated Android App Testing Tool and Framework in 2024.pdf
8 Best Automated Android App Testing Tool and Framework in 2024.pdf
kalichargn70th171
 
Using Query Store in Azure PostgreSQL to Understand Query Performance
Using Query Store in Azure PostgreSQL to Understand Query PerformanceUsing Query Store in Azure PostgreSQL to Understand Query Performance
Using Query Store in Azure PostgreSQL to Understand Query Performance
Grant Fritchey
 
socradar-q1-2024-aviation-industry-report.pdf
socradar-q1-2024-aviation-industry-report.pdfsocradar-q1-2024-aviation-industry-report.pdf
socradar-q1-2024-aviation-industry-report.pdf
SOCRadar
 
SMS API Integration in Saudi Arabia| Best SMS API Service
SMS API Integration in Saudi Arabia| Best SMS API ServiceSMS API Integration in Saudi Arabia| Best SMS API Service
SMS API Integration in Saudi Arabia| Best SMS API Service
Yara Milbes
 
Transform Your Communication with Cloud-Based IVR Solutions
Transform Your Communication with Cloud-Based IVR SolutionsTransform Your Communication with Cloud-Based IVR Solutions
Transform Your Communication with Cloud-Based IVR Solutions
TheSMSPoint
 
Vitthal Shirke Java Microservices Resume.pdf
Vitthal Shirke Java Microservices Resume.pdfVitthal Shirke Java Microservices Resume.pdf
Vitthal Shirke Java Microservices Resume.pdf
Vitthal Shirke
 
Fundamentals of Programming and Language Processors
Fundamentals of Programming and Language ProcessorsFundamentals of Programming and Language Processors
Fundamentals of Programming and Language Processors
Rakesh Kumar R
 
UI5con 2024 - Keynote: Latest News about UI5 and it’s Ecosystem
UI5con 2024 - Keynote: Latest News about UI5 and it’s EcosystemUI5con 2024 - Keynote: Latest News about UI5 and it’s Ecosystem
UI5con 2024 - Keynote: Latest News about UI5 and it’s Ecosystem
Peter Muessig
 
Revolutionizing Visual Effects Mastering AI Face Swaps.pdf
Revolutionizing Visual Effects Mastering AI Face Swaps.pdfRevolutionizing Visual Effects Mastering AI Face Swaps.pdf
Revolutionizing Visual Effects Mastering AI Face Swaps.pdf
Undress Baby
 
KuberTENes Birthday Bash Guadalajara - Introducción a Argo CD
KuberTENes Birthday Bash Guadalajara - Introducción a Argo CDKuberTENes Birthday Bash Guadalajara - Introducción a Argo CD
KuberTENes Birthday Bash Guadalajara - Introducción a Argo CD
rodomar2
 
DDS-Security 1.2 - What's New? Stronger security for long-running systems
DDS-Security 1.2 - What's New? Stronger security for long-running systemsDDS-Security 1.2 - What's New? Stronger security for long-running systems
DDS-Security 1.2 - What's New? Stronger security for long-running systems
Gerardo Pardo-Castellote
 

Recently uploaded (20)

Artificia Intellicence and XPath Extension Functions
Artificia Intellicence and XPath Extension FunctionsArtificia Intellicence and XPath Extension Functions
Artificia Intellicence and XPath Extension Functions
 
OpenMetadata Community Meeting - 5th June 2024
OpenMetadata Community Meeting - 5th June 2024OpenMetadata Community Meeting - 5th June 2024
OpenMetadata Community Meeting - 5th June 2024
 
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
 
Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Need for Speed: Removing speed bumps from your Symfony projects ⚡️Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Need for Speed: Removing speed bumps from your Symfony projects ⚡️
 
Oracle Database 19c New Features for DBAs and Developers.pptx
Oracle Database 19c New Features for DBAs and Developers.pptxOracle Database 19c New Features for DBAs and Developers.pptx
Oracle Database 19c New Features for DBAs and Developers.pptx
 
Microservice Teams - How the cloud changes the way we work
Microservice Teams - How the cloud changes the way we workMicroservice Teams - How the cloud changes the way we work
Microservice Teams - How the cloud changes the way we work
 
Graspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code AnalysisGraspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code Analysis
 
AI Fusion Buddy Review: Brand New, Groundbreaking Gemini-Powered AI App
AI Fusion Buddy Review: Brand New, Groundbreaking Gemini-Powered AI AppAI Fusion Buddy Review: Brand New, Groundbreaking Gemini-Powered AI App
AI Fusion Buddy Review: Brand New, Groundbreaking Gemini-Powered AI App
 
Neo4j - Product Vision and Knowledge Graphs - GraphSummit Paris
Neo4j - Product Vision and Knowledge Graphs - GraphSummit ParisNeo4j - Product Vision and Knowledge Graphs - GraphSummit Paris
Neo4j - Product Vision and Knowledge Graphs - GraphSummit Paris
 
8 Best Automated Android App Testing Tool and Framework in 2024.pdf
8 Best Automated Android App Testing Tool and Framework in 2024.pdf8 Best Automated Android App Testing Tool and Framework in 2024.pdf
8 Best Automated Android App Testing Tool and Framework in 2024.pdf
 
Using Query Store in Azure PostgreSQL to Understand Query Performance
Using Query Store in Azure PostgreSQL to Understand Query PerformanceUsing Query Store in Azure PostgreSQL to Understand Query Performance
Using Query Store in Azure PostgreSQL to Understand Query Performance
 
socradar-q1-2024-aviation-industry-report.pdf
socradar-q1-2024-aviation-industry-report.pdfsocradar-q1-2024-aviation-industry-report.pdf
socradar-q1-2024-aviation-industry-report.pdf
 
SMS API Integration in Saudi Arabia| Best SMS API Service
SMS API Integration in Saudi Arabia| Best SMS API ServiceSMS API Integration in Saudi Arabia| Best SMS API Service
SMS API Integration in Saudi Arabia| Best SMS API Service
 
Transform Your Communication with Cloud-Based IVR Solutions
Transform Your Communication with Cloud-Based IVR SolutionsTransform Your Communication with Cloud-Based IVR Solutions
Transform Your Communication with Cloud-Based IVR Solutions
 
Vitthal Shirke Java Microservices Resume.pdf
Vitthal Shirke Java Microservices Resume.pdfVitthal Shirke Java Microservices Resume.pdf
Vitthal Shirke Java Microservices Resume.pdf
 
Fundamentals of Programming and Language Processors
Fundamentals of Programming and Language ProcessorsFundamentals of Programming and Language Processors
Fundamentals of Programming and Language Processors
 
UI5con 2024 - Keynote: Latest News about UI5 and it’s Ecosystem
UI5con 2024 - Keynote: Latest News about UI5 and it’s EcosystemUI5con 2024 - Keynote: Latest News about UI5 and it’s Ecosystem
UI5con 2024 - Keynote: Latest News about UI5 and it’s Ecosystem
 
Revolutionizing Visual Effects Mastering AI Face Swaps.pdf
Revolutionizing Visual Effects Mastering AI Face Swaps.pdfRevolutionizing Visual Effects Mastering AI Face Swaps.pdf
Revolutionizing Visual Effects Mastering AI Face Swaps.pdf
 
KuberTENes Birthday Bash Guadalajara - Introducción a Argo CD
KuberTENes Birthday Bash Guadalajara - Introducción a Argo CDKuberTENes Birthday Bash Guadalajara - Introducción a Argo CD
KuberTENes Birthday Bash Guadalajara - Introducción a Argo CD
 
DDS-Security 1.2 - What's New? Stronger security for long-running systems
DDS-Security 1.2 - What's New? Stronger security for long-running systemsDDS-Security 1.2 - What's New? Stronger security for long-running systems
DDS-Security 1.2 - What's New? Stronger security for long-running systems
 

SWAD timeline

  • 1. SWAD, an Open Learning Management System Including timeline implementation Antonio Cañas University of Granada (UGR) @acanasvargas acanas@ugr.es acanas@openswad.org https://openswad.org/ @openswad SWAD, an Open Learning Management System Including timeline implementation Antonio Cañas University of Granada (UGR) @acanasvargas acanas@ugr.es acanas@openswad.org https://openswad.org/ @openswad 1 1 Antonio Cañas et al. May 27, 2022, Granada, Spain May 27, 2022, Granada, Spain
  • 2. Contents ● History ● Summary of features ● swad.ugr.es ● Figures ● Keys to success ● OpenSWAD ● Project ● Advertising ● Figures ● Free software ● Implementation ● Timeline ● Notes & publications ● Database ● Getting publications ● Showing publications ● Layout ● Inserting links ● Future goals and tasks ● Conclusions ● About us
  • 3. History “The best time to plant a tree was 20 years ago. The second best time is now.” Chinese proverb History “The best time to plant a tree was 20 years ago. The second best time is now.” Chinese proverb
  • 4. History ● LMS in 2022: a very broad offer ● Hundreds of LMS ● proprietary / free software ● expensive / free of charge ● installable on the client's servers / accessible in the cloud
  • 7. ...but in 1999 not so many available → we started to develop our own system: Sistema Web de Apoyo a la Docencia (Web System for Teaching Support) ⬇ Social Workspace At a Distance https://swad.ugr.es/ https://openswad.org/ A web platform to manage courses, students and teachers, with functions to support teaching and learning. History
  • 8. Dpt.ATC: 1999-2003 1º TIP: 2003-2004 2º TIP: 2005-2006 3º TIP: 2006-2008 V.L.Center:2008-2016 Free Software: 2010... UNA.py: 2012-2014 OpenSWAD: 2012… Dpt.ATC: 2016... History openswad.org 2012... ugr.es CEVUG 2008-2016 ugr.es TIPs 2003-2008 ugr.es ATC 1999-2003 una.py 2012-2015 ugr.es ATC 2016... 23 years of development and use free software 2010...
  • 9. Summary of features “swad: a bunch, a grouping of a number of similar things” . https://www.thefreedictionary.com/swad Summary of features “swad: a bunch, a grouping of a number of similar things” . https://www.thefreedictionary.com/swad
  • 10. Summary of features This is how it looks. Some parts of its appearance, such as colors or icons, are customizable
  • 11. Summary of features Free software · 9 languages · Responsive design · Android app · Face-to-face or blended learning Hierarchical organization: System · Countries · Institutions (universities, companies) · Centers (faculties, schools) · Degrees · Courses · Group types · Groups 10 available roles: Unknown · Guest · User · Student · Non- editing teacher · Teacher · Degree admin · Center admin · Institution admin · System admin
  • 12. Summary of features Social network · Calendar · Notifications · Course information · Syllabus · Documents · Shared files · Portfolio · Grades · Assignments · Projects · Exam announcements · Quizzes · Exams · Games · Surveys · Groups · Lists of students and teachers · Attendance control using QR codes · Forums · Notices · Messaging system · Statistics · Agenda · Preferences All features in https://github.com/acanas/swad-core/wiki/UserGuide.en
  • 13. swad.ugr.es: Figures “What goes up, must come down” “What goes up”, The Alan Parsons Project - British rock band swad.ugr.es: Figures “What goes up, must come down” “What goes up”, The Alan Parsons Project - British rock band
  • 14. 485 million clicks (page views) 389 million (80%) students 26 million (5%) teachers 69 million (14%) others 1 million (<1%) admin. swad.ugr.es: Figures (Jan 2005 May → 2022)
  • 15. 199,794 users have used the platform 174,879 (88%) as students 3933 (2%) as teachers 36,479 (18%) as guests 133 (<1%) as admin. swad.ugr.es: Figures (Jan 2005 May → 2022)
  • 18. ...from 1108institutions ugr 115,780 (74%) from UGR 11,351 (7%) from other institutions 28,819 (18%) unknown 538 degrees 7654 courses swad.ugr.es: Figures (May 2022)
  • 19. 835,619 (1.9 TB) files 47,349 test questions 1403 forums 26 million times answered 66,589 posts swad.ugr.es: Figures (May 2022)
  • 20. swad.ugr.es: Figures (Oct 1999 May 2022) → 7654 courses 5104 with students
  • 21. swad.ugr.es: Figures (Oct 1999 May 2022) → 3651 teachers
  • 22. swad.ugr.es: Figures (Oct 1999 May 2022) → 129,589 students
  • 23. swad.ugr.es: Figures (2005 2021) → real users / academic year
  • 24. swad.ugr.es: Figures (Jan 2005 May 2022) → page views / week
  • 25. swad.ugr.es: Figures (Jan 2005 May 2022) → users / week
  • 26. swad.ugr.es: keys to success “Want your users to fall in love with your designs? Fall in love with your users.” Dana Chisnell - Designer and usability researcher swad.ugr.es: keys to success “Want your users to fall in love with your designs? Fall in love with your users.” Dana Chisnell - Designer and usability researcher
  • 27. swad.ugr.es: Keys to success ● #1: Platform open to the entire University since 2004 I Meeting of SWAD Users
  • 28. swad.ugr.es: Keys to success ● #2: Teacher training
  • 29. swad.ugr.es: Keys to success ● #3: User support: thousands of queries answered Thank you for your help and efficiency... and for having designed a computer invention that really works, which reconciles me with the new technologies...
  • 30. ● #4: Developed according to the users’ requests swad.ugr.es: Keys to success A user wants the platform to congratulate him on his birthday... Days later a new feature congratulates users for their birthdays.
  • 31. swad.ugr.es: Keys to success ● #5: Strengths of the tool ● Functionality and usability ● Simplicity ● It has what most teachers asked ● Reliability and safety ● It consumes few resources ● It works 24 hours, fast and almost without failures
  • 32. OpenSWAD: Project “A planet is the cradle of mind, but one cannot live in a cradle forever.” Konstantin Tsiolkovski - Russian physicist OpenSWAD: Project “A planet is the cradle of mind, but one cannot live in a cradle forever.” Konstantin Tsiolkovski - Russian physicist
  • 33. OpenSWAD: Project ● SWAD outside the UGR after release ● Little diffusion ● Difficult to reach the target audience (need for advertising) ● Absence of simple installation ● Many competitors ● Many LMS, some of them very widespread ● Released as free software too late (2010) ● A lot of work, small team ● Conclusion ● Very few (two or three) installations
  • 34. OpenSWAD: Project ● OpenSWAD.org is an installation in the cloud of the SWAD educational platform, offered free of charge for any country by the OpenSWAD Association (non-profit organization, independent of the UGR) ● OpenSWAD.org is available since 2012, but it did not start growing until 2015, when we decided to carry out advertising campaigns
  • 35. OpenSWAD: Project ● Why “Open”? ● Free software ● So open source ● Open and free for everyone ● Open design and interaction ● You can access many features (hierarchy, courses, teachers, statistics) even if you are not logged in ● Open content allowed ● Upload, mark as public and choose license ● Anyone could access, even without log in
  • 36. OpenSWAD: Project Steps for internationalization: 1. Code independent from the institution (100%) 2. Translation to 9 languages (90%) 3. ISO 8601 format for date-times (100%) 4. Dates-hours independent of location (100%) 5. Calendars independent of location (100%) 6. Weeks starting on Monday or Sunday (100%) 7. Floating point / comma format (10%)
  • 37. OpenSWAD: Advertising “Doing business without advertising is like winking at a girl in the dark. You know what you are doing, but nobody else does.” Steuart Henderson Britt - American professor of marketing OpenSWAD: Advertising “Doing business without advertising is like winking at a girl in the dark. You know what you are doing, but nobody else does.” Steuart Henderson Britt - American professor of marketing
  • 38. OpenSWAD.org: Advertising 2,600,000 ad impressions on Twitter and Facebook 2,600,000 ad impressions on Twitter and Facebook 2600 filled in their data (50%) 2600 filled in their data (50%) 260 created center, degree, course (10%) 260 created center, degree, course (10%) 130,000 clicked link (5%) 130,000 clicked link (5%) 5200 created account ( 5200 created account (4% 4%) ) 130 enrolled in course (50%) 130 enrolled in course (50%) 65 created course content (50%) 65 created course content (50%) 13 used with students (20%, 5 per million) 13 used with students (20%, 5 per million) Example: Feb. 2015 March 2016 → Conversion funnel
  • 39. OpenSWAD.org: Advertising Cost Dates Days Cost/day Impressions Clicks Cost/click Twitter 4650.29€ Feb 12, 2015 Sep 25, 2017 956 4.86 € 14,042,284 50,119 €0.108 Facebook 2400.84€ Sep 26, 2015 Sep 25, 2017 730 3.29 € 12,858,591 192,833 €0.012 AdWords 1255.93€ Feb 16, 2017 Sep 25, 2017 221 5.68 € 392,298 15,046 €0.083 Total 8307.06€ Feb 12, 2015 Sep 25, 2017 956 8.69 € 27,293,173 257,998 €0.032 Courses Teachers Students Total users Courses or users with real use 528 385 1657 18 411 Cost per course or user €15,73 €21,58 €5,01 €0,45 Cost of advertising (2015 2017) →
  • 40. OpenSWAD.org: Advertising Cost Dates Days Impresiones Clicks Page views Users New accounts New courses Twitter €66.20 Sep 6 - Sep 24, 2017 7 €9.46 / day 271,072 €0.00024 / impression 734 €0.09 / click 14 632 €0.0045 / page view 342 €0.19 / user 186 €0.36 / new account 10 €6.62 / new course Facebook €109.66 Sep 7 - Sep 25, 2017 7 €15.66 / day 148,206 €0.00074 / impression 3780 €0.03 / click 33 087 €0.0033 / page view 274 €0.40 / user 114 €0.96 / new account 12 €9.14 / new course AdWords €65.83 Sep 5 - Sep 23, 2017 7 €9.40 / day 13,210 €0.00498 / impression 808 €0.08 / click 11 169 €0.0060 / page view 243 €0.27 / user 94 €0.70 / new account 7 €9.40 / new course Total €241.69 Sep 5 - Sep 25, 2017 21 €11.51 / day 432,488 €0.00056 / impression 5322 €0.05 / click 58 888 €0.0041 / page view 859 €0.28 / user 394 €0.61 / new account 29 €8.33 / new course Conversion comparison (2017)
  • 41. OpenSWAD: Figures “Y si no me quieres ver, ya sabes que seguro que hay alguien que querrá.” “Volverás”, Niños Mutantes – Spanish indie rock band OpenSWAD: Figures “Y si no me quieres ver, ya sabes que seguro que hay alguien que querrá.” “Volverás”, Niños Mutantes – Spanish indie rock band
  • 45. First countries in OpenSWAD according to number of users First countries in OpenSWAD according to number of users OpenSWAD: Users / country 34,803 users from 152 countries
  • 46. OpenSWAD: Users / country ● A report on OpenSWAD was even broadcast on a Latin American TV channel OpenSWAD in Atomun, Telesur TV (Venezuela), July 2017
  • 47. OpenSWAD: Users / institution Users from 2173 institutions
  • 48. OpenSWAD: Users / month 2014 2022 → Advertisements
  • 49. OpenSWAD: Teachers / month 2014 2022 → Advertisements
  • 50. OpenSWAD: Students / month 2014 2022 → Advertisements
  • 51. Free software “You're frozen When your heart's not open” “Frozen”, Madonna - American singer-songwriter Free software “You're frozen When your heart's not open” “Frozen”, Madonna - American singer-songwriter
  • 52. Free software January 21, 2010 Free Software Office of the University of Granada
  • 53. Free software ● Steps to release the core: 1. Code (names, comments) in English (100%) 2. Code independent from the UGR (100%) 3. Translation to 9 languages (90%) 4. Add AGPL headers to files (100%) 5. Publish the source code (100%) https://openswad.org/source/ 6. Publish the installation procedure (100%) https://openswad.org/install/ 7. Use git version control system (100%) 8. Upload to GitHub (100%) https://github.com/acanas/swad-core 9. Desirable: automate installation (20%)
  • 54. Free software ● Because it facilitates collaborative development Fourth Hackathon of free software projects of the UGR, 2012. Photo: A. Cañas
  • 55. Free software ● Because it encourages better programming @psicobyte_ explains the benefits of free software. Photo: A. Cañas
  • 56. Free software ● Because it improves the code quality Hackathon of SWADroid and SWAD, 2013. Photo: A. Cañas
  • 57. Free software ● Because it provides freedom and security to users https://www.gnu.org/philosophy/
  • 58. Implementation “Every step that you take Could be your biggest mistake It could bend or it could break That's the risk that you take” “What If”, Coldplay - British rock band Implementation “Every step that you take Could be your biggest mistake It could bend or it could break That's the risk that you take” “What If”, Coldplay - British rock band
  • 59. How much work is behind? swad-core SWADroid Affero GPL v3 license https://github.com/acanas/swad-core GPL v3 license https://github.com/Amab/SWADroid 364,503 C code lines 144 MySQL tables 60,761 Java code lines 17K downloads 95 person-years estimated effort* 14 person-years estimated effort* $5,239,555 estimated cost* $793,894 estimated cost* Other modules and more info: https://openswad.org/source * According to the COCOMO model in Open Hub
  • 60. The core ● Written from scratch in C (compiled, not interpreted) ✔Advantages: ● + speed ● - memory ● Functional even in a Raspberry Pi ● + stability of source code over time ✘Disadvantages: ● absence of specialized library functions for the web
  • 61. 2nd: 2004-2006 Pentium 4 HT RAM 2 GiB 2 HD 160 GB Fedora 3 3rd: 2007-2008 Core 2 Duo RAM 4 GiB 2 HD 500 GB Fedora 6 4th: 2009-2010 Core 2 Quad RAM 4 GiB 2 HD 146 GB 2 HD 1 TB Fedora 10 5th: 2011-2016 2 Xeon Quad RAM 24 GiB 4 HD 146 GB 4 HD 500 GB CentOS 5.7 1st: 1999-2003 Shared server Former servers at the UGR
  • 62. Current server at the UGR (6th: 2016-2022) ● HP Proliant DL160 G9, 2 Xeon with 6 cores, RAM 32 GiB 4 HD 146 GB SAS 15000 rpm RAID 1+0 (292 GB) SO CentOS 7.2 MySQL database 4 HD 1 TB SAS 7200 rpm RAID 5 (3 TB) Web files ( /var/www )
  • 63. Plugins ● It is possible to develop add-ons (plugins) that run on: ● other servers ● mobile devices. Example: SWADroid ● The plugins interact with the swad core through an API: https://openswad.org/api/
  • 64. Photographs of users ● Our own automatic system for detecting faces and improving the quality of photos, trained with 90K photos
  • 65. Up to 400K times per day Up to 2000 times / minute (30 times / second) Log “click” logged access HTML5 server database swad-core
  • 66. 144 database tables. The largest is the one used to store the access log. Database
  • 67. Log table ● It allows analyzing a lot of information: ● By role ● By user ● By action performed ● By qualification ● By subject ● By dates ● ... UGR: 485 million registered hits since 2005
  • 68. Log table Pages per minute (averaged during an academic year) teachers students
  • 69. Log table Matches of the Soccer World Cup 2010 You can even see the rest in the match
  • 70. Log table Peak: students choosing groups Page views per minute
  • 71. Log table ● What if we convert every click into a sound? ● At 1 am: http://swad.ugr.es/stat/clicks/clicks_1am.wav ● At 1 pm: http://swad.ugr.es/stat/clicks/clicks_1pm.wav ● Peak (students choosing groups): http://swad.ugr.es/stat/clicks/clicks_grupos.wav
  • 72. Timeline: Notes & Publications “You think you know when you learn, are more sure when you can write, even more when you can teach, but certain when you can program.” Alan Perlis - Computer scientist and professor Timeline: Notes & Publications “You think you know when you learn, are more sure when you can write, even more when you can teach, but certain when you can program.” Alan Perlis - Computer scientist and professor
  • 73. Timeline: Notes & Publications ● Timeline: set of publications ● from a user ● global ● Only me ● Followed users ● All users typedef enum { Tml_Usr_TIMELINE_USR, Tml_Usr_TIMELINE_GBL, } Tml_Usr_UsrOrGbl_t; typedef enum { Usr_WHO_UNKNOWN, Usr_WHO_ME, Usr_WHO_SELECTED, // Not applicable to timeline Usr_WHO_FOLLOWED, Usr_WHO_ALL, } Usr_Who_t;
  • 74. Timeline: Notes & Publications ● Publication: · original note (25393, 76% of 33504) · shared note ( 1425, 4% of 33504) · comment to a note ( 6686, 20% of 33504) typedef enum { Tml_Pub_UNKNOWN = 0, Tml_Pub_ORIGINAL_NOTE = 1, Tml_Pub_SHARED_NOTE = 2, Tml_Pub_COMMENT_TO_NOTE = 3, } TmlPub_Type_t; struct TmlPub_Publication { long PubCod; // Publication code long NotCod; // Note code long PublisherCod; // Sharer or writer of the publication TmlPub_Type_t Type; // Original note, shared note, comment struct TmlPub_Publication *Next; // Used for chained list }; *swad.ugr.es, may 2022
  • 75. Timeline: Notes & Publications ● Note: timeline post ( 4755, 19% of 25393) public file ( 66, <1% of 25393) call for exam ( 2807, 11% of 25393) notice (17480, 69% of 25393) forum post ( 285, 1% of 25393) *swad.ugr.es, may 2022
  • 76. Timeline: Notes & Publications typedef enum { TmlNot_UNKNOWN = 0, /* Start tab */ TmlNot_POST = 10, // Post written directly in timeline /* Institution tab */ TmlNot_INS_DOC_PUB_FILE = 1, // Public file in documents of institution TmlNot_INS_SHA_PUB_FILE = 2, // Public file in shared files of institution /* Center tab */ TmlNot_CTR_DOC_PUB_FILE = 3, // Public file in documents of center TmlNot_CTR_SHA_PUB_FILE = 4, // Public file in shared files of center /* Degree tab */ TmlNot_DEG_DOC_PUB_FILE = 5, // Public file in documents of degree TmlNot_DEG_SHA_PUB_FILE = 6, // Public file in shared files of degree /* Course tab */ TmlNot_CRS_DOC_PUB_FILE = 7, // Public file in documents of course TmlNot_CRS_SHA_PUB_FILE = 8, // Public file in shared files of course /* Assessment tab */ TmlNot_CALL_FOR_EXAM = 9, // Call for exam in a course /* Users tab */ /* Messages tab */ TmlNot_NOTICE = 12, // A public notice in a course TmlNot_FORUM_POST = 11, // Post in global/swad forums /* Analytics tab */ /* Profile tab */ } TmlNot_Type_t;
  • 77. Timeline: Notes & Publications struct TmlNot_Note { long NotCod; // Unique code/identifier for each note TmlNot_Type_t Type; // Timeline post, public file, // call for exam, notice, forum post... long UsrCod; // Publisher long HieCod; // Hierarchy code // (institution/center/degree/course) long Cod; // Code of file, forum post, // notice, timeline post... bool Unavailable; // File, forum post, notice... // unavailable (removed) time_t DateTimeUTC; // Date-time of publication in UTC time unsigned NumShared; // Number of times (users) // this note has been shared unsigned NumFavs; // Number of times (users) // this note has been favourited };
  • 78. Timeline: Notes & Publications __________________ |@author | | Note | |__________________| |@author | | Comment 1 | |______________| |@author | | Comment 2 | |______________| | | | ... | |______________| |@author | | Comment n | |______________| ● A note can have comments attached to it:
  • 79. Timeline: Notes & Publications _tml_pubs______ _tml_comments | | | | | Publication p |---------->| Comment c |-----+ | (comment) | | (to note 2) | | |_______________| |_____________| | | | | | | · ... · · ... · | · ... · · ... · | |_______________| |_____________| | | | | | | |Publication i+4|---------->| Comment 1 |---+ | | (comment) | | (to note n) | | | |_______________| |_____________| | | | | (6686) | | |Publication i+3|-- | | |(original note)| | | |_______________| _tml_notes_____ | | _cfe_exams_____ | | | | | | | | |Publication i+2|-- ---->| Note n |<-+ | | Call for exam | (5649) |(original note)| |(exam announc.)|-(2807)->|_______________| |_______________| |_______________| 11% __brw_files____ | | | | | | | |Publication i+1|-- ---->| Note n-1 |-(66)--->| Public file | (1561098) |(original note)| | (public file) | <1% |_______________| |_______________| |_______________| | _not_notices___ | | | | | | | | Publication i |-- ---->| Note n-2 |-(17480)>| Notice | (15219) |(original note)| | (notice) | 69% |_______________| |_______________| |_______________| | __tml_posts____ | | | | | | | · ... · ---->| Note n-3 |-(4755)->| Post s | · ... · | (tl. post) | 19% | | |_______________| |_______________| | |_______________| | | | | | | | | Publication 3 | · ... · | · ... · (4755) | (shared note) |--- · ... · | · ... · |_______________| |_______________| | |_______________| | | | | | | | | Publication 2 | ---->| Note 2 |<---+ | Post 1 | |(original note)|--------->| (tl. post) |-------->| | |_______________| |_______________| |_______________| | | | | _for_posts_____ | Publication 1 |--------->| Note 1 | | | |(original note)| | (forum post) |-(285)-->| Forum post | (66612) |_______________| |_______________| 1% |_______________| (33504) (25393) timeline posts public files calls for exams notices forum posts notes comments publications *swad.ugr.es, may 2022
  • 80. Timeline: Database “Don't forget to put the WHERE in the DELETE FROM.” Jorge Rubira Santos - Entrepreneur and Youtuber Timeline: Database “Don't forget to put the WHERE in the DELETE FROM.” Jorge Rubira Santos - Entrepreneur and Youtuber
  • 81. 144 database tables. 7 for timeline. Timeline: Database
  • 82. Timeline: Database mysql> SHOW TABLES LIKE 'tml_%'; +------------------------+ | Tables_in_swad (tml_%) | +------------------------+ | tml_comments | | tml_comments_fav | | tml_notes | | tml_notes_fav | | tml_posts | | tml_pubs | | tml_timelines | +------------------------+ 7 rows in set (0.00 sec)
  • 83. Timeline: Database mysql> DESCRIBE tml_pubs; +--------------+----------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +--------------+----------+------+-----+---------+----------------+ | PubCod | bigint | NO | PRI | NULL | auto_increment | | NotCod | bigint | NO | MUL | NULL | | | PublisherCod | int | NO | MUL | NULL | | | PubType | tinyint | NO | MUL | NULL | | | TimePublish | datetime | NO | MUL | NULL | | +--------------+----------+------+-----+---------+----------------+
  • 84. Timeline: Database mysql> DESCRIBE tml_notes; +-------------+---------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------------+---------------+------+-----+---------+----------------+ | NotCod | bigint | NO | PRI | NULL | auto_increment | | NoteType | tinyint | NO | MUL | NULL | | | Cod | int | NO | | -1 | | | UsrCod | int | NO | MUL | NULL | | | HieCod | int | NO | | -1 | | | Unavailable | enum('N','Y') | NO | | N | | | TimeNote | datetime | NO | MUL | NULL | | +-------------+---------------+------+-----+---------+----------------+ mysql> DESCRIBE tml_notes_fav; +---------+----------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +---------+----------+------+-----+---------+----------------+ | FavCod | bigint | NO | PRI | NULL | auto_increment | | NotCod | bigint | NO | MUL | NULL | | | UsrCod | int | NO | MUL | NULL | | | TimeFav | datetime | NO | | NULL | | +---------+----------+------+-----+---------+----------------+
  • 85. Timeline: Database mysql> DESCRIBE tml_comments; +--------+----------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +--------+----------+------+-----+---------+-------+ | PubCod | bigint | NO | PRI | NULL | | | Txt | longtext | NO | MUL | NULL | | | MedCod | int | NO | MUL | -1 | | +--------+----------+------+-----+---------+-------+ mysql> DESCRIBE tml_comments_fav; +---------+----------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +---------+----------+------+-----+---------+----------------+ | FavCod | bigint | NO | PRI | NULL | auto_increment | | PubCod | bigint | NO | MUL | NULL | | | UsrCod | int | NO | MUL | NULL | | | TimeFav | datetime | NO | | NULL | | +---------+----------+------+-----+---------+----------------+
  • 86. Timeline: Database mysql> DESCRIBE tml_posts; +--------+----------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +--------+----------+------+-----+---------+----------------+ | PstCod | int | NO | PRI | NULL | auto_increment | | Txt | longtext | NO | MUL | NULL | | | MedCod | int | NO | MUL | -1 | | +--------+----------+------+-----+---------+----------------+ mysql> DESCRIBE cfe_exams; +-------------+---------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------------+---------------+------+-----+---------+----------------+ | ExaCod | int | NO | PRI | NULL | auto_increment | | ... | ... | ... | ... | ... | ... | mysql> DESCRIBE brw_files; +-----------------+---------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-----------------+---------------+------+-----+---------+----------------+ | FilCod | int | NO | PRI | NULL | auto_increment | | ... | ... | ... | ... | ... | ... | mysql> DESCRIBE not_notices; +-----------+----------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-----------+----------+------+-----+---------+----------------+ | NotCod | int | NO | PRI | NULL | auto_increment | | ... | ... | ... | ... | ... | ... | mysql> DESCRIBE for_posts; +-----------+----------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-----------+----------+------+-----+---------+----------------+ | PstCod | int | NO | PRI | NULL | auto_increment | | ... | ... | ... | ... | ... | ... |
  • 87. Timeline: Database mysql> DESCRIBE tml_timelines; +-----------+----------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-----------+----------+------+-----+---------+-------+ | SessionId | char(43) | NO | PRI | NULL | | | NotCod | bigint | NO | PRI | NULL | | +-----------+----------+------+-----+---------+-------+ mysql> DESCRIBE tml_tmp_timeline; +--------+--------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +--------+--------+------+-----+---------+-------+ | NotCod | bigint | NO | PRI | NULL | NULL | +--------+--------+------+-----+---------+-------+ What is being displayed on the screens of each of the users What is being displayed on the current user's screen
  • 88. Timeline: Getting publications “When I wrote this code, only God and I understood what I did. Now only God knows.” Unknown source Timeline: Getting publications “When I wrote this code, only God and I understood what I did. Now only God knows.” Unknown source
  • 89. Timeline: Getting publications ● Our algorithm: ● Select publications one by one in a loop ● In each iteration: ● Get the most recent publication (original, shared or comment) checking that its note is not already retrieved ● After getting a publication, save its note code to not get it again. SELECT PubCod FROM tml_pubs WHERE NotCod NOT IN (SELECT NotCod FROM tml_tmp_timeline) ORDER BY PubCod DESC LIMIT 1;
  • 90. Timeline: Getting publications ● Slower alternative (may need seconds for large tables): ● Get the maximum PubCod, i.e more recent publication (original, shared or commment), of every set of publications corresponding to the same note: SELECT MAX(PubCod) AS NewestPubCod FROM tml_pubs GROUP BY NotCod ORDER BY NewestPubCod DESC LIMIT 10;
  • 91. Timeline: Getting publications ● Restricting publications to mine and those I follow: CREATE TEMPORARY TABLE fol_tmp_me_and_followed (UsrCod INT NOT NULL, UNIQUE INDEX(UsrCod)) ENGINE=MEMORY SELECT my_usr_cod AS UsrCod UNION SELECT FollowedCod AS UsrCod FROM usr_follow WHERE FollowerCod=my_usr_cod; ------------------------------ SELECT tml_pubs.PubCod, tml_pubs.NotCod, tml_pubs.PublisherCod, tml_pubs.PubType FROM tml_pubs, fol_tmp_me_and_followed WHERE tml_pubs.PublisherCod=fol_tmp_me_and_followed.UsrCod AND tml_pubs.NotCod NOT IN (SELECT NotCod FROM tml_tmp_timeline) ORDER BY PubCod DESC LIMIT 1; mysql> DESCRIBE usr_follow; +-------------+----------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------------+----------+------+-----+---------+-------+ | FollowerCod | int | NO | PRI | NULL | | | FollowedCod | int | NO | PRI | NULL | | | FollowTime | datetime | NO | MUL | NULL | | +-------------+----------+------+-----+---------+-------+
  • 92. Timeline: Getting publications ● Three types of timeline updates _ ______________________ / |______________________| New < |______________________| _|______________________| _|_See_new_activity_(3)_| / |______________________| | |______________________| Recent < |______________________| | |______________________| _|______________________| _|_______See_more_______| / |______________________| | |______________________| Old < |______________________| | |______________________| _|______________________| typedef enum { Tml_GET_NEW_PUBS, // automatically // from time // to time (AJAX) Tml_GET_REC_PUBS, // user clicks // on menu // or after // editing // timeline Tml_GET_OLD_PUBS, // user clicks // on bottom // link (AJAX) } Tml_WhatToGet_t;
  • 93. Timeline: Getting publications tml_pubs _____ |_____|11 |_____|10 _|_____| 9 <-- RangePubsToGet.Top Get / |_____| 8 pubs | |_____| 7 from < |_____| 6 this | |_____| 5 range _|_____| 4 |_____| 3 <-- RangePubsToGet.Bottom |_____| 2 |_____| 1 0
  • 94. Timeline: Getting publications case Tml_GET_REC_PUBS: // Get some limited recent publications /* First query to get initial timeline shown ==> no notes yet in current timeline table */ RangePubsToGet->Top = 0; /* _ _____ 0 <-- RangePubsToGet.Top = +infinite / |_____| 8 Get | |_____| 7 pubs < |_____| 6 from | |_____| 5 all | |_____| 4 range . |_____| 3 . |_____| 2 . |_____| 1 0 <-- RangePubsToGet.Bottom = -infinite */ RangePubsToGet->Bottom = 0;
  • 95. Timeline: Getting publications case Tml_GET_NEW_PUBS: // Get the publications (without limit) // newer than last pub. code /* Via AJAX automatically from time to time */ RangePubsToGet->Top = 0; /* _ _____ 0 <-- RangePubsToGet.Top = +infinite Get / |_____|11 these < |_____|10 pubs _|_____| 9 / |_____| 8 <-- RangePubsToGet.Bottom = last pub. code Pubs | |_____| 7 already < |_____| 6 shown | |_____| 5 | |_____| 4 . |_____| . . |_____| . . |_____| . */ RangePubsToGet->Bottom = Tml_DB_GetPubCodFromSession (Tml_Pub_LAST);
  • 96. Timeline: Getting publications case Tml_GET_OLD_PUBS: // Get some limited publications // older than first pub. code /* Via AJAX when I click in link to get old publications */ RangePubsToGet->Top = Tml_DB_GetPubCodFromSession (Tml_Pub_FIRST); /* _____ . |_____| . . |_____| . . |_____| . Pubs | |_____| 8 already < |_____| 7 shown | |_____| 6 | |_____| 5 Get _|_____| 4 <-- RangePubsToGet.Top = first pub. code pubs / |_____| 3 from < |_____| 2 this _|_____| 1 rage 0 <-- RangePubsToGet.Bottom = -infinite */ RangePubsToGet->Bottom = 0;
  • 97. Timeline: Getting publications ● Restricting publications to range: SELECT tml_pubs.PubCod, tml_pubs.NotCod, tml_pubs.PublisherCod, tml_pubs.PubType FROM tml_pubs, fol_tmp_me_and_followed WHERE tml_pubs.PublisherCod=fol_tmp_me_and_followed.UsrCod AND tml_pubs.PubCod>bottom // if type == Tml_GET_REC_PUBS AND tml_pubs.PubCod<top // updated every iteration // to last pub. code got AND tml_pubs.NotCod NOT IN (SELECT NotCod FROM tml_tmp_timeline) ORDER BY PubCod DESC LIMIT 1;
  • 98. Timeline: Getting publications Timeline->Pubs.Top Pub #0 ______ ______ Pub #1 |______|------>|______| ______ Pub #2 |______| -> |______| ______ Pub #3 |______| / |______| ->|______| ______ |______| / |______| / |______| ->|______| |_Next_|-- |______| / |______| // |______| more recent |_Next_|-- |______| // |______| ______ |_Next_|--/ |______| |______|---------------------------------------------- |_NULL_| older Timeline->Pubs.Bottom ● After getting the publications, the result is a chained list:
  • 99. Timeline: Showing publications “There is beauty when something works and works intuitively.” Jonathan Paul Ive - Designer Timeline: Showing publications “There is beauty when something works and works intuitively.” Jonathan Paul Ive - Designer
  • 100. Timeline: Showing publications _____ / |_____| just_now_timeline_list (Posts retrieved automatically | |_____| via AJAX from time to time. | |_____| They are transferred inmediately | | to new_timeline_list.) Hidden < __v__ | |_____| new_timeline_list (Posts retrieved but hidden. | |_____| When user clicks to view them, | |_____| the most recent of each note is |_____| is transferred | to visible timeline_list.) See new activity (0) __v__ / |_____| timeline_list (Posts visible on page) | |_____| Visible | |_____| on < |_____| page | |_____| | |_____| |_____| ^ See more __|__ / |_____| old_timeline_list (Posts just retrieved via AJAX | |_____| when user clicks "see more". | |_____| They are transferred inmediately Hidden < |_____| to timeline_list.) | |_____| | |_____| |_____| <ul id="just_now_timeline_list" ...> </ul> <ul id="new_timeline_list" ...> </ul> <div id="view_new_container" ... style="display:none;"> <a href="" ... onclick="moveNewTimelineToTimeline(); return false;"> See new activity (<span id="view_new_count"> 0 </span>) </a> </div> <ul id="timeline_list" ...> visible timeline </ul> <div id="view_old_container" ...> <a href="" ... onclick="... refreshOldTimeline(); return false;"> ... See more </a> </div> <ul id="old_timeline_list" ...> </ul>
  • 101. Timeline: Showing publications <head> ... <script type="text/javascript" ...> var delayNewTml = Cfg_TIME_TO_REFRESH_TIMELINE; // 2000 ms function init() { ActionAJAX = "SWAD_URL"; ... setTimeout('refreshNewTimeline()',delayNewTL); ... } </script> <script type="text/javascript" ...> var refreshParamIdSes = "ses=..."; var refreshParamNxtActNewPub = "act=..."; var refreshParamWho = "Who=..."; </script> ... </head> <body onload="init();"> ... </body> ● Automatic refresh via AJAX every 2 s → 3 s → 4 s... _____ / |_____| just_now_timeline_list | |_____| | |_____| | | Hidden < __v__ | |_____| new_timeline_list | |_____| | |_____| |_____| | See new activity (0) __v__ / |_____| timeline_list | |_____| Visible | |_____| on < |_____| page | |_____| | |_____| |_____| ^ See more __|__ / |_____| old_timeline_list | |_____| | |_____| Hidden < |_____| | |_____| | |_____| |_____|
  • 102. Timeline: Showing publications var objXMLHttpReqNewTml = false; function refreshNewTimeline () { objXMLHttpReqNewTml = AJAXCreateObject(); // new XMLHttpRequest() if (objXMLHttpReqNewTml) { var RefreshParams = refreshParamNxtActNewPub + '&' + refreshParamIdSes + '&' + refreshParamWho; objXMLHttpReqNewTml.onreadystatechange = readNewTimelineData; objXMLHttpReqNewTml.open('POST',ActionAJAX,true); objXMLHttpReqNewTml.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); objXMLHttpReqNewTml.send(RefreshParams); } } _____ / |_____| just_now_timeline_list | |_____| | |_____| | | Hidden < __v__ | |_____| new_timeline_list | |_____| | |_____| |_____| | See new activity (0) __v__ / |_____| timeline_list | |_____| Visible | |_____| on < |_____| page | |_____| | |_____| |_____| ^ See more __|__ / |_____| old_timeline_list | |_____| | |_____| Hidden < |_____| | |_____| | |_____| |_____|
  • 103. Timeline: Showing publications function readNewTimelineData () { if (objXMLHttpReqNewTml.readyState == 4) // Check if data have been received if (objXMLHttpReqNewTml.status == 200) { // Access to UL for just now timeline var justNowTimeline = document.getElementById('just_now_timeline_list'); if (justNowTimeline) { // Update list of publications in just now timeline justNowTimeline.innerHTML = objXMLHttpReqNewTml.responseText; var numNotesJustGot = justNowTimeline.childNodes.length; if (numNotesJustGot) {// New notes received // Scripts in timeline got via AJAX not executed ==> execute them evalScriptsInElem (justNowTimeline); // Process maths MathJax.typeset(); ... _____ / |_____| just_now_timeline_list | |_____| | |_____| | | Hidden < __v__ | |_____| new_timeline_list | |_____| | |_____| |_____| | See new activity (0) __v__ / |_____| timeline_list | |_____| Visible | |_____| on < |_____| page | |_____| | |_____| |_____| ^ See more __|__ / |_____| old_timeline_list | |_____| | |_____| Hidden < |_____| | |_____| | |_____| |_____|
  • 104. Timeline: Showing publications ... // Move all the LI elements (notes) in UL 'just_now_timeline_list' // ...to the top of UL 'new_timeline_list' var newTimeline = document.getElementById('new_timeline_list'); for (var i=0; i<numNotesJustGot; i++) { // Move node from just now timeline to new timeline newTimeline.insertBefore(justNowTimeline.lastChild, newTimeline.firstChild); newTimeline.firstChild.className += " Tml_NEW_PUB"; } // Update number of notes in new timeline var viewNewCount = document.getElementById('view_new_count'); viewNewCount.innerHTML = newTimeline.childNodes.length; // Unhide message with number of notes if hidden var viewNewContainer = document.getElementById('view_new_container'); viewNewContainer.style.display = ''; } } // Global delay variable is set initially in swad-core delayNewTml += 1000; // Increase one second on each call setTimeout('refreshNewTimeline()',delayNewTml); } } _____ / |_____| just_now_timeline_list | |_____| | |_____| | | Hidden < __v__ | |_____| new_timeline_list | |_____| | |_____| |_____| | See new activity (0) __v__ / |_____| timeline_list | |_____| Visible | |_____| on < |_____| page | |_____| | |_____| |_____| ^ See more __|__ / |_____| old_timeline_list | |_____| | |_____| Hidden < |_____| | |_____| | |_____| |_____|
  • 105. _____ / |_____| just_now_timeline_list | |_____| | |_____| | | Hidden < __v__ | |_____| new_timeline_list | |_____| | |_____| |_____| | See new activity (0) __v__ / |_____| timeline_list | |_____| Visible | |_____| on < |_____| page | |_____| | |_____| |_____| ^ See more __|__ / |_____| old_timeline_list | |_____| | |_____| Hidden < |_____| | |_____| | |_____| |_____| Timeline: Showing publications function moveNewTimelineToTimeline () { // Move the LI elements (notes) in UL 'new_timeline_list'... // ...to the top of UL 'timeline_list', only if not repeated before var newTimeline = document.getElementById('new_timeline_list'); var numNewNotes = newTimeline.childNodes.length; if (numNewNotes) { var timeline = document.getElementById("timeline_list"); for (var i=1; i<=numNewNotes; i++) { // Check if the last child (the oldest) in the new timeline... // ...is the last ocurrence of the note var mostRecentOcurrenceOfNote = true; var lastChildIndex = numNewNotes - i; var noteCode = newTimeline.lastChild.dataset.noteCode; for (var j=0; j<lastChildIndex; j++) if (newTimeline.childNodes[j].dataset.noteCode == noteCode) { mostRecentOcurrenceOfNote = false; break; } ... ● User clicks "See new activity" → View new pubs.
  • 106. Timeline: Showing publications ... // Move or remove node from new timeline if (mostRecentOcurrenceOfNote) { // Move node from new timeline to timeline timeline.insertBefore(newTimeline.lastChild,timeline.firstChild); timeline.firstChild.className += " Tml_NEW_PUB"; } else // Remove last child (because is repeated in more recent pubs) newTimeline.removeChild(newTimeline.lastChild); } } // Reset number of new publications after moving var viewNewCount = document.getElementById('view_new_count'); viewNewCount.innerHTML = 0; // Hide link to view new publications after moving var viewNewContainer = document.getElementById('view_new_container'); viewNewContainer.style.display = 'none'; } _____ / |_____| just_now_timeline_list | |_____| | |_____| | | Hidden < __v__ | |_____| new_timeline_list | |_____| | |_____| |_____| | See new activity (0) __v__ / |_____| timeline_list | |_____| Visible | |_____| on < |_____| page | |_____| | |_____| |_____| ^ See more __|__ / |_____| old_timeline_list | |_____| | |_____| Hidden < |_____| | |_____| | |_____| |_____|
  • 107. _____ / |_____| just_now_timeline_list | |_____| | |_____| | | Hidden < __v__ | |_____| new_timeline_list | |_____| | |_____| |_____| | See new activity (0) __v__ / |_____| timeline_list | |_____| Visible | |_____| on < |_____| page | |_____| | |_____| |_____| ^ See more __|__ / |_____| old_timeline_list | |_____| | |_____| Hidden < |_____| | |_____| | |_____| |_____| Timeline: Showing publications var objXMLHttpReqOldTml = false; function refreshOldTimeline () { objXMLHttpReqOldTml = AJAXCreateObject (); // new XMLHttpRequest() if (objXMLHttpReqOldTml) { var refreshParams = refreshParamNxtActOldPub + '&' + refreshParamIdSes; if (typeof refreshParamUsr !== 'undefined') { if (refreshParamUsr.length) refreshParams += '&' + refreshParamUsr; } if (typeof refreshParamWho !== 'undefined') { if (refreshParamWho.length) refreshParams += '&' + refreshParamWho; } objXMLHttpReqOldTml.onreadystatechange = readOldTimelineData; objXMLHttpReqOldTml.open('POST',actionAJAX,true); objXMLHttpReqOldTml.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); objXMLHttpReqOldTml.send(refreshParams); } } ● User clicks "See more..." → View old pubs.
  • 108. Timeline: Showing publications function readOldTimelineData () { if (objXMLHttpReqOldTml.readyState == 4) // Check if data have been received if (objXMLHttpReqOldTml.status == 200) { // Access to UL with the old timeline var oldTimeline = document.getElementById('old_timeline_list'); if (oldTimeline) { // Fill list of publications in old timeline oldTimeline.innerHTML = objXMLHttpReqOldTml.responseText; var countOldTimeline = oldTimeline.childNodes.length; if (countOldTimeline) { // Scripts in timeline got via AJAX not executed ==> execute them evalScriptsInElem (oldTimeline); // Process maths MathJax.typeset(); // Move all the LI elements in UL 'old_timeline_list' // to the bottom of UL 'timeline_list' var timeline = document.getElementById("timeline_list"); for (var i=0; i<countOldTimeline; i++) timeline.appendChild(oldTimeline.firstChild); ... _____ / |_____| just_now_timeline_list | |_____| | |_____| | | Hidden < __v__ | |_____| new_timeline_list | |_____| | |_____| |_____| | See new activity (0) __v__ / |_____| timeline_list | |_____| Visible | |_____| on < |_____| page | |_____| | |_____| |_____| ^ See more __|__ / |_____| old_timeline_list | |_____| | |_____| Hidden < |_____| | |_____| | |_____| |_____|
  • 109. Timeline: Showing publications ... // There may be more publications // Unhide icon to be hidden on click document.getElementById('get_old_timeline').style.display = ''; // Hide icon to be shown on click document.getElementById('getting_old_timeline').style.display = 'none'; } else // No old publications retrieved, so we have reached the oldest pub. // Hide container with link to get old publications document.getElementById("view_old_pubs_container").style.display = 'none'; } } } _____ / |_____| just_now_timeline_list | |_____| | |_____| | | Hidden < __v__ | |_____| new_timeline_list | |_____| | |_____| |_____| | See new activity (0) __v__ / |_____| timeline_list | |_____| Visible | |_____| on < |_____| page | |_____| | |_____| |_____| ^ See more __|__ / |_____| old_timeline_list | |_____| | |_____| Hidden < |_____| | |_____| | |_____| |_____|
  • 110. Timeline: Layout “Don't make me think.” Steve Krug - User Experience professional Timeline: Layout “Don't make me think.” Steve Krug - User Experience professional
  • 111. Timeline: Layout ___________________________________________ | | | Top message: | > top message |___________________________________________| / | _____ | | | || | | Author's name | Date-time | | | ||Auth.| |______________________|___________| | | ||photo| | | | author's | ||_____| | | > name, time | | | Note | | and content | | | content | | | | | | | | | |__________________________________| / | | | | | | | | | Favs | Shared |Remove| | > note | |_____________|_____________|______| | | |________| | | | | | List | | buttons | | Comment| of | > and | | icon | comments | | comments | |________|__________________________________| | | | | | | | Form to write new comment | | | |__________________________________| / /
  • 112. Timeline: Layout ● Top message <div class="Tml_TOP_CONT Tml_TOP_PUBLISHER Tml_WIDTH"> <form method="post" action="https://openswad.org/en" id="form_..." ...> <input type="hidden" name="act" value="1402"> <input type="hidden" name="ses" value="..."> <input type="hidden" name="OtherUsrCod" value="..."> <button type="submit" title="Another user's profile" class="BT_LINK Tml_TOP_PUBLISHER"> user name </button> </form> has shared: </div>
  • 113. Timeline: Layout ___________________________________________ | | | Top message: | > top message |___________________________________________| / | _____ | | | || | | Author's name | Date-time | | | ||Auth.| |______________________|___________| | | ||photo| | | | author's | ||_____| | | > name, time | | | Note | | and content | | | content | | | | | | | | | |__________________________________| / | | | | | | | | | Favs | Shared |Remove| | > note | |_____________|_____________|______| | | |________| | | | | | List | | buttons | | Comment| of | > and | | icon | comments | | comments | |________|__________________________________| | | | | | | | Form to write new comment | | | |__________________________________| / /
  • 114. Timeline: Layout ● Photo <div class="Tml_LEFT_PHOTO"> <form method="post" action="https://openswad.org/en" id="form_..." ...> <input type="hidden" name="act" value="1402"> <input type="hidden" name="ses" value="..."> <input type="hidden" name="OtherUsrCod" value="..."> <button type="submit" class="BT_LINK"> <img src="user-photo.jpg" alt="" title="username" class="PHOTO45x60" onmouseover="zoom(this,'user-photo.jpg','id_...');" onmouseout="noZoom();"> <div id="id_..." class="NOT_SHOWN"> <div class="ZOOM_TXT_LINE DAT_N_BOLD">first name<br>last name</div> <div class="ZOOM_TXT_LINE DAT_SMALL_N">@nickname</div> <div class="ZOOM_TXT_LINE DAT_SMALL">institution&nbsp;(country)</div> <div class="ZOOM_TXT_LINE DAT_SMALL"> <div class="ZOOM_DEG" style="background-image:url('user-icon.svg');">degree</div> </div> <div class="ZOOM_TXT_LINE"> <span class="DAT_N_BOLD">1</span><span class="DAT_SMALL">&nbsp;Following&nbsp;</span> <span class="DAT_N_BOLD">1</span><span class="DAT_SMALL">&nbsp;Followers</span> </div> </div> </button> </form> </div> Photo caption
  • 115. Timeline: Layout ___________________________________________ | | | Top message: | > top message |___________________________________________| / | _____ | | | || | | Author's name | Date-time | | | ||Auth.| |______________________|___________| | | ||photo| | | | author's | ||_____| | | > name, time | | | Note | | and content | | | content | | | | | | | | | |__________________________________| / | | | | | | | | | Favs | Shared |Remove| | > note | |_____________|_____________|______| | | |________| | | | | | List | | buttons | | Comment| of | > and | | icon | comments | | comments | |________|__________________________________| | | | | | | | Form to write new comment | | | |__________________________________| / /
  • 116. Timeline: Layout ● Author's name, date-time and note content <div class="Tml_RIGHT_CONT Tml_RIGHT_WIDTH"> <form method="post" action="https://openswad.org/en" id="form_..." ...> <input type="hidden" name="act" value="1402"> <input type="hidden" name="ses" value="..."> <input type="hidden" name="OtherUsrCod" value="..."> <button type="submit" title="My public profile" class="BT_LINK Tml_RIGHT_AUTHOR Tml_RIGHT_AUTHOR_WIDTH DAT_N_BOLD"> user name </button> </form> <div id="id_..." class="Tml_RIGHT_TIME DAT_LIGHT">date,&nbsp;time</div> <script type="text/javascript"> writeLocalDateHMSFromUTC ('id_...',unix-time,1,',&nbsp;',3,true,true,false,0x6); </script> <div class="Tml_TXT"> post content </div> </div>
  • 117. Timeline: Layout function writeLocalDateHMSFromUTC (id,TimeUTC,DateFormat, Separator,Language, WriteToday,WriteDateOnSameDay, WriteWeekDay,WriteHMS) { // HMS: Hour, Minutes, Seconds var today = new Date(); var todayYea = today.getFullYear (); var todayMon = today.getMonth () + 1; var todayDay = today.getDate (); var d = new Date(); var WriteDate; var Yea,Mon,Day; var DayOfWeek; var Hou,Min,Sec; var StrDat; var StrMon; var StrDay; var StrHou; var StrMin; var StrSec; d.setTime (TimeUTC * 1000); Yea = d.getFullYear (); Mon = d.getMonth () + 1; Day = d.getDate (); if (WriteDateOnSameDay) WriteDate = true; // Check to see if the last date has been initialized else if (typeof writeLocalDateHMSFromUTC.lastd == 'undefined') // lastd: static variable to remember date for the next call // Not initialized WriteDate = true; else WriteDate = (Yea != writeLocalDateHMSFromUTC.lastd.getFullYear () || Mon != writeLocalDateHMSFromUTC.lastd.getMonth () + 1 || Day != writeLocalDateHMSFromUTC.lastd.getDate ()); // Update last date for the next call writeLocalDateHMSFromUTC.lastd = d; /* Set date */ StrDat = ''; if (WriteDate) { WriteToday = WriteToday && (Yea == todayYea && Mon == todayMon && Day == todayDay); // Date is today if (WriteToday) StrDat = txtToday[Language]; else switch (DateFormat) { case 0: // Dat_FORMAT_YYYY_MM_DD StrMon = ((Mon < 10) ? '0' : '') + Mon; StrDay = ((Day < 10) ? '0' : '') + Day; StrDat = Yea.toString () + '-' + StrMon + '-' + StrDay; break; case 1: // Dat_FORMAT_DD_MONTH_YYYY StrDat = Day.toString () + '&nbsp;' + MonthsShort[Mon - 1] + '&nbsp;' + Yea.toString (); break; case 2: // Dat_FORMAT_MONTH_DD_YYYY StrDat = MonthsShort[Mon - 1] + '&nbsp;' + Day.toString() + ',&nbsp;' + Yea.toString (); break; default: break; } if (WriteWeekDay) { DayOfWeek = d.getDay (); DayOfWeek = (DayOfWeek == 0) ? 6 : DayOfWeek - 1; StrDat += Separator + DAYS[DayOfWeek]; } StrDat += Separator; } /* Set HH:MM:SS */ StrHou = ''; StrMin = ''; StrSec = ''; if (WriteHMS & (1<<2)) { // Bit 2 on => Write hour Hou = d.getHours(); StrHou = ((Hou < 10) ? '0' : '') + Hou; if (WriteHMS & (1<<1)) { // Bits 2,1 on => Write minutes Min = d.getMinutes (); StrMin = ((Min < 10) ? ':0' : ':') + Min; if (WriteHMS & 1) { // Bits 2,1,0 on => Write seconds Sec = d.getSeconds (); StrSec = ((Sec < 10) ? ':0' : ':') + Sec; } } } /* Write date and time */ document.getElementById (id).innerHTML = StrDat + StrHou + StrMin + StrSec; }
  • 118. Timeline: Layout ___________________________________________ | | | Top message: | > top message |___________________________________________| / | _____ | | | || | | Author's name | Date-time | | | ||Auth.| |______________________|___________| | | ||photo| | | | author's | ||_____| | | > name, time | | | Note | | and content | | | content | | | | | | | | | |__________________________________| / | | | | | | | | | Favs | Shared |Remove| | > note | |_____________|_____________|______| | | |________| | | | | | List | | buttons | | Comment| of | > and | | icon | comments | | comments | |________|__________________________________| | | | | | | | Form to write new comment | | | |__________________________________| / /
  • 119. Timeline: Layout ___________________________________________________________________________ | div which content will be updated (parent of parent of form) | | _____________________ _______ _____________________________________ | | | div (parent of form)| | div | | div for users | | | | _________________ | | for | | ______ ______ ______ ______ | | | | | this form | | | num. | | | | | | | | | form | | | | | | _____________ | | | of | | | user | | user | | user | | to | | | | | | | | | | | users | | | 1 | | 2 | | 3 | | show | | | | | | |_____________| | | | | | | | | | | | | all | | | | | |_________________| | | | | |______| |______| |______| |______| | | | |_____________________| |_______| |_____________________________________| | |___________________________________________________________________________| typedef enum { Tml_Usr_SHOW_FEW_USRS, // Show a few first favers/sharers Tml_Usr_SHOW_ALL_USRS, // Show all favers/sharers } Tml_Usr_HowManyUsrs_t;
  • 120. Timeline: Layout ● Favourite <div class="Tml_BOTTOM_RIGHT Tml_RIGHT_WIDTH"> <div class="Tml_FOOT Tml_RIGHT_WIDTH"> <div id="fav_not_..." class="Tml_FAV_NOT Tml_FAV_NOT_WIDTH"> <div class="Tml_ICO"> <form method="post" action="https://openswad.org/en" id="form_..." onsubmit="updateDivFaversSharers (this,'act=1512" "&amp;ses=session&amp;NotCod=note-code');" "return false;" ...> <input type="image" src="...fav-icon.svg" alt="Fav" title="Fav" class="CONTEXT_OPT ICO_HIGHLIGHT CONTEXT_ICO_16x16"> </form> </div> <div class="Tml_NUM_USRS">&nbsp;0</div> <div class="Tml_USRS"></div> </div>
  • 121. Timeline: Layout ● Share <div id="sha_not_..." class="Tml_SHA_NOT Tml_SHA_NOT_WIDTH"> <div class="Tml_ICO"> <form method="post" action="https://openswad.org/en" id="form_..." onsubmit="updateDivFaversSharers (this,'act=1495" "&amp;ses=session&amp;NotCod=note-code');" "return false;" ...> <input type="image" src="...share-icon.svg" alt="Share" title="Share" class="CONTEXT_OPT ICO_HIGHLIGHT CONTEXT_ICO_16x16"> </form> </div> <div class="Tml_NUM_USRS">&nbsp;0</div> <div class="Tml_USRS"></div> </div>
  • 122. Timeline: Layout ● Show all users <div id="fav_not_..." class="Tml_FAV_NOT Tml_FAV_NOT_WIDTH"> <div class="Tml_ICO">fav icon</div> <div class="Tml_NUM_USRS">number of users</div> <div class="Tml_USRS"> <div class="Tml_SHARER">user</div> ... <div class="Tml_SHARER">user</div> <form method="post" action="https://openswad.org/en" id="form_..." onsubmit="updateDivFaversSharers (this,'act=1767" "&amp;ses=session&amp;NotCod=note-code');" " return false;" ...> <input type="image" src="...ellipsis-h.svg" alt="View all" title="View all" class="CONTEXT_OPT ICO_HIGHLIGHT CONTEXT_ICO_16x16"> </form> </div> </div>
  • 123. Timeline: Layout function updateDivFaversSharers (form,Params) { var id = form.parentNode.parentNode.id; var objXMLHttp = AJAXCreateObject (); if (objXMLHttp) { /* Send request to server */ objXMLHttp.onreadystatechange = function () { if (objXMLHttp.readyState == 4) // Check if data have been received if (objXMLHttp.status == 200) if (id) { var div = document.getElementById (id); // Access to DIV if (div) div.innerHTML = objXMLHttp.responseText; // Update DIV content } }; objXMLHttp.open ('POST',actionAJAX,true); objXMLHttp.setRequestHeader ('Content-Type','application/x-www-form-urlencoded'); objXMLHttp.send (Params); } }
  • 124. Timeline: Layout ___________________________________________ | | | Top message: | > top message |___________________________________________| / | _____ | | | || | | Author's name | Date-time | | | ||Auth.| |______________________|___________| | | ||photo| | | | author's | ||_____| | | > name, time | | | Note | | and content | | | content | | | | | | | | | |__________________________________| / | | | | | | | | | Favs | Shared |Remove| | > note | |_____________|_____________|______| | | |________| | | | | | List | | buttons | | Comment| of | > and | | icon | comments | | comments | |________|__________________________________| | | | | | | | Form to write new comment | | | |__________________________________| / /
  • 125. Timeline: Layout ● Remove <div class="Tml_REM"> <form method="post" action="https://openswad.org/en" id="form_..." ...> <input type="hidden" name="act" value="1494"> <input type="hidden" name="ses" value="session"> <input type="hidden" name="Who" value="4"> <input type="hidden" name="NotCod" value="note-code"> <input type="image" src="remove-icon.svg" alt="Remove" title="Remove" class="CONTEXT_OPT ICO_HIGHLIGHT CONTEXT_ICO_16x16"> </form> </div> </div> </div>
  • 126. Timeline: Layout ___________________________________________ | | | Top message: | > top message |___________________________________________| / | _____ | | | || | | Author's name | Date-time | | | ||Auth.| |______________________|___________| | | ||photo| | | | author's | ||_____| | | > name, time | | | Note | | and content | | | content | | | | | | | | | |__________________________________| / | | | | | | | | | Favs | Shared |Remove| | > note | |_____________|_____________|______| | | |________| | | | | | List | | buttons | | Comment| of | > and | | icon | comments | | comments | |________|__________________________________| | | | | | | | Form to write new comment | | | |__________________________________| / /
  • 127. Timeline: Layout ● Comment icon <div class="Tml_BOTTOM_LEFT"> <div id="id_..._ico" class="Tml_ICO_COM_OFF"> <a href="" onclick="toggleNewComment ('id_...');return false;"> <img src="comment-icon.svg" alt="Comment" title="Comment" class="CONTEXT_ICO_16x16"> </a> </div> </div> function toggleNewComment (id) { var iconDiv = document.getElementById (id + '_ico'); iconDiv.className = (iconDiv.className == 'Tml_ICO_COM_OFF') ? 'Tml_ICO_COM_ON' :'Tml_ICO_COM_OFF'; toggleDisplay(id); } function toggleDisplay (elementID) { var element = document.getElementById (elementID); var stl; if (element) { stl = element.style; stl.display = (stl.display === 'none') ? '' : 'none'; } }
  • 128. Timeline: Layout ● New comment <div id="id_..." class="Tml_FORM_NEW_COM Tml_RIGHT_WIDTH" style=""> <div class="Tml_COM_PHOTO">...</div> <div class="Tml_COM_CONT Tml_COMM_WIDTH"> <form method="post" action="https://openswad.org/en" id="..." enctype="multipart/form-data" ...> <input type="hidden" name="act" value="1503"> <input type="hidden" name="ses" value="session"> <input type="hidden" name="Who" value="4"> <input type="hidden" name="NotCod" value="note code"> <textarea name="Txt" rows="6" maxlength="1000" placeholder="New comment…" class="Tml_COM_TEXTAREA Tml_COMM_WIDTH" onfocus="expandTextarea (this,'id_...','6');"> </textarea> <div id="id_..." style=""> <div class="HELP_EDIT">...</div> <div class="MED_UPLOADER">...</div> <button type="submit" class="BT_SUBMIT_INLINE BT_CREATE">Post</button> </div> </form> </div> </div> function expandTextarea (textareaElem,idButton,rows) { textareaElem.rows = rows; document.getElementById (idButton).style.display = ''; }
  • 129. Timeline: Layout ___________________________________________ | | | Top message: | > top message |___________________________________________| / | _____ | | | || | | Author's name | Date-time | | | ||Auth.| |______________________|___________| | | ||photo| | | | author's | ||_____| | | > name, time | | | Note | | and content | | | content | | | | | | | | | |__________________________________| / | | | | | | | | | Favs | Shared |Remove| | > note | |_____________|_____________|______| | | |________| | | | | | List | | buttons | | Comment| of | > and | | icon | comments | | comments | |________|__________________________________| | | | | | | | Form to write new comment | | | |__________________________________| / /
  • 130. Timeline: Layout ___________________________________________ | _____ | | | || | | Author's name | Date-time | | | ||Auth.| |______________________|___________| | | ||photo| | | | author's | ||_____| | | > name, time | | | Comment | | and content > comment | | content | | | | | | | | | |__________________________________| / | | | | | | | | Favs |Remove| > buttons | |________|___________________________|______| / / ● Layout and code similar to those described for the notes.
  • 131. Timeline: Layout Before clicking "See prev..." --> After clicking "See prev..." _________________________________ _________________________________ | div con_<id> | | div con_<id> | | (hidden) | | (visible) | | _____________________________ | | _____________________________ | | | v See only the latest | | | | v See only the latest | | | |_________(contract)__________| | | |_________(contract)__________| | |_________________________________| |_________________________________| _________________________________ _________________________________ | div <id> | | div <id> updated | | which content | | _____________________________ | | will be updated via AJAX | | | ul com_<id> | | | (parent of parent of form) | | | _________________________ | | | | | | | li (comment 1) | | | | | | | |_________________________| | | | | | | | ... | | | | | | | |_________________________| | | | | | | | li (comment n) | | | | | --> | | |_________________________| | | | | | |_____________________________| | | _____________________________ | | _____________________________ | | | div exp_<id> | | | | div exp_<id> | | | | (visible) | | | | (hidden) | | | | _________________________ | | | | | | | | | form | | | | | | | | | | _____________________ | | | | | _____________________ | | | | | | ^ See prev.comments | | | | | | | ^ See prev.comments | | | | | | |_______(expand)______| | | | | | |_______(expand)______| | | | | |_________________________| | | | | | | | |_____________________________| | | |_____________________________| | |_________________________________| |_________________________________| _________________________________ _________________________________ | ul | | ul | | _________________________ | | _________________________ | | | li (comment n+1) | | | | li (comment n+1) | | | |_________________________| | | |_________________________| | | | ... | | | | ... | | | |_________________________| | | |_________________________| | | | li (comment m) | | | | li (comment m) | | | |_________________________| | | |_________________________| | |_________________________________| |_________________________________| ● Only the last comments are displayed. ● Only the last comments are displayed.
  • 132. Timeline: Layout Before clicking "See prev..." --> After clicking "See prev..." _________________________________ _________________________________ | div con_<id> | | div con_<id> | | (hidden) | | (visible) | | _____________________________ | | _____________________________ | | | v See only the latest | | | | v See only the latest | | | |_________(contract)__________| | | |_________(contract)__________| | |_________________________________| |_________________________________| _________________________________ _________________________________ | div <id> | | div <id> updated | | which content | | _____________________________ | | will be updated via AJAX | | | ul com_<id> | | | (parent of parent of form) | | | _________________________ | | | | | | | li (comment 1) | | | | | | | |_________________________| | | | | | | | ... | | | | | | | |_________________________| | | | | | | | li (comment n) | | | | | --> | | |_________________________| | | | | | |_____________________________| | | _____________________________ | | _____________________________ | | | div exp_<id> | | | | div exp_<id> | | | | (visible) | | | | (hidden) | | | | _________________________ | | | | | | | | | form | | | | | | | | | | _____________________ | | | | | _____________________ | | | | | | ^ See prev.comments | | | | | | | ^ See prev.comments | | | | | | |_______(expand)______| | | | | | |_______(expand)______| | | | | |_________________________| | | | | | | | |_____________________________| | | |_____________________________| | |_________________________________| |_________________________________| _________________________________ _________________________________ | ul | | ul | | _________________________ | | _________________________ | | | li (comment n+1) | | | | li (comment n+1) | | | |_________________________| | | |_________________________| | | | ... | | | | ... | | | |_________________________| | | |_________________________| | | | li (comment m) | | | | li (comment m) | | | |_________________________| | | |_________________________| | |_________________________________| |_________________________________| ● Only the last comments are displayed. ● You can click on "See previous". ● Only the last comments are displayed. ● You can click on "See previous".
  • 133. Timeline: Layout Before clicking "See prev..." --> After clicking "See prev..." _________________________________ _________________________________ | div con_<id> | | div con_<id> | | (hidden) | | (visible) | | _____________________________ | | _____________________________ | | | v See only the latest | | | | v See only the latest | | | |_________(contract)__________| | | |_________(contract)__________| | |_________________________________| |_________________________________| _________________________________ _________________________________ | div <id> | | div <id> updated | | which content | | _____________________________ | | will be updated via AJAX | | | ul com_<id> | | | (parent of parent of form) | | | _________________________ | | | | | | | li (comment 1) | | | | | | | |_________________________| | | | | | | | ... | | | | | | | |_________________________| | | | | | | | li (comment n) | | | | | --> | | |_________________________| | | | | | |_____________________________| | | _____________________________ | | _____________________________ | | | div exp_<id> | | | | div exp_<id> | | | | (visible) | | | | (hidden) | | | | _________________________ | | | | | | | | | form | | | | | | | | | | _____________________ | | | | | _____________________ | | | | | | ^ See prev.comments | | | | | | | ^ See prev.comments | | | | | | |_______(expand)______| | | | | | |_______(expand)______| | | | | |_________________________| | | | | | | | |_____________________________| | | |_____________________________| | |_________________________________| |_________________________________| _________________________________ _________________________________ | ul | | ul | | _________________________ | | _________________________ | | | li (comment n+1) | | | | li (comment n+1) | | | |_________________________| | | |_________________________| | | | ... | | | | ... | | | |_________________________| | | |_________________________| | | | li (comment m) | | | | li (comment m) | | | |_________________________| | | |_________________________| | |_________________________________| |_________________________________| ● Only the last comments are displayed. ● You can click on "See previous". ● Previous comments are retrieved via AJAX. ● Only the last comments are displayed. ● You can click on "See previous". ● Previous comments are retrieved via AJAX.
  • 134. Timeline: Layout Before clicking "See prev..." --> After clicking "See prev..." _________________________________ _________________________________ | div con_<id> | | div con_<id> | | (hidden) | | (visible) | | _____________________________ | | _____________________________ | | | v See only the latest | | | | v See only the latest | | | |_________(contract)__________| | | |_________(contract)__________| | |_________________________________| |_________________________________| _________________________________ _________________________________ | div <id> | | div <id> updated | | which content | | _____________________________ | | will be updated via AJAX | | | ul com_<id> | | | (parent of parent of form) | | | _________________________ | | | | | | | li (comment 1) | | | | | | | |_________________________| | | | | | | | ... | | | | | | | |_________________________| | | | | | | | li (comment n) | | | | | --> | | |_________________________| | | | | | |_____________________________| | | _____________________________ | | _____________________________ | | | div exp_<id> | | | | div exp_<id> | | | | (visible) | | | | (hidden) | | | | _________________________ | | | | | | | | | form | | | | | | | | | | _____________________ | | | | | _____________________ | | | | | | ^ See prev.comments | | | | | | | ^ See prev.comments | | | | | | |_______(expand)______| | | | | | |_______(expand)______| | | | | |_________________________| | | | | | | | |_____________________________| | | |_____________________________| | |_________________________________| |_________________________________| _________________________________ _________________________________ | ul | | ul | | _________________________ | | _________________________ | | | li (comment n+1) | | | | li (comment n+1) | | | |_________________________| | | |_________________________| | | | ... | | | | ... | | | |_________________________| | | |_________________________| | | | li (comment m) | | | | li (comment m) | | | |_________________________| | | |_________________________| | |_________________________________| |_________________________________| ● Only the last comments are displayed. ● You can click on "See previous". ● Previous comments are retrieved via AJAX. ● "See previous" is hidden. ● Only the last comments are displayed. ● You can click on "See previous". ● Previous comments are retrieved via AJAX. ● "See previous" is hidden.
  • 135. Timeline: Layout Before clicking "See prev..." --> After clicking "See prev..." _________________________________ _________________________________ | div con_<id> | | div con_<id> | | (hidden) | | (visible) | | _____________________________ | | _____________________________ | | | v See only the latest | | | | v See only the latest | | | |_________(contract)__________| | | |_________(contract)__________| | |_________________________________| |_________________________________| _________________________________ _________________________________ | div <id> | | div <id> updated | | which content | | _____________________________ | | will be updated via AJAX | | | ul com_<id> | | | (parent of parent of form) | | | _________________________ | | | | | | | li (comment 1) | | | | | | | |_________________________| | | | | | | | ... | | | | | | | |_________________________| | | | | | | | li (comment n) | | | | | --> | | |_________________________| | | | | | |_____________________________| | | _____________________________ | | _____________________________ | | | div exp_<id> | | | | div exp_<id> | | | | (visible) | | | | (hidden) | | | | _________________________ | | | | | | | | | form | | | | | | | | | | _____________________ | | | | | _____________________ | | | | | | ^ See prev.comments | | | | | | | ^ See prev.comments | | | | | | |_______(expand)______| | | | | | |_______(expand)______| | | | | |_________________________| | | | | | | | |_____________________________| | | |_____________________________| | |_________________________________| |_________________________________| _________________________________ _________________________________ | ul | | ul | | _________________________ | | _________________________ | | | li (comment n+1) | | | | li (comment n+1) | | | |_________________________| | | |_________________________| | | | ... | | | | ... | | | |_________________________| | | |_________________________| | | | li (comment m) | | | | li (comment m) | | | |_________________________| | | |_________________________| | |_________________________________| |_________________________________| ● Only the last comments are displayed. ● You can click on "See previous". ● Previous comments are retrieved via AJAX. ● "See previous" is hidden. ● "See only the last" is unhidden. ● Only the last comments are displayed. ● You can click on "See previous". ● Previous comments are retrieved via AJAX. ● "See previous" is hidden. ● "See only the last" is unhidden.
  • 136. Timeline: Layout Before clicking "See prev..." --> After clicking "See prev..." _________________________________ _________________________________ | div con_<id> | | div con_<id> | | (hidden) | | (visible) | | _____________________________ | | _____________________________ | | | v See only the latest | | | | v See only the latest | | | |_________(contract)__________| | | |_________(contract)__________| | |_________________________________| |_________________________________| _________________________________ _________________________________ | div <id> | | div <id> updated | | which content | | _____________________________ | | will be updated via AJAX | | | ul com_<id> | | | (parent of parent of form) | | | _________________________ | | | | | | | li (comment 1) | | | | | | | |_________________________| | | | | | | | ... | | | | | | | |_________________________| | | | | | | | li (comment n) | | | | | --> | | |_________________________| | | | | | |_____________________________| | | _____________________________ | | _____________________________ | | | div exp_<id> | | | | div exp_<id> | | | | (visible) | | | | (hidden) | | | | _________________________ | | | | | | | | | form | | | | | | | | | | _____________________ | | | | | _____________________ | | | | | | ^ See prev.comments | | | | | | | ^ See prev.comments | | | | | | |_______(expand)______| | | | | | |_______(expand)______| | | | | |_________________________| | | | | | | | |_____________________________| | | |_____________________________| | |_________________________________| |_________________________________| _________________________________ _________________________________ | ul | | ul | | _________________________ | | _________________________ | | | li (comment n+1) | | | | li (comment n+1) | | | |_________________________| | | |_________________________| | | | ... | | | | ... | | | |_________________________| | | |_________________________| | | | li (comment m) | | | | li (comment m) | | | |_________________________| | | |_________________________| | |_________________________________| |_________________________________| ● Only the last comments are displayed. ● You can click on "See previous". ● Previous comments are retrieved via AJAX. ● "See previous" is hidden. ● "See only the last" is unhidden. ● From now on no AJAX is needed, sections are hidden / unhidden using JavaScript. ● Only the last comments are displayed. ● You can click on "See previous". ● Previous comments are retrieved via AJAX. ● "See previous" is hidden. ● "See only the last" is unhidden. ● From now on no AJAX is needed, sections are hidden / unhidden using JavaScript.
  • 137. Timeline: Layout <div class="MED_UPLOADER"> <div id="id_..._med_ico"> <a href="" onclick="mediaActivateMediaUploader('id_...');" "return false;"> <img src="...paperclip.svg" alt="Multimedia" title="Multimedia" class="ICO_HIGHLIGHT ICOx16"> </a> </div> <div id="id_..._med_upl" style="display:none;"> <div class="FRAME_CONT"> <div class="FRAME"> <div class="FRAME_ICO"> <div class="FRAME_ICO_RIGHT"> help-link </div> </div> <div class="FRAME_TITLE FRAME_TITLE_SMALL"> Multimedia </div> <input type="hidden" name="MedAct" value="2"> _container_____________________________________________ | _<id>_med_ico | | |____Clip_____| | | | | _container <id>_med_upl_(initially hidden)_________ | | | _box___________________________________________ | | | | | ? | | | | | | Multimedia | | | | | | | | | | | | _prefs_container___________________ | | | | | | | _pref_container_________________ | | | | | | | | | _______ _______ _______ | | | | | | | | | | | Image/| |YouTube| | Embed | | | | | | | | | | | |_video_| |_______| |_______| | | | | | | | | | |_______________________________| | | | | | | | |___________________________________| | | | | | | _file_container____________________________ | | | | | | | ___________ | | | | | | | | |_Browse..._| No file selected. | | | | | | | |___________________________________________| | | | | | | _URL_container_____________________________ | | | | | | | _______________________________________ | | | | | | | | |_Link__________________________________| | | | | | | | |___________________________________________| | | | | | | _title_container___________________________ | | | | | | | _______________________________________ | | | | | | | | |_Title/attribution_____________________| | | | | | | | |___________________________________________| | | | | | |_______________________________________________| | | | |___________________________________________________| | |_______________________________________________________| function mediaActivateMediaUploader (id) { document.getElementById (id + '_med_ico').style.display = 'none'; document.getElementById (id + '_med_upl').style.display = ''; }
  • 138. Timeline: Layout <div class="PREF_CONTS"> <div class="PREF_CONT"> <div id="id_..._ico_upl" class="PREF_OFF"> <a href="" onclick="mediaClickOnActivateUpload('id_...');" "return false;"> <img src="...photo-video.svg" alt="Image/video" title="Image/video" class="ICO_HIGHLIGHT ICOx16"> </a> </div> <div id="id_..._ico_you" class="PREF_OFF"> <a href="" onclick="mediaClickOnActivateYoutube('id_...');" "return false;"> <img src="...youtube-brands.svg" alt="YouTube" title="YouTube" class="ICO_HIGHLIGHT ICOx16"> </a> </div> <div id="id_..._ico_emb" class="PREF_OFF"> <a href="" onclick="mediaClickOnActivateEmbed('id_...');" "return false;"> <img src="...code.svg" alt="Embed" title="Embed" class="ICO_HIGHLIGHT ICOx16"> </a> </div> </div> </div> _container_____________________________________________ | _<id>_med_ico | | |____Clip_____| | | | | _container <id>_med_upl_(initially hidden)_________ | | | _box___________________________________________ | | | | | ? | | | | | | Multimedia | | | | | | | | | | | | _prefs_container___________________ | | | | | | | _pref_container_________________ | | | | | | | | | _______ _______ _______ | | | | | | | | | | | Image/| |YouTube| | Embed | | | | | | | | | | | |_video_| |_______| |_______| | | | | | | | | | |_______________________________| | | | | | | | |___________________________________| | | | | | | _file_container____________________________ | | | | | | | ___________ | | | | | | | | |_Browse..._| No file selected. | | | | | | | |___________________________________________| | | | | | | _URL_container_____________________________ | | | | | | | _______________________________________ | | | | | | | | |_Link__________________________________| | | | | | | | |___________________________________________| | | | | | | _title_container___________________________ | | | | | | | _______________________________________ | | | | | | | | |_Title/attribution_____________________| | | | | | | | |___________________________________________| | | | | | |_______________________________________________| | | | |___________________________________________________| | |_______________________________________________________|
  • 139. _container_____________________________________________ | _<id>_med_ico | | |____Clip_____| | | | | _container <id>_med_upl_(initially hidden)_________ | | | _box___________________________________________ | | | | | ? | | | | | | Multimedia | | | | | | | | | | | | _prefs_container___________________ | | | | | | | _pref_container_________________ | | | | | | | | | _______ _______ _______ | | | | | | | | | | | Image/| |YouTube| | Embed | | | | | | | | | | | |_video_| |_______| |_______| | | | | | | | | | |_______________________________| | | | | | | | |___________________________________| | | | | | | _file_container____________________________ | | | | | | | ___________ | | | | | | | | |_Browse..._| No file selected. | | | | | | | |___________________________________________| | | | | | | _URL_container_____________________________ | | | | | | | _______________________________________ | | | | | | | | |_Link__________________________________| | | | | | | | |___________________________________________| | | | | | | _title_container___________________________ | | | | | | | _______________________________________ | | | | | | | | |_Title/attribution_____________________| | | | | | | | |___________________________________________| | | | | | |_______________________________________________| | | | |___________________________________________________| | |_______________________________________________________| Timeline: Layout <input type="hidden" id="id_..._par_upl" name="MedFrm" value="1" disabled> <input type="hidden" id="id_..._par_you" name="MedFrm" value="2" disabled> <input type="hidden" id="id_..._par_emb" name="MedFrm" value="3" disabled> <div> <input type="file" name="MedFil" accept="image/,video/" id="id_..._fil" class="Tml_MED_INPUT_WIDTH" style="display:none;" disabled> </div> <div> <input type="url" name="MedURL" maxlength="255" value="" id="id_..._url" class="Tml_MED_INPUT_WIDTH" placeholder="Link" style="display:none;" disabled> </div> <div> <input type="text" name="MedTit" maxlength="127" value="" id="id_..._tit" class="Tml_MED_INPUT_WIDTH" placeholder="Title/attribution" style="display:none;" disabled> </div> </div> </div> </div> </div> </div>
  • 140. Timeline: Layout _container_____________________________________________ | _<id>_med_ico | | |____Clip_____| | | | | _container <id>_med_upl_(initially hidden)_________ | | | _box___________________________________________ | | | | | ? | | | | | | Multimedia | | | | | | | | | | | | _prefs_container___________________ | | | | | | | _pref_container_________________ | | | | | | | | | _______ _______ _______ | | | | | | | | | | | Image/| |YouTube| | Embed | | | | | | | | | | | |_video_| |_______| |_______| | | | | | | | | | |_______________________________| | | | | | | | |___________________________________| | | | | | | _file_container____________________________ | | | | | | | ___________ | | | | | | | | |_Browse..._| No file selected. | | | | | | | |___________________________________________| | | | | | | _URL_container_____________________________ | | | | | | | _______________________________________ | | | | | | | | |_Link__________________________________| | | | | | | | |___________________________________________| | | | | | | _title_container___________________________ | | | | | | | _______________________________________ | | | | | | | | |_Title/attribution_____________________| | | | | | | | |___________________________________________| | | | | | |_______________________________________________| | | | |___________________________________________________| | |_______________________________________________________| function mediaClickOnActivateUpload (id) { var par_upl = document.getElementById (id + '_par_upl'); if (par_upl.disabled) { // Click on highlighted icon // par_upl already got var par_you = document.getElementById (id + '_par_you'); var par_emb = document.getElementById (id + '_par_emb'); var ico_upl = document.getElementById (id + '_ico_upl'); var ico_you = document.getElementById (id + '_ico_you'); var ico_emb = document.getElementById (id + '_ico_emb'); var fil = document.getElementById (id + '_fil'); var url = document.getElementById (id + '_url'); var tit = document.getElementById (id + '_tit'); // Enable upload, disable others par_upl.disabled = false; // Enable upload par_you.disabled = true; // Disable youtube par_emb.disabled = true; // Disable embed ico_upl.className = 'PREF_ON'; // Highlighted upload icon ico_you.className = 'PREF_OFF'; // Normal youtube icon ico_emb.className = 'PREF_OFF'; // Normal embed icon fil.style.display = ''; // Show file input fil.disabled = false; // Enable file input url.style.display = ''; // Show URL input url.disabled = false; // Enable URL input tit.style.display = ''; // Show title input tit.disabled = false; // Enable title input } else // Click on shadowed icon mediaDisableAll (id); }
  • 141. Timeline: Inserting links “The C language combines all the power of assembly language with all the ease-of-use of assembly language.” Mark Pearce - Freelance consultant and developer Timeline: Inserting links “The C language combines all the power of assembly language with all the ease-of-use of assembly language.” Mark Pearce - Freelance consultant and developer
  • 142. Timeline: Inserting links ● 1. Parse string creating a list of links (URLs or nicknames) ● Hi @admin, can I use https://openswad.org for free? ______ ______ ______ ______ |______|<-- -->|______|<-- -->|______|<-- -->|______|<--- LastLink |______| / |______| / |______| / |______| |______| / |______| / |______| / |______| |_NULL_| / ---|_Prev_| / ---|_Prev_| / ---|_Prev_| |_Next_|-- |_Next_|-- |_Next_|-- |_NULL_| struct ALn_Link { ALn_LinkType_t Type; // URL or nickname? struct ALn_Substring URLorNick; // Link text struct ALn_Substring NickAnchor[3]; // Pointer to anchors if nick size_t LengthAddedUpToHere; // Total length of extra HTML code... // ...added up to this link (included) struct ALn_Link *Prev; // Pointer to previous link struct ALn_Link *Next; // Pointer to next link }; struct ALn_Substring { // Pointer to // the first // char of // substring char *Str; // Length of // the substring size_t Len; };
  • 143. Timeline: Inserting links ● 2. For each link in the list, going back from last to first: ● 1 Move forward the text after the link ● 2 Copy the 3rd part of the anchor ● 3 Move forward the link _______________________________ |H|i|_|@|a|d|m|i|n|,|_|c|a|n|...| | | | | | | | | | | | | | | | | | | | | | | | | ___________________________________________1____ | | | | | | ______________________________3____ | | | | | | | | | | | | | | | | | | ______5____ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 6 | | | | | | 4 | | | | | | 2 | | | | | | v v v anchor#1 v v v v v v anchor#2 v v v v v v anchor#3 v v v v v v ___________________________________________________________________________ |H|i|_|<|_|_|_|_|@|a|d|m|i|n|_|_|_|_|>|@|a|d|m|i|n|<|_|_|_|_|>|,|_|c|a|n|...| ● 4 Copy the 2nd part of the anchor ● 5 Copy the link into the anchor ● 6 Copy the 1st part of the anchor
  • 144. Future goals and tasks “The dream of yesterday is the hope of today and the reality of tomorrow.” Robert H. Goddard - Engineer, professor, physicist and inventor Future goals and tasks “The dream of yesterday is the hope of today and the reality of tomorrow.” Robert H. Goddard - Engineer, professor, physicist and inventor
  • 145. Future goals and tasks ● Objective 1: Incorporate new functionalities in the platform and improve some of the existing ones for its integration with gamification, geolocation and EDM Objective 1 tasks T1.1 Instructional design + planning T1.5 Improved test exams  T1.2 Monitoring + activity reports T1.6 Scanning homework with the mobile T1.3 Collaborative edition (wiki) T1.7 Integrated grades T1.4 Improved schedule + calendar T1.8 Enhanced forums + chat + messages
  • 146. Future goals and tasks ● Objective 2: Integration of gamification based on typical game elements in the functionalities of the web platform and the mobile app Objective 2 tasks T2.1 ARS integrated (interactive games with remote control)  T2.2 Scores + badges in global and course functionalities T2.3 Karma in timeline, forums and files T2.4 Progress bars in user profiles and courses
  • 147. Future goals and tasks ● Objective 3: Integration of indoor geolocation to improve the location of users in institutional dependencies and attendance control Objective 3 tasks T3.1 Database + location prototype  T3.5 Possible improvements • Alerts about friends that are close • Display location on map • QR to check-in • Store history for activity reports and recommendations T3.2 SWAD API functions  T3.3 Integration in SWADroid  T3.4 Add gamification
  • 148. Future goals and tasks ● Objective 4: Integrate Educational Data Mining techniques to improve student assessment, identify study tips, and offer alerts to students and teachers Objective 4 tasks T4.1 Study state of the art of EDM (lines of research, articles) T4.2 Study algorithms + software tools T4.3 Off-platform experiments (predict + recommend + alert) T4.4 Select algorithms and integrate them into the platform
  • 149. Future goals and tasks ● Objective 5: Analyze educational changes in motivation and participation, results, and degree of use and satisfaction after the improvements Objective 5 tasks T5.1 Interviews with users prior to the improvement T5.2 Acquire reference data prior to improvement T5.3 Measure indicators after improvement: performance, use, motivation ... T5.4 Disseminate partial and final results
  • 150. Conclusions “We are free, we can be wide open" “Analyse”, The Cranberries - Irish rock band Conclusions “We are free, we can be wide open" “Analyse”, The Cranberries - Irish rock band
  • 151. Conclusions ● We have developed and used an educational platform for 23 years at UGR (Spain) ● It’s a fast tool that consumes very few computing resources, making it suitable for low-cost installations
  • 152. Conclusions ● It had a great growth between 2005 and 2015 ● In 2015 it was almost used by the entire UGR (≈60K students) ● In total, it has been used by 200,000 users at UGR
  • 153. Conclusions ● Since 2010 it’s free software, so anyone can install it (and improve it) ● Since 2012 it is freely available in the cloud for everyone, in the portal OpenSWAD.org ● Of course, you can try it at https://openswad.org/
  • 154. Conclusions ● Since 2016 its use at UGR has decreased due to institutional support to another official platform ● However, we have continued working on the improvement of the platform ● We will continue its upgrade with gamification, geolocation and data mining, among other features
  • 155. About us “When they ask me when a program will be ready, I answer: it depends on how much you work on it.” Richard M. Stallman - Free software activist and programmer About us “When they ask me when a program will be ready, I answer: it depends on how much you work on it.” Richard M. Stallman - Free software activist and programmer
  • 156. About us ● Recent programmers: ● Antonio Cañas Vargas (swad-core, servers, management, courses) ● Daniel J. Calandria Hernández (photo processing, chat) ● Juan Miguel Boyero Corral (SWADroid) ● Bate Ye (iSWAD) ● Javier Bueno López (SWADroid) ● Adrián Lara Roldán (iSWAD) ● Jesús Mesa González (photo processing) ● Sergio Díaz Rueda (SWADroid) (green = free software)
  • 157. About us ● Former programmers (I): ● Jesús Álvarez Martín (photo processing) ● Alberto E. Rodrigo Gámiz (photo processing) ● Ana Belén Cara Carmona (chat & whiteboard) ● Carlos Moreno Muñoz (chat & whiteboard)
  • 158. About us ● Former programmers (II): ● Antonio Manuel Aguilera Malagón (SWADroid) ● Helena Rodríguez Gijón (SWADroid) ● José Antonio Guerrero Avilés (SWADroid) ● Alejandro Alcalde Barros (SWADroid) ● Rubén Martín Hidalgo (SWADroid) ● Miguel Ángel Cerrailo Valle (Triswados, app Android) ● Raúl Álvarez Hinojosa (iSWAD)
  • 159. About us ● Programmers of modules that were not used: ● Andrés Ramón Masegosa Aredondo (photo processing) ● Raúl Jiménez Benítez (chat) ● María Beatriz Medina Yáñez (whiteboard) ● Raquel Cazalilla Sáez (chat & whiteboard) ● Emiliano Luis Rincón Vallejos (rich text editor) ● Diego Montesinos Hervás (iSWAD) ● Lucas Ortiz Velasco (SWADMyPage) ● David Medina Godoy (SWADE, rich text editor) ● Marta Muñoz López (SWAD2Moodle)
  • 160. About us ● Translators: ● Antonio Cañas Vargas (CA,DE,EN,ES,FR,GN,IT,PL,PT) ● Joan Lluís Díaz Rodríguez (CA) ● Rafael Barranco Droege (DE) ● Giuseppe Antonio Pagin, Antonella Grande, Francisco Manuel Herrero Pérez, Nicola Comunale Rizzo (IT) ● Wojtek Kieca, Tomasz Olechowski, Mateusz Stanko (PL)
  • 161. About us ● Contributors (I): ● Javier Fernández Baldomero (forums, papers) ● Antonio F. Díaz García (servers) ● Eva Martínez Ortigosa (administration, papers) ● Francisco Illeras García (servers) ● Alberto Prieto Espinosa (papers) ● Mancia Anguita López (papers) ● Eduardo Ros Vidal (papers)
  • 162. About us ● Contributors (II): ● Francisco A. Ocaña Lara (FAQ, papers) ● Adrián Gómez Anaya (WikiSwad) ● Paloma Marín Arraiza (video tutorials) ● technicians and scholars from the Virtual Learning Center ● 150 degree administrators ● ...and many more