├── LICENSE.md ├── README.md ├── css └── main.css ├── data ├── CNTK.json ├── atom.json └── meta.json ├── images ├── CNTK.png ├── atom.png ├── d3.png ├── favicon.png ├── freecodecamp.png ├── hex-loader.gif ├── linux.png ├── linux_zoomed.png ├── logo.png └── zerowing.png ├── index.html └── js ├── github.js └── jquery.tipsy.js /LICENSE.md: -------------------------------------------------------------------------------- 1 | The GNU General Public License, Version 2, June 1991 (GPLv2) 2 | ============================================================ 3 | 4 | > Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | > 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 6 | 7 | Everyone is permitted to copy and distribute verbatim copies of this license 8 | document, but changing it is not allowed. 9 | 10 | 11 | Preamble 12 | -------- 13 | 14 | The licenses for most software are designed to take away your freedom to share 15 | and change it. By contrast, the GNU General Public License is intended to 16 | guarantee your freedom to share and change free software--to make sure the 17 | software is free for all its users. This General Public License applies to most 18 | of the Free Software Foundation's software and to any other program whose 19 | authors commit to using it. (Some other Free Software Foundation software is 20 | covered by the GNU Library General Public License instead.) You can apply it to 21 | your programs, too. 22 | 23 | When we speak of free software, we are referring to freedom, not price. Our 24 | General Public Licenses are designed to make sure that you have the freedom to 25 | distribute copies of free software (and charge for this service if you wish), 26 | that you receive source code or can get it if you want it, that you can change 27 | the software or use pieces of it in new free programs; and that you know you can 28 | do these things. 29 | 30 | To protect your rights, we need to make restrictions that forbid anyone to deny 31 | you these rights or to ask you to surrender the rights. These restrictions 32 | translate to certain responsibilities for you if you distribute copies of the 33 | software, or if you modify it. 34 | 35 | For example, if you distribute copies of such a program, whether gratis or for a 36 | fee, you must give the recipients all the rights that you have. You must make 37 | sure that they, too, receive or can get the source code. And you must show them 38 | these terms so they know their rights. 39 | 40 | We protect your rights with two steps: (1) copyright the software, and (2) offer 41 | you this license which gives you legal permission to copy, distribute and/or 42 | modify the software. 43 | 44 | Also, for each author's protection and ours, we want to make certain that 45 | everyone understands that there is no warranty for this free software. If the 46 | software is modified by someone else and passed on, we want its recipients to 47 | know that what they have is not the original, so that any problems introduced by 48 | others will not reflect on the original authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software patents. We wish 51 | to avoid the danger that redistributors of a free program will individually 52 | obtain patent licenses, in effect making the program proprietary. To prevent 53 | this, we have made it clear that any patent must be licensed for everyone's free 54 | use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and modification 57 | follow. 58 | 59 | 60 | Terms And Conditions For Copying, Distribution And Modification 61 | --------------------------------------------------------------- 62 | 63 | **0.** This License applies to any program or other work which contains a notice 64 | placed by the copyright holder saying it may be distributed under the terms of 65 | this General Public License. The "Program", below, refers to any such program or 66 | work, and a "work based on the Program" means either the Program or any 67 | derivative work under copyright law: that is to say, a work containing the 68 | Program or a portion of it, either verbatim or with modifications and/or 69 | translated into another language. (Hereinafter, translation is included without 70 | limitation in the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not covered by 73 | this License; they are outside its scope. The act of running the Program is not 74 | restricted, and the output from the Program is covered only if its contents 75 | constitute a work based on the Program (independent of having been made by 76 | running the Program). Whether that is true depends on what the Program does. 77 | 78 | **1.** You may copy and distribute verbatim copies of the Program's source code 79 | as you receive it, in any medium, provided that you conspicuously and 80 | appropriately publish on each copy an appropriate copyright notice and 81 | disclaimer of warranty; keep intact all the notices that refer to this License 82 | and to the absence of any warranty; and give any other recipients of the Program 83 | a copy of this License along with the Program. 84 | 85 | You may charge a fee for the physical act of transferring a copy, and you may at 86 | your option offer warranty protection in exchange for a fee. 87 | 88 | **2.** You may modify your copy or copies of the Program or any portion of it, 89 | thus forming a work based on the Program, and copy and distribute such 90 | modifications or work under the terms of Section 1 above, provided that you also 91 | meet all of these conditions: 92 | 93 | * **a)** You must cause the modified files to carry prominent notices stating 94 | that you changed the files and the date of any change. 95 | 96 | * **b)** You must cause any work that you distribute or publish, that in whole 97 | or in part contains or is derived from the Program or any part thereof, to 98 | be licensed as a whole at no charge to all third parties under the terms of 99 | this License. 100 | 101 | * **c)** If the modified program normally reads commands interactively when 102 | run, you must cause it, when started running for such interactive use in the 103 | most ordinary way, to print or display an announcement including an 104 | appropriate copyright notice and a notice that there is no warranty (or 105 | else, saying that you provide a warranty) and that users may redistribute 106 | the program under these conditions, and telling the user how to view a copy 107 | of this License. (Exception: if the Program itself is interactive but does 108 | not normally print such an announcement, your work based on the Program is 109 | not required to print an announcement.) 110 | 111 | These requirements apply to the modified work as a whole. If identifiable 112 | sections of that work are not derived from the Program, and can be reasonably 113 | considered independent and separate works in themselves, then this License, and 114 | its terms, do not apply to those sections when you distribute them as separate 115 | works. But when you distribute the same sections as part of a whole which is a 116 | work based on the Program, the distribution of the whole must be on the terms of 117 | this License, whose permissions for other licensees extend to the entire whole, 118 | and thus to each and every part regardless of who wrote it. 119 | 120 | Thus, it is not the intent of this section to claim rights or contest your 121 | rights to work written entirely by you; rather, the intent is to exercise the 122 | right to control the distribution of derivative or collective works based on the 123 | Program. 124 | 125 | In addition, mere aggregation of another work not based on the Program with the 126 | Program (or with a work based on the Program) on a volume of a storage or 127 | distribution medium does not bring the other work under the scope of this 128 | License. 129 | 130 | **3.** You may copy and distribute the Program (or a work based on it, under 131 | Section 2) in object code or executable form under the terms of Sections 1 and 2 132 | above provided that you also do one of the following: 133 | 134 | * **a)** Accompany it with the complete corresponding machine-readable source 135 | code, which must be distributed under the terms of Sections 1 and 2 above on 136 | a medium customarily used for software interchange; or, 137 | 138 | * **b)** Accompany it with a written offer, valid for at least three years, to 139 | give any third party, for a charge no more than your cost of physically 140 | performing source distribution, a complete machine-readable copy of the 141 | corresponding source code, to be distributed under the terms of Sections 1 142 | and 2 above on a medium customarily used for software interchange; or, 143 | 144 | * **c)** Accompany it with the information you received as to the offer to 145 | distribute corresponding source code. (This alternative is allowed only for 146 | noncommercial distribution and only if you received the program in object 147 | code or executable form with such an offer, in accord with Subsection b 148 | above.) 149 | 150 | The source code for a work means the preferred form of the work for making 151 | modifications to it. For an executable work, complete source code means all the 152 | source code for all modules it contains, plus any associated interface 153 | definition files, plus the scripts used to control compilation and installation 154 | of the executable. However, as a special exception, the source code distributed 155 | need not include anything that is normally distributed (in either source or 156 | binary form) with the major components (compiler, kernel, and so on) of the 157 | operating system on which the executable runs, unless that component itself 158 | accompanies the executable. 159 | 160 | If distribution of executable or object code is made by offering access to copy 161 | from a designated place, then offering equivalent access to copy the source code 162 | from the same place counts as distribution of the source code, even though third 163 | parties are not compelled to copy the source along with the object code. 164 | 165 | **4.** You may not copy, modify, sublicense, or distribute the Program except as 166 | expressly provided under this License. Any attempt otherwise to copy, modify, 167 | sublicense or distribute the Program is void, and will automatically terminate 168 | your rights under this License. However, parties who have received copies, or 169 | rights, from you under this License will not have their licenses terminated so 170 | long as such parties remain in full compliance. 171 | 172 | **5.** You are not required to accept this License, since you have not signed 173 | it. However, nothing else grants you permission to modify or distribute the 174 | Program or its derivative works. These actions are prohibited by law if you do 175 | not accept this License. Therefore, by modifying or distributing the Program (or 176 | any work based on the Program), you indicate your acceptance of this License to 177 | do so, and all its terms and conditions for copying, distributing or modifying 178 | the Program or works based on it. 179 | 180 | **6.** Each time you redistribute the Program (or any work based on the 181 | Program), the recipient automatically receives a license from the original 182 | licensor to copy, distribute or modify the Program subject to these terms and 183 | conditions. You may not impose any further restrictions on the recipients' 184 | exercise of the rights granted herein. You are not responsible for enforcing 185 | compliance by third parties to this License. 186 | 187 | **7.** If, as a consequence of a court judgment or allegation of patent 188 | infringement or for any other reason (not limited to patent issues), conditions 189 | are imposed on you (whether by court order, agreement or otherwise) that 190 | contradict the conditions of this License, they do not excuse you from the 191 | conditions of this License. If you cannot distribute so as to satisfy 192 | simultaneously your obligations under this License and any other pertinent 193 | obligations, then as a consequence you may not distribute the Program at all. 194 | For example, if a patent license would not permit royalty-free redistribution of 195 | the Program by all those who receive copies directly or indirectly through you, 196 | then the only way you could satisfy both it and this License would be to refrain 197 | entirely from distribution of the Program. 198 | 199 | If any portion of this section is held invalid or unenforceable under any 200 | particular circumstance, the balance of the section is intended to apply and the 201 | section as a whole is intended to apply in other circumstances. 202 | 203 | It is not the purpose of this section to induce you to infringe any patents or 204 | other property right claims or to contest validity of any such claims; this 205 | section has the sole purpose of protecting the integrity of the free software 206 | distribution system, which is implemented by public license practices. Many 207 | people have made generous contributions to the wide range of software 208 | distributed through that system in reliance on consistent application of that 209 | system; it is up to the author/donor to decide if he or she is willing to 210 | distribute software through any other system and a licensee cannot impose that 211 | choice. 212 | 213 | This section is intended to make thoroughly clear what is believed to be a 214 | consequence of the rest of this License. 215 | 216 | **8.** If the distribution and/or use of the Program is restricted in certain 217 | countries either by patents or by copyrighted interfaces, the original copyright 218 | holder who places the Program under this License may add an explicit 219 | geographical distribution limitation excluding those countries, so that 220 | distribution is permitted only in or among countries not thus excluded. In such 221 | case, this License incorporates the limitation as if written in the body of this 222 | License. 223 | 224 | **9.** The Free Software Foundation may publish revised and/or new versions of 225 | the General Public License from time to time. Such new versions will be similar 226 | in spirit to the present version, but may differ in detail to address new 227 | problems or concerns. 228 | 229 | Each version is given a distinguishing version number. If the Program specifies 230 | a version number of this License which applies to it and "any later version", 231 | you have the option of following the terms and conditions either of that version 232 | or of any later version published by the Free Software Foundation. If the 233 | Program does not specify a version number of this License, you may choose any 234 | version ever published by the Free Software Foundation. 235 | 236 | **10.** If you wish to incorporate parts of the Program into other free programs 237 | whose distribution conditions are different, write to the author to ask for 238 | permission. For software which is copyrighted by the Free Software Foundation, 239 | write to the Free Software Foundation; we sometimes make exceptions for this. 240 | Our decision will be guided by the two goals of preserving the free status of 241 | all derivatives of our free software and of promoting the sharing and reuse of 242 | software generally. 243 | 244 | 245 | No Warranty 246 | ----------- 247 | 248 | **11.** BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR 249 | THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE 250 | STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM 251 | "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, 252 | BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 253 | PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 254 | PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 255 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 256 | 257 | **12.** IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 258 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE 259 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 260 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR 261 | INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA 262 | BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 263 | FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER 264 | OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GitHub Visualization Tool 2 | ## What it does 3 | Provides an at-a-glance overview of the repository structure. Finer details can be explored via zooming and tooltips. It makes exploring large and complex projects a breeze. 4 | 5 | Files are displayed as a directed graph, color coded based on file types, and sized accordingly to length of file. 6 | 7 | ## Installation 8 | Replace your own GitHub personal token key into `/js/github.js`. Serve static `index.html` on webserver of your choice. 9 | 10 | ## License 11 | [GPL v2](LICENSE.md) 12 | 13 | ## Others 14 | Created at StacsHack 2016 15 | Winner of Bloomberg's Favourite Project. 16 | -------------------------------------------------------------------------------- /css/main.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | margin: 0; 4 | padding: 0; 5 | overflow: hidden; 6 | font-family: 'Raleway', 'Helvetica', sans-serif; 7 | font-weight: 300; 8 | } 9 | 10 | #header { 11 | height: 100vh; 12 | position: relative; 13 | text-align: center 14 | } 15 | 16 | header { 17 | position: fixed; 18 | height: auto; 19 | top: 50%; 20 | transform: translateY(-50%); 21 | left: 0px; 22 | width: 100%; 23 | opacity: 0.8; 24 | } 25 | 26 | header h1 { 27 | font-size: 3em; 28 | line-height: 1.25em; 29 | margin: 0; 30 | } 31 | 32 | img#logo { 33 | opacity: 0.7; 34 | /*filter: grayscale(100%); 35 | -webkit-filter: grayscale(100%);*/ 36 | } 37 | 38 | header p { 39 | font-weight: 700; 40 | font-size: 15pt; 41 | margin: 1.5em 0 0 0; 42 | } 43 | 44 | footer { 45 | position: fixed; 46 | bottom: 1.5em; 47 | width: 100%; 48 | text-align: center; 49 | transition: bottom 2s; 50 | } 51 | 52 | footer.shift { 53 | bottom: 0.1em; 54 | } 55 | 56 | footer a { 57 | color: #777; 58 | text-decoration: none; 59 | text-shadow: #fff 0px 0px 3px, #fff 0px 0px 3px, #fff 0px 0px 3px, 60 | #fff 0px 0px 3px, #fff 0px 0px 3px, #fff 0px 0px 3px; 61 | font-weight: 100; 62 | font-size: 0.8em; 63 | font-variant: small-caps; 64 | } 65 | 66 | p.filename { 67 | margin: 1px; 68 | } 69 | 70 | #prompt { 71 | position: absolute; 72 | top: 0; 73 | margin: 10px; 74 | transition: opacity 0.2s; 75 | } 76 | 77 | #prompt.fade { 78 | opacity: 0.5; 79 | } 80 | 81 | #prompt.fade:hover { 82 | opacity: 1; 83 | } 84 | 85 | form.start { 86 | -webkit-animation: glow 1.5s ease-in-out infinite alternate; 87 | -moz-animation: glow 1.5s ease-in-out infinite alternate; 88 | animation: glow 1.5s ease-in-out infinite alternate; 89 | } 90 | 91 | @-webkit-keyframes glow { 92 | from { 93 | box-shadow: 0 0 10px #fff, 0 0 10px #B6FF00, 0 0 15px #B6FF00; 94 | } 95 | to { 96 | box-shadow: 0 0 5px #fff, 0 0 1px #B6FF00, 0 0 5px #B6FF00; 97 | } 98 | } 99 | 100 | b { 101 | font-weight: 900; 102 | } 103 | 104 | .outline { 105 | fill: none; 106 | stroke: #888888; 107 | stroke-width: 1px; 108 | } 109 | 110 | .highlight { 111 | stroke: red; 112 | stroke-weight: 4px; 113 | stroke-opacity: 1.0; 114 | } 115 | 116 | .node { 117 | cursor: pointer; 118 | stroke: #3182bd; 119 | stroke-width: 1.5px; 120 | } 121 | 122 | .link { 123 | fill: none; 124 | stroke: #9ecae1; 125 | stroke-width: 1.5px; 126 | } 127 | 128 | #tooltip { 129 | font-size: 10pt; 130 | font-weight: 900; 131 | z-index: : 999; 132 | fill: #000000; 133 | stroke: #ffffff; 134 | stroke-width: 0.25px; 135 | } 136 | 137 | .tipsy-inner { 138 | padding: 1px; 139 | } 140 | 141 | .tipsy { 142 | font-size: 14px; 143 | pointer-events: none; 144 | } 145 | 146 | .flat-button { 147 | position: relative; 148 | vertical-align: top; 149 | color: white; 150 | text-align: center; 151 | text-shadow: 0 1px 2px rgba(0, 0, 0, 0.25); 152 | background: #27ae60; 153 | padding-top: 3px; 154 | border: 0; 155 | border-bottom: 2px solid #219d55; 156 | cursor: pointer; 157 | -webkit-box-shadow: inset 0 -2px #219d55; 158 | box-shadow: inset 0 -2px #219d55; 159 | } 160 | .flat-button:active { 161 | top: 1px; 162 | outline: none; 163 | -webkit-box-shadow: none; 164 | box-shadow: none; 165 | } 166 | 167 | /*! 168 | * "Fork me on GitHub" CSS ribbon v0.2.0 | MIT License 169 | * https://github.com/simonwhitaker/github-fork-ribbon-css 170 | */ 171 | 172 | .github-fork-ribbon { 173 | width: 12.1em; 174 | height: 12.1em; 175 | position: absolute; 176 | overflow: hidden; 177 | top: 0; 178 | right: 0; 179 | z-index: 9999; 180 | pointer-events: none; 181 | font-size: 13px; 182 | text-decoration: none; 183 | text-indent: -999999px; 184 | } 185 | 186 | .github-fork-ribbon.fixed { 187 | position: fixed; 188 | } 189 | 190 | .github-fork-ribbon:before, 191 | .github-fork-ribbon:after { 192 | /* The right and left classes determine the side we attach our banner to */ 193 | position: absolute; 194 | display: block; 195 | width: 15.38em; 196 | height: 1.54em; 197 | top: 3.23em; 198 | right: -3.23em; 199 | -webkit-transform: rotate(45deg); 200 | -moz-transform: rotate(45deg); 201 | -ms-transform: rotate(45deg); 202 | -o-transform: rotate(45deg); 203 | transform: rotate(45deg); 204 | } 205 | 206 | .github-fork-ribbon:before { 207 | content: ""; 208 | /* Add a bit of padding to give some substance outside the "stitching" */ 209 | padding: .38em 0; 210 | /* Set the base colour */ 211 | background-color: #333; 212 | /* Set a gradient: transparent black at the top to almost-transparent black at the bottom */ 213 | background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(0, 0, 0, 0)), to(rgba(0, 0, 0, 0.15))); 214 | background-image: -webkit-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15)); 215 | background-image: -moz-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15)); 216 | background-image: -ms-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15)); 217 | background-image: -o-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15)); 218 | background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15)); 219 | /* Add a drop shadow */ 220 | -webkit-box-shadow: 0 .15em .23em 0 rgba(0, 0, 0, 0.5); 221 | -moz-box-shadow: 0 .15em .23em 0 rgba(0, 0, 0, 0.5); 222 | box-shadow: 0 .15em .23em 0 rgba(0, 0, 0, 0.5); 223 | pointer-events: auto; 224 | } 225 | 226 | .github-fork-ribbon:after { 227 | /* Set the text from the title attribute */ 228 | content: attr(title); 229 | /* Set the text properties */ 230 | color: #fff; 231 | font: 700 1em "Helvetica Neue", Helvetica, Arial, sans-serif; 232 | line-height: 1.54em; 233 | text-decoration: none; 234 | text-shadow: 0 -.08em rgba(0, 0, 0, 0.5); 235 | text-align: center; 236 | text-indent: 0; 237 | /* Set the layout properties */ 238 | padding: .15em 0; 239 | margin: .15em 0; 240 | /* Add "stitching" effect */ 241 | border-width: .08em 0; 242 | border-style: dotted; 243 | border-color: #fff; 244 | border-color: rgba(255, 255, 255, 0.7); 245 | } 246 | 247 | .github-fork-ribbon.left-top, 248 | .github-fork-ribbon.left-bottom { 249 | right: auto; 250 | left: 0; 251 | } 252 | 253 | .github-fork-ribbon.left-bottom, 254 | .github-fork-ribbon.right-bottom { 255 | top: auto; 256 | bottom: 0; 257 | } 258 | 259 | .github-fork-ribbon.left-top:before, 260 | .github-fork-ribbon.left-top:after, 261 | .github-fork-ribbon.left-bottom:before, 262 | .github-fork-ribbon.left-bottom:after { 263 | right: auto; 264 | left: -3.23em; 265 | } 266 | 267 | .github-fork-ribbon.left-bottom:before, 268 | .github-fork-ribbon.left-bottom:after, 269 | .github-fork-ribbon.right-bottom:before, 270 | .github-fork-ribbon.right-bottom:after { 271 | top: auto; 272 | bottom: 3.23em; 273 | } 274 | 275 | .github-fork-ribbon.left-top:before, 276 | .github-fork-ribbon.left-top:after, 277 | .github-fork-ribbon.right-bottom:before, 278 | .github-fork-ribbon.right-bottom:after { 279 | -webkit-transform: rotate(-45deg); 280 | -moz-transform: rotate(-45deg); 281 | -ms-transform: rotate(-45deg); 282 | -o-transform: rotate(-45deg); 283 | transform: rotate(-45deg); 284 | } -------------------------------------------------------------------------------- /data/meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "sha": "5f392e860a4cb5a4ea8252e2e956f231243b70e1", 3 | "url": "https://api.github.com/repos/veniversum/language-whitespace/git/trees/5f392e860a4cb5a4ea8252e2e956f231243b70e1", 4 | "tree": [ 5 | { 6 | "path": ".gitignore", 7 | "mode": "100644", 8 | "type": "blob", 9 | "sha": "ade14b9196fcad03cd0177c25ec1c31000ecf86a", 10 | "size": 37, 11 | "url": "https://api.github.com/repos/veniversum/language-whitespace/git/blobs/ade14b9196fcad03cd0177c25ec1c31000ecf86a" 12 | }, 13 | { 14 | "path": "LICENSE.md", 15 | "mode": "100644", 16 | "type": "blob", 17 | "sha": "97bcecb3fff089879a3e57bc12a1a606cd5b041e", 18 | "size": 1054, 19 | "url": "https://api.github.com/repos/veniversum/language-whitespace/git/blobs/97bcecb3fff089879a3e57bc12a1a606cd5b041e" 20 | }, 21 | { 22 | "path": "README.md", 23 | "mode": "100644", 24 | "type": "blob", 25 | "sha": "0bed7ab0692d637ef59849a67f436a582aca05e5", 26 | "size": 124, 27 | "url": "https://api.github.com/repos/veniversum/language-whitespace/git/blobs/0bed7ab0692d637ef59849a67f436a582aca05e5" 28 | }, 29 | { 30 | "path": "grammars", 31 | "mode": "040000", 32 | "type": "tree", 33 | "sha": "b67dc9262bb3450faaa823091d918b62e8f173f3", 34 | "url": "https://api.github.com/repos/veniversum/language-whitespace/git/trees/b67dc9262bb3450faaa823091d918b62e8f173f3" 35 | }, 36 | { 37 | "path": "grammars/whitespace.cson", 38 | "mode": "100644", 39 | "type": "blob", 40 | "sha": "e0504a95b57d2ad054907ee448bd8840fedb1b19", 41 | "size": 346, 42 | "url": "https://api.github.com/repos/veniversum/language-whitespace/git/blobs/e0504a95b57d2ad054907ee448bd8840fedb1b19" 43 | }, 44 | { 45 | "path": "package.json", 46 | "mode": "100644", 47 | "type": "blob", 48 | "sha": "fc413aee7a97759869266adf669ff5232100c480", 49 | "size": 304, 50 | "url": "https://api.github.com/repos/veniversum/language-whitespace/git/blobs/fc413aee7a97759869266adf669ff5232100c480" 51 | }, 52 | { 53 | "path": "settings", 54 | "mode": "040000", 55 | "type": "tree", 56 | "sha": "b7835cbbd524fb31a47dd7577a213f7c5be4c145", 57 | "url": "https://api.github.com/repos/veniversum/language-whitespace/git/trees/b7835cbbd524fb31a47dd7577a213f7c5be4c145" 58 | }, 59 | { 60 | "path": "settings/language-whitespace.cson", 61 | "mode": "100644", 62 | "type": "blob", 63 | "sha": "01504acb4217138bef93c4394b17a19e5af4adf1", 64 | "size": 362, 65 | "url": "https://api.github.com/repos/veniversum/language-whitespace/git/blobs/01504acb4217138bef93c4394b17a19e5af4adf1" 66 | }, 67 | { 68 | "path": "styles", 69 | "mode": "040000", 70 | "type": "tree", 71 | "sha": "0464eae232559743154868bf698e3faad2256fc3", 72 | "url": "https://api.github.com/repos/veniversum/language-whitespace/git/trees/0464eae232559743154868bf698e3faad2256fc3" 73 | }, 74 | { 75 | "path": "styles/language-whitespace.less", 76 | "mode": "100644", 77 | "type": "blob", 78 | "sha": "a61ab0d15a85818cb1eaf6dde127159fba5ab118", 79 | "size": 610, 80 | "url": "https://api.github.com/repos/veniversum/language-whitespace/git/blobs/a61ab0d15a85818cb1eaf6dde127159fba5ab118" 81 | } 82 | ], 83 | "truncated": false 84 | } -------------------------------------------------------------------------------- /images/CNTK.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veniversum/git-visualizer/81c57a36f8b213ce5c092aa3e694b330b9454e87/images/CNTK.png -------------------------------------------------------------------------------- /images/atom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veniversum/git-visualizer/81c57a36f8b213ce5c092aa3e694b330b9454e87/images/atom.png -------------------------------------------------------------------------------- /images/d3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veniversum/git-visualizer/81c57a36f8b213ce5c092aa3e694b330b9454e87/images/d3.png -------------------------------------------------------------------------------- /images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veniversum/git-visualizer/81c57a36f8b213ce5c092aa3e694b330b9454e87/images/favicon.png -------------------------------------------------------------------------------- /images/freecodecamp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veniversum/git-visualizer/81c57a36f8b213ce5c092aa3e694b330b9454e87/images/freecodecamp.png -------------------------------------------------------------------------------- /images/hex-loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veniversum/git-visualizer/81c57a36f8b213ce5c092aa3e694b330b9454e87/images/hex-loader.gif -------------------------------------------------------------------------------- /images/linux.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veniversum/git-visualizer/81c57a36f8b213ce5c092aa3e694b330b9454e87/images/linux.png -------------------------------------------------------------------------------- /images/linux_zoomed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veniversum/git-visualizer/81c57a36f8b213ce5c092aa3e694b330b9454e87/images/linux_zoomed.png -------------------------------------------------------------------------------- /images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veniversum/git-visualizer/81c57a36f8b213ce5c092aa3e694b330b9454e87/images/logo.png -------------------------------------------------------------------------------- /images/zerowing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veniversum/git-visualizer/81c57a36f8b213ce5c092aa3e694b330b9454e87/images/zerowing.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | GitHub Visualizer 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 28 |
29 |
30 | 31 | 32 | 33 |
34 |
35 | Fork me on GitHub 36 | 37 | 38 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /js/github.js: -------------------------------------------------------------------------------- 1 | var access_token = ['f1aff3072a385154ffe18aed3b893aa46ce8577c', '2e71ec1017dda2220ccba0f6922ecefd9ea44ac7', 'bfaeb43c92d3e2f534745a6df977f68b64dc7c55', '7731a6f681df209067f597a04822c7abf0425c9a', 'b59d67cf0ba63a89b87ebad75d4ec1e08d9f2e43', 'daf69c16bec62f7c2faf5e5a7f445a4823f2f531']; 2 | 3 | var width = window.innerWidth; 4 | var height = window.innerHeight; 5 | var margin = 20; 6 | var pad = margin / 2; 7 | var root; 8 | var treeData = []; 9 | var highlighted = []; 10 | var exclude; 11 | 12 | function checkQuery() { 13 | var owner = fromQuery('owner'); 14 | var repo = fromQuery('repo'); 15 | var branch = fromQuery('branch'); 16 | exclude = fromQuery('exclude'); 17 | if (exclude){ 18 | exclude = exclude.split(','); 19 | } 20 | 21 | if (owner && repo) { 22 | $('input#owner').val(owner); 23 | $('input#repo').val(repo); 24 | getRepo(branch); 25 | } 26 | } 27 | 28 | function fromQuery(value) { 29 | var qs = window.location.search; 30 | var re = new RegExp(value + '=([^&]*)'); 31 | var match = re.exec(qs); 32 | if (match) { 33 | return match[1]; 34 | } else { 35 | return null; 36 | } 37 | } 38 | 39 | function getRepo(branch) { 40 | var owner = $('input#owner').val().trim(), 41 | repo = $('input#repo').val().trim(), 42 | queryString = 'owner=' + owner + '&repo=' + repo + (branch ? '&branch=' + branch : '') + (exclude ? '&exclude=' + exclude.join() : ''); 43 | window.history.pushState({}, '', window.location.protocol + "//" + window.location.host + window.location.pathname + '?' + queryString); 44 | $('img#logo').attr('src', 'images/hex-loader.gif'); 45 | 46 | $.ajax({ 47 | url: "https://api.github.com/repos/" + owner + "/" + repo + (branch ? "/branches/" + branch : "/commits"), 48 | data: { 49 | access_token: access_token[Math.floor(Math.random() * access_token.length)] 50 | }, 51 | success: function (data) { 52 | $('header').show(); 53 | $('form.start').removeClass('start'); 54 | $('header p').remove(); 55 | $('footer').addClass('shift'); 56 | $('#prompt').addClass('fade'); 57 | var sha = branch ? data.commit.sha : data[0].sha, 58 | url = "https://api.github.com/repos/" + owner + "/" + repo + "/git/trees/" + sha + "?recursive=1&access_token=" + access_token[Math.floor(Math.random() * access_token.length)]; 59 | init(url); 60 | }, 61 | error: function (request, status, error) { 62 | $('img#logo').attr('src', 'images/logo.png'); 63 | alert('Error loading repo: ' + request.statusText); 64 | } 65 | }); 66 | } 67 | 68 | var color = d3.scale.category20b(); 69 | 70 | var force = d3.layout.force() 71 | .gravity(0.2) 72 | .charge(-220) 73 | .size([width, height]) 74 | .linkStrength(0.9) 75 | .linkDistance(function (d) { 76 | return d.source.type === 'tree' && d.target.type === 'tree' ? 1 : 10; 77 | }) 78 | .on("tick", tick); 79 | 80 | var outer = d3.select("div#graph").append("svg") 81 | .call(d3.behavior.zoom().on("zoom", rescale)) 82 | .on("dblclick.zoom", null) 83 | .attr("width", width) 84 | .attr("height", height) 85 | .attr("pointer-events", "all"); 86 | 87 | var svg = outer.append('svg:g'); 88 | 89 | //Rescale function, called on zoom event 90 | function rescale() { 91 | trans = d3.event.translate; 92 | scale = d3.event.scale; 93 | svg.attr("transform", 94 | "translate(" + trans + ")" + " scale(" + scale + ")"); 95 | } 96 | 97 | 98 | var link = svg.selectAll(".link"), 99 | node = svg.selectAll(".node"); 100 | 101 | function init(url) { 102 | treeData = []; 103 | root = null; 104 | d3.json(url, function (error, json) { 105 | if (error) { 106 | return console.warn(error); 107 | } 108 | $('header').hide(); 109 | json.tree.forEach(function (o) { 110 | var indexSlash = o.path.lastIndexOf('/'); 111 | if (indexSlash < 0) { 112 | o.parent = 'root'; 113 | o.filename = o.path; 114 | o.name = o.path; 115 | } else { 116 | o.parent = o.path.substr(0, indexSlash); 117 | o.filename = o.path.substr(indexSlash + 1); 118 | o.name = o.path; 119 | } 120 | }); 121 | json.tree.unshift({ 122 | "path": "root", 123 | "type": "tree", 124 | "size": 0, 125 | "parent": null, 126 | "filename": "root", 127 | "name": "root" 128 | }); 129 | var dataMap = json.tree.reduce(function (map, node) { 130 | map[node.path] = node; 131 | return map; 132 | }, {}); 133 | json.tree.forEach(function (node) { 134 | // add to parent 135 | var parent = dataMap[node.parent]; 136 | if (parent) { 137 | if (exclude && exclude.indexOf(parent.path) > -1){ 138 | (parent._children || (parent._children = [])).push(node);} 139 | // create child array if it doesn't exist 140 | else 141 | (parent.children || (parent.children = [])).push(node); 142 | } else { 143 | // parent is null or missing 144 | treeData.push(node); 145 | } 146 | }); 147 | root = treeData[0]; 148 | update(); 149 | exclude = null; 150 | }); 151 | } 152 | 153 | function update() { 154 | var nodes = flatten(root), 155 | links = d3.layout.tree().links(nodes); 156 | 157 | // Restart the force layout. 158 | force 159 | .nodes(nodes) 160 | .links(links) 161 | .start(); 162 | 163 | // Update the links… 164 | link = link.data(links, function (d) { 165 | return d.target.id; 166 | }); 167 | 168 | // Exit any old links. 169 | link.exit().remove(); 170 | 171 | // Enter any new links. 172 | link.enter().insert("line", ".node") 173 | .attr("class", "link") 174 | .attr("x1", function (d) { 175 | return d.source.x; 176 | }) 177 | .attr("y1", function (d) { 178 | return d.source.y; 179 | }) 180 | .attr("x2", function (d) { 181 | return d.target.x; 182 | }) 183 | .attr("y2", function (d) { 184 | return d.target.y; 185 | }); 186 | 187 | // Update the nodes… 188 | node = node.data(nodes, function (d) { 189 | return d.id; 190 | }).style("fill", function (d) { 191 | return d.name === "root" ? '#f00' : d.type === "tree" ? "#ccc" : color(d.filename.lastIndexOf('.') >= 0 ? d.filename.substring(d.filename.lastIndexOf('.')) : "others"); 192 | }); 193 | 194 | // Exit any old nodes. 195 | node.exit().remove(); 196 | 197 | // Enter any new nodes. 198 | node.enter().append("circle") 199 | .attr("class", "node") 200 | .attr("cx", function (d) { 201 | return d.x; 202 | }) 203 | .attr("cy", function (d) { 204 | return d.y; 205 | }) 206 | .attr("r", function (d) { 207 | return d.name === "root" ? 10 : d.type === 'tree' ? 7 : Math.log(d.size + 1) || 3; 208 | }) 209 | .style("fill", function (d) { 210 | return d.name === "root" ? '#f00' : d.type === "tree" ? "#ccc" : color(d.filename.lastIndexOf('.') >= 0 ? d.filename.substring(d.filename.lastIndexOf('.')) : "others"); 211 | }) 212 | .on("click", click) 213 | .on('mouseover', function (d) { 214 | var ancestors = d.path; 215 | link.style('stroke-width', function (l) { 216 | if (ancestors && d.name == l.target.name || ancestors.indexOf(l.target.name + '/') >= 0) 217 | return 4; 218 | else 219 | return 2; 220 | }); 221 | link.style('stroke', function (l) { 222 | if (ancestors && d.name == l.target.name || ancestors.indexOf(l.target.name + '/') >= 0) 223 | return "#ff8080"; 224 | else 225 | return '#9ecae1'; 226 | }); 227 | node.style('stroke', function (n) { 228 | if (ancestors && ancestors.indexOf(n.name) >= 0 || n.name == "root") 229 | return "#ff8080"; 230 | else 231 | return '#3182bd'; 232 | }); 233 | link.each(function(l){ 234 | if (ancestors && d.name == l.target.name || ancestors.indexOf(l.target.name + '/') >= 0) { 235 | this.parentNode.appendChild(this); 236 | highlighted.push(this); 237 | } 238 | }); 239 | node.each(function(n){ 240 | if (ancestors && ancestors.indexOf(n.name) >= 0 || n.name == "root") 241 | this.parentNode.appendChild(this); 242 | }); 243 | }) 244 | .on('mouseout', function () { 245 | while (highlighted.length > 0) { 246 | var l = highlighted.pop(); 247 | var firstChild = l.parentNode.firstChild; 248 | if (firstChild) { 249 | l.parentNode.insertBefore(l, firstChild); 250 | } 251 | } 252 | link.style('stroke-width', 2); 253 | link.style('stroke', '#9ecae1'); 254 | node.style('stroke', '#3182bd'); 255 | }); 256 | 257 | //Update legend 258 | var legend = outer.selectAll(".legend") 259 | .data(color.domain()) 260 | .enter().append("g") 261 | .attr("class", "legend") 262 | .attr("transform", function (d, i) { 263 | return "translate(-10," + (i * 20 + 10) + ")"; 264 | }); 265 | 266 | legend.append("rect") 267 | .attr("x", width - 18) 268 | .attr("width", 18) 269 | .attr("height", 18) 270 | .style("fill", color); 271 | 272 | legend.append("text") 273 | .attr("x", width - 24) 274 | .attr("y", 9) 275 | .attr("dy", ".35em") 276 | .style("text-anchor", "end") 277 | .text(function (d) { 278 | return d; 279 | }); 280 | 281 | var styleTooltip = function (name) { 282 | return "

" + name + "

"; 283 | }; 284 | 285 | 286 | svg.selectAll("circle.node") 287 | .each(function (v) { 288 | $(this).tipsy({ 289 | gravity: "w", 290 | opacity: 1, 291 | html: true, 292 | title: function () { 293 | var d = this.__data__; 294 | return styleTooltip(d.filename); 295 | } 296 | }); 297 | }); 298 | } 299 | 300 | function tick() { 301 | link.attr("x1", function (d) { 302 | return d.source.x; 303 | }) 304 | .attr("y1", function (d) { 305 | return d.source.y; 306 | }) 307 | .attr("x2", function (d) { 308 | return d.target.x; 309 | }) 310 | .attr("y2", function (d) { 311 | return d.target.y; 312 | }); 313 | 314 | node.attr("cx", function (d) { 315 | return d.x; 316 | }) 317 | .attr("cy", function (d) { 318 | return d.y; 319 | }); 320 | } 321 | 322 | // Toggle children on click. 323 | function click(d) { 324 | //if (!d3.event.defaultPrevented) { 325 | if (d.children) { 326 | d._children = d.children; 327 | d.children = null; 328 | } else { 329 | d.children = d._children; 330 | d._children = null; 331 | } 332 | update(); 333 | // } 334 | } 335 | 336 | /*function listAncestors(d) { 337 | var ancestors = []; 338 | ancestors.push(d.name); 339 | var cur = d.parent; 340 | ancestors.push(cur); 341 | while (cur != null) { 342 | node.each(function (n) { 343 | if (n.name === cur) { 344 | cur = n.parent; 345 | ancestors.push(cur); 346 | } 347 | }); 348 | return ancestors; 349 | } 350 | }*/ 351 | 352 | // Returns a list of all nodes under the root. 353 | function flatten(root) { 354 | var nodes = [], 355 | i = 0; 356 | 357 | function recurse(node) { 358 | if (node.children) node.children.forEach(recurse); 359 | else if (node._children) node._children.forEach(recurse_exclude); 360 | if (!node.id) node.id = ++i; 361 | nodes.push(node); 362 | } 363 | 364 | function recurse_exclude(node) { 365 | if (node.children) node.children.forEach(recurse_exclude); 366 | else if (node._children) node._children.forEach(recurse_exclude); 367 | if (!node.id) node.id = ++i; 368 | } 369 | 370 | recurse(root); 371 | return nodes; 372 | } -------------------------------------------------------------------------------- /js/jquery.tipsy.js: -------------------------------------------------------------------------------- 1 | // tipsy, facebook style tooltips for jquery 2 | // version 1.0.0a 3 | // (c) 2008-2010 jason frame [jason@onehackoranother.com] 4 | // released under the MIT license 5 | 6 | (function($) { 7 | 8 | function maybeCall(thing, ctx) { 9 | return (typeof thing == 'function') ? (thing.call(ctx)) : thing; 10 | } 11 | 12 | function Tipsy(element, options) { 13 | this.$element = $(element); 14 | this.options = options; 15 | this.enabled = true; 16 | this.fixTitle(); 17 | } 18 | 19 | Tipsy.prototype = { 20 | show: function() { 21 | var title = this.getTitle(); 22 | if (title && this.enabled) { 23 | var $tip = this.tip(); 24 | 25 | $tip.find('.tipsy-inner')[this.options.html ? 'html' : 'text'](title); 26 | $tip[0].className = 'tipsy'; // reset classname in case of dynamic gravity 27 | $tip.remove().css({top: 0, left: 0, visibility: 'hidden', display: 'block'}).prependTo(document.body); 28 | 29 | var pos = $.extend({}, this.$element.offset(), { 30 | width: this.$element[0].offsetWidth || 0, 31 | height: this.$element[0].offsetHeight || 0 32 | }); 33 | 34 | if (typeof this.$element[0].nearestViewportElement == 'object') { 35 | // SVG 36 | var el = this.$element[0]; 37 | var rect = el.getBoundingClientRect(); 38 | pos.width = rect.width; 39 | pos.height = rect.height; 40 | } 41 | 42 | 43 | var actualWidth = $tip[0].offsetWidth, 44 | actualHeight = $tip[0].offsetHeight, 45 | gravity = maybeCall(this.options.gravity, this.$element[0]); 46 | 47 | var tp; 48 | switch (gravity.charAt(0)) { 49 | case 'n': 50 | tp = {top: pos.top + pos.height + this.options.offset, left: pos.left + pos.width / 2 - actualWidth / 2}; 51 | break; 52 | case 's': 53 | tp = {top: pos.top - actualHeight - this.options.offset, left: pos.left + pos.width / 2 - actualWidth / 2}; 54 | break; 55 | case 'e': 56 | tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth - this.options.offset}; 57 | break; 58 | case 'w': 59 | tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width + this.options.offset}; 60 | break; 61 | } 62 | 63 | if (gravity.length == 2) { 64 | if (gravity.charAt(1) == 'w') { 65 | tp.left = pos.left + pos.width / 2 - 15; 66 | } else { 67 | tp.left = pos.left + pos.width / 2 - actualWidth + 15; 68 | } 69 | } 70 | 71 | $tip.css(tp).addClass('tipsy-' + gravity); 72 | $tip.find('.tipsy-arrow')[0].className = 'tipsy-arrow tipsy-arrow-' + gravity.charAt(0); 73 | if (this.options.className) { 74 | $tip.addClass(maybeCall(this.options.className, this.$element[0])); 75 | } 76 | 77 | if (this.options.fade) { 78 | $tip.stop().css({opacity: 0, display: 'block', visibility: 'visible'}).animate({opacity: this.options.opacity}); 79 | } else { 80 | $tip.css({visibility: 'visible', opacity: this.options.opacity}); 81 | } 82 | 83 | var t = this; 84 | var set_hovered = function(set_hover){ 85 | return function(){ 86 | t.$tip.stop(); 87 | t.tipHovered = set_hover; 88 | if (!set_hover){ 89 | if (t.options.delayOut === 0) { 90 | t.hide(); 91 | } else { 92 | setTimeout(function() { 93 | if (t.hoverState == 'out') t.hide(); }, t.options.delayOut); 94 | } 95 | } 96 | }; 97 | }; 98 | $tip.hover(set_hovered(true), set_hovered(false)); 99 | } 100 | }, 101 | 102 | hide: function() { 103 | if (this.options.fade) { 104 | this.tip().stop().fadeOut(function() { $(this).remove(); }); 105 | } else { 106 | this.tip().remove(); 107 | } 108 | }, 109 | 110 | fixTitle: function() { 111 | var $e = this.$element; 112 | 113 | if ($e.attr('title') || typeof($e.attr('original-title')) != 'string') { 114 | $e.attr('original-title', $e.attr('title') || '').removeAttr('title'); 115 | } 116 | if (typeof $e.context.nearestViewportElement == 'object'){ 117 | if ($e.children('title').length){ 118 | $e.append('' + ($e.children('title').text() || '') + '') 119 | .children('title').remove(); 120 | } 121 | } 122 | }, 123 | 124 | getTitle: function() { 125 | 126 | var title, $e = this.$element, o = this.options; 127 | this.fixTitle(); 128 | 129 | if (typeof o.title == 'string') { 130 | var title_name = o.title == 'title' ? 'original-title' : o.title; 131 | if ($e.children(title_name).length){ 132 | title = $e.children(title_name).html(); 133 | } else{ 134 | title = $e.attr(title_name); 135 | } 136 | 137 | } else if (typeof o.title == 'function') { 138 | title = o.title.call($e[0]); 139 | } 140 | title = ('' + title).replace(/(^\s*|\s*$)/, ""); 141 | return title || o.fallback; 142 | }, 143 | 144 | tip: function() { 145 | if (!this.$tip) { 146 | this.$tip = $('
').html('
'); 147 | } 148 | return this.$tip; 149 | }, 150 | 151 | validate: function() { 152 | if (!this.$element[0].parentNode) { 153 | this.hide(); 154 | this.$element = null; 155 | this.options = null; 156 | } 157 | }, 158 | 159 | enable: function() { this.enabled = true; }, 160 | disable: function() { this.enabled = false; }, 161 | toggleEnabled: function() { this.enabled = !this.enabled; } 162 | }; 163 | 164 | $.fn.tipsy = function(options) { 165 | 166 | if (options === true) { 167 | return this.data('tipsy'); 168 | } else if (typeof options == 'string') { 169 | var tipsy = this.data('tipsy'); 170 | if (tipsy) tipsy[options](); 171 | return this; 172 | } 173 | 174 | options = $.extend({}, $.fn.tipsy.defaults, options); 175 | 176 | if (options.hoverlock && options.delayOut === 0) { 177 | options.delayOut = 100; 178 | } 179 | 180 | function get(ele) { 181 | var tipsy = $.data(ele, 'tipsy'); 182 | if (!tipsy) { 183 | tipsy = new Tipsy(ele, $.fn.tipsy.elementOptions(ele, options)); 184 | $.data(ele, 'tipsy', tipsy); 185 | } 186 | return tipsy; 187 | } 188 | 189 | function enter() { 190 | var tipsy = get(this); 191 | tipsy.hoverState = 'in'; 192 | if (options.delayIn === 0) { 193 | tipsy.show(); 194 | } else { 195 | tipsy.fixTitle(); 196 | setTimeout(function() { if (tipsy.hoverState == 'in') tipsy.show(); }, options.delayIn); 197 | } 198 | } 199 | 200 | function leave() { 201 | var tipsy = get(this); 202 | tipsy.hoverState = 'out'; 203 | if (options.delayOut === 0) { 204 | tipsy.hide(); 205 | } else { 206 | var to = function() { 207 | if (!tipsy.tipHovered || !options.hoverlock){ 208 | if (tipsy.hoverState == 'out') tipsy.hide(); 209 | } 210 | }; 211 | setTimeout(to, options.delayOut); 212 | } 213 | } 214 | 215 | if (options.trigger != 'manual') { 216 | var binder = options.live ? 'live' : 'bind', 217 | eventIn = options.trigger == 'hover' ? 'mouseenter' : 'focus', 218 | eventOut = options.trigger == 'hover' ? 'mouseleave' : 'blur'; 219 | this[binder](eventIn, enter)[binder](eventOut, leave); 220 | } 221 | 222 | return this; 223 | 224 | }; 225 | 226 | $.fn.tipsy.defaults = { 227 | className: null, 228 | delayIn: 0, 229 | delayOut: 0, 230 | fade: false, 231 | fallback: '', 232 | gravity: 'n', 233 | html: false, 234 | live: false, 235 | offset: 0, 236 | opacity: 0.8, 237 | title: 'title', 238 | trigger: 'hover', 239 | hoverlock: false 240 | }; 241 | 242 | // Overwrite this method to provide options on a per-element basis. 243 | // For example, you could store the gravity in a 'tipsy-gravity' attribute: 244 | // return $.extend({}, options, {gravity: $(ele).attr('tipsy-gravity') || 'n' }); 245 | // (remember - do not modify 'options' in place!) 246 | $.fn.tipsy.elementOptions = function(ele, options) { 247 | return $.metadata ? $.extend({}, options, $(ele).metadata()) : options; 248 | }; 249 | 250 | $.fn.tipsy.autoNS = function() { 251 | return $(this).offset().top > ($(document).scrollTop() + $(window).height() / 2) ? 's' : 'n'; 252 | }; 253 | 254 | $.fn.tipsy.autoWE = function() { 255 | return $(this).offset().left > ($(document).scrollLeft() + $(window).width() / 2) ? 'e' : 'w'; 256 | }; 257 | 258 | /** 259 | * yields a closure of the supplied parameters, producing a function that takes 260 | * no arguments and is suitable for use as an autogravity function like so: 261 | * 262 | * @param margin (int) - distance from the viewable region edge that an 263 | * element should be before setting its tooltip's gravity to be away 264 | * from that edge. 265 | * @param prefer (string, e.g. 'n', 'sw', 'w') - the direction to prefer 266 | * if there are no viewable region edges effecting the tooltip's 267 | * gravity. It will try to vary from this minimally, for example, 268 | * if 'sw' is preferred and an element is near the right viewable 269 | * region edge, but not the top edge, it will set the gravity for 270 | * that element's tooltip to be 'se', preserving the southern 271 | * component. 272 | */ 273 | $.fn.tipsy.autoBounds = function(margin, prefer) { 274 | return function() { 275 | var dir = {ns: prefer[0], ew: (prefer.length > 1 ? prefer[1] : false)}, 276 | boundTop = $(document).scrollTop() + margin, 277 | boundLeft = $(document).scrollLeft() + margin, 278 | $this = $(this); 279 | 280 | if ($this.offset().top < boundTop) dir.ns = 'n'; 281 | if ($this.offset().left < boundLeft) dir.ew = 'w'; 282 | if ($(window).width() + $(document).scrollLeft() - $this.offset().left < margin) dir.ew = 'e'; 283 | if ($(window).height() + $(document).scrollTop() - $this.offset().top < margin) dir.ns = 's'; 284 | 285 | return dir.ns + (dir.ew ? dir.ew : ''); 286 | }; 287 | }; 288 | })(jQuery); --------------------------------------------------------------------------------