// UnListen detaches the EventListener from the window. func (l *EventListener) UnListen() { if l.detached == true { panic("Already detached") } jquery.NewJQuery(js.Global.Get("document")).Off(l.event, l.listener) l.detached = true }
//ParseHtml returns a NarrowDom that points at the fragment //of HTML provided in t. No attempt is made to validate that //the HTML is sensible, much less syntatically correct. func ParseHtml(t string) NarrowDom { parsed := jquery.ParseHTML(t) var nDom NarrowDom if TestMode { nDom = newTestOps() } else { if len(parsed) > 1 { div := jquery.NewJQuery(jquery.ParseHTML("<div/>")) div.Append(parsed...) return wrap(div) } else { nDom = wrap(jquery.NewJQuery(parsed[0])) } } return nDom }
// Listen attaches the Handler to the window and begins listening for the specified // jQuery event, reterning an EventListener object func Listen(event string, handler Handler) *EventListener { console.Log("Adding jQuery event listener") listener := func(event *jquery.Event, data *js.Object) bool { return handler.HandleEvent(event, data, url.Values{}) } jquery.NewJQuery(js.Global.Get("document")).On(event, listener) return &EventListener{event: event, listener: listener} }
// Run initializes the browser environment and hooks up the provided application. func Run(app env.Application) { canvas := jquery.NewJQuery("canvas#output") window, _ := NewWebGlWindow(canvas.Get(0)) app.Init(window) root := newViewModelFiller() app.ViewModel().Specialize(root) vm := ko.ViewModelFromJS(root.object) ko.ApplyBindings(vm) }
func CheckAuth(h jqeventrouter.Handler) jqeventrouter.Handler { return jqeventrouter.HandlerFunc(func(event *jquery.Event, ui *js.Object, p url.Values) bool { uri := util.JqmTargetUri(ui) if uri != "/login.html" && util.CurrentUser() == "" { // Nobody's logged in ui.Set("toPage", "login.html") event.StopImmediatePropagation() jquery.NewJQuery(":mobile-pagecontainer").Trigger("pagecontainerbeforechange", ui) return true } return h.HandleEvent(event, ui, p) }) }
//NewRadioGroup selects a named set of radio button elements //with a given name. func NewRadioGroup(name string) RadioGroup { selector := "input:radio[name=\"" + name + "\"]" result := radioGroupImpl{selector: selector} if TestMode { result.dom = newTestOps() } else { result.dom = wrap(jquery.NewJQuery(selector)) } result.attr = NewAttribute(VALUE_ONLY, result.value, nil) result.dom.On(CLICK, func(jquery.Event) { result.attr.markDirty() }) return result }
//NewSelectGroup selects one of a named set of elements, usually //rendered as a drop down list. func NewSelectGroupId(id string) SelectGroup { selector := "select#" + id result := selectGroupImpl{selector: selector} if TestMode { result.dom = newTestOps() } else { result.dom = wrap(jquery.NewJQuery(selector)) } result.attr = NewAttribute(VALUE_ONLY, result.value, nil) result.dom.On(CLICK, func(jquery.Event) { result.attr.markDirty() }) return result }
func CheckAuth(h jqeventrouter.Handler) jqeventrouter.Handler { return jqeventrouter.HandlerFunc(func(event *jquery.Event, ui *js.Object) bool { console.Log("CheckAuth") uri := util.JqmTargetUri(ui) console.Log("Auth URI = %s", uri) if uri != "/login.html" && util.CurrentUser() == "" { console.Log("nobody's logged in") // Nobody's logged in ui.Set("toPage", "login.html") event.StopImmediatePropagation() console.Log("Attempting to re-trigger the event") jquery.NewJQuery(":mobile-pagecontainer").Trigger("pagecontainerbeforechange", ui) return true } console.Log("Auth allowing to proceed") return h.HandleEvent(event, ui) }) }
//newHtmlIdNoCheck is the same as NewHtmlId except that no check is performed //to see if the named element exists in the DOM. This is useful in a few cases //where dynamically constructed HTML but should not be used by client code //because it is error prone. func newHtmlIdNoCheck(tag, id string) HtmlId { if TestMode { return htmlIdImpl{ tag: tag, id: id, t: newTestOps(), cache: make(map[string]DomAttribute), } } jq := jquery.NewJQuery(tag + "#" + id) return htmlIdImpl{ tag: tag, id: id, t: wrap(jq), cache: make(map[string]DomAttribute), } }
//NewHtmlId returns a selctor that can find tag#id in the dom. Note that //in production mode (with jquery) this panics if this not "hit" exactly //one html entity. func NewHtmlId(tag, id string) HtmlId { if TestMode { return htmlIdImpl{ tag: tag, id: id, t: newTestOps(), cache: make(map[string]DomAttribute), } } jq := jquery.NewJQuery(tag + "#" + id) if jq.Length == 0 { panic(fmt.Sprintf("probably your HTML and your code are out of sync: %s not found", tag+"#"+id)) } if jq.Length > 1 { panic(fmt.Sprintf("probably your HTML and your code are out of sync: %s not unique", tag+"#"+id)) } return htmlIdImpl{ tag: tag, id: id, t: wrap(jq), cache: make(map[string]DomAttribute), } }
func GetContext(c interface{}) *Context { return &Context{Object: jquery.NewJQuery(c).Underlying().Index(0).Call("getContext", "2d")} }
func Main(app Application) { jquery.NewJQuery(js.Global.Get("document")).Ready(func() { app.Start() }) }
//Add() is the method that is called in response to an element being //added to the collection (self.todos). This is the "magic" turns an //instance of todo into a view. func (self *todoApp) Add(length int, newObj s5.Model) { model := newObj.(*todo) //note: There are two legal things that can be passed to any //note: of the tag creation methods. Sadly, there is no way //note: to typecheck these until runtime (it is checked then). //note: //note: The two legal things are some type of option, such as //note: Class() or ModelId() that affect the resulting tag. //note: One of the common types of "options" is something creates //note: a constraint between a dom "piece" of the tag being //note: being constructed and some value, usually in the model. //note: //note: The other leagl item is another tag, that will be added //note: as a child of the one it is neted in. This lack of type //note: safety has been chosen for convenience of notation. tree := s5.LI( //LI: Pass in a model ID to generate unique id for this tag, //LI: and make easy to remove the whole subtree by id. s5.ModelId(model), //LI: constraint that toggles the completed property s5.CssExistence(completed, model.done), //LI: constraint that toggles the editing property s5.CssExistence(editing, model.editing), s5.DIV( //DIV: just one CSS class to make it look nice s5.Class(view), s5.INPUT( //INPUT: has a CSS class "toggle" to make it look nice s5.Class(toggle), //INPUT: we force the "type" of this to be the constant "checkbox" (possibly overkill) s5.HtmlAttrEqual(s5.TYPE, s5.NewStringSimple("checkbox")), //INPUT: make the checked attr be equal to the model's done s5.PropEqual(s5.CHECKED, model.done), //INPUT: when clicked, it toggles the value on the model s5.Event(s5.CHANGE, func(e jquery.Event) { model.done.Set(!model.done.Value()) }), ), s5.LABEL( //LABEL: We use a constraint to bind the name attribute of the //LABEL: model to the label's displayed text. s5.TextEqual(model.name), //LABEL: Double clicking on the label causes edit mode s5.Event(s5.DBLCLICK, func(jquery.Event) { model.editing.Set(true) //XXX UGH, don't have a handle to the input object in := s5.HtmlIdFromModel("INPUT", model).Dom() in.SetVal(model.name.Value()) in.Focus() in.Select() }), ), s5.BUTTON( //BUTTON: destroy class makes it look nice s5.Class(destroy), //BUTTON: click function that calls remove on the list //BUTTON: element that was used to create this whole structure //JQUERY: Neither of the jquery params are used. s5.Event(s5.CLICK, func(jquery.Event) { //note: we are calling remove on the *collection* which //note: will end up calling the Remove() method of our //note: joiner. If we don't tell the collection that the //note: model was removed, we could end up with a display //note: that doesn't correctly reflect the constraints //note: state (since these constraints would have dependencies //note: one items no longer visible). self.todos.Remove(model) }), ), //BUTTON ), //DIV s5.INPUT( //INPUT: Use a model to make this input easy to find s5.ModelId(model), //INPUT: edit CSS class to make it look nice s5.Class(edit), //INPUT: wire the placeholder to be name of the model... (overkill?) s5.HtmlAttrEqual(s5.PLACEHOLDER, model.name), //INPUT:the spec calls for escape to cancel editing with no change //INPUT:and for return to commit the changes EXCEPT if the //INPUT:user edited out all the text, then we should delete the //INPUT:whole thing //JQUERY: This uses the jquery selector to get the value of the input. //JQUERY: This uses the event object to get the keyboard code. s5.Event(s5.KEYDOWN, func(e jquery.Event) { //note: This type of "event handler" is the glue that //note: connects a user action to something that manipulates //note: the model. Most event handlers do not need to //note: manipulate the view as well because they have constraints //note: that connect the model to the view. switch e.Which { case 13: //This conversion is a no-op other than the go language type. //The e.Target value is ALREADY a jquery object, but it's not //typed correctly for this function to use conveniently. j := s5.WrapJQuery(jquery.NewJQuery(e.Target)) v := strings.Trim(j.Val(), CUTSET) //check for the special case of making a name=="" if v == "" { self.todos.Remove(model) } else { //just reset the model name and it propagates to display model.name.Set(v) } j.Blur() fallthrough case 27: model.editing.Set(false) primaryInput.Dom().Focus() } }), ), //INPUT ).Build() listContainer.Dom().Append(tree) }
//Start is called by concorde once the DOM is fully loaded. Most of the //application intialization code should be put in here. func (self *todoApp) Start() { //Setup an event handler for the primary input field. The called func //creates model instance and puts in the list of todos. // JQUERY: Any use of jquery is suspect as it allows many non type-safe operations. primaryInput.Dom().On(s5.CHANGE, func(event jquery.Event) { if !self.createTodo(primaryInput.Dom().Val()) { event.PreventDefault() } }) //We need to attach the self.numNotDone string to the proper place //in the DOM. Note that we use the lower-level jquery selector //(Select().Children())) plus NewTextAttr() we needed the string //child of span#todo-count (so we can't use HtmlId) and because //that object is directly in the HTML file. // JQUERY: Any use of jquery is suspect as it allows many non type-safe operations. selector := jquery.NewJQuery(todoCount.TagName() + "#" + todoCount.Id()) todoCountSelect := selector.Children("strong") s5.Equality(s5.NewTextAttr(s5.WrapJQuery(todoCountSelect)), self.numNotDone) //We need to attach the self.plural string to the proper place //in the dom. s5.Equality(pluralSpan.TextAttribute(), self.plural) //These two calls attach the inverse of the empty attribute derived //from the model collection the display property (turning them on //when the list is not empty). Note that we can't use the simpler //"Equality()" because we want to invert the value. The BooleanInverter //is a built in constraint function. sectionMain.DisplayAttribute().Attach( s5.NewBooleanInverter(self.todos.EmptyAttribute())) footer.DisplayAttribute().Attach( s5.NewBooleanInverter(self.todos.EmptyAttribute())) //This connects the display property of the clearCompleted to the boolean //that is true if some of the elements are done. This effectively //turns on the button when there are some elements in the list and //some of those elements are done. s5.Equality(clearCompleted.DisplayAttribute(), self.someDone) //This connects the display in the button to the number of done //elements. Note that this wont be visible if there are no //done elements. s5.Equality(numCompleted.TextAttribute(), self.numDone) //This is the event handler for click on the clearCompleted //dom element. We just walk the list of objects building a kill list, //then we destroy all the items in the kill list //JQUERY: Neither of the jquery params are used. clearCompleted.Dom().On(s5.CLICK, func(jquery.Event) { all := self.todos.All() if len(all) == 0 { return } dead := make([]s5.Model, len(all)) ct := 0 for _, model := range all { if model.(*todo).done.Value() { dead[ct] = model ct++ } } for _, d := range dead { self.todos.Remove(d) } }) //toggleAll's behavior is to toggle any items that are not already //marked done, unless they are all marked done in which they should all //be umarked //JQUERY: Neither of the jquery params are used. toggleAll.Dom().On(s5.CLICK, func(jquery.Event) { desired := true //Compare the output of the constraints to see if all are done if self.todos.LengthAttribute().Value() == self.numDone.Value() { desired = false } for _, m := range self.todos.All() { m.(*todo).done.Set(desired) } }) //These are discussed below. These are constraints that depend //on *all* the values in the list. self.dependsOnAll() }
func (self jqueryWrapper) RadioButton(groupName string) string { selector := "input[name=\"" + groupName + "\"][type=\"radio\"]" + ":checked" print("selector is ", selector) jq := jquery.NewJQuery(selector) return jq.Val() }
func (self jqueryWrapper) SetRadioButton(groupName string, value string) { selector := "input[name=\"" + groupName + "\"][type=\"radio\"]" print("selector is ", selector) jq := jquery.NewJQuery(selector) jq.SetVal(value) }