├── LICENSE.txt
├── README.md
├── client
└── main.go
├── config.json
├── config
└── config.go
├── db
├── files.go
├── tasks.go
└── user.go
├── files
└── README.md
├── install.sh
├── main.go
├── public
└── static
│ ├── css
│ ├── bootstrap-glyphicons.css
│ ├── bootstrap.min.css
│ ├── font-awesome.min.css
│ ├── jquery-ui.min.css
│ ├── sidebar-bootstrap.css
│ ├── sidebar.css
│ └── styles.css
│ ├── fonts
│ ├── glyphiconshalflings-regular.eot
│ ├── glyphiconshalflings-regular.otf
│ ├── glyphiconshalflings-regular.svg
│ ├── glyphiconshalflings-regular.ttf
│ └── glyphiconshalflings-regular.woff
│ └── js
│ ├── app.js
│ ├── bootstrap.min.js
│ ├── hammer.min.js
│ ├── jquery-ui.min.js
│ ├── jquery.min.js
│ ├── script.js
│ ├── sidebar.js
│ ├── vue-resource.js
│ ├── vue-router.js
│ └── vue.js
├── schema.sql
├── sessions
└── sessions.go
├── templates
├── _foot.html
├── _head.html
└── tasks.html
├── types
└── types.go
├── utils
└── utils.go
└── views
├── api.go
├── api_sessions.go
└── views.go
/LICENSE.txt:
--------------------------------------------------------------------------------
1 |
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2015 Suraj Patil
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
7 |
8 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
9 |
10 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
11 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Tasks
2 |
3 | Tasks is a simplistic Go webapp to manage tasks, I built this tool to manage tasks which I wanted to do, there are many good kanban style boards, but I felt they were a bit too heavyweight for my taste. Also I wanted to learn the Go webapp development.
4 |
5 | How to use?
6 | ==================
7 | Via script: `bash install.sh`
8 |
9 | This will generate the binary and set up the database. If you want, you can copy the binary and the public folder into a folder of your choice.
10 |
11 | Manually:
12 |
13 | 1. `go get github.com/thewhitetulip/Tasks`
14 | 1. change dir to the respective folder and create the db file: `cat schema.sql | sqlite3 tasks.db`
15 | 1. run `go build`
16 | 1. `./Tasks`
17 | 1. open [localhost:8081](http://localhost:8081)
18 |
19 | You can change the port in the [config](https://github.com/thewhitetulip/Tasks/blob/master/config.json) file
20 |
21 | ##Features
22 |
23 | 1. Add, update, delete task.
24 | 2. Search tasks, the query is highlighted in the search results page.
25 | 3. Github flavoured markdown, which enables us for using a task list, advanced syntax highlighting and much more.
26 | 4. Supports file upload, randomizes the file name, stores the user given filename in a db and works on the randomized file name for security reasons.
27 | 5. Priorities are assigned, High = 3, medium = 2 and low = 1, sorting is done on priority descending and created date ascending.
28 | 6. Categories are supported, you can add tasks to different categories.
29 | 1. Ability to hide a task from the timeline.
30 | 1. For a task list, shows 6 out of 8 tasks completed.
31 | 1. Single click install, just run the install.sh file.
32 |
33 |
34 | ##### Book
35 | I am learning writing webapps with Go as I build this application, I took to writing an introductory book about [building webapps in Go](https://github.com/thewhitetulip/web-dev-golang-anti-textbook) because I faced a lot of problems while learning how to write webapps in Go, it, the book strives to teach by practical examples. You are welcome to contribute to the book.
36 |
37 | #Screenshots
38 | The Home Page
39 |
40 | 
41 |
42 | Add Task dialog
43 |
44 | 
45 |
46 | Navigation drawer
47 |
48 | 
49 |
50 | #License
51 |
52 | The MIT License (MIT)
53 |
54 | Copyright (c) 2015 Suraj Patil
55 |
56 | Permission is hereby granted, free of charge, to any person obtaining a copy
57 | of this software and associated documentation files (the "Software"), to deal
58 | in the Software without restriction, including without limitation the rights
59 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
60 | copies of the Software, and to permit persons to whom the Software is
61 | furnished to do so, subject to the following conditions:
62 |
63 | The above copyright notice and this permission notice shall be included in all
64 | copies or substantial portions of the Software.
65 |
66 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
67 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
68 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
69 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
70 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
71 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
72 | SOFTWARE.
73 |
--------------------------------------------------------------------------------
/client/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "io/ioutil"
7 | "net/http"
8 | "net/url"
9 | "os"
10 |
11 | "github.com/thewhitetulip/Tasks-vue/types"
12 | )
13 |
14 | func main() {
15 | baseURL := "http://127.0.0.1:8080/"
16 |
17 | usernamePwd := url.Values{}
18 | usernamePwd.Set("username", "suraj")
19 | usernamePwd.Set("password", "suraj")
20 |
21 | resp, err := http.PostForm(baseURL+"api/get-token/", usernamePwd)
22 | if err != nil {
23 | fmt.Println("Is the server running?")
24 | os.Exit(1)
25 | } else {
26 | fmt.Println("response received")
27 | }
28 |
29 | defer resp.Body.Close()
30 | body, err := ioutil.ReadAll(resp.Body)
31 | if err != nil {
32 | fmt.Println("Error reading body")
33 | } else {
34 | fmt.Println("Token received")
35 | }
36 | token := string(body)
37 |
38 | client := &http.Client{}
39 | req, err := http.NewRequest("GET", baseURL+"api/get-task/", nil)
40 |
41 | if err != nil {
42 | fmt.Println("Unable to form a GET /api/get-task/")
43 | }
44 |
45 | req.Header.Add("Token", token)
46 | resp, err = client.Do(req)
47 |
48 | if (err != nil) || (resp.StatusCode != 200) {
49 | fmt.Println("Something went wrong in the getting a response")
50 | }
51 |
52 | defer resp.Body.Close()
53 | body, err = ioutil.ReadAll(resp.Body)
54 | fmt.Println(string(body))
55 |
56 | var context types.Tasks
57 |
58 | if err := json.Unmarshal(body, &context); err != nil {
59 | panic(err)
60 | }
61 |
62 | fmt.Println(context)
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "ServerPort": ":9081"
3 | }
4 |
--------------------------------------------------------------------------------
/config/config.go:
--------------------------------------------------------------------------------
1 | /*
2 | Configuration package is used to read the configuration file
3 | config.json which stores the server port for current implementation
4 | {
5 | "ServerPort": ":8081"
6 | }
7 | */
8 | package config
9 |
10 | import (
11 | "encoding/json"
12 | "io/ioutil"
13 | "log"
14 | )
15 |
16 | //Configuration Stores the main configuration for the application
17 | type Configuration struct {
18 | ServerPort string
19 | }
20 |
21 | var err error
22 | var config Configuration
23 |
24 | //ReadConfig will read the configuration json file to read the parameters
25 | //which will be passed in the config file
26 | func ReadConfig(fileName string) (Configuration, error) {
27 | configFile, err := ioutil.ReadFile(fileName)
28 | if err != nil {
29 | log.Print("Unable to read config file, switching to flag mode")
30 | return Configuration{}, err
31 | }
32 | //log.Print(configFile)
33 | err = json.Unmarshal(configFile, &config)
34 | if err != nil {
35 | log.Print("Invalid JSON, expecting port from command line flag")
36 | return Configuration{}, err
37 | }
38 | return config, nil
39 | }
40 |
--------------------------------------------------------------------------------
/db/files.go:
--------------------------------------------------------------------------------
1 | package db
2 |
3 | /*
4 | stores the functions related to file IO and category
5 | */
6 | import (
7 | "log"
8 |
9 | "github.com/thewhitetulip/Tasks-vue/types"
10 | )
11 |
12 | // AddFile is used to add the md5 of a file name which is uploaded to our application
13 | // this will enable us to randomize the URL without worrying about the file names
14 | func AddFile(fileName, token, username string) error {
15 | userID, err := GetUserID(username)
16 | if err != nil {
17 | return err
18 | }
19 | err = taskQuery("insert into files values(?,?,?,datetime())", fileName, token, userID)
20 | return err
21 | }
22 |
23 | // GetFileName is used to fetch the name according to the md5 checksum from the db
24 | func GetFileName(token string) (string, error) {
25 | sql := "select name from files where autoName=?"
26 | var fileName string
27 | rows := database.query(sql, fileName)
28 | defer rows.Close()
29 | if rows.Next() {
30 | err := rows.Scan(&fileName)
31 | if err != nil {
32 | log.Println(err)
33 | return "", err
34 | }
35 | }
36 | if err != nil {
37 | return "", err
38 | }
39 |
40 | return fileName, nil
41 | }
42 |
43 | //GetCategories will return the list of categories to be
44 | //rendered in the template
45 | func GetCategories(username string) ([]types.Category, error) {
46 | var categories []types.Category
47 | var category types.Category
48 |
49 | userID, err := GetUserID(username)
50 | if err != nil {
51 | return categories, nil
52 | }
53 | stmt := "select c.id, c.name, count(*) from category c left outer join task t join status s on c.id = t.cat_id and t.task_status_id=s.id where s.status='PENDING' and c.user_id=? group by name union select c.id, name, 0 from category c, user u where c.user_id=? and name not in (select distinct name from task t join category c join status s on s.id = t.task_status_id and t.cat_id = c.id and s.status='PENDING' and c.user_id=?)"
54 | rows := database.query(stmt, userID, userID, userID)
55 |
56 | defer rows.Close()
57 | for rows.Next() {
58 | err := rows.Scan(&category.ID, &category.Name, &category.TaskCount)
59 | if err != nil {
60 | return categories, err
61 | }
62 | categories = append(categories, category)
63 | }
64 | return categories, nil
65 | }
66 |
67 | //AddCategory is used to add the task in the database
68 | func AddCategory(username, category string) error {
69 | userID, err := GetUserID(username)
70 | if err != nil {
71 | return nil
72 | }
73 | log.Println("executing query to add category")
74 | err = taskQuery("insert into category(name, user_id) values(?,?)", category, userID)
75 | return err
76 | }
77 |
78 | // GetCategoryByName will return the ID of that category passed as args
79 | // used while inserting tasks into the table
80 | func GetCategoryByName(username, category string) int {
81 | stmt := "select id from category where name=? and user_id = (select id from user where username=?)"
82 | rows := database.query(stmt, category, username)
83 | var categoryID int
84 | defer rows.Close()
85 | for rows.Next() {
86 | err := rows.Scan(&categoryID)
87 | if err != nil {
88 | log.Println(err)
89 | }
90 | }
91 | return categoryID
92 | }
93 |
94 | //DeleteCategoryByName will be used to delete a category from the category page
95 | func DeleteCategoryByName(username, category string) error {
96 | //first we delete entries from task and then from category
97 | categoryID := GetCategoryByName(username, category)
98 | userID, err := GetUserID(username)
99 | if err != nil {
100 | return err
101 | }
102 | query := "update task set cat_id = null where id =? and user_id = ?"
103 | err = taskQuery(query, categoryID, userID)
104 | if err == nil {
105 | err = taskQuery("delete from category where id=? and user_id=?", categoryID, userID)
106 | if err != nil {
107 | return err
108 | }
109 | }
110 | return err
111 | }
112 |
113 | //UpdateCategoryByName will be used to delete a category from the category page
114 | func UpdateCategoryByName(username, oldName, newName string) error {
115 | userID, err := GetUserID(username)
116 | if err != nil {
117 | return err
118 | }
119 | query := "update category set name = ? where name=? and user_id=?"
120 | log.Println(query)
121 | err = taskQuery(query, newName, oldName, userID)
122 | return err
123 | }
124 |
125 | //DeleteCommentByID will actually delete the comment from db
126 | func DeleteCommentByID(username string, id int) error {
127 | userID, err := GetUserID(username)
128 | if err != nil {
129 | return err
130 | }
131 | query := "delete from comments where id=? and user_id = ?"
132 | err = taskQuery(query, id, userID)
133 | return err
134 | }
135 |
--------------------------------------------------------------------------------
/db/tasks.go:
--------------------------------------------------------------------------------
1 | package db
2 |
3 | /*
4 | Stores the database functions related to tasks like
5 | GetTaskByID(id int)
6 | GetTasks(status string)
7 | DeleteAll()
8 | */
9 |
10 | import (
11 | "database/sql"
12 | "log"
13 | "strconv"
14 | "strings"
15 | "time"
16 |
17 | _ "github.com/mattn/go-sqlite3" //we want to use sqlite natively
18 | "github.com/thewhitetulip/Tasks-vue/types"
19 | )
20 |
21 | var database Database
22 | var taskStatus map[string]int
23 | var err error
24 |
25 | //Database encapsulates database
26 | type Database struct {
27 | db *sql.DB
28 | }
29 |
30 | //Begins a transaction
31 | func (db Database) begin() (tx *sql.Tx) {
32 | tx, err := db.db.Begin()
33 | if err != nil {
34 | log.Println(err)
35 | return nil
36 | }
37 | return tx
38 | }
39 |
40 | func (db Database) prepare(q string) (stmt *sql.Stmt) {
41 | stmt, err := db.db.Prepare(q)
42 | if err != nil {
43 | log.Println(err)
44 | return nil
45 | }
46 | return stmt
47 | }
48 |
49 | func (db Database) query(q string, args ...interface{}) (rows *sql.Rows) {
50 | rows, err := db.db.Query(q, args...)
51 | if err != nil {
52 | log.Println(err)
53 | return nil
54 | }
55 | return rows
56 | }
57 |
58 | func init() {
59 | database.db, err = sql.Open("sqlite3", "./tasks.db")
60 | taskStatus = map[string]int{"COMPLETE": 1, "PENDING": 2, "DELETED": 3}
61 | if err != nil {
62 | log.Fatal(err)
63 | }
64 | }
65 |
66 | //Close function closes this database connection
67 | func Close() {
68 | database.db.Close()
69 | }
70 |
71 | //GetTasks retrieves all the tasks depending on the
72 | //status pending or trashed or completed
73 | func GetTasks(username, status, category string) (types.Context, error) {
74 | log.Println("getting tasks for ", status)
75 | var tasks []types.Task
76 | var task types.Task
77 | var TaskCreated time.Time
78 | var context types.Context
79 | var getTaskSQL string
80 | var rows *sql.Rows
81 |
82 | comments, err := GetComments(username)
83 |
84 | if err != nil {
85 | return context, err
86 | }
87 |
88 | basicSQL := "select t.id, title, content, created_date, priority, case when c.name is null then 'NA' else c.name end from task t, status s, user u left outer join category c on c.id=t.cat_id where u.username=? and s.id=t.task_status_id and u.id=t.user_id "
89 | if category == "" {
90 | switch status {
91 | case "pending":
92 | getTaskSQL = basicSQL + " and s.status='PENDING' and t.hide!=1"
93 | case "deleted":
94 | getTaskSQL = basicSQL + " and s.status='DELETED' and t.hide!=1"
95 | case "completed":
96 | getTaskSQL = basicSQL + " and s.status='COMPLETE' and t.hide!=1"
97 | }
98 |
99 | getTaskSQL += " order by t.created_date asc"
100 |
101 | rows = database.query(getTaskSQL, username, username)
102 | } else {
103 | status = category
104 | //This is a special case for showing tasks with null categories, we do a union query
105 | if category == "UNCATEGORIZED" {
106 | getTaskSQL = "select t.id, title, content, created_date, priority, 'UNCATEGORIZED' from task t, status s, user u where u.username=? and s.id=t.task_status_id and u.id=t.user_id and t.cat_id=0 and s.status='PENDING' order by priority desc, created_date asc, finish_date asc"
107 | rows, err = database.db.Query(getTaskSQL, username)
108 | } else {
109 | getTaskSQL = basicSQL + " and name = ? and s.status='PENDING' order by priority desc, created_date asc, finish_date asc"
110 | rows, err = database.db.Query(getTaskSQL, username, category)
111 | }
112 |
113 | if err != nil {
114 | log.Println("tasks.go: something went wrong while getting query fetch tasks by category")
115 | }
116 | }
117 |
118 | defer rows.Close()
119 | for rows.Next() {
120 | task = types.Task{}
121 |
122 | err = rows.Scan(&task.Id, &task.Title, &task.Content, &TaskCreated, &task.Priority, &task.Category)
123 |
124 | taskCompleted := 0
125 | totalTasks := 0
126 |
127 | if strings.HasPrefix(task.Content, "- [") {
128 | for _, value := range strings.Split(task.Content, "\n") {
129 | if strings.HasPrefix(value, "- [x]") {
130 | taskCompleted += 1
131 | }
132 | totalTasks += 1
133 | }
134 | task.CompletedMsg = strconv.Itoa(taskCompleted) + " complete out of " + strconv.Itoa(totalTasks)
135 | }
136 |
137 | // TaskContent = strings.Replace(TaskContent, "\n", "
", -1)
138 | if err != nil {
139 | log.Println(err)
140 | }
141 |
142 | if comments[task.Id] != nil {
143 | task.Comments = comments[task.Id]
144 | }
145 |
146 | TaskCreated = TaskCreated.Local()
147 | // if task.Priority != "1" { // if priority is not 1 then calculate, else why bother?
148 | // CurrentTime := time.Now().Local()
149 | // diff := CurrentTime.Sub(TaskCreated).Hours()
150 | // if diff > 168 {
151 | // task.IsOverdue = true // If one week then overdue by default
152 | // }
153 | // }
154 | task.Created = TaskCreated.Format("Jan 2 2006")
155 |
156 | tasks = append(tasks, task)
157 | }
158 | context = types.Context{Tasks: tasks, Navigation: status}
159 | return context, nil
160 | }
161 |
162 | //GetTaskByID function gets the tasks from the ID passed to the function, used to populate EditTask
163 | func GetTaskByID(username string, id int) (types.Context, error) {
164 | var tasks []types.Task
165 | var task types.Task
166 |
167 | getTaskSQL := "select t.id, t.title, t.content, t.priority, t.hide, c.name from task t join user u left outer join category c where c.id = t.cat_id and t.user_id=u.id and t.id=? and u.username=? union select t.id, t.title, t.content, t.priority, t.hide, 'UNCATEGORIZED' from task t join user u where t.user_id=u.id and t.cat_id=0 ;"
168 |
169 | rows := database.query(getTaskSQL, id, username)
170 | defer rows.Close()
171 | if rows.Next() {
172 | err := rows.Scan(&task.Id, &task.Title, &task.Content, &task.Priority, &task.IsHidden, &task.Category)
173 | if err != nil {
174 | log.Println(err)
175 | //send email to respective people
176 | }
177 | }
178 | tasks = append(tasks, task)
179 | context := types.Context{Tasks: tasks, Navigation: "edit"}
180 | return context, nil
181 | }
182 |
183 | //TrashTask is used to delete the task
184 | func TrashTask(username string, id int) error {
185 | err := taskQuery("update task set task_status_id=?,last_modified_at=datetime() where user_id=(select id from user where username=?) and id=?", taskStatus["DELETED"], username, id)
186 | return err
187 | }
188 |
189 | //CompleteTask is used to mark tasks as complete
190 | func CompleteTask(username string, id int) error {
191 | err := taskQuery("update task set task_status_id=?, finish_date=datetime(),last_modified_at=datetime() where id=? and user_id=(select id from user where username=?) ", taskStatus["COMPLETE"], id, username)
192 | return err
193 | }
194 |
195 | //DeleteAll is used to empty the trash
196 | func DeleteAll(username string) error {
197 | err := taskQuery("delete from task where task_status_id=? where user_id=(select id from user where username=?)", taskStatus["DELETED"], username)
198 | return err
199 | }
200 |
201 | //RestoreTask is used to restore tasks from the Trash
202 | func RestoreTask(username string, id int) error {
203 | err := taskQuery("update task set task_status_id=?,last_modified_at=datetime(),finish_date=null where id=? and user_id=(select id from user where username=?)", taskStatus["PENDING"], id, username)
204 | return err
205 | }
206 |
207 | //RestoreTaskFromComplete is used to restore tasks from the Trash
208 | func RestoreTaskFromComplete(username string, id int) error {
209 | err := taskQuery("update task set finish_date=null,last_modified_at=datetime(), task_status_id=? where id=? and user_id=(select id from user where username=?)", taskStatus["PENDING"], id, username)
210 | return err
211 | }
212 |
213 | //DeleteTask is used to delete the task from the database
214 | func DeleteTask(username string, id int) error {
215 | err := taskQuery("delete from task where id = ? and user_id=(select id from user where username=?)", id, username)
216 | return err
217 | }
218 |
219 | //AddTask is used to add the task in the database
220 | //TODO: add dueDate feature later
221 | func AddTask(title, content, category string, taskPriority int, username string, hidden int) error {
222 | log.Println("AddTask: started function")
223 | var err error
224 | /*var timeDueDate time.Time
225 | if duedate != "" {
226 | timeDueDate, err = time.Parse("12/31/2016", duedate)
227 | if err != nil {
228 | log.Fatal(err)
229 | }
230 | }*/
231 | userID, err := GetUserID(username)
232 | if err != nil && (title != "" || content != "") {
233 | return err
234 | }
235 |
236 | if category == "" {
237 | err = taskQuery("insert into task(title, content, priority, task_status_id, created_date, last_modified_at, user_id,hide) values(?,?,?,?,datetime(), datetime(),?,?)", title, content, taskPriority, taskStatus["PENDING"], userID, hidden)
238 | } else {
239 | categoryID := GetCategoryByName(username, category)
240 | err = taskQuery("insert into task(title, content, priority, created_date, last_modified_at, cat_id, task_status_id, user_id,hide) values(?,?,?,datetime(), datetime(), ?,?,?,?)", title, content, taskPriority, categoryID, taskStatus["PENDING"], userID, hidden)
241 | }
242 | return err
243 | }
244 |
245 | //GetCategoryIDByName will return the category ID for the category, used in the edit task
246 | //function where we need to be able to update the categoryID of the task
247 | func GetCategoryIDByName(username string, category string) int {
248 | var categoryID int
249 | getTaskSQL := "select c.id from category c , user u where u.id = c.user_id and name=? and u.username=?"
250 |
251 | rows := database.query(getTaskSQL, category, username)
252 | defer rows.Close()
253 | if rows.Next() {
254 | err := rows.Scan(&categoryID)
255 | if err != nil {
256 | log.Println(err)
257 | //send email to respective people
258 | }
259 | }
260 |
261 | return categoryID
262 | }
263 |
264 | //UpdateTask is used to update the tasks in the database
265 | func UpdateTask(id int, title, content, category string, priority int, username string, hidden int) error {
266 | categoryID := GetCategoryIDByName(username, category)
267 | userID, err := GetUserID(username)
268 | if err != nil {
269 | return err
270 | }
271 | err = taskQuery("update task set title=?, content=?, cat_id=?, priority = ? where id=? and user_id=?", title, content, categoryID, priority, id, userID)
272 | return err
273 | }
274 |
275 | //taskQuery encapsulates running multiple queries which don't do much things
276 | func taskQuery(sql string, args ...interface{}) error {
277 | log.Print("inside task query")
278 | SQL := database.prepare(sql)
279 | tx := database.begin()
280 | _, err = tx.Stmt(SQL).Exec(args...)
281 | if err != nil {
282 | log.Println("taskQuery: ", err)
283 | tx.Rollback()
284 | } else {
285 | err = tx.Commit()
286 | if err != nil {
287 | log.Println(err)
288 | return err
289 | }
290 | log.Println("Commit successful")
291 | }
292 | return err
293 | }
294 |
295 | //SearchTask is used to return the search results depending on the query
296 | func SearchTask(username, query string) (types.Context, error) {
297 | var tasks []types.Task
298 | var task types.Task
299 | var TaskCreated time.Time
300 | var context types.Context
301 |
302 | comments, err := GetComments(username)
303 | if err != nil {
304 | log.Println("SearchTask: something went wrong in finding comments")
305 | }
306 |
307 | userID, err := GetUserID(username)
308 | if err != nil {
309 | return context, err
310 | }
311 |
312 | stmt := "select t.id, title, content, created_date, priority, c.name from task t, category c where t.user_id=? and c.id = t.cat_id and (title like '%" + query + "%' or content like '%" + query + "%') order by created_date desc"
313 |
314 | rows := database.query(stmt, userID, query, query)
315 | defer rows.Close()
316 | for rows.Next() {
317 | err := rows.Scan(&task.Id, &task.Title, &task.Content, &TaskCreated, &task.Priority, &task.Category)
318 | if err != nil {
319 | log.Println(err)
320 | }
321 |
322 | if comments[task.Id] != nil {
323 | task.Comments = comments[task.Id]
324 | }
325 |
326 | task.Title = strings.Replace(task.Title, query, ""+query+"", -1)
327 | task.Content = strings.Replace(task.Content, query, ""+query+"", -1)
328 |
329 | TaskCreated = TaskCreated.Local()
330 | CurrentTime := time.Now().Local()
331 | week := TaskCreated.AddDate(0, 0, 7)
332 |
333 | if (week.String() < CurrentTime.String()) && (task.Priority != "1") {
334 | task.IsOverdue = true // If one week then overdue by default
335 | }
336 | task.Created = TaskCreated.Format("Jan 2 2006")
337 |
338 | tasks = append(tasks, task)
339 | }
340 | context = types.Context{Tasks: tasks, Search: query, Navigation: "search"}
341 | return context, nil
342 | }
343 |
344 | //GetComments is used to get comments, all of them.
345 | //We do not want 100 different pages to show tasks, we want to use as few pages as possible
346 | //so we are going to populate everything on the damn home pages
347 | func GetComments(username string) (map[int][]types.Comment, error) {
348 | commentMap := make(map[int][]types.Comment)
349 |
350 | var taskID int
351 | var comment types.Comment
352 | var created time.Time
353 |
354 | userID, err := GetUserID(username)
355 | if err != nil {
356 | return commentMap, err
357 | }
358 | stmt := "select c.id, c.taskID, c.content, c.created, u.username from comments c, task t, user u where t.id=c.taskID and c.user_id=t.user_id and t.user_id=u.id and u.id=?"
359 | rows := database.query(stmt, userID)
360 |
361 | defer rows.Close()
362 | for rows.Next() {
363 | err := rows.Scan(&comment.ID, &taskID, &comment.Content, &created, &comment.Username)
364 | if err != nil {
365 | return commentMap, err
366 | }
367 | // comment.Content = string(md.Markdown([]byte(comment.Content))) ## have to fix the
issue markdown support 368 | created = created.Local() 369 | comment.Created = created.Format("Jan 2 2006 15:04:05") 370 | commentMap[taskID] = append(commentMap[taskID], comment) 371 | } 372 | return commentMap, nil 373 | } 374 | 375 | // AddComments will be used to add comments in the database and return the added comment's ID and created date 376 | // along with the error if there is any. It will be sent back to the front end for display. 377 | func AddComments(username string, id int, content string) (types.Comment, error) { 378 | var comment types.Comment 379 | 380 | userID, err := GetUserID(username) 381 | if err != nil { 382 | return comment, err 383 | } 384 | stmt := "insert into comments(taskID, content, created, user_id) values (?,?,datetime(),?)" 385 | 386 | created := time.Now().Local().Format("Jan 2 2006 15:04:05") 387 | 388 | err = taskQuery(stmt, id, content, userID) 389 | 390 | if err != nil { 391 | return comment, err 392 | } 393 | 394 | stmt = "select id, created from comments where taskID=? and content=? and user_id=?" 395 | rows := database.query(stmt, id, content, userID) 396 | 397 | defer rows.Close() 398 | 399 | for rows.Next() { 400 | err := rows.Scan(&comment.ID, &comment.Created) 401 | if err != nil { 402 | log.Println("Error ", err) 403 | } 404 | } 405 | comment.Created = created 406 | 407 | comment.Username = username 408 | comment.Content = content 409 | 410 | log.Println("added comment to task ID ", id) 411 | 412 | return comment, nil 413 | } 414 | -------------------------------------------------------------------------------- /db/user.go: -------------------------------------------------------------------------------- 1 | package db 2 | 3 | import "log" 4 | 5 | //CreateUser will create a new user, take as input the parameters and 6 | //insert it into database 7 | func CreateUser(username, password, email string) error { 8 | err := taskQuery("insert into user(username, password, email) values(?,?,?)", username, password, email) 9 | return err 10 | } 11 | 12 | //ValidUser will check if the user exists in db and if exists if the username password 13 | //combination is valid 14 | func ValidUser(username, password string) bool { 15 | var passwordFromDB string 16 | userSQL := "select password from user where username=?" 17 | log.Print("validating user ", username) 18 | rows := database.query(userSQL, username) 19 | 20 | defer rows.Close() 21 | if rows.Next() { 22 | err := rows.Scan(&passwordFromDB) 23 | if err != nil { 24 | return false 25 | } 26 | } 27 | //If the password matches, return true 28 | if password == passwordFromDB { 29 | return true 30 | } 31 | //by default return false 32 | return false 33 | } 34 | 35 | //GetUserID will get the user's ID from the database 36 | func GetUserID(username string) (int, error) { 37 | var userID int 38 | userSQL := "select id from user where username=?" 39 | rows := database.query(userSQL, username) 40 | 41 | defer rows.Close() 42 | if rows.Next() { 43 | err := rows.Scan(&userID) 44 | if err != nil { 45 | return -1, err 46 | } 47 | } 48 | return userID, nil 49 | } 50 | -------------------------------------------------------------------------------- /files/README.md: -------------------------------------------------------------------------------- 1 | Will store the files uploaded to the application 2 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | echo "changing directory to Tasks" 2 | cd $GOPATH/src/github.com/thewhitetulip/Tasks 3 | echo "creating table" 4 | cat schema.sql | sqlite3 tasks.db 5 | echo "building the go binary" 6 | go build -o Tasks 7 | 8 | echo "starting the binary" 9 | ./Tasks 10 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | /** 4 | * This is the main file for the Task application 5 | * License: MIT 6 | **/ 7 | import ( 8 | "flag" 9 | "log" 10 | "net/http" 11 | "strings" 12 | 13 | "github.com/thewhitetulip/Tasks-vue/config" 14 | "github.com/thewhitetulip/Tasks-vue/views" 15 | 16 | "github.com/gorilla/mux" 17 | ) 18 | 19 | func main() { 20 | values, err := config.ReadConfig("config.json") 21 | var port *string 22 | 23 | if err != nil { 24 | port = flag.String("port", "", "IP address") 25 | flag.Parse() 26 | 27 | // User is expected to give :8080 like input, if they give 8080 28 | // we'll append the required ':'. 29 | if !strings.HasPrefix(*port, ":") { 30 | *port = ":" + *port 31 | log.Println("port is " + *port) 32 | } 33 | 34 | values.ServerPort = *port 35 | } 36 | 37 | views.PopulateTemplates() 38 | 39 | r := mux.NewRouter() 40 | 41 | http.Handle("/static/", http.FileServer(http.Dir("public"))) 42 | 43 | r.HandleFunc("/task/", views.GetTasksFuncAPI).Methods("GET") 44 | r.HandleFunc("/task/", views.AddTaskFuncAPI).Methods("PUT") 45 | r.HandleFunc("/task/", views.UpdateTaskFuncAPI).Methods("POST") 46 | r.HandleFunc("/task/{id}", views.TrashTaskFuncAPI).Methods("DELETE") 47 | r.HandleFunc("/deleted/", views.GetDeletedTaskFuncAPI).Methods("GET") 48 | 49 | r.HandleFunc("/completed/", views.GetCompletedTaskFuncAPI).Methods("GET") 50 | r.HandleFunc("/categories/", views.GetCategoryFuncAPI).Methods("GET") 51 | 52 | r.HandleFunc("/category/{category}", views.ShowCategoryFuncAPI).Methods("GET") 53 | r.HandleFunc("/category/{category}", views.DeleteCategoryFuncAPI).Methods("DELETE") 54 | r.HandleFunc("/complete-task/{id}", views.CompleteTaskFuncAPI).Methods("GET") 55 | r.HandleFunc("/incomplete-task/{id}", views.RestoreFromCompleteFuncAPI).Methods("GET") 56 | r.HandleFunc("/restore-task/{id}", views.RestoreTaskFuncAPI).Methods("GET") 57 | r.HandleFunc("/", views.Home).Methods("GET") 58 | 59 | r.HandleFunc("/comment/", views.AddCommentFuncAPI).Methods("PUT") 60 | r.HandleFunc("/comment/{id}", views.DeleteCommentFuncAPI).Methods("DELETE") 61 | r.HandleFunc("/category/", views.AddCategoryFuncAPI).Methods("PUT") 62 | r.HandleFunc("/category/{category}", views.UpdateCategoryFuncAPI).Methods("POST") 63 | 64 | //Login logout 65 | r.HandleFunc("/login/", views.LoginFuncAPI).Methods("POST", "GET") 66 | r.HandleFunc("/logout/", views.RequiresLogin(views.LogoutFuncAPI)).Methods("GET") 67 | r.HandleFunc("/signup/", views.SignUpFuncAPI).Methods("PUT") 68 | 69 | //these handlers perform action like delete, mark as complete etc 70 | // http.HandleFunc("/files/", views.RequiresLogin(views.UploadedFileHandler)) 71 | // http.HandleFunc("/search/", views.RequiresLogin(views.SearchTaskFunc)) 72 | http.Handle("/", r) 73 | log.Println("running server on ", values.ServerPort) 74 | log.Fatal(http.ListenAndServe(values.ServerPort, nil)) 75 | } 76 | -------------------------------------------------------------------------------- /public/static/css/bootstrap-glyphicons.css: -------------------------------------------------------------------------------- 1 | @font-face{font-family:'Glyphicons Halflings';src:url('../fonts/glyphiconshalflings-regular.eot');src:url('../fonts/glyphiconshalflings-regular.eot?#iefix') format('embedded-opentype'),url('../fonts/glyphiconshalflings-regular.woff') format('woff'),url('../fonts/glyphiconshalflings-regular.ttf') format('truetype'),url('../fonts/glyphiconshalflings-regular.svg#glyphicons_halflingsregular') format('svg')}.glyphicon:before{font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-plus:before{content:"\002b"}.glyphicon-minus:before{content:"\2212"}.glyphicon-asterisk:before{content:"\002a"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-euro:before{content:"\20ac"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse:before{content:"\e159"}.glyphicon-collapse-top:before{content:"\e160"} 2 | /* This beautiful CSS-File has been crafted with LESS (lesscss.org) and compiled by simpLESS (wearekiss.com/simpless) */ 3 | -------------------------------------------------------------------------------- /public/static/css/jquery-ui.min.css: -------------------------------------------------------------------------------- 1 | /*! jQuery UI - v1.11.1 - 2014-08-13 2 | * http://jqueryui.com 3 | * Includes: core.css, accordion.css, autocomplete.css, button.css, datepicker.css, dialog.css, draggable.css, menu.css, progressbar.css, resizable.css, selectable.css, selectmenu.css, slider.css, sortable.css, spinner.css, tabs.css, tooltip.css, theme.css 4 | * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Trebuchet%20MS%2CTahoma%2CVerdana%2CArial%2Csans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=f6a828&bgTextureHeader=gloss_wave&bgImgOpacityHeader=35&borderColorHeader=e78f08&fcHeader=ffffff&iconColorHeader=ffffff&bgColorContent=eeeeee&bgTextureContent=highlight_soft&bgImgOpacityContent=100&borderColorContent=dddddd&fcContent=333333&iconColorContent=222222&bgColorDefault=f6f6f6&bgTextureDefault=glass&bgImgOpacityDefault=100&borderColorDefault=cccccc&fcDefault=1c94c4&iconColorDefault=ef8c08&bgColorHover=fdf5ce&bgTextureHover=glass&bgImgOpacityHover=100&borderColorHover=fbcb09&fcHover=c77405&iconColorHover=ef8c08&bgColorActive=ffffff&bgTextureActive=glass&bgImgOpacityActive=65&borderColorActive=fbd850&fcActive=eb8f00&iconColorActive=ef8c08&bgColorHighlight=ffe45c&bgTextureHighlight=highlight_soft&bgImgOpacityHighlight=75&borderColorHighlight=fed22f&fcHighlight=363636&iconColorHighlight=228ef1&bgColorError=b81900&bgTextureError=diagonals_thick&bgImgOpacityError=18&borderColorError=cd0a0a&fcError=ffffff&iconColorError=ffd27a&bgColorOverlay=666666&bgTextureOverlay=diagonals_thick&bgImgOpacityOverlay=20&opacityOverlay=50&bgColorShadow=000000&bgTextureShadow=flat&bgImgOpacityShadow=10&opacityShadow=20&thicknessShadow=5px&offsetTopShadow=-5px&offsetLeftShadow=-5px&cornerRadiusShadow=5px 5 | * Copyright 2014 jQuery Foundation and other contributors; Licensed MIT */ 6 | 7 | .ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-clearfix{min-height:0}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important}.ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-accordion .ui-accordion-header{display:block;cursor:pointer;position:relative;margin:2px 0 0 0;padding:.5em .5em .5em .7em;min-height:0;font-size:100%}.ui-accordion .ui-accordion-icons{padding-left:2.2em}.ui-accordion .ui-accordion-icons .ui-accordion-icons{padding-left:2.2em}.ui-accordion .ui-accordion-header .ui-accordion-header-icon{position:absolute;left:.5em;top:50%;margin-top:-8px}.ui-accordion .ui-accordion-content{padding:1em 2.2em;border-top:0;overflow:auto}.ui-autocomplete{position:absolute;top:0;left:0;cursor:default}.ui-button{display:inline-block;position:relative;padding:0;line-height:normal;margin-right:.1em;cursor:pointer;vertical-align:middle;text-align:center;overflow:visible}.ui-button,.ui-button:link,.ui-button:visited,.ui-button:hover,.ui-button:active{text-decoration:none}.ui-button-icon-only{width:2.2em}button.ui-button-icon-only{width:2.4em}.ui-button-icons-only{width:3.4em}button.ui-button-icons-only{width:3.7em}.ui-button .ui-button-text{display:block;line-height:normal}.ui-button-text-only .ui-button-text{padding:.4em 1em}.ui-button-icon-only .ui-button-text,.ui-button-icons-only .ui-button-text{padding:.4em;text-indent:-9999999px}.ui-button-text-icon-primary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 1em .4em 2.1em}.ui-button-text-icon-secondary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 2.1em .4em 1em}.ui-button-text-icons .ui-button-text{padding-left:2.1em;padding-right:2.1em}input.ui-button{padding:.4em 1em}.ui-button-icon-only .ui-icon,.ui-button-text-icon-primary .ui-icon,.ui-button-text-icon-secondary .ui-icon,.ui-button-text-icons .ui-icon,.ui-button-icons-only .ui-icon{position:absolute;top:50%;margin-top:-8px}.ui-button-icon-only .ui-icon{left:50%;margin-left:-8px}.ui-button-text-icon-primary .ui-button-icon-primary,.ui-button-text-icons .ui-button-icon-primary,.ui-button-icons-only .ui-button-icon-primary{left:.5em}.ui-button-text-icon-secondary .ui-button-icon-secondary,.ui-button-text-icons .ui-button-icon-secondary,.ui-button-icons-only .ui-button-icon-secondary{right:.5em}.ui-buttonset{margin-right:7px}.ui-buttonset .ui-button{margin-left:0;margin-right:-.3em}input.ui-button::-moz-focus-inner,button.ui-button::-moz-focus-inner{border:0;padding:0}.ui-datepicker{width:17em;padding:.2em .2em 0;display:none}.ui-datepicker .ui-datepicker-header{position:relative;padding:.2em 0}.ui-datepicker .ui-datepicker-prev,.ui-datepicker .ui-datepicker-next{position:absolute;top:2px;width:1.8em;height:1.8em}.ui-datepicker .ui-datepicker-prev-hover,.ui-datepicker .ui-datepicker-next-hover{top:1px}.ui-datepicker .ui-datepicker-prev{left:2px}.ui-datepicker .ui-datepicker-next{right:2px}.ui-datepicker .ui-datepicker-prev-hover{left:1px}.ui-datepicker .ui-datepicker-next-hover{right:1px}.ui-datepicker .ui-datepicker-prev span,.ui-datepicker .ui-datepicker-next span{display:block;position:absolute;left:50%;margin-left:-8px;top:50%;margin-top:-8px}.ui-datepicker .ui-datepicker-title{margin:0 2.3em;line-height:1.8em;text-align:center}.ui-datepicker .ui-datepicker-title select{font-size:1em;margin:1px 0}.ui-datepicker select.ui-datepicker-month,.ui-datepicker select.ui-datepicker-year{width:45%}.ui-datepicker table{width:100%;font-size:.9em;border-collapse:collapse;margin:0 0 .4em}.ui-datepicker th{padding:.7em .3em;text-align:center;font-weight:bold;border:0}.ui-datepicker td{border:0;padding:1px}.ui-datepicker td span,.ui-datepicker td a{display:block;padding:.2em;text-align:right;text-decoration:none}.ui-datepicker .ui-datepicker-buttonpane{background-image:none;margin:.7em 0 0 0;padding:0 .2em;border-left:0;border-right:0;border-bottom:0}.ui-datepicker .ui-datepicker-buttonpane button{float:right;margin:.5em .2em .4em;cursor:pointer;padding:.2em .6em .3em .6em;width:auto;overflow:visible}.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current{float:left}.ui-datepicker.ui-datepicker-multi{width:auto}.ui-datepicker-multi .ui-datepicker-group{float:left}.ui-datepicker-multi .ui-datepicker-group table{width:95%;margin:0 auto .4em}.ui-datepicker-multi-2 .ui-datepicker-group{width:50%}.ui-datepicker-multi-3 .ui-datepicker-group{width:33.3%}.ui-datepicker-multi-4 .ui-datepicker-group{width:25%}.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header{border-left-width:0}.ui-datepicker-multi .ui-datepicker-buttonpane{clear:left}.ui-datepicker-row-break{clear:both;width:100%;font-size:0}.ui-datepicker-rtl{direction:rtl}.ui-datepicker-rtl .ui-datepicker-prev{right:2px;left:auto}.ui-datepicker-rtl .ui-datepicker-next{left:2px;right:auto}.ui-datepicker-rtl .ui-datepicker-prev:hover{right:1px;left:auto}.ui-datepicker-rtl .ui-datepicker-next:hover{left:1px;right:auto}.ui-datepicker-rtl .ui-datepicker-buttonpane{clear:right}.ui-datepicker-rtl .ui-datepicker-buttonpane button{float:left}.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,.ui-datepicker-rtl .ui-datepicker-group{float:right}.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header{border-right-width:0;border-left-width:1px}.ui-dialog{overflow:hidden;position:absolute;top:0;left:0;padding:.2em;outline:0}.ui-dialog .ui-dialog-titlebar{padding:.4em 1em;position:relative}.ui-dialog .ui-dialog-title{float:left;margin:.1em 0;white-space:nowrap;width:90%;overflow:hidden;text-overflow:ellipsis}.ui-dialog .ui-dialog-titlebar-close{position:absolute;right:.3em;top:50%;width:20px;margin:-10px 0 0 0;padding:1px;height:20px}.ui-dialog .ui-dialog-content{position:relative;border:0;padding:.5em 1em;background:none;overflow:auto}.ui-dialog .ui-dialog-buttonpane{text-align:left;border-width:1px 0 0 0;background-image:none;margin-top:.5em;padding:.3em 1em .5em .4em}.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset{float:right}.ui-dialog .ui-dialog-buttonpane button{margin:.5em .4em .5em 0;cursor:pointer}.ui-dialog .ui-resizable-se{width:12px;height:12px;right:-5px;bottom:-5px;background-position:16px 16px}.ui-draggable .ui-dialog-titlebar{cursor:move}.ui-draggable-handle{-ms-touch-action:none;touch-action:none}.ui-menu{list-style:none;padding:0;margin:0;display:block;outline:none}.ui-menu .ui-menu{position:absolute}.ui-menu .ui-menu-item{position:relative;margin:0;padding:3px 1em 3px .4em;cursor:pointer;min-height:0;list-style-image:url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7")}.ui-menu .ui-menu-divider{margin:5px 0;height:0;font-size:0;line-height:0;border-width:1px 0 0 0}.ui-menu .ui-state-focus,.ui-menu .ui-state-active{margin:-1px}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item{padding-left:2em}.ui-menu .ui-icon{position:absolute;top:0;bottom:0;left:.2em;margin:auto 0}.ui-menu .ui-menu-icon{left:auto;right:0}.ui-progressbar{height:2em;text-align:left;overflow:hidden}.ui-progressbar .ui-progressbar-value{margin:-1px;height:100%}.ui-progressbar .ui-progressbar-overlay{background:url("data:image/gif;base64,R0lGODlhKAAoAIABAAAAAP///yH/C05FVFNDQVBFMi4wAwEAAAAh+QQJAQABACwAAAAAKAAoAAACkYwNqXrdC52DS06a7MFZI+4FHBCKoDeWKXqymPqGqxvJrXZbMx7Ttc+w9XgU2FB3lOyQRWET2IFGiU9m1frDVpxZZc6bfHwv4c1YXP6k1Vdy292Fb6UkuvFtXpvWSzA+HycXJHUXiGYIiMg2R6W459gnWGfHNdjIqDWVqemH2ekpObkpOlppWUqZiqr6edqqWQAAIfkECQEAAQAsAAAAACgAKAAAApSMgZnGfaqcg1E2uuzDmmHUBR8Qil95hiPKqWn3aqtLsS18y7G1SzNeowWBENtQd+T1JktP05nzPTdJZlR6vUxNWWjV+vUWhWNkWFwxl9VpZRedYcflIOLafaa28XdsH/ynlcc1uPVDZxQIR0K25+cICCmoqCe5mGhZOfeYSUh5yJcJyrkZWWpaR8doJ2o4NYq62lAAACH5BAkBAAEALAAAAAAoACgAAAKVDI4Yy22ZnINRNqosw0Bv7i1gyHUkFj7oSaWlu3ovC8GxNso5fluz3qLVhBVeT/Lz7ZTHyxL5dDalQWPVOsQWtRnuwXaFTj9jVVh8pma9JjZ4zYSj5ZOyma7uuolffh+IR5aW97cHuBUXKGKXlKjn+DiHWMcYJah4N0lYCMlJOXipGRr5qdgoSTrqWSq6WFl2ypoaUAAAIfkECQEAAQAsAAAAACgAKAAAApaEb6HLgd/iO7FNWtcFWe+ufODGjRfoiJ2akShbueb0wtI50zm02pbvwfWEMWBQ1zKGlLIhskiEPm9R6vRXxV4ZzWT2yHOGpWMyorblKlNp8HmHEb/lCXjcW7bmtXP8Xt229OVWR1fod2eWqNfHuMjXCPkIGNileOiImVmCOEmoSfn3yXlJWmoHGhqp6ilYuWYpmTqKUgAAIfkECQEAAQAsAAAAACgAKAAAApiEH6kb58biQ3FNWtMFWW3eNVcojuFGfqnZqSebuS06w5V80/X02pKe8zFwP6EFWOT1lDFk8rGERh1TTNOocQ61Hm4Xm2VexUHpzjymViHrFbiELsefVrn6XKfnt2Q9G/+Xdie499XHd2g4h7ioOGhXGJboGAnXSBnoBwKYyfioubZJ2Hn0RuRZaflZOil56Zp6iioKSXpUAAAh+QQJAQABACwAAAAAKAAoAAACkoQRqRvnxuI7kU1a1UU5bd5tnSeOZXhmn5lWK3qNTWvRdQxP8qvaC+/yaYQzXO7BMvaUEmJRd3TsiMAgswmNYrSgZdYrTX6tSHGZO73ezuAw2uxuQ+BbeZfMxsexY35+/Qe4J1inV0g4x3WHuMhIl2jXOKT2Q+VU5fgoSUI52VfZyfkJGkha6jmY+aaYdirq+lQAACH5BAkBAAEALAAAAAAoACgAAAKWBIKpYe0L3YNKToqswUlvznigd4wiR4KhZrKt9Upqip61i9E3vMvxRdHlbEFiEXfk9YARYxOZZD6VQ2pUunBmtRXo1Lf8hMVVcNl8JafV38aM2/Fu5V16Bn63r6xt97j09+MXSFi4BniGFae3hzbH9+hYBzkpuUh5aZmHuanZOZgIuvbGiNeomCnaxxap2upaCZsq+1kAACH5BAkBAAEALAAAAAAoACgAAAKXjI8By5zf4kOxTVrXNVlv1X0d8IGZGKLnNpYtm8Lr9cqVeuOSvfOW79D9aDHizNhDJidFZhNydEahOaDH6nomtJjp1tutKoNWkvA6JqfRVLHU/QUfau9l2x7G54d1fl995xcIGAdXqMfBNadoYrhH+Mg2KBlpVpbluCiXmMnZ2Sh4GBqJ+ckIOqqJ6LmKSllZmsoq6wpQAAAh+QQJAQABACwAAAAAKAAoAAAClYx/oLvoxuJDkU1a1YUZbJ59nSd2ZXhWqbRa2/gF8Gu2DY3iqs7yrq+xBYEkYvFSM8aSSObE+ZgRl1BHFZNr7pRCavZ5BW2142hY3AN/zWtsmf12p9XxxFl2lpLn1rseztfXZjdIWIf2s5dItwjYKBgo9yg5pHgzJXTEeGlZuenpyPmpGQoKOWkYmSpaSnqKileI2FAAACH5BAkBAAEALAAAAAAoACgAAAKVjB+gu+jG4kORTVrVhRlsnn2dJ3ZleFaptFrb+CXmO9OozeL5VfP99HvAWhpiUdcwkpBH3825AwYdU8xTqlLGhtCosArKMpvfa1mMRae9VvWZfeB2XfPkeLmm18lUcBj+p5dnN8jXZ3YIGEhYuOUn45aoCDkp16hl5IjYJvjWKcnoGQpqyPlpOhr3aElaqrq56Bq7VAAAOw==");height:100%;filter:alpha(opacity=25);opacity:0.25}.ui-progressbar-indeterminate .ui-progressbar-value{background-image:none}.ui-resizable{position:relative}.ui-resizable-handle{position:absolute;font-size:0.1px;display:block;-ms-touch-action:none;touch-action:none}.ui-resizable-disabled .ui-resizable-handle,.ui-resizable-autohide .ui-resizable-handle{display:none}.ui-resizable-n{cursor:n-resize;height:7px;width:100%;top:-5px;left:0}.ui-resizable-s{cursor:s-resize;height:7px;width:100%;bottom:-5px;left:0}.ui-resizable-e{cursor:e-resize;width:7px;right:-5px;top:0;height:100%}.ui-resizable-w{cursor:w-resize;width:7px;left:-5px;top:0;height:100%}.ui-resizable-se{cursor:se-resize;width:12px;height:12px;right:1px;bottom:1px}.ui-resizable-sw{cursor:sw-resize;width:9px;height:9px;left:-5px;bottom:-5px}.ui-resizable-nw{cursor:nw-resize;width:9px;height:9px;left:-5px;top:-5px}.ui-resizable-ne{cursor:ne-resize;width:9px;height:9px;right:-5px;top:-5px}.ui-selectable{-ms-touch-action:none;touch-action:none}.ui-selectable-helper{position:absolute;z-index:100;border:1px dotted black}.ui-selectmenu-menu{padding:0;margin:0;position:absolute;top:0;left:0;display:none}.ui-selectmenu-menu .ui-menu{overflow:auto;overflow-x:hidden;padding-bottom:1px}.ui-selectmenu-menu .ui-menu .ui-selectmenu-optgroup{font-size:1em;font-weight:bold;line-height:1.5;padding:2px 0.4em;margin:0.5em 0 0 0;height:auto;border:0}.ui-selectmenu-open{display:block}.ui-selectmenu-button{display:inline-block;overflow:hidden;position:relative;text-decoration:none;cursor:pointer}.ui-selectmenu-button span.ui-icon{right:0.5em;left:auto;margin-top:-8px;position:absolute;top:50%}.ui-selectmenu-button span.ui-selectmenu-text{text-align:left;padding:0.4em 2.1em 0.4em 1em;display:block;line-height:1.4;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-slider{position:relative;text-align:left}.ui-slider .ui-slider-handle{position:absolute;z-index:2;width:1.2em;height:1.2em;cursor:default;-ms-touch-action:none;touch-action:none}.ui-slider .ui-slider-range{position:absolute;z-index:1;font-size:.7em;display:block;border:0;background-position:0 0}.ui-slider.ui-state-disabled .ui-slider-handle,.ui-slider.ui-state-disabled .ui-slider-range{filter:inherit}.ui-slider-horizontal{height:.8em}.ui-slider-horizontal .ui-slider-handle{top:-.3em;margin-left:-.6em}.ui-slider-horizontal .ui-slider-range{top:0;height:100%}.ui-slider-horizontal .ui-slider-range-min{left:0}.ui-slider-horizontal .ui-slider-range-max{right:0}.ui-slider-vertical{width:.8em;height:100px}.ui-slider-vertical .ui-slider-handle{left:-.3em;margin-left:0;margin-bottom:-.6em}.ui-slider-vertical .ui-slider-range{left:0;width:100%}.ui-slider-vertical .ui-slider-range-min{bottom:0}.ui-slider-vertical .ui-slider-range-max{top:0}.ui-sortable-handle{-ms-touch-action:none;touch-action:none}.ui-spinner{position:relative;display:inline-block;overflow:hidden;padding:0;vertical-align:middle}.ui-spinner-input{border:none;background:none;color:inherit;padding:0;margin:.2em 0;vertical-align:middle;margin-left:.4em;margin-right:22px}.ui-spinner-button{width:16px;height:50%;font-size:.5em;padding:0;margin:0;text-align:center;position:absolute;cursor:default;display:block;overflow:hidden;right:0}.ui-spinner a.ui-spinner-button{border-top:none;border-bottom:none;border-right:none}.ui-spinner .ui-icon{position:absolute;margin-top:-8px;top:50%;left:0}.ui-spinner-up{top:0}.ui-spinner-down{bottom:0}.ui-spinner .ui-icon-triangle-1-s{background-position:-65px -16px}.ui-tabs{position:relative;padding:.2em}.ui-tabs .ui-tabs-nav{margin:0;padding:.2em .2em 0}.ui-tabs .ui-tabs-nav li{list-style:none;float:left;position:relative;top:0;margin:1px .2em 0 0;border-bottom-width:0;padding:0;white-space:nowrap}.ui-tabs .ui-tabs-nav .ui-tabs-anchor{float:left;padding:.5em 1em;text-decoration:none}.ui-tabs .ui-tabs-nav li.ui-tabs-active{margin-bottom:-1px;padding-bottom:1px}.ui-tabs .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-state-disabled .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-tabs-loading .ui-tabs-anchor{cursor:text}.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor{cursor:pointer}.ui-tabs .ui-tabs-panel{display:block;border-width:0;padding:1em 1.4em;background:none}.ui-tooltip{padding:8px;position:absolute;z-index:9999;max-width:300px;-webkit-box-shadow:0 0 5px #aaa;box-shadow:0 0 5px #aaa}body .ui-tooltip{border-width:2px}.ui-widget{font-family:Trebuchet MS,Tahoma,Verdana,Arial,sans-serif;font-size:1.1em}.ui-widget .ui-widget{font-size:1em}.ui-widget input,.ui-widget select,.ui-widget textarea,.ui-widget button{font-family:Trebuchet MS,Tahoma,Verdana,Arial,sans-serif;font-size:1em}.ui-widget-content{border:1px solid #ddd;background:#eee url("images/ui-bg_highlight-soft_100_eeeeee_1x100.png") 50% top repeat-x;color:#333}.ui-widget-content a{color:#333}.ui-widget-header{border:1px solid #e78f08;background:#f6a828 url("images/ui-bg_gloss-wave_35_f6a828_500x100.png") 50% 50% repeat-x;color:#fff;font-weight:bold}.ui-widget-header a{color:#fff}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default{border:1px solid #ccc;background:#f6f6f6 url("images/ui-bg_glass_100_f6f6f6_1x400.png") 50% 50% repeat-x;font-weight:bold;color:#1c94c4}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited{color:#1c94c4;text-decoration:none}.ui-state-hover,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-hover,.ui-state-focus,.ui-widget-content .ui-state-focus,.ui-widget-header .ui-state-focus{border:1px solid #fbcb09;background:#fdf5ce url("images/ui-bg_glass_100_fdf5ce_1x400.png") 50% 50% repeat-x;font-weight:bold;color:#c77405}.ui-state-hover a,.ui-state-hover a:hover,.ui-state-hover a:link,.ui-state-hover a:visited,.ui-state-focus a,.ui-state-focus a:hover,.ui-state-focus a:link,.ui-state-focus a:visited{color:#c77405;text-decoration:none}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active{border:1px solid #fbd850;background:#fff url("images/ui-bg_glass_65_ffffff_1x400.png") 50% 50% repeat-x;font-weight:bold;color:#eb8f00}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#eb8f00;text-decoration:none}.ui-state-highlight,.ui-widget-content .ui-state-highlight,.ui-widget-header .ui-state-highlight{border:1px solid #fed22f;background:#ffe45c url("images/ui-bg_highlight-soft_75_ffe45c_1x100.png") 50% top repeat-x;color:#363636}.ui-state-highlight a,.ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a{color:#363636}.ui-state-error,.ui-widget-content .ui-state-error,.ui-widget-header .ui-state-error{border:1px solid #cd0a0a;background:#b81900 url("images/ui-bg_diagonals-thick_18_b81900_40x40.png") 50% 50% repeat;color:#fff}.ui-state-error a,.ui-widget-content .ui-state-error a,.ui-widget-header .ui-state-error a{color:#fff}.ui-state-error-text,.ui-widget-content .ui-state-error-text,.ui-widget-header .ui-state-error-text{color:#fff}.ui-priority-primary,.ui-widget-content .ui-priority-primary,.ui-widget-header .ui-priority-primary{font-weight:bold}.ui-priority-secondary,.ui-widget-content .ui-priority-secondary,.ui-widget-header .ui-priority-secondary{opacity:.7;filter:Alpha(Opacity=70);font-weight:normal}.ui-state-disabled,.ui-widget-content .ui-state-disabled,.ui-widget-header .ui-state-disabled{opacity:.35;filter:Alpha(Opacity=35);background-image:none}.ui-state-disabled .ui-icon{filter:Alpha(Opacity=35)}.ui-icon{width:16px;height:16px}.ui-icon,.ui-widget-content .ui-icon{background-image:url("images/ui-icons_222222_256x240.png")}.ui-widget-header .ui-icon{background-image:url("images/ui-icons_ffffff_256x240.png")}.ui-state-default .ui-icon{background-image:url("images/ui-icons_ef8c08_256x240.png")}.ui-state-hover .ui-icon,.ui-state-focus .ui-icon{background-image:url("images/ui-icons_ef8c08_256x240.png")}.ui-state-active .ui-icon{background-image:url("images/ui-icons_ef8c08_256x240.png")}.ui-state-highlight .ui-icon{background-image:url("images/ui-icons_228ef1_256x240.png")}.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background-image:url("images/ui-icons_ffd27a_256x240.png")}.ui-icon-blank{background-position:16px 16px}.ui-icon-carat-1-n{background-position:0 0}.ui-icon-carat-1-ne{background-position:-16px 0}.ui-icon-carat-1-e{background-position:-32px 0}.ui-icon-carat-1-se{background-position:-48px 0}.ui-icon-carat-1-s{background-position:-64px 0}.ui-icon-carat-1-sw{background-position:-80px 0}.ui-icon-carat-1-w{background-position:-96px 0}.ui-icon-carat-1-nw{background-position:-112px 0}.ui-icon-carat-2-n-s{background-position:-128px 0}.ui-icon-carat-2-e-w{background-position:-144px 0}.ui-icon-triangle-1-n{background-position:0 -16px}.ui-icon-triangle-1-ne{background-position:-16px -16px}.ui-icon-triangle-1-e{background-position:-32px -16px}.ui-icon-triangle-1-se{background-position:-48px -16px}.ui-icon-triangle-1-s{background-position:-64px -16px}.ui-icon-triangle-1-sw{background-position:-80px -16px}.ui-icon-triangle-1-w{background-position:-96px -16px}.ui-icon-triangle-1-nw{background-position:-112px -16px}.ui-icon-triangle-2-n-s{background-position:-128px -16px}.ui-icon-triangle-2-e-w{background-position:-144px -16px}.ui-icon-arrow-1-n{background-position:0 -32px}.ui-icon-arrow-1-ne{background-position:-16px -32px}.ui-icon-arrow-1-e{background-position:-32px -32px}.ui-icon-arrow-1-se{background-position:-48px -32px}.ui-icon-arrow-1-s{background-position:-64px -32px}.ui-icon-arrow-1-sw{background-position:-80px -32px}.ui-icon-arrow-1-w{background-position:-96px -32px}.ui-icon-arrow-1-nw{background-position:-112px -32px}.ui-icon-arrow-2-n-s{background-position:-128px -32px}.ui-icon-arrow-2-ne-sw{background-position:-144px -32px}.ui-icon-arrow-2-e-w{background-position:-160px -32px}.ui-icon-arrow-2-se-nw{background-position:-176px -32px}.ui-icon-arrowstop-1-n{background-position:-192px -32px}.ui-icon-arrowstop-1-e{background-position:-208px -32px}.ui-icon-arrowstop-1-s{background-position:-224px -32px}.ui-icon-arrowstop-1-w{background-position:-240px -32px}.ui-icon-arrowthick-1-n{background-position:0 -48px}.ui-icon-arrowthick-1-ne{background-position:-16px -48px}.ui-icon-arrowthick-1-e{background-position:-32px -48px}.ui-icon-arrowthick-1-se{background-position:-48px -48px}.ui-icon-arrowthick-1-s{background-position:-64px -48px}.ui-icon-arrowthick-1-sw{background-position:-80px -48px}.ui-icon-arrowthick-1-w{background-position:-96px -48px}.ui-icon-arrowthick-1-nw{background-position:-112px -48px}.ui-icon-arrowthick-2-n-s{background-position:-128px -48px}.ui-icon-arrowthick-2-ne-sw{background-position:-144px -48px}.ui-icon-arrowthick-2-e-w{background-position:-160px -48px}.ui-icon-arrowthick-2-se-nw{background-position:-176px -48px}.ui-icon-arrowthickstop-1-n{background-position:-192px -48px}.ui-icon-arrowthickstop-1-e{background-position:-208px -48px}.ui-icon-arrowthickstop-1-s{background-position:-224px -48px}.ui-icon-arrowthickstop-1-w{background-position:-240px -48px}.ui-icon-arrowreturnthick-1-w{background-position:0 -64px}.ui-icon-arrowreturnthick-1-n{background-position:-16px -64px}.ui-icon-arrowreturnthick-1-e{background-position:-32px -64px}.ui-icon-arrowreturnthick-1-s{background-position:-48px -64px}.ui-icon-arrowreturn-1-w{background-position:-64px -64px}.ui-icon-arrowreturn-1-n{background-position:-80px -64px}.ui-icon-arrowreturn-1-e{background-position:-96px -64px}.ui-icon-arrowreturn-1-s{background-position:-112px -64px}.ui-icon-arrowrefresh-1-w{background-position:-128px -64px}.ui-icon-arrowrefresh-1-n{background-position:-144px -64px}.ui-icon-arrowrefresh-1-e{background-position:-160px -64px}.ui-icon-arrowrefresh-1-s{background-position:-176px -64px}.ui-icon-arrow-4{background-position:0 -80px}.ui-icon-arrow-4-diag{background-position:-16px -80px}.ui-icon-extlink{background-position:-32px -80px}.ui-icon-newwin{background-position:-48px -80px}.ui-icon-refresh{background-position:-64px -80px}.ui-icon-shuffle{background-position:-80px -80px}.ui-icon-transfer-e-w{background-position:-96px -80px}.ui-icon-transferthick-e-w{background-position:-112px -80px}.ui-icon-folder-collapsed{background-position:0 -96px}.ui-icon-folder-open{background-position:-16px -96px}.ui-icon-document{background-position:-32px -96px}.ui-icon-document-b{background-position:-48px -96px}.ui-icon-note{background-position:-64px -96px}.ui-icon-mail-closed{background-position:-80px -96px}.ui-icon-mail-open{background-position:-96px -96px}.ui-icon-suitcase{background-position:-112px -96px}.ui-icon-comment{background-position:-128px -96px}.ui-icon-person{background-position:-144px -96px}.ui-icon-print{background-position:-160px -96px}.ui-icon-trash{background-position:-176px -96px}.ui-icon-locked{background-position:-192px -96px}.ui-icon-unlocked{background-position:-208px -96px}.ui-icon-bookmark{background-position:-224px -96px}.ui-icon-tag{background-position:-240px -96px}.ui-icon-home{background-position:0 -112px}.ui-icon-flag{background-position:-16px -112px}.ui-icon-calendar{background-position:-32px -112px}.ui-icon-cart{background-position:-48px -112px}.ui-icon-pencil{background-position:-64px -112px}.ui-icon-clock{background-position:-80px -112px}.ui-icon-disk{background-position:-96px -112px}.ui-icon-calculator{background-position:-112px -112px}.ui-icon-zoomin{background-position:-128px -112px}.ui-icon-zoomout{background-position:-144px -112px}.ui-icon-search{background-position:-160px -112px}.ui-icon-wrench{background-position:-176px -112px}.ui-icon-gear{background-position:-192px -112px}.ui-icon-heart{background-position:-208px -112px}.ui-icon-star{background-position:-224px -112px}.ui-icon-link{background-position:-240px -112px}.ui-icon-cancel{background-position:0 -128px}.ui-icon-plus{background-position:-16px -128px}.ui-icon-plusthick{background-position:-32px -128px}.ui-icon-minus{background-position:-48px -128px}.ui-icon-minusthick{background-position:-64px -128px}.ui-icon-close{background-position:-80px -128px}.ui-icon-closethick{background-position:-96px -128px}.ui-icon-key{background-position:-112px -128px}.ui-icon-lightbulb{background-position:-128px -128px}.ui-icon-scissors{background-position:-144px -128px}.ui-icon-clipboard{background-position:-160px -128px}.ui-icon-copy{background-position:-176px -128px}.ui-icon-contact{background-position:-192px -128px}.ui-icon-image{background-position:-208px -128px}.ui-icon-video{background-position:-224px -128px}.ui-icon-script{background-position:-240px -128px}.ui-icon-alert{background-position:0 -144px}.ui-icon-info{background-position:-16px -144px}.ui-icon-notice{background-position:-32px -144px}.ui-icon-help{background-position:-48px -144px}.ui-icon-check{background-position:-64px -144px}.ui-icon-bullet{background-position:-80px -144px}.ui-icon-radio-on{background-position:-96px -144px}.ui-icon-radio-off{background-position:-112px -144px}.ui-icon-pin-w{background-position:-128px -144px}.ui-icon-pin-s{background-position:-144px -144px}.ui-icon-play{background-position:0 -160px}.ui-icon-pause{background-position:-16px -160px}.ui-icon-seek-next{background-position:-32px -160px}.ui-icon-seek-prev{background-position:-48px -160px}.ui-icon-seek-end{background-position:-64px -160px}.ui-icon-seek-start{background-position:-80px -160px}.ui-icon-seek-first{background-position:-80px -160px}.ui-icon-stop{background-position:-96px -160px}.ui-icon-eject{background-position:-112px -160px}.ui-icon-volume-off{background-position:-128px -160px}.ui-icon-volume-on{background-position:-144px -160px}.ui-icon-power{background-position:0 -176px}.ui-icon-signal-diag{background-position:-16px -176px}.ui-icon-signal{background-position:-32px -176px}.ui-icon-battery-0{background-position:-48px -176px}.ui-icon-battery-1{background-position:-64px -176px}.ui-icon-battery-2{background-position:-80px -176px}.ui-icon-battery-3{background-position:-96px -176px}.ui-icon-circle-plus{background-position:0 -192px}.ui-icon-circle-minus{background-position:-16px -192px}.ui-icon-circle-close{background-position:-32px -192px}.ui-icon-circle-triangle-e{background-position:-48px -192px}.ui-icon-circle-triangle-s{background-position:-64px -192px}.ui-icon-circle-triangle-w{background-position:-80px -192px}.ui-icon-circle-triangle-n{background-position:-96px -192px}.ui-icon-circle-arrow-e{background-position:-112px -192px}.ui-icon-circle-arrow-s{background-position:-128px -192px}.ui-icon-circle-arrow-w{background-position:-144px -192px}.ui-icon-circle-arrow-n{background-position:-160px -192px}.ui-icon-circle-zoomin{background-position:-176px -192px}.ui-icon-circle-zoomout{background-position:-192px -192px}.ui-icon-circle-check{background-position:-208px -192px}.ui-icon-circlesmall-plus{background-position:0 -208px}.ui-icon-circlesmall-minus{background-position:-16px -208px}.ui-icon-circlesmall-close{background-position:-32px -208px}.ui-icon-squaresmall-plus{background-position:-48px -208px}.ui-icon-squaresmall-minus{background-position:-64px -208px}.ui-icon-squaresmall-close{background-position:-80px -208px}.ui-icon-grip-dotted-vertical{background-position:0 -224px}.ui-icon-grip-dotted-horizontal{background-position:-16px -224px}.ui-icon-grip-solid-vertical{background-position:-32px -224px}.ui-icon-grip-solid-horizontal{background-position:-48px -224px}.ui-icon-gripsmall-diagonal-se{background-position:-64px -224px}.ui-icon-grip-diagonal-se{background-position:-80px -224px}.ui-corner-all,.ui-corner-top,.ui-corner-left,.ui-corner-tl{border-top-left-radius:4px}.ui-corner-all,.ui-corner-top,.ui-corner-right,.ui-corner-tr{border-top-right-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-left,.ui-corner-bl{border-bottom-left-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-right,.ui-corner-br{border-bottom-right-radius:4px}.ui-widget-overlay{background:#666 url("images/ui-bg_diagonals-thick_20_666666_40x40.png") 50% 50% repeat;opacity:.5;filter:Alpha(Opacity=50)}.ui-widget-shadow{margin:-5px 0 0 -5px;padding:5px;background:#000 url("images/ui-bg_flat_10_000000_40x100.png") 50% 50% repeat-x;opacity:.2;filter:Alpha(Opacity=20);border-radius:5px} -------------------------------------------------------------------------------- /public/static/css/sidebar-bootstrap.css: -------------------------------------------------------------------------------- 1 | .navbar-fixed-top + .sidebar-trigger .sidebar-toggle, 2 | .navbar-fixed-bottom + .sidebar-trigger .sidebar-toggle, 3 | .navbar-fixed-top + .sidebar-trigger + .sidebar-trigger .sidebar-toggle, 4 | .navbar-fixed-bottom + .sidebar-trigger + .sidebar-trigger .sidebar-toggle { 5 | position: fixed; 6 | z-index: 1032; 7 | } 8 | .navbar-fixed-top + .sidebar-trigger .sidebar-wrapper, 9 | .navbar-fixed-bottom + .sidebar-trigger .sidebar-wrapper, 10 | .navbar-fixed-top + .sidebar-trigger + .sidebar-trigger .sidebar-wrapper, 11 | .navbar-fixed-bottom + .sidebar-trigger + .sidebar-trigger .sidebar-wrapper { 12 | z-index: 1033; 13 | } 14 | .navbar-fixed-bottom + .sidebar-trigger .sidebar-toggle, 15 | .navbar-fixed-bottom + .sidebar-trigger + .sidebar-trigger .sidebar-toggle { 16 | top: inherit; 17 | bottom: 0; 18 | } 19 | .navbar-fixed-top + .container, 20 | .navbar-fixed-top + .container-fluid, 21 | .navbar-fixed-top + .sidebar-trigger + .container, 22 | .navbar-fixed-top + .sidebar-trigger + .container-fluid, 23 | .navbar-fixed-top + .sidebar-trigger + .sidebar-trigger + .container, 24 | .navbar-fixed-top + .sidebar-trigger + .sidebar-trigger + .container-fluid { 25 | margin-top: 70px; 26 | } 27 | .navbar-fixed-bottom + .container, 28 | .navbar-fixed-bottom + .container-fluid, 29 | .navbar-fixed-bottom + .sidebar-trigger + .container, 30 | .navbar-fixed-bottom + .sidebar-trigger + .container-fluid, 31 | .navbar-fixed-bottom + .sidebar-trigger + .sidebar-trigger + .container, 32 | .navbar-fixed-bottom + .sidebar-trigger + .sidebar-trigger + .container-fluid { 33 | margin-bottom: 70px; 34 | } 35 | @media (min-width: 992px) { 36 | .sidebar-force-open:not(.sidebar-right) + .container, 37 | .sidebar-force-open:not(.sidebar-right) + .sidebar-trigger + .container { 38 | padding-left: 225px; 39 | } 40 | .sidebar-force-open:not(.sidebar-right) + .container-fluid, 41 | .sidebar-force-open:not(.sidebar-right) + .sidebar-trigger + .container-fluid { 42 | margin-left: 210px; 43 | } 44 | .sidebar-force-open.sidebar-right + .container, 45 | .sidebar-force-open.sidebar-right + .sidebar-trigger + .container { 46 | padding-right: 225px; 47 | } 48 | .sidebar-force-open.sidebar-right + .container-fluid, 49 | .sidebar-force-open.sidebar-right + .sidebar-trigger + .container-fluid { 50 | margin-right: 210px; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /public/static/css/sidebar.css: -------------------------------------------------------------------------------- 1 | .sidebar-toggle { 2 | position: absolute; 3 | top: 0; 4 | left: 0; 5 | height: 51px; 6 | cursor: pointer; 7 | margin: 0; 8 | padding: 17px 20px 17px 0; 9 | } 10 | .sidebar-toggle .glyphicon{ 11 | color:white; 12 | } 13 | .sidebar-toggle > i { 14 | font-size: 18px; 15 | margin: 0 0 0 -5px; 16 | -webkit-transition: all 0.1s ease-in-out; 17 | transition: all 0.1s ease-in-out; 18 | } 19 | .sidebar-toggle > .fa-sidebar-toggle:before { 20 | content: "\f0c9"; 21 | } 22 | .sidebar-toggle:hover > i, 23 | .sidebar-toggle.sidebar-toggle-opened > i { 24 | margin-left: -9px; 25 | } 26 | .sidebar-toggle + .navbar-brand > img { 27 | margin-left: 10px; 28 | } 29 | .sidebar-togglable .sidebar-toggle { 30 | display: block; 31 | } 32 | .sidebar-wrapper { 33 | position: fixed; 34 | top: 0; 35 | overflow: hidden; 36 | bottom: 0; 37 | width: 210px; 38 | cursor: default; 39 | -moz-user-select: -moz-none; 40 | user-select: none; 41 | -webkit-transform: translate3d(-210px, 0px, 0px); 42 | transform: translate3d(-210px, 0px, 0px); 43 | } 44 | .sidebar-wrapper.sidebar-ready { 45 | -webkit-transition: -webkit-transform 0.2s; 46 | transition: transform 0.2s; 47 | } 48 | .sidebar-wrapper.sidebar-open { 49 | -webkit-transform: translate3d(0px, 0px, 0px); 50 | transform: translate3d(0px, 0px, 0px); 51 | } 52 | .sidebar-wrapper .sidebar-scroller { 53 | position: absolute; 54 | overflow-x: hidden; 55 | overflow-y: scroll; 56 | left: 0; 57 | right: -18px; 58 | height: 100%; 59 | } 60 | .sidebar-wrapper .sidebar-menu { 61 | margin: 0; 62 | padding: 0; 63 | overflow-x: hidden; 64 | list-style: none; 65 | text-align: left; 66 | font-size: 14px; 67 | } 68 | .sidebar-wrapper .sidebar-menu ul { 69 | padding: 0; 70 | margin: 0; 71 | } 72 | .sidebar-wrapper .sidebar-menu li { 73 | display: block; 74 | } 75 | .sidebar-wrapper .sidebar-group > span, 76 | .sidebar-wrapper .sidebar-item > a { 77 | display: block; 78 | height: 100%; 79 | padding: 12px 15px; 80 | text-decoration: none; 81 | } 82 | .sidebar-wrapper .sidebar-item > a.active { 83 | border-left: 5px solid; 84 | padding: 12px 15px 12px 10px; 85 | } 86 | .sidebar-wrapper .sidebar-item.sidebar-item-mini { 87 | font-size: 0.7em; 88 | } 89 | .sidebar-wrapper .sidebar-item.sidebar-item-mini > a { 90 | padding-top: 7px; 91 | padding-bottom: 7px; 92 | } 93 | .sidebar-wrapper .sidebar-group { 94 | margin-top: 20px; 95 | } 96 | .sidebar-wrapper .sidebar-group:first-child { 97 | margin-top: 0; 98 | } 99 | .sidebar-wrapper .sidebar-group > span { 100 | font-family: inherit; 101 | font-size: 24px; 102 | border-bottom: 1px solid transparent; 103 | } 104 | .sidebar-wrapper .sidebar-group.sticky-header { 105 | position: absolute; 106 | height: auto; 107 | top: 0; 108 | left: 0; 109 | right: 0; 110 | z-index: 1; 111 | margin-top: 0; 112 | } 113 | .sidebar-wrapper .sidebar-group + .sidebar-item { 114 | margin-top: 32px; 115 | border-top: 1px solid transparent; 116 | } 117 | .sidebar-wrapper .sidebar-item > a { 118 | cursor: pointer; 119 | } 120 | .sidebar-swipe { 121 | position: fixed; 122 | z-index: 1001; 123 | width: 20px; 124 | left: 0; 125 | top: 0; 126 | bottom: 0; 127 | -moz-user-select: -moz-none; 128 | user-select: none; 129 | } 130 | .sidebar-open + .sidebar-swipe, 131 | .sidebar-force-open .sidebar-swipe { 132 | left: 210px; 133 | } 134 | .sidebar-trigger .sidebar-toggle { 135 | z-index: 1002; 136 | } 137 | .sidebar-trigger .sidebar-wrapper { 138 | z-index: 1003; 139 | } 140 | .sidebar-wrapper.sidebar-default { 141 | color: #222222; 142 | background-color: #ffffff; 143 | } 144 | .sidebar-wrapper.sidebar-default.sidebar-open, 145 | .sidebar-wrapper.sidebar-default.sidebar-dragging { 146 | -webkit-box-shadow: 3px 0 4px rgba(0, 0, 0, 0.18); 147 | box-shadow: 3px 0 4px rgba(0, 0, 0, 0.18); 148 | } 149 | .sidebar-wrapper.sidebar-default .sidebar-group > span { 150 | color: #dbdbdb; 151 | border-bottom-color: #eeeeee; 152 | } 153 | .sidebar-wrapper.sidebar-default .sidebar-group.sticky-header > span { 154 | background-color: #ffffff; 155 | } 156 | .sidebar-wrapper.sidebar-default .sidebar-group + .sidebar-item { 157 | border-top-color: #eeeeee; 158 | } 159 | .sidebar-wrapper.sidebar-default .sidebar-item > a { 160 | color: #222222; 161 | background-color: #ffffff; 162 | } 163 | .sidebar-wrapper.sidebar-default .sidebar-item > a:hover, 164 | .sidebar-wrapper.sidebar-default .sidebar-item > a:focus { 165 | color: #333333; 166 | background-color: #eeeeee; 167 | } 168 | .sidebar-wrapper.sidebar-default .sidebar-item > a.active { 169 | color: #337ab7; 170 | background-color: #ffffff; 171 | } 172 | .sidebar-wrapper.sidebar-default .sidebar-item.sidebar-item-mini > a { 173 | color: #747474; 174 | } 175 | .sidebar-wrapper.sidebar-default .hammer-scrollbar { 176 | background-color: #555555; 177 | } 178 | .sidebar-wrapper.sidebar-inverse { 179 | color: #9d9d9d; 180 | background-color: #2a3542; 181 | } 182 | .sidebar-wrapper.sidebar-inverse.sidebar-open, 183 | .sidebar-wrapper.sidebar-inverse.sidebar-dragging { 184 | -webkit-box-shadow: 3px 0 4px rgba(0, 0, 0, 0.32); 185 | box-shadow: 3px 0 4px rgba(0, 0, 0, 0.32); 186 | } 187 | .sidebar-wrapper.sidebar-inverse .sidebar-group > span { 188 | color: #46586e; 189 | border-bottom-color: #344252; 190 | } 191 | .sidebar-wrapper.sidebar-inverse .sidebar-group.sticky-header > span { 192 | background-color: #2a3542; 193 | } 194 | .sidebar-wrapper.sidebar-inverse .sidebar-group + .sidebar-item { 195 | border-top-color: #344252; 196 | } 197 | .sidebar-wrapper.sidebar-inverse .sidebar-item > a { 198 | color: #9d9d9d; 199 | background-color: #2a3542; 200 | } 201 | .sidebar-wrapper.sidebar-inverse .sidebar-item > a:hover, 202 | .sidebar-wrapper.sidebar-inverse .sidebar-item > a:focus { 203 | color: #ffffff; 204 | background-color: #344252; 205 | } 206 | .sidebar-wrapper.sidebar-inverse .sidebar-item > a.active { 207 | color: #dfecf6; 208 | background-color: #2a3542; 209 | } 210 | .sidebar-wrapper.sidebar-inverse .sidebar-item.sidebar-item-mini > a { 211 | color: #6d85a2; 212 | } 213 | .sidebar-wrapper.sidebar-inverse .hammer-scrollbar { 214 | background-color: #e4e8ed; 215 | } 216 | .navbar-default + .sidebar-trigger .sidebar-toggle > i, 217 | .navbar-default + .sidebar-trigger + .sidebar-trigger .sidebar-toggle > i { 218 | color: #888888; 219 | } 220 | .navbar-default + .sidebar-trigger .sidebar-toggle:hover > i, 221 | .navbar-default + .sidebar-trigger + .sidebar-trigger .sidebar-toggle:hover > i { 222 | color: #333333; 223 | } 224 | .navbar-inverse + .sidebar-trigger .sidebar-toggle > i, 225 | .navbar-inverse + .sidebar-trigger + .sidebar-trigger .sidebar-toggle > i { 226 | color: #ffffff; 227 | } 228 | .navbar-inverse + .sidebar-trigger .sidebar-toggle:hover > i, 229 | .navbar-inverse + .sidebar-trigger + .sidebar-trigger .sidebar-toggle:hover > i { 230 | color: #ffffff; 231 | } 232 | .sidebar-right .sidebar-toggle { 233 | left: auto; 234 | right: 0; 235 | padding-left: 20px; 236 | padding-right: 0; 237 | } 238 | .sidebar-right .sidebar-toggle > i { 239 | margin-left: 0; 240 | margin-right: -5px; 241 | } 242 | .sidebar-right .sidebar-toggle:hover > i, 243 | .sidebar-right .sidebar-toggle.sidebar-toggle-opened > i { 244 | margin-right: -9px; 245 | } 246 | .sidebar-right .sidebar-wrapper { 247 | right: 0; 248 | -webkit-transform: translate3d(210px, 0px, 0px); 249 | transform: translate3d(210px, 0px, 0px); 250 | } 251 | .sidebar-right .sidebar-wrapper.sidebar-open { 252 | -webkit-transform: translate3d(0px, 0px, 0px); 253 | transform: translate3d(0px, 0px, 0px); 254 | } 255 | .sidebar-right .sidebar-wrapper.sidebar-default.sidebar-open, 256 | .sidebar-right .sidebar-wrapper.sidebar-default.sidebar-dragging { 257 | -webkit-box-shadow: -3px 0 4px rgba(0, 0, 0, 0.18); 258 | box-shadow: -3px 0 4px rgba(0, 0, 0, 0.18); 259 | } 260 | .sidebar-right .sidebar-wrapper.sidebar-inverse.sidebar-open, 261 | .sidebar-right .sidebar-wrapper.sidebar-inverse.sidebar-dragging { 262 | -webkit-box-shadow: -3px 0 4px rgba(0, 0, 0, 0.32); 263 | box-shadow: -3px 0 4px rgba(0, 0, 0, 0.32); 264 | } 265 | .sidebar-right .sidebar-wrapper .sidebar-item > a.active { 266 | border-left: inherit; 267 | border-right: 5px solid; 268 | padding: 12px 10px 12px 15px; 269 | } 270 | .sidebar-right .sidebar-swipe { 271 | left: auto; 272 | right: 0; 273 | } 274 | .sidebar-right .sidebar-open + .sidebar-swipe, 275 | .sidebar-right .sidebar-force-open .sidebar-swipe { 276 | right: 210px; 277 | } 278 | @media (max-width: 767px) { 279 | .sidebar-wrapper { 280 | width: 80%; 281 | -webkit-transform: translate3d(-100%, 0px, 0px); 282 | transform: translate3d(-100%, 0px, 0px); 283 | } 284 | .sidebar-open + .sidebar-swipe, 285 | .sidebar-force-open .sidebar-open + .sidebar-swipe { 286 | left: 80%; 287 | } 288 | .sidebar-force-open .sidebar-swipe { 289 | left: 0; 290 | } 291 | .sidebar-right .sidebar-toggle { 292 | padding-left: 7px; 293 | } 294 | .sidebar-right .sidebar-wrapper { 295 | -webkit-transform: translate3d(100%, 0px, 0px); 296 | transform: translate3d(100%, 0px, 0px); 297 | } 298 | .sidebar-right .sidebar-open + .sidebar-swipe { 299 | left: auto; 300 | right: 80%; 301 | } 302 | .sidebar-right .sidebar-force-open .sidebar-swipe { 303 | left: auto; 304 | right: 0; 305 | } 306 | } 307 | @media (max-width: 991px) { 308 | .sidebar-force-open .sidebar-wrapper:not(.sidebar-open) + .sidebar-swipe { 309 | left: 0; 310 | } 311 | } 312 | @media (min-width: 992px) { 313 | .sidebar-trigger.sidebar-locked .sidebar-toggle { 314 | display: none; 315 | } 316 | .sidebar-trigger.sidebar-locked .sidebar-wrapper { 317 | margin-top: 51px; 318 | } 319 | .sidebar-wrapper.sidebar-open-init { 320 | -webkit-transform: translate3d(0px, 0px, 0px); 321 | transform: translate3d(0px, 0px, 0px); 322 | } 323 | .sidebar-force-open .sidebar-wrapper.sidebar-open, 324 | .sidebar-force-open.sidebar-right .sidebar-wrapper.sidebar-open, 325 | .sidebar-force-open .sidebar-wrapper.sidebar-dragging, 326 | .sidebar-force-open.sidebar-right .sidebar-wrapper.sidebar-dragging { 327 | -webkit-box-shadow: none; 328 | box-shadow: none; 329 | } 330 | } 331 | .sidebar-wrapper { 332 | -ms-touch-action: none; 333 | } 334 | .sidebar-swipe { 335 | -ms-touch-action: none; 336 | } 337 | -------------------------------------------------------------------------------- /public/static/css/styles.css: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | omninotesweb main stylesheet 4 | ============= 5 | 6 | Author: Suraj Patil 7 | Updated: January 13, 2014 8 | Notes: omninotesweb 9 | 10 | */ 11 | 12 | 13 | /*-------------------------------------- 14 | Layout 15 | -------------------------------------- */ 16 | 17 | .commentslist { 18 | background-color: #f5f5f5; 19 | } 20 | 21 | .loginbutton { 22 | height: 38px; 23 | padding: 8px 12px; 24 | font-size: 14px; 25 | line-height: 1.428571429; 26 | color: #555; 27 | background-color: #fff; 28 | border: 1px solid #ccc; 29 | border-radius: 4px; 30 | -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); 31 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); 32 | -webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; 33 | transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s 34 | } 35 | 36 | .comment { 37 | padding-left: 25px; 38 | padding-right: 25px; 39 | padding-top: 15px; 40 | } 41 | 42 | ul { 43 | list-style-type: none; 44 | } 45 | 46 | .timestamp { 47 | color: #aaa; 48 | } 49 | 50 | .badge { 51 | background-color: #1a78c9; 52 | margin-right: 10px; 53 | float: right; 54 | } 55 | 56 | .center { 57 | text-align: center; 58 | } 59 | 60 | .navbar-brand:hover { 61 | color: white; 62 | } 63 | 64 | .footer { 65 | height: 30px; 66 | width: auto; 67 | text-align: center; 68 | } 69 | 70 | .floating-action-icon { 71 | position: fixed; 72 | bottom: 40px; 73 | right: 30px; 74 | z-index: 101; 75 | width: 56px; 76 | height: 56px; 77 | font-size: 20px; 78 | border-radius: 35px; 79 | box-shadow: 0 0 4px #111; 80 | padding-top: 10px !important; 81 | } 82 | 83 | .notification { 84 | width: -moz-fit-content; 85 | position: fixed; 86 | right: 10px; 87 | max-width: 400px; 88 | padding: 12px; 89 | background-color: #F2FCFF; 90 | box-shadow: 1px 0px 9px 0px rgba(27, 123, 216, 0.4); 91 | border: 1px solid #5596CE; 92 | border-radius: 10px; 93 | border-radius: 10px; 94 | z-index: 1100; 95 | max-height: 90px; 96 | margin-top: 20px; 97 | min-width: 200px; 98 | } 99 | 100 | #btnMessage { 101 | padding: 1px 12px; 102 | height: 30px; 103 | text-align: center; 104 | float: right; 105 | } 106 | 107 | 108 | /*-------------------------------------- 109 | Navbar 110 | -------------------------------------- */ 111 | 112 | .mainHeader { 113 | background-color: #3f51b5; 114 | border-radius: 0px; 115 | } 116 | 117 | .navbar-brand { 118 | margin-left: 25px; 119 | font-size: 1.5em; 120 | color: white; 121 | max-width: 2000px; 122 | } 123 | 124 | .btn-action { 125 | background-color: #3f51b5; 126 | } 127 | 128 | #icons { 129 | text-align: right; 130 | float: right; 131 | height: 50%; 132 | line-height: 52px; 133 | float: right; 134 | margin-top: 10px; 135 | } 136 | 137 | nav .glyphicon { 138 | color: white; 139 | } 140 | 141 | nav .glyphicon:hover { 142 | color: black; 143 | } 144 | 145 | .sr-only { 146 | display: block; 147 | width: 20px; 148 | height: 3px; 149 | background-color: white; 150 | margin-bottom: 4px; 151 | } 152 | 153 | .hidden { 154 | display: none; 155 | } 156 | 157 | 158 | /*-------------------------------------- 159 | NotesFeed 160 | -------------------------------------- */ 161 | 162 | .overdue { 163 | color: red; 164 | margin-top: 1px; 165 | font-size: 12px; 166 | padding-top: -100px; 167 | position: absolute; 168 | padding-left: 5px; 169 | } 170 | 171 | .noteHeading { 172 | font-weight: 900; 173 | font-size: 17px; 174 | color: #666666; 175 | margin-bottom: 0px; 176 | padding-bottom: 5px; 177 | } 178 | 179 | hr { 180 | margin: 0; 181 | padding: 0; 182 | } 183 | 184 | .noteHeading a { 185 | font-weight: 400; 186 | font-size: 11px; 187 | } 188 | 189 | .noteContent { 190 | padding-top: 7px; 191 | font-size: 0.9em; 192 | } 193 | 194 | .noteContent img { 195 | width: 90%; 196 | padding-left: 10%; 197 | } 198 | 199 | .toggle { 200 | cursor: pointer; 201 | margin-top: -30px; 202 | float: right; 203 | } 204 | 205 | .notefooter { 206 | color: #aaa; 207 | height: 20px; 208 | } 209 | 210 | 211 | /* These are the classes that are going to be applied: */ 212 | 213 | .column { 214 | float: left; 215 | } 216 | 217 | .note { 218 | display: block; 219 | margin: 4px; 220 | margin-bottom: 6px; 221 | padding: 15px; 222 | background-color: white; 223 | box-shadow: 1px 1px 2px 1px #7D7470; 224 | border-radius: 4px 4px 4px 4px; 225 | height: auto; 226 | } 227 | 228 | .note:hover { 229 | border-bottom: 2px solid black; 230 | } 231 | 232 | .menu a { 233 | text-decoration: none; 234 | } 235 | 236 | .menu li { 237 | margin-top: -10px; 238 | list-style: none; 239 | float: right; 240 | padding: 5px; 241 | height: 15px; 242 | } 243 | 244 | 245 | /*-------------------------------------- 246 | Navigation drawer 247 | -------------------------------------- */ 248 | 249 | .list-group-item { 250 | border: none; 251 | } 252 | 253 | .sidebar-item h5 { 254 | margin-left: 15px; 255 | display: block; 256 | } 257 | 258 | .sidebar-item .glyphicon:hover { 259 | color: black; 260 | } 261 | 262 | .col-sm-2 a.list-group-item:hover, 263 | a.list-group-item:focus { 264 | text-decoration: none; 265 | background-color: transparent; 266 | } 267 | 268 | body { 269 | background-color: #f5f5f5; 270 | overflow-x: hidden; 271 | overflow-y: auto; 272 | margin-top: 70px; 273 | } 274 | 275 | .nav-item { 276 | padding-left: 10px; 277 | } 278 | 279 | .col-sm-2 { 280 | background-color: white; 281 | } 282 | 283 | .badge { 284 | background-color: #7D8EF0; 285 | margin-right: 10px; 286 | float: right; 287 | } 288 | 289 | 290 | /* -------------------------------------- 291 | Global Styles 292 | -------------------------------------- */ 293 | 294 | body { 295 | width: 100%; 296 | } 297 | 298 | .main-content { 299 | color: black; 300 | } 301 | 302 | .highlight { 303 | background-color: #72CBFF; 304 | } 305 | 306 | 307 | /* -------------------------------------- 308 | Media Queries 309 | -------------------------------------- */ 310 | 311 | 312 | /* Portrait & landscape phone */ 313 | 314 | @media (max-width: 480px) { 315 | body { 316 | margin-top: 105px; 317 | } 318 | 319 | textarea { 320 | resize: vertical; 321 | width:50%; 322 | } 323 | 324 | .timeline { 325 | overflow: hidden; 326 | width: 100%; 327 | } 328 | 329 | #icons { 330 | text-align: center; 331 | padding: 0; 332 | height: 50%; 333 | line-height: 52px; 334 | float: right; 335 | margin-top: 10px; 336 | } 337 | .mainHeader h3 { 338 | padding: 0px; 339 | text-align: center; 340 | } 341 | 342 | .btn-primary { 343 | width: auto; 344 | } 345 | 346 | .input { 347 | width:100px; 348 | } 349 | 350 | .floating-action-icon { 351 | position: fixed; 352 | bottom: 35px; 353 | right: 20px; 354 | z-index: 101; 355 | width: 50px; 356 | height: 50px; 357 | padding: 10px 10px; 358 | font-size: 24px; 359 | border-radius: 25px; 360 | text-align: center; 361 | } 362 | .modal-dialog { 363 | width: 240px; 364 | } 365 | } 366 | 367 | 368 | /* Landscape phone to portrait tablet */ 369 | 370 | @media (max-width: 768px) and (min-width:481px) { 371 | #icons { 372 | text-align: center; 373 | padding: 0; 374 | height: 50%; 375 | line-height: 52px; 376 | float: right; 377 | margin-top: 10px; 378 | } 379 | 380 | textarea { 381 | resize: vertical; 382 | width: 200px; 383 | } 384 | 385 | body { 386 | margin-top: 105px; 387 | } 388 | 389 | .timeline { 390 | overflow: hidden; 391 | width: 80%; 392 | padding-left: 40px; 393 | } 394 | .mainHeader h3 { 395 | padding: 0px; 396 | text-align: center; 397 | } 398 | .note-lg { 399 | height: 360px; 400 | /*change later*/ 401 | } 402 | .modal-dialog { 403 | width: 250px; 404 | } 405 | } 406 | 407 | 408 | /* Large desktop */ 409 | 410 | @media (max-width: 1400px) and (min-width:769px) { 411 | .timeline { 412 | overflow: hidden; 413 | width: 55%; 414 | margin-left: 20%; 415 | } 416 | 417 | textarea { 418 | resize: vertical; 419 | width: 400px; 420 | } 421 | } 422 | 423 | 424 | /*-------------------------------------- 425 | Sidebar 426 | -------------------------------------- */ 427 | 428 | .sidebar-toggle { 429 | left: 10px !important; 430 | } 431 | 432 | .sidebar-wrapper.sidebar-default.sidebar-open, 433 | .sidebar-wrapper.sidebar-default.sidebar-dragging { 434 | width: 260px; 435 | } 436 | 437 | 438 | /*Modal dialog*/ 439 | 440 | .modal-footer { 441 | padding: 10px 15px 15px; 442 | margin: 0; 443 | border: none; 444 | } 445 | 446 | .modal-body { 447 | padding: 20px 20px 10px 20px; 448 | } 449 | 450 | .modal { 451 | overflow: hidden; 452 | } 453 | -------------------------------------------------------------------------------- /public/static/fonts/glyphiconshalflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thewhitetulip/Tasks-vue/d9da739f0ff5968abdac9555e1321dcf30b931c5/public/static/fonts/glyphiconshalflings-regular.eot -------------------------------------------------------------------------------- /public/static/fonts/glyphiconshalflings-regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thewhitetulip/Tasks-vue/d9da739f0ff5968abdac9555e1321dcf30b931c5/public/static/fonts/glyphiconshalflings-regular.otf -------------------------------------------------------------------------------- /public/static/fonts/glyphiconshalflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thewhitetulip/Tasks-vue/d9da739f0ff5968abdac9555e1321dcf30b931c5/public/static/fonts/glyphiconshalflings-regular.ttf -------------------------------------------------------------------------------- /public/static/fonts/glyphiconshalflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thewhitetulip/Tasks-vue/d9da739f0ff5968abdac9555e1321dcf30b931c5/public/static/fonts/glyphiconshalflings-regular.woff -------------------------------------------------------------------------------- /public/static/js/app.js: -------------------------------------------------------------------------------- 1 | /* 2 | Author: Suraj Patil http://github.com/thewhitetulip 3 | License: MIT 4 | 5 | This is the Vue front end for the Tasks application. We will not be using webpack or any other fancy tech. Plain JS. 6 | You are expected to know a little bit of JS. If you are a total newbie, we recommend reading, 7 | https://github.com/getify/You-Dont-Know-JS 8 | You certainly do not need to be a pro in JS, just need to know enough to follow along, but you do need to read the book 9 | eventually some day to become comfortable with the concepts in JS, so we recommend strongly to read the book before continuing. 10 | */ 11 | 12 | var delimiters = ["${", "}"]; 13 | 14 | // add-comment is the component for adding a comment. 15 | Vue.component('add-comment', { 16 | props:["taskindex", "comment"], 17 | delimiters: delimiters, 18 | data: function() { 19 | return app.comment 20 | }, 21 | template: '
\ 69 | \ 70 | \ 71 |