Repository: bep/gr Branch: master Commit: 52c9d7f2f11a Files: 64 Total size: 9.3 MB Directory structure: gitextract_4b8_jk_d/ ├── .gitignore ├── .travis.yml ├── LICENSE.md ├── Makefile ├── README.md ├── attr/ │ ├── generate.go │ ├── htmlattributes.autogen.go │ └── htmlattributes.source.txt ├── component.go ├── el/ │ ├── elements.autogen.go │ └── generate.go ├── element.go ├── event.go ├── evt/ │ ├── event.autogen.go │ └── generate.go ├── examples/ │ ├── .gitignore │ ├── ajax/ │ │ ├── ajax.js │ │ ├── index.html │ │ └── main.go │ ├── basic/ │ │ ├── basic.js │ │ ├── index.html │ │ └── main.go │ ├── basic-click-counter/ │ │ ├── basic-click-counter.js │ │ ├── index.html │ │ └── main.go │ ├── build.sh │ ├── composition/ │ │ ├── composition.js │ │ ├── index.html │ │ └── main.go │ ├── debounce/ │ │ ├── debounce.js │ │ ├── index.html │ │ └── main.go │ ├── helpers.go │ ├── interop/ │ │ ├── index.html │ │ ├── interop-ext-global.js │ │ ├── interop-ext-module-bundle.js │ │ ├── interop-ext-module.js │ │ ├── interop-ext-reverse-bundle.js │ │ ├── interop-ext-reverse.js │ │ ├── interop.js │ │ └── main.go │ ├── lifecycle/ │ │ ├── index.html │ │ ├── lifecycle.js │ │ └── main.go │ └── router/ │ ├── index.html │ ├── main.go │ └── router.js ├── helpers.go ├── lifecycle.go ├── modifiers.go ├── package.json ├── render.go ├── support/ │ └── support.go ├── tests/ │ ├── component_test.go │ ├── component_tests.inc.js │ ├── doc.go │ ├── element_test.go │ ├── event_test.go │ ├── grt/ │ │ ├── test_helpers.go │ │ ├── test_helpers.inc.js │ │ └── test_helpers_test.go │ ├── modifier_test.go │ └── this_test.go └── this.go ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # Compiled Object files, Static and Dynamic libs (Shared Objects) *.o *.a *.so # Folders _obj _test # Architecture specific extensions/prefixes *.[568vq] [568vq].out *.cgo1.go *.cgo2.c _cgo_defun.c _cgo_gotypes.go _cgo_export.* _testmain.go *.exe *.test *.prof test.* node_modules/ nohup.out ================================================ FILE: .travis.yml ================================================ sudo: false language: go env: - SOURCE_MAP_SUPPORT=false TRAVIS_NODE_VERSION="5.1" CXX="g++-4.8" go: - 1.8 install: - rm -rf ~/.nvm && git clone https://github.com/creationix/nvm.git ~/.nvm && (cd ~/.nvm && git checkout `git describe --abbrev=0 --tags`) && source ~/.nvm/nvm.sh && nvm install $TRAVIS_NODE_VERSION - node -v - go get -u github.com/gopherjs/gopherjs - npm install - npm install --global node-gyp - pushd $HOME/gopath/src/github.com/gopherjs/gopherjs/node-syscall && node-gyp rebuild && mkdir -p ~/.node_libraries/ && cp build/Release/syscall.node ~/.node_libraries/syscall.node && popd script: - make check os: - linux addons: apt: sources: - ubuntu-toolchain-r-test packages: - g++-4.8 notifications: email: true ================================================ FILE: LICENSE.md ================================================ Apache License ============== _Version 2.0, January 2004_ _<>_ ### Terms and Conditions for use, reproduction, and distribution #### 1. Definitions “License” shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. “Licensor” shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. “Legal Entity” shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, “control” means **(i)** the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or **(ii)** ownership of fifty percent (50%) or more of the outstanding shares, or **(iii)** beneficial ownership of such entity. “You” (or “Your”) shall mean an individual or Legal Entity exercising permissions granted by this License. “Source” form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. “Object” form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. “Work” shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). “Derivative Works” shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. “Contribution” shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, “submitted” means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as “Not a Contribution.” “Contributor” shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. #### 2. Grant of Copyright License Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. #### 3. Grant of Patent License Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. #### 4. Redistribution You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: * **(a)** You must give any other recipients of the Work or Derivative Works a copy of this License; and * **(b)** You must cause any modified files to carry prominent notices stating that You changed the files; and * **(c)** You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and * **(d)** If the Work includes a “NOTICE” text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. #### 5. Submission of Contributions Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. #### 6. Trademarks This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. #### 7. Disclaimer of Warranty Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. #### 8. Limitation of Liability In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. #### 9. Accepting Warranty or Additional Liability While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. _END OF TERMS AND CONDITIONS_ ### APPENDIX: How to apply the Apache License to your work To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets `[]` replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same “printed page” as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: Makefile ================================================ DIRS=$(shell go list -f {{.Dir}} ./...) check: fmt vet lint test cyclo: @for d in $(DIRS) ; do \ if [ "`gocyclo -over 20 $$d | tee /dev/stderr`" ]; then \ echo "^ cyclomatic complexity exceeds 20, refactor the code!" && echo && exit 1; \ fi \ done fmt: @for d in $(DIRS) ; do \ if [ "`gofmt -l -s $$d/*.go | tee /dev/stderr`" ]; then \ echo "^ improperly formatted go files" && echo && exit 1; \ fi \ done lint: @if [ "`golint -min_confidence 0.85 ./... | tee /dev/stderr`" ]; then \ echo "^ golint errors!" && echo && exit 1; \ fi test: gopherjs test github.com/bep/gr/tests vet: @if [ "`go vet ./... | tee /dev/stderr`" ]; then \ echo "^ go vet errors!" && echo && exit 1; \ fi ================================================ FILE: README.md ================================================ # Go React [![Build Status](https://travis-ci.org/bep/gr.svg)](https://travis-ci.org/bep/gr) [![GoDoc](https://godoc.org/github.com/bep/gr?status.svg)](https://godoc.org/github.com/bep/gr) [![Go Report Card](https://goreportcard.com/badge/github.com/bep/gr)](https://goreportcard.com/report/github.com/bep/gr) **See Also:** * https://github.com/bep/grcomponents * [grouter: react-router bindings](https://github.com/bep/grouter) [GopherJS](https://github.com/gopherjs/gopherjs) bindings for Facebook React. **NOTE: Still early and not production ready.** ## Examples **NOTE: Make sure that your GopherJS is up-to-date before running these: `go get -u github.com/gopherjs/gopherjs`** For a live demo of the examples below, see [http://bego.io/gr/](http://bego.io/gr/) (may not be up-to-date). There are some runnable examples in `/examples`. Just navigate to that folder and do a: ```bash gopherjs serve ``` Then navigate to [http://localhost:8080/github.com/bep/gr/examples/](http://localhost:8080/github.com/bep/gr/examples/). To get a sense of the API, here is the [click-counter](https://github.com/bep/gr/blob/master/examples/basic-click-counter/main.go) example: ```go func main() { component := gr.New(new(clickCounter)) gr.RenderLoop(func() { component.Render("react", gr.Props{}) }) } type clickCounter struct { *gr.This } // Implements the StateInitializer interface. func (c clickCounter) GetInitialState() gr.State { return gr.State{"counter": 0} } // Implements the Renderer interface. func (c clickCounter) Render() gr.Component { counter := c.State()["counter"] message := fmt.Sprintf(" Click me! Number of clicks: %v", counter) elem := el.Div( el.Button( gr.CSS("btn", "btn-lg", "btn-primary"), gr.Style("color", "orange"), gr.Text(message), evt.Click(c.onClick))) return examples.Example("Click Counter", elem) } func (c clickCounter) onClick(event *gr.Event) { c.SetState(gr.State{"counter": c.State().Int("counter") + 1}) } // Implements the ShouldComponentUpdate interface. func (c clickCounter) ShouldComponentUpdate(next gr.Cops) bool { return c.State().HasChanged(next.State, "counter") } ``` For help installing GopherJS, please visit [that cool project](https://github.com/gopherjs/gopherjs). ## Inspiration This project is highly inspired by [Vecty](https://github.com/gopherjs/vecty), a *promising and pure* Go React-like framework. If you're not heavily invested in Facebook's React, take that for a spin. ================================================ FILE: attr/generate.go ================================================ // +build ignore /* Copyright 2016 Bjørn Erik Pedersen All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package main import ( "fmt" "io/ioutil" "log" "os" "sort" "strings" ) var altDoc = map[string]string{ "key": `Key adds an optional, unique identifier. When your component shuffles around during render passes, it might be destroyed and recreated due to the diff algorithm. Assigning it a key that persists makes sure the component stays.`, "ref": "Ref adds an ref to a component, see http://facebook.github.io/react/docs/more-about-refs.html", "dangerouslySetInnerHTML": `DangerouslySetInnerHTML Provides the ability to insert raw HTML, mainly for cooperating with DOM string manipulation libraries.`, "defaultValue": `DefaultValue can be used to initialize an uncontrolled React component with a non-empty value. See https://facebook.github.io/react/docs/forms.html`, } var altType = map[string]string{ "key": "interface{}", "ref": "interface{}", "dangerouslySetInnerHTML": "interface{}", } func main() { b, err := ioutil.ReadFile("htmlattributes.source.txt") if err != nil { log.Fatal(err) } replacements := strings.NewReplacer( "Html", "HTML", "Http", "HTTP", "Href", "HRef", "Id", "ID", "Wmode", "WMode") source := string(b) file, err := os.Create("htmlattributes.autogen.go") if err != nil { panic(err) } defer file.Close() fmt.Fprint(file, `//go:generate go run generate.go // Package attr defines markup to create HTML attributes supported by Facebook React. // // Created from "HTML Attributes" as defined by Facebook in // - https://facebook.github.io/react/docs/tags-and-attributes.html // - http://facebook.github.io/react/docs/special-non-dom-attributes.html package attr import "github.com/bep/gr" `) words := strings.Fields(source) sort.Strings(words) for _, w := range words { funcName := strings.Title(w) funcName = replacements.Replace(funcName) docString := fmt.Sprintf("%s creates an HTML attribute for '%s'.", funcName, w) propType := "interface{}" if alt, ok := altDoc[w]; ok { docString = strings.Replace(alt, "\n", "\n// ", -1) } if alt, ok := altType[w]; ok { propType = alt } funcBody := fmt.Sprintf(` // %s func %s(v %s) gr.Modifier { return gr.Prop("%s", v) } `, docString, funcName, propType, w) fmt.Fprintf(file, "%s", funcBody) } } ================================================ FILE: attr/htmlattributes.autogen.go ================================================ //go:generate go run generate.go // Package attr defines markup to create HTML attributes supported by Facebook React. // // Created from "HTML Attributes" as defined by Facebook in // - https://facebook.github.io/react/docs/tags-and-attributes.html // - http://facebook.github.io/react/docs/special-non-dom-attributes.html package attr import "github.com/bep/gr" // About creates an HTML attribute for 'about'. func About(v interface{}) gr.Modifier { return gr.Prop("about", v) } // Accept creates an HTML attribute for 'accept'. func Accept(v interface{}) gr.Modifier { return gr.Prop("accept", v) } // AcceptCharset creates an HTML attribute for 'acceptCharset'. func AcceptCharset(v interface{}) gr.Modifier { return gr.Prop("acceptCharset", v) } // AccessKey creates an HTML attribute for 'accessKey'. func AccessKey(v interface{}) gr.Modifier { return gr.Prop("accessKey", v) } // Action creates an HTML attribute for 'action'. func Action(v interface{}) gr.Modifier { return gr.Prop("action", v) } // AllowFullScreen creates an HTML attribute for 'allowFullScreen'. func AllowFullScreen(v interface{}) gr.Modifier { return gr.Prop("allowFullScreen", v) } // AllowTransparency creates an HTML attribute for 'allowTransparency'. func AllowTransparency(v interface{}) gr.Modifier { return gr.Prop("allowTransparency", v) } // Alt creates an HTML attribute for 'alt'. func Alt(v interface{}) gr.Modifier { return gr.Prop("alt", v) } // Async creates an HTML attribute for 'async'. func Async(v interface{}) gr.Modifier { return gr.Prop("async", v) } // AutoCapitalize creates an HTML attribute for 'autoCapitalize'. func AutoCapitalize(v interface{}) gr.Modifier { return gr.Prop("autoCapitalize", v) } // AutoComplete creates an HTML attribute for 'autoComplete'. func AutoComplete(v interface{}) gr.Modifier { return gr.Prop("autoComplete", v) } // AutoCorrect creates an HTML attribute for 'autoCorrect'. func AutoCorrect(v interface{}) gr.Modifier { return gr.Prop("autoCorrect", v) } // AutoFocus creates an HTML attribute for 'autoFocus'. func AutoFocus(v interface{}) gr.Modifier { return gr.Prop("autoFocus", v) } // AutoPlay creates an HTML attribute for 'autoPlay'. func AutoPlay(v interface{}) gr.Modifier { return gr.Prop("autoPlay", v) } // AutoSave creates an HTML attribute for 'autoSave'. func AutoSave(v interface{}) gr.Modifier { return gr.Prop("autoSave", v) } // Capture creates an HTML attribute for 'capture'. func Capture(v interface{}) gr.Modifier { return gr.Prop("capture", v) } // CellPadding creates an HTML attribute for 'cellPadding'. func CellPadding(v interface{}) gr.Modifier { return gr.Prop("cellPadding", v) } // CellSpacing creates an HTML attribute for 'cellSpacing'. func CellSpacing(v interface{}) gr.Modifier { return gr.Prop("cellSpacing", v) } // Challenge creates an HTML attribute for 'challenge'. func Challenge(v interface{}) gr.Modifier { return gr.Prop("challenge", v) } // CharSet creates an HTML attribute for 'charSet'. func CharSet(v interface{}) gr.Modifier { return gr.Prop("charSet", v) } // Checked creates an HTML attribute for 'checked'. func Checked(v interface{}) gr.Modifier { return gr.Prop("checked", v) } // Cite creates an HTML attribute for 'cite'. func Cite(v interface{}) gr.Modifier { return gr.Prop("cite", v) } // ClassID creates an HTML attribute for 'classID'. func ClassID(v interface{}) gr.Modifier { return gr.Prop("classID", v) } // ClassName creates an HTML attribute for 'className'. func ClassName(v interface{}) gr.Modifier { return gr.Prop("className", v) } // ColSpan creates an HTML attribute for 'colSpan'. func ColSpan(v interface{}) gr.Modifier { return gr.Prop("colSpan", v) } // Color creates an HTML attribute for 'color'. func Color(v interface{}) gr.Modifier { return gr.Prop("color", v) } // Cols creates an HTML attribute for 'cols'. func Cols(v interface{}) gr.Modifier { return gr.Prop("cols", v) } // Content creates an HTML attribute for 'content'. func Content(v interface{}) gr.Modifier { return gr.Prop("content", v) } // ContentEditable creates an HTML attribute for 'contentEditable'. func ContentEditable(v interface{}) gr.Modifier { return gr.Prop("contentEditable", v) } // ContextMenu creates an HTML attribute for 'contextMenu'. func ContextMenu(v interface{}) gr.Modifier { return gr.Prop("contextMenu", v) } // Controls creates an HTML attribute for 'controls'. func Controls(v interface{}) gr.Modifier { return gr.Prop("controls", v) } // Coords creates an HTML attribute for 'coords'. func Coords(v interface{}) gr.Modifier { return gr.Prop("coords", v) } // CrossOrigin creates an HTML attribute for 'crossOrigin'. func CrossOrigin(v interface{}) gr.Modifier { return gr.Prop("crossOrigin", v) } // DangerouslySetInnerHTML Provides the ability to insert raw HTML, // mainly for cooperating with DOM string manipulation libraries. func DangerouslySetInnerHTML(v interface{}) gr.Modifier { return gr.Prop("dangerouslySetInnerHTML", v) } // Data creates an HTML attribute for 'data'. func Data(v interface{}) gr.Modifier { return gr.Prop("data", v) } // Datatype creates an HTML attribute for 'datatype'. func Datatype(v interface{}) gr.Modifier { return gr.Prop("datatype", v) } // DateTime creates an HTML attribute for 'dateTime'. func DateTime(v interface{}) gr.Modifier { return gr.Prop("dateTime", v) } // Default creates an HTML attribute for 'default'. func Default(v interface{}) gr.Modifier { return gr.Prop("default", v) } // DefaultValue can be used to initialize an uncontrolled React component with a non-empty value. // // See https://facebook.github.io/react/docs/forms.html func DefaultValue(v interface{}) gr.Modifier { return gr.Prop("defaultValue", v) } // Defer creates an HTML attribute for 'defer'. func Defer(v interface{}) gr.Modifier { return gr.Prop("defer", v) } // Dir creates an HTML attribute for 'dir'. func Dir(v interface{}) gr.Modifier { return gr.Prop("dir", v) } // Disabled creates an HTML attribute for 'disabled'. func Disabled(v interface{}) gr.Modifier { return gr.Prop("disabled", v) } // Download creates an HTML attribute for 'download'. func Download(v interface{}) gr.Modifier { return gr.Prop("download", v) } // Draggable creates an HTML attribute for 'draggable'. func Draggable(v interface{}) gr.Modifier { return gr.Prop("draggable", v) } // EncType creates an HTML attribute for 'encType'. func EncType(v interface{}) gr.Modifier { return gr.Prop("encType", v) } // Form creates an HTML attribute for 'form'. func Form(v interface{}) gr.Modifier { return gr.Prop("form", v) } // FormAction creates an HTML attribute for 'formAction'. func FormAction(v interface{}) gr.Modifier { return gr.Prop("formAction", v) } // FormEncType creates an HTML attribute for 'formEncType'. func FormEncType(v interface{}) gr.Modifier { return gr.Prop("formEncType", v) } // FormMethod creates an HTML attribute for 'formMethod'. func FormMethod(v interface{}) gr.Modifier { return gr.Prop("formMethod", v) } // FormNoValidate creates an HTML attribute for 'formNoValidate'. func FormNoValidate(v interface{}) gr.Modifier { return gr.Prop("formNoValidate", v) } // FormTarget creates an HTML attribute for 'formTarget'. func FormTarget(v interface{}) gr.Modifier { return gr.Prop("formTarget", v) } // FrameBorder creates an HTML attribute for 'frameBorder'. func FrameBorder(v interface{}) gr.Modifier { return gr.Prop("frameBorder", v) } // Headers creates an HTML attribute for 'headers'. func Headers(v interface{}) gr.Modifier { return gr.Prop("headers", v) } // Height creates an HTML attribute for 'height'. func Height(v interface{}) gr.Modifier { return gr.Prop("height", v) } // Hidden creates an HTML attribute for 'hidden'. func Hidden(v interface{}) gr.Modifier { return gr.Prop("hidden", v) } // High creates an HTML attribute for 'high'. func High(v interface{}) gr.Modifier { return gr.Prop("high", v) } // HRef creates an HTML attribute for 'href'. func HRef(v interface{}) gr.Modifier { return gr.Prop("href", v) } // HRefLang creates an HTML attribute for 'hrefLang'. func HRefLang(v interface{}) gr.Modifier { return gr.Prop("hrefLang", v) } // HTMLFor creates an HTML attribute for 'htmlFor'. func HTMLFor(v interface{}) gr.Modifier { return gr.Prop("htmlFor", v) } // HTTPEquiv creates an HTML attribute for 'httpEquiv'. func HTTPEquiv(v interface{}) gr.Modifier { return gr.Prop("httpEquiv", v) } // Icon creates an HTML attribute for 'icon'. func Icon(v interface{}) gr.Modifier { return gr.Prop("icon", v) } // ID creates an HTML attribute for 'id'. func ID(v interface{}) gr.Modifier { return gr.Prop("id", v) } // Inlist creates an HTML attribute for 'inlist'. func Inlist(v interface{}) gr.Modifier { return gr.Prop("inlist", v) } // InputMode creates an HTML attribute for 'inputMode'. func InputMode(v interface{}) gr.Modifier { return gr.Prop("inputMode", v) } // Integrity creates an HTML attribute for 'integrity'. func Integrity(v interface{}) gr.Modifier { return gr.Prop("integrity", v) } // Is creates an HTML attribute for 'is'. func Is(v interface{}) gr.Modifier { return gr.Prop("is", v) } // ItemProp creates an HTML attribute for 'itemProp'. func ItemProp(v interface{}) gr.Modifier { return gr.Prop("itemProp", v) } // Key adds an optional, unique identifier. // When your component shuffles around during render passes, it might be destroyed // and recreated due to the diff algorithm. Assigning it a key that persists makes // sure the component stays. func Key(v interface{}) gr.Modifier { return gr.Prop("key", v) } // KeyParams creates an HTML attribute for 'keyParams'. func KeyParams(v interface{}) gr.Modifier { return gr.Prop("keyParams", v) } // KeyType creates an HTML attribute for 'keyType'. func KeyType(v interface{}) gr.Modifier { return gr.Prop("keyType", v) } // Kind creates an HTML attribute for 'kind'. func Kind(v interface{}) gr.Modifier { return gr.Prop("kind", v) } // Label creates an HTML attribute for 'label'. func Label(v interface{}) gr.Modifier { return gr.Prop("label", v) } // Lang creates an HTML attribute for 'lang'. func Lang(v interface{}) gr.Modifier { return gr.Prop("lang", v) } // List creates an HTML attribute for 'list'. func List(v interface{}) gr.Modifier { return gr.Prop("list", v) } // Loop creates an HTML attribute for 'loop'. func Loop(v interface{}) gr.Modifier { return gr.Prop("loop", v) } // Low creates an HTML attribute for 'low'. func Low(v interface{}) gr.Modifier { return gr.Prop("low", v) } // Manifest creates an HTML attribute for 'manifest'. func Manifest(v interface{}) gr.Modifier { return gr.Prop("manifest", v) } // MarginHeight creates an HTML attribute for 'marginHeight'. func MarginHeight(v interface{}) gr.Modifier { return gr.Prop("marginHeight", v) } // MarginWidth creates an HTML attribute for 'marginWidth'. func MarginWidth(v interface{}) gr.Modifier { return gr.Prop("marginWidth", v) } // Max creates an HTML attribute for 'max'. func Max(v interface{}) gr.Modifier { return gr.Prop("max", v) } // MaxLength creates an HTML attribute for 'maxLength'. func MaxLength(v interface{}) gr.Modifier { return gr.Prop("maxLength", v) } // Media creates an HTML attribute for 'media'. func Media(v interface{}) gr.Modifier { return gr.Prop("media", v) } // MediaGroup creates an HTML attribute for 'mediaGroup'. func MediaGroup(v interface{}) gr.Modifier { return gr.Prop("mediaGroup", v) } // Method creates an HTML attribute for 'method'. func Method(v interface{}) gr.Modifier { return gr.Prop("method", v) } // Min creates an HTML attribute for 'min'. func Min(v interface{}) gr.Modifier { return gr.Prop("min", v) } // MinLength creates an HTML attribute for 'minLength'. func MinLength(v interface{}) gr.Modifier { return gr.Prop("minLength", v) } // Multiple creates an HTML attribute for 'multiple'. func Multiple(v interface{}) gr.Modifier { return gr.Prop("multiple", v) } // Muted creates an HTML attribute for 'muted'. func Muted(v interface{}) gr.Modifier { return gr.Prop("muted", v) } // Name creates an HTML attribute for 'name'. func Name(v interface{}) gr.Modifier { return gr.Prop("name", v) } // NoValidate creates an HTML attribute for 'noValidate'. func NoValidate(v interface{}) gr.Modifier { return gr.Prop("noValidate", v) } // Nonce creates an HTML attribute for 'nonce'. func Nonce(v interface{}) gr.Modifier { return gr.Prop("nonce", v) } // Open creates an HTML attribute for 'open'. func Open(v interface{}) gr.Modifier { return gr.Prop("open", v) } // Optimum creates an HTML attribute for 'optimum'. func Optimum(v interface{}) gr.Modifier { return gr.Prop("optimum", v) } // Pattern creates an HTML attribute for 'pattern'. func Pattern(v interface{}) gr.Modifier { return gr.Prop("pattern", v) } // Placeholder creates an HTML attribute for 'placeholder'. func Placeholder(v interface{}) gr.Modifier { return gr.Prop("placeholder", v) } // Poster creates an HTML attribute for 'poster'. func Poster(v interface{}) gr.Modifier { return gr.Prop("poster", v) } // Prefix creates an HTML attribute for 'prefix'. func Prefix(v interface{}) gr.Modifier { return gr.Prop("prefix", v) } // Preload creates an HTML attribute for 'preload'. func Preload(v interface{}) gr.Modifier { return gr.Prop("preload", v) } // Profile creates an HTML attribute for 'profile'. func Profile(v interface{}) gr.Modifier { return gr.Prop("profile", v) } // Property creates an HTML attribute for 'property'. func Property(v interface{}) gr.Modifier { return gr.Prop("property", v) } // RadioGroup creates an HTML attribute for 'radioGroup'. func RadioGroup(v interface{}) gr.Modifier { return gr.Prop("radioGroup", v) } // ReadOnly creates an HTML attribute for 'readOnly'. func ReadOnly(v interface{}) gr.Modifier { return gr.Prop("readOnly", v) } // Ref adds an ref to a component, see http://facebook.github.io/react/docs/more-about-refs.html func Ref(v interface{}) gr.Modifier { return gr.Prop("ref", v) } // Rel creates an HTML attribute for 'rel'. func Rel(v interface{}) gr.Modifier { return gr.Prop("rel", v) } // Required creates an HTML attribute for 'required'. func Required(v interface{}) gr.Modifier { return gr.Prop("required", v) } // Resource creates an HTML attribute for 'resource'. func Resource(v interface{}) gr.Modifier { return gr.Prop("resource", v) } // Results creates an HTML attribute for 'results'. func Results(v interface{}) gr.Modifier { return gr.Prop("results", v) } // Reversed creates an HTML attribute for 'reversed'. func Reversed(v interface{}) gr.Modifier { return gr.Prop("reversed", v) } // Role creates an HTML attribute for 'role'. func Role(v interface{}) gr.Modifier { return gr.Prop("role", v) } // RowSpan creates an HTML attribute for 'rowSpan'. func RowSpan(v interface{}) gr.Modifier { return gr.Prop("rowSpan", v) } // Rows creates an HTML attribute for 'rows'. func Rows(v interface{}) gr.Modifier { return gr.Prop("rows", v) } // Sandbox creates an HTML attribute for 'sandbox'. func Sandbox(v interface{}) gr.Modifier { return gr.Prop("sandbox", v) } // Scope creates an HTML attribute for 'scope'. func Scope(v interface{}) gr.Modifier { return gr.Prop("scope", v) } // Scoped creates an HTML attribute for 'scoped'. func Scoped(v interface{}) gr.Modifier { return gr.Prop("scoped", v) } // Scrolling creates an HTML attribute for 'scrolling'. func Scrolling(v interface{}) gr.Modifier { return gr.Prop("scrolling", v) } // Seamless creates an HTML attribute for 'seamless'. func Seamless(v interface{}) gr.Modifier { return gr.Prop("seamless", v) } // Security creates an HTML attribute for 'security'. func Security(v interface{}) gr.Modifier { return gr.Prop("security", v) } // Selected creates an HTML attribute for 'selected'. func Selected(v interface{}) gr.Modifier { return gr.Prop("selected", v) } // Shape creates an HTML attribute for 'shape'. func Shape(v interface{}) gr.Modifier { return gr.Prop("shape", v) } // Size creates an HTML attribute for 'size'. func Size(v interface{}) gr.Modifier { return gr.Prop("size", v) } // Sizes creates an HTML attribute for 'sizes'. func Sizes(v interface{}) gr.Modifier { return gr.Prop("sizes", v) } // Span creates an HTML attribute for 'span'. func Span(v interface{}) gr.Modifier { return gr.Prop("span", v) } // SpellCheck creates an HTML attribute for 'spellCheck'. func SpellCheck(v interface{}) gr.Modifier { return gr.Prop("spellCheck", v) } // Src creates an HTML attribute for 'src'. func Src(v interface{}) gr.Modifier { return gr.Prop("src", v) } // SrcDoc creates an HTML attribute for 'srcDoc'. func SrcDoc(v interface{}) gr.Modifier { return gr.Prop("srcDoc", v) } // SrcLang creates an HTML attribute for 'srcLang'. func SrcLang(v interface{}) gr.Modifier { return gr.Prop("srcLang", v) } // SrcSet creates an HTML attribute for 'srcSet'. func SrcSet(v interface{}) gr.Modifier { return gr.Prop("srcSet", v) } // Start creates an HTML attribute for 'start'. func Start(v interface{}) gr.Modifier { return gr.Prop("start", v) } // Step creates an HTML attribute for 'step'. func Step(v interface{}) gr.Modifier { return gr.Prop("step", v) } // Style creates an HTML attribute for 'style'. func Style(v interface{}) gr.Modifier { return gr.Prop("style", v) } // Summary creates an HTML attribute for 'summary'. func Summary(v interface{}) gr.Modifier { return gr.Prop("summary", v) } // TabIndex creates an HTML attribute for 'tabIndex'. func TabIndex(v interface{}) gr.Modifier { return gr.Prop("tabIndex", v) } // Target creates an HTML attribute for 'target'. func Target(v interface{}) gr.Modifier { return gr.Prop("target", v) } // Title creates an HTML attribute for 'title'. func Title(v interface{}) gr.Modifier { return gr.Prop("title", v) } // Type creates an HTML attribute for 'type'. func Type(v interface{}) gr.Modifier { return gr.Prop("type", v) } // Typeof creates an HTML attribute for 'typeof'. func Typeof(v interface{}) gr.Modifier { return gr.Prop("typeof", v) } // Unselectable creates an HTML attribute for 'unselectable'. func Unselectable(v interface{}) gr.Modifier { return gr.Prop("unselectable", v) } // UseMap creates an HTML attribute for 'useMap'. func UseMap(v interface{}) gr.Modifier { return gr.Prop("useMap", v) } // Value creates an HTML attribute for 'value'. func Value(v interface{}) gr.Modifier { return gr.Prop("value", v) } // Vocab creates an HTML attribute for 'vocab'. func Vocab(v interface{}) gr.Modifier { return gr.Prop("vocab", v) } // Width creates an HTML attribute for 'width'. func Width(v interface{}) gr.Modifier { return gr.Prop("width", v) } // WMode creates an HTML attribute for 'wmode'. func WMode(v interface{}) gr.Modifier { return gr.Prop("wmode", v) } // Wrap creates an HTML attribute for 'wrap'. func Wrap(v interface{}) gr.Modifier { return gr.Prop("wrap", v) } ================================================ FILE: attr/htmlattributes.source.txt ================================================ accept acceptCharset accessKey action allowFullScreen allowTransparency alt async autoComplete autoFocus autoPlay capture cellPadding cellSpacing challenge charSet checked cite classID className colSpan cols content contentEditable contextMenu controls coords crossOrigin data dateTime default defer dir disabled download draggable encType form formAction formEncType formMethod formNoValidate formTarget frameBorder headers height hidden high href hrefLang htmlFor httpEquiv icon id inputMode integrity is keyParams keyType kind label lang list loop low manifest marginHeight marginWidth max maxLength media mediaGroup method min minLength multiple muted name noValidate nonce open optimum pattern placeholder poster preload profile radioGroup readOnly rel required reversed role rowSpan rows sandbox scope scoped scrolling seamless selected shape size sizes span spellCheck src srcDoc srcLang srcSet start step style summary tabIndex target title type useMap value width wmode wrap about datatype inlist prefix property resource typeof vocab autoCapitalize autoCorrect color itemProp security unselectable results autoSave key ref dangerouslySetInnerHTML defaultValue ================================================ FILE: component.go ================================================ /* Copyright 2016 Bjørn Erik Pedersen All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package gr import ( "errors" "fmt" "strings" "reflect" "github.com/bep/gr/support" "github.com/gopherjs/gopherjs/js" ) var ( react = js.Global.Get("React") reactDOM = js.Global.Get("ReactDOM") ) func init() { if react == js.Undefined || reactDOM == js.Undefined { // Require as a fallback var err error if react, err = support.Require("react"); err != nil { panic(fmt.Sprintf("Cannot find React")) } if reactDOM, err = support.Require("react-dom"); err != nil { panic(fmt.Sprintf("Cannot find ReactDOM")) } } } // A Component represents a React JS component. // // http://facebook.github.io/react/docs/glossary.html#react-nodes for a reference. // // A Component can be either a constructed element (analogous to a ReactElement) // or a factory (a ReactClass or a ReactFactory). Factories are identified by their // implementation of the Factory interface. type Component interface { Node() *js.Object } // A Factory is a Component that can construct Elements (analogous to a ReactClass or a ReactFactory). type Factory interface { Component CreateElement(props Props, children ...Component) *Element } // ReactComponent wraps a Facebook React component. // This component can either be constructed from a Go implementation (see New) or // loaded from JavaScript (see FromGlobal and Require). type ReactComponent struct { // The React.createClass response. node *js.Object // Prototype cached for the cloning purpose. elementPrototype *js.Object // The minimum interface needed to display something. r Renderer reactClass *reactClass // Options exportName string globalName string componentConfig ComponentConfig // Needs to be created by createElement as opposed to standalone React factories. // TODO(bep) figure a way to extract that info from the JS object. needsCreate bool } // FromGlobal loads a React component from JavaScript's global object // ("window" for browsers and "GLOBAL" for Node.js) func FromGlobal(path ...string) *ReactComponent { var component *js.Object for _, p := range path { if component != nil { component = component.Get(p) } else { component = js.Global.Get(p) } } if component == nil || component == js.Undefined { panic(fmt.Sprintf("JS component in path %v not found", path)) } // TODO(bep): No concept of a Renderer implementation here. Do we need it? return &ReactComponent{node: component, needsCreate: true} } // Require loads a module the Node.js way. // Note that this requires that the require function is present; if in the browser, // and not in Node.js, try Browserify. func Require(path ...string) *ReactComponent { m, err := support.Require(path...) if err != nil { panic(err) } return &ReactComponent{node: m, needsCreate: true} } // ComponentConfig is used to add optional static configuration to a component. type ComponentConfig struct { ContextTypesTemplate Context } // Option is used to configure a component. type Option struct { action func(*ReactComponent) error // Whether to apply this option on the created React component or not. preparePhase bool } // WithConfig adds optional static configuration to the component. func WithConfig(config ComponentConfig) Option { // This needs to run before createClass return Option{preparePhase: true, action: func(r *ReactComponent) error { r.componentConfig = config return nil }} } // Export is an option used to mark that the component should be exported to the // JavaScript world as a Node.js module export. func Export(name string) Option { return Option{action: func(r *ReactComponent) error { if name == "" { return errors.New("Must provide export name") } r.exportName = name return nil }} } // Global is an option used to mark that the component should be exported to the // JavaScript world as a global with the given name. func Global(name string) Option { return Option{action: func(r *ReactComponent) error { if name == "" { return errors.New("Must provide global name") } r.globalName = name return nil }} } // Apply the func to the newly created React component. func Apply(f func(o *js.Object) *js.Object) Option { return Option{action: func(r *ReactComponent) error { r.node = f(r.node) return nil }} } // NewSimpleRenderer can be used for quickly putting together components that only // need to implement Renderer with no need of the owner (this) argument. func NewSimpleRenderer(c Component) Renderer { return simpleRenderer{c} } type simpleRenderer struct { c Component } // Implements the Renderer interface. func (s simpleRenderer) Render() Component { return s.c } // NewSimpleComponent can be used for quickly putting together components that only // need to implement Renderer with no need of the owner (this) argument. // Especially convenient for testing. func NewSimpleComponent(c Component, options ...Option) *ReactComponent { return New(NewSimpleRenderer(c), options...) } type reactClass struct { *js.Object displayName string `js:"displayName"` render *js.Object `js:"render"` getDefaultProps *js.Object `js:"getDefaultProps"` getInitialState *js.Object `js:"getInitialState"` getChildContext *js.Object `js:"getChildContext"` childContextTypes js.M `js:"childContextTypes"` contextTypes js.M `js:"contextTypes"` shouldComponentUpdate *js.Object `js:"shouldComponentUpdate"` componentWillUpdate *js.Object `js:"componentWillUpdate"` componentDidUpdate *js.Object `js:"componentDidUpdate"` componentWillReceiveProps *js.Object `js:"componentWillReceiveProps"` componentWillMount *js.Object `js:"componentWillMount"` componentDidMount *js.Object `js:"componentDidMount"` componentWillUnmount *js.Object `js:"componentWillUnmount"` } type delegateRenderer struct { delegate func() Component } // Render implements the Renderer interface. func (d delegateRenderer) Render() Component { return d.delegate() } // NewRenderer creates a Renderer with the provided func as the implementation. func NewRenderer(renderFunc func() Component) Renderer { return delegateRenderer{renderFunc} } // New creates a new Component given a Renderer and optional option(s). // Note that the Renderer is the minimum interface that needs to be implemented, // but New will perform interface upgrades for other lifecycle interfaces. func New(r Renderer, options ...Option) *ReactComponent { root := &ReactComponent{r: r, reactClass: &reactClass{Object: js.Global.Get("Object").New()}} typ := fmt.Sprintf("%T", r) displayName := strings.TrimLeft(typ, "*") root.reactClass.displayName = displayName // TODO(bep) // getDefaultProps propTypes https://github.com/bep/gr/issues/23 // mixins https://github.com/bep/gr/issues/24 // statics https://github.com/bep/gr/issues/25 ts := extractThisSetter(r) // Every component needs to render itself. root.reactClass.render = makeRenderFunc(ts, displayName, r.Render) // Optional lifecycle implementations below. if v, ok := r.(StateInitializer); ok { root.reactClass.getInitialState = makeStateFunc(ts, v.GetInitialState) } else if ts != nil { root.reactClass.getInitialState = js.MakeFunc(func(this *js.Object, arguments []*js.Object) interface{} { ts.SetThis(this) return nil }) } if v, ok := r.(ChildContextProvider); ok { root.reactClass.getChildContext, root.reactClass.childContextTypes = makeChildContextFunc(ts, v.GetChildContext) } if v, ok := r.(ShouldComponentUpdate); ok { root.reactClass.shouldComponentUpdate = makeComponentUpdateFunc(ts, v.ShouldComponentUpdate) } if v, ok := r.(ComponentWillUpdate); ok { root.reactClass.componentWillUpdate = makeComponentUpdateVoidFunc(ts, v.ComponentWillUpdate) } if v, ok := r.(ComponentDidUpdate); ok { root.reactClass.componentDidUpdate = makeComponentUpdateVoidFunc(ts, v.ComponentDidUpdate) } if v, ok := r.(ComponentWillReceiveProps); ok { root.reactClass.componentWillReceiveProps = makeComponentPropertyReceiverFunc(ts, v.ComponentWillReceiveProps) } if v, ok := r.(ComponentWillMount); ok { root.reactClass.componentWillMount = makeVoidFunc(ts, v.ComponentWillMount, true) } if v, ok := r.(ComponentDidMount); ok { root.reactClass.componentDidMount = makeVoidFunc(ts, v.ComponentDidMount, true) } if v, ok := r.(ComponentWillUnmount); ok { root.reactClass.componentWillUnmount = makeVoidFunc(ts, v.ComponentWillUnmount, true) } for _, opt := range options { if !opt.preparePhase { continue } err := opt.action(root) if err != nil { panic(err) } } root.handleOptionsOnPrepare() class := react.Call("createClass", root.reactClass.Object) root.node = react.Call("createFactory", class) for _, opt := range options { if opt.preparePhase { continue } err := opt.action(root) if err != nil { panic(err) } } root.handleOptionsOnCreate() return root } // CreateIfNeeded evaluates the given Component and returns an Element, creating // a new instance if needed. This is a convenience method; if you need to pass // properties, use the factory directly. func CreateIfNeeded(c Component) *Element { switch v := c.(type) { case *Element: return v case Factory: return v.CreateElement(nil) default: return NewPreparedElement(c.Node()) } } // Node implements the Component interface. func (r *ReactComponent) Node() *js.Object { return r.node } // Render the Component in the DOM with the given element ID and props. func (r *ReactComponent) Render(elementID string, props Props) { container := js.Global.Get("document").Call("getElementById", elementID) elem := r.CreateElement(props) // TODO(bep) evaluate if the need the "this" returned on render. reactDOM.Call("render", elem.Node(), container) } // CreateElement implements the Factory interface. // TODO(bep) consolidate and clean func (r *ReactComponent) CreateElement(props Props, children ...Component) *Element { return &Element{properties: props, children: children, elFactory: createElementElementFactory(r)} } // CloneElement will, provided that an element has already been created for this component, clone that element with the // original element's props with the new props merged in shallowly. // New children will replace existing children. // If this is the first invocation, a new element will be created. // This may be be slightly faster when creating elements in a tight loop. // // See https://facebook.github.io/react/docs/top-level-api.html#react.cloneelement func (r *ReactComponent) CloneElement(props Props, children ...Component) *Element { return &Element{properties: props, children: children, elFactory: cloneOrCreateElementElementFactory(r)} } func cloneOrCreateElementElementFactory(r *ReactComponent) func(e *Element) *js.Object { return func(e *Element) *js.Object { if r.elementPrototype == nil { r.elementPrototype = createOrInvoke(r.Node(), e, r.needsCreate) return r.elementPrototype } return cloneElement(r.elementPrototype, e) } } func createElementElementFactory(r *ReactComponent) func(e *Element) *js.Object { return func(e *Element) *js.Object { elem := createOrInvoke(r.Node(), e, r.needsCreate) r.elementPrototype = elem return elem } } func cloneElement(prototype *js.Object, e *Element) *js.Object { var elem *js.Object var args []interface{} if len(e.children) > 0 { for _, c := range e.children { args = append(args, c.Node()) } } elem = react.Call("cloneElement", prototype, e.properties, args) return elem } func createOrInvoke(node *js.Object, e *Element, needsCreate bool) *js.Object { var elem *js.Object var args []interface{} if len(e.children) > 0 { for _, c := range e.children { args = append(args, c.Node()) } } if needsCreate { elem = react.Call("createElement", node, e.properties, args) } else { elem = node.Invoke(e.properties, args) } return elem } func extractThisSetter(r Renderer) ThisSetter { var thisSetter ThisSetter rv := reflect.ValueOf(r) if rv.Kind() == reflect.Ptr { rv = rv.Elem() } rt := rv.Type() if rt.Kind() == reflect.Struct { for i := 0; i < rt.NumField(); i++ { fv := rv.Field(i) if fv.CanInterface() { if init, ok := fv.Interface().(ThisSetter); ok { if fv.IsNil() { newVal := reflect.New(rt.Field(i).Type.Elem()) fv.Set(newVal) thisSetter = newVal.Interface().(ThisSetter) } else { thisSetter = init } // We should maybe check for others and report an error, but for now the first one wins. break } } } } return thisSetter } func makeComponentUpdateFunc(ts ThisSetter, f func(c Cops) bool) *js.Object { return js.MakeFunc(func(this *js.Object, arguments []*js.Object) interface{} { if ts != nil { ts.SetThis(this) } return f(extractComponentUpdateArgs(arguments)) }) } func makeComponentUpdateVoidFunc(ts ThisSetter, f func(c Cops)) *js.Object { return js.MakeFunc(func(this *js.Object, arguments []*js.Object) interface{} { if ts != nil { ts.SetThis(this) } f(extractComponentUpdateArgs(arguments)) return nil }) } func makeComponentPropertyReceiverFunc(ts ThisSetter, f func(c Cops)) *js.Object { return js.MakeFunc(func(this *js.Object, arguments []*js.Object) interface{} { if ts != nil { ts.SetThis(this) } data := extractComponentUpdateArgs(arguments) f(data) return nil }) } func extractComponentUpdateArgs(arguments []*js.Object) Cops { var ( props Props state State context Context ) if len(arguments) > 0 && arguments[0] != nil { props = objectToMap(arguments[0]) } if len(arguments) > 1 && arguments[1] != nil { state = objectToMap(arguments[1]) } if len(arguments) > 2 && arguments[2] != nil { context = objectToMap(arguments[2]) } return Cops{Props: props, State: state, Context: context} } func makeVoidFunc(ts ThisSetter, f func(), assumeBlocking bool) *js.Object { return js.MakeFunc(func(this *js.Object, arguments []*js.Object) interface{} { if ts != nil { ts.SetThis(this) } if assumeBlocking { go func() { f() }() } else { f() } return nil }) } func makeStateFunc(ts ThisSetter, f func() State) *js.Object { return js.MakeFunc(func(this *js.Object, arguments []*js.Object) interface{} { if ts != nil { ts.SetThis(this) } return f() }) } func makeChildContextFunc(ts ThisSetter, f func() Context) (*js.Object, js.M) { getChildContext := js.MakeFunc(func(this *js.Object, arguments []*js.Object) interface{} { if ts != nil { ts.SetThis(this) } return f() }) childContextTypes := extractPropTypesFromTemplate(f()) return getChildContext, childContextTypes } func extractPropTypesFromTemplate(t map[string]interface{}) js.M { propTypes := js.M{} for k, v := range t { switch v.(type) { case string: propTypes[k] = react.Get("PropTypes").Get("string") case int: propTypes[k] = react.Get("PropTypes").Get("number") default: // See: https://facebook.github.io/react/docs/reusable-components.html // TODO(bep): Reconsider all of this. panic("Context type not implemented") } } return propTypes } type incrementer struct { counter int } func (i *incrementer) next() int { i.counter++ return i.counter } func makeRenderFunc(ts ThisSetter, s string, f func() Component) *js.Object { return js.MakeFunc(func(this *js.Object, arguments []*js.Object) interface{} { if ts != nil { ts.SetThis(this) } comp := f() if comp == nil { return nil } that := NewThis(this) // TODO(bep) refactor if e, ok := comp.(*Element); ok { addEventListeners(ts, comp, that) idFactory := &incrementer{} addMissingKeys(s, e, idFactory) } if _, ok := comp.(Factory); ok { panic("Render should return a ready-to-use Element.") } return comp.Node() }) } func addEventListeners(ts ThisSetter, c Component, that *This) { if e, ok := c.(*Element); ok { for _, l := range e.eventListeners { l.delegate = func(event *js.Object) { if ts != nil { ts.SetThis(that.This) } if l.preventDefault { event.Call("preventDefault") } if l.stopPropagation { event.Call("stopPropagation") } l.listener(&Event{Object: event, This: that}) } e.properties[l.name] = l.delegate } for _, child := range e.children { addEventListeners(ts, child, that) } } } func (r *ReactComponent) handleOptionsOnCreate() { if r.exportName != "" { exports := js.Module.Get("exports") if exports == js.Undefined { panic("module.exports not present.") } exports.Set(r.exportName, r.node) } if r.globalName != "" { js.Global.Set(r.globalName, r.node) } } func (r *ReactComponent) handleOptionsOnPrepare() { if r.componentConfig.ContextTypesTemplate != nil { r.reactClass.contextTypes = extractPropTypesFromTemplate(r.componentConfig.ContextTypesTemplate) } } func addMissingKeys(s string, e *Element, id *incrementer) { if !e.dynamic { if e.properties == nil { e.properties = make(map[string]interface{}) } if _, ok := e.properties["key"]; !ok { key := fmt.Sprintf("%s-%d", s, id.next()) e.properties["key"] = key } } for _, c2 := range e.children { if e2, ok := c2.(*Element); ok { addMissingKeys(s, e2, id) } } } ================================================ FILE: el/elements.autogen.go ================================================ //go:generate go run generate.go // Package el defines markup to create DOM elements. // // Generated from "HTML element reference" by Mozilla Contributors, https://developer.mozilla.org/en-US/docs/Web/HTML/Element, licensed under CC-BY-SA 2.5. package el import "github.com/bep/gr" // Anchor — The HTML Anchor Element () defines a hyperlink to a location on the same page or any other page on the Web. It can also be used (in an obsolete way) to create an anchor point—a destination for hyperlinks within the content of a page, so that links aren't limited to connecting simply to the top of a page. // // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a func Anchor(mods ...gr.Modifier) *gr.Element { e := gr.NewElement("a") gr.Modifiers(mods).Modify(e) return e } // Abbreviation — The HTML element (or HTML Abbreviation Element) represents an abbreviation and optionally provides a full description for it. If present, the title attribute must contain this full description and nothing else. // // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/abbr func Abbreviation(mods ...gr.Modifier) *gr.Element { e := gr.NewElement("abbr") gr.Modifiers(mods).Modify(e) return e } // Address — The HTML 
element supplies contact information for its nearest
or ancestor; in the latter case, it applies to the whole document. // // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/address func Address(mods ...gr.Modifier) *gr.Element { e := gr.NewElement("address") gr.Modifiers(mods).Modify(e) return e } // Area — The HTML element defines a hot-spot region on an image, and optionally associates it with a hypertext link. This element is used only within a element. // // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/area func Area(mods ...gr.Modifier) *gr.Element { e := gr.NewElement("area") gr.Modifiers(mods).Modify(e) return e } // Article — The HTML
element represents a self-contained composition in a document, page, application, or site, which is intended to be independently distributable or reusable (e.g., in syndication). This could be a forum post, a magazine or newspaper article, a blog entry, an object, or any other independent item of content. Each
should be identified, typically by including a heading (

-

element) as a child of the
element. // // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/article func Article(mods ...gr.Modifier) *gr.Element { e := gr.NewElement("article") gr.Modifiers(mods).Modify(e) return e } // Aside — The HTML