so mamy things...
This commit is contained in:
1 parent
f7a8d416c1
commit
78d50d9a6d
23 files changed
+441
-98
No files matched your search
@@ -16,8 +16,8 @@ func init() {
|
|||||||
|
|
||||||
func TestGetAllDoormen(t *testing.T) {
|
func TestGetAllDoormen(t *testing.T) {
|
||||||
conn = inmemoryconnector.NewInMemoryDBConnector()
|
conn = inmemoryconnector.NewInMemoryDBConnector()
|
||||||
conn.Save(doormen.QuickNewDoormanDefinition("foo", 0.25, 0.75))
|
conn.Save(doormen.QuickNewDoormanDefinition("foo", "0.25", "0.75"))
|
||||||
conn.Save(doormen.QuickNewDoormanDefinition("bar", 0.5, 0.5))
|
conn.Save(doormen.QuickNewDoormanDefinition("bar", "0.5", "0.5"))
|
||||||
|
|
||||||
req, err := http.NewRequest("GET", "http://bigtits.com/api/doormen", nil)
|
req, err := http.NewRequest("GET", "http://bigtits.com/api/doormen", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -44,11 +44,19 @@ func Create(root string) http.Handler {
|
|||||||
UpdateDoorman,
|
UpdateDoorman,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getDoormanStatus := &simpleapi.Endpoint{
|
||||||
|
"/doormen/{id}/status",
|
||||||
|
`Returns the status of the doorman as a doorman client expect it.`,
|
||||||
|
"GET",
|
||||||
|
GetDoormanStatus,
|
||||||
|
}
|
||||||
|
|
||||||
api := simpleapi.New(
|
api := simpleapi.New(
|
||||||
root,
|
root,
|
||||||
serverSpecification,
|
serverSpecification,
|
||||||
createDoorman,
|
createDoorman,
|
||||||
allDoorman,
|
allDoorman,
|
||||||
|
getDoormanStatus,
|
||||||
doorman,
|
doorman,
|
||||||
updateDoorman,
|
updateDoorman,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ func TestCreateDoorman(t *testing.T) {
|
|||||||
conn = inmemoryconnector.NewInMemoryDBConnector()
|
conn = inmemoryconnector.NewInMemoryDBConnector()
|
||||||
payload := `
|
payload := `
|
||||||
{"name":"name",
|
{"name":"name",
|
||||||
"values":[{"name":"red","probability":0.2},{"name":"blue","probability":0.8}],
|
"values":[{"name":"red","probability":"1/5"},{"name":"blue","probability": "4/5"}],
|
||||||
"emails": ["alice"]
|
"emails": ["alice"]
|
||||||
}`
|
}`
|
||||||
req, err := http.NewRequest(
|
req, err := http.NewRequest(
|
||||||
@@ -34,7 +34,7 @@ func TestCreateDoorman(t *testing.T) {
|
|||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
CreateDoorman(w, req)
|
CreateDoorman(w, req)
|
||||||
if w.Code != 201 {
|
if w.Code != 201 {
|
||||||
t.Error("bad status code", w.Code)
|
t.Error("bad status code", w.Code, "\n", w.Body)
|
||||||
} else if location := w.Header().Get("location"); location == "" {
|
} else if location := w.Header().Get("location"); location == "" {
|
||||||
t.Error("missing location header", location)
|
t.Error("missing location header", location)
|
||||||
} else if dor, _ := conn.GetDoorman(GetIdFromLocation(location)); dor == nil {
|
} else if dor, _ := conn.GetDoorman(GetIdFromLocation(location)); dor == nil {
|
||||||
|
|||||||
@@ -21,3 +21,24 @@ func GetDoorman(w http.ResponseWriter, r *http.Request) {
|
|||||||
encoder.Encode(doorman)
|
encoder.Encode(doorman)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetDoormanStatus(w http.ResponseWriter, r *http.Request) {
|
||||||
|
id := getDoormanIdFromRequest(w, r)
|
||||||
|
if id == "" {
|
||||||
|
Write404Error(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
doorman, err := conn.GetDoorman(id)
|
||||||
|
if err != nil {
|
||||||
|
Write500Error(w, err)
|
||||||
|
} else if doorman == nil {
|
||||||
|
Write404Error(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
if payload, err := doorman.AsDoormanUpdatePayload(); err != nil {
|
||||||
|
Write500Error(w, err)
|
||||||
|
} else {
|
||||||
|
w.Write(payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+23
-13
@@ -4,18 +4,22 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"gopkg.in/mgo.v2/bson"
|
||||||
|
"math/big"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/didiercrunch/doorman/shared"
|
"github.com/didiercrunch/doorman/shared"
|
||||||
"gopkg.in/mgo.v2/bson"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const epsilon float64 = 0.0001
|
|
||||||
|
|
||||||
type DoormanValue struct {
|
type DoormanValue struct {
|
||||||
Name string `json:"name" bson:"name"`
|
Name string `json:"name"`
|
||||||
Probability float64 `json:"probability" bson:"probability"`
|
Probability *big.Rat `json:"probability"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type doormanValue struct {
|
||||||
|
Name string
|
||||||
|
Probability string
|
||||||
}
|
}
|
||||||
|
|
||||||
type DoormanId struct {
|
type DoormanId struct {
|
||||||
@@ -43,10 +47,15 @@ func NewDoormanDefinition(name string, ownerEmails ...string) *DoormanDefinition
|
|||||||
|
|
||||||
// a way to quickly create doormen in tests. do not use in real code. will
|
// a way to quickly create doormen in tests. do not use in real code. will
|
||||||
// panic if a doorman is wrongly specify
|
// panic if a doorman is wrongly specify
|
||||||
func QuickNewDoormanDefinition(name string, probs ...float64) *DoormanDefinition {
|
func QuickNewDoormanDefinition(name string, probs ...string) *DoormanDefinition {
|
||||||
ret := NewDoormanDefinition(name, "natasha@bigtits.com")
|
ret := NewDoormanDefinition(name, "natasha@bigtits.com")
|
||||||
for i, prob := range probs {
|
for i, prob := range probs {
|
||||||
ret.Values = append(ret.Values, &DoormanValue{"T" + strconv.Itoa(i), prob})
|
r := new(big.Rat)
|
||||||
|
_, err := fmt.Sscan(prob, r)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
ret.Values = append(ret.Values, &DoormanValue{"T" + strconv.Itoa(i), r})
|
||||||
}
|
}
|
||||||
if err := ret.Validate("natasha@bigtits.com"); err != nil {
|
if err := ret.Validate("natasha@bigtits.com"); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@@ -79,18 +88,19 @@ func (dmd *DoormanDefinition) AsWriteAccess(email string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (dmd *DoormanDefinition) ValidateDoormanValueProbabilities() error {
|
func (dmd *DoormanDefinition) ValidateDoormanValueProbabilities() error {
|
||||||
var sum float64 = 0
|
sum, zero, one := big.NewRat(0, 1), big.NewRat(0, 1), big.NewRat(1, 1)
|
||||||
for _, w := range dmd.Values {
|
for _, w := range dmd.Values {
|
||||||
|
|
||||||
if p := w.Probability; p < 0-epsilon || p > 1+epsilon {
|
if p := w.Probability; p.Cmp(zero) < 0 || p.Cmp(one) > 0 {
|
||||||
return errors.New(fmt.Sprintf("doorman value %v is out of range", p))
|
return errors.New(fmt.Sprintf("doorman value %v is out of range", p))
|
||||||
} else {
|
} else {
|
||||||
sum += p
|
sum = new(big.Rat).Add(sum, p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if sum < 1-epsilon || sum > 1+epsilon {
|
if sum.Cmp(one) != 0 {
|
||||||
return errors.New("the sum of the probability must be 1.0")
|
return errors.New("the sum of the probability must be 1")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,7 +135,7 @@ func (dmd *DoormanDefinition) CanBeUpdatedBy(dmd2 *DoormanDefinition) error {
|
|||||||
func (dmd *DoormanDefinition) AsDoormanUpdatePayload() ([]byte, error) {
|
func (dmd *DoormanDefinition) AsDoormanUpdatePayload() ([]byte, error) {
|
||||||
wu := &shared.DoormanUpdater{Id: dmd.Id.Hex()}
|
wu := &shared.DoormanUpdater{Id: dmd.Id.Hex()}
|
||||||
wu.Timestamp = time.Now().Unix()
|
wu.Timestamp = time.Now().Unix()
|
||||||
wu.Probabilities = make([]float64, len(dmd.Values))
|
wu.Probabilities = make([]*big.Rat, len(dmd.Values))
|
||||||
for i, value := range dmd.Values {
|
for i, value := range dmd.Values {
|
||||||
wu.Probabilities[i] = value.Probability
|
wu.Probabilities[i] = value.Probability
|
||||||
}
|
}
|
||||||
|
|||||||
+23
-19
@@ -2,13 +2,17 @@ package doormen
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"math"
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/didiercrunch/doorman/shared"
|
"github.com/didiercrunch/doorman/shared"
|
||||||
"gopkg.in/mgo.v2/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var zero = big.NewRat(0, 1)
|
||||||
|
|
||||||
|
const epsilon float64 = 0.0001
|
||||||
|
|
||||||
func TestNewDoormanDefinition(t *testing.T) {
|
func TestNewDoormanDefinition(t *testing.T) {
|
||||||
dmd := NewDoormanDefinition("some_name")
|
dmd := NewDoormanDefinition("some_name")
|
||||||
if dmd.Id == "" {
|
if dmd.Id == "" {
|
||||||
@@ -33,40 +37,40 @@ func TestValidate(t *testing.T) {
|
|||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
dmd = &DoormanDefinition{Name: "foo", Values: []*DoormanValue{&DoormanValue{"foo", 0}, &DoormanValue{"foo", 0}}}
|
dmd = &DoormanDefinition{Name: "foo", Values: []*DoormanValue{&DoormanValue{"foo", zero}, &DoormanValue{"foo", zero}}}
|
||||||
if err := dmd.Validate("bob"); err.Error() != "doorman value names must be unique within a doorman" {
|
if err := dmd.Validate("bob"); err.Error() != "doorman value names must be unique within a doorman" {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
dmd = &DoormanDefinition{Name: "foo", Values: []*DoormanValue{&DoormanValue{"foo", 0}, &DoormanValue{"", 0}}}
|
dmd = &DoormanDefinition{Name: "foo", Values: []*DoormanValue{&DoormanValue{"foo", zero}, &DoormanValue{"", zero}}}
|
||||||
if err := dmd.Validate("bob"); err.Error() != "doorman value cannot be empty" {
|
if err := dmd.Validate("bob"); err.Error() != "doorman value cannot be empty" {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
dmd = &DoormanDefinition{Name: "foo", Values: []*DoormanValue{&DoormanValue{"foo", -0.25}, &DoormanValue{"bar", 0.5}}}
|
dmd = &DoormanDefinition{Name: "foo", Values: []*DoormanValue{&DoormanValue{"foo", big.NewRat(-1, 4)}, &DoormanValue{"bar", big.NewRat(1, 2)}}}
|
||||||
if err := dmd.Validate("bob"); err.Error() != "doorman value -0.25 is out of range" {
|
if err := dmd.Validate("bob"); err.Error() != "doorman value -1/4 is out of range" {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
dmd = &DoormanDefinition{Name: "foo", Values: []*DoormanValue{&DoormanValue{"foo", 2.5}, &DoormanValue{"bar", 0.5}}}
|
dmd = &DoormanDefinition{Name: "foo", Values: []*DoormanValue{&DoormanValue{"foo", big.NewRat(5, 2)}, &DoormanValue{"bar", big.NewRat(1, 2)}}}
|
||||||
if err := dmd.Validate("bob"); err.Error() != "doorman value 2.5 is out of range" {
|
if err := dmd.Validate("bob"); err.Error() != "doorman value 5/2 is out of range" {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
dmd = &DoormanDefinition{Name: "foo", Values: []*DoormanValue{&DoormanValue{"foo", 0.75}, &DoormanValue{"bar", 0.5}}}
|
dmd = &DoormanDefinition{Name: "foo", Values: []*DoormanValue{&DoormanValue{"foo", big.NewRat(3, 4)}, &DoormanValue{"bar", big.NewRat(1, 2)}}}
|
||||||
if err := dmd.Validate("bob"); err.Error() != "the sum of the probability must be 1.0" {
|
if err := dmd.Validate("bob"); err.Error() != "the sum of the probability must be 1" {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
dmd = &DoormanDefinition{Name: "foo", Values: []*DoormanValue{&DoormanValue{"foo", 0.2}, &DoormanValue{"bar", 0.2}}}
|
dmd = &DoormanDefinition{Name: "foo", Values: []*DoormanValue{&DoormanValue{"foo", big.NewRat(1, 5)}, &DoormanValue{"bar", big.NewRat(1, 5)}}}
|
||||||
if err := dmd.Validate("bob"); err.Error() != "the sum of the probability must be 1.0" {
|
if err := dmd.Validate("bob"); err.Error() != "the sum of the probability must be 1" {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
dmd = &DoormanDefinition{Name: "foo", Values: []*DoormanValue{&DoormanValue{"foo", 0.8}, &DoormanValue{"bar", 0.2}}}
|
dmd = &DoormanDefinition{Name: "foo", Values: []*DoormanValue{&DoormanValue{"foo", big.NewRat(4, 5)}, &DoormanValue{"bar", big.NewRat(1, 5)}}}
|
||||||
if err := dmd.Validate("bob"); err.Error() != "A doorman needs at least one owner specify as 'email'." {
|
if err := dmd.Validate("bob"); err.Error() != "A doorman needs at least one owner specify as 'email'." {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
dmd = &DoormanDefinition{Name: "foo", Values: []*DoormanValue{&DoormanValue{"foo", 0.8}, &DoormanValue{"bar", 0.2}}, OwnerEmails: []string{"alice"}}
|
dmd = &DoormanDefinition{Name: "foo", Values: []*DoormanValue{&DoormanValue{"foo", big.NewRat(4, 5)}, &DoormanValue{"bar", big.NewRat(1, 5)}}, OwnerEmails: []string{"alice"}}
|
||||||
if err := dmd.Validate("bob"); err.Error() != "'bob' is not allow to edit this doorman." {
|
if err := dmd.Validate("bob"); err.Error() != "'bob' is not allow to edit this doorman." {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
@@ -91,7 +95,7 @@ func TestAsJson(t *testing.T) {
|
|||||||
func TestAsDoormanUpdatePayload(t *testing.T) {
|
func TestAsDoormanUpdatePayload(t *testing.T) {
|
||||||
wd := &DoormanDefinition{}
|
wd := &DoormanDefinition{}
|
||||||
wd.Id = bson.NewObjectId()
|
wd.Id = bson.NewObjectId()
|
||||||
wd.Values = []*DoormanValue{&DoormanValue{"C", 0.25}, &DoormanValue{"T1", 0.75}}
|
wd.Values = []*DoormanValue{&DoormanValue{"C", big.NewRat(1, 4)}, &DoormanValue{"T1", big.NewRat(3, 4)}}
|
||||||
data, err := wd.AsDoormanUpdatePayload()
|
data, err := wd.AsDoormanUpdatePayload()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
@@ -106,9 +110,9 @@ func TestAsDoormanUpdatePayload(t *testing.T) {
|
|||||||
}
|
}
|
||||||
if len(wu.Probabilities) != 2 {
|
if len(wu.Probabilities) != 2 {
|
||||||
t.Error("bad probability length")
|
t.Error("bad probability length")
|
||||||
} else if math.Abs(wu.Probabilities[0]-0.25) > epsilon {
|
} else if wu.Probabilities[0].Cmp(big.NewRat(1, 4)) != 0 {
|
||||||
t.Error("bad first probability")
|
t.Error("bad first probability")
|
||||||
} else if math.Abs(wu.Probabilities[1]-0.75) > epsilon {
|
} else if wu.Probabilities[1].Cmp(big.NewRat(3, 4)) != 0 {
|
||||||
t.Error("bad second probability")
|
t.Error("bad second probability")
|
||||||
} else if wu.Timestamp == 0 {
|
} else if wu.Timestamp == 0 {
|
||||||
t.Error("no time specify")
|
t.Error("no time specify")
|
||||||
@@ -118,7 +122,7 @@ func TestAsDoormanUpdatePayload(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestQuickNewDoormanDefinition(t *testing.T) {
|
func TestQuickNewDoormanDefinition(t *testing.T) {
|
||||||
dmd := QuickNewDoormanDefinition("foo", 0.75, 0.25)
|
dmd := QuickNewDoormanDefinition("foo", "0.75", "0.25")
|
||||||
if dmd.Name != "foo" {
|
if dmd.Name != "foo" {
|
||||||
t.Error()
|
t.Error()
|
||||||
}
|
}
|
||||||
@@ -127,11 +131,11 @@ func TestQuickNewDoormanDefinition(t *testing.T) {
|
|||||||
t.Error()
|
t.Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
if dmd.Values[0].Name != "T0" || dmd.Values[0].Probability != 0.75 {
|
if dmd.Values[0].Name != "T0" || dmd.Values[0].Probability.Cmp(big.NewRat(3, 4)) != 0 {
|
||||||
t.Error()
|
t.Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
if dmd.Values[1].Name != "T1" || dmd.Values[1].Probability != 0.25 {
|
if dmd.Values[1].Name != "T1" || dmd.Values[1].Probability.Cmp(big.NewRat(1, 4)) != 0 {
|
||||||
t.Error()
|
t.Error()
|
||||||
}
|
}
|
||||||
if len(dmd.OwnerEmails) != 1 && dmd.OwnerEmails[0] != "natasha@bigtits.com" {
|
if len(dmd.OwnerEmails) != 1 && dmd.OwnerEmails[0] != "natasha@bigtits.com" {
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package doormen
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gopkg.in/mgo.v2/bson"
|
||||||
|
"math/big"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (val *DoormanValue) GetBSON() (interface{}, error) {
|
||||||
|
ret := &doormanValue{val.Name, ""}
|
||||||
|
txt, err := val.Probability.MarshalText()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ret.Probability = string(txt)
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (val *DoormanValue) SetBSON(raw bson.Raw) error {
|
||||||
|
v := new(doormanValue)
|
||||||
|
if err := raw.Unmarshal(v); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
val.Name = v.Name
|
||||||
|
val.Probability = new(big.Rat)
|
||||||
|
return val.Probability.UnmarshalText([]byte(v.Probability))
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package doormen
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"gopkg.in/mgo.v2/bson"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestJsonEncoding(t *testing.T) {
|
||||||
|
dmd := QuickNewDoormanDefinition("test json", "1/4", "3/4")
|
||||||
|
data, err := json.Marshal(dmd)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
dmd2 := new(DoormanDefinition)
|
||||||
|
if err = json.Unmarshal(data, dmd2); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(dmd2, dmd) {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBsonEncoding(t *testing.T) {
|
||||||
|
dmd := QuickNewDoormanDefinition("test bson", "1/4", "3/4")
|
||||||
|
data, err := bson.Marshal(dmd)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
dmd2 := new(DoormanDefinition)
|
||||||
|
if err = bson.Unmarshal(data, dmd2); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(dmd2, dmd) {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func createMockDoorman(name string) *doormen.DoormanDefinition {
|
func createMockDoorman(name string) *doormen.DoormanDefinition {
|
||||||
return doormen.QuickNewDoormanDefinition(name, 0.5, 0.5)
|
return doormen.QuickNewDoormanDefinition(name, "0.5", "0.5")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewInMemoryDBConnector(t *testing.T) {
|
func TestNewInMemoryDBConnector(t *testing.T) {
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"directory": "app/bower_components"
|
||||||
|
}
|
||||||
+2
-1
@@ -22,6 +22,7 @@
|
|||||||
"angularAMD": "~0.2.1",
|
"angularAMD": "~0.2.1",
|
||||||
"angular-foundation": "~0.5.1",
|
"angular-foundation": "~0.5.1",
|
||||||
"lodash": "~3.9.3",
|
"lodash": "~3.9.3",
|
||||||
"font-awesome": "~4.3.0"
|
"font-awesome": "~4.3.0",
|
||||||
|
"bourbon": "~4.2.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
|
|
||||||
define [
|
define [
|
||||||
"angularAMD"
|
"angularAMD"
|
||||||
|
"lodash"
|
||||||
"angular-route"
|
"angular-route"
|
||||||
"foundation"
|
"foundation"
|
||||||
], (angularAMD) ->
|
|
||||||
|
], (angularAMD, _) ->
|
||||||
app = angular.module("webapp", ["ngRoute", "mm.foundation"])
|
app = angular.module("webapp", ["ngRoute", "mm.foundation"])
|
||||||
app.config ($routeProvider) ->
|
app.config ($routeProvider) ->
|
||||||
$routeProvider.when("/", angularAMD.route(
|
$routeProvider.when("/", angularAMD.route(
|
||||||
@@ -39,6 +41,24 @@ define [
|
|||||||
document.getElementsByTagName("body")[0].style.visibility = ""
|
document.getElementsByTagName("body")[0].style.visibility = ""
|
||||||
return
|
return
|
||||||
|
|
||||||
|
app.controller "topbarCtrl", ["$scope", "$rootScope", "$location", ($scope, $rootScope, $location) ->
|
||||||
|
|
||||||
|
$scope.init = () ->
|
||||||
|
$scope.email = localStorage.getItem("email")
|
||||||
|
$scope.loggedIn = !!$scope.email
|
||||||
|
if !$scope.loggedIn
|
||||||
|
$location.path('/').replace()
|
||||||
|
|
||||||
|
$scope.logout = () ->
|
||||||
|
localStorage.setItem("email", "")
|
||||||
|
$scope.email = ""
|
||||||
|
$scope.loggedIn = false
|
||||||
|
$scope.$emit("logout")
|
||||||
|
|
||||||
|
$scope.init()
|
||||||
|
$rootScope.$on('login', $scope.init)
|
||||||
|
return
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
angularAMD.bootstrap(app)
|
angularAMD.bootstrap(app)
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
define ["app", "lodash"], (app, _) ->
|
define ["app", "lodash", "directives/ratinput"], (app, _, ratinput) ->
|
||||||
|
|
||||||
app.controller "DoormanCtrl", ["$scope", "$http","$routeParams","$location", ($scope, $http, $routeParams, $location) ->
|
app.controller "DoormanCtrl", ["$scope", "$http","$routeParams","$location", ($scope, $http, $routeParams, $location) ->
|
||||||
$scope.doorman = {values: []}
|
$scope.doorman = {values: []}
|
||||||
|
$scope.somevalue = "2/6"
|
||||||
$scope.apiurl = "/api/doormen/#{$routeParams.id}"
|
$scope.apiurl = "/api/doormen/#{$routeParams.id}"
|
||||||
$scope.user = localStorage.getItem("email")
|
$scope.user = localStorage.getItem("email")
|
||||||
|
|
||||||
@@ -20,10 +22,18 @@ define ["app", "lodash"], (app, _) ->
|
|||||||
$scope.initEmails = () ->
|
$scope.initEmails = () ->
|
||||||
[$scope.leftEmailColumns, $scope.rightEmailColumns] = _.chunk($scope.doorman.emails, 2)
|
[$scope.leftEmailColumns, $scope.rightEmailColumns] = _.chunk($scope.doorman.emails, 2)
|
||||||
|
|
||||||
|
$scope.rationalToFloat = (rat) ->
|
||||||
|
if _.contains(rat, "/")
|
||||||
|
num = Number(rat.substr(0, rat.indexOf("/")))
|
||||||
|
denum = Number(rat.substr(rat.indexOf("/") + 1))
|
||||||
|
return num / denum
|
||||||
|
Number(rat)
|
||||||
|
|
||||||
|
|
||||||
$scope.validate = ()->
|
$scope.validate = ()->
|
||||||
ret = 0
|
ret = 0
|
||||||
for val in $scope.doorman.values
|
for val in $scope.doorman.values
|
||||||
ret += val.probability
|
ret += $scope.rationalToFloat(val.probability)
|
||||||
return Math.abs(ret - 1.0) < 0.000001
|
return Math.abs(ret - 1.0) < 0.000001
|
||||||
|
|
||||||
$scope.addNewAuthorEmail = () ->
|
$scope.addNewAuthorEmail = () ->
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
define ["app"], (app) ->
|
define ["app"], (app) ->
|
||||||
app.controller "HomeCtrl", ($scope) ->
|
app.controller "HomeCtrl", ['$scope', '$rootScope', ($scope, $rootScope) ->
|
||||||
$scope.message = "message from home ctrl"
|
$scope.init = () ->
|
||||||
$scope.loggedEmail = localStorage.getItem("email")
|
$scope.loggedEmail = localStorage.getItem("email")
|
||||||
|
|
||||||
$scope.login = () ->
|
$scope.login = () ->
|
||||||
if $scope.email
|
if $scope.email
|
||||||
localStorage.setItem("email", $scope.email)
|
localStorage.setItem("email", $scope.email)
|
||||||
$scope.loggedEmail = $scope.email
|
$scope.loggedEmail = $scope.email
|
||||||
$scope.email = ""
|
$scope.email = ""
|
||||||
|
$scope.$emit("login")
|
||||||
|
|
||||||
return
|
$scope.init()
|
||||||
|
$rootScope.$on('logout', $scope.init)
|
||||||
|
]
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
epsilon = 0.0001
|
epsilon = 0.0001
|
||||||
|
|
||||||
define ["app", "../filters"], (app, filters) ->
|
define ["app", "lodash", "../filters", "directives/ratinput"], (app, _, filters, ratinput) ->
|
||||||
app.controller "NewDoormanCtrl", ["$scope", "$http", "$location", ($scope, $http, $location) ->
|
app.controller "NewDoormanCtrl", ["$scope", "$http", "$location", "rationals", ($scope, $http, $location, rationals) ->
|
||||||
$scope.error = ""
|
$scope.error = ""
|
||||||
$scope.user = localStorage.getItem("email")
|
$scope.user = localStorage.getItem("email")
|
||||||
$scope.value = {probability: 0, name: ""}
|
$scope.value = {probability: "1", name: ""}
|
||||||
$scope.payload =
|
$scope.payload =
|
||||||
name: ""
|
name: ""
|
||||||
values: []
|
values: []
|
||||||
@@ -17,27 +17,34 @@ define ["app", "../filters"], (app, filters) ->
|
|||||||
if !$scope.isValidValue()
|
if !$scope.isValidValue()
|
||||||
return
|
return
|
||||||
$scope.payload.values.push($scope.value)
|
$scope.payload.values.push($scope.value)
|
||||||
$scope.value = {name: "", probability: 0}
|
$scope.value =
|
||||||
|
name: ""
|
||||||
|
probability: $scope.getProbabilityRemaining()
|
||||||
|
|
||||||
$scope.removeValue = (idx) ->
|
$scope.removeValue = (idx) ->
|
||||||
$scope.payload.values.splice(idx, 1);
|
$scope.payload.values.splice(idx, 1);
|
||||||
|
|
||||||
$scope.getProbabilityRemaining = () ->
|
$scope.getProbabilityRemaining = () ->
|
||||||
ret = 0
|
sum = rationals.sum(_.pluck($scope.payload.values, "probability")...)
|
||||||
for v in $scope.payload.values
|
return rationals.minus("1", sum)
|
||||||
ret += v.probability
|
|
||||||
return 1 - ret
|
|
||||||
|
|
||||||
$scope.redirectToDoorman = (doormanLocation) ->
|
$scope.redirectToDoorman = (doormanLocation) ->
|
||||||
$http.get(doormanLocation).then (res) ->
|
$http.get(doormanLocation).then (res) ->
|
||||||
id = res.data.id
|
id = res.data.id
|
||||||
return $location.url("/doormen/#{id}")
|
return $location.url("/doormen/#{id}")
|
||||||
|
|
||||||
|
$scope.getPayload = () ->
|
||||||
|
payload = _.cloneDeep($scope.payload)
|
||||||
|
for value in payload.values
|
||||||
|
value.probability = value.probability
|
||||||
|
return payload
|
||||||
|
|
||||||
$scope.createDoorman = () ->
|
$scope.createDoorman = () ->
|
||||||
if not $scope.isDoormanValid()
|
if not $scope.isDoormanValid()
|
||||||
return
|
return
|
||||||
params = {params: {user: $scope.user}}
|
params = {params: {user: $scope.user}}
|
||||||
$http.post("/api/doormen", $scope.payload, params).
|
$http.post("/api/doormen", $scope.getPayload(), params).
|
||||||
then((res, s) ->
|
then((res, s) ->
|
||||||
$scope.redirectToDoorman(res.headers("location"))
|
$scope.redirectToDoorman(res.headers("location"))
|
||||||
).catch((res) ->
|
).catch((res) ->
|
||||||
@@ -49,9 +56,8 @@ define ["app", "../filters"], (app, filters) ->
|
|||||||
return false
|
return false
|
||||||
if $scope.payload.values.length < 2
|
if $scope.payload.values.length < 2
|
||||||
return false
|
return false
|
||||||
if Math.abs($scope.getProbabilityRemaining()) > epsilon
|
rationals.equal($scope.getProbabilityRemaining(), "0" )
|
||||||
return false
|
|
||||||
return true
|
|
||||||
|
|
||||||
$scope.addEmail = () ->
|
$scope.addEmail = () ->
|
||||||
if not $scope.newEmail
|
if not $scope.newEmail
|
||||||
@@ -64,6 +70,10 @@ define ["app", "../filters"], (app, filters) ->
|
|||||||
return
|
return
|
||||||
$scope.payload.emails.splice(idx, 1);
|
$scope.payload.emails.splice(idx, 1);
|
||||||
|
|
||||||
|
$scope.getSum = () ->
|
||||||
|
probs = _.pluck($scope.payload.values, "probability")
|
||||||
|
return rationals.pp(rationals.sum(probs...))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
template = """
|
||||||
|
<div class="row rat-input">
|
||||||
|
<div class="row" ng-show="!edit" >
|
||||||
|
<div class="columns large-12" style="text-align: center;">
|
||||||
|
<span class="fraction-box" ng-click="enableEdit()">
|
||||||
|
<span ng-bind="nominator"></span> ⁄ <span ng-bind="denominator" ></span>
|
||||||
|
<i class="fa fa-pencil-square-o" ng-show="!ngDisabled"></i>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div ng-show="edit" class="edit">
|
||||||
|
<form ng-submit="edit=false">
|
||||||
|
<div class="large-12 columns" style="text-align: center;">
|
||||||
|
<input ng-model="nominator" type="text" ng-change="changeModel()" ng-disabled="ngDisabled">
|
||||||
|
<span style="text-align: center;">⁄<span>
|
||||||
|
<input ng-model="denominator" type="text" ng-change="changeModel()" ng-disabled="ngDisabled">
|
||||||
|
<i class="fa fa-check" ng-click="edit=false"></i>
|
||||||
|
<input type="submit" style="display:none;">
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
define ["app", "angularAMD", "lodash", "services/rationals"], (app, angularAMD, _, rationals) ->
|
||||||
|
|
||||||
|
angularAMD.directive "ratInput", () ->
|
||||||
|
directive =
|
||||||
|
restrict: 'E',
|
||||||
|
template: template
|
||||||
|
scope:
|
||||||
|
ngModel: "="
|
||||||
|
ngDisabled: "="
|
||||||
|
controller: [ '$scope', "rationals", ($scope, rationals) ->
|
||||||
|
|
||||||
|
$scope.getNominator = ()->
|
||||||
|
if _.contains($scope.ngModel, "/")
|
||||||
|
return Number($scope.ngModel.substr(0, $scope.ngModel.indexOf("/")))
|
||||||
|
Number($scope.ngModel)
|
||||||
|
|
||||||
|
$scope.getDenominator = () ->
|
||||||
|
if _.contains($scope.ngModel, "/")
|
||||||
|
return Number($scope.ngModel.substr($scope.ngModel.indexOf("/") + 1))
|
||||||
|
1
|
||||||
|
|
||||||
|
$scope.changeModel = ()->
|
||||||
|
$scope.ngModel = rationals.newRat($scope.nominator, $scope.denominator)
|
||||||
|
|
||||||
|
$scope.enableEdit = () ->
|
||||||
|
if not $scope.ngDisabled
|
||||||
|
$scope.edit = true
|
||||||
|
|
||||||
|
$scope.init = () ->
|
||||||
|
$scope.nominator = rationals.getNominator($scope.ngModel)
|
||||||
|
$scope.denominator = $scope.getDenominator()
|
||||||
|
|
||||||
|
$scope.$watch 'ngModel', () ->
|
||||||
|
$scope.init()
|
||||||
|
|
||||||
|
$scope.init()
|
||||||
|
|
||||||
|
]
|
||||||
|
return directive
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
define ["app", "angularAMD", "lodash"], (app, angularAMD, _) ->
|
||||||
|
|
||||||
|
app.service "rationals", () ->
|
||||||
|
service =
|
||||||
|
getNominator: (rat) ->
|
||||||
|
if _.contains(rat, "/")
|
||||||
|
return Number(rat.substr(0, rat.indexOf("/")))
|
||||||
|
Number(rat)
|
||||||
|
|
||||||
|
getDenominator: (rat) ->
|
||||||
|
if _.contains(rat, "/")
|
||||||
|
return Number(rat.substr(rat.indexOf("/") + 1))
|
||||||
|
1
|
||||||
|
|
||||||
|
getNomDenom: (rat) ->
|
||||||
|
return [service.getNominator(rat), service.getDenominator(rat)]
|
||||||
|
|
||||||
|
gcd: (a, b) ->
|
||||||
|
if b == 0
|
||||||
|
return a
|
||||||
|
return service.gcd(b, a % b)
|
||||||
|
|
||||||
|
lcm: (a, b) ->
|
||||||
|
return a * b / service.gcd(a, b)
|
||||||
|
|
||||||
|
changeDenominator: (rat, newDenom) ->
|
||||||
|
[nom, denom] = service.getNomDenom(rat)
|
||||||
|
return service.newRat( nom * newDenom / denom, newDenom)
|
||||||
|
|
||||||
|
add: (rat1, rat2) ->
|
||||||
|
[nom, denom] = service.getNomDenom(rat2)
|
||||||
|
[nNom, nDenom] = service.getNomDenom(rat1)
|
||||||
|
gcd = service.gcd(nDenom, denom)
|
||||||
|
|
||||||
|
rNom = nom*nDenom + nNom * denom
|
||||||
|
rDenom = denom * nDenom
|
||||||
|
return service.newRat(rNom/gcd , rDenom/gcd)
|
||||||
|
|
||||||
|
minus: (rat1, rat2) ->
|
||||||
|
return service.add(rat1, service.opposite(rat2))
|
||||||
|
|
||||||
|
reduce: (rat) ->
|
||||||
|
[nom, denom] = service.getNomDenom(rat)
|
||||||
|
gcd = service.gcd(nom, denom)
|
||||||
|
return service.newRat(nom/gcd, denom/gcd)
|
||||||
|
|
||||||
|
opposite: (rat) ->
|
||||||
|
[nom, denom] = service.getNomDenom(rat)
|
||||||
|
return service.newRat(-nom, denom)
|
||||||
|
|
||||||
|
|
||||||
|
sum: (rats...) ->
|
||||||
|
ret = "0/1"
|
||||||
|
for rat in rats
|
||||||
|
ret = service.add(ret, rat)
|
||||||
|
return service.reduce(ret)
|
||||||
|
|
||||||
|
equal: (rat1, rat2) ->
|
||||||
|
[nom1, denom1] = service.getNomDenom(rat1)
|
||||||
|
[nom2, denom2] = service.getNomDenom(rat2)
|
||||||
|
return nom1 * denom2 == nom2 * denom1
|
||||||
|
|
||||||
|
pp: (x) ->
|
||||||
|
[num, denum] = service.getNomDenom(service.reduce(x))
|
||||||
|
if denum == 1
|
||||||
|
return num
|
||||||
|
return "#{num}/#{denum}"
|
||||||
|
|
||||||
|
|
||||||
|
newRat: (nom , denom) ->
|
||||||
|
if nom * denom >= 0
|
||||||
|
return "#{Math.abs(nom)}/#{Math.abs(denom)}"
|
||||||
|
return "#{-Math.abs(nom)}/#{Math.abs(denom)}"
|
||||||
|
|
||||||
|
return service
|
||||||
|
|
||||||
|
app.filter "ratpp", ["rationals", (rationals) ->
|
||||||
|
filter = (n) ->
|
||||||
|
return rationals.pp(n)
|
||||||
|
]
|
||||||
+1
-1
@@ -17,7 +17,7 @@ gulp.task('bower', function() {
|
|||||||
|
|
||||||
gulp.task('sass', ['bower'], function () {
|
gulp.task('sass', ['bower'], function () {
|
||||||
return gulp.src('./scss/*.scss')
|
return gulp.src('./scss/*.scss')
|
||||||
.pipe(sass({includePaths: ['bower_components/foundation/scss']}))
|
.pipe(sass({includePaths: ['bower_components/foundation/scss', 'bower_components/bourbon/app/assets/stylesheets']}))
|
||||||
.pipe(gulp.dest('./css'));
|
.pipe(gulp.dest('./css'));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
+13
-9
@@ -9,35 +9,39 @@
|
|||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body style="visibility:hidden;">
|
<body style="visibility:hidden;">
|
||||||
|
<div ng-controller="topbarCtrl">
|
||||||
|
|
||||||
<top-bar>
|
<top-bar>
|
||||||
<ul class="title-area">
|
<ul class="title-area">
|
||||||
<li class="name">
|
<li class="name">
|
||||||
<h1><a href="#">Doorman</a></h1>
|
<h1><a href="#/">Doorman</a></h1>
|
||||||
</li>
|
</li>
|
||||||
<li toggle-top-bar class="menu-icon"><a href="#">Menu</a></li>
|
<li toggle-top-bar class="menu-icon"><a >Menu</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<top-bar-section>
|
<top-bar-section>
|
||||||
<!-- Right Nav Section -->
|
<ul class="left show-for-large-up">
|
||||||
|
<li>
|
||||||
|
<a ng-bind="email" href="#"></a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
<ul class="right">
|
<ul class="right">
|
||||||
<li has-dropdown>
|
<li has-dropdown>
|
||||||
<a href="#">Dropdown</a>
|
<a >Dropdown</a>
|
||||||
<ul top-bar-dropdown>
|
<ul top-bar-dropdown ng-show="loggedIn">
|
||||||
<li><a href="#/doormen">doormen</a></li>
|
<li><a href="#/doormen">doormen</a></li>
|
||||||
<li><a href="#/newdoorman">new doorman</a></li>
|
<li><a href="#/newdoorman">new doorman</a></li>
|
||||||
<li><a href="#/apispec">api specification</a></li>
|
<li><a href="#/apispec">api specification</a></li>
|
||||||
<li><a href="#/serverspec">server specification</a></li>
|
<li><a href="#/serverspec">server specification</a></li>
|
||||||
|
<li ng-click="logout()"><a href="#/">logout</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
</top-bar-section>
|
</top-bar-section>
|
||||||
</top-bar>
|
</top-bar>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="large-12 small-12 columns" ng-view></div>
|
<div class="large-12 small-12 columns" ng-view></div>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
@@ -12,19 +12,13 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row" ng-repeat="value in doorman.values">
|
<div class="row" ng-repeat="value in doorman.values">
|
||||||
<div class="columns large-8 small-10">
|
<div class="columns large-7 small-10">
|
||||||
<label >name<input type="text" placeholder="value name" ng-value="value.name" disabled></label>
|
<label >name<input type="text" placeholder="value name" ng-value="value.name" disabled></label>
|
||||||
</div>
|
</div>
|
||||||
<div class="columns large-4 small-2">
|
<div class="columns large-4 small-2">
|
||||||
<label >
|
<label >
|
||||||
probability
|
probability
|
||||||
<input type="number"
|
<rat-input ng-model="value.probability" ng-disabled="!isAdmin"></rat-input>
|
||||||
placeholder="value probability"
|
|
||||||
ng-model="value.probability"
|
|
||||||
ng-disabled="!isAdmin"
|
|
||||||
min="0"
|
|
||||||
max="1"
|
|
||||||
step="0.01"></label>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -55,11 +49,11 @@
|
|||||||
<label>
|
<label>
|
||||||
new admin
|
new admin
|
||||||
<div class="row collapse">
|
<div class="row collapse">
|
||||||
<div class="columns large-10">
|
<div class="columns large-10 small-10">
|
||||||
|
|
||||||
<input type="text" ng-model="newEmail"/>
|
<input type="text" ng-model="newEmail"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="columns large-2">
|
<div class="columns large-2 small-2">
|
||||||
|
|
||||||
<a class="button postfix" ng-click="addNewAuthorEmail()" ng-class=" canAddNewEmail() ? '' : 'disabled' " >+</a>
|
<a class="button postfix" ng-click="addNewAuthorEmail()" ng-class=" canAddNewEmail() ? '' : 'disabled' " >+</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
<form ng-submit="login()" >
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>Login</legend>
|
<legend>Login</legend>
|
||||||
<div class="large-12 columns">
|
<div class="large-12 columns">
|
||||||
@@ -15,11 +16,12 @@
|
|||||||
<input type="text" placeholder="email" ng-model="email">
|
<input type="text" placeholder="email" ng-model="email">
|
||||||
</div>
|
</div>
|
||||||
<div class="small-2 columns">
|
<div class="small-2 columns">
|
||||||
<a class="button postfix" ng-click="login()">Login!</a>
|
<input type="submit" class="button postfix" >Login!</input>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
<form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row" ng-show="loggedEmail">
|
<div class="row" ng-show="loggedEmail">
|
||||||
|
|||||||
@@ -4,14 +4,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form>
|
<div class="row">
|
||||||
<div class="row">
|
|
||||||
<div class="columns large-12">
|
<div class="columns large-12">
|
||||||
<label >name<input type="text" placeholder="unique doorman name" ng-model="payload.name"></label>
|
<label >name<input type="text" placeholder="unique doorman name" ng-model="payload.name"></label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="columns large-12">
|
<div class="columns large-12">
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>doorman state</legend>
|
<legend>doorman state</legend>
|
||||||
@@ -21,12 +20,16 @@
|
|||||||
<label >name<input type="text" placeholder="value name" ng-model="value.name"></label>
|
<label >name<input type="text" placeholder="value name" ng-model="value.name"></label>
|
||||||
</div>
|
</div>
|
||||||
<div class="columns large-3">
|
<div class="columns large-3">
|
||||||
<label >probability<input type="number" placeholder="value probability" ng-model="value.probability" min="0" max="1" step="0.01"></label>
|
<label >probability
|
||||||
|
<rat-input ng-model="value.probability"></rat-input>
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="columns large-1">
|
<div class="columns large-1">
|
||||||
<br>
|
<br>
|
||||||
<a class="button round tiny" ng-class="{disabled: !isValidValue()}" ng-click="addNewValue()">+</a>
|
<a class="button round tiny" ng-class="{disabled: !isValidValue()}" ng-click="addNewValue()">
|
||||||
|
<i class="fa fa-plus"></i>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -35,28 +38,34 @@
|
|||||||
<label >value<input type="text" placeholder="value name" ng-model="value.name"></label>
|
<label >value<input type="text" placeholder="value name" ng-model="value.name"></label>
|
||||||
</div>
|
</div>
|
||||||
<div class="columns large-3">
|
<div class="columns large-3">
|
||||||
<label >probability<input type="number" placeholder="value probability" ng-model="value.probability" min="0" max="1" step="0.01"></label>
|
<label >probability
|
||||||
|
<rat-input ng-model="value.probability"></rat-input>
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="columns large-1">
|
<div class="columns large-1">
|
||||||
<br>
|
<br>
|
||||||
<a class="button round tiny" ng-click="removeValue( payload.values.length - $index - 1 )">-</a>
|
<a class="button round tiny" ng-click="removeValue( payload.values.length - $index - 1 )">
|
||||||
|
<i class="fa fa-times"></i>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="columns large-12">
|
<div class="columns large-12">
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>administrator</legend>
|
<legend>administrator</legend>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="columns large-11">
|
<div class="columns large-11">
|
||||||
<label>admin email <input type="text" placeholder="wild cards are allow here" ng-model="newEmail"></label>
|
<label>admin email <input type="text" placeholder="admin email" ng-model="newEmail"></label>
|
||||||
</div>
|
</div>
|
||||||
<div class="columns large-1">
|
<div class="columns large-1">
|
||||||
<br><a class="button round tiny" ng-click="addEmail()" ng-class="{disabled: !newEmail}">+</a>
|
<br><a class="button round tiny" ng-click="addEmail()" ng-class="{disabled: !newEmail}">
|
||||||
|
<i class="fa fa-plus"></i>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -65,28 +74,28 @@
|
|||||||
<label>admin email <input type="text" ng-disabled="email==user" placeholder="wild cards are allow here" ng-model="email"></label>
|
<label>admin email <input type="text" ng-disabled="email==user" placeholder="wild cards are allow here" ng-model="email"></label>
|
||||||
</div>
|
</div>
|
||||||
<div class="columns large-1">
|
<div class="columns large-1">
|
||||||
<br><a class="button round tiny" ng-click="removeEmail(payload.emails.length - $index -1)" ng-disabled="email==user? 'disabled' : ''">-</a>
|
<br><a class="button round tiny" ng-click="removeEmail(payload.emails.length - $index -1)" ng-disabled="email==user? 'disabled' : ''">
|
||||||
|
<i class="fa fa-times"></i>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row" ng-show="error">
|
<div class="row" ng-show="error">
|
||||||
<div class="columns large-12">
|
<div class="columns large-12">
|
||||||
<code style="width:100%; height:100%; display:block; margin-bottom: 1em;">{{ error }}</code>
|
<code style="width:100%; height:100%; display:block; margin-bottom: 1em;">{{ error }}</code>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="large-11 columns">
|
<div class="large-11 columns">
|
||||||
<button ng-click="createDoorman()" ng-class="{disabled: !isDoormanValid()}">create</button>
|
<button ng-click="createDoorman()" ng-class="{disabled: !isDoormanValid()}">create</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="large-1 columns">
|
<div class="large-1 columns">
|
||||||
<span >propability remaning: {{ getProbabilityRemaining() }}</span>
|
<span >propability remaning: {{ getProbabilityRemaining() | ratpp}}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</form>
|
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
@import "settings";
|
@import "settings";
|
||||||
|
@import "bourbon";
|
||||||
|
|
||||||
// @import url(http://fonts.googleapis.com/css?family=Orbitron:400,900,500,700);
|
// @import url(http://fonts.googleapis.com/css?family=Orbitron:400,900,500,700);
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Orbitron';
|
font-family: 'Orbitron';
|
||||||
@@ -26,3 +28,36 @@ h1, h2{
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.rat-input{
|
||||||
|
.fraction-box{
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 1.3em;
|
||||||
|
border: 2px;
|
||||||
|
padding: 0.3em;
|
||||||
|
box-shadow: 2px 2px 1px #888;
|
||||||
|
@include border-top-radius(5px);
|
||||||
|
@include border-bottom-radius(5px);
|
||||||
|
|
||||||
|
i{
|
||||||
|
font-size: 1em;
|
||||||
|
margin-left: 0.2em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.fraction-box:hover{
|
||||||
|
border: 2px;
|
||||||
|
padding: 0.3em;
|
||||||
|
box-shadow: 2px 2px 1px red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.edit{
|
||||||
|
input{
|
||||||
|
width: 4em;
|
||||||
|
height: 2em;
|
||||||
|
display: inline;
|
||||||
|
padding: 0px;
|
||||||
|
padding-left: 0.5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user