Use Knockout.js to design and build dynamic client-side web applications
- that are extremely responsive and easy to maintain. This example-driven book shows
- you how to use this lightweight JavaScript framework and its Model-View-ViewModel
- (MVVM) pattern. You’ll learn how to build your own data bindings, extend the framework
- with reusable functions, and work with a server to enhance your client-side application
- with persistence. In the final chapter, you’ll build a shopping cart to see how
- everything fits together.
If you’re a web developer with experience in
- JavaScript, HTML, and CSS, you’re ready for Knockout.
Learn how to
- create a ViewModel
Bind HTML data and attributes, and CSS classes and
- styles
Understand data binding in Knockout’s context hierarchy
Use
- properties that change dynamically through user interaction
Work with
- forms by using several different bindings
Bind multiple ViewModels on
- a single page
Extend or attach custom functions to observables
Perform
- server-side interactions with jQuery
Map a JavaScript object or apply
- JSON data to a new object
"
- industryIdentifiers:
- - type: ISBN_10
- identifier: '1491914319'
- - type: ISBN_13
- identifier: '9781491914311'
- readingModes:
- text: false
- image: false
- pageCount: 86
- printedPageCount: 86
- dimensions:
- height: 23.30 cm
- width: 17.80 cm
- thickness: 0.50 cm
- printType: BOOK
- categories:
- - Computers / Programming Languages / JavaScript
- - Computers / Internet / Application Development
- - Computers / Web / Web Programming
- maturityRating: NOT_MATURE
- allowAnonLogging: false
- contentVersion: preview-1.0.0
- imageLinks:
- smallThumbnail: https://books.google.ca/books/content?id=ZPDnoQEACAAJ&printsec=frontcover&img=1&zoom=5&imgtk=AFLRE73xh8xZACPIjOtB8rD5RE06-ElVbzgtH5e0nmkyo0UjgGwBZweLwET2ieAFeO_E6k4vI1gqVVxyRWIhOlXmxrprvBuMm-oQigjlTEfm9M9bABMXNcxwZKRTZvvdUBkP14nJ6MIp&source=gbs_api
- thumbnail: https://books.google.ca/books/content?id=ZPDnoQEACAAJ&printsec=frontcover&img=1&zoom=1&imgtk=AFLRE717dECAVjOpJblfNu0EPHVMBQmgOOan5rn21GWN2OQhSbPiehsljCYRsxdJQ1wcejFwt0wBmNnRraYQUHHWPqjrHJW0kRSrXjobRrKukJDD-hhmn5DWwNGA--8nQVITS2vbv8t6&source=gbs_api
- language: en
- previewLink: https://books.google.ca/books?id=ZPDnoQEACAAJ&hl=&source=gbs_api
- infoLink: https://books.google.ca/books?id=ZPDnoQEACAAJ&hl=&source=gbs_api
- canonicalVolumeLink: https://books.google.ca/books/about/Knockout_js.html?hl=&id=ZPDnoQEACAAJ
-
- - title: Asp.net Mvc 5 With Bootstrap and Knockout.js
- subtitle: Building Dynamic, Responsive Web Applications
- authors:
- - Jamie Munro
- publisher: O'Reilly Media, Incorporated
- publishedDate: '2015-03-25'
- description: "
Bring dynamic server-side web content and responsive web design
- together to build websites that work and display well on any resolution, desktop
- or mobile. With this practical book, you’ll learn how by combining the ASP.NET
- MVC server-side language, the Bootstrap front-end framework, and Knockout.js—the
- JavaScript implementation of the Model-View-ViewModel pattern.
Author Jamie
- Munro introduces these and other related technologies by having you work with
- sophisticated web forms. At the end of the book, experienced and aspiring web
- developers alike will learn how to build a complete shopping cart that demonstrates
- how these technologies interact with each other in a sleek, dynamic, and responsive
- web application.
Build well-organized, easy-to-maintain web applications
- by letting ASP.NET MVC 5, Bootstrap, and Knockout.js do the heavy lifting
-
Use ASP.NET MVC 5 to build server-side web applications, interact with a database,
- and dynamically render HTML
Create responsive views with Bootstrap that
- render on a variety of modern devices; you may never code with CSS again
-
Add Knockout.js to enhance responsive web design with snappy client-side interactions
- driven by your server-side web application
"
- industryIdentifiers:
- - type: ISBN_10
- identifier: '1491914394'
- - type: ISBN_13
- identifier: '9781491914397'
- readingModes:
- text: false
- image: false
- pageCount: 278
- printedPageCount: 278
- dimensions:
- height: 23.30 cm
- width: 17.80 cm
- thickness: 1.30 cm
- printType: BOOK
- categories:
- - Computers / Programming Languages / ASP.NET
- - Computers / Web / General
- - Computers / Web / Web Programming
- maturityRating: NOT_MATURE
- allowAnonLogging: false
- contentVersion: preview-1.0.0
- imageLinks:
- smallThumbnail: https://books.google.ca/books/content?id=try8oQEACAAJ&printsec=frontcover&img=1&zoom=5&imgtk=AFLRE71NgZ3twak4WXm7mMrpPXQwM5LLeI3zeLgpf4CSBir_nKmU0mZJoh6Z5JPwwrMk_WjQE_j04VenoDv3PBQAY0yCp4w_tW5TM4BjdModKb6BhbGfnYR0Qt1Qmn6SmtV6WDNhsqd2&source=gbs_api
- thumbnail: https://books.google.ca/books/content?id=try8oQEACAAJ&printsec=frontcover&img=1&zoom=1&imgtk=AFLRE71KQ8fmuM2sSfN0TOooxRRz51cBqbN-oSufwl2TKH6qSzuzhI_Sarc_I5dMWgvbKB1SmWvA3IREW1ByGHSRAnTsybrM8B4LxCKEjavv9Zq2VxVBR3pweSl2UWtLe4Oav0m5_S5G&source=gbs_api
- language: en
- previewLink: https://books.google.ca/books?id=try8oQEACAAJ&hl=&source=gbs_api
- infoLink: https://books.google.ca/books?id=try8oQEACAAJ&hl=&source=gbs_api
- canonicalVolumeLink: https://books.google.ca/books/about/Asp_net_Mvc_5_With_Bootstrap_and_Knockou.html?hl=&id=try8oQEACAAJ
-
- - title: Getting Started with Knockout.js for .NET Developers
- authors:
- - Andrey Akinshin
- publisher: Packt Publishing Ltd
- publishedDate: '2015-05-27'
- description: This book is intended for .NET developers who want to use the MVVM
- design pattern to create powerful client-side JavaScript linked to server-side
- C# logic. Basic experience with ASP.NET, Razor, and creating web applications
- is needed.
- industryIdentifiers:
- - type: ISBN_10
- identifier: '1783984015'
- - type: ISBN_13
- identifier: '9781783984015'
- readingModes:
- text: true
- image: true
- pageCount: 188
- printedPageCount: 188
- printType: BOOK
- categories:
- - Computers / Programming Languages / JavaScript
- - Computers / Internet / Application Development
- - Computers / Programming Languages / ASP.NET
- maturityRating: NOT_MATURE
- allowAnonLogging: false
- contentVersion: 0.1.1.0.preview.3
- imageLinks:
- smallThumbnail: https://books.google.ca/books/content?id=A-iuCQAAQBAJ&printsec=frontcover&img=1&zoom=5&edge=curl&imgtk=AFLRE700Ur2bUx3-xG1lJ7dhXYNiVxT0TlvFTCLKBDmCgsc2s1pOb_YVZxtI6jUwv53hOOAMnvSH2j3GR2NKExvEev5ALEK68u7oLyrUTxA-4j5iwmH7jEV0USmCSJE8PE6Nke2aUWS2&source=gbs_api
- thumbnail: https://books.google.ca/books/content?id=A-iuCQAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&imgtk=AFLRE72rh8mTdqUnmJDjLIi1wLaea_frTsNMmKGHxTa2lID6PyuW_qNH_XzvkxqDVn3QEa2LfnTsvAmj6Vq_Wd73Zl4Q9_gIQA0lmIwRfK0Zr17YFHAV9uSx-9q5bTOOepwmRpwG3fbG&source=gbs_api
- small: https://books.google.ca/books/content?id=A-iuCQAAQBAJ&printsec=frontcover&img=1&zoom=2&edge=curl&imgtk=AFLRE71Y9WVxVSRTitqbcivBU-WgoXUCyyPTuNsjEn7uZ9oFTc7vKFCJekAx1vMoo_v4lV59_ehco3Lt8vcJTalPxGaIZj57lo1DPirPBwRhGu_kuQtALcu0khKaKimJdwj4Sp_kEIEj&source=gbs_api
- medium: https://books.google.ca/books/content?id=A-iuCQAAQBAJ&printsec=frontcover&img=1&zoom=3&edge=curl&imgtk=AFLRE71n9MaRenbMt90bPtLsyELGmzZq6U4KEbYvVRl7e_kLBJD0QvZ36lTpLejO3BJ4i3WWHL-hzY10ThMf3Qg5vSGD4q3TFoHU62YmSImkw1obbyph6p04pfMutEekEHYXO6d-Yuc9&source=gbs_api
- large: https://books.google.ca/books/content?id=A-iuCQAAQBAJ&printsec=frontcover&img=1&zoom=4&edge=curl&imgtk=AFLRE73BGDB8DqNQzhG2wE-jBgyb-JdjNtiNXeqazRtGxQUwrTnpjHSg2G5LSXaassUEItKLZbyrt8myz6fLL2dl5M_xvH-tZosq63njrzlZYkJuJqjhj2ZxNItqlkYShzh6C0jMklxu&source=gbs_api
- extraLarge: https://books.google.ca/books/content?id=A-iuCQAAQBAJ&printsec=frontcover&img=1&zoom=6&edge=curl&imgtk=AFLRE72ntS5Ll1QmMWu-A2hwAdGAqTBeG9EEYgH4qlIvCZH3p5gaoPJO4XxPTCKfOZVpVzPN0gTVAoTclhd6v1Yrmk5dvyfX4032bvw9fEp9HP1AemUNgCh_Cjtgzcwma2HlyVG9n7jh&source=gbs_api
- language: en
- previewLink: https://books.google.ca/books?id=A-iuCQAAQBAJ&hl=&source=gbs_api
- infoLink: https://books.google.ca/books?id=A-iuCQAAQBAJ&hl=&source=gbs_api
- canonicalVolumeLink: https://books.google.ca/books/about/Getting_Started_with_Knockout_js_for_NET.html?hl=&id=A-iuCQAAQBAJ
-
- - title: Mastering KnockoutJS
- authors:
- - Timothy Moran
- publisher: Packt Publishing Ltd
- publishedDate: '2014-11-26'
- description: If you are an experienced JavaScript developer who is looking for new
- tools to build web applications and get an understanding of core elements and
- applications, this is the book for you. A basic knowledge of DOM, JavaScript,
- and KnockoutJS is assumed.
- industryIdentifiers:
- - type: ISBN_10
- identifier: '1783981016'
- - type: ISBN_13
- identifier: '9781783981014'
- readingModes:
- text: true
- image: true
- pageCount: 270
- printedPageCount: 489
- printType: BOOK
- categories:
- - Computers / Web / Design
- - Computers / Programming Languages / JavaScript
- - Computers / Internet / Application Development
- maturityRating: NOT_MATURE
- allowAnonLogging: true
- contentVersion: 1.1.1.0.preview.3
- imageLinks:
- smallThumbnail: https://books.google.ca/books/content?id=BoqbBQAAQBAJ&printsec=frontcover&img=1&zoom=5&edge=curl&imgtk=AFLRE71OGVtK3R39HAA3YPPexcAfdqkhHpK2qY2aqN2VwnuRbzJ5pWfCdPP_5p0KuPpod7GvQPI8wHYLAO8zssun_5j31mq5DrjNHULX097DHieG55cZxoF3R3nX4po7w9urdhoH83CT&source=gbs_api
- thumbnail: https://books.google.ca/books/content?id=BoqbBQAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&imgtk=AFLRE70GS42a68O_DBLirScLduiYOUbk80jGntqSuuykg8RU1usaN5xdHy5Gl13pgEb2LdZYZ7b5sYtt4qmedX1FiwDuhbprf-X1ADNLHolZCVletNeHvoUvy0gFKPplc4eopBGHQnPG&source=gbs_api
- small: https://books.google.ca/books/content?id=BoqbBQAAQBAJ&printsec=frontcover&img=1&zoom=2&edge=curl&imgtk=AFLRE72HypPfd5WB7VNPF5ovT8veIkql_616DZvT64hc5QPN8HhYCwP3F_XuPKD5D3euB0qJSau7qlRgyrp7VjnOACjsF10v9PekqqAw7fnOakZVnLGBJ3_tWNTl-GByWWxzTDi1rXrQ&source=gbs_api
- medium: https://books.google.ca/books/content?id=BoqbBQAAQBAJ&printsec=frontcover&img=1&zoom=3&edge=curl&imgtk=AFLRE72bJ_PJ9fydBJC1A4b8n-F1x_VHnyeBSp9uRJTFYxQVcIyEO-hCcU51x-TmUrH4JOblv0J2g2OzpwxQK2oELDtzlE7qzE0a_D-KsqSqoFFPXLlPrL45r8fLLXvTRUubJNJy31No&source=gbs_api
- large: https://books.google.ca/books/content?id=BoqbBQAAQBAJ&printsec=frontcover&img=1&zoom=4&edge=curl&imgtk=AFLRE70OgKfn3_48ic1MFdtFGQyoOBg8JHQwln0q5M1fKTYREAuugBOOtf5Q7m6_yD-DEN_n933Y5labtoiq-KM_BEWWukCgkOeJvT1Xr-XuATJrtXX9N-cq1Z-1qbfO3ncRz0yMo-_c&source=gbs_api
- extraLarge: https://books.google.ca/books/content?id=BoqbBQAAQBAJ&printsec=frontcover&img=1&zoom=6&edge=curl&imgtk=AFLRE71OClJjx-G3VrcH4lga7AKeiw0CGOSwyAvjxfZ8ns3TKv_o8SLzY_p3_e5Q8kJgiVXA1GWpNT-kWgwNwHa5BYsVHbF5DXlGpqyLGxOT8fOXBlsBr8e_H375DucdcSP-0v7L1jF8&source=gbs_api
- language: en
- previewLink: https://books.google.ca/books?id=BoqbBQAAQBAJ&hl=&source=gbs_api
- infoLink: https://books.google.ca/books?id=BoqbBQAAQBAJ&hl=&source=gbs_api
- canonicalVolumeLink: https://books.google.ca/books/about/Mastering_KnockoutJS.html?hl=&id=BoqbBQAAQBAJ
-
- - title: Web App Testing Using Knockout.JS
- authors:
- - Roberto Messora
- publisher: Packt Publishing Ltd
- publishedDate: '2014-11-17'
- description: If you are a JavaScript developer, beginner, or an expert who wants
- to improve quality standards in terms of solutions design and functional verification,
- this book is for you. Basic understanding of web development, HTML, and JavaScript
- is required.
- industryIdentifiers:
- - type: ISBN_10
- identifier: '1783982853'
- - type: ISBN_13
- identifier: '9781783982851'
- readingModes:
- text: true
- image: true
- pageCount: 154
- printedPageCount: 237
- printType: BOOK
- categories:
- - Computers / Software Development & Engineering / Quality Assurance & Testing
- - Computers / Programming Languages / JavaScript
- - Computers / Web / Web Programming
- averageRating: 5
- ratingsCount: 2
- maturityRating: NOT_MATURE
- allowAnonLogging: false
- contentVersion: 1.1.1.0.preview.3
- imageLinks:
- smallThumbnail: https://books.google.ca/books/content?id=dZN1BQAAQBAJ&printsec=frontcover&img=1&zoom=5&edge=curl&imgtk=AFLRE70A3vdwml0dXDKn1YCWpz8n0p8IKHaCN6FnhytFUt7ZiwPTttCa3_2-Q6ZRyyeCrTzWd3AvkTSQwvO31hHUZjEbUVKlNij50crBaQerevytbQWF6ZMvTW6qxlFH-DfN-AvUv6e2&source=gbs_api
- thumbnail: https://books.google.ca/books/content?id=dZN1BQAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&imgtk=AFLRE71zzDoAJ8_68JqPI9sZ3Tlvyhyqxiyi_z0QwpVpjChRp5YC3bKNGiUBlDLThbtmQ3uIdVes5uGumrDrmUPlvGA_3PSqev9ZbCwthmLIjwEisbAwI1z2nJNzqwSHb7b-8uEekpvB&source=gbs_api
- small: https://books.google.ca/books/content?id=dZN1BQAAQBAJ&printsec=frontcover&img=1&zoom=2&edge=curl&imgtk=AFLRE71Bq-gmv0FqD2RAIGkqGsnAMEI2VSAlzOme8QiPTpwA09b16Xx9fwBL7WAHIONiyVnFu6iACEO9SVQqZDGf9l56_gTMChhENAXWnM_ZnV5l-K4ouOHjqhAzx61yzxdj2OgmS7Bl&source=gbs_api
- medium: https://books.google.ca/books/content?id=dZN1BQAAQBAJ&printsec=frontcover&img=1&zoom=3&edge=curl&imgtk=AFLRE72glYr_QFUGY7Xc2cBVMa1kXnEaRIn5W2ULqSu6McZlyOZLXhZ1Aw2EYxWmfIzkpr9Le6d8D0AmMCP2YI8RRAAkmrrtQxTO3ow44Gf_kINC2GIrZtLywg9ul7tGgtJNdqMLyfWi&source=gbs_api
- large: https://books.google.ca/books/content?id=dZN1BQAAQBAJ&printsec=frontcover&img=1&zoom=4&edge=curl&imgtk=AFLRE72x5vBQpMoPigr6fGa246ERfQvakIU7pB6PpTEUbktcoWhXxik5WF8TohPvbPuOGXqG0Lzh1JmSy6N7PIVpqCJXIyHV2UIzOxz1u1SeyfQNatsajdpQ16rGp6uaJxPhT31o0JUy&source=gbs_api
- extraLarge: https://books.google.ca/books/content?id=dZN1BQAAQBAJ&printsec=frontcover&img=1&zoom=6&edge=curl&imgtk=AFLRE73xjKYwV0fwumEQIryeYX8vFDu7KUe8WgpYN-QvZU8ZMbVU5b5Ua8cYnD_FBBGpDTf22w_tiYOC8G9BpvSOkHaO07HRV-YDM51FaVQWlXywSXL7UVgOWUaI0iG5xbY3M6CJWMOz&source=gbs_api
- language: en
- previewLink: https://books.google.ca/books?id=dZN1BQAAQBAJ&hl=&source=gbs_api
- infoLink: https://books.google.ca/books?id=dZN1BQAAQBAJ&hl=&source=gbs_api
- canonicalVolumeLink: https://books.google.ca/books/about/Web_App_Testing_Using_Knockout_JS.html?hl=&id=dZN1BQAAQBAJ
-
- - title: KnockoutJS Essentials
- authors:
- - Jorge Ferrando
- publisher: Packt Publishing Ltd
- publishedDate: '2015-02-27'
- description: If you are a JavaScript developer who has been using DOM manipulation
- libraries such as Mootools or Scriptaculous, and you want go further in modern
- JavaScript development with a simple and well-documented library, then this book
- is for you. Learning how to use Knockout will be perfect as your next step towards
- building JavaScript applications that respond to user interaction.
- industryIdentifiers:
- - type: ISBN_10
- identifier: '1784395285'
- - type: ISBN_13
- identifier: '9781784395285'
- readingModes:
- text: true
- image: true
- pageCount: 232
- printedPageCount: 232
- printType: BOOK
- categories:
- - Computers / Internet / General
- - Computers / Internet / Application Development
- - Computers / Programming Languages / Java
- maturityRating: NOT_MATURE
- allowAnonLogging: false
- contentVersion: 2.2.2.0.preview.3
- imageLinks:
- smallThumbnail: https://books.google.ca/books/content?id=HEXfBgAAQBAJ&printsec=frontcover&img=1&zoom=5&edge=curl&imgtk=AFLRE73KcIEK76fLL4WMQf9A1CJTvx-SGdI5O2ezmLb54SZbJGzguyU7PjmjzBRqRYw0fFGHmcGBjfwozfYegr6gQ12u-c5vUhXf7szQkTjXEXWV5Y0KQcgDfg_OFQmKi9h-9cm-4zdb&source=gbs_api
- thumbnail: https://books.google.ca/books/content?id=HEXfBgAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&imgtk=AFLRE72iT2HkL3gawhD9TqH0Ozcj5SZW5bchxnpKvWAjxtYdxh8HcnIKbul_cXzv6zK-EDmZh5QY29qCYf-JQQEGU6sjiaaVSoeGbbezRI32UgWJNVpiPu6kd2aeMSZa5Vamelt0nAda&source=gbs_api
- small: https://books.google.ca/books/content?id=HEXfBgAAQBAJ&printsec=frontcover&img=1&zoom=2&edge=curl&imgtk=AFLRE72qNwfz7Ar9qbXS_7Z_y2lsYAYpWy2pEy37MmEtZSajj0E7AMzXnEHIk2EG6otNwbELtO63zSSVjiAs3jvlerXq_N-uD227lrRMSDt8-N2-rZr0d396FW0F0oukatK3HcBwkBzc&source=gbs_api
- medium: https://books.google.ca/books/content?id=HEXfBgAAQBAJ&printsec=frontcover&img=1&zoom=3&edge=curl&imgtk=AFLRE72m6oGoEwL5xAbLyuU4C_334JN-IgaHkW70a4mFNRW58iirrlcuJaZ8hDEPGcADH_Qd1HeLukT2e_1gxJUEqOVGAqdTJopfflSRdEFSy_d3R3TFxvTCvrWqw2b9RBsbgnWL-vu2&source=gbs_api
- large: https://books.google.ca/books/content?id=HEXfBgAAQBAJ&printsec=frontcover&img=1&zoom=4&edge=curl&imgtk=AFLRE727dgJxfT9K-HpbDFySw0YytRHfJV1Nr8z87ClKXeljh02ZGsv-9KyehOnyFMH11gXgyN7Rks3adufGjMDwsMgxCVvvsFQgX2LHt1_jeB7EoPeoVgRdKllAd6TqnHSvPYG5dePq&source=gbs_api
- extraLarge: https://books.google.ca/books/content?id=HEXfBgAAQBAJ&printsec=frontcover&img=1&zoom=6&edge=curl&imgtk=AFLRE70WdC_9qZ_FtUczIwDq4_4XBZMUl-HwNXyucuOI0v4OCtyRxQAgvDM3m7jJDeXcrm83b-Bi5-TdzSkjxZu4RbpTzW4NL8mPDRAFUlMGPViNw4xMw-ebSHRkgWYsMriAUYjYp_OZ&source=gbs_api
- language: en
- previewLink: https://books.google.ca/books?id=HEXfBgAAQBAJ&hl=&source=gbs_api
- infoLink: https://books.google.ca/books?id=HEXfBgAAQBAJ&hl=&source=gbs_api
- canonicalVolumeLink: https://books.google.ca/books/about/KnockoutJS_Essentials.html?hl=&id=HEXfBgAAQBAJ
-
- - title: KnockoutJS Blueprints
- authors:
- - Carlo Russo
- publisher: Packt Publishing Ltd
- publishedDate: '2015-02-25'
- description: If you are a JavaScript developer and already know the basics of KnockoutJS
- and you want to get the most out of it, then this book is for you. This book will
- help in your transition from a small site to a large web application that is easily
- maintainable.
- industryIdentifiers:
- - type: ISBN_10
- identifier: '1783980850'
- - type: ISBN_13
- identifier: '9781783980857'
- readingModes:
- text: true
- image: true
- pageCount: 218
- printedPageCount: 218
- printType: BOOK
- categories:
- - Computers / General
- - Computers / Programming Languages / JavaScript
- maturityRating: NOT_MATURE
- allowAnonLogging: false
- contentVersion: 2.2.2.0.preview.3
- imageLinks:
- smallThumbnail: https://books.google.ca/books/content?id=5ljTBgAAQBAJ&printsec=frontcover&img=1&zoom=5&edge=curl&imgtk=AFLRE73zg0-XBzMzQAcMQW_DYHtbhQovG3pLSICrTsQiuPtQjcoh0uUD8mixpJOoQ5Jyhx_Q39QcF8zNZW9vZxYpfOY2H-vNHZ1Q3F-RtZ4urPVrSSKQauMG9YeZOtFE_uyJhwPTkVmA&source=gbs_api
- thumbnail: https://books.google.ca/books/content?id=5ljTBgAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&imgtk=AFLRE709pFQ7H1gOnU-LAndEX0z9bqHUPQAi5rRoYbighr68U9tTN7ONHq8sgiLrkmhFBO5isUK3dKydyNM1aWDgk4FqErfk2DSbjC2T_jd7nfsnQzXHcFCVEcD3rLNxV7n0pegmMoEy&source=gbs_api
- small: https://books.google.ca/books/content?id=5ljTBgAAQBAJ&printsec=frontcover&img=1&zoom=2&edge=curl&imgtk=AFLRE70TIZJ2jb02xZbyrF-pi7rCkKtRbM9QNCKS-7PZfJcNhsqHXwROEZ1W6tasXaC0cOmDdIrUrgAVLgDmP6Yg6HGwxqeV_MyZdZeeJ8zbhL4R9M0jQpKGggoGGLzLzoJ39ID5dCIn&source=gbs_api
- medium: https://books.google.ca/books/content?id=5ljTBgAAQBAJ&printsec=frontcover&img=1&zoom=3&edge=curl&imgtk=AFLRE714ZgU0oxMuFEtbSrhaZJwsYhvkBEr1D_wYVJsJyiy6NE80XQxdDKopHEcJtSOG-WVKnjsrgrvidnWoxo2kvauH97Nr4iE44nAJeTFsjlLOG0Xv8anJAMSd2_aA4KYAK5cXZ0u8&source=gbs_api
- large: https://books.google.ca/books/content?id=5ljTBgAAQBAJ&printsec=frontcover&img=1&zoom=4&edge=curl&imgtk=AFLRE72zC_ZRz28WbKJAHvaFUB6LqLgItZOT3XobgdMZDn_fnYVVWIg8iv1gMPtNek1yrVlTFwWmWa061ZS5xZVFRxlkXRWPmxiroQjmhiAoCEQ7cjp2Gb6Tos7xcoH1rjVU7GCbMYhH&source=gbs_api
- extraLarge: https://books.google.ca/books/content?id=5ljTBgAAQBAJ&printsec=frontcover&img=1&zoom=6&edge=curl&imgtk=AFLRE732FDrzmu-zRydUQ7jmyI9LnQxtWx49_kOuxlwgjW2jI95C_GWB_UWIg02hmKbYRHXbU7jtLw_VL38n-_DUntiCj_f9AG5Lswlq1KaXyjlwfCEXWTIsH82VkQeqnC77S3bqLkFV&source=gbs_api
- language: en
- previewLink: https://books.google.ca/books?id=5ljTBgAAQBAJ&hl=&source=gbs_api
- infoLink: https://books.google.ca/books?id=5ljTBgAAQBAJ&hl=&source=gbs_api
- canonicalVolumeLink: https://books.google.ca/books/about/KnockoutJS_Blueprints.html?hl=&id=5ljTBgAAQBAJ
diff --git a/tko.io/src/3to4.md b/tko.io/src/3to4.md
new file mode 100644
index 000000000..55b5413c9
--- /dev/null
+++ b/tko.io/src/3to4.md
@@ -0,0 +1,249 @@
+---
+layout: base.njk
+title: Knockout 3 to 4 Guide
+---
+
+# Overview of the Differences
+
+TKO is a fundamental change in the foundation of the code behind Knockout, representing the reverse engineering, compartmentalization, and reintegration of the original code that dates back to 2010.
+
+With this reengineering of Knockout into discrete pieces, it will be easier to update, build, and test the features of Knockout, as well as put the individual packages that make up Knockout to use in situations outside Knockout itself.
+
+To see the differences, have a look at the [CHANGELOG.md](https://github.com/knockout/tko/blob/master/CHANGELOG.md).
+
+
+# Version Comparison
+
+| Version | tko.js | Knockout 4 | Knockout 3.x |
+| --- | --- | --- | --- |
+| Browser compatibility | Modern browsers (i.e. [`Proxy`](https://caniuse.com/#feat=proxy) support) | Internet Explorer 9+ | Internet Explorer 6+ |
+| `ko.BindingHandler` | Yes | Yes | No |
+| `observableArray.length` | Yes | Browsers with [Array subclass](https://kangax.github.io/compat-table/es6/#test-Array_is_subclassable_length_property_(accessing)) support [More info](http://perfectionkills.com/how-ecmascript-5-still-does-not-allow-to-subclass-an-array/#wrappers_prototype_chain_injection) | No |
+| iterable `observableArray` | Yes | Browsers with [Symbol support](https://kangax.github.io/compat-table/es6/#test-Symbol) | No |
+| event `throttle` / `debounce` | Yes | Yes | No |
+| `ko.Component` | Yes | Yes | No |
+| `applyBindings` returns `Promise` | Yes | Yes | No |
+| Polyfills included | None | Up to ES6 | `Object.prototype.bind` |
+| `ko.proxy` | Yes | No | No |
+| `ko.onError` | Does not automatically throw (you need to add `throw error` to `ko.options.onError`) | Does not rethrow automatically | Always re-throws error |
+| `foreach` binding | FastForEach | Template foreach | Template foreach |
+| `each` binding | FastForEach | FastForEach | Template foreach
+
+# Security advantages in TKO
+TKO is ready for strict Content Security Policies (CSP) and does not use `evil-eval` or `new function` techniques. It also provides HTML sanitization through configurable options. To sanitize HTML templates, override the `options.sanitizeHtmlTemplate` setting using a library such as DOMPurify or Validator.js.
+# Build System
+
+TKO has a complete build system rewrite and a conversion of the code from a concatenation of source files to discrete ES6 modules with `import` and `export` statements. This process has been complex and taken years, with the result being a Knockout with a strong foundation of discrete reusable components.
+
+Knockout 4 and TKO will be maintained at the new monorepo [knockout/tko](https://github.com/knockout/tko) on GitHub. Knockout 3.x will continue to be maintained at [knockout/knockout](https://github.com/knockout/knockout).
+
+TKO now uses standard tools like `lerna` and `yarn`, and employs [StandardJS](https://standardjs.com/) for code style — though all the old code is not yet updated to StandardJS yet.
+
+# Test System
+
+Knockout 3 used Jasmine 1 to perform tests. Some packages in TKO continue to use Jasmine 1, while others now use Mocha.
+
+## Backwards compatibility and 💥 breaking changes
+
+We've strived to have backwards compatibility, and the numerous test cases we've run it through have been successful. A key value of Knockout has been and remains the comprehensive test cases that enforce performance to a predictable standard, and TKO meets all the tests that were enforced on Knockout 3.x, notwithstanding a few issues:
+
+- The `function` no longer works in `data-bind`, having been replaced by lambdas, so `data-bind='click: function () { x++ }'` will have to be replaced by e.g. `data-bind='click: => x++'`
+- The `data-bind` is now interpreted by a LL compiler (based on [knockout-secure-binding](https://github.com/brianmhunt/knockout-secure-binding)), so some edge case parsing issues may crop up
+
+## Browser support
+
+Knockout 4 and TKO and the underlying packages will start support from IE9 forward. We aim to test Knockout across all browsers from this point forward.
+
+If you need IE6, 7, and 8 support you may prefer to keep using the Knockout 3.x line, or be prepared for workarounds or missing functionality.
+
+# Options
+
+* (options) Allow importing `ko` in node
+* various new [`options`](https://github.com/knockout/tko.utils/blob/master/src/options.js)
+
+# Utilities
+
+* (utils) Several array utilities use native functions now (`arrayPushAll`, `arrayFilter`, `arrayGetDistinctValues`, `arrayFirst`, `arrayIndexOf`)
+* The `throttle` and `debounce` utilities now pass arguments to the target functions
+* utils
+ * utils.domNodeDisposal is now exposed as domNodeDisposal
+ * arguments to setHtml that are functions are called (not just observables)
+ * cleanExternalData now exposed in domNodeDisposal.otherNodeCleanerFunctions
+
+* error handling
+ * onError no longer throws if overloaded; default function is to re-throw.
+ * error is thrown when an extender is not found
+
+# Life Cycles
+
+* (internal) Add the ES6 LifeCycle class (see tko.lifecycle)
+
+# Observables
+
+* (observable) When supported, `observable.length` will now be undefined (was `0` before), and `observableArray.length` will now be the length of the wrapped array
+* (observableArray) `observableArray` is now iterable (has a `Symbol.iterator` property)
+* (subscribable) Add the `once`, `then`, `when`, `yet`, and `next` functions
+
+# Components
+
+* (components) Warn with custom-element names that cannot be used with custom elements re. #43 & knockout/knockout#1603
+* (components) Add `ko.Component`, an abstract base class that simplifies the Component creation and registration API (see `tko.utils.component/src/ComponentABC.js`)
+* (components) Add `getBindingHandler(key)` to use binding handlers local to a component
+
+Components can control their binding handlers.
+
+## ko.Component example
+
+
+
+# Bindings
+
+* (binding) `ko.applyBindings` now returns a Promise that resolves when bindings are completed
+
+* (binding handlers) Add new-style ES6 Binding Handler class (see custom-bindings documentation and tko.bind/src/BindingHandler.js), descended from the LifeCycle class
+* (bind) String errors on binding are now propagated
+
+## Binding Handlers and ko.BindingHandler
+
+In TKO, binding handlers can be either an `object`, a `function` or a descendant of `ko.BindingHandler`. The following are all valid binding handlers:
+
+```javascript
+class NewHandler extends ko.BindingHandler {
+ constructor ({$element, valueAccessor, allBindings, $context, onError}) {
+ /*
+ this.value is valueAccessor()
+ this.value(x) is valueAccessor(x);
+ if valueAccessor() is observable or a property, it will be set properly.
+ */
+ }
+
+ get controlsDescendants () { return true|false }
+
+ get bindingComplete () {
+ /* overload where binding is asynchronous. See e.g. Component binding*/
+ }
+ static get allowVirtualElements () { return true|false }
+}
+
+handler_fn = (element, valueAccessor, allBindings, viewModel, bindingContext) => { /* ... */ }
+
+the_knockout_3_way = {
+ init (element, valueAccessor, allBindings, viewModel, bindingContext) {
+ /* ... */
+ },
+
+ update (element, valueAccessor, allBindings, viewModel, bindingContext) {
+ /* ... */
+ },
+
+ allowVirtualElements: true|false
+}
+
+// Virtual Elements may be permitted for a binding explicitly.
+virtualElements.allowedBindings[handler_name] = true|false
+```
+
+Binding handlers can be registered in the following ways:
+
+```javascript
+// Globally, where NewHandler is a BindingHandler descendant.
+NewHandler.registerAs('handler')
+
+// Globally, for any handler type.
+ko.bindingHandlers.set(handler_name: handler)
+
+// Knockout 3.x style
+ko.bindingHandlers[handler_name] = handler
+
+// For a component
+class Component {
+ getBindingHandler(bindingKey) {
+ if (bindingKey === handler_name) { return handler }
+ // Alternatively:
+ // return { bindingKey[bindingKey]: handler }[bindingKey]
+ }
+}
+```
+
+## Parsing
+
+* (parser) Fix interpretation of unicode characters as identifiers / variables
+* `==` and `===` use `===` for comparison (same for `!=` and `!==`); fuzzy equality ~== / ~!= for the evil twins
+* Knockout 4 will work with a Content Security Policy that prohibits unsafe-eval.
+ * add "naked" `=>` lambdas (even in legacy browsers e.g. `data-bind='click: => was_clicked(true)'`
+ * inline functions are no longer supported (e.g. `data-bind='click: function (){...}'` will fail)
+ * No longer uses `with` statements
+ * No longer uses `eval`/`new Function`
+
+## Namespacing
+
+ * incorporate punches namespacing i.e. `data-bind='event.click: => thing(true)'` is equivalent to `data-bind='event: {click: => thing(true)}'`
+
+## Attribute Interpolation
+
+
+## Text Interpolation
+
+* incorporate punches {% raw %}`{{ }}`{% endraw %} and {% raw %}`{{{}}}` {% endraw %}text and attribute interpolation
+
+
+## Event
+* (`event` binding) Add object-based event handler e.g. `event.click: { handler: fn, once: true, capture: true, bubble: false, passive: false}`. Also, bubbling can be prevented with `event.click: {bubble: false }` re #32
+* (`event` binding) Add `throttle` and `debounce` parameters
+
+## With
+* (with binding) Fix dependency count for function-arguments [knockout/knockout#2285]
+
+## Attr
+* (attr) Support namespaced attributes with `attr` binding #27
+
+## Foreach
+
+* Use tko.binding.foreach for the `foreach` binding (based on brianmhunt/knockout-fast-foreach)
+* Add `each` as an alias of `foreach`
+* Rewritten as O(1)
+* (foreach binding) When using the `as` parameter, the `$data` remains unchanged (i.e. the context inside a `foreach` is no longer a "child" context, but an extension of the current context); this deprecates the `noContext` parameter
+* (foreach binding) Expose the `conditional` on the `domData` for use by the `else` binding (when the array is empty, the `else` binding will be rendered)
+* (foreach binding) Expose `$list` inside the foreach
+* (foreach binding) Allow `noIndex` as a peer binding parameter (e.g. `foreach: items, noIndex: true`)
+* (foreach) Preserve focus when items are deleted and re-added (i.e. moved) in the same animation frame.
+
+## Template
+
+* Make the `template` binding expose a conditional for else-binding
+* support template literals (\`\`) in bindings (even in legacy browsers)
+* add the `@` prefix operator that calls/unwrap functions (i.e. `obs()()` is the same as `@obs`)
+
+## If / Else
+
+* add `` inside the `if` binding, and add an `else` binding (following the brianmhunt/knockout-else plugin)
+* Add `else` binding
+* Add `unless` binding
+
+## Using
+
+## Hidden
+
+ * add `hidden` binding (knockout/knockut#2103)
+
+## HTML
+
+The HTML binding now works in virtual elements. Based on ko.punches.
+
+## Filtering
+
+Filters can be applied to modify values in bindings. Based on ko.punches.
+
+
+# Deprecated
+
+ - Template binding options are deprecated
+ - expressionWriting (twoWayBinding)
+ - ‘.’ in binding handler names
+ - jsonExpressionRewriting (expressionRewriting)
+ - form parsing
+ - `bind` shim
+ - ko.utils.parseJson
+ - getFormFields
+ - fieldsIncludedWithJsonPost
+ - postJson
diff --git a/tko.io/src/CNAME b/tko.io/src/CNAME
new file mode 100644
index 000000000..b091eb46d
--- /dev/null
+++ b/tko.io/src/CNAME
@@ -0,0 +1 @@
+tko.io
\ No newline at end of file
diff --git a/tko.io/src/_layouts/base.njk b/tko.io/src/_layouts/base.njk
new file mode 100644
index 000000000..4acbdd35b
--- /dev/null
+++ b/tko.io/src/_layouts/base.njk
@@ -0,0 +1,59 @@
+
+
+
+
+
+ {{ title }} - TKO
+
+
+
+
+
+
+
+
+ {{ content | safe }}
+
+
+
+
+
diff --git a/tko.io/src/css/tko.css b/tko.io/src/css/tko.css
new file mode 100644
index 000000000..402dfc9b8
--- /dev/null
+++ b/tko.io/src/css/tko.css
@@ -0,0 +1,659 @@
+@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap');
+
+/* CSS Reset and Base Styles */
+* {
+ box-sizing: border-box;
+}
+
+html {
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+html,
+body {
+ margin: 0;
+ padding: 0;
+ overflow-x: hidden;
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', sans-serif;
+ font-size: 16px;
+ line-height: 1.6;
+ color: #1a1a1a;
+ background-color: #ffffff;
+}
+
+body {
+ display: grid;
+ margin-top: 64px;
+ height: calc(100vh - 64px);
+ grid-template-columns: 280px 1fr;
+ grid-template-areas: 'sidebar main';
+ position: relative;
+}
+
+@media screen and (max-width: 991px) {
+ body {
+ grid-template-columns: 1fr;
+ grid-template-areas:
+ 'sidebar'
+ 'main';
+ height: auto;
+ }
+}
+
+/* Typography */
+h1, h2, h3, h4, h5, h6 {
+ font-weight: 600;
+ line-height: 1.25;
+ margin-top: 1.5em;
+ margin-bottom: 0.5em;
+ color: #111827;
+}
+
+h1 {
+ font-size: 2.25rem;
+ font-weight: 700;
+ margin-top: 0;
+ margin-bottom: 1rem;
+ letter-spacing: -0.025em;
+}
+
+h2 {
+ font-size: 1.875rem;
+ margin-top: 2em;
+ padding-bottom: 0.3em;
+ border-bottom: 1px solid #e5e7eb;
+}
+
+h3 {
+ font-size: 1.5rem;
+ margin-top: 1.6em;
+}
+
+h4 {
+ font-size: 1.25rem;
+}
+
+p {
+ margin: 1em 0;
+ line-height: 1.7;
+}
+
+/* Links */
+a {
+ color: #2563eb;
+ text-decoration: none;
+ transition: color 0.15s ease;
+}
+
+a:hover {
+ color: #1d4ed8;
+}
+
+a:focus {
+ outline: 2px solid #3b82f6;
+ outline-offset: 2px;
+ border-radius: 2px;
+}
+
+main a {
+ text-decoration: underline;
+ text-decoration-color: #93c5fd;
+ text-underline-offset: 2px;
+}
+
+main a:hover {
+ text-decoration-color: #2563eb;
+}
+
+/* Tables */
+table {
+ width: 100%;
+ border-collapse: collapse;
+ margin: 1.5em 0;
+ font-size: 0.9375rem;
+}
+
+th {
+ padding: 0.75rem 1rem;
+ text-align: left;
+ font-weight: 600;
+ background-color: #f9fafb;
+ border-bottom: 2px solid #e5e7eb;
+ color: #374151;
+}
+
+td {
+ padding: 0.75rem 1rem;
+ border-bottom: 1px solid #e5e7eb;
+}
+
+tr:hover {
+ background-color: #f9fafb;
+}
+
+/* Lists */
+ul, ol {
+ margin: 1em 0;
+ padding-left: 1.5em;
+}
+
+li {
+ margin: 0.5em 0;
+ line-height: 1.7;
+}
+
+/* Blockquotes */
+blockquote {
+ margin: 1.5em 0;
+ padding: 1em 1.5em;
+ border-left: 4px solid #3b82f6;
+ background-color: #eff6ff;
+ color: #1e40af;
+}
+
+/*
+ * TOP BAR
+ */
+.top-bar {
+ width: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 2rem;
+ padding: 0 2rem;
+ top: 0;
+ left: 0;
+ position: fixed;
+ z-index: 1200;
+ height: 64px;
+ background-color: #ffffff;
+ border-bottom: 1px solid #e5e7eb;
+ box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);
+}
+
+.top-bar .tko {
+ font-size: 1.5rem;
+ font-weight: 700;
+ color: #2563eb;
+ letter-spacing: -0.025em;
+}
+
+.top-bar a {
+ padding: 0.5rem 1rem;
+ color: #4b5563;
+ font-size: 0.9375rem;
+ font-weight: 500;
+ border-radius: 6px;
+ transition: all 0.15s ease;
+}
+
+.top-bar a:hover {
+ color: #2563eb;
+ background-color: #eff6ff;
+}
+
+.top-bar a.external::after {
+ content: '↗';
+ margin-left: 0.25rem;
+ font-size: 0.875rem;
+}
+
+.current-page {
+ color: #2563eb !important;
+ background-color: #eff6ff;
+}
+
+@media screen and (max-width: 768px) {
+ .top-bar {
+ padding: 0 1rem;
+ gap: 0.5rem;
+ }
+
+ .top-bar a {
+ padding: 0.5rem;
+ font-size: 0.875rem;
+ }
+}
+
+/**
+ * SIDEBAR
+ */
+.sidebar {
+ grid-area: sidebar;
+ height: calc(100vh - 64px);
+ overflow-y: auto;
+ overflow-x: hidden;
+ background-color: #f9fafb;
+ border-right: 1px solid #e5e7eb;
+ padding: 1rem 0;
+}
+
+/* Custom scrollbar for sidebar */
+.sidebar::-webkit-scrollbar {
+ width: 6px;
+}
+
+.sidebar::-webkit-scrollbar-track {
+ background: transparent;
+}
+
+.sidebar::-webkit-scrollbar-thumb {
+ background-color: #d1d5db;
+ border-radius: 3px;
+}
+
+.sidebar::-webkit-scrollbar-thumb:hover {
+ background-color: #9ca3af;
+}
+
+.toc {
+ display: flex;
+ flex-direction: column;
+ gap: 0.125rem;
+ padding: 0 1rem;
+}
+
+.sidebar a {
+ display: block;
+ padding: 0.375rem 0.75rem;
+ color: #4b5563;
+ font-size: 0.875rem;
+ border-radius: 6px;
+ transition: all 0.15s ease;
+ text-decoration: none;
+}
+
+.sidebar a:hover {
+ color: #111827;
+ background-color: #e5e7eb;
+}
+
+.sidebar .section {
+ font-size: 0.875rem;
+ font-weight: 600;
+ color: #111827;
+ padding: 0.5rem 0.75rem 0.25rem;
+ margin-top: 1rem;
+ text-transform: uppercase;
+ letter-spacing: 0.05em;
+ font-size: 0.75rem;
+}
+
+.sidebar .section:first-child {
+ margin-top: 0;
+}
+
+.sidebar .subheading {
+ padding-left: 1.5rem;
+ font-weight: 400;
+ position: relative;
+}
+
+.sidebar .subheading::before {
+ content: '';
+ position: absolute;
+ left: 0.75rem;
+ top: 50%;
+ transform: translateY(-50%);
+ width: 2px;
+ height: 60%;
+ background-color: transparent;
+ transition: background-color 0.15s ease;
+}
+
+.sidebar .subheading:hover::before {
+ background-color: #3b82f6;
+}
+
+/* Binding name code styling in sidebar */
+.sidebar .binding-name code {
+ background-color: transparent;
+ color: inherit;
+ padding: 0;
+ border-radius: 0;
+ font-size: 0.8125rem;
+ font-weight: 500;
+}
+
+@keyframes slideIn {
+ from {
+ opacity: 0;
+ transform: translateX(-4px);
+ }
+ to {
+ opacity: 1;
+ transform: translateX(0);
+ }
+}
+
+.sidebar .in-viewport {
+ color: #2563eb;
+ background-color: #eff6ff;
+ font-weight: 500;
+}
+
+.sidebar .in-viewport::before {
+ background-color: #2563eb;
+}
+
+@media screen and (max-width: 991px) {
+ .sidebar {
+ height: auto;
+ max-height: 400px;
+ border-right: none;
+ border-bottom: 1px solid #e5e7eb;
+ }
+}
+
+/**
+ * MAIN CONTENT
+ */
+main {
+ grid-area: main;
+ height: calc(100vh - 64px);
+ background-color: #ffffff;
+ padding: 3rem 0;
+ overflow-y: auto;
+ overflow-x: hidden;
+ /* Use CSS grid to allow examples to break out while keeping content centered */
+ display: grid;
+ grid-template-columns: minmax(3rem, 1fr) minmax(0, 1000px) minmax(3rem, 1fr);
+ grid-auto-rows: auto;
+}
+
+main > * {
+ /* Most content goes in the center column */
+ grid-column: 2;
+}
+
+main > *:first-child {
+ margin-top: 0;
+}
+
+h1 code {
+ background-color: #eff6ff;
+ border: 2px solid #3b82f6;
+ font-size: inherit;
+ padding: 0.1em 0.3em;
+ border-radius: 6px;
+ font-weight: 700;
+}
+
+@media screen and (max-width: 991px) {
+ main {
+ padding: 2rem 1.5rem;
+ height: auto;
+ }
+}
+
+/**
+ * CODE BLOCKS
+ */
+
+code {
+ font-family: 'JetBrains Mono', 'SF Mono', 'Monaco', 'Inconsolata', 'Fira Code', 'Droid Sans Mono', 'Source Code Pro', monospace;
+ font-size: 0.875em;
+ font-weight: 400;
+}
+
+/* Inline code */
+:not(pre) > code {
+ background-color: #f3f4f6;
+ color: #dc2626;
+ padding: 0.2em 0.4em;
+ border-radius: 4px;
+ font-size: 0.875em;
+ white-space: nowrap;
+}
+
+/* Code blocks */
+pre {
+ background-color: #1e293b;
+ color: #e2e8f0;
+ padding: 1.25rem 1.5rem;
+ margin: 1.5em 0;
+ border-radius: 8px;
+ overflow-x: auto;
+ overflow-y: visible;
+ line-height: 1.6;
+ box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);
+ min-height: fit-content;
+ height: auto;
+}
+
+pre code {
+ background-color: transparent;
+ color: #e2e8f0;
+ padding: 0;
+ border-radius: 0;
+ white-space: pre;
+ font-size: 0.875rem;
+ line-height: 1.6;
+}
+
+/* Syntax highlighting hints */
+pre code .keyword {
+ color: #c792ea;
+}
+
+pre code .string {
+ color: #c3e88d;
+}
+
+pre code .comment {
+ color: #636e7b;
+ font-style: italic;
+}
+
+/* Custom scrollbar for code blocks */
+pre::-webkit-scrollbar {
+ height: 8px;
+}
+
+pre::-webkit-scrollbar-track {
+ background: #0f172a;
+ border-radius: 4px;
+}
+
+pre::-webkit-scrollbar-thumb {
+ background-color: #475569;
+ border-radius: 4px;
+}
+
+pre::-webkit-scrollbar-thumb:hover {
+ background-color: #64748b;
+}
+
+/**
+ * UTILITY CLASSES
+ */
+
+.section-title {
+ font-size: 2.5rem;
+ font-weight: 700;
+ margin-bottom: 1rem;
+ color: #111827;
+}
+
+/**
+ * Source Linking
+ */
+.source {
+ display: block;
+ text-align: right;
+ font-size: 0.875rem;
+ position: sticky;
+ top: 0;
+ margin-bottom: 1rem;
+}
+
+.source a {
+ display: inline-block;
+ padding: 0.5rem 1rem;
+ background-color: #f3f4f6;
+ color: #4b5563;
+ border: 1px solid #d1d5db;
+ border-radius: 6px;
+ transition: all 0.15s ease;
+}
+
+.source a:hover {
+ background-color: #e5e7eb;
+ border-color: #9ca3af;
+}
+
+/**
+ * BOOK GRID
+ */
+.book-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
+ gap: 1.5rem;
+ margin: 2rem 0;
+}
+
+.book-grid .card {
+ background: #ffffff;
+ border: 1px solid #e5e7eb;
+ border-radius: 8px;
+ padding: 1.5rem;
+ transition: all 0.2s ease;
+}
+
+.book-grid .card:hover {
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
+ transform: translateY(-2px);
+}
+
+/**
+ * INTERACTIVE EXAMPLES
+ */
+.example-container {
+ /* Span all 3 columns of the main grid */
+ grid-column: 1 / -1;
+ margin: 1.5em 3rem;
+ height: 400px;
+ border: 1px solid #e5e7eb;
+ border-radius: 8px;
+ overflow: hidden;
+ box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);
+ display: flex;
+ flex-direction: row;
+ position: relative;
+}
+
+.example-editor {
+ flex: 1;
+ min-width: 0;
+ height: 100%;
+ border-right: 2px solid #3b82f6;
+ overflow: auto;
+}
+
+.example-editor .cm-editor {
+ height: 100%;
+ font-family: 'JetBrains Mono', 'SF Mono', 'Monaco', 'Inconsolata', monospace;
+ font-size: 0.875rem;
+}
+
+.example-editor .cm-scroller {
+ overflow: auto;
+}
+
+.example-editor .cm-focused {
+ outline: none !important;
+}
+
+.example-editor:focus-within {
+ border-right-color: #2563eb;
+}
+
+.example-result {
+ flex: 1;
+ min-width: 0;
+ height: 100%;
+ border: none;
+ background-color: #ffffff;
+ overflow: hidden;
+}
+
+.example-error {
+ position: absolute;
+ bottom: 0;
+ left: 50%;
+ right: 0;
+ padding: 1rem 1.5rem;
+ background-color: #fef2f2;
+ color: #991b1b;
+ border-top: 2px solid #dc2626;
+ font-family: 'JetBrains Mono', monospace;
+ font-size: 0.875rem;
+ line-height: 1.5;
+ z-index: 10;
+}
+
+/* Responsive: stack vertically on mobile */
+@media (max-width: 768px) {
+ .example-container {
+ flex-direction: column;
+ margin: 1.5em 1rem;
+ height: 600px;
+ }
+
+ .example-editor {
+ border-right: none;
+ border-bottom: 2px solid #3b82f6;
+ max-height: 50%;
+ }
+
+ .example-editor:focus-within {
+ border-bottom-color: #2563eb;
+ }
+
+ .example-result {
+ max-height: 50%;
+ }
+
+ .example-error {
+ left: 0;
+ }
+}
+
+/**
+ * ACCESSIBILITY & FOCUS STATES
+ */
+*:focus-visible {
+ outline: 2px solid #3b82f6;
+ outline-offset: 2px;
+}
+
+/**
+ * PRINT STYLES
+ */
+@media print {
+ .top-bar,
+ .sidebar {
+ display: none;
+ }
+
+ main {
+ max-width: 100%;
+ padding: 1rem;
+ }
+
+ body {
+ grid-template-columns: 1fr;
+ margin-top: 0;
+ }
+
+ a {
+ text-decoration: underline;
+ }
+
+ a[href^="http"]::after {
+ content: " (" attr(href) ")";
+ font-size: 0.875em;
+ color: #6b7280;
+ }
+}
diff --git a/packages/provider.databind/docs/databind-parser.md b/tko.io/src/docs/advanced/databind-parser.md
similarity index 99%
rename from packages/provider.databind/docs/databind-parser.md
rename to tko.io/src/docs/advanced/databind-parser.md
index db9df61cd..9b7405602 100644
--- a/packages/provider.databind/docs/databind-parser.md
+++ b/tko.io/src/docs/advanced/databind-parser.md
@@ -1,3 +1,9 @@
+---
+layout: base.njk
+title: DataBind Parser
+---
+
+# DataBind Parser
tko.provider is a binding provider for [Knockout](http://knockoutjs.com), namely it parses HTML attributes and converts them to handlers of bidirectional updates.
diff --git a/packages/lifecycle/docs/life-cycle.md b/tko.io/src/docs/advanced/life-cycle.md
similarity index 98%
rename from packages/lifecycle/docs/life-cycle.md
rename to tko.io/src/docs/advanced/life-cycle.md
index 565e95a2e..7cdecab87 100644
--- a/packages/lifecycle/docs/life-cycle.md
+++ b/tko.io/src/docs/advanced/life-cycle.md
@@ -1,4 +1,9 @@
-# tko.lifecycle
+---
+layout: base.njk
+title: Lifecycle
+---
+
+# Lifecycle
The `tko.lifecycle` package exports one class, `LifeCycle`, which is intended to make tracking and disposing of temporary computations, subscriptions, and DOM event handlers simpler.
diff --git a/packages/provider/docs/provider.md b/tko.io/src/docs/advanced/provider.md
similarity index 83%
rename from packages/provider/docs/provider.md
rename to tko.io/src/docs/advanced/provider.md
index adcb20017..4f5e8591e 100644
--- a/packages/provider/docs/provider.md
+++ b/tko.io/src/docs/advanced/provider.md
@@ -1,3 +1,7 @@
+---
+layout: base.njk
+title: Provider
+---
# Provider
@@ -9,8 +13,8 @@ The `Provider` is a class that is responsible for linking nodes to binding handl
| `VirtualProvider` | ``
| `ComponentProvider` | ``
| `AttributeProvider` | ``
-| `TextMustacheProvider` | `{{ x_text }}` `{{{ x_html }}}` `{{# text: thing /}}`
-| `AttributeMustacheProvider` | ``
+| `TextMustacheProvider` | {% raw %}`{{ x_text }}`{% endraw %} {% raw %}`{{{ x_html }}}`{% endraw %} {% raw %}`{{# text: thing /}}`{% endraw %}
+| `AttributeMustacheProvider` | {% raw %}``{% endraw %}
| `MultiProvider` | Combines more than one provider together.
When building custom versions of tko, one can choose to use one or more binding providers, or to create a custom binding provider.
diff --git a/packages/bind/docs/binding-context.md b/tko.io/src/docs/binding-context/binding-context.md
similarity index 94%
rename from packages/bind/docs/binding-context.md
rename to tko.io/src/docs/binding-context/binding-context.md
index 14c342c05..c453d7249 100644
--- a/packages/bind/docs/binding-context.md
+++ b/tko.io/src/docs/binding-context/binding-context.md
@@ -1,7 +1,12 @@
+---
+layout: base.njk
+title: Binding Context
+---
+
# Binding Context
-A *binding context* is an object that holds data that you can reference from your bindings. While applying bindings, Knockout automatically creates and manages a hierarchy of binding contexts. The root level of the hierarchy refers to the `viewModel` parameter you supplied to `ko.applyBindings(viewModel)`. Then, each time you use a control flow binding such as [`with`](with-binding.html) or [`foreach`](foreach-binding.html), that creates a child binding context that refers to the nested view model data.
+A *binding context* is an object that holds data that you can reference from your bindings. While applying bindings, Knockout automatically creates and manages a hierarchy of binding contexts. The root level of the hierarchy refers to the `viewModel` parameter you supplied to `ko.applyBindings(viewModel)`. Then, each time you use a control flow binding such as [`with`](../with-binding/) or [`foreach`](../foreach-binding/), that creates a child binding context that refers to the nested view model data.
Bindings contexts offer the following special properties that you can reference in any binding:
diff --git a/packages/bind/docs/binding-preprocessing.md b/tko.io/src/docs/binding-context/binding-preprocessing.md
similarity index 97%
rename from packages/bind/docs/binding-preprocessing.md
rename to tko.io/src/docs/binding-context/binding-preprocessing.md
index bf6392858..2b0b76851 100644
--- a/packages/bind/docs/binding-preprocessing.md
+++ b/tko.io/src/docs/binding-context/binding-preprocessing.md
@@ -1,3 +1,8 @@
+---
+layout: base.njk
+title: Binding Preprocessing
+---
+
# Binding Preprocessing
@@ -7,7 +12,7 @@ Starting with Knockout 3.0, developers can define custom syntaxes by providing c
## Preprocessing binding strings
-You can hook into Knockout's logic for interpreting `data-bind` attributes by providing a *binding preprocessor* for a specific binding handler (such as `click`, `visible`, or any [custom binding handler](custom-bindings.html)).
+You can hook into Knockout's logic for interpreting `data-bind` attributes by providing a *binding preprocessor* for a specific binding handler (such as `click`, `visible`, or any [custom binding handler](../../binding-context/custom-bindings/)).
To do this, attach a `preprocess` function to the binding handler:
@@ -77,7 +82,7 @@ Now you can bind `click` like this:
## Preprocessing DOM nodes
-You can hook into Knockout's logic for traversing the DOM by providing a *node preprocessor*. This is a function that Knockout will call once for each DOM node that it walks over, both when the UI is first bound, and later when any new DOM subtrees are injected (e.g., via a [`foreach` binding](foreach-binding.html)).
+You can hook into Knockout's logic for traversing the DOM by providing a *node preprocessor*. This is a function that Knockout will call once for each DOM node that it walks over, both when the UI is first bound, and later when any new DOM subtrees are injected (e.g., via a [`foreach` binding](../foreach-binding/)).
To do this, define a `preprocessNode` function on your binding provider:
diff --git a/packages/bind/docs/binding-syntax.md b/tko.io/src/docs/binding-context/binding-syntax.md
similarity index 91%
rename from packages/bind/docs/binding-syntax.md
rename to tko.io/src/docs/binding-context/binding-syntax.md
index 192c19360..5da2b5c4b 100644
--- a/packages/bind/docs/binding-syntax.md
+++ b/tko.io/src/docs/binding-context/binding-syntax.md
@@ -1,3 +1,8 @@
+---
+layout: base.njk
+title: Binding Syntax
+---
+
# The `data-bind` Syntax
@@ -21,7 +26,7 @@ Your value:
Cellphone:
```
-The binding *name* should generally match a registered binding handler (either built-in or [custom](custom-bindings.html)) or be a parameter for another binding. If the name matches neither of those, Knockout will ignore it (without any error or warning). So if a binding doesn't appear to work, first check that the name is correct.
+The binding *name* should generally match a registered binding handler (either built-in or [custom](../../binding-context/custom-bindings/)) or be a parameter for another binding. If the name matches neither of those, Knockout will ignore it (without any error or warning). So if a binding doesn't appear to work, first check that the name is correct.
#### Binding values
diff --git a/packages/bind/docs/custom-bindings-controlling-descendant-bindings.md b/tko.io/src/docs/binding-context/custom-bindings-controlling-descendant-bindings.md
similarity index 94%
rename from packages/bind/docs/custom-bindings-controlling-descendant-bindings.md
rename to tko.io/src/docs/binding-context/custom-bindings-controlling-descendant-bindings.md
index c1187ae7f..d4c931643 100644
--- a/packages/bind/docs/custom-bindings-controlling-descendant-bindings.md
+++ b/tko.io/src/docs/binding-context/custom-bindings-controlling-descendant-bindings.md
@@ -1,3 +1,8 @@
+---
+layout: base.njk
+title: Custom Bindings Controlling Descendant Bindings
+---
+
# Controlling Descendant Bindnings
*Note: Creating custom bindings that control descendant binding is an advanced technique, typically used only when creating libraries of reusable bindings. It's not something you'll normally need to do when building applications with Knockout.*
@@ -36,7 +41,7 @@ To see this take effect, here's a sample usage:
### Example: Supplying additional values to descendant bindings
-Normally, bindings that use `controlsDescendantBindings` will also call `ko.applyBindingsToDescendants(someBindingContext, element)` to apply the descendant bindings against some modified [binding context](binding-context.html). For example, you could have a binding called `withProperties` that attaches some extra properties to the binding context that will then be available to all descendant bindings:
+Normally, bindings that use `controlsDescendantBindings` will also call `ko.applyBindingsToDescendants(someBindingContext, element)` to apply the descendant bindings against some modified [binding context](../../binding-context/binding-context/). For example, you could have a binding called `withProperties` that attaches some extra properties to the binding context that will then be available to all descendant bindings:
```javascript
ko.bindingHandlers.withProperties = {
diff --git a/packages/bind/docs/custom-bindings-disposal.md b/tko.io/src/docs/binding-context/custom-bindings-disposal.md
similarity index 82%
rename from packages/bind/docs/custom-bindings-disposal.md
rename to tko.io/src/docs/binding-context/custom-bindings-disposal.md
index fdcc7e607..23f1a4307 100644
--- a/packages/bind/docs/custom-bindings-disposal.md
+++ b/tko.io/src/docs/binding-context/custom-bindings-disposal.md
@@ -1,6 +1,11 @@
+---
+layout: base.njk
+title: Custom Bindings Disposal
+---
+
# Custom Disposal Logic
-In a typical Knockout application, DOM elements are dynamically added and removed, for example using the [`template`](template-binding.html) binding or via control-flow bindings ([`if`](if-binding.html), [`ifnot`](ifnot-binding.html), [`with`](with-binding.html), and [`foreach`](foreach-binding.html)). When creating a custom binding, it is often desirable to add clean-up logic that runs when an element associated with your custom binding is removed by Knockout.
+In a typical Knockout application, DOM elements are dynamically added and removed, for example using the [`template`](template-binding.html) binding or via control-flow bindings ([`if`](../if-binding/), [`ifnot`](ifnot-binding.html), [`with`](../with-binding/), and [`foreach`](../foreach-binding/)). When creating a custom binding, it is often desirable to add clean-up logic that runs when an element associated with your custom binding is removed by Knockout.
### Registering a callback on the disposal of an element
diff --git a/packages/bind/docs/custom-bindings-for-virtual-elements.md b/tko.io/src/docs/binding-context/custom-bindings-for-virtual-elements.md
similarity index 95%
rename from packages/bind/docs/custom-bindings-for-virtual-elements.md
rename to tko.io/src/docs/binding-context/custom-bindings-for-virtual-elements.md
index 0a6fbdf26..a7aa1024c 100644
--- a/packages/bind/docs/custom-bindings-for-virtual-elements.md
+++ b/tko.io/src/docs/binding-context/custom-bindings-for-virtual-elements.md
@@ -1,9 +1,14 @@
+---
+layout: base.njk
+title: Custom Bindings For Virtual Elements
+---
+
# Custom Bindings and Virtual Elements
*Note: Creating custom bindings that support virtual elements is an advanced technique, typically used only when creating libraries of reusable bindings. It's not something you'll normally need to do when building applications with Knockout.*
-Knockout's *control flow bindings* (e.g., [`if`](if-binding.html) and [`foreach`](foreach-binding.html)) can be applied not only to regular DOM elements, but also to "virtual" DOM elements defined by a special comment-based syntax. For example:
+Knockout's *control flow bindings* (e.g., [`if`](../if-binding/) and [`foreach`](../foreach-binding/)) can be applied not only to regular DOM elements, but also to "virtual" DOM elements defined by a special comment-based syntax. For example:
```html
diff --git a/packages/bind/docs/custom-bindings.md b/tko.io/src/docs/binding-context/custom-bindings.md
similarity index 99%
rename from packages/bind/docs/custom-bindings.md
rename to tko.io/src/docs/binding-context/custom-bindings.md
index a9d78c7d4..8de3fcb04 100644
--- a/packages/bind/docs/custom-bindings.md
+++ b/tko.io/src/docs/binding-context/custom-bindings.md
@@ -1,3 +1,8 @@
+---
+layout: base.njk
+title: Custom Bindings
+---
+
# Creating Custom Bindings
diff --git a/packages/binding.core/docs/unobtrusive-event-handling.md b/tko.io/src/docs/binding-context/unobtrusive-event-handling.md
similarity index 96%
rename from packages/binding.core/docs/unobtrusive-event-handling.md
rename to tko.io/src/docs/binding-context/unobtrusive-event-handling.md
index ac96d2ba1..002476cdc 100644
--- a/packages/binding.core/docs/unobtrusive-event-handling.md
+++ b/tko.io/src/docs/binding-context/unobtrusive-event-handling.md
@@ -1,3 +1,8 @@
+---
+layout: base.njk
+title: Unobtrusive Event Handling Binding
+---
+
# Unobtrusive Event Handlers
In most cases, data-bind attributes provide a clean and succinct way to bind to a view model. However, event handling is one area that can often result in verbose data-bind attributes, as anonymous functions were typically the recommended techinique to pass arguments. For example:
@@ -11,7 +16,7 @@ In most cases, data-bind attributes provide a clean and succinct way to bind to
As an alternative, Knockout provides two helper functions that allow you to identify the data associated with a DOM element:
* `ko.dataFor(element)` - returns the data that was available for binding against the element
- * `ko.contextFor(element)` - returns the entire [binding context](binding-context.html) that was available to the DOM element.
+ * `ko.contextFor(element)` - returns the entire [binding context](../../binding-context/binding-context/) that was available to the DOM element.
These helper functions can be used in event handlers that are attached unobtrusively using something like jQuery's `bind` or `click`. The above function could be attached to each link with a `remove` class like:
diff --git a/packages/binding.core/docs/attr-binding.md b/tko.io/src/docs/bindings/attr-binding.md
similarity index 97%
rename from packages/binding.core/docs/attr-binding.md
rename to tko.io/src/docs/bindings/attr-binding.md
index 4254ddbdd..ff391b3f2 100644
--- a/packages/binding.core/docs/attr-binding.md
+++ b/tko.io/src/docs/bindings/attr-binding.md
@@ -1,3 +1,8 @@
+---
+layout: base.njk
+title: Attr Binding
+---
+
# `attr`
### Purpose
diff --git a/packages/binding.core/docs/checked-binding.md b/tko.io/src/docs/bindings/checked-binding.md
similarity index 97%
rename from packages/binding.core/docs/checked-binding.md
rename to tko.io/src/docs/bindings/checked-binding.md
index fb4b32228..36edb5b09 100644
--- a/packages/binding.core/docs/checked-binding.md
+++ b/tko.io/src/docs/bindings/checked-binding.md
@@ -1,3 +1,8 @@
+---
+layout: base.njk
+title: Checked Binding
+---
+
# `checked`
@@ -6,7 +11,7 @@ The `checked` binding links a checkable form control — i.e., a checkbox (`
When the user checks the associated form control, this updates the value on your view model. Likewise, when you update the value in your view model, this checks or unchecks the form control on screen.
-Note: For text boxes, drop-down lists, and all non-checkable form controls, use [the `value` binding](value-binding.html) to read and write the element's value, not the `checked` binding.
+Note: For text boxes, drop-down lists, and all non-checkable form controls, use [the `value` binding](../value-binding/) to read and write the element's value, not the `checked` binding.
### Example with checkbox
diff --git a/packages/binding.core/docs/click-binding.md b/tko.io/src/docs/bindings/click-binding.md
similarity index 95%
rename from packages/binding.core/docs/click-binding.md
rename to tko.io/src/docs/bindings/click-binding.md
index d7159a2b2..14a7700a9 100644
--- a/packages/binding.core/docs/click-binding.md
+++ b/tko.io/src/docs/bindings/click-binding.md
@@ -1,3 +1,8 @@
+---
+layout: base.njk
+title: Click Binding
+---
+
# `click`
### Purpose
@@ -30,7 +35,7 @@ some UI for each item in a collection, and you need to know which item's UI was
Two points to note about this example:
- * If you're inside a nested [binding context](binding-context.html), for example if you're inside a `foreach` or a `with` block, but your handler function
+ * If you're inside a nested [binding context](../../binding-context/binding-context/), for example if you're inside a `foreach` or a `with` block, but your handler function
is on the root viewmodel or some other parent context, you'll need to use a prefix such as `$parent` or `$root` to locate the
handler function.
* In your viewmodel, it's often useful to declare `self` (or some other variable) as an alias for `this`. Doing so avoids any problems
diff --git a/packages/binding.core/docs/css-binding.md b/tko.io/src/docs/bindings/css-binding.md
similarity index 98%
rename from packages/binding.core/docs/css-binding.md
rename to tko.io/src/docs/bindings/css-binding.md
index 38c945376..6f0433c02 100644
--- a/packages/binding.core/docs/css-binding.md
+++ b/tko.io/src/docs/bindings/css-binding.md
@@ -1,9 +1,14 @@
+---
+layout: base.njk
+title: Css Binding
+---
+
# `css`
### Purpose
The `css` binding adds or removes one or more named CSS classes to the associated DOM element. This is useful, for example, to highlight some value in red if it becomes negative.
-(Note: If you don't want to apply a CSS class but instead want to assign a `style` attribute value directly, see [the style binding](style-binding.html).)
+(Note: If you don't want to apply a CSS class but instead want to assign a `style` attribute value directly, see [the style binding](../style-binding/).)
### Example with static classes
```html
diff --git a/packages/binding.core/docs/disable-binding.md b/tko.io/src/docs/bindings/disable-binding.md
similarity index 54%
rename from packages/binding.core/docs/disable-binding.md
rename to tko.io/src/docs/bindings/disable-binding.md
index 791cf2539..e8af8f6c2 100644
--- a/packages/binding.core/docs/disable-binding.md
+++ b/tko.io/src/docs/bindings/disable-binding.md
@@ -1,6 +1,11 @@
+---
+layout: base.njk
+title: Disable Binding
+---
+
# `disable`
### Purpose
The `disable` binding causes the associated DOM element to be disabled only when the parameter value is `true`. This is useful with form elements like `input`, `select`, and `textarea`.
-This is the mirror image of the `enable` binding. For more information, see [documentation for the `enable` binding](#enable-binding), because `disable` works in exactly the same way except that it negates whatever parameter you pass to it.
+This is the mirror image of the `enable` binding. For more information, see [documentation for the `enable` binding](../enable-binding/), because `disable` works in exactly the same way except that it negates whatever parameter you pass to it.
diff --git a/packages/binding.core/docs/enable-binding.md b/tko.io/src/docs/bindings/enable-binding.md
similarity index 96%
rename from packages/binding.core/docs/enable-binding.md
rename to tko.io/src/docs/bindings/enable-binding.md
index 4c0ca9c03..126ae3ed7 100644
--- a/packages/binding.core/docs/enable-binding.md
+++ b/tko.io/src/docs/bindings/enable-binding.md
@@ -1,3 +1,8 @@
+---
+layout: base.njk
+title: Enable Binding
+---
+
# `enable`
diff --git a/packages/binding.core/docs/event-binding.md b/tko.io/src/docs/bindings/event-binding.md
similarity index 90%
rename from packages/binding.core/docs/event-binding.md
rename to tko.io/src/docs/bindings/event-binding.md
index 99634db65..efcd8a462 100644
--- a/packages/binding.core/docs/event-binding.md
+++ b/tko.io/src/docs/bindings/event-binding.md
@@ -1,3 +1,8 @@
+---
+layout: base.njk
+title: Event Binding
+---
+
# `event`
### Purpose
@@ -70,7 +75,7 @@ function MyViewModel() {
Two points to note about this example:
- * If you're inside a nested [binding context](binding-context.html), for example if you're inside a `foreach` or a `with` block, but your handler function
+ * If you're inside a nested [binding context](../../binding-context/binding-context/), for example if you're inside a `foreach` or a `with` block, but your handler function
is on the root viewmodel or some other parent context, you'll need to use a prefix such as `$parent` or `$root` to locate the
handler function.
* In your viewmodel, it's often useful to declare `self` (or some other variable) as an alias for `this`. Doing so avoids any problems
@@ -119,7 +124,7 @@ Alternatively, if you prefer to avoid the function literal in your view, you can
### Note 3: Allowing the default action
-By default, Knockout will prevent the event from taking any default action. For example if you use the `event` binding to capture the `keypress` event of an `input` tag, the browser will only call your handler function and will *not* add the value of the key to the `input` element's value. A more common example is using [the click binding](click-binding.html), which internally uses this binding, where your handler function will be called, but the browser will *not* navigate to the link's `href`. This is a useful default because when you use the `click` binding, it's normally because you're using the link as part of a UI that manipulates your view model, not as a regular hyperlink to another web page.
+By default, Knockout will prevent the event from taking any default action. For example if you use the `event` binding to capture the `keypress` event of an `input` tag, the browser will only call your handler function and will *not* add the value of the key to the `input` element's value. A more common example is using [the click binding](../click-binding/), which internally uses this binding, where your handler function will be called, but the browser will *not* navigate to the link's `href`. This is a useful default because when you use the `click` binding, it's normally because you're using the link as part of a UI that manipulates your view model, not as a regular hyperlink to another web page.
However, if you *do* want to let the default action proceed, just return `true` from your `event` handler function.
diff --git a/packages/binding.template/docs/foreach-binding.md b/tko.io/src/docs/bindings/foreach-binding.md
similarity index 91%
rename from packages/binding.template/docs/foreach-binding.md
rename to tko.io/src/docs/bindings/foreach-binding.md
index db773c014..bb8248fcf 100644
--- a/packages/binding.template/docs/foreach-binding.md
+++ b/tko.io/src/docs/bindings/foreach-binding.md
@@ -1,10 +1,15 @@
+---
+layout: base.njk
+title: Foreach Binding
+---
+
# `foreach` Binding
### Purpose
The `foreach` binding duplicates a section of markup for each entry in an array, and binds each copy of that markup to the corresponding array item. This is especially useful for rendering lists or tables.
-Assuming your array is an [observable array](observableArrays.html), whenever you later add, remove, or re-order array entries, the binding will efficiently update the UI to match - inserting or removing more copies of the markup, or re-ordering existing DOM elements, without affecting any other DOM elements. This is far faster than regenerating the entire `foreach` output after each array change.
+Assuming your array is an [observable array](../../observables/observableArrays/), whenever you later add, remove, or re-order array entries, the binding will efficiently update the UI to match - inserting or removing more copies of the markup, or re-ordering existing DOM elements, without affecting any other DOM elements. This is far faster than regenerating the entire `foreach` output after each array change.
Of course, you can arbitrarily nest any number of `foreach` bindings along with other control-flow bindings such as `if` and `with`.
@@ -43,7 +48,7 @@ The following example shows that, if your array is observable, then the UI will
As shown in the above examples, bindings within the `foreach` block can refer to properties on the array entries. For example, [Example 1](#example_1_iterating_over_an_array) referenced the `firstName` and `lastName` properties on each array entry.
-But what if you want to refer to the array entry itself (not just one of its properties)? In that case, you can use the [special context property](binding-context.html) `$data`. Within a `foreach` block, it means "the current item". For example,
+But what if you want to refer to the array entry itself (not just one of its properties)? In that case, you can use the [special context property](../../binding-context/binding-context/) `$data`. Within a `foreach` block, it means "the current item". For example,
@@ -71,11 +76,11 @@ Similarly, you can use `$parent` to refer to data from outside the `foreach`, e.
```
-For more information about `$index` and other context properties such as `$parent`, see documentation for [binding context properties](binding-context.html).
+For more information about `$index` and other context properties such as `$parent`, see documentation for [binding context properties](../../binding-context/binding-context/).
### Note 3: Using "as" to give an alias to "foreach" items
-As described in Note 1, you can refer to each array entry using the `$data` [context variable](binding-context.html). In some cases though, it may be useful to give the current item a more descriptive name using the `as` option like:
+As described in Note 1, you can refer to each array entry using the `$data` [context variable](../../binding-context/binding-context/). In some cases though, it may be useful to give the current item a more descriptive name using the `as` option like:
```html