Преглед изворни кода

Working on orm/templates refactoring

Andrea Fazzi пре 5 година
родитељ
комит
624603b016

+ 2 - 0
main.go

@@ -34,6 +34,8 @@ var (
 	models = []interface{}{
 		&orm.Teacher{},
 		&orm.Department{},
+		&orm.Subject{},
+		&orm.Class{},
 	}
 )
 

+ 76 - 141
orm/class.go

@@ -30,42 +30,49 @@ type Class struct {
 	CoordinatorID uint `schema:"coordinator_id"`
 	MinuterID     uint `schema:"minuter_id"`
 
-	Coordinator Teacher
-	Minuter     Teacher
+	Coordinator *Teacher
+	Minuter     *Teacher
 
 	Teachers   []*Teacher
 	Activities []*Activity
 	Students   []*Student
-}
-
-type ClassForUpdate struct {
-	Class               Class
-	AllTeachers         []*Teacher
-	SelectedCoordinator map[uint]string
-	SelectedMinuter     map[uint]string
-}
 
-type ClassForAdd struct {
-	AllTeachers []*Teacher
+	AllTeachers         []*Teacher      `gorm:"-"`
+	SelectedCoordinator map[uint]string `gorm:"-"`
+	SelectedMinuter     map[uint]string `gorm:"-"`
 }
 
 func (t *Class) GetID() uint    { return t.ID }
 func (c *Class) String() string { return c.Name }
 
-func GetClass(args map[string]string) (interface{}, error) {
-	var class Class
-	if err := DB().First(&class, args["id"]).Error; err != nil {
-		return nil, err
+func (c *Class) Create(args map[string]string, r *http.Request) (interface{}, error) {
+	if r.Method == "GET" {
+		class := new(Class)
+		if err := DB().Find(&class.AllTeachers).Error; err != nil {
+			return nil, err
+		}
+		return class, nil
+	} else {
+		class := new(Class)
+		err := renderer.Decode(class, r)
+		if err != nil {
+			return nil, err
+		}
+		class, err = CreateClass(class)
+		if err != nil {
+			return nil, err
+		}
+
+		return class, nil
 	}
-	return &class, nil
 }
 
-func GetClassAll(args map[string]string) (interface{}, error) {
+func (c *Class) Read(args map[string]string, r *http.Request) (interface{}, error) {
 	var class Class
 
 	id := args["id"]
 
-	if err := DB().First(&class, id).Error; err != nil {
+	if err := DB().Preload("Coordinator").Preload("Minuter").Where("id = ?", id).Find(&class).Error; err != nil {
 		return nil, err
 	}
 
@@ -77,133 +84,79 @@ func GetClassAll(args map[string]string) (interface{}, error) {
 		return nil, err
 	}
 
-	if class.CoordinatorID != 0 {
-		if !DB().First(&class.Coordinator, class.CoordinatorID).RecordNotFound() {
-			if err := DB().First(&class.Coordinator, class.CoordinatorID).Error; err != nil {
-				return nil, err
-			}
-		}
-	}
-
-	if class.MinuterID != 0 {
-		if !DB().First(&class.Minuter, class.MinuterID).RecordNotFound() {
-			if err := DB().First(&class.Minuter, class.MinuterID).Error; err != nil {
-				return nil, err
-			}
-		}
-	}
-
 	return &class, nil
 }
 
-func GetClasses(args map[string]string) (interface{}, error) {
-	var classes []*Class
-	if err := DB().Order("name").Find(&classes).Error; err != nil {
+func (c *Class) ReadAll(args map[string]string, r *http.Request) (interface{}, error) {
+	var classs []*Class
+	if err := DB().Preload("Coordinator").Preload("Minuter").Order("name").Find(&classs).Error; err != nil {
 		return nil, err
 	}
-	return classes, nil
-}
-
-func GetClassesAll(args map[string]string) (interface{}, error) {
-	var classes []*Class
-	if err := DB().Order("name").Find(&classes).Error; err != nil {
-		return nil, err
-	}
-	for _, class := range classes {
+	for _, class := range classs {
 		class.GetTeachers()
 	}
+	return classs, nil
+}
 
-	for _, class := range classes {
-		class.GetActivities()
-	}
-
-	for _, class := range classes {
-		if class.CoordinatorID != 0 {
-			if !DB().First(&class.Coordinator, class.CoordinatorID).RecordNotFound() {
-				if err := DB().First(&class.Coordinator, class.CoordinatorID).Error; err != nil {
-					return nil, err
-				}
-			}
+func (c *Class) Update(args map[string]string, r *http.Request) (interface{}, error) {
+	if r.Method == "GET" {
+		result, err := c.Read(args, r)
+		if err != nil {
+			return nil, err
 		}
 
-		if class.MinuterID != 0 {
-			if !DB().First(&class.Minuter, class.MinuterID).RecordNotFound() {
-				if err := DB().First(&class.Minuter, class.MinuterID).Error; err != nil {
-					return nil, err
-				}
-			}
+		class := result.(*Class)
+
+		if err := DB().Find(&class.AllTeachers).Error; err != nil {
+			return nil, err
 		}
 
-	}
+		class.SelectedMinuter = make(map[uint]string)
+		class.SelectedMinuter[class.MinuterID] = "selected"
 
-	return classes, nil
-}
+		class.SelectedCoordinator = make(map[uint]string)
+		class.SelectedCoordinator[class.CoordinatorID] = "selected"
 
-func SaveClass(class interface{}) (interface{}, error) {
-	if err := DB().Save(class).Error; err != nil {
-		return nil, err
+		return class, nil
+	} else {
+		class, err := c.Read(args, r)
+		if err != nil {
+			return nil, err
+		}
+		err = renderer.Decode(class, r)
+		if err != nil {
+			return nil, err
+		}
+		_, err = SaveClass(class)
+		if err != nil {
+			return nil, err
+		}
+		class, err = c.Read(args, r)
+		if err != nil {
+			return nil, err
+		}
+		return class.(*Class), nil
 	}
-	return class, nil
 }
 
-func UpdateClass(args map[string]string, r *http.Request) (IDer, error) {
-	class, err := GetClass(args)
-	if err != nil {
-		return nil, err
-	}
-	err = renderer.Decode(class, r)
+func (c *Class) Delete(args map[string]string, r *http.Request) (interface{}, error) {
+	class, err := c.Read(args, r)
 	if err != nil {
 		return nil, err
 	}
-	_, err = SaveClass(class)
-	if err != nil {
-		return nil, err
-	}
-	class, err = GetClass(args)
-	if err != nil {
+	if err := DB().Unscoped().Delete(class.(*Class)).Error; err != nil {
 		return nil, err
 	}
 	return class.(*Class), nil
 }
 
-func AddClass(args map[string]string, r *http.Request) (IDer, error) {
-	class := new(Class)
-	err := renderer.Decode(class, r)
-	if err != nil {
-		return nil, err
-	}
-	class, err = CreateClass(class)
-	if err != nil {
-		return nil, err
-	}
-	return class, nil
-}
-
-func CreateClass(class *Class) (*Class, error) {
-	var classes []*Class
-	if err := DB().Where("name=?", class.Name).Find(&classes).Error; err != nil {
-		return nil, err
-	}
-	if len(classes) > 0 {
-		return nil, fmt.Errorf("Class %s already exists!", class.Name)
-	}
-	if err := DB().Create(class).Error; err != nil {
+func SaveClass(class interface{}) (interface{}, error) {
+	if err := DB().Debug().Omit("Coordinator", "Minuter", "Teachers", "Activities", "Students").Save(class).Error; err != nil {
 		return nil, err
 	}
 	return class, nil
 }
 
-func DeleteClass(args map[string]string, r *http.Request) (IDer, error) {
-	class, err := GetClass(args)
-	if err != nil {
-		return nil, err
-	}
-	if err := DB().Unscoped().Delete(class.(*Class)).Error; err != nil {
-		return nil, err
-	}
-	return class.(*Class), nil
-}
-
 func (c *Class) GetTeachers() ([]*Teacher, error) {
 	if err := DB().Raw(selectUniqueClassTeachers, c.ID).Scan(&c.Teachers).Error; err != nil {
 		return nil, err
@@ -218,34 +171,16 @@ func (c *Class) GetActivities() ([]*Activity, error) {
 	return c.Activities, nil
 }
 
-func GetClassForUpdate(args map[string]string) (interface{}, error) {
-	var data ClassForUpdate
-
-	id := args["id"]
-
-	if err := DB().Preload("Coordinator").Preload("Minuter").First(&data.Class, id).Error; err != nil {
+func CreateClass(class *Class) (*Class, error) {
+	var classes []*Class
+	if err := DB().Where("name=?", class.Name).Find(&classes).Error; err != nil {
 		return nil, err
 	}
-
-	if err := DB().Find(&data.AllTeachers).Error; err != nil {
-		return nil, err
+	if len(classes) > 0 {
+		return nil, fmt.Errorf("Class %s already exists!", class.Name)
 	}
-
-	data.SelectedMinuter = make(map[uint]string)
-	data.SelectedMinuter[data.Class.MinuterID] = "selected"
-
-	data.SelectedCoordinator = make(map[uint]string)
-	data.SelectedCoordinator[data.Class.CoordinatorID] = "selected"
-
-	return data, nil
-}
-
-func GetClassForAdd(args map[string]string) (interface{}, error) {
-	var data ClassForAdd
-
-	if err := DB().Find(&data.AllTeachers).Error; err != nil {
+	if err := DB().Create(class).Error; err != nil {
 		return nil, err
 	}
-
-	return data, nil
+	return class, nil
 }

+ 24 - 52
orm/department.go

@@ -16,17 +16,9 @@ type Department struct {
 
 	Subjects []*Subject
 	Teachers []*Teacher
-}
-
-type DepartmentForUpdate struct {
-	Department          Department
-	AllTeachers         []*Teacher
-	SelectedCoordinator map[uint]string
-	SelectedMinuter     map[uint]string
-}
 
-type DepartmentForAdd struct {
-	AllTeachers []*Teacher
+	AllTeachers         []*Teacher      `gorm:"-"`
+	SelectedCoordinator map[uint]string `gorm:"-"`
 }
 
 var (
@@ -49,7 +41,11 @@ func (d *Department) String() string {
 
 func (d *Department) Create(args map[string]string, r *http.Request) (interface{}, error) {
 	if r.Method == "GET" {
-		return nil, nil
+		department := new(Department)
+		if err := DB().Find(&department.AllTeachers).Error; err != nil {
+			return nil, err
+		}
+		return department, nil
 	} else {
 		department := new(Department)
 		err := renderer.Decode(department, r)
@@ -70,7 +66,7 @@ func (d *Department) Read(args map[string]string, r *http.Request) (interface{},
 
 	id := args["id"]
 
-	if err := DB().Where("id = ?", id).Find(&department).Error; err != nil {
+	if err := DB().Preload("Coordinator").Where("id = ?", id).Find(&department).Error; err != nil {
 		return nil, err
 	}
 
@@ -82,14 +78,6 @@ func (d *Department) Read(args map[string]string, r *http.Request) (interface{},
 		return nil, err
 	}
 
-	if department.CoordinatorID != 0 {
-		if !DB().First(&department.Coordinator, department.CoordinatorID).RecordNotFound() {
-			if err := DB().First(&department.Coordinator, department.CoordinatorID).Error; err != nil {
-				return nil, err
-			}
-		}
-	}
-
 	return &department, nil
 }
 
@@ -106,9 +94,22 @@ func (d *Department) ReadAll(args map[string]string, r *http.Request) (interface
 
 func (d *Department) Update(args map[string]string, r *http.Request) (interface{}, error) {
 	if r.Method == "GET" {
-		return d.Read(args, r)
-	} else {
+		result, err := d.Read(args, r)
+		if err != nil {
+			return nil, err
+		}
+
+		department := result.(*Department)
 
+		if err := DB().Find(&department.AllTeachers).Error; err != nil {
+			return nil, err
+		}
+
+		department.SelectedCoordinator = make(map[uint]string)
+		department.SelectedCoordinator[department.CoordinatorID] = "selected"
+
+		return department, nil
+	} else {
 		department, err := d.Read(args, r)
 		if err != nil {
 			return nil, err
@@ -142,7 +143,7 @@ func (d *Department) Delete(args map[string]string, r *http.Request) (interface{
 }
 
 func SaveDepartment(department interface{}) (interface{}, error) {
-	if err := DB().Omit("Teachers", "Subjects").Save(department).Error; err != nil {
+	if err := DB().Debug().Omit("Coordinator", "Teachers", "Subjects").Save(department).Error; err != nil {
 		return nil, err
 	}
 	return department, nil
@@ -169,35 +170,6 @@ func CreateDepartment(department *Department) (*Department, error) {
 	return department, nil
 }
 
-func GetDepartmentForAdd(args map[string]string) (interface{}, error) {
-	var data DepartmentForAdd
-
-	if err := DB().Find(&data.AllTeachers).Error; err != nil {
-		return nil, err
-	}
-
-	return data, nil
-}
-
-func GetDepartmentForUpdate(args map[string]string) (interface{}, error) {
-	var data DepartmentForUpdate
-
-	id := args["id"]
-
-	if err := DB().Preload("Coordinator").First(&data.Department, id).Error; err != nil {
-		return nil, err
-	}
-
-	if err := DB().Find(&data.AllTeachers).Error; err != nil {
-		return nil, err
-	}
-
-	data.SelectedCoordinator = make(map[uint]string)
-	data.SelectedCoordinator[data.Department.CoordinatorID] = "selected"
-
-	return data, nil
-}
-
 func (t *Department) GetTeachers() ([]*Teacher, error) {
 	if err := DB().Raw(selectUniqueDepartmentTeachers, t.ID).Scan(&t.Teachers).Error; err != nil {
 		return nil, err

+ 67 - 96
orm/subject.go

@@ -21,39 +21,46 @@ type Subject struct {
 	Alias string
 
 	DepartmentID uint `schema:"department_id"`
+	Department   *Department
 
 	Teachers   []*Teacher
 	Activities []*Activity
-}
-
-type SubjectForUpdate struct {
-	Subject Subject
-
-	SelectedDepartment map[uint]string
-	AllDepartments     []*Department
-}
 
-type SubjectForAdd struct {
-	AllDepartments []*Department
+	AllDepartments     []*Department   `gorm:"-"`
+	SelectedDepartment map[uint]string `gorm:"-"`
 }
 
 func (s *Subject) GetID() uint    { return s.ID }
 func (s *Subject) String() string { return s.Name }
 
-func GetSubject(args map[string]string) (interface{}, error) {
-	var subject Subject
-	if err := DB().First(&subject, args["id"]).Error; err != nil {
-		return nil, err
+func (s *Subject) Create(args map[string]string, r *http.Request) (interface{}, error) {
+	if r.Method == "GET" {
+		subject := new(Subject)
+		if err := DB().Find(&subject.AllDepartments).Error; err != nil {
+			return nil, err
+		}
+		return subject, nil
+	} else {
+		subject := new(Subject)
+		err := renderer.Decode(subject, r)
+		if err != nil {
+			return nil, err
+		}
+		subject, err = CreateSubject(subject)
+		if err != nil {
+			return nil, err
+		}
+
+		return subject, nil
 	}
-	return &subject, nil
 }
 
-func GetSubjectAll(args map[string]string) (interface{}, error) {
+func (s *Subject) Read(args map[string]string, r *http.Request) (interface{}, error) {
 	var subject Subject
 
 	id := args["id"]
 
-	if err := DB().First(&subject, id).Error; err != nil {
+	if err := DB().Preload("Department").Where("id = ?", id).Find(&subject).Error; err != nil {
 		return nil, err
 	}
 
@@ -61,68 +68,72 @@ func GetSubjectAll(args map[string]string) (interface{}, error) {
 		return nil, err
 	}
 
-	if err := DB().Preload("Teacher").Preload("Subject").Preload("Class").Where("subject_id=?", id).Find(&subject.Activities).Error; err != nil {
-		return nil, err
-	}
-
 	return &subject, nil
 }
 
-func GetSubjects(args map[string]string) (interface{}, error) {
-	var subjects []*Subject
-	if err := DB().Order("name").Find(&subjects).Error; err != nil {
-		return nil, err
-	}
-	return subjects, nil
-}
-
-func GetSubjectsAll(args map[string]string) (interface{}, error) {
+func (s *Subject) ReadAll(args map[string]string, r *http.Request) (interface{}, error) {
 	var subjects []*Subject
-	if err := DB().Order("name").Find(&subjects).Error; err != nil {
+	if err := DB().Preload("Department").Order("name").Find(&subjects).Error; err != nil {
 		return nil, err
 	}
 	for _, subject := range subjects {
 		subject.GetTeachers()
 	}
-
 	return subjects, nil
 }
 
-func SaveSubject(subject interface{}) (interface{}, error) {
-	if err := DB().Save(subject).Error; err != nil {
-		return nil, err
+func (s *Subject) Update(args map[string]string, r *http.Request) (interface{}, error) {
+	if r.Method == "GET" {
+		result, err := s.Read(args, r)
+		if err != nil {
+			return nil, err
+		}
+
+		subject := result.(*Subject)
+
+		if err := DB().Find(&subject.AllDepartments).Error; err != nil {
+			return nil, err
+		}
+
+		subject.SelectedDepartment = make(map[uint]string)
+		subject.SelectedDepartment[subject.DepartmentID] = "selected"
+
+		return subject, nil
+	} else {
+		subject, err := s.Read(args, r)
+		if err != nil {
+			return nil, err
+		}
+		err = renderer.Decode(subject, r)
+		if err != nil {
+			return nil, err
+		}
+		_, err = SaveSubject(subject)
+		if err != nil {
+			return nil, err
+		}
+		subject, err = s.Read(args, r)
+		if err != nil {
+			return nil, err
+		}
+
+		return subject.(*Subject), nil
 	}
-	return subject, nil
 }
 
-func UpdateSubject(args map[string]string, r *http.Request) (IDer, error) {
-	subject, err := GetSubject(args)
-	if err != nil {
-		return nil, err
-	}
-	err = renderer.Decode(subject, r)
+func (s *Subject) Delete(args map[string]string, r *http.Request) (interface{}, error) {
+	subject, err := s.Read(args, r)
 	if err != nil {
 		return nil, err
 	}
-	_, err = SaveSubject(subject)
-	if err != nil {
-		return nil, err
-	}
-	subject, err = GetSubject(args)
-	if err != nil {
+	if err := DB().Unscoped().Delete(subject.(*Subject)).Error; err != nil {
 		return nil, err
 	}
 	return subject.(*Subject), nil
 }
 
-func AddSubject(args map[string]string, r *http.Request) (IDer, error) {
-	subject := new(Subject)
-	err := renderer.Decode(subject, r)
-	if err != nil {
-		return nil, err
-	}
-	subject, err = CreateSubject(subject)
-	if err != nil {
+func SaveSubject(subject interface{}) (interface{}, error) {
+	if err := DB().Omit("Department").Save(subject).Error; err != nil {
 		return nil, err
 	}
 	return subject, nil
@@ -143,49 +154,9 @@ func CreateSubject(subject *Subject) (*Subject, error) {
 	return subject, nil
 }
 
-func DeleteSubject(args map[string]string, r *http.Request) (IDer, error) {
-	subject, err := GetSubject(args)
-	if err != nil {
-		return nil, err
-	}
-	if err := DB().Unscoped().Delete(subject.(*Subject)).Error; err != nil {
-		return nil, err
-	}
-	return subject.(*Subject), nil
-}
-
 func (c *Subject) GetTeachers() ([]*Teacher, error) {
 	if err := DB().Raw(selectUniqueSubjectTeachers, c.ID).Scan(&c.Teachers).Error; err != nil {
 		return nil, err
 	}
 	return c.Teachers, nil
 }
-
-func GetSubjectForUpdate(args map[string]string) (interface{}, error) {
-	var data SubjectForUpdate
-
-	id := args["id"]
-
-	if err := DB().First(&data.Subject, id).Error; err != nil {
-		return nil, err
-	}
-
-	if err := DB().Find(&data.AllDepartments).Error; err != nil {
-		return nil, err
-	}
-
-	data.SelectedDepartment = make(map[uint]string)
-	data.SelectedDepartment[data.Subject.DepartmentID] = "selected"
-
-	return data, nil
-}
-
-func GetSubjectForAdd(args map[string]string) (interface{}, error) {
-	var data SubjectForAdd
-
-	if err := DB().Find(&data.AllDepartments).Error; err != nil {
-		return nil, err
-	}
-
-	return data, nil
-}

+ 5 - 1
renderer/funcmap.go

@@ -129,7 +129,11 @@ func query(values ...string) template.URL {
 	return template.URL(urlValues.Encode())
 }
 
-func convertDate(t time.Time) string {
+func convertDate(value interface{}) string {
+	t, ok := value.(time.Time)
+	if !ok {
+		return ""
+	}
 	return fmt.Sprintf("%d-%02d-%02d", t.Year(), t.Month(), t.Day())
 }
 

+ 27 - 39
templates/classes.html.tpl

@@ -1,45 +1,33 @@
 {{ define "content" }}
 
-<div class="container">
-  
-  <div class="karmen-info-header">
-    <div class="row">
-      <div class="col-md-8">
-	<h1>Classi ({{len .Data}})</h1>
-      </div>
-      <div class="col-md-4">
-	<div class="btn-group float-right">
+<div class="container">  
 
-	  <a href="/classes/add/?{{query "tpl_layout" "base" "tpl_content" "classes_add_update"}}" class="btn btn-primary">
-	    <span class="fa fa-plus-circle" aria-hidden="true"></span>
-	    Crea nuova classe
-	  </a>
-	  
-	</div>
+  {{$options := `
+  title: "Classi"
+  buttonTitle: "Crea nuova classe"
+  `}}
+  
+  {{template "read_all_header" dict  "options" ($options | yaml) "lengthData" (len .Data) "modelPath" (create "class")}}
+  {{template "search_input"}}
+    
+  {{if not .}}
+  {{template "display_no_elements"}}
+  {{else}}
+  <div class="list-group" id="myUL">
+    {{range $class := .Data}}
+    <a class="list-group-item list-group-item-action" href={{$class.ID|show "class"}}>
+      <span class="fa fa-user"></span>
+      {{$class.Name}}
+      <div class="text-right">
+        {{$options := `noElements: "no docenti"`}}
+        {{template "small" dict "options" ($options | yaml) "data" $class.Teachers}}
       </div>
-    </div>
-
-    <div class="input-group" style="margin-bottom: 20px">
-      <span class="input-group-addon" id="search-query"><span class="glyphicon glyphicon-search"></span></span>
-      <input type="text" id="myInput" class="form-control" aria-describedby="search-query">
-    </div>
-    {{if not .Data}}
-    <p>Non c'è alcun elemento da visualizzare.</p>
-    {{else}}
-    <div class="list-group" id="myUL">
-      {{range $class := .Data}}
-      <a class="list-group-item list-group-item-action list-group-item-action" href="/classes/{{$class.ID}}?{{query "tpl_layout" "base" "tpl_content" "classes_show"}}">
-	<span class="fa fa-users"></span>
-	{{$class.Name}}
-	<div class="text-right">
- 	  {{range $teacher := $class.Teachers}}
-	  <small>{{$teacher.Surname}}</small>
-	  {{end}}
-	</div>
-      </a>
-      {{end}}
-    </div>
+    </a>
+    {{end}}
     {{end}}
   </div>
-  
-  {{ end }}
+
+</div>
+
+{{ end }}
+

+ 42 - 95
templates/classes_add_update.html.tpl

@@ -2,106 +2,53 @@
 
 <div class="container">
 
-  {{if .Options.Get "update"}}
-  <nav aria-label="breadcrumb">
-    <ol class="breadcrumb">
-      <li class="breadcrumb-item"><a href="/classes?{{query "tpl_layout" "base" "tpl_content" "teachers"}}">Classi</a></li>
-      <li class="breadcrumb-item"><a href="/classes/{{.Data.Class.ID}}?{{query "tpl_layout" "base" "tpl_content" "classes"}}">{{.Data.Class.Name}}</a></li>
-      <li class="breadcrumb-item active"><a href="#">Aggiorna la classe</a></li>
-    </ol>
-  </nav>
-  {{else}}
-  <nav aria-label="breadcrumb">
-    <ol class="breadcrumb">
-      <li class="breadcrumb-item"><a href="/classes/?{{query "tpl_layout" "base" "tpl_content" "classes"}}">Classi</a></li>
-      <li class="breadcrumb-item active"><a href="#">Aggiungi</a></li>
-    </ol>
-  </nav>
-  {{end}}
+  {{$update := .Options.Get "update"}}
 
-  {{if .Options.Get "update"}}
-  <h1 class="karmen-info-header">Aggiorna la classe "{{.Data.Class.Name}}"</h1>
+  {{if $update}}
+  {{template "breadcrumb" toSlice "Classi" (all "Class") (.Data|string) (.Data.ID|show "Class") "Aggiorna" "current"}}
   {{else}}
-  <h1 class="karmen-info-header">Crea una nuova classe</h1>
+  {{template "breadcrumb" toSlice "Classi" (all "Class") "Aggiungi" "current"}}
   {{end}}
+  
+  {{template "add_update_header" dict "update" $update "addTitle" "Crea nuova classe" "updateTitle" (printf "Aggiorna la classe %s" (.Data|string))}}
 
-  {{if .Options.Get "update"}}
-  <form id="form_classes_add_update" action="/classes/{{.Data.Class.ID}}/update" method="POST" role="form" class="needs-validation">
-  {{else}}
-  <form id="form_classes_add_update" action="/classes/add/" method="POST" role="form" class="needs-validation">
-  {{end}}  
-    
-    <div class="form-group">
-      <label class="control-label" for="class_name">Nome</label>
-      <input type="text" name="Name" class="form-control" id="class_name" placeholder="Nome" {{if .Options.Get "update"}} value="{{.Data.Class.Name}}" {{end}} required>
-    </div>
-
-    <div class="form-group">
-      <label class="control-label" for="class_year">Anno</label>
-      <input type="number" min="1" name="Year" class="form-control" id="class_year" placeholder="Annualità" {{if .Options.Get "update"}} value="{{.Data.Class.Year}}" {{end}} required>
-    </div>
-    
-    <div class="form-group">
-      <label class="control-label" for="class_name">Sezione</label>
-      <input type="text" name="Section" class="form-control" id="class_section" placeholder="Sezione" {{if .Options.Get "update"}} value="{{.Data.Class.Section}}" {{end}} required>
-    </div>
-
-    <div class="form-group">
-      <label class="control-label" for="class_field">Indirizzo</label>
-      <input type="text" name="Field" class="form-control" id="class_field" placeholder="Indirizzo" {{if .Options.Get "update"}} value="{{.Data.Class.Field}}" {{end}} required>
-    </div>
-
-    <div class="form-group">
-      <label class="control-label" for="class_alias">Nome alternativo</label>
-      <input type="text" name="Alias" class="form-control" id="class_alias" placeholder="Nome alternativo" {{if .Options.Get "update"}} value="{{.Data.Class.Alias}}" {{end}}>
-    </div>
-
-    <div class="form-group">
-      <label class="control-label" for="coordinator_id">Coordinatore</label>
-      <select name="coordinator_id" class="form-control selectpicker" id="coordinator_id" placeholder="Coordinatore" data-live-search="true" form="form_classes_add_update" title="Seleziona il nome del coordinatore" data-dropup-auto="false">
-	<option value="0"></option>
-  	{{range $teacher := .Data.AllTeachers}}
-	{{if $.Options.Get "update"}}
-  	<option
-	   value="{{$teacher.ID}}"
-	   {{index $.Data.SelectedCoordinator $teacher.ID}}>{{$teacher.Name}} {{$teacher.Surname}}
-	</option>
-	{{else}}
-  	<option value="{{$teacher.ID}}">{{$teacher.Name}} {{$teacher.Surname}}</option>
-	{{end}}
-  	{{end}}
-      </select>
-    </div>
-
-    
-    <div class="form-group">
-      <label class="control-label" for="minuter_id">Verbalizzante</label>
-      <select name="minuter_id" class="form-control selectpicker" id="minuter_id" placeholder="Verbalizzante" data-live-search="true" form="form_classes_add_update" title="Seleziona il nome del verbalizzante" data-dropup-auto="false">
-	<option value="0"></option>
-  	{{range $teacher := .Data.AllTeachers}}
-	{{if $.Options.Get "update"}}
-  	<option
-	   value="{{$teacher.ID}}"
-	   {{index $.Data.SelectedMinuter $teacher.ID}}>{{$teacher.Name}} {{$teacher.Surname}}
-	</option>
-	{{else}}
-  	<option value="{{$teacher.ID}}">{{$teacher.Name}} {{$teacher.Surname}}</option>
-	{{end}}
-  	{{end}}
-      </select>
-    </div>
-
-    <div class="form-group">
-      <button type="submit" class="btn btn-primary">Salva</button>
-      {{if .Options.Get "update"}}
-      <a href="/classes/{{.Data.Class.ID}}?{{query "tpl_layout" "base" "tpl_content" "classes_show"}}" class="btn btn-default">Annulla</a>
-      {{else}}
-      <a href="/classes/?{{query "tpl_layout" "base" "tpl_content" "classes"}}" class="btn btn-default">Annulla</a>
-      {{end}}
-    </div>
-    
-  </form>
+  {{$form := "form_classes_add_update"}}
+  <form
+    class="needs-validation"
+    action="{{if $update}}{{.Data.ID|update "Class"}}{{else}}{{create "Class"}}{{end}}"
+    method="POST"
+    role="form"
+    id={{$form}}>
+
+    {{$options := ` { name: "Name",id: "class_name",label: "Nome",placeholder: "Nome",type: "text",required: "true"} `}}
+    {{template "input" dict "options" ($options|yaml) "value" (.Data|field "Name") "update" $update}}
+
+    {{$options := ` { name: "Alias",id: "class_alias",label: "Nome alternativo",placeholder: "Nome alternativo",type: "text"} `}}
+    {{template "input" dict "options" ($options|yaml) "value" (.Data|field "Alias") "update" $update}}
+
+    {{$options := ` { name: "Year",id: "class_year",label: "Anno",placeholder: "",type: "number",required: "true"} `}}
+    {{template "input" dict "options" ($options|yaml) "value" (.Data|field "Year") "update" $update}}
+
+    {{$options := ` { name: "Section",id: "class_section",label: "Sezione",placeholder: "Sezione",type: "text",required: "true"} `}}
+    {{template "input" dict "options" ($options|yaml) "value" (.Data|field "Section") "update" $update}}
 
+    {{$options := ` { name: "Field",id: "class_field",label: "Indirizzo",placeholder: "Indirizzo",type: "text",required: "true"} `}}
+    {{template "input" dict "options" ($options|yaml) "value" (.Data|field "Field") "update" $update}}
+
+    {{$options := ` { name: "coordinator_id", id: "coordinator_id", label: "Coordinatore", title: "Seleziona il coordinatore"}`}}
+    {{template "select" dict "options" ($options|yaml) "data" (.Data|field "AllTeachers") "selected" (.Data|field "SelectedCoordinator") "update" $update "form" $form}}
+
+    {{$options := ` { name: "minuter_id", id: "minuter_id", label: "Verbalizzante", title: "Seleziona il verbalizzante"}`}}
+    {{template "select" dict "options" ($options|yaml) "data" (.Data|field "AllTeachers") "selected" (.Data|field "SelectedMinuter") "update" $update "form" $form}}
+
+    {{ $options := ` { cancelTitle: "Annulla", saveTitle: "Salva", model: "Class"} ` }}
+    {{template "submit_cancel_buttons" dict "options" ($options|yaml) "id" (.Data|field "ID") "update" $update}}
+  
+  </form>
+  
 </div>
 
 {{ end }}
+
+
+

+ 28 - 79
templates/classes_show.html.tpl

@@ -2,91 +2,40 @@
 
 <div class="container">
 
-  <nav aria-label="breadcrumb">
-    <ol class="breadcrumb">
-      <li class="breadcrumb-item"><a href="/classes?{{query "tpl_content" "classes" "tpl_layout" "base"}}">Classi</a></li>
-      <li class="breadcrumb-item active"><a href="#">{{.Data.Name}}</a></li>
-    </ol>
-  </nav>
+  {{template "breadcrumb" toSlice "Classi" (all "Class") (.Data|string) "current"}}
+  {{template "show_header" dict "title" (.Data|string) "updatePath" (.Data.ID|update "Class") "deletePath" (.Data.ID|delete "Class")}}
 
+  <h2 class="karmen-relation-header">Informazioni generali</h2>
+  
+  <p>Questa classe appartiene all'indirizzo <strong>{{.Data.Field}}</strong>.</p>
 
-  <div class="karmen-info-header">
-    <div class="row">
-      <div class="col-md-8">
-	<h1>{{.Data.Name}}</h1>
-      </div>
-      <div class="col-md-4">
-	<div class="btn-group float-right" role="group">
-	  <a href="/classes/{{.Data.ID}}/update?{{query "tpl_layout" "base" "tpl_content" "classes_add_update" "update" "true"}}" class="btn btn-primary">
-	    <span class="fa fa-edit" aria-hidden="true"></span>
-	    Modifica
-	  </a>
-	  <button href="/classes/{{.Data.ID}}/delete"
-		  data-url="/classes/{{.Data.ID}}/delete"
-		  class="btn btn-danger karmen-ajax-delete">
-	    <span class="fa fa-trash" aria-hidden="true"></span>
-	    Elimina
-	  </button>
-	</div>
-      </div>
-    </div>
-  </div>
-
-  <h2 class="karmen-relation-header">Attività della {{.Data.Name}}</h2>
-  <div class="list-group" id="classes_list_group">
-    {{if not .Data.Teachers}}
-    <p>Alla classe non è associata alcuna attività
-	didattica. Clicca <a href="/activities/add">qui</a> per creare
-	una nuova attività didattica da associare alla classe.</p>
-    {{else}}
-    {{range $activity := .Data.Activities}}
-      <a href="/activities/{{$activity.ID}}?{{query "tpl_layout" "base" "tpl_content" "activities_show"}}" class="list-group-item list-group-item-action">
-	<span class="fa fa-user"></span>
-	{{if $activity.Teacher}}{{$activity.Teacher.Surname}} {{$activity.Teacher.Name}}{{else}}no docente{{end}}
-	<div class="text-right">
-	  <small>{{if $activity.Subject}}{{$activity.Subject.Name}}{{else}}no materia{{end}} {{$activity.Hours}}h</small>
-	</div>
-      </a>
-    {{end}}
-    {{end}}
-  </div>
-
-  <h2 class="karmen-relation-header">Coordinatore e verbalizzante</h2>
-  <div class="list-group" id="classes_list_group">
-    {{if not .Data.Teachers}}
-    <p>Alla classe non è associata alcuna attività
-	didattica. Clicca <a href="/activities/add">qui</a> per creare
-	una nuova attività didattica da associare alla classe.</p>
+  {{if .Data.Coordinator}}
+  <p>Il coordinatore è il docente {{(.Data.Coordinator.ID|show "Teacher")|anchor (.Data.Coordinator|string)}}.
     {{else}}
+  <p>Alla classe non è associato nessun coordinatore. Clicca {{(.Data.ID|update "Class")|anchor "qui"}} per associare un coordinatore alla classe.</p>
+  {{end}}
 
-    {{if ne .Data.Coordinator.ID 0}}
-    <a href="/teachers/{{.Data.Coordinator.ID}}?{{query "tpl_layout" "base" "tpl_content" "teachers_show"}}" class="list-group-item list-group-item-action">
-      <span class="fa fa-user"></span>
-      {{.Data.Coordinator.Name}} {{.Data.Coordinator.Surname}}
-      <div class="text-right">
-	<small>Coordinatore</small>
-      </div>
-    </a>
+  {{if .Data.Minuter}}
+  <p>Il verbalizzante è il docente {{(.Data.Minuter.ID|show "Teacher")|anchor (.Data.Minuter|string)}}.
     {{else}}
-    <span class="list-group-item list-group-item-action">Nessun coordinatore</span>
-    {{end}}
-
-    {{if ne .Data.Minuter.ID 0}}
-    <a href="/teachers/{{.Data.Minuter.ID}}?{{query "tpl_layout" "base" "tpl_content" "teachers_show"}}" class="list-group-item list-group-item-action">
-      <span class="fa fa-user"></span>
-      {{.Data.Minuter.Name}} {{.Data.Minuter.Surname}}
-      <div class="text-right">
-	<small>Verbalizzante</small>
-      </div>
-    </a>
-    {{else}}
-    <span class="list-group-item list-group-item-action">Nessun verbalizzante</span>
-    {{end}}
- 
-    {{end}}
+  <p>Alla classe non è associato nessun verbalizzante. Clicca {{(.Data.ID|update "Class")|anchor "qui"}} per associare un verbalizzante alla classe.</p>
+  {{end}}
+
+  <div class="row">
+    <div class="col-md-12">
+
+      {{$options := `
+      title: "Attività associate alla classe"
+      model: "Activity"
+      icon: "fa fa-business"
+      `}}
+      
+      {{$noElements := "Nessuna attività associata alla classe."}}
+      {{template "relation_list" dict "options" ($options|yaml) "data" .Data.Activities "noElements" $noElements "small" (toSlice "Teacher")}}
+    
+    </div>
   </div>
-
-
+  
 </div>    
 
 {{ end }}

+ 21 - 60
templates/departments_add_update.html.tpl

@@ -2,74 +2,35 @@
 
 <div class="container">
 
-  {{if .Options.Get "update"}}
-  <nav aria-label="breadcrumb">
-    <ol class="breadcrumb">
-      <li class="breadcrumb-item"><a href="/departments?{{query "tpl_layout" "base" "tpl_content" "departments"}}">Dipartimento</a></li>
-      <li class="breadcrumb-item active"><a href="#">Aggiorna il dipartimento</a></li>
-    </ol>
-  </nav>
-  {{else}}
-  <nav aria-label="breadcrumb">
-    <ol class="breadcrumb">
-      <li class="breadcrumb-item"><a href="/departments?{{query "tpl_layout" "base" "tpl_content" "departments"}}">Dipartimento</a></li>
-      <li class="breadcrumb-item active"><a href="#">Aggiungi</a></li>
-    </ol>
-  </nav>
-  {{end}}
-
- {{if .Options.Get "update"}}
-  <div class="karmen-info-header">
-    <div class="row">
-      <div class="col-md-8">
-	<h1>Aggiorna il dipartimento</h1>
-      </div>
-    </div>
-  </div>
-  
-  {{else}}
-  <h1 class="karmen-info-header">Crea nuovo dipartimento</h1>
-  {{end}}
+  {{$update := .Options.Get "update"}}
 
-  {{if .Options.Get "update"}}
-  <form id="form_departments_add_update" action="/departments/{{.Data.Department.ID}}/update" method="POST" role="form" class="needs-validation">
+  {{if $update}}
+  {{template "breadcrumb" toSlice "Dipartimenti" (all "Department") (.Data|string) (.Data.ID|show "Department") "Aggiorna" "current"}}
   {{else}}
-  <form id="form_departments_add_update" action="/departments/add/" method="POST" role="form" class="needs-validation">
+  {{template "breadcrumb" toSlice "Dipartimenti" (all "Department") "Aggiungi" "current"}}
   {{end}}
+  
+  {{template "add_update_header" dict "update" $update "addTitle" "Crea nuovo dipartimento" "updateTitle" (printf "Aggiorna dipartimento %s" (.Data|string))}}
 
-    <div class="form-group">
-      <label class="control-label" for="department_name">Nome</label>
-      <input type="text" name="Name" class="form-control" id="department_name" placeholder="Nome" {{if .Options.Get "update"}} value="{{.Data.Department.Name}}" {{end}} required>
-    </div>
+  {{$form := "form_departments_add_update"}}
+  <form
+    class="needs-validation"
+    action="{{if $update}}{{.Data.ID|update "Department"}}{{else}}{{create "Department"}}{{end}}"
+    method="POST"
+    role="form"
+    id={{$form}}>
 
-    <div class="form-group">
-      <label class="control-label" for="coordinator_id">Coordinatore</label>
-      <select name="coordinator_id" class="form-control selectpicker" id="coordinator_id" placeholder="Coordinatore" data-live-search="true" form="form_departments_add_update" title="Seleziona il nome del coordinatore" data-dropup-auto="false">
-	<option value="0"></option>
-  	{{range $teacher := .Data.AllTeachers}}
-	{{if $.Options.Get "update"}}
-  	<option
-	  value="{{$teacher.ID}}"
-	  {{index $.Data.SelectedCoordinator $teacher.ID}}>{{$teacher.Name}} {{$teacher.Surname}}
-	</option>
-	{{else}}
-  	<option value="{{$teacher.ID}}">{{$teacher.Name}} {{$teacher.Surname}}</option>
-	{{end}}
-  	{{end}}
-      </select>
-    </div>
+    {{$options := ` { name: "Name",id: "department_name",label: "Nome",placeholder: "Nome",type: "text",required: "true"} `}}
+    {{template "input" dict "options" ($options|yaml) "value" (.Data|field "Name") "update" $update}}
 
-    <div class="form-group">
-      <button type="submit" class="btn btn-primary">Salva</button>
-      {{if .Options.Get "update"}}
-      <a href="/departments/{{.Data.Department.ID}}?{{query "tpl_layout" "base" "tpl_content" "departments_show"}}" class="btn btn-default">Annulla</a>
-      {{else}}
-      <a href="/departments/?{{query "tpl_layout" "base" "tpl_content" "departments"}}" class="btn btn-default">Annulla</a>
-      {{end}}
-    </div>
+    {{$options := ` { name: "coordinator_id", id: "coordinator_id", label: "Coordinatore", title: "Seleziona il coordinatore"}`}}
+    {{template "select" dict "options" ($options|yaml) "data" (.Data|field "AllTeachers") "selected" (.Data|field "SelectedCoordinator") "update" $update "form" $form}}
     
+    {{ $options := ` { cancelTitle: "Annulla", saveTitle: "Salva", model: "Department"} ` }}
+    {{template "submit_cancel_buttons" dict "options" ($options|yaml) "id" (.Data|field "ID") "update" $update}}
+  
   </form>
-
+  
 </div>
 
 {{ end }}

+ 35 - 83
templates/departments_show.html.tpl

@@ -2,95 +2,47 @@
 
 <div class="container">
 
-  <nav aria-label="breadcrumb">
-    <ol class="breadcrumb">
-      <li class="breadcrumb-item"><a href="/departments?{{query "tpl_layout" "base" "tpl_content" "departments"}}">Dipartimenti</a></li>
-      <li class="breadcrumb-item active"><a href="#">{{.Data.Name}}</a></li>
-    </ol>
-  </nav>
-
-  <div class="karmen-info-header">
-    <div class="row">
-      <div class="col-md-8">
-	<h1>Dipartimento di {{.Data.Name}}</h1>
-      </div>
-      <div class="col-md-4">
-
-	<div class="btn-group float-right" role="group">
-	  <a href="/departments/add/?{{query "tpl_layout" "base" "tpl_content" "departments_add_update"}}" class="btn btn-success">
-	    <span class="fa fa-edit" aria-hidden="true"></span>
-	    Crea
-	  </a>
-
-	  <a href="/departments/{{.Data.ID}}/update?{{query "tpl_layout" "base" "tpl_content" "departments_add_update" "update" "true"}}"  class="btn btn-primary">
-	    <span class="fa fa-edit" aria-hidden="true"></span>
-	    Modifica
-	  </a>
-	  <button href="/departments/{{.Data.ID}}/delete"
-		  data-url="/departments/{{.Data.ID}}/delete"
-		  class="btn btn-danger karmen-ajax-delete">
-	    <span class="fa fa-trash" aria-hidden="true"></span>
-	    Elimina
-	  </button>
-	</div>
+  {{template "breadcrumb" toSlice "Dipartimenti" (all "Department") (.Data|string) "current"}}
+  {{template "show_header" dict "title" (.Data|string) "updatePath" (.Data.ID|update "Department") "deletePath" (.Data.ID|delete "Department")}}
+
+  {{if .Data.Coordinator}}
+  <p>Il coordinatore di questo dipartimento è {{(.Data.Coordinator.ID|show "Teacher")|anchor (.Data.Coordinator|string)}}.</p>
+  {{else}}
+  <p>Il dipartimento non ha coordinatore. Clicca {{(.Data.ID|update "Department")|anchor "qui"}} per aggiungere un coordinatore.</p>
+  {{end}}
+  
+  <div class="row">
+    <div class="col-md-12">
 
-      </div>
+      {{$options := `
+      title: "Materie afferenti al dipartimento"
+      model: "Subject"
+      icon: "fa fa-book"
+      `}}
+      
+      {{$noElements := "Nessuna materia associata al dipartimento."}}
+      {{template "relation_list" dict "options" ($options|yaml) "data" .Data.Subjects "noElements" $noElements}}
+    
     </div>
   </div>
-
+  
   <div class="row">
-
     <div class="col-md-12">
-      <h2 class="karmen-relation-header">Coordinatore del dipartimento</h2>
-      <div class="list-group" id="departments_list_group">
-	{{if ne .Data.Coordinator.ID 0}}
-	<a href="/teachers/{{.Data.Coordinator.ID}}?{{query "tpl_layout" "base" "tpl_content" "teachers_show"}}" class="list-group-item list-group-item-action">
-	  <span class="fa fa-user"></span>
-	  {{.Data.Coordinator.Surname}} {{.Data.Coordinator.Name}}
-	  <div class="text-right">
-	    <small>Coordinatore</small>
-	  </div>
-	</a>
-	{{else}}
-	<span class="list-group-item list-group-item-action">Nessun coordinatore</span>
-	{{end}}
-      </div>
+
+      {{$options := `
+      title: "Docenti"
+      model: "Teacher"
+      icon: "fa fa-users"
+      `}}
+      
+      {{$noElements := "Nessun docente associato al dipartimento."}}
+      {{template "relation_list" dict "options" ($options|yaml) "data" .Data.Teachers "noElements" $noElements}}
+
     </div>
     
-    <div class="col-md-12">
-      <h2 class="karmen-relation-header">Docenti del dipartimento</h2>
-      {{if not .Data.Teachers}}
-      <p>Nel dipartimento non è presente alcun docente
-	didattica. Clicca <a href="/activities/add/?{{query "tpl_layout" "base" "tpl_content" "activities_add_update"}}">qui</a> per creare
-	una nuova attività didattica.</p>
-      {{else}}
-      <div class="list-group" id="teachers_list_group">
-	{{range $teacher := .Data.Teachers}}
-	<a class="list-group-item list-group-item-action" href="/teachers/{{$teacher.ID}}?{{query "tpl_layout" "base" "tpl_content" "teachers_show"}}">
-	  <span class="fa fa-user"></span>
-	  {{$teacher.Surname}} {{$teacher.Name}}
-	</a>
-	{{end}}
-      </div>
-      {{end}}
-    </div>    
+  </div>
 
-    <div class="col-md-12">
-      <h2 class="karmen-relation-header">Materie afferenti al dipartimento</h2>
-      {{if not .Data.Teachers}}
-      <p>Nel dipartimento non è presente alcuna materia
-	didattica. Clicca <a href="/subjects?{{query "tpl_layout" "base" "tpl_content" "subjects"}}">qui</a> per visualizzare le materie.</p>
-      {{else}}
-      <div class="list-group" id="subjects_list_group">
-	{{range $subject := .Data.Subjects}}
-	<a class="list-group-item list-group-item-action" href="/subjects/{{$subject.ID}}?{{query "tpl_layout" "base" "tpl_content" "subjects_show"}}">
-	  <span class="fa fa-book"></span>
-	  {{$subject.Name}}
-	</a>
-	{{end}}
-	
-      </div>
-      {{end}}
-    </div>    
+  
+</div>    
 
-    {{ end }}
+{{ end }}

+ 10 - 0
templates/layout/checkbox.html.tpl

@@ -0,0 +1,10 @@
+{{define "checkbox"}}
+<div class="{{if .options.formClass}}{{.options.formClass}}{{else}}form-group{{end}}">
+  <input type="checkbox"
+         name="{{.options.name}}"
+         class="form-check-input"
+         id="{{.options.id}}"
+         {{if .update}} value="{{.value}}" {{end}} {{.options.required}}>
+  <label class="form-check-label" for="{{.options.id}}">{{.options.label}}</label>
+</div>
+{{end}}

+ 2 - 2
templates/layout/delete_button.html.tpl

@@ -1,6 +1,6 @@
 {{define "delete_button"}}
-<button href="/teachers/{{.Data.ID}}/delete"
-	data-url="/teachers/{{.Data.ID}}/delete"
+<button href="{{.modelPath}}"
+	data-url="{{.modelPath}}"
 	class="btn btn-danger karmen-ajax-delete">
   <span class="fa fa-trash" aria-hidden="true"></span>
   Elimina

+ 3 - 3
templates/layout/input.html.tpl

@@ -1,10 +1,10 @@
 {{define "input"}}
-<div class="form-group">
+<div class="{{if .options.formClass}}{{.options.formClass}}{{else}}form-group{{end}}">
   <label class="control-label" for="{{.options.id}}">{{.options.label}}</label>
   <input type="{{.options.type}}"
          name="{{.options.name}}"
-         class="form-control"
+         class="{{if .options.inputClass}}{{.options.inputClass}}{{else}}form-control{{end}}"
          id="{{.options.id}}"
-         placeholder="{{.options.placeholder}}" {{if .update}} value="{{.value}}" {{end}} {{.options.required}}>
+         placeholder="{{.options.placeholder}}" {{if .update}}value="{{.value}}"{{end}} {{if .options.required}}required{{end}}>
 </div>
 {{end}}

+ 8 - 0
templates/layout/relation_list.html.tpl

@@ -6,6 +6,14 @@
   <a href="{{$el.ID | show $.options.model}}" class="list-group-item list-group-item-action">
     <span class="{{$.options.icon}}"></span>
     {{$el | string}}
+    {{if $.small}}
+    {{range $s := $.small}}
+    <div class="text-right">
+      {{$options := `noElements: "nessun elemento"`}}
+      {{template "small" dict "options" ($options | yaml) "data" ($el|field $s)}}
+    </div>
+    {{end}}
+    {{end}}
     {{end}}
   </a>
 </div>

+ 25 - 0
templates/layout/select.html.tpl

@@ -0,0 +1,25 @@
+{{define "select"}}
+<div class="form-group">
+  <label class="control-label" for="{{.options.id}}">{{.options.label}}</label>
+  <select name="{{.options.name}}"
+          class="form-control selectpicker"
+          id="{{.options.id}}"
+          placeholder="{{.options.placeholder}}"
+          data-live-search="true"
+          form="{{.form}}"
+          title="{{.options.title}}"
+          data-dropup-auto="false">
+    <option value="0"></option>
+    {{range $el := .data}}
+    {{if $.update}}
+    <option
+      value="{{$el.ID}}"
+      {{index $.selected $el.ID}}>{{$el|string}}
+    </option>
+    {{else}}
+    <option value="{{$el.ID}}">{{$el|string}}</option>
+    {{end}}
+    {{end}}
+  </select>
+</div>
+{{end}}

+ 1 - 1
templates/layout/small.html.tpl

@@ -2,7 +2,7 @@
 {{if .data}}
 {{if .data | isSlice}}
 {{range $el := .data}}
-<small>{{$el.Name}}</small>
+<small>{{$el|string}}</small>
 {{end}}
 {{else}}
 <small>{{.data|string}}</small>

+ 10 - 0
templates/layout/submit_cancel_button.html.tpl

@@ -0,0 +1,10 @@
+{{define "submit_cancel_buttons"}}
+<div class="form-group">
+  <button type="submit" class="btn btn-primary">{{.options.saveTitle}}</button>
+  {{if .options.update}}
+  <a href="{{.id|show .options.model}}" class="btn btn-default">Annulla</a>
+  {{else}}
+  <a href="{{all .options.model}}" class="btn btn-default">Annulla</a>
+  {{end}}
+</div>
+{{end}}

+ 19 - 35
templates/subjects.html.tpl

@@ -1,49 +1,33 @@
 {{ define "content" }}
 
-<div class="container">
-  
-  <div class="karmen-info-header">
-    <div class="row">
-      <div class="col-md-8">
-	<h1>Materie ({{len .Data}})</h1>
-      </div>
-      <div class="col-md-4">
-	<div class="btn-group float-right">
-
-	  <a href="/subjects/add/?{{query "tpl_layout" "base" "tpl_content" "subjects_add_update"}}" class="btn btn-primary">
-	    <span class="fa fa-plus-circle" aria-hidden="true"></span>
-	    Crea nuova materia
-	  </a>
-	
-      </div>
-    </div>
-  </div>
+<div class="container">  
 
-  <div class="input-group" style="margin-bottom: 20px">
-    <span class="input-group-addon" id="search-query"><span class="glyphicon glyphicon-search"></span></span>
-    <input type="text" id="myInput" class="form-control" aria-describedby="search-query">
-  </div>
-  {{if not .Data}}
-  <p>Non c'è alcun elemento da visualizzare.</p>
+  {{$options := `
+  title: "Materie"
+  buttonTitle: "Crea nuova materia"
+  `}}
+  
+  {{template "read_all_header" dict  "options" ($options | yaml) "lengthData" (len .Data) "modelPath" (create "subject")}}
+  {{template "search_input"}}
+    
+  {{if not .}}
+  {{template "display_no_elements"}}
   {{else}}
   <div class="list-group" id="myUL">
     {{range $subject := .Data}}
-    <a class="list-group-item list-group-item-action" href="/subjects/{{$subject.ID}}?{{query "tpl_layout" "base" "tpl_content" "subjects_show"}}">
-      <span class="fa fa-book"></span>
+    <a class="list-group-item list-group-item-action" href={{$subject.ID|show "subject"}}>
+      <span class="fa fa-user"></span>
       {{$subject.Name}}
       <div class="text-right">
-	{{if $subject.Teachers}}
-	{{range $teacher := $subject.Teachers}}
-	<small>{{$teacher.Surname}}</small>
-	{{end}}
-	{{else}}
-	<small>no docente</small>
-	{{end}}
+        {{$options := `noElements: "no docenti"`}}
+        {{template "small" dict "options" ($options | yaml) "data" $subject.Teachers}}
       </div>
     </a>
     {{end}}
+    {{end}}
   </div>
-  {{end}}
+
 </div>
-  
+
 {{ end }}
+

+ 20 - 59
templates/subjects_add_update.html.tpl

@@ -2,73 +2,34 @@
 
 <div class="container">
 
-  {{if .Options.Get "update"}}
-  <nav aria-label="breadcrumb">
-    <ol class="breadcrumb">
-      <li class="breadcrumb-item"><a href="/subjects">Materie</a></li>
-      <li class="breadcrumb-item"><a href="/subjects/{{.Data.Subject.ID}}">{{.Data.Subject.Name}}</a></li>
-      <li class="breadcrumb-item active"><a href="#">Aggiorna materia</a></li>
-    </ol>
-  </nav>
-  {{else}}
-  <nav aria-label="breadcrumb">
-    <ol class="breadcrumb">
-      <li class="breadcrumb-item"><a href="/subjects">Materie</a></li>
-      <li class="breadcrumb-item active"><a href="#">Aggiungi</a></li>
-    </ol>
-  </nav>
-  {{end}}
+  {{$update := .Options.Get "update"}}
 
-  {{if .Options.Get "update"}}
-  <h1 class="karmen-info-header">Aggiorna la materia "{{.Data.Subject.Name}}"</h1>
+  {{if $update}}
+  {{template "breadcrumb" toSlice "Materie" (all "Subject") (.Data|string) (.Data.ID|show "Subject") "Aggiorna" "current"}}
   {{else}}
-  <h1 class="karmen-info-header">Crea una nuova materia</h1>
+  {{template "breadcrumb" toSlice "Materie" (all "Subject") "Aggiungi" "current"}}
   {{end}}
+  
+  {{template "add_update_header" dict "update" $update "addTitle" "Crea nuova materia" "updateTitle" (printf "Aggiorna materia %s" (.Data|string))}}
 
-  {{if .Options.Get "update"}}
-  <form id="form_subjects_add_update" action="/subjects/{{.Data.Subject.ID}}/update" method="POST" role="form" class="needs-validation">
-  {{else}}
-  <form id="form_subjects_add_update" action="/subjects/add/" method="POST" role="form" class="needs-validation">
-  {{end}}  
-    
-    <div class="form-group">
-      <label class="control-label" for="subject_name">Nome</label>
-      <input type="text" name="Name" class="form-control" id="subject_name" placeholder="Nome" {{if .Options.Get "update"}} value="{{.Data.Subject.Name}}" {{end}} required>
-    </div>
+  {{$form := "form_subjects_add_update"}}
+  <form
+    class="needs-validation"
+    action="{{if $update}}{{.Data.ID|update "Subject"}}{{else}}{{create "Subject"}}{{end}}"
+    method="POST"
+    role="form"
+    id={{$form}}>
 
-    <div class="form-group">
-      <label class="control-label" for="subject_alias">Nome alternativo</label>
-      <input type="text" name="Alias" class="form-control" id="subject_alias" placeholder="Nome alternativo" {{if .Options.Get "update"}} value="{{.Data.Subject.Alias}}" {{end}}>
-    </div>
+    {{$options := ` { name: "Name",id: "subject_name",label: "Nome",placeholder: "Nome",type: "text",required: "true"} `}}
+    {{template "input" dict "options" ($options|yaml) "value" (.Data|field "Name") "update" $update}}
 
-    <div class="form-group">
-      <label class="control-label" for="department_id">Dipartimento</label>
-      <select name="department_id" class="form-control selectpicker" id="department_id" placeholder="Dipartimento" data-live-search="true" form="form_subjects_add_update" title="Seleziona il nome del dipartimento" data-dropup-auto="false">
-	<option value="0"></option>
-  	{{range $department := .Data.AllDepartments}}
-	{{if $.Options.Get "update"}}
-  	<option
-	   value="{{$department.ID}}"
-	   {{index $.Data.SelectedDepartment $department.ID}}>{{$department.Name}}
-	</option>
-	{{else}}
-  	<option value="{{$department.ID}}">{{$department.Name}}</option>
-	{{end}}
-  	{{end}}
-      </select>
-    </div>
-	
-    <div class="form-group">
-      <button type="submit" class="btn btn-primary">Salva</button>
-      {{if .Options.Get "update"}}
-      <a href="/subjects/{{.Data.Subject.ID}}?{{query "tpl_layout" "base" "tpl_content" "subjects_show"}}" class="btn btn-default">Annulla</a>
-      {{else}}
-      <a href="/subjects?{{query "tpl_layout" "base" "tpl_content" "subjects"}}" class="btn btn-default">Annulla</a>
-      {{end}}
-    </div>
+    {{$options := ` { name: "department_id", id: "department_id", label: "Dipartimento", title: "Seleziona il dipartimento"}`}}
+    {{template "select" dict "options" ($options|yaml) "data" (.Data|field "AllDepartments") "selected" (.Data|field "Selected") "update" $update "form" $form}}
     
+    {{ $options := ` { cancelTitle: "Annulla", saveTitle: "Salva", model: "Subject"} ` }}
+    {{template "submit_cancel_buttons" dict "options" ($options|yaml) "id" (.Data|field "ID") "update" $update}}
+  
   </form>
-
   
 </div>
 

+ 22 - 46
templates/subjects_show.html.tpl

@@ -2,55 +2,31 @@
 
 <div class="container">
 
-  <nav aria-label="breadcrumb">
-    <ol class="breadcrumb">
-      <li class="breadcrumb-item"><a href="/subjects?{{query "tpl_layout" "base" "tpl_content" "subjects"}}">Materie</a></li>
-      <li class="breadcrumb-item active"><a href="#">{{.Data.Name}}</a></li>
-    </ol>
-  </nav>
+  {{template "breadcrumb" toSlice "Materie" (all "Subject") (.Data|string) "current"}}
+  {{template "show_header" dict "title" (.Data|string) "updatePath" (.Data.ID|update "Subject") "deletePath" (.Data.ID|delete "Subject")}}
+
+  <h2 class="karmen-relation-header">Informazioni generali</h2>
+  {{if .Data.Department}}
+  <p>Questa materia afferisce al dipartimento di {{(.Data.Department.ID|show "Department")|anchor (.Data.Department|string)}}.</p>
+  {{else}}
+  <p>Questa materia non afferisce a nessun dipartimento. Clicca {{(.Data.ID|update "Subject")|anchor "qui"}} per associare un dipartimento alla materia.</p>
+  {{end}}
   
-  <div class="karmen-info-header">
-    <div class="row">
-      <div class="col-md-8">
-	<h1>{{.Data.Name}}</h1>
-      </div>
-      <div class="col-md-4">
-	<div class="btn-group float-right" role="group">
-	  <a href="/subjects/{{.Data.ID}}/update?{{query "tpl_layout" "base" "tpl_content" "subjects_add_update" "update" "true"}}" class="btn btn-primary">
-	    <span class="fa fa-edit" aria-hidden="true"></span>
-	    Modifica
-	  </a>
-	  <button href="/subjects/{{.Data.ID}}/delete"
-		  data-url="/subjects/{{.Data.ID}}/delete"
-		  class="btn btn-danger karmen-ajax-delete">
-	    <span class="fa fa-trash" aria-hidden="true"></span>
-	    Elimina
-	  </button>
-	</div>
-      </div>
-    </div>
-  </div>
+  <div class="row">
+    <div class="col-md-12">
 
-  <h2 class="karmen-relation-header">Docenti di {{.Data.Name}}</h2>
-  <div class="list-group" id="subjects_list_group">
-    {{if not .Data.Teachers}}
-    <p>Alla materia non è associata alcuna attività
-      didattica. Clicca <a href="/activities/add?{{query "tpl_layout" "base" "tpl_content" "activities_add_update"}}">qui</a> per creare
-      una nuova attività didattica da associare alla materia.</p>
-    {{else}}
-    {{range $activity := .Data.Activities}}
-    <a href="/activities/{{$activity.ID}}?{{query "tpl_layout" "base" "tpl_content" "activities_show"}}" class="list-group-item list-group-item-action">
-      <span class="fa fa-user"></span>
-      {{$activity.Teacher.Surname}} {{$activity.Teacher.Name}}
-      <div class="text-right">
-	<small>{{$activity.Subject.Name}} {{$activity.Hours}}h</small>
-      </div>
-    </a>
-    {{end}}
-    {{end}}
+      {{$options := `
+      title: "Docenti della materia"
+      model: "Teacher"
+      icon: "fa fa-user"
+      `}}
+      
+      {{$noElements := "Nessun docente associato alla materia."}}
+      {{template "relation_list" dict "options" ($options|yaml) "data" .Data.Teachers "noElements" $noElements}}
+    
+    </div>
   </div>
-
-
+  
 </div>    
 
 {{ end }}

+ 37 - 51
templates/teachers_add_update.html.tpl

@@ -3,7 +3,7 @@
 <div class="container">
 
   {{$update := .Options.Get "update"}}
-  
+
   {{if $update}}
   {{template "breadcrumb" toSlice "Docenti" (all "Teacher") (.Data|string) (.Data.ID|show "Teacher") "Aggiorna" "current"}}
   {{else}}
@@ -12,69 +12,55 @@
   
   {{template "add_update_header" dict "update" $update "addTitle" "Crea nuovo docente" "updateTitle" (printf "Aggiorna docente %s" (.Data|string))}}
 
-  {{if $update}}
-  <form class="needs-validation" action="/teachers/{{.Data.ID}}/update" method="POST" role="form">
-  {{else}}
-  <form action="/teachers/create/" method="POST" role="form" class="needs-validation">
-  {{end}}
-
-  {{$options := ` { name: "Name",id: "teacher_name",label: "Nome",placeholder: "Nome",type: "text" } `}}
-  {{template "input" dict "options" ($options|yaml) "value" (.Data|field "Name") "update" $update}}
+  <form
+    class="needs-validation"
+    action="{{if $update}}{{.Data.ID|update "Teacher"}}{{else}}{{create "Teacher"}}{{end}}" method="POST" role="form">
 
-  {{$options := ` { name: "Surname",id: "teacher_surname",label: "Cognome",placeholder: "Cognome",type: "text" } `}}
-  {{template "input" dict "options" ($options|yaml) "value" (.Data|field "Surname") "update" $update}}
+    {{$options := ` { name: "Name",id: "teacher_name",label: "Nome",placeholder: "Nome",type: "text" } `}}
+    {{template "input" dict "options" ($options|yaml) "value" (.Data|field "Name") "update" $update}}
+    
+    {{$options := ` { name: "Surname",id: "teacher_surname",label: "Cognome",placeholder: "Cognome",type: "text" } `}}
+    {{template "input" dict "options" ($options|yaml) "value" (.Data|field "Surname") "update" $update}}
 
-  {{$options := ` { name: "Hours",id: "teacher_hours",label: "Numero di ore",placeholder: "",type: "number" } `}}
-  {{template "input" dict "options" ($options|yaml) "value" (.Data|field "Hours") "update" $update}}
+    {{$options := ` { name: "Hours",id: "teacher_hours",label: "Numero di ore",placeholder: "",type: "number" } `}}
+    {{template "input" dict "options" ($options|yaml) "value" (.Data|field "Hours") "update" $update}}
 
-  {{$options := ` { name: "AltEmail",id: "teacher_altemail",label: "Email alternativa",placeholder: "Inserire indirizzo email",type: "email" } `}}
-  {{template "input" dict "options" ($options|yaml) "value" (.Data|field "AltEmail") "update" $update}}
+    {{$options := ` { name: "AltEmail",id: "teacher_altemail",label: "Email alternativa",placeholder: "Inserire indirizzo email",type: "email" } `}}
+    {{template "input" dict "options" ($options|yaml) "value" (.Data|field "AltEmail") "update" $update}}
 
-  <div class="form-row">
-    <div class="col">
-      <div class="form-check form-check-inline">
-	<input type="checkbox" name="Regenerate" class="form-check-input" id="teacher_regenerate" {{if .Options.Get "update"}}{{if .Data.Regenerate}}checked{{end}}{{end}}>
-	<label class="form-check-label has-feedback" for="teacher_regenerate">Rigenerare/inviare le credenziali</label>
+    <div class="form-row">
+      <div class="col">
+        {{$options := ` { name: "Regenerate",id: "teacher_regenerate",label: "Rigenerare/inviare le credenziali",formClass: "form-check form-check-inline" } `}}
+        {{template "checkbox" dict "options" ($options|yaml) "value" (.Data|field "Regenerate") "update" $update}}
       </div>
-      <div class="form-check form-check-inline">
-	<input type="checkbox" name="Exclude" class="form-check-input" id="teacher_exclude" {{if .Options.Get "update"}}{{if .Data.Exclude}}checked{{end}}{{end}}>
-	<label class="form-check-label has-feedback" for="teacher_exclude">Escludere dalle utenze</label>
+      <div class="col">
+        {{$options := ` { name: "Exclude",id: "teacher_exclude",label: "Escludere dalle utenze",formClass: "form-check form-check-inline" } `}}
+        {{template "checkbox" dict "options" ($options|yaml) "value" (.Data|field "Exclude") "update" $update}}
       </div>
-      <div class="form-check form-check-inline">
-        <input type="checkbox" name="NotInvited" class="form-check-input" id="teacher_not_invited" {{if .Options.Get "update"}}{{if .Data.NotInvited}}checked{{end}}{{end}}>
-	<label class="form-check-label has-feedback" for="teacher_not_invited">Escludere dagli inviti</label>
+      <div class="col">
+        {{$options := ` { name: "NotInvited",id: "teacher_not_invited",label: "Escludere dagli inviti",formClass: "form-check form-check-inline" } `}}
+        {{template "checkbox" dict "options" ($options|yaml) "value" (.Data|field "NotInvited") "update" $update}}
       </div>
-      
     </div>
-  </div>
 
-  <div class="form-row">
-    <div class="col">
-      <label class="control-label" for="teacher_date_from">In servizio dal</label>
-      <input type="date" name="DateFrom" class="form-control" id="teacher_date_from" {{if .Options.Get "update"}} value="{{convertDate .Data.DateFrom}}" {{end}}>
-    </div>
-    <div class="col">
-      <label class="control-label" for="teacher_date_to">In servizio fino al</label>
-      <input type="date" name="DateTo" class="form-control" id="teacher_date_to" {{if .Options.Get "update"}} value="{{convertDate .Data.DateTo}}" {{end}}>
+    <div class="form-row">
+      <div class="col">
+        {{$options := ` { name: "DateFrom",id: "teacher_date_from",label: "In servizio dal",type: "date" } `}}
+        {{template "input" dict "options" ($options|yaml) "value" (.Data|field "DateFrom"|convertDate) "update" $update}}
+      </div>
+      <div class="col">
+        {{$options := ` { name: "DateTo",id: "teacher_date_to",label: "In servizio fino al",type: "date" } `}}
+        {{template "input" dict "options" ($options|yaml) "value" (.Data|field "DateTo"|convertDate) "update" $update}}
+      </div>
     </div>
-  </div>
-  
-  <div class="form-group">
-    <label class="control-label has-feedback" for="teacher_ldapdnfmt">Stringa DN per LDAP</label>
-    <input type="text" name="LdapDNFmt" class="form-control" id="teacher_ldapdnfmt" placeholder="cn=%s %s,ou=People,dc=foo,dc=org" {{if .Options.Get "update"}}value="{{.Data.LdapDNFmt}}"{{end}}>
-  </div>
+    
+    {{$options := ` { name: "LdapDNFmt",id: "teacher_ldapfnfmt",label: "Stringa DN per LDAP",placeholder: "cn=%s %s,ou=People,dc=foo,dc=org",type: "text" } `}}
+    {{template "input" dict "options" ($options|yaml) "value" (.Data|field "LdapDNFmt") "update" $update}}
 
-  <div class="form-group">
-    <button type="submit" class="btn btn-primary">Salva</button>
-    {{if .Options.Get "update"}}
-    <a href="/teachers/{{.Data.ID}}?{{query "tpl_layout" "base" "tpl_content" "teachers_show"}}" class="btn btn-default">Annulla</a>
-    {{else}}
-    <a href="/teachers/?{{query "tpl_layout" "base" "tpl_content" "teachers"}}" class="btn btn-default">Annulla</a>
-    {{end}}
-  </div>
+    {{ $options := ` { cancelTitle: "Annulla", saveTitle: "Salva", model: "Teacher"} ` }}
+    {{template "submit_cancel_buttons" dict "options" ($options|yaml) "id" (.Data|field "ID") "update" $update}}
   
   </form>
-
   
 </div>