├── .editorconfig ├── .gitignore ├── LICENSE.md ├── README.md ├── bower.json ├── data ├── browser-action │ ├── css │ │ └── style.scss │ ├── index.html │ └── js │ │ └── script.js ├── css │ ├── _app-browser.scss │ ├── _app-downloader.scss │ ├── _app-epg.scss │ ├── _app-lanbrowser.scss │ ├── _app-settings.scss │ ├── _app-tasklist.scss │ ├── _components.scss │ ├── _desktop-login.scss │ ├── _desktop.scss │ ├── _icons.scss │ ├── _inputs.scss │ ├── _material-buttons.scss │ ├── _material.scss │ ├── _toolbar.scss │ ├── _window.scss │ ├── fonts │ │ ├── _fonts-mixins.scss │ │ ├── _materialdesignicons-woff.scss │ │ ├── _materialdesignicons-woff2.scss │ │ ├── _roboto-light-woff.scss │ │ ├── _roboto-light-woff2.scss │ │ ├── _roboto-medium-woff.scss │ │ ├── _roboto-medium-woff2.scss │ │ ├── _roboto-regular-woff.scss │ │ ├── _roboto-regular-woff2.scss │ │ ├── materialdesignicons.scss │ │ └── roboto.scss │ └── style.scss ├── img │ ├── icon-128x128.png │ ├── icon-16x16.png │ ├── icon-18x18.png │ ├── icon-19x19.png │ ├── icon-256x256.png │ ├── icon-32x32.png │ ├── icon-36x36.png │ ├── icon-38x38.png │ ├── icon-48x48.png │ ├── icon-64x64.png │ ├── icon-90x90.png │ ├── icon.svg │ ├── mdi-check.png │ ├── wallpaper1.jpg │ ├── wallpaper2.jpg │ ├── wallpaper3.jpg │ ├── wallpaper4.jpg │ ├── wallpaper5.jpg │ └── wallpaper6.jpg ├── js │ ├── content-script.js │ ├── injector.js │ └── material-freebox-os.js └── vendor │ ├── fonts │ ├── README.md │ ├── Roboto │ │ ├── Roboto-Light.woff │ │ ├── Roboto-Light.woff2 │ │ ├── Roboto-Medium.woff │ │ ├── Roboto-Medium.woff2 │ │ ├── Roboto-Regular.woff │ │ └── Roboto-Regular.woff2 │ └── materialdesignicons │ │ ├── materialdesignicons-webfont.eot │ │ ├── materialdesignicons-webfont.svg │ │ ├── materialdesignicons-webfont.ttf │ │ ├── materialdesignicons-webfont.woff │ │ └── materialdesignicons-webfont.woff2 │ └── jquery-3.3.1.slim.min.js ├── doc ├── download-chrome-web-store.png ├── download-firefox.png ├── download-opera.png ├── opera │ ├── opera-en.md │ ├── opera-fr.md │ ├── opera-install.png │ └── opera-warning.png ├── screenshot1.png ├── screenshot2.png └── screenshot3.png ├── generate-icons.py ├── manifest.json └── prepare-release.py /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | # 4 space indentation 7 | indent_style = space 8 | indent_size = 4 9 | 10 | charset = utf-8 11 | insert_final_newline = true 12 | trim_trailing_whitespace = true 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # PhpStorm 2 | .idea 3 | 4 | # Bower components 5 | bower_components/ 6 | 7 | # Compiled CSS files 8 | data/css/style.css* 9 | data/css/fonts/roboto.css* 10 | data/css/fonts/materialdesignicons.css* 11 | data/browser-action/css/style.css* 12 | 13 | # Release files 14 | release/ 15 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Material Freebox OS 2 | 3 | This project's aim is to redesign Freebox OS's UI by injecting custom stylesheets into its web interface via a Google Chrome 4 | or Firefox extension. 5 | 6 | As you can see, the redesign is hugely inspired from [Google's Material design guidelines](http://www.google.com/design/spec/material-design/introduction.html) 7 | and Chrome OS specs. 8 | 9 | [![Download on Chrome Web Store](doc/download-chrome-web-store.png)](https://chrome.google.com/webstore/detail/material-freebox-os/lhdfonhgkclaigpfmclbahllambeednh) 10 | [![Download for Firefox](doc/download-firefox.png)](https://addons.mozilla.org/fr/firefox/addon/material-freeboxos/) 11 | [![Download for Opera](doc/download-opera.png)](doc/opera/opera-en.md) 12 | 13 | ![Material-Freebox-OS](doc/screenshot2.png) 14 | 15 | See [below](#screenshots) for more screenshots. 16 | 17 | ## How does it work? 18 | Quite straight-forward actually: [`injector.js`](data/js/injector.js) file is injected by either Chrome or Firefox inside the tab. 19 | His aim is to inject the necessary resources - `style.css`, `content-script.js`, MaterialDesignIcons stylesheet and Roboto font. 20 | 21 | We use SCSS (compiled CSS) to override Freebox OS's styles alongside with some Javascript when necessary. 22 | 23 | That's it! 24 | 25 | This project relies on the following resources: 26 | 27 | * [Material Design Icons](https://materialdesignicons.com) 28 | * [Roboto font](https://www.google.com/fonts/specimen/Roboto) 29 | * Wallpaper credits: see [`material-freebox-os.js/MaterialFreeboxOS.wallpaper.wallpapers`](https://github.com/chteuchteu/Material-Freebox-OS/blob/master/data/js/material-freebox-os.js#L71) 30 | 31 | 32 | ### How about security? 33 | That's a legitimate question: you can browse Javascript files ([`injector.js`](data/js/injector.js) and [`content-script.js`](data/js/content-script.js)) 34 | in this repo or directly from Chrome's debugger tools - to see that their sole purpose is to manipulate the DOM to apply 35 | some styling that couldn't be set in CSS. 36 | 37 | ## How to contribute 38 | Do not hesitate to open issues or to create pull requests against the master branch! 39 | The main project is based on SCSS to build CSS files: you'll need an appropriate compiler alongside with some Chrome extensions notions. 40 | 41 | > Note: we're using the EditorConfig standard to supply coding rules for this project, learn more about it [here](http://editorconfig.org/). 42 | 43 | > Warning: this is not meant to be perfect. Freebox OS's UI is quite difficult to style, and some changes aren't possible for now. 44 | I'd rather keep this project maintainable and compatible with upcoming releases of Freebox OS than doing some Javascript black 45 | magic to set these minimize/maximize/close buttons padding. 46 | 47 | ## Screenshots 48 | ![Material-Freebox-OS](doc/screenshot1.png) 49 | ![Material-Freebox-OS](doc/screenshot3.png) 50 | 51 | Check Material Freebox OS's page on the [Chrome Web Store](https://chrome.google.com/webstore/detail/material-freebox-os/lhdfonhgkclaigpfmclbahllambeednh) 52 | or [Firefox addons repository](https://addons.mozilla.org/fr/firefox/addon/material-freeboxos/) for some more. 53 | 54 | ## Licensing 55 | Material-Freebox-OS is distributed under the GNU GPL version 2. 56 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "material-freebox-os", 3 | "homepage": "https://github.com/chteuchteu/Material-Freebox-OS", 4 | "authors": [ 5 | "Quentin Stoeckel " 6 | ], 7 | "description": "", 8 | "main": "", 9 | "license": "GPL-2.0", 10 | "private": true, 11 | "dependencies": { 12 | "materialdesignicons-scss-variables": "^2.3.0", 13 | "bourbon": "^4.2.7" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /data/browser-action/css/style.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Material-Freebox-OS 3 | * Browser action style 4 | */ 5 | 6 | // Bower bourbon dependency 7 | @import '../../../bower_components/bourbon/app/assets/stylesheets/bourbon'; 8 | 9 | // Bower materialdesignicons-scss-variables dependency 10 | @import '../../../bower_components/materialdesignicons-scss-variables/dist/materialdesignicons'; 11 | @import '../../../bower_components/materialdesignicons-scss-variables/dist/materialdesignicons-vars'; 12 | 13 | @import '../../css/material'; 14 | @import '../../css/material-buttons'; 15 | @import '../../css/inputs'; 16 | 17 | html, body { 18 | margin: 0; 19 | padding: 0; 20 | width: 380px; 21 | overflow-x: hidden; 22 | overflow-y: auto; 23 | } 24 | 25 | body { 26 | font-family: $roboto; 27 | color: $color-text-dark; 28 | 29 | cursor: default; 30 | user-select: none; 31 | } 32 | 33 | * { 34 | box-sizing: border-box; 35 | } 36 | 37 | header, .content .part, footer { 38 | padding: 5px 10px; 39 | } 40 | 41 | h1 { 42 | margin: 5px 0 0 0; 43 | } 44 | h2 { 45 | font-weight: 500; 46 | margin: 25px 0 5px 0; 47 | 48 | .source { 49 | color: $color-text-dark; 50 | text-decoration: none; 51 | font-size: 10px; 52 | opacity: 0.4; 53 | } 54 | } 55 | 56 | .ul-nostyle { 57 | margin: 0; 58 | padding: 0; 59 | list-style: none; 60 | font-size: 0; 61 | line-height: 0; 62 | } 63 | 64 | .content { 65 | position: relative; 66 | 67 | // Colors & wallpapers lists 68 | .part-colors, .part-wallpapers { 69 | ul { 70 | @extend .ul-nostyle; 71 | 72 | li { 73 | cursor: pointer; 74 | display: inline-block; 75 | margin: 2px; 76 | border-radius: 2px; 77 | 78 | // Check icon 79 | position: relative; 80 | 81 | &:before { 82 | position: absolute; 83 | bottom: 2px; 84 | right: 2px; 85 | font-size: 20px; 86 | color: #fff; 87 | text-shadow: 1px 1px 1px rgba(#000, 0.3); 88 | transition-duration: $timing-short; 89 | @include material-icon-simple($mdi-check-circle); 90 | opacity: 0; 91 | } 92 | 93 | &.current:before { 94 | opacity: 1; 95 | } 96 | } 97 | } 98 | } 99 | 100 | .part-colors { 101 | h2:first-child { 102 | margin-top: 0; 103 | } 104 | 105 | ul { 106 | @extend .ul-nostyle; 107 | 108 | li { 109 | width: 32px; 110 | height: 32px; 111 | } 112 | } 113 | } 114 | 115 | .part-wallpapers { 116 | ul { 117 | @extend .ul-nostyle; 118 | 119 | li { 120 | width: calc(33% - 4px); 121 | height: 75px; 122 | background-position: center; 123 | background-repeat: no-repeat; 124 | background-size: cover; 125 | } 126 | } 127 | 128 | #wallpapers-url { 129 | display: inline-block; 130 | width: calc(100% - 8px); 131 | margin: 6px 2px 2px; 132 | } 133 | 134 | .credits { 135 | display: table; 136 | margin-left: auto; 137 | opacity: 0.4; 138 | transition-duration: $timing-short; 139 | transition-property: opacity; 140 | 141 | &:hover { 142 | opacity: 0.8; 143 | } 144 | } 145 | } 146 | } 147 | 148 | footer { 149 | margin-top: 20px; 150 | text-align: right; 151 | @extend .primary-color--background; 152 | transition-duration: $timing-medium; 153 | transition-property: background; 154 | 155 | a.material-button--flat--primary { 156 | display: inline-block; 157 | text-decoration: none; 158 | padding-left: 7px; 159 | margin: 0; 160 | 161 | .x-btn-inner { 162 | font-size: 13px; 163 | 164 | &:before { 165 | font-size: 16px!important; 166 | vertical-align: middle; 167 | margin-right: 5px; 168 | margin-top: -1px; 169 | } 170 | } 171 | 172 | &.btn-author .x-btn-inner:before { 173 | @include material-icon-simple($mdi-account); 174 | } 175 | &.btn-github .x-btn-inner:before { 176 | @include material-icon-simple($mdi-github-circle); 177 | } 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /data/browser-action/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Material Freebox OS 6 | 7 | 8 | 9 | 10 | 11 |
12 |

Material Freebox OS

13 |
14 |
15 |
16 |

Couleur primaire

17 |
    18 | 19 |

    Couleur secondaire

    20 |
      21 |
      22 |
      23 |

      Fond d'écran (source)

      24 | 25 |
        26 | 27 |
        28 |
        29 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /data/browser-action/js/script.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Material-Freebox-OS 3 | * Browser action JS 4 | */ 5 | (function() { 6 | var browserHandle = MaterialFreeboxOS.environment.getBrowserHandle(); 7 | 8 | var BrowserAction = { 9 | updateColorsAndSave: function(primary, accent) { 10 | $('body') 11 | .attr('data-color-primary', primary) 12 | .attr('data-color-accent', accent); 13 | 14 | BrowserAction.updateColorsInTab(primary, accent); 15 | chrome.storage.local.set({ 16 | 'color-primary': primary, 17 | 'color-accent': accent 18 | }); 19 | }, 20 | 21 | updateColorsInTab: function(primary, accent) { 22 | browserHandle.tabs.query({}, function(tabs) { 23 | tabs.forEach(function(tab) { 24 | if (MaterialFreeboxOS.matches(tab.title)) { 25 | var updateColors = function(primary, accent) { 26 | document.body.setAttribute('data-color-primary', primary); 27 | document.body.setAttribute('data-color-accent', accent); 28 | }; 29 | 30 | var code = 31 | "var updateColors = " + updateColors.toString() + ";\ 32 | updateColors('" + primary + "', '" + accent + "');"; 33 | 34 | browserHandle.tabs.executeScript(tab.id, { 35 | code: code 36 | }); 37 | } 38 | }); 39 | }); 40 | }, 41 | 42 | updateWallpaperAndSave: function(uri) { 43 | BrowserAction.updateWallpaperInTab(uri, MaterialFreeboxOS.wallpaper.findWallpaperInfos(uri)); 44 | browserHandle.storage.local.set({ 45 | 'wallpaper': uri 46 | }); 47 | }, 48 | 49 | /** 50 | * Updates wallpaper in current tab 51 | * @param projectUri 52 | * @param wallpaperInfos 53 | */ 54 | updateWallpaperInTab: function(projectUri, wallpaperInfos) { 55 | var uri = MaterialFreeboxOS.getDepURI(projectUri); 56 | 57 | browserHandle.tabs.query({}, function(tabs) { 58 | tabs.forEach(function(tab) { 59 | if (MaterialFreeboxOS.matches(tab.title)) { 60 | var updateWallpaper = function(uri, wallpaperInfos) { 61 | document.body.style.backgroundImage = "url(" + uri + ")"; 62 | 63 | var element = document.getElementsByClassName('desktop-wallpaper-credits')[0]; 64 | MaterialFreeboxOS.wallpaper.updateWallpaperCredits(element, wallpaperInfos); 65 | }; 66 | 67 | var code = 68 | "var updateWallpaper = " + updateWallpaper.toString() + ";\ 69 | updateWallpaper('" + uri + "', eval('(" + JSON.stringify(wallpaperInfos) + ")'))"; 70 | 71 | browserHandle.tabs.executeScript(tab.id, { 72 | code: code 73 | }); 74 | } 75 | }); 76 | }); 77 | } 78 | }; 79 | 80 | $(document).ready(function () { 81 | // Colors 82 | var primaryColorsUl = $('#colors-primary'), 83 | accentColorsUl = $('#colors-accent'); 84 | 85 | // Inflate list 86 | MaterialFreeboxOS.materialColors.colors.forEach(function(color) { 87 | $('
      • ') 88 | .attr('data-color', color) 89 | .css('background-color', color) 90 | .appendTo(primaryColorsUl) 91 | .clone().appendTo(accentColorsUl); 92 | }); 93 | 94 | var primaryColor_colors = primaryColorsUl.find('li'), 95 | accentColor_colors = accentColorsUl.find('li'); 96 | 97 | // Retrieve current settings 98 | browserHandle.storage.local.get('color-primary', function (data) { 99 | var defaultPrimaryColor = MaterialFreeboxOS.materialColors.defaultPrimary, 100 | primaryColor = data['color-primary'] || defaultPrimaryColor; 101 | 102 | primaryColor_colors.filter('[data-color="' + primaryColor + '"]').addClass('current'); 103 | $('body').attr('data-color-primary', primaryColor); 104 | }); 105 | browserHandle.storage.local.get('color-accent', function (data) { 106 | var defaultAccentColor = MaterialFreeboxOS.materialColors.defaultAccent, 107 | accentColor = data['color-accent'] || defaultAccentColor; 108 | 109 | accentColor_colors.filter('[data-color="' + accentColor + '"]').addClass('current'); 110 | $('body').attr('data-color-accent', accentColor); 111 | }); 112 | 113 | // Update current colors 114 | $().add(primaryColor_colors).add(accentColor_colors).click(function() { 115 | $(this).closest('ul').find('li').removeClass('current'); 116 | $(this).addClass('current'); 117 | 118 | BrowserAction.updateColorsAndSave( 119 | primaryColorsUl.find('li.current').attr('data-color'), 120 | accentColorsUl.find('li.current').attr('data-color') 121 | ); 122 | }); 123 | 124 | 125 | // Wallpapers 126 | var wallpapersUl = $('#wallpapers-images'); 127 | 128 | // Inflate list 129 | MaterialFreeboxOS.wallpaper.wallpapers.forEach(function(wallpaper) { 130 | $('
      • ') 131 | .attr('data-uri', wallpaper.image) 132 | .attr('data-credits', wallpaper.credits) 133 | .attr('data-source', wallpaper.source) 134 | .css('background-image', "url(" + MaterialFreeboxOS.getDepURI(wallpaper.image) + ")") 135 | .prependTo(wallpapersUl); 136 | }); 137 | 138 | var wallpapers_images = wallpapersUl.find('li'), 139 | wallpapers_url = $('#wallpapers-url'); 140 | 141 | // Retrieve current settings 142 | browserHandle.storage.local.get('wallpaper', function (data) { 143 | var defaultWallpaper = MaterialFreeboxOS.wallpaper.defaultWallpaper.image, 144 | wallpaper = data['wallpaper'] || defaultWallpaper; 145 | 146 | if (MaterialFreeboxOS.wallpaper.findWallpaperInfos(wallpaper) != null) 147 | wallpapers_images.filter('[data-uri="' + wallpaper + '"]').addClass('current'); 148 | else 149 | wallpapers_url.val(wallpaper); 150 | }); 151 | 152 | // Update current wallpaper: image 153 | wallpapers_images.click(function () { 154 | wallpapers_images.removeClass('current'); 155 | $(this).addClass('current'); 156 | wallpapers_url.val(''); 157 | 158 | BrowserAction.updateWallpaperAndSave($(this).data('uri')); 159 | }); 160 | 161 | // Update current wallpaper: input 162 | wallpapers_url.keyup(function(e) { 163 | if (e.which == 13) { 164 | wallpapers_images.removeClass('current'); 165 | 166 | BrowserAction.updateWallpaperAndSave($(this).val()); 167 | } 168 | }); 169 | }); 170 | })(); 171 | -------------------------------------------------------------------------------- /data/css/_app-browser.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Material-Freebox-OS 3 | * File browser app 4 | */ 5 | 6 | // Treeview 7 | .x-tree-view { 8 | .x-grid-row { 9 | &.x-grid-tree-node-expanded { 10 | 11 | } 12 | 13 | .x-grid-cell { 14 | transition-property: background-color; 15 | transition-duration: $timing-short; 16 | 17 | .x-grid-cell-inner { 18 | padding: 5px 6px 6px 0; 19 | 20 | .x-tree-icon { 21 | margin-left: 6px; 22 | } 23 | .x-tree-node-text { 24 | font-family: $roboto; 25 | color: $color-text-dark; 26 | font-size: 12px; 27 | margin-left: 5px; 28 | display: inline-block; 29 | } 30 | } 31 | } 32 | 33 | // Selected row 34 | &.x-grid-row-selected .x-grid-cell { 35 | border-color: transparent; 36 | background-color: transparent!important; 37 | 38 | .x-tree-node-text { 39 | font-weight: 600; 40 | @extend .accent-color--color; 41 | } 42 | } 43 | } 44 | } 45 | 46 | // Mount point 47 | .fs-mount-point { 48 | height: auto; 49 | margin: 7px 8px; 50 | padding: 5px 8px 5px 5px; 51 | @extend .selectable-item; 52 | 53 | .fs-mount-icon { 54 | height: 40px; 55 | } 56 | 57 | &.x-item-selected { 58 | text-shadow: none; 59 | @extend .selectable-item.selected; 60 | 61 | .fs-mount-icon div { 62 | color: #fff; 63 | } 64 | } 65 | 66 | .x-progress-wrap { 67 | margin: 3px 0; 68 | border-radius: 1px; 69 | @extend .accent-color--background; 70 | 71 | .x-progress-inner { 72 | .x-progress-bar { 73 | @extend .accent-color--dark--background; 74 | border-radius: 1px; 75 | } 76 | 77 | // Percentage text 78 | > div:not(.x-progress-bar) { 79 | color: #fff; 80 | padding-top: 3px; 81 | } 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /data/css/_app-downloader.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Material-Freebox-OS 3 | * Downloader app 4 | */ 5 | 6 | .animprogress { 7 | height: 12px; 8 | border: 0; 9 | border-radius: 2px; 10 | 11 | .pct { 12 | font-family: $roboto; 13 | } 14 | 15 | > span { 16 | height: 12px; 17 | background-image: none; 18 | background-color: material-color($color-green); 19 | border-radius: 2px; 20 | box-shadow: none; 21 | } 22 | 23 | &.blue > span { 24 | background-color: material-color($color-blue); 25 | } 26 | } 27 | 28 | .btn-24-download-stopped { color: material-color($color-red); } 29 | .btn-24-download-queued { color: material-color($color-orange); } 30 | .btn-24-download-downloading { color: material-color($color-green); } 31 | 32 | .x-form-timetable-table { 33 | tr { 34 | border: 1px solid #fff; 35 | } 36 | } 37 | 38 | .timetable-btn { 39 | margin-top: -5px; 40 | 41 | em span { 42 | color: #fff; 43 | font-style: normal; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /data/css/_app-epg.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Material-Freebox-OS 3 | * EPG ("Guide des programmes") 4 | */ 5 | 6 | $prog-elem-colors: ( 7 | 0: material-color($color-purple), 8 | 1: material-color($color-indigo), 9 | 2: material-color($color-blue), 10 | 3: material-color($color-orange), 11 | 4: material-color($color-amber), 12 | 5: material-color($color-brown), 13 | 6: material-color($color-teal), 14 | 7: material-color($color-green), 15 | 8: material-color($color-red), 16 | 9: material-color($color-blue-grey), 17 | ); 18 | 19 | .epg-highlights, .epg-outer { 20 | background-color: #eeeeee; 21 | 22 | .epg-btn-container { 23 | width: 100%!important; 24 | height: auto!important; 25 | left: 0!important; 26 | padding: 7px 0; 27 | text-align: center; 28 | background-color: #fff; 29 | 30 | > * { 31 | float: none; 32 | display: inline-block; 33 | vertical-align: middle; 34 | } 35 | 36 | .btn-epg-view-toggle { 37 | height: auto; 38 | padding: 8px 10px!important; 39 | color: $color-text-dark; 40 | @extend .material-button--elevated; 41 | 42 | &.btn-epg-view-toggle-selected { 43 | color: #fff; 44 | @extend .material-button--elevated--primary; 45 | } 46 | } 47 | 48 | .btn-epg-complete, .btn-now { 49 | margin-right: 20px; 50 | } 51 | 52 | .btn-day { 53 | width: auto; 54 | height: auto; 55 | padding: 6px 10px!important; 56 | color: $color-text-dark; 57 | @extend .material-button--elevated; 58 | 59 | &.btn-now { 60 | padding: 8px 10px!important; 61 | } 62 | 63 | &.btn-day-selected { 64 | color: #fff; 65 | @extend .material-button--elevated--primary; 66 | } 67 | } 68 | 69 | .btn-hour-container { 70 | .btn-hour { 71 | font-family: $roboto; 72 | border-radius: 2px; 73 | } 74 | } 75 | } 76 | 77 | .epg-viewport { 78 | box-shadow: inset $elevation-2; 79 | } 80 | 81 | .epg-timeline { 82 | background-color: transparent; 83 | @extend .elevation-lowest; 84 | 85 | .epg-time-elem { 86 | font-family: $roboto; 87 | background-color: transparent; 88 | color: $color-text-dark; 89 | } 90 | } 91 | 92 | .epg-channellist { 93 | .epg-channel-elem { 94 | background-color: material-color($color-amber); 95 | border: 0; 96 | border-radius: 2px; 97 | @extend .elevation-lowest; 98 | 99 | .epg-channel-name { 100 | color: rgba(0, 0, 0, 0.8); 101 | font-family: $roboto; 102 | font-weight: 700; 103 | } 104 | } 105 | } 106 | 107 | .epg-container { 108 | .epg-prog-elem { 109 | border: 0; 110 | background-color: #ffffff; 111 | font-family: $roboto; 112 | border-radius: 1px; 113 | 114 | // Colors 115 | @each $index, $icon in $prog-elem-colors { 116 | &.epg-prog-cat-#{$index} { 117 | box-shadow: inset $icon 0 3px 0, $elevation-1; 118 | } 119 | } 120 | 121 | .epg-prog-infos { 122 | > * { 123 | color: $color-text-dark; 124 | } 125 | .epg-prog-timeinfo { 126 | opacity: 0.7; 127 | } 128 | } 129 | } 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /data/css/_app-lanbrowser.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Material-Freebox-OS 3 | * Lan browser app 4 | */ 5 | 6 | .lan-host { 7 | @extend .selectable-item; 8 | 9 | .lan-host-name { 10 | font-weight: 600; 11 | } 12 | 13 | &.lan-host-selected { 14 | border: 1px solid transparent; 15 | @extend .selectable-item.selected; 16 | 17 | .lan-host-name { 18 | text-shadow: none; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /data/css/_app-settings.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Material-Freebox-OS 3 | * Settings app 4 | */ 5 | 6 | .setting-list-app { 7 | h3 { 8 | border-bottom: 0; 9 | font-family: $roboto; 10 | margin: 10px 5px 5px 5px; 11 | border-bottom: 1px solid #ddd; 12 | padding-bottom: 6px; 13 | } 14 | 15 | .setting-app { 16 | cursor: default; 17 | border-radius: 2px; 18 | transition-property: background; 19 | transition-duration: $timing-short; 20 | 21 | &.setting-app-over { 22 | border-color: transparent; 23 | background: $color-hover-light; 24 | } 25 | 26 | span[role="presentation"] { 27 | font-family: $roboto; 28 | } 29 | 30 | &.setting-app-selected { 31 | border-color: transparent; 32 | @extend .accent-color--background; 33 | 34 | .thumb .setting-app-img { 35 | color: #fff; 36 | } 37 | } 38 | 39 | @for $i from 1 through length($material-colors) { 40 | &:nth-child(#{$i}n) .setting-app-img { 41 | color: material-color(nth(map-values($material-colors), $i)); 42 | } 43 | } 44 | } 45 | } 46 | 47 | .x-docked { 48 | // Remove background from wifi settings left pane icons 49 | .btn-32-wps, 50 | .btn-32-lock-edit, 51 | .btn-32-wifi-calendar, 52 | .btn-32-wifi-toggle-on, 53 | .btn-32-wifi-toggle-off, 54 | .btn-32-delete { 55 | background: none; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /data/css/_app-tasklist.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Material-Freebox-OS 3 | * Tasks list 4 | */ 5 | 6 | .task-list-win { 7 | .task-list-grid-body { 8 | background: transparent; 9 | 10 | .x-grid-table { 11 | border: 0; 12 | 13 | .x-grid-row { 14 | &, &.x-grid-row-over { 15 | background: transparent; 16 | } 17 | } 18 | 19 | .x-grid-cell { 20 | background-color: transparent!important; 21 | 22 | .fstask-view { 23 | border: 0; 24 | margin: 0; 25 | background-color: #fff; 26 | border-radius: 2px!important; 27 | @extend .elevation-low; 28 | 29 | .fstask-title { 30 | padding: 10px 40px 10px 10px; 31 | height: auto; 32 | border-radius: 2px 2px 0 0; 33 | } 34 | 35 | .fstask-content { 36 | border: 0; 37 | background: transparent; 38 | color: $color-text-dark; 39 | padding: 8px 10px; 40 | 41 | // Progressbar 42 | .fstask-progress-outer { 43 | background: #ccc; 44 | 45 | .fstask-progress { 46 | border-radius: 2px; 47 | 48 | &.fstask-progress-done { 49 | background-color: material-color($color-green); 50 | } 51 | } 52 | .fstask-progress-txt { 53 | font-size: 12px; 54 | } 55 | } 56 | 57 | .fstask-path { 58 | text-overflow: ellipsis; 59 | } 60 | } 61 | } 62 | } 63 | 64 | .task-list-grid-action-column img { 65 | margin-left: 5px; 66 | margin-top: 10px; 67 | margin-right: -2px; 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /data/css/_components.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Material-Freebox-OS 3 | * Various UI components 4 | */ 5 | 6 | // Tabs 7 | .x-tab { 8 | cursor: default; 9 | padding: 10px 16px 8px 16px; 10 | background: transparent; 11 | border: 0!important; 12 | border-bottom: 3px solid transparent!important; 13 | transition-duration: 150ms; 14 | transition-property: background, border-bottom-color; 15 | border-radius: 0; 16 | 17 | .x-tab-inner { 18 | color: #fff!important; 19 | font-family: $roboto; 20 | font-weight: 500; 21 | } 22 | 23 | &.x-tab-top-active { 24 | background: transparent!important; 25 | border-bottom-color: rgba(#000, 0.4)!important; 26 | } 27 | 28 | &.x-tab-top-disabled { 29 | background: none!important; 30 | opacity: 0.5; 31 | } 32 | 33 | &:hover { 34 | background-color: $color-hover-light; 35 | } 36 | } 37 | 38 | // Panel header 39 | .x-panel-header { 40 | border-radius: 2px 2px 0 0; 41 | 42 | .x-panel-header-text-default { 43 | font-family: $roboto; 44 | font-weight: 500; 45 | } 46 | } 47 | 48 | // Table header 49 | .x-grid-header-ct { 50 | background: $color-background-light none; 51 | box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3); 52 | 53 | .x-column-header { 54 | background: $color-background-light none; 55 | 56 | .x-column-header-inner { 57 | padding: 9px 9px 8px; 58 | 59 | .x-column-header-text { 60 | font-family: $roboto; 61 | font-weight: $typography-label-font-weight; 62 | font-size: $typography-label-font-size; 63 | color: $typography-label-color; 64 | } 65 | 66 | .x-column-header-trigger { 67 | visibility: hidden; 68 | right: 2px; 69 | background: none; 70 | @include material-icon($mdi-dots-vertical); 71 | 72 | &:before { 73 | font-size: 15px; 74 | line-height: 30px; 75 | } 76 | } 77 | 78 | &.x-column-header-over { 79 | background: $color-hover-light none; 80 | 81 | .x-column-header-trigger { 82 | visibility: visible; 83 | } 84 | } 85 | } 86 | 87 | // ASC / DESC icon 88 | &.x-column-header-sort-ASC, 89 | &.x-column-header-sort-DESC { 90 | .x-column-header-text { 91 | background-image: none; 92 | 93 | &:before { 94 | margin-left: 5px; 95 | float: right; 96 | } 97 | } 98 | } 99 | &.x-column-header-sort-ASC .x-column-header-text { 100 | @include material-icon($mdi-chevron-up); 101 | } 102 | &.x-column-header-sort-DESC .x-column-header-text { 103 | @include material-icon($mdi-chevron-down); 104 | } 105 | } 106 | } 107 | 108 | // Dropdown, contextual menu 109 | .x-menu { 110 | @extend .elevation-low; 111 | border-radius: 2px; 112 | 113 | .x-menu-body { 114 | border: 0; 115 | background-color: #fff; 116 | padding: 3px 0; 117 | 118 | .x-menu-icon-separator { 119 | display: none; 120 | } 121 | 122 | .x-menu-item { 123 | cursor: default; 124 | padding: 0; 125 | border-color: transparent; 126 | transition-property: background; 127 | transition-duration: $timing-short; 128 | border-radius: 0; 129 | 130 | .x-menu-item-link { 131 | cursor: default; 132 | padding-top: 5px; 133 | padding-bottom: 5px; 134 | margin-left: 35px; 135 | 136 | .x-menu-item-icon { 137 | top: 9px!important; 138 | left: 8px!important; 139 | color: $color-icon-dark; 140 | } 141 | .x-menu-item-text { 142 | cursor: default; 143 | font-size: 13px; 144 | font-family: $roboto; 145 | } 146 | .x-menu-item-arrow { 147 | top: 10px; 148 | right: 3px; 149 | color: $color-text-dark; 150 | background-image: none; 151 | @include material-icon($mdi-chevron-right); 152 | } 153 | .x-menu-item-checkbox, 154 | .btn-bullet-blue { 155 | background-image: none; 156 | font-size: 8px; 157 | line-height: 16px; 158 | } 159 | .x-menu-item-checkbox { 160 | @include material-icon($mdi-checkbox-blank-circle-outline); 161 | } 162 | .btn-bullet-blue { 163 | @include material-icon($mdi-checkbox-blank-circle); 164 | } 165 | } 166 | &.x-menu-item-checked .x-menu-item-checkbox { 167 | @include material-icon($mdi-checkbox-blank-circle); 168 | } 169 | 170 | &.x-menu-item-active { 171 | border: 0; 172 | background: $color-hover-light; 173 | 174 | .x-menu-item-link { 175 | background: transparent !important; 176 | } 177 | } 178 | 179 | &.x-menu-item-separator { 180 | display: none; 181 | } 182 | } 183 | } 184 | } 185 | 186 | // Tip 187 | .x-tip { 188 | border: 0; 189 | background-color: $color-dark; 190 | border-radius: 2px; 191 | @extend .elevation-lowest; 192 | 193 | .x-tip-body { 194 | color: #fff; 195 | font-family: $roboto; 196 | } 197 | 198 | &.x-tip-form-invalid { 199 | background-color: material-color($color-red); 200 | 201 | .x-tip-body-form-invalid { 202 | background: none; 203 | 204 | > span:before { 205 | position: absolute; 206 | left: 0; 207 | font-size: 15px; 208 | @include material-icon-simple($mdi-alert-circle); 209 | } 210 | } 211 | } 212 | } 213 | 214 | // Table 215 | .x-grid-table { 216 | .x-grid-data-row { 217 | .x-grid-cell { 218 | padding: 3px 0; 219 | border-width: 0; 220 | 221 | .x-grid-cell-inner { 222 | padding: 6px 8px 6px; 223 | font-family: $roboto; 224 | font-size: 12px; 225 | } 226 | } 227 | } 228 | } 229 | 230 | .selectable-item { 231 | border: 0; 232 | background-color: $color-background-light; 233 | border-radius: 1px; 234 | transition-property: box-shadow; 235 | transition-duration: $timing-short; 236 | @extend .elevation-lowest; 237 | 238 | &.selected { 239 | @extend .accent-color--background; 240 | } 241 | } 242 | 243 | // Active item in a list 244 | .dl-filter-active { 245 | background-color: $color-active-light; 246 | 247 | .x-menu-item-link { 248 | border: 0; 249 | padding-left: 0; 250 | background: transparent none; 251 | } 252 | } 253 | 254 | .x-btn-default-toolbar-small { 255 | background: none; 256 | 257 | .x-btn-split-right { 258 | background-image: none; 259 | @include material-icon($mdi-chevron-down); 260 | 261 | &:before { 262 | position: absolute; 263 | right: 0; 264 | top: 3px; 265 | } 266 | } 267 | } 268 | 269 | .x-toolbar .x-toolbar-separator-horizontal { 270 | border: 0; 271 | } 272 | 273 | .help-ttip { 274 | margin-top: 5px; 275 | } 276 | 277 | hr { 278 | border-width: 1px 0 0 0; 279 | border-color: $color-border-light; 280 | } 281 | -------------------------------------------------------------------------------- /data/css/_desktop-login.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Material-Freebox-OS 3 | * Desktop - login 4 | */ 5 | 6 | // Login form, loading & restart splashes 7 | #formContent, #loadingInfo { 8 | background-color: #fff; 9 | border-radius: 2px; 10 | @extend .elevation-medium; 11 | 12 | h3 { 13 | font-family: $roboto; 14 | font-size: 18px; 15 | text-transform: none; 16 | } 17 | 18 | h5 { 19 | font-family: $roboto; 20 | font-weight: 500; 21 | font-size: 13px; 22 | border: 0; 23 | text-shadow: none; 24 | box-shadow: none; 25 | } 26 | } 27 | 28 | // Login form 29 | #login-form #formContent { 30 | .submit-btn { 31 | cursor: default; 32 | width: auto; 33 | margin-left: auto; 34 | margin-right: auto; 35 | padding: 8px 15px; 36 | background-image: none; 37 | @extend .material-button--elevated--primary; 38 | } 39 | 40 | #errorMsg { 41 | @extend .alert--danger; 42 | } 43 | } 44 | 45 | // Loading splash 46 | #loadingInfo { 47 | // Progressbar 48 | #loading { 49 | border: 0; 50 | 51 | #loadPct { 52 | padding: 2px 0; 53 | font-family: $roboto; 54 | } 55 | #loadContent { 56 | background: material-color($color-green); 57 | border-radius: 2px; 58 | } 59 | } 60 | } 61 | 62 | // Alerts 63 | #secureLogin, #browserWarning, #diskFull { 64 | font-size: 14px; 65 | @extend .elevation-low; 66 | @extend .alert--danger; 67 | 68 | a { 69 | cursor: pointer; 70 | display: table; 71 | margin: 10px auto 0 auto; 72 | @extend .material-button--flat; 73 | 74 | &, &:hover { 75 | color: #fff; 76 | } 77 | } 78 | 79 | .linklist div { 80 | margin: 0; 81 | &, &:hover { 82 | background-color: transparent; 83 | } 84 | } 85 | } 86 | 87 | // Links 88 | #resetLinks a { 89 | display: table; 90 | margin: 0 auto; 91 | cursor: pointer; 92 | @extend .material-button--flat; 93 | 94 | &, &:hover { 95 | color: #fff; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /data/css/_desktop.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Material-Freebox-OS 3 | * Desktop 4 | */ 5 | 6 | html, body { 7 | min-height: 100%; 8 | } 9 | 10 | body { 11 | margin: 0; 12 | background-image: url('../img/wallpaper1.jpg'); 13 | background-position: center; 14 | background-size: cover; 15 | } 16 | 17 | // Logo 18 | .fbxos-logo { 19 | text-align: center; 20 | 21 | &:before { 22 | content: "Freebox OS"; 23 | font-family: $roboto; 24 | font-size: 60px; 25 | color: rgba(#fff, 0.95); 26 | text-shadow: 0 0 4px rgba(#000, 0.5); 27 | } 28 | 29 | #logo_freeboxos { 30 | display: none; 31 | } 32 | 33 | .fbxos-version { 34 | right: 20px; 35 | bottom: 15px; 36 | 37 | .fbxos-version-sprite { 38 | display: none; 39 | } 40 | .fbxos-version-text { 41 | font-size: 21px; 42 | color: rgba(#fff, 0.95); 43 | text-shadow: 0 0 4px rgba(#000, 0.5); 44 | opacity: 0.6; 45 | } 46 | } 47 | } 48 | 49 | // Icons 50 | .desktop-icon-outer { 51 | height: 120px; 52 | cursor: default; 53 | 54 | .desktop-icon { 55 | width: 60px; 56 | height: 60px; 57 | margin: 5px auto 10px auto; 58 | background-color: $color-dark; 59 | color: rgba(#fff, 0.95); 60 | font-size: 42px!important; 61 | line-height: 60px; 62 | text-shadow: 1px 1px 1px rgba(#000, 0.1); 63 | border-radius: 50%; 64 | @extend .elevation-low; 65 | 66 | // Set colors 67 | @each $name, $color in $icons-colors-80-32 { 68 | &.app-icons-80-#{$name} { 69 | background-color: $color; 70 | } 71 | } 72 | 73 | // Exceptions 74 | &.app-icons-80-pvr { 75 | font-size: 60px!important; 76 | } 77 | &.app-icons-80-calls { 78 | padding-right: 5px; 79 | padding-top: 2px; 80 | } 81 | } 82 | 83 | &.desktop-selected { 84 | padding: 5px; 85 | border: 0; 86 | background-color: $color-active-dark; 87 | @extend .elevation-medium; 88 | border-radius: 2px!important; 89 | transition-duration: $timing-short; 90 | } 91 | 92 | span[aria-label] { 93 | color: rgba(#fff, 0.95); 94 | font-family: $roboto; 95 | line-height: 15px; 96 | text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.3); 97 | font-weight: 600; 98 | } 99 | } 100 | 101 | // MobileInfo 102 | #mobileInfo { 103 | border: 0; 104 | background-color: $color-dark; 105 | border-radius: 2px; 106 | @extend .elevation-low; 107 | 108 | h3 { 109 | font-family: $roboto; 110 | margin-top: 0; 111 | } 112 | 113 | .btn-cancel { 114 | color: #fff; 115 | } 116 | } 117 | 118 | // Wallpaper credits 119 | .desktop-wallpaper-credits { 120 | cursor: default; 121 | position: absolute; 122 | top: 0; 123 | right: 0; 124 | padding: 5px 0; 125 | color: #fff; 126 | font-family: $roboto; 127 | font-size: 12px; 128 | text-shadow: 1px 1px 0 rgba(#000, 0.3); 129 | text-decoration: none; 130 | opacity: 0.5; 131 | transition: rotate(-90deg); 132 | transform-origin: right bottom; 133 | transition-duration: $timing-short; 134 | transition-property: opacity; 135 | 136 | &:hover { 137 | opacity: 0.8; 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /data/css/_icons.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Material-Freebox-OS 3 | * Icons replacements 4 | * We define materialdesignicons replacement icons for "each" Freebox OS png icon 5 | */ 6 | 7 | // Icons colors 8 | // Each color should be assigned in its context when possible 9 | $icons-colors-80-32: ( 10 | settings-connectionstatus: material-color($color-amber), 11 | tv: material-color($color-red), 12 | downloader: material-color($color-purple), 13 | explorer: material-color($color-deep-purple), 14 | settings-parentalfilterconfig: material-color($color-indigo), 15 | lanbrowser: material-color($color-blue), 16 | calls: material-color($color-teal), 17 | pvr: material-color($color-green), 18 | epg: material-color($color-light-green), 19 | contacts: material-color($color-orange), 20 | settings: material-color($color-deep-orange), 21 | help: material-color($color-brown), 22 | ); 23 | 24 | $icons-colors-24: ( 25 | ); 26 | 27 | $icons-colors-16: ( 28 | help: material-color($color-blue) 29 | ); 30 | 31 | // Desktop icons (size: 80) 32 | $icons-80: ( 33 | settings-connectionstatus: $mdi-heart-pulse, // Etat de la Freebox 34 | tv: $mdi-television, // Freebox TV 35 | downloader: $mdi-cloud-download, // Téléchargements 36 | explorer: $mdi-folder, // Explorateur de fichiers 37 | settings-parentalfilterconfig: $mdi-folder-lock, // Contrôle parental 38 | lanbrowser: $mdi-lan, // Périphériques réseau 39 | calls: $mdi-phone-log, // Journal d'appels 40 | pvr: $mdi-record-rec, // Gestion des enregistrements 41 | epg: $mdi-newspaper, // Guide des programmes 42 | contacts: $mdi-contact-mail, // Contacts 43 | settings: $mdi-settings, // Paramètres de la Freebox 44 | help: $mdi-help-circle, 45 | ); 46 | 47 | // UI icons (size: 32) 48 | $icons-32: ( 49 | logout: $mdi-logout-variant, 50 | login: $mdi-login-variant, 51 | reboot: $mdi-reload, 52 | quickstart: $mdi-auto-fix, 53 | wifi-toggle-off: $mdi-wifi-off, 54 | wifi-toggle-on: $mdi-wifi, 55 | pub-toggle-off: $mdi-hexagon-outline, 56 | pub-toggle-on: $mdi-hexagon, 57 | harddisk: $mdi-harddisk, 58 | usb: $mdi-usb, 59 | lock-edit: $mdi-lock-open, 60 | wifi-calendar: $mdi-clock, 61 | delete: $mdi-delete, 62 | disk-full: $mdi-harddisk, 63 | wps: $mdi-rotate-3d, 64 | settings-connectionconfig: $mdi-settings-box, 65 | settings-connectionipv6config: $mdi-web, 66 | settings-connectiondyndns: $mdi-dns, 67 | settings-vpnserver: $mdi-vpn, 68 | settings-vpnclient: $mdi-vpn, 69 | settings-ports-portredir: $mdi-power-socket, 70 | settings-domains-domains: $mdi-web, 71 | settings-phonefxsstatus: $mdi-deskphone, 72 | settings-phonedectstatus: $mdi-cellphone-basic, 73 | settings-wizarddect: $mdi-cellphone-basic, 74 | settings-networkmode: $mdi-server-network, 75 | settings-wifi-wifi: $mdi-access-point-network, 76 | settings-wizardwifi: $mdi-access-point-network, 77 | settings-dhcp: $mdi-lan, 78 | settings-switch: $mdi-switch, 79 | settings-freeplugs: $mdi-ethernet-cable, 80 | settings-upnpigd: $mdi-server-network, 81 | settings-storage-storage: $mdi-harddisk, 82 | settings-ftp: $mdi-folder-move, 83 | settings-sharesamba: $mdi-windows, 84 | settings-shareafp: $mdi-apple, 85 | settings-airmedia: $mdi-speaker, 86 | settings-upnpav: $mdi-television-guide, 87 | settings-lcd: $mdi-television, 88 | settings-license: $mdi-message-text, 89 | settings-speedtest: $mdi-speedometer, 90 | settings-tnt: $mdi-radar, 91 | settings-accounts: $mdi-lock, 92 | settings-adblockconfig: $mdi-hexagon, 93 | settings-reset: $mdi-reload, 94 | settings-wifi-wifiguest: $mdi-account-network 95 | ); 96 | // Add $icons-80 to $icons-32 97 | $icons-32: map_merge($icons-32, $icons-80); 98 | 99 | // Toolbar icons (size: 24) 100 | $icons-24: ( 101 | add: $mdi-plus-circle, 102 | setting-tools: $mdi-settings, 103 | control-play-blue: $mdi-play-circle, 104 | control-pause-blue: $mdi-pause-circle, 105 | rss-add: $mdi-rss-box, 106 | download-stopped: $mdi-close-octagon, 107 | download-queued: $mdi-dots-horizontal, 108 | download-downloading: $mdi-download, 109 | pvr: $mdi-record-rec, 110 | epg: $mdi-newspaper 111 | ); 112 | 113 | // Toolbar icons (size: 16) 114 | $icons-16: ( 115 | folder: $mdi-folder, 116 | folder-add: $mdi-folder-plus, 117 | arrow-refresh: $mdi-refresh, 118 | share: $mdi-share, 119 | bullet-white: $mdi-checkbox-blank-circle, 120 | delete: $mdi-delete, 121 | setting-tools: $mdi-settings, 122 | vcard-add: $mdi-account-multiple-plus, 123 | export-excel: $mdi-file-export, 124 | add: $mdi-plus-circle, 125 | group-add: $mdi-account-multiple-plus, 126 | cancel: $mdi-close, 127 | save: $mdi-content-save, 128 | disk: $mdi-content-save, 129 | epg: $mdi-newspaper, 130 | help: $mdi-help-circle, 131 | accept: $mdi-check-circle, 132 | filter-add: $mdi-filter, 133 | edit: $mdi-pencil, 134 | winrar-add: $mdi-zip-box, 135 | page-copy: $mdi-content-copy, 136 | cut: $mdi-content-cut, 137 | page-paste: $mdi-content-paste, 138 | folder-delete: $mdi-delete, 139 | folder-edit: $mdi-rename-box, 140 | application: $mdi-open-in-app, 141 | properties: $mdi-information, 142 | control-play-blue: $mdi-play-circle, 143 | recycle: $mdi-autorenew, 144 | control-pause-blue: $mdi-pause-circle, 145 | magnifier: $mdi-magnify, 146 | time: $mdi-camera-timer, 147 | table-row-insert: $mdi-table-row-height, 148 | move-top: $mdi-chevron-double-up, 149 | move-up: $mdi-chevron-up, 150 | move-down: $mdi-chevron-down, 151 | move-bottom: $mdi-chevron-double-down, 152 | download-downloading: $mdi-download, 153 | download-seeding: $mdi-transfer, 154 | download-done: $mdi-check-circle, 155 | download-error: $mdi-alert-box, 156 | rss: $mdi-rss-box, 157 | rocket: $mdi-rocket, 158 | turtle: $mdi-duck, 159 | stop: $mdi-octagon, 160 | calendar-view-month: $mdi-calendar-blank, 161 | access-allowed: $mdi-check-circle, 162 | rss-add: $mdi-rss-box, 163 | rss-refresh: $mdi-rss-box, 164 | world-add: $mdi-plus-circle, 165 | page-add: $mdi-folder-plus, 166 | cog-add: $mdi-library-plus, 167 | phone-add: $mdi-phone, 168 | email-add: $mdi-email, 169 | building-add: $mdi-home-map-marker, 170 | player-quality: $mdi-quality-high, 171 | player-play: $mdi-play, 172 | player-stop: $mdi-stop, 173 | player-record: $mdi-record, 174 | player-volume: $mdi-volume-high, 175 | sound-mute: $mdi-volume-off, 176 | subtitle: $mdi-message-text, 177 | pvr: $mdi-record-rec, 178 | settings-parentalfilterconfig: $mdi-human-child, 179 | transmit: $mdi-wifi, 180 | wol: $mdi-power, 181 | system-monitor: $mdi-chart-line, 182 | drive-delete: $mdi-close-circle, 183 | table-delete: $mdi-delete, 184 | transmit-add: $mdi-plus 185 | ); 186 | 187 | // Sprite icons (no .btn- prefix) 188 | $icons-16-no-prefix: ( 189 | tel-icon-fixed: $mdi-phone, 190 | tel-icon-work: $mdi-phone, 191 | tel-icon-other: $mdi-phone, 192 | tel-icon-mobile: $mdi-cellphone, 193 | tel-icon-fax: $mdi-fax, 194 | email-icon-work: $mdi-email, 195 | email-icon-home: $mdi-email, 196 | email-icon-other: $mdi-email, 197 | address-icon-home: $mdi-home, 198 | address-icon-work: $mdi-home-modern, 199 | address-icon-other: $mdi-home, 200 | url-icon-profile: $mdi-account, 201 | url-icon-blog: $mdi-web, 202 | url-icon-site: $mdi-web, 203 | url-icon-other: $mdi-web, 204 | app-icons-16-downloader: $mdi-cloud-download, 205 | app-icons-16-settings-ports-portredir: $mdi-power-socket, 206 | app-icons-16-settings-dhcp: $mdi-lan, 207 | icon-whitelist: $mdi-playlist-check, 208 | icon-blacklist: $mdi-playlist-remove, 209 | x-hmenu-sort-asc: $mdi-sort-ascending, 210 | x-hmenu-sort-desc: $mdi-sort-descending, 211 | x-cols-icon: $mdi-view-column 212 | ); 213 | 214 | 215 | // USE ICONS DEFINITIONS 216 | // Define classes 217 | @mixin app-icon() { 218 | background: none 0; 219 | } 220 | .app-icons-16 { 221 | @include app-icon; 222 | 223 | font-size: 16px; 224 | } 225 | .app-icons-24 { 226 | @include app-icon; 227 | 228 | font-size: 24px; 229 | } 230 | .app-icons-32 { 231 | @include app-icon; 232 | 233 | color: $color-icon-dark; 234 | font-size: 28px; 235 | } 236 | .app-icons-80 { 237 | @include app-icon; 238 | 239 | display: block!important; 240 | font-size: 60px!important; 241 | } 242 | 243 | // Set icons 244 | // Desktop icons (80) 245 | .desktop-icon { 246 | @extend .app-icons-80; 247 | 248 | @each $name, $mdi in $icons-80 { 249 | &.app-icons-80-#{$name} { 250 | @include material-icon($mdi); 251 | } 252 | } 253 | } 254 | 255 | // UI icons (32) 256 | @each $name, $mdi in $icons-32 { 257 | $selector-suffix: "32-#{$name}:not(img)"; 258 | 259 | .btn-#{$selector-suffix}, .app-icons-#{$selector-suffix} { 260 | @extend .app-icons-32; 261 | @include material-icon($mdi); 262 | } 263 | } 264 | 265 | // Toolbar icons (24) 266 | @each $name, $mdi in $icons-24 { 267 | $selector: ".btn-24-#{$name}:not(img)"; 268 | 269 | #{$selector}, 270 | .x-btn-icon-text-right #{$selector}, 271 | .x-btn-icon-text-left #{$selector} { 272 | @extend .app-icons-24; 273 | @include material-icon($mdi); 274 | } 275 | } 276 | 277 | // Toolbar icons (16) 278 | @each $name, $mdi in $icons-16 { 279 | $selector: ".btn-#{$name}:not(img)"; 280 | 281 | #{$selector}, 282 | .x-btn-icon-text-right #{$selector}, 283 | .x-btn-icon-text-left #{$selector} { 284 | @extend .app-icons-16; 285 | @include material-icon($mdi); 286 | } 287 | } 288 | @each $name, $mdi in $icons-16-no-prefix { 289 | $selector: ".#{$name}:not(img)"; 290 | 291 | #{$selector} { 292 | @extend .app-icons-16; 293 | @include material-icon($mdi); 294 | } 295 | } 296 | 297 | // Set colors 298 | // Toolbar icons (size: 24) 299 | @each $name, $color in $icons-colors-24 { 300 | $selector: ".btn-24-#{$name}:not(img)"; 301 | 302 | #{$selector}, 303 | .x-btn-icon-text-right #{$selector}, 304 | .x-btn-icon-text-left #{$selector} { 305 | color: $color; 306 | } 307 | } 308 | 309 | // Toolbar icons (16) 310 | @each $name, $color in $icons-colors-16 { 311 | $selector: ".btn-#{$name}:not(img)"; 312 | 313 | #{$selector}, 314 | .x-btn-icon-text-right #{$selector}, 315 | .x-btn-icon-text-left #{$selector} { 316 | color: $color; 317 | } 318 | } 319 | 320 | 321 | // Separate icons 322 | .x-message-box-question, .x-message-box-warning { 323 | font-size: 35px; 324 | color: $color-text-dark; 325 | background-image: none; 326 | } 327 | .x-message-box-question { 328 | color: $color-alert-info; 329 | @include material-icon($mdi-comment-question-outline); 330 | } 331 | .x-message-box-warning { 332 | color: $color-alert-warning; 333 | @include material-icon($mdi-alert-circle); 334 | } 335 | -------------------------------------------------------------------------------- /data/css/_inputs.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Material-Freebox-OS 3 | * Inputs styling 4 | */ 5 | 6 | // Default button 7 | .x-btn-default-small { 8 | @extend .material-button--elevated--primary; 9 | } 10 | 11 | // Radio, checkbox 12 | .x-form-checkbox, 13 | .x-form-radio { 14 | width: 16px; 15 | height: 16px; 16 | background: none no-repeat -1px -2px; 17 | border: 2px solid $color-input-border; 18 | transition-duration: $timing-medium; 19 | } 20 | .x-form-checkbox { 21 | border-radius: 2px; 22 | } 23 | .x-form-radio { 24 | margin-top: 3px; 25 | margin-right: 3px; 26 | border-radius: 50%; 27 | box-shadow: inset 0 0 0 8px #fff; 28 | } 29 | .x-form-cb-checked { 30 | .x-form-checkbox { 31 | border-width: 2px; 32 | border-style: solid; 33 | @extend .accent-color--border; 34 | 35 | background-image: url('../img/mdi-check.png'); 36 | background-position: -1px -2px; 37 | @extend .accent-color--background; 38 | } 39 | .x-form-radio { 40 | @extend .accent-color--background; 41 | box-shadow: inset 0 0 0 2px #fff; 42 | } 43 | } 44 | 45 | // Fieldset 46 | fieldset.x-fieldset { 47 | position: relative; 48 | padding-top: 22px!important; 49 | padding-left: 14px!important; 50 | border-color: $color-input-border; 51 | border-width: 0 0 0 1px; 52 | margin: 10px 0 20px 0; 53 | 54 | legend.x-fieldset-header { 55 | position: absolute; 56 | top: 2px; 57 | padding: 0; 58 | 59 | .x-fieldset-header-text { 60 | font-family: $roboto; 61 | font-weight: 600; 62 | font-size: 14px; 63 | @extend .accent-color--dark--color; 64 | } 65 | } 66 | } 67 | 68 | // Label, simple text value 69 | .x-form-item-label, .x-form-display-field { 70 | font-family: $roboto; 71 | margin-top: 8px; 72 | } 73 | 74 | // Text input 75 | .x-form-text { 76 | background-image: none; 77 | padding: 0 8px; 78 | height: 28px; 79 | font-family: $roboto; 80 | 81 | &.x-field-form-focus { 82 | @extend .accent-color--border; 83 | } 84 | &.x-form-invalid-field { 85 | color: material-color($color-red); 86 | background-image: none!important; 87 | border-bottom: 1px solid material-color($color-red)!important; 88 | } 89 | 90 | &.x-form-textarea { 91 | height: auto; 92 | padding: 4px 8px; 93 | } 94 | } 95 | 96 | // Shared styling between text input & combobox 97 | .x-form-text, .x-form-trigger-wrap { 98 | border: 1px solid $color-input-border; 99 | border-radius: 2px; 100 | transition-property: box-shadow, background-color, border-color; 101 | transition-duration: $timing-short; 102 | 103 | &:hover { 104 | background-color: rgba(#000, 0.01); 105 | @extend .elevation-tiny; 106 | } 107 | } 108 | // Input inside combobox: no hover effect { 109 | .x-form-trigger-wrap .x-form-text:hover { 110 | @extend .elevation-none; 111 | } 112 | 113 | // Combobox, numeric field 114 | .x-form-trigger-wrap { 115 | .x-form-field { 116 | padding: 0 8px; 117 | height: 28px; 118 | border: 0; 119 | background-color: transparent!important; 120 | font-family: $roboto; 121 | 122 | // Invalid value 123 | &.x-form-invalid-field { 124 | border-radius: 0; 125 | } 126 | } 127 | .x-form-field[role="combobox"] { 128 | user-select: none; 129 | } 130 | 131 | // Right buttons 132 | .x-form-arrow-trigger, 133 | .x-form-time-trigger, 134 | .x-form-spinner-up, 135 | .x-form-spinner-down { 136 | background: none; 137 | border: 0; 138 | 139 | // Dropdown chevron-down button 140 | &.x-form-arrow-trigger, 141 | &.x-form-time-trigger { 142 | @include material-icon($mdi-chevron-down); 143 | 144 | &:before { 145 | position: absolute; 146 | top: 8px; 147 | } 148 | } 149 | 150 | // Up/down numeric value buttons 151 | &.x-form-spinner-up, 152 | &.x-form-spinner-down { 153 | text-align: center; 154 | padding-top: 1px; 155 | 156 | &.x-form-spinner-up { @include material-icon($mdi-chevron-up); } 157 | &.x-form-spinner-down { @include material-icon($mdi-chevron-down); } 158 | } 159 | } 160 | } 161 | // Focus state 162 | .x-form-trigger-wrap-focus .x-form-trigger-wrap { 163 | @extend .accent-color--border; 164 | } 165 | 166 | // Combobox inside window toolbar (primary-color background) 167 | .x-toolbar-docked-top .x-form-trigger-wrap { 168 | border-color: $color-border-light; 169 | 170 | .x-form-text { 171 | color: #fff; 172 | } 173 | } 174 | 175 | // Combobox items list 176 | .x-boundlist { 177 | border: 0; 178 | border-radius: 2px; 179 | @extend .elevation-lowest; 180 | 181 | .x-list-plain { 182 | padding: 3px 0; 183 | 184 | .x-boundlist-item { 185 | cursor: default; 186 | padding: 5px 10px; 187 | border: 0; 188 | font-family: $roboto; 189 | transition-property: background; 190 | transition-duration: $timing-short; 191 | border-radius: 0; 192 | 193 | &.x-boundlist-item-over { 194 | background: $color-hover-light; 195 | } 196 | &.x-boundlist-selected { 197 | background: $color-active-light; 198 | } 199 | } 200 | } 201 | } 202 | 203 | // Slider 204 | .x-slider { 205 | height: 2px; 206 | background-image: none; 207 | @extend .accent-color--background; 208 | 209 | .x-slider-end { 210 | background: none; 211 | 212 | .x-slider-inner { 213 | background: none; 214 | 215 | .x-slider-thumb { 216 | cursor: pointer; 217 | margin-top: -5px; 218 | background: #fff none; 219 | border-width: 1px; 220 | border-style: solid; 221 | @extend .accent-color--border; 222 | border-radius: 50%; 223 | width: 14px; 224 | height: 14px; 225 | @extend .elevation-tiny; 226 | transition-property: width, height, margin; 227 | transition-duration: $timing-short; 228 | 229 | &.x-slider-thumb-drag { 230 | width: 16px; 231 | height: 16px; 232 | margin-top: -6px; 233 | margin-left: -8px; 234 | @extend .elevation-lowest; 235 | } 236 | } 237 | } 238 | } 239 | } 240 | 241 | .x-form-trigger { 242 | cursor: default; 243 | 244 | &.x-form-clear-trigger, 245 | &.x-form-search-trigger, 246 | &.x-form-date-trigger { 247 | background: none; 248 | border: 0; 249 | height: 24px; 250 | line-height: 28px; 251 | font-size: 16px; 252 | color: $color-text-dark; 253 | } 254 | 255 | &.x-form-clear-trigger { 256 | font-size: 13px; 257 | @include material-icon($mdi-close-circle); 258 | } 259 | &.x-form-search-trigger { 260 | @include material-icon($mdi-magnify); 261 | } 262 | &.x-form-date-trigger { 263 | @include material-icon($mdi-calendar); 264 | } 265 | } 266 | -------------------------------------------------------------------------------- /data/css/_material-buttons.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Material-Freebox-OS 3 | * Material buttons 4 | */ 5 | 6 | // Buttons 7 | .material-button { 8 | cursor: default; 9 | font-family: $roboto; 10 | border: 0; 11 | padding: 5px 10px; 12 | margin: 3px 1px; 13 | transition-property: background, box-shadow; 14 | transition-duration: $timing-short; 15 | border-radius: 2px!important; 16 | box-shadow: none; 17 | 18 | .x-btn-inner { 19 | color: #333; 20 | font-family: $roboto; 21 | text-transform: uppercase; 22 | font-size: 12px; 23 | white-space: nowrap; 24 | font-weight: 600; 25 | } 26 | 27 | &:hover { 28 | text-decoration: none; 29 | } 30 | } 31 | 32 | .material-button--flat { 33 | @extend .material-button; 34 | 35 | border: 0!important; 36 | background-color: transparent; 37 | 38 | .x-btn-inner, .x-btn-icon-el { 39 | color: #000; 40 | font-weight: 500; 41 | } 42 | 43 | &:hover { 44 | background-color: $color-hover-light; 45 | } 46 | &:active, &.x-btn-pressed { 47 | background-color: $color-active-light; 48 | 49 | color: #000; 50 | } 51 | } 52 | 53 | .material-button--elevated { 54 | @extend .material-button; 55 | 56 | background-color: rgba(0, 0, 0, 0.05); 57 | border: 1px solid rgba(0, 0, 0, 0.15) !important; 58 | 59 | .x-btn-inner { 60 | color: #000; 61 | } 62 | 63 | &:hover { 64 | background-color: $color-hover-light; 65 | box-shadow: $elevation-1; 66 | } 67 | 68 | &:active, &.x-btn-pressed { 69 | background-color: $color-active-light; 70 | box-shadow: $elevation-negative; 71 | 72 | .x-btn-icon-el { 73 | color: #000; 74 | } 75 | } 76 | } 77 | 78 | .material-button--flat--primary { 79 | @extend .accent-color--background; 80 | @extend .material-button--flat; 81 | } 82 | .material-button--elevated--primary { 83 | @extend .accent-color--background; 84 | @extend .material-button--elevated; 85 | } 86 | 87 | .material-button--flat--primary, 88 | .material-button--elevated--primary { 89 | @extend .accent-color--background; 90 | 91 | &:hover { 92 | @extend .accent-color--hover--background; 93 | } 94 | 95 | .x-btn-inner, .x-btn-icon-el { 96 | color: #fff; 97 | } 98 | &:active, &.x-btn-pressed { 99 | @extend .accent-color--active--background--important; 100 | 101 | .x-btn-icon-el { 102 | color: #fff; 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /data/css/_material.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Material-Freebox-OS 3 | * Material variables & classes 4 | */ 5 | 6 | // Font 7 | $roboto: Roboto, sans-serif; 8 | 9 | 10 | // Colors 11 | $color-red: ( 500: #F44336, 600: #E53935, 700: #D32F2F, 800: #C62828, 900: #B71C1C ); 12 | $color-pink: ( 500: #E91E63, 600: #D81B60, 700: #C2185B, 800: #AD1457, 900: #880E4F ); 13 | $color-purple: ( 500: #9C27B0, 600: #8E24AA, 700: #7B1FA2, 800: #6A1B9A, 900: #4A148C ); 14 | $color-deep-purple: ( 500: #673AB7, 600: #5E35B1, 700: #512DA8, 800: #4527A0, 900: #311B92 ); 15 | $color-indigo: ( 500: #3F51B5, 600: #3949AB, 700: #303F9F, 800: #283593, 900: #1A237E ); 16 | $color-blue: ( 500: #2196F3, 600: #1E88E5, 700: #1976D2, 800: #1565C0, 900: #0D47A1 ); 17 | $color-light-blue: ( 500: #03A9F4, 600: #039BE5, 700: #0288D1, 800: #0277BD, 900: #01579B ); 18 | $color-cyan: ( 500: #00BCD4, 600: #00ACC1, 700: #0097A7, 800: #00838F, 900: #006064 ); 19 | $color-teal: ( 500: #009688, 600: #00897B, 700: #00796B, 800: #00695C, 900: #004D40 ); 20 | $color-green: ( 500: #4CAF50, 600: #43A047, 700: #388E3C, 800: #2E7D32, 900: #1B5E20 ); 21 | $color-light-green: ( 500: #8BC34A, 600: #7CB342, 700: #689F38, 800: #558B2F, 900: #33691E ); 22 | $color-lime: ( 500: #CDDC39, 600: #C0CA33, 700: #AFB42B, 800: #9E9D24, 900: #827717 ); 23 | $color-yellow: ( 500: #FFEB3B, 600: #FDD835, 700: #FBC02D, 800: #F9A825, 900: #F57F17 ); 24 | $color-amber: ( 500: #FFC107, 600: #FFB300, 700: #FFA000, 800: #FF8F00, 900: #FF6F00 ); 25 | $color-orange: ( 500: #FF9800, 600: #FB8C00, 700: #F57C00, 800: #EF6C00, 900: #E65100 ); 26 | $color-deep-orange: ( 500: #FF5722, 600: #F4511E, 700: #E64A19, 800: #D84315, 900: #BF360C ); 27 | $color-brown: ( 500: #795548, 600: #6D4C41, 700: #5D4037, 800: #4E342E, 900: #3E2723 ); 28 | $color-grey: ( 500: #9E9E9E, 600: #757575, 700: #616161, 800: #424242, 900: #212121 ); 29 | $color-blue-grey: ( 500: #607D8B, 600: #546E7A, 700: #455A64, 800: #37474F, 900: #263238 ); 30 | 31 | @function material-color($color, $hue:500) { 32 | @return map-get($color, $hue); 33 | } 34 | 35 | // Primary & accent colors 36 | $material-colors: ( 37 | 'red': $color-red, 38 | 'pink': $color-pink, 39 | 'purple': $color-purple, 40 | 'deep-purple': $color-deep-purple, 41 | 'indigo': $color-indigo, 42 | 'blue': $color-blue, 43 | 'light-blue': $color-light-blue, 44 | 'cyan': $color-cyan, 45 | 'teal': $color-teal, 46 | 'green': $color-green, 47 | 'light-green': $color-light-green, 48 | 'lime': $color-lime, 49 | 'yellow': $color-yellow, 50 | 'amber': $color-amber, 51 | 'orange': $color-orange, 52 | 'deep-orange': $color-deep-orange, 53 | 'brown': $color-brown, 54 | 'grey': $color-grey, 55 | 'blue-grey': $color-blue-grey 56 | ); 57 | 58 | @each $color-name, $color-hexes in $material-colors { 59 | $color-500: material-color($color-hexes, 500); 60 | $color-600: material-color($color-hexes, 600); 61 | $color-700: material-color($color-hexes, 700); 62 | $color-800: material-color($color-hexes, 800); 63 | $color-900: material-color($color-hexes, 900); 64 | 65 | @each $color-type in ('primary', 'accent') { 66 | $selector: 'body[data-color-#{$color-type}="#{$color-500}"]'; 67 | 68 | #{$selector} { 69 | $color: $color-500; 70 | $color-hover: $color-600; 71 | $color-dark: $color-700; 72 | $color-active: $color-800; 73 | 74 | @each $modifier, $color in ( 75 | '': $color, 76 | '--hover': $color-hover, 77 | '--dark': $color-dark, 78 | '--active': $color-active 79 | ) { 80 | .#{$color-type}-color#{$modifier}--color { color: $color!important; } 81 | .#{$color-type}-color#{$modifier}--border { border-color: $color!important; } 82 | .#{$color-type}-color#{$modifier}--background { background-color: $color; } 83 | .#{$color-type}-color#{$modifier}--background--important { background-color: $color!important; } 84 | } 85 | } 86 | } 87 | } 88 | 89 | 90 | $color-dark: #303030; 91 | $color-text-dark: rgba(#000, 0.87); 92 | $color-border-light: rgba(#fff, 0.5); 93 | 94 | $color-icon-dark: #444444; 95 | 96 | $color-input-border: rgba(#000, 0.2); 97 | 98 | $color-hover-light: rgba(#000, 0.1); 99 | $color-active-light: rgba(#000, 0.2); 100 | $color-hover-dark: rgba(#000, 0.7); 101 | $color-active-dark: rgba(#000, 0.85); 102 | 103 | $color-alert-info: #0AB1FC; 104 | $color-alert-success: #55B559; 105 | $color-alert-warning: #FBC53C; 106 | $color-alert-danger: $color-red; 107 | 108 | $color-background-light: #FAFAFA; 109 | 110 | $typography-label-font-weight: 600; 111 | $typography-label-color: rgba(#000, 0.7); 112 | $typography-label-font-size: 12px; 113 | 114 | 115 | // Elevation 116 | $elevation-tiny: 0 1px 1px rgba(0,0,0,0.1); 117 | $elevation-1: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24); 118 | $elevation-2: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23); 119 | $elevation-3: 0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23); 120 | $elevation-4: 0 14px 28px rgba(0,0,0,0.25), 0 10px 10px rgba(0,0,0,0.22); 121 | $elevation-5: 0 19px 38px rgba(0,0,0,0.30), 0 15px 12px rgba(0,0,0,0.22); 122 | $elevation-negative: inset 1px 1px 1px rgba(0, 0, 0, 0.1); 123 | 124 | .elevation-tiny { box-shadow: $elevation-tiny; } 125 | .elevation-1, .elevation-lowest { box-shadow: $elevation-1; } 126 | .elevation-2, .elevation-low { box-shadow: $elevation-2; } 127 | .elevation-3, .elevation-medium { box-shadow: $elevation-3; } 128 | .elevation-4, .elevation-high { box-shadow: $elevation-4; } 129 | .elevation-5, .elevation-highest { box-shadow: $elevation-5; } 130 | .elevation-negative { box-shadow: $elevation-negative; } 131 | .elevation-none { box-shadow: none; } 132 | 133 | 134 | // Animations duration 135 | $timing-short: 150ms; 136 | $timing-medium: 250ms; 137 | $timing-long: 350ms; 138 | 139 | 140 | // Slight border 141 | $slight-border-top: inset 0 1px 0 0px rgba(0, 0, 0, 0.2); 142 | $slight-border-right: inset -1px 0 0 0px rgba(0, 0, 0, 0.2); 143 | $slight-border-bottom: inset 0 -1px 0 0px rgba(0, 0, 0, 0.2); 144 | $slight-border-left: inset 1px 0 0 0px rgba(0, 0, 0, 0.2); 145 | 146 | 147 | // Alerts 148 | .alert { 149 | font-family: $roboto; 150 | color: #ffffff; 151 | border: 0; 152 | border-radius: 2px; 153 | } 154 | .alert--info { 155 | @extend .alert; 156 | background-color: $color-alert-info; 157 | } 158 | .alert--success { 159 | @extend .alert; 160 | background-color: $color-alert-success; 161 | } 162 | .alert--warning { 163 | @extend .alert; 164 | background-color: $color-alert-warning; 165 | } 166 | .alert--danger { 167 | @extend .alert; 168 | background-color: material-color($color-red); 169 | } 170 | -------------------------------------------------------------------------------- /data/css/_toolbar.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Material-Freebox-OS 3 | * Toolbar 4 | */ 5 | 6 | .freeboxos-southbar.x-toolbar { 7 | border: 0!important; 8 | padding: 0; 9 | background: transparent!important; 10 | transition-property: background; 11 | transition-duration: $timing-short; 12 | 13 | &.solid-background { 14 | background: $color-dark!important; 15 | box-shadow: 0 0 8px -1px rgba(#000, 0.8); 16 | } 17 | 18 | // "Start" button 19 | .btn-start { 20 | padding: 6px 0 0 10px; 21 | margin-right: 20px; 22 | background: none!important; 23 | width: auto!important; 24 | 25 | .x-btn-button { 26 | $size: 34px; 27 | width: $size!important; 28 | height: $size!important; 29 | padding: 0; 30 | font-size: 19px; 31 | color: rgba(#fff, 0.9); 32 | border-radius: 50%; 33 | text-align: center; 34 | background: rgba(#000, 0.65); 35 | transition-property: color, background-color; 36 | transition-duration: $timing-short; 37 | text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.2); 38 | 39 | @include material-icon($mdi-checkbox-blank-circle-outline); 40 | 41 | &:hover { 42 | color: #fff; 43 | background: rgba(#000, 0.75) none !important; 44 | } 45 | &:before { 46 | line-height: $size; 47 | } 48 | } 49 | &.x-menu-active .x-btn-button { 50 | @extend .primary-color--background--important; 51 | } 52 | } 53 | 54 | // Windows list 55 | .x-btn.fbx-taskbar { 56 | background: none!important; 57 | border: none!important; 58 | border-bottom: 2px solid transparent!important; 59 | border-radius: 0; 60 | transition-duration: $timing-short; 61 | 62 | // Let shadow go outside the container 63 | .x-btn-button { 64 | overflow: visible; 65 | } 66 | 67 | .x-btn-wrap { 68 | .x-btn-inner { 69 | font-family: $roboto; 70 | font-size: 13px; 71 | padding-left: 40px; 72 | padding-right: 10px; 73 | text-overflow: ellipsis; 74 | text-shadow: 1px 1px 1px rgba(#000, 0.3); 75 | } 76 | .x-btn-icon-el { 77 | padding-left: 4px; 78 | font-size: 24px; 79 | line-height: 32px; 80 | color: #fff; 81 | text-shadow: 1px 1px 1px rgba(#000, 0.3); 82 | border-radius: 50%; 83 | @extend .elevation-lowest; 84 | 85 | // Default background color 86 | @extend .accent-color--background; 87 | 88 | // Override for specific icons 89 | @each $name, $color in $icons-colors-80-32 { 90 | &.app-icons-32-#{$name} { 91 | background-color: $color!important; 92 | } 93 | } 94 | } 95 | } 96 | 97 | &.x-pressed { 98 | border-color: rgba(#fff, 0.9)!important; 99 | } 100 | } 101 | // No icon elevation with solid background 102 | &.solid-background .x-btn.fbx-taskbar .x-btn-wrap .x-btn-icon-el { 103 | @extend .elevation-none; 104 | } 105 | 106 | // Right icons 107 | // Loading indicator 108 | .taskbar-activity-btn { 109 | background-color: transparent!important; 110 | border-width: 0!important; 111 | padding: 0; 112 | box-shadow: none!important; 113 | 114 | .x-btn-icon-el { 115 | font-size: 28px; 116 | margin-top: 8px; 117 | color: rgba(#fff, 0.9); 118 | background-image: none!important; 119 | @include material-icon($mdi-cached); 120 | } 121 | } 122 | // Standard icon (wifi, adblock) 123 | .x-icon .x-btn-icon-el { 124 | margin-top: 5px; 125 | color: rgba(#fff, 0.9); 126 | text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.2); 127 | 128 | // Disk full icon 129 | &.btn-32-disk-full { 130 | margin-top: 4px; 131 | color: material-color($color-red); 132 | } 133 | } 134 | 135 | // Clock 136 | .clock-display-field { 137 | .x-form-display-field { 138 | cursor: default; 139 | padding: 4px 1px; 140 | margin: 14px 6px; 141 | border-radius: 2px; 142 | background-color: rgba(0, 0, 0, 0.4); 143 | font-family: $roboto; 144 | font-size: 14px; 145 | color: #ffffff!important; 146 | font-weight: 600; 147 | } 148 | } 149 | } 150 | 151 | // Apps list (start menu) 152 | .fbx-start-menu { 153 | border-color: transparent; 154 | border-radius: 2px; 155 | @extend .elevation-low; 156 | 157 | .x-menu-body { 158 | border: 0; 159 | background: #fff; 160 | background-image: none!important; 161 | 162 | .x-menu-item { 163 | border-radius: 0; 164 | 165 | .x-menu-item-link { 166 | transition-property: background; 167 | transition-duration: $timing-short; 168 | 169 | .x-menu-item-text { 170 | font-size: 14px; 171 | font-family: $roboto; 172 | line-height: 34px; 173 | } 174 | 175 | .x-menu-item-icon { 176 | top: 6px!important; 177 | 178 | // Set colors 179 | @each $name, $color in $icons-colors-80-32 { 180 | &.app-icons-32-#{$name} { 181 | color: $color; 182 | } 183 | } 184 | } 185 | 186 | .x-menu-item-arrow { 187 | background-image: none; 188 | font-size: 20px!important; 189 | color: #333; 190 | top: 12px; 191 | right: 10px; 192 | 193 | @include material-icon($mdi-chevron-right); 194 | } 195 | } 196 | 197 | &.x-menu-item-active { 198 | background: $color-hover-dark !important; 199 | 200 | .x-menu-item-link { 201 | background: transparent; 202 | 203 | .x-menu-item-icon { 204 | color: #fff; 205 | } 206 | 207 | .x-menu-item-arrow { 208 | right: 10px; 209 | color: #eee!important; 210 | } 211 | } 212 | } 213 | 214 | &.grayscale { 215 | opacity: 0.5; 216 | 217 | 218 | a, a .x-menu-item-text { 219 | cursor: default; 220 | } 221 | } 222 | } 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /data/css/_window.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Material-Freebox-OS 3 | * Windows 4 | */ 5 | 6 | .x-css-shadow { 7 | box-shadow: none!important; 8 | } 9 | 10 | .x-window { 11 | $shadow-base: 0 0 1px rgba(0, 0, 0, 0.5), 12 | 0 3px rgba(0, 0, 0, 0.1); 13 | 14 | padding: 0!important; 15 | border: 0!important; 16 | border-radius: 2px!important; 17 | transition-property: box-shadow; 18 | transition-duration: $timing-short; 19 | box-shadow: $shadow-base, $elevation-3; 20 | 21 | // Blur / focus states 22 | &.x-window-focus-blurred { 23 | box-shadow: $shadow-base; 24 | 25 | .x-window-header .x-window-header-body { 26 | opacity: 0.3; 27 | } 28 | } 29 | &.x-window-focus-focused { } 30 | 31 | .x-window-header { 32 | $window-header-padding-top: 12px; 33 | $window-header-padding-bottom: 7px; 34 | 35 | padding: 0 0 0 10px; 36 | border: 0; 37 | border-radius: 2px 2px 0 0; 38 | @extend .primary-color--dark--background--important; 39 | 40 | .x-window-header-body { 41 | cursor: default; 42 | background: transparent; 43 | transition-property: opacity; 44 | transition-duration: $timing-short; 45 | 46 | // Hide window icon 47 | .x-window-header-icon { 48 | display: none; 49 | } 50 | 51 | // Text 52 | .x-window-header-text-container { 53 | font-family: $roboto; 54 | font-weight: 500; 55 | font-size: 14px; 56 | text-shadow: none; 57 | margin-top: $window-header-padding-top; 58 | margin-bottom: $window-header-padding-bottom; 59 | 60 | &, .x-header-text { 61 | color: rgba(255, 255, 255, 0.9); 62 | } 63 | } 64 | 65 | // Buttons 66 | .x-box-item.x-tool-after-title { 67 | cursor: default; 68 | font-size: 18px!important; 69 | color: rgba(#fff, 0.95); 70 | transition-duration: $timing-short; 71 | transition-property: color; 72 | 73 | $window-icons: ( 74 | "Fermer": $mdi-close, 75 | "Maximiser": $mdi-window-maximize, 76 | "restorer": $mdi-window-restore, 77 | "Minimiser": $mdi-window-minimize, 78 | "Aide de l'application": $mdi-help 79 | ); 80 | 81 | @each $name, $mdi in $window-icons { 82 | &[aria-label="#{$name}"] { 83 | padding-top: 8px; 84 | text-align: center; 85 | @include material-icon($mdi); 86 | } 87 | } 88 | 89 | // Special cases 90 | &[aria-label="Minimiser"] { padding-top: 14px; font-size: 15px!important; } 91 | &[aria-label="Aide de l'application"] { font-size: 16px!important; } 92 | 93 | 94 | .x-tool-close, .x-tool-restore, .x-tool-maximize, .x-tool-minimize, .x-tool-help { 95 | display: none; 96 | } 97 | 98 | &:hover { 99 | color: rgba(#fff, 1); 100 | background-color: rgba(0, 0, 0, 0.06); 101 | } 102 | &:active { 103 | color: rgba(#fff, 0.95); 104 | background-color: rgba(0, 0, 0, 0.08); 105 | } 106 | } 107 | } 108 | } 109 | 110 | .x-window-body { 111 | @extend .primary-color--background; 112 | 113 | &, .x-header .x-tab-bar-body, .x-toolbar-docked-top { 114 | padding: 0; 115 | box-shadow: 0 1px 3px 0 rgba(#000, 0.2); 116 | @extend .primary-color--background--important; 117 | } 118 | 119 | .x-header { 120 | .x-tab-bar-strip { 121 | height: 0; 122 | border: 0; 123 | } 124 | } 125 | 126 | // Top toolbar 127 | .x-toolbar-docked-top { 128 | .x-btn { 129 | cursor: default; 130 | border: 0!important; 131 | padding: 14px 10px; 132 | border-radius: 0; 133 | transition-property: background; 134 | transition-duration: $timing-short; 135 | 136 | .x-btn-arrow { 137 | background: none; 138 | padding-right: 0; 139 | font-size: 16px; 140 | @include material-icon($mdi-chevron-down); 141 | 142 | &:before { 143 | float: right; 144 | margin-left: 5px; 145 | } 146 | } 147 | 148 | &.x-btn-default-toolbar-medium { 149 | .x-btn-arrow:before { 150 | margin-top: 4px; 151 | } 152 | } 153 | 154 | .x-btn-inner { 155 | font-family: $roboto; 156 | font-size: 12px; 157 | font-weight: 500; 158 | } 159 | 160 | &:hover { 161 | border: 0!important; 162 | background: $color-hover-light !important; 163 | 164 | .x-btn-inner { 165 | color: #fff; 166 | } 167 | } 168 | 169 | &.x-btn-menu-active { 170 | background: $color-active-light !important; 171 | } 172 | } 173 | 174 | .x-toolbar-separator-horizontal { 175 | border: 0; 176 | } 177 | } 178 | 179 | // Default background color 180 | .x-border-layout-ct { 181 | background-color: #fff; 182 | } 183 | 184 | iframe { 185 | border: 0; 186 | } 187 | } 188 | 189 | // Bottom toolbar 190 | .x-toolbar-docked-bottom { 191 | margin-right: 0; 192 | padding-right: 4px; 193 | padding-bottom: 4px; 194 | 195 | &.x-toolbar-default { 196 | @extend .primary-color--dark--background--important; 197 | } 198 | 199 | .x-btn { 200 | @extend .material-button--flat--primary; 201 | } 202 | } 203 | 204 | // Bottom toolbar on white background 205 | .x-panel .x-toolbar-docked-bottom { 206 | .x-btn { 207 | @extend .material-button--flat--primary; 208 | } 209 | } 210 | 211 | .x-splitter { 212 | background-color: rgba(#000, 0.2); 213 | transition-duration: $timing-short; 214 | transition-property: box-shadow; 215 | 216 | &:hover { 217 | box-shadow: inset 0 0 1px rgba(#000, 0.8); 218 | } 219 | } 220 | } 221 | 222 | // Messagebox 223 | .x-message-box { 224 | .x-window-body .x-box-inner, .x-toolbar-footer { 225 | background-color: #fff!important; 226 | } 227 | 228 | .x-window-body { 229 | box-shadow: none; 230 | } 231 | .x-toolbar-footer { 232 | margin-top: 0; 233 | 234 | .x-btn { 235 | @extend .material-button--flat--primary; 236 | } 237 | } 238 | } 239 | 240 | .x-panel-body { 241 | border: 0; 242 | } 243 | -------------------------------------------------------------------------------- /data/css/fonts/_fonts-mixins.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Material-Freebox-OS 3 | * Fonts declaration generation 4 | * Inspired from https://github.com/FontFaceKit/roboto 5 | */ 6 | 7 | // Define font-definition mixin 8 | @mixin font-definition($woff-base64, $woff2-base64) { 9 | src: url(data:application/x-font-woff2;charset:utf-8;base64,#{$woff2-base64}) format('woff2'), 10 | url(data:application/x-font-woff;charset:utf-8;base64,#{$woff-base64}) format('woff'); 11 | } 12 | -------------------------------------------------------------------------------- /data/css/fonts/materialdesignicons.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Material-Freebox-OS 3 | * MaterialDesignIcons font definition 4 | * Inspired from https://github.com/FontFaceKit/roboto 5 | */ 6 | 7 | @import 'fonts-mixins'; 8 | 9 | // Import base64 definitions 10 | @import 'materialdesignicons-woff'; 11 | @import 'materialdesignicons-woff2'; 12 | 13 | @font-face { 14 | font-family: "Material Design Icons"; 15 | @include font-definition($materialdesignicons-woff, $materialdesignicons-woff2); 16 | font-weight: normal; 17 | font-style: normal; 18 | } 19 | 20 | .mdi { 21 | display: inline-block; 22 | font: normal normal normal 24px/1 "Material Design Icons"; 23 | font-size: inherit; 24 | text-rendering: auto; 25 | -webkit-font-smoothing: antialiased; 26 | -moz-osx-font-smoothing: grayscale; 27 | transform: translate(0, 0); 28 | } 29 | -------------------------------------------------------------------------------- /data/css/fonts/roboto.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Material-Freebox-OS 3 | * Roboto font definition 4 | * Inspired from https://github.com/FontFaceKit/roboto 5 | */ 6 | 7 | @import 'fonts-mixins'; 8 | 9 | // Import base64 definitions 10 | @import 'roboto-light-woff'; 11 | @import 'roboto-light-woff2'; 12 | @import 'roboto-regular-woff'; 13 | @import 'roboto-regular-woff2'; 14 | @import 'roboto-medium-woff'; 15 | @import 'roboto-medium-woff2'; 16 | 17 | // Declare fonts 18 | // Light (400) 19 | @font-face { 20 | font-family: Roboto; 21 | @include font-definition($roboto-light-woff, $roboto-light-woff2); 22 | font-weight: 300; 23 | font-style: normal; 24 | } 25 | 26 | // Regular 27 | @font-face { 28 | font-family: Roboto; 29 | @include font-definition($roboto-regular-woff, $roboto-regular-woff2); 30 | font-weight: 400; 31 | font-style: normal; 32 | } 33 | @font-face { 34 | font-family: Roboto; 35 | @include font-definition($roboto-regular-woff, $roboto-regular-woff2); 36 | font-weight: normal; 37 | font-style: normal; 38 | } 39 | 40 | // Medium (500) 41 | /*@font-face { 42 | font-family: Roboto; 43 | @include font-definition($roboto-medium-woff, $roboto-medium-woff2); 44 | font-weight: 500; 45 | font-style: normal; 46 | }*/ 47 | -------------------------------------------------------------------------------- /data/css/style.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Material-Freebox-OS 3 | */ 4 | 5 | // Import part files 6 | // Bower materialdesignicons-scss-variables dependency 7 | @import '../../bower_components/materialdesignicons-scss-variables/dist/materialdesignicons'; 8 | @import '../../bower_components/materialdesignicons-scss-variables/dist/materialdesignicons-vars'; 9 | 10 | @import 'material'; 11 | @import 'material-buttons'; 12 | @import 'icons'; 13 | 14 | @import 'components'; 15 | @import 'inputs'; 16 | @import 'window'; 17 | @import 'toolbar'; 18 | @import 'desktop'; 19 | @import 'desktop-login'; 20 | 21 | @import 'app-browser'; 22 | @import 'app-downloader'; 23 | @import 'app-epg'; 24 | @import 'app-lanbrowser'; 25 | @import 'app-settings'; 26 | @import 'app-tasklist'; 27 | -------------------------------------------------------------------------------- /data/img/icon-128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentin-st/Material-Freebox-OS/2523bc5a6437c851341007258eab8fd989c85a83/data/img/icon-128x128.png -------------------------------------------------------------------------------- /data/img/icon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentin-st/Material-Freebox-OS/2523bc5a6437c851341007258eab8fd989c85a83/data/img/icon-16x16.png -------------------------------------------------------------------------------- /data/img/icon-18x18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentin-st/Material-Freebox-OS/2523bc5a6437c851341007258eab8fd989c85a83/data/img/icon-18x18.png -------------------------------------------------------------------------------- /data/img/icon-19x19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentin-st/Material-Freebox-OS/2523bc5a6437c851341007258eab8fd989c85a83/data/img/icon-19x19.png -------------------------------------------------------------------------------- /data/img/icon-256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentin-st/Material-Freebox-OS/2523bc5a6437c851341007258eab8fd989c85a83/data/img/icon-256x256.png -------------------------------------------------------------------------------- /data/img/icon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentin-st/Material-Freebox-OS/2523bc5a6437c851341007258eab8fd989c85a83/data/img/icon-32x32.png -------------------------------------------------------------------------------- /data/img/icon-36x36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentin-st/Material-Freebox-OS/2523bc5a6437c851341007258eab8fd989c85a83/data/img/icon-36x36.png -------------------------------------------------------------------------------- /data/img/icon-38x38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentin-st/Material-Freebox-OS/2523bc5a6437c851341007258eab8fd989c85a83/data/img/icon-38x38.png -------------------------------------------------------------------------------- /data/img/icon-48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentin-st/Material-Freebox-OS/2523bc5a6437c851341007258eab8fd989c85a83/data/img/icon-48x48.png -------------------------------------------------------------------------------- /data/img/icon-64x64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentin-st/Material-Freebox-OS/2523bc5a6437c851341007258eab8fd989c85a83/data/img/icon-64x64.png -------------------------------------------------------------------------------- /data/img/icon-90x90.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentin-st/Material-Freebox-OS/2523bc5a6437c851341007258eab8fd989c85a83/data/img/icon-90x90.png -------------------------------------------------------------------------------- /data/img/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /data/img/mdi-check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentin-st/Material-Freebox-OS/2523bc5a6437c851341007258eab8fd989c85a83/data/img/mdi-check.png -------------------------------------------------------------------------------- /data/img/wallpaper1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentin-st/Material-Freebox-OS/2523bc5a6437c851341007258eab8fd989c85a83/data/img/wallpaper1.jpg -------------------------------------------------------------------------------- /data/img/wallpaper2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentin-st/Material-Freebox-OS/2523bc5a6437c851341007258eab8fd989c85a83/data/img/wallpaper2.jpg -------------------------------------------------------------------------------- /data/img/wallpaper3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentin-st/Material-Freebox-OS/2523bc5a6437c851341007258eab8fd989c85a83/data/img/wallpaper3.jpg -------------------------------------------------------------------------------- /data/img/wallpaper4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentin-st/Material-Freebox-OS/2523bc5a6437c851341007258eab8fd989c85a83/data/img/wallpaper4.jpg -------------------------------------------------------------------------------- /data/img/wallpaper5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentin-st/Material-Freebox-OS/2523bc5a6437c851341007258eab8fd989c85a83/data/img/wallpaper5.jpg -------------------------------------------------------------------------------- /data/img/wallpaper6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentin-st/Material-Freebox-OS/2523bc5a6437c851341007258eab8fd989c85a83/data/img/wallpaper6.jpg -------------------------------------------------------------------------------- /data/js/content-script.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Material-Freebox-OS 3 | * Main script - injected by injector.js 4 | */ 5 | (function() { 6 | // Could be undefined on login page 7 | if (typeof Ext !== 'undefined') { 8 | // Override windows buttons size 9 | // We need to override this ASAP 10 | Ext.panel.Tool.prototype.width = Ext.panel.Tool.prototype.height = 34; 11 | } 12 | 13 | 14 | /** 15 | * This function is called once the desktop is fully loaded 16 | */ 17 | var desktopLoaded = function() { 18 | // We're on login page, no need to go further 19 | if (window.FbxConf === undefined) 20 | return; 21 | 22 | var ui = { 23 | toolbar: $('.freeboxos-southbar.x-toolbar') 24 | }; 25 | 26 | // DESKTOP 27 | // Write Freebox OS version next to the huge title 28 | $('
        ') 29 | .addClass('fbxos-version-text') 30 | .text('v' + FbxConf.firmwareVersionMajor + '.' + FbxConf.firmwareVersionMinor) 31 | .appendTo($('.fbxos-version')); 32 | 33 | 34 | // Listen for window size change events 35 | var syncMonitorWindowResize = Ext.window.Window.prototype.syncMonitorWindowResize; 36 | Ext.window.Window.prototype.syncMonitorWindowResize = function() { 37 | var result = syncMonitorWindowResize.apply(this, arguments); 38 | 39 | // If any of the visible windows is fullscreen 40 | ui.toolbar.toggleClass('solid-background', $('.x-window-maximized:not(.x-hide-offsets)').length > 0); 41 | 42 | return result; 43 | }; 44 | 45 | 46 | // Listen for window focus change 47 | var sortByZIndex = function(a, b) { 48 | var aZindex = $(a).css('z-index'); 49 | var bZindex = $(b).css('z-index'); 50 | 51 | return ((aZindex < bZindex) ? -1 : ((aZindex > bZindex) ? 1 : 0)); 52 | }; 53 | 54 | var bringToFront = Ext.ZIndexManager.prototype.bringToFront; 55 | Ext.ZIndexManager.prototype.bringToFront = function() { 56 | var result = bringToFront.apply(this, arguments); 57 | var windows = $('.x-window:not(.x-hide-offsets)').slice(); 58 | 59 | // Set blurred class on all windows 60 | windows.toggleClass('x-window-focus-blurred', true); 61 | 62 | // Find focused window 63 | windows.sort(sortByZIndex); 64 | 65 | // Set focuses class on active window 66 | $(windows[windows.length-1]) 67 | .toggleClass('x-window-focus-focused', true) 68 | .toggleClass('x-window-focus-blurred', false); 69 | 70 | return result; 71 | }; 72 | 73 | 74 | // Change default height on some windows 75 | [ 76 | [Fbx.os.app.settings.Switch, 650], 77 | [Fbx.os.app.settings.ConnectionConfig, 435], 78 | [Fbx.os.app.settings.UpnpAv, 150], 79 | [Fbx.os.app.settings.NetworkMode, 385], 80 | [Fbx.os.app.settings.AirMedia, 155], 81 | [Fbx.os.app.settings.Lcd, 185], 82 | [Fbx.os.app.settings.PhoneFxsStatus, 400], 83 | [Fbx.os.app.settings.ShareAfp, 250] 84 | ].forEach(function(array) { 85 | var curDefaultHeight = array[0].prototype.self.defaultHeight, 86 | newHeight = array[1]; 87 | 88 | // Don't set it lower than it already is (future FB OS updates) 89 | if (newHeight > curDefaultHeight) 90 | array[0].prototype.self.defaultHeight = newHeight; 91 | }); 92 | }; 93 | 94 | function waitFor(something, onceReady) { 95 | var i = setInterval(function() { 96 | if (something()) { 97 | clearInterval(i); 98 | onceReady(); 99 | } 100 | }, 200); 101 | } 102 | 103 | // Wait for jQuery & desktop to be loaded 104 | waitFor(function() { 105 | return !!window.jQuery && !!$('.fbxos-version').length; 106 | }, desktopLoaded); 107 | })(); 108 | -------------------------------------------------------------------------------- /data/js/injector.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Material-Freebox-OS 3 | * Client dependencies injector 4 | */ 5 | (function() { 6 | if (!MaterialFreeboxOS.matches(document.title)) 7 | return; 8 | 9 | // Define functions 10 | var Injector = { 11 | metaName: 'MaterialFreeboxOS', 12 | hasMeta: function(key) { 13 | var metas = document.getElementsByTagName('meta'); 14 | for (var i = 0; i < metas.length; i++) { 15 | if (metas[i].name == key) 16 | return true; 17 | } 18 | 19 | return false; 20 | }, 21 | addMeta: function(key, val) { 22 | var m = document.createElement('meta'); 23 | m.name = key; 24 | m.content = val; 25 | document.head.appendChild(m); 26 | return m; 27 | }, 28 | getDeps: function() { 29 | return { 30 | js: [ 31 | 'data/js/material-freebox-os.js', 32 | 'data/js/content-script.js' 33 | ], 34 | css: [ 35 | 'data/css/style.css', 36 | 'data/css/fonts/roboto.css', 37 | 'data/css/fonts/materialdesignicons.css' 38 | ] 39 | }; 40 | }, 41 | injectScript: function(src) { 42 | var s = document.createElement('script'); 43 | s.src = src; 44 | (document.head || document.documentElement).appendChild(s); 45 | }, 46 | injectStylesheet: function(src) { 47 | var s = document.createElement('link'); 48 | s.rel = 'stylesheet'; 49 | s.href = src; 50 | s.media = 'all'; 51 | s.type = 'text/css'; 52 | document.head.appendChild(s); 53 | }, 54 | injectAll: function() { 55 | var deps = this.getDeps(); 56 | var that = this; 57 | 58 | // Inject scripts 59 | deps.js.forEach(function(uri) { 60 | that.injectScript(MaterialFreeboxOS.getDepURI(uri)); 61 | }); 62 | 63 | // Inject stylesheets 64 | deps.css.forEach(function(uri) { 65 | that.injectStylesheet(MaterialFreeboxOS.getDepURI(uri)); 66 | }); 67 | }, 68 | applyColors: function() { 69 | chrome.storage.local.get('color-primary', function (data) { 70 | var primaryColor = data['color-primary'] || MaterialFreeboxOS.materialColors.defaultPrimary; 71 | 72 | document.body.setAttribute('data-color-primary', primaryColor); 73 | }); 74 | chrome.storage.local.get('color-accent', function (data) { 75 | var accentColor = data['color-accent'] || MaterialFreeboxOS.materialColors.defaultAccent; 76 | 77 | document.body.setAttribute('data-color-accent', accentColor); 78 | }); 79 | }, 80 | applyWallpaper: function() { 81 | // Retrieve setting 82 | chrome.storage.local.get('wallpaper', function(data) { 83 | var wallpaperUri = data['wallpaper'] || MaterialFreeboxOS.wallpaper.defaultWallpaper.image; 84 | 85 | var wallpaperInfos = MaterialFreeboxOS.wallpaper.findWallpaperInfos(wallpaperUri); 86 | 87 | document.body.style.backgroundImage = "url('" + MaterialFreeboxOS.getDepURI(wallpaperUri) + "')"; 88 | 89 | // Add credits information to page 90 | var span = document.createElement('a'); 91 | span.className = 'desktop-wallpaper-credits'; 92 | document.body.appendChild(span); 93 | 94 | if (wallpaperInfos !== null) 95 | MaterialFreeboxOS.wallpaper.updateWallpaperCredits(span, wallpaperInfos); 96 | }); 97 | } 98 | }; 99 | 100 | // Check if Material-Freebox-OS meta tag is here 101 | // (it would mean that another instance has already been injected) 102 | if (Injector.hasMeta(Injector.metaName)) 103 | throw new Error('Material-Freebox-OS already injected, aborting.'); 104 | 105 | // Append Material-Freebox-OS meta tag to head 106 | Injector.addMeta(Injector.metaName, true); 107 | 108 | // Apply colors & wallpaper (defined in browser-action) 109 | Injector.applyColors(); 110 | Injector.applyWallpaper(); 111 | 112 | // Inject dependencies 113 | Injector.injectAll(); 114 | })(); 115 | -------------------------------------------------------------------------------- /data/js/material-freebox-os.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Material-Freebox-OS 3 | * Shared scripts 4 | */ 5 | (function() { 6 | window.MaterialFreeboxOS = { 7 | /** 8 | * Returns true if page title begins with Freebox OS 9 | * @param pageTitle 10 | * @returns {boolean} 11 | */ 12 | matches: function(pageTitle) { 13 | return pageTitle.indexOf('Freebox OS') == 0; 14 | }, 15 | 16 | getDepURI: function(relative) { 17 | var prefix = relative.substring(0, 'http'.length); 18 | 19 | return prefix == 'http' || prefix == 'file' 20 | ? relative 21 | : chrome.extension.getURL(relative); 22 | }, 23 | 24 | materialColors: { 25 | colors: [ 26 | '#F44336', // red 27 | '#E91E63', // pink 28 | '#9C27B0', // purple 29 | '#673AB7', // deep-purple 30 | '#3F51B5', // indigo 31 | '#2196F3', // blue 32 | '#03A9F4', // light-blue 33 | '#00BCD4', // cyan 34 | '#009688', // teal 35 | '#4CAF50', // green 36 | '#8BC34A', // light-green 37 | '#CDDC39', // lime 38 | '#FFEB3B', // yellow 39 | '#FFC107', // amber 40 | '#FF9800', // orange 41 | '#FF5722', // deep-orange 42 | '#795548', // brown 43 | '#9E9E9E', // grey 44 | '#607D8B' // blue-grey 45 | ], 46 | 47 | get defaultPrimary() { 48 | return this.colors[5]; 49 | }, 50 | 51 | get defaultAccent() { 52 | return this.colors[9]; 53 | } 54 | }, 55 | 56 | /** 57 | * Wallpaper-related methods 58 | */ 59 | wallpaper: { 60 | findWallpaperInfos: function (uri) { 61 | var wallpaper = null; 62 | 63 | this.wallpapers.forEach(function (w) { 64 | if (w.image == uri) 65 | wallpaper = w; 66 | }); 67 | 68 | return wallpaper; 69 | }, 70 | 71 | wallpapers: [ 72 | { 73 | name: 'Earth 064', 74 | credits: 'Google Maps / DigitalGlobe', 75 | image: 'data/img/wallpaper1.jpg' 76 | }, 77 | { 78 | name: 'Earth 152', 79 | credits: 'Google Maps / Aerometrex', 80 | image: 'data/img/wallpaper2.jpg' 81 | }, 82 | { 83 | name: 'Off The Road', 84 | credits: 'Trey Ratcliff', 85 | source: 'http://www.stuckincustoms.com/', 86 | image: 'data/img/wallpaper3.jpg' 87 | }, 88 | { 89 | name: 'The Remarkables', 90 | credits: 'Trey Ratcliff', 91 | source: 'http://www.stuckincustoms.com/', 92 | image: 'data/img/wallpaper4.jpg' 93 | }, 94 | { 95 | name: 'Blue Sky', 96 | credits: 'Henry Lien', 97 | source: 'https://plus.google.com/u/1/+HenryLien/about', 98 | image: 'data/img/wallpaper5.jpg' 99 | }, 100 | { 101 | name: 'Golden Gate Afternoon', 102 | credits: 'Romain Guy', 103 | source: 'http://www.curious-creature.org/', 104 | image: 'data/img/wallpaper6.jpg' 105 | } 106 | ], 107 | 108 | get defaultWallpaper() { 109 | return this.wallpapers[0]; 110 | }, 111 | 112 | updateWallpaperCredits: function (element, wallpaperInfos) { 113 | element.style.display = wallpaperInfos !== null ? 'block' : 'none'; 114 | 115 | if (wallpaperInfos === null) 116 | return; 117 | 118 | if (wallpaperInfos['source'] !== undefined) { 119 | element.href = wallpaperInfos['source']; 120 | element.target = '_blank'; 121 | } else { 122 | element.removeAttribute('href'); 123 | element.removeAttribute('target'); 124 | } 125 | 126 | // Equivalent for element.innerHTML = "Fond d'écran : " + wallpaperInfos['name'] + " par " + wallpaperInfos['credits'] + ""; 127 | // but Firefox validation process will complain about creating DOM nodes from HTML string 128 | element.innerHTML = ''; 129 | element.appendChild(document.createTextNode("Fond d'écran : ")); 130 | element.appendChild( 131 | document.createElement('b').appendChild(document.createTextNode(wallpaperInfos['name'])).parentNode 132 | ); 133 | element.appendChild(document.createTextNode(" par ")); 134 | element.appendChild( 135 | document.createElement('b').appendChild(document.createTextNode(wallpaperInfos['credits'])).parentNode 136 | ); 137 | } 138 | }, 139 | 140 | environment: { 141 | isFirefox: function() { 142 | return /firefox/i.test(navigator.userAgent); 143 | }, 144 | 145 | getBrowserHandle: function() { 146 | return this.isFirefox() ? browser : chrome; 147 | } 148 | } 149 | }; 150 | })(); 151 | -------------------------------------------------------------------------------- /data/vendor/fonts/README.md: -------------------------------------------------------------------------------- 1 | # Bundled base64 Roboto & MaterialDesignIcons fonts 2 | To generate the base64 representation of a font: 3 | 4 | base64 Roboto-Regular.woff | tr -d '\n' > _roboto-regular-woff.scss 5 | -------------------------------------------------------------------------------- /data/vendor/fonts/Roboto/Roboto-Light.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentin-st/Material-Freebox-OS/2523bc5a6437c851341007258eab8fd989c85a83/data/vendor/fonts/Roboto/Roboto-Light.woff -------------------------------------------------------------------------------- /data/vendor/fonts/Roboto/Roboto-Light.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentin-st/Material-Freebox-OS/2523bc5a6437c851341007258eab8fd989c85a83/data/vendor/fonts/Roboto/Roboto-Light.woff2 -------------------------------------------------------------------------------- /data/vendor/fonts/Roboto/Roboto-Medium.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentin-st/Material-Freebox-OS/2523bc5a6437c851341007258eab8fd989c85a83/data/vendor/fonts/Roboto/Roboto-Medium.woff -------------------------------------------------------------------------------- /data/vendor/fonts/Roboto/Roboto-Medium.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentin-st/Material-Freebox-OS/2523bc5a6437c851341007258eab8fd989c85a83/data/vendor/fonts/Roboto/Roboto-Medium.woff2 -------------------------------------------------------------------------------- /data/vendor/fonts/Roboto/Roboto-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentin-st/Material-Freebox-OS/2523bc5a6437c851341007258eab8fd989c85a83/data/vendor/fonts/Roboto/Roboto-Regular.woff -------------------------------------------------------------------------------- /data/vendor/fonts/Roboto/Roboto-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentin-st/Material-Freebox-OS/2523bc5a6437c851341007258eab8fd989c85a83/data/vendor/fonts/Roboto/Roboto-Regular.woff2 -------------------------------------------------------------------------------- /data/vendor/fonts/materialdesignicons/materialdesignicons-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentin-st/Material-Freebox-OS/2523bc5a6437c851341007258eab8fd989c85a83/data/vendor/fonts/materialdesignicons/materialdesignicons-webfont.eot -------------------------------------------------------------------------------- /data/vendor/fonts/materialdesignicons/materialdesignicons-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentin-st/Material-Freebox-OS/2523bc5a6437c851341007258eab8fd989c85a83/data/vendor/fonts/materialdesignicons/materialdesignicons-webfont.ttf -------------------------------------------------------------------------------- /data/vendor/fonts/materialdesignicons/materialdesignicons-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentin-st/Material-Freebox-OS/2523bc5a6437c851341007258eab8fd989c85a83/data/vendor/fonts/materialdesignicons/materialdesignicons-webfont.woff -------------------------------------------------------------------------------- /data/vendor/fonts/materialdesignicons/materialdesignicons-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentin-st/Material-Freebox-OS/2523bc5a6437c851341007258eab8fd989c85a83/data/vendor/fonts/materialdesignicons/materialdesignicons-webfont.woff2 -------------------------------------------------------------------------------- /data/vendor/jquery-3.3.1.slim.min.js: -------------------------------------------------------------------------------- 1 | /*! jQuery v3.3.1 -ajax,-ajax/jsonp,-ajax/load,-ajax/parseXML,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-event/ajax,-effects,-effects/Tween,-effects/animatedSelector | (c) JS Foundation and other contributors | jquery.org/license */ 2 | !function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(e,t){"use strict";var n=[],r=e.document,i=Object.getPrototypeOf,o=n.slice,a=n.concat,u=n.push,s=n.indexOf,l={},c=l.toString,f=l.hasOwnProperty,d=f.toString,p=d.call(Object),h={},g=function e(t){return"function"==typeof t&&"number"!=typeof t.nodeType},v=function e(t){return null!=t&&t===t.window},y={type:!0,src:!0,noModule:!0};function m(e,t,n){var i,o=(t=t||r).createElement("script");if(o.text=e,n)for(i in y)n[i]&&(o[i]=n[i]);t.head.appendChild(o).parentNode.removeChild(o)}function b(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[c.call(e)]||"object":typeof e}var x="3.3.1 -ajax,-ajax/jsonp,-ajax/load,-ajax/parseXML,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-event/ajax,-effects,-effects/Tween,-effects/animatedSelector",w=function(e,t){return new w.fn.init(e,t)},C=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;w.fn=w.prototype={jquery:x,constructor:w,length:0,toArray:function(){return o.call(this)},get:function(e){return null==e?o.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=w.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return w.each(this,e)},map:function(e){return this.pushStack(w.map(this,function(t,n){return e.call(t,n,t)}))},slice:function(){return this.pushStack(o.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(n>=0&&n0&&t-1 in e)}var E=function(e){var t,n,r,i,o,a,u,s,l,c,f,d,p,h,g,v,y,m,b,x="sizzle"+1*new Date,w=e.document,C=0,T=0,E=ae(),N=ae(),k=ae(),A=function(e,t){return e===t&&(f=!0),0},D={}.hasOwnProperty,S=[],L=S.pop,j=S.push,q=S.push,O=S.slice,P=function(e,t){for(var n=0,r=e.length;n+~]|"+I+")"+I+"*"),_=new RegExp("="+I+"*([^\\]'\"]*?)"+I+"*\\]","g"),U=new RegExp(M),V=new RegExp("^"+R+"$"),X={ID:new RegExp("^#("+R+")"),CLASS:new RegExp("^\\.("+R+")"),TAG:new RegExp("^("+R+"|[*])"),ATTR:new RegExp("^"+B),PSEUDO:new RegExp("^"+M),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+I+"*(even|odd|(([+-]|)(\\d*)n|)"+I+"*(?:([+-]|)"+I+"*(\\d+)|))"+I+"*\\)|)","i"),bool:new RegExp("^(?:"+H+")$","i"),needsContext:new RegExp("^"+I+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+I+"*((?:-\\d)?\\d*)"+I+"*\\)|)(?=[^-]|$)","i")},Q=/^(?:input|select|textarea|button)$/i,Y=/^h\d$/i,G=/^[^{]+\{\s*\[native \w/,K=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,J=/[+~]/,Z=new RegExp("\\\\([\\da-f]{1,6}"+I+"?|("+I+")|.)","ig"),ee=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},te=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ne=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},re=function(){d()},ie=me(function(e){return!0===e.disabled&&("form"in e||"label"in e)},{dir:"parentNode",next:"legend"});try{q.apply(S=O.call(w.childNodes),w.childNodes),S[w.childNodes.length].nodeType}catch(e){q={apply:S.length?function(e,t){j.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function oe(e,t,r,i){var o,u,l,c,f,h,y,m=t&&t.ownerDocument,C=t?t.nodeType:9;if(r=r||[],"string"!=typeof e||!e||1!==C&&9!==C&&11!==C)return r;if(!i&&((t?t.ownerDocument||t:w)!==p&&d(t),t=t||p,g)){if(11!==C&&(f=K.exec(e)))if(o=f[1]){if(9===C){if(!(l=t.getElementById(o)))return r;if(l.id===o)return r.push(l),r}else if(m&&(l=m.getElementById(o))&&b(t,l)&&l.id===o)return r.push(l),r}else{if(f[2])return q.apply(r,t.getElementsByTagName(e)),r;if((o=f[3])&&n.getElementsByClassName&&t.getElementsByClassName)return q.apply(r,t.getElementsByClassName(o)),r}if(n.qsa&&!k[e+" "]&&(!v||!v.test(e))){if(1!==C)m=t,y=e;else if("object"!==t.nodeName.toLowerCase()){(c=t.getAttribute("id"))?c=c.replace(te,ne):t.setAttribute("id",c=x),u=(h=a(e)).length;while(u--)h[u]="#"+c+" "+ye(h[u]);y=h.join(","),m=J.test(e)&&ge(t.parentNode)||t}if(y)try{return q.apply(r,m.querySelectorAll(y)),r}catch(e){}finally{c===x&&t.removeAttribute("id")}}}return s(e.replace($,"$1"),t,r,i)}function ae(){var e=[];function t(n,i){return e.push(n+" ")>r.cacheLength&&delete t[e.shift()],t[n+" "]=i}return t}function ue(e){return e[x]=!0,e}function se(e){var t=p.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function le(e,t){var n=e.split("|"),i=n.length;while(i--)r.attrHandle[n[i]]=t}function ce(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function fe(e){return function(t){return"input"===t.nodeName.toLowerCase()&&t.type===e}}function de(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function pe(e){return function(t){return"form"in t?t.parentNode&&!1===t.disabled?"label"in t?"label"in t.parentNode?t.parentNode.disabled===e:t.disabled===e:t.isDisabled===e||t.isDisabled!==!e&&ie(t)===e:t.disabled===e:"label"in t&&t.disabled===e}}function he(e){return ue(function(t){return t=+t,ue(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}function ge(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}n=oe.support={},o=oe.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return!!t&&"HTML"!==t.nodeName},d=oe.setDocument=function(e){var t,i,a=e?e.ownerDocument||e:w;return a!==p&&9===a.nodeType&&a.documentElement?(p=a,h=p.documentElement,g=!o(p),w!==p&&(i=p.defaultView)&&i.top!==i&&(i.addEventListener?i.addEventListener("unload",re,!1):i.attachEvent&&i.attachEvent("onunload",re)),n.attributes=se(function(e){return e.className="i",!e.getAttribute("className")}),n.getElementsByTagName=se(function(e){return e.appendChild(p.createComment("")),!e.getElementsByTagName("*").length}),n.getElementsByClassName=G.test(p.getElementsByClassName),n.getById=se(function(e){return h.appendChild(e).id=x,!p.getElementsByName||!p.getElementsByName(x).length}),n.getById?(r.filter.ID=function(e){var t=e.replace(Z,ee);return function(e){return e.getAttribute("id")===t}},r.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&g){var n=t.getElementById(e);return n?[n]:[]}}):(r.filter.ID=function(e){var t=e.replace(Z,ee);return function(e){var n="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return n&&n.value===t}},r.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&g){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),r.find.TAG=n.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):n.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},r.find.CLASS=n.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&g)return t.getElementsByClassName(e)},y=[],v=[],(n.qsa=G.test(p.querySelectorAll))&&(se(function(e){h.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+I+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+I+"*(?:value|"+H+")"),e.querySelectorAll("[id~="+x+"-]").length||v.push("~="),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+x+"+*").length||v.push(".#.+[+~]")}),se(function(e){e.innerHTML="";var t=p.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+I+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),h.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(n.matchesSelector=G.test(m=h.matches||h.webkitMatchesSelector||h.mozMatchesSelector||h.oMatchesSelector||h.msMatchesSelector))&&se(function(e){n.disconnectedMatch=m.call(e,"*"),m.call(e,"[s!='']:x"),y.push("!=",M)}),v=v.length&&new RegExp(v.join("|")),y=y.length&&new RegExp(y.join("|")),t=G.test(h.compareDocumentPosition),b=t||G.test(h.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},A=t?function(e,t){if(e===t)return f=!0,0;var r=!e.compareDocumentPosition-!t.compareDocumentPosition;return r||(1&(r=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!n.sortDetached&&t.compareDocumentPosition(e)===r?e===p||e.ownerDocument===w&&b(w,e)?-1:t===p||t.ownerDocument===w&&b(w,t)?1:c?P(c,e)-P(c,t):0:4&r?-1:1)}:function(e,t){if(e===t)return f=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],u=[t];if(!i||!o)return e===p?-1:t===p?1:i?-1:o?1:c?P(c,e)-P(c,t):0;if(i===o)return ce(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)u.unshift(n);while(a[r]===u[r])r++;return r?ce(a[r],u[r]):a[r]===w?-1:u[r]===w?1:0},p):p},oe.matches=function(e,t){return oe(e,null,null,t)},oe.matchesSelector=function(e,t){if((e.ownerDocument||e)!==p&&d(e),t=t.replace(_,"='$1']"),n.matchesSelector&&g&&!k[t+" "]&&(!y||!y.test(t))&&(!v||!v.test(t)))try{var r=m.call(e,t);if(r||n.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(e){}return oe(t,p,null,[e]).length>0},oe.contains=function(e,t){return(e.ownerDocument||e)!==p&&d(e),b(e,t)},oe.attr=function(e,t){(e.ownerDocument||e)!==p&&d(e);var i=r.attrHandle[t.toLowerCase()],o=i&&D.call(r.attrHandle,t.toLowerCase())?i(e,t,!g):void 0;return void 0!==o?o:n.attributes||!g?e.getAttribute(t):(o=e.getAttributeNode(t))&&o.specified?o.value:null},oe.escape=function(e){return(e+"").replace(te,ne)},oe.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},oe.uniqueSort=function(e){var t,r=[],i=0,o=0;if(f=!n.detectDuplicates,c=!n.sortStable&&e.slice(0),e.sort(A),f){while(t=e[o++])t===e[o]&&(i=r.push(o));while(i--)e.splice(r[i],1)}return c=null,e},i=oe.getText=function(e){var t,n="",r=0,o=e.nodeType;if(o){if(1===o||9===o||11===o){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=i(e)}else if(3===o||4===o)return e.nodeValue}else while(t=e[r++])n+=i(t);return n},(r=oe.selectors={cacheLength:50,createPseudo:ue,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(Z,ee),e[3]=(e[3]||e[4]||e[5]||"").replace(Z,ee),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||oe.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&oe.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return X.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&U.test(n)&&(t=a(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(Z,ee).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=E[e+" "];return t||(t=new RegExp("(^|"+I+")"+e+"("+I+"|$)"))&&E(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=oe.attr(r,e);return null==i?"!="===t:!t||(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i.replace(W," ")+" ").indexOf(n)>-1:"|="===t&&(i===n||i.slice(0,n.length+1)===n+"-"))}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),u="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,s){var l,c,f,d,p,h,g=o!==a?"nextSibling":"previousSibling",v=t.parentNode,y=u&&t.nodeName.toLowerCase(),m=!s&&!u,b=!1;if(v){if(o){while(g){d=t;while(d=d[g])if(u?d.nodeName.toLowerCase()===y:1===d.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?v.firstChild:v.lastChild],a&&m){b=(p=(l=(c=(f=(d=v)[x]||(d[x]={}))[d.uniqueID]||(f[d.uniqueID]={}))[e]||[])[0]===C&&l[1])&&l[2],d=p&&v.childNodes[p];while(d=++p&&d&&d[g]||(b=p=0)||h.pop())if(1===d.nodeType&&++b&&d===t){c[e]=[C,p,b];break}}else if(m&&(b=p=(l=(c=(f=(d=t)[x]||(d[x]={}))[d.uniqueID]||(f[d.uniqueID]={}))[e]||[])[0]===C&&l[1]),!1===b)while(d=++p&&d&&d[g]||(b=p=0)||h.pop())if((u?d.nodeName.toLowerCase()===y:1===d.nodeType)&&++b&&(m&&((c=(f=d[x]||(d[x]={}))[d.uniqueID]||(f[d.uniqueID]={}))[e]=[C,b]),d===t))break;return(b-=i)===r||b%r==0&&b/r>=0}}},PSEUDO:function(e,t){var n,i=r.pseudos[e]||r.setFilters[e.toLowerCase()]||oe.error("unsupported pseudo: "+e);return i[x]?i(t):i.length>1?(n=[e,e,"",t],r.setFilters.hasOwnProperty(e.toLowerCase())?ue(function(e,n){var r,o=i(e,t),a=o.length;while(a--)e[r=P(e,o[a])]=!(n[r]=o[a])}):function(e){return i(e,0,n)}):i}},pseudos:{not:ue(function(e){var t=[],n=[],r=u(e.replace($,"$1"));return r[x]?ue(function(e,t,n,i){var o,a=r(e,null,i,[]),u=e.length;while(u--)(o=a[u])&&(e[u]=!(t[u]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),t[0]=null,!n.pop()}}),has:ue(function(e){return function(t){return oe(e,t).length>0}}),contains:ue(function(e){return e=e.replace(Z,ee),function(t){return(t.textContent||t.innerText||i(t)).indexOf(e)>-1}}),lang:ue(function(e){return V.test(e||"")||oe.error("unsupported lang: "+e),e=e.replace(Z,ee).toLowerCase(),function(t){var n;do{if(n=g?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return(n=n.toLowerCase())===e||0===n.indexOf(e+"-")}while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===h},focus:function(e){return e===p.activeElement&&(!p.hasFocus||p.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:pe(!1),disabled:pe(!0),checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!r.pseudos.empty(e)},header:function(e){return Y.test(e.nodeName)},input:function(e){return Q.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:he(function(){return[0]}),last:he(function(e,t){return[t-1]}),eq:he(function(e,t,n){return[n<0?n+t:n]}),even:he(function(e,t){for(var n=0;n=0;)e.push(r);return e}),gt:he(function(e,t,n){for(var r=n<0?n+t:n;++r1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function xe(e,t,n){for(var r=0,i=t.length;r-1&&(o[l]=!(a[l]=f))}}else y=we(y===a?y.splice(h,y.length):y),i?i(null,a,y,s):q.apply(a,y)})}function Te(e){for(var t,n,i,o=e.length,a=r.relative[e[0].type],u=a||r.relative[" "],s=a?1:0,c=me(function(e){return e===t},u,!0),f=me(function(e){return P(t,e)>-1},u,!0),d=[function(e,n,r){var i=!a&&(r||n!==l)||((t=n).nodeType?c(e,n,r):f(e,n,r));return t=null,i}];s1&&be(d),s>1&&ye(e.slice(0,s-1).concat({value:" "===e[s-2].type?"*":""})).replace($,"$1"),n,s0,i=e.length>0,o=function(o,a,u,s,c){var f,h,v,y=0,m="0",b=o&&[],x=[],w=l,T=o||i&&r.find.TAG("*",c),E=C+=null==w?1:Math.random()||.1,N=T.length;for(c&&(l=a===p||a||c);m!==N&&null!=(f=T[m]);m++){if(i&&f){h=0,a||f.ownerDocument===p||(d(f),u=!g);while(v=e[h++])if(v(f,a||p,u)){s.push(f);break}c&&(C=E)}n&&((f=!v&&f)&&y--,o&&b.push(f))}if(y+=m,n&&m!==y){h=0;while(v=t[h++])v(b,x,a,u);if(o){if(y>0)while(m--)b[m]||x[m]||(x[m]=L.call(s));x=we(x)}q.apply(s,x),c&&!o&&x.length>0&&y+t.length>1&&oe.uniqueSort(s)}return c&&(C=E,l=w),b};return n?ue(o):o}return u=oe.compile=function(e,t){var n,r=[],i=[],o=k[e+" "];if(!o){t||(t=a(e)),n=t.length;while(n--)(o=Te(t[n]))[x]?r.push(o):i.push(o);(o=k(e,Ee(i,r))).selector=e}return o},s=oe.select=function(e,t,n,i){var o,s,l,c,f,d="function"==typeof e&&e,p=!i&&a(e=d.selector||e);if(n=n||[],1===p.length){if((s=p[0]=p[0].slice(0)).length>2&&"ID"===(l=s[0]).type&&9===t.nodeType&&g&&r.relative[s[1].type]){if(!(t=(r.find.ID(l.matches[0].replace(Z,ee),t)||[])[0]))return n;d&&(t=t.parentNode),e=e.slice(s.shift().value.length)}o=X.needsContext.test(e)?0:s.length;while(o--){if(l=s[o],r.relative[c=l.type])break;if((f=r.find[c])&&(i=f(l.matches[0].replace(Z,ee),J.test(s[0].type)&&ge(t.parentNode)||t))){if(s.splice(o,1),!(e=i.length&&ye(s)))return q.apply(n,i),n;break}}}return(d||u(e,p))(i,t,!g,n,!t||J.test(e)&&ge(t.parentNode)||t),n},n.sortStable=x.split("").sort(A).join("")===x,n.detectDuplicates=!!f,d(),n.sortDetached=se(function(e){return 1&e.compareDocumentPosition(p.createElement("fieldset"))}),se(function(e){return e.innerHTML="","#"===e.firstChild.getAttribute("href")})||le("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),n.attributes&&se(function(e){return e.innerHTML="",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||le("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),se(function(e){return null==e.getAttribute("disabled")})||le(H,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),oe}(e);w.find=E,w.expr=E.selectors,w.expr[":"]=w.expr.pseudos,w.uniqueSort=w.unique=E.uniqueSort,w.text=E.getText,w.isXMLDoc=E.isXML,w.contains=E.contains,w.escapeSelector=E.escape;var N=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&w(e).is(n))break;r.push(e)}return r},k=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},A=w.expr.match.needsContext;function D(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var S=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function L(e,t,n){return g(t)?w.grep(e,function(e,r){return!!t.call(e,r,e)!==n}):t.nodeType?w.grep(e,function(e){return e===t!==n}):"string"!=typeof t?w.grep(e,function(e){return s.call(t,e)>-1!==n}):w.filter(t,e,n)}w.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?w.find.matchesSelector(r,e)?[r]:[]:w.find.matches(e,w.grep(t,function(e){return 1===e.nodeType}))},w.fn.extend({find:function(e){var t,n,r=this.length,i=this;if("string"!=typeof e)return this.pushStack(w(e).filter(function(){for(t=0;t1?w.uniqueSort(n):n},filter:function(e){return this.pushStack(L(this,e||[],!1))},not:function(e){return this.pushStack(L(this,e||[],!0))},is:function(e){return!!L(this,"string"==typeof e&&A.test(e)?w(e):e||[],!1).length}});var j,q=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(w.fn.init=function(e,t,n){var i,o;if(!e)return this;if(n=n||j,"string"==typeof e){if(!(i="<"===e[0]&&">"===e[e.length-1]&&e.length>=3?[null,e,null]:q.exec(e))||!i[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(i[1]){if(t=t instanceof w?t[0]:t,w.merge(this,w.parseHTML(i[1],t&&t.nodeType?t.ownerDocument||t:r,!0)),S.test(i[1])&&w.isPlainObject(t))for(i in t)g(this[i])?this[i](t[i]):this.attr(i,t[i]);return this}return(o=r.getElementById(i[2]))&&(this[0]=o,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):g(e)?void 0!==n.ready?n.ready(e):e(w):w.makeArray(e,this)}).prototype=w.fn,j=w(r);var O=/^(?:parents|prev(?:Until|All))/,P={children:!0,contents:!0,next:!0,prev:!0};w.fn.extend({has:function(e){var t=w(e,this),n=t.length;return this.filter(function(){for(var e=0;e-1:1===n.nodeType&&w.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(o.length>1?w.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?s.call(w(e),this[0]):s.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(w.uniqueSort(w.merge(this.get(),w(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function H(e,t){while((e=e[t])&&1!==e.nodeType);return e}w.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return N(e,"parentNode")},parentsUntil:function(e,t,n){return N(e,"parentNode",n)},next:function(e){return H(e,"nextSibling")},prev:function(e){return H(e,"previousSibling")},nextAll:function(e){return N(e,"nextSibling")},prevAll:function(e){return N(e,"previousSibling")},nextUntil:function(e,t,n){return N(e,"nextSibling",n)},prevUntil:function(e,t,n){return N(e,"previousSibling",n)},siblings:function(e){return k((e.parentNode||{}).firstChild,e)},children:function(e){return k(e.firstChild)},contents:function(e){return D(e,"iframe")?e.contentDocument:(D(e,"template")&&(e=e.content||e),w.merge([],e.childNodes))}},function(e,t){w.fn[e]=function(n,r){var i=w.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=w.filter(r,i)),this.length>1&&(P[e]||w.uniqueSort(i),O.test(e)&&i.reverse()),this.pushStack(i)}});var I=/[^\x20\t\r\n\f]+/g;function R(e){var t={};return w.each(e.match(I)||[],function(e,n){t[n]=!0}),t}w.Callbacks=function(e){e="string"==typeof e?R(e):w.extend({},e);var t,n,r,i,o=[],a=[],u=-1,s=function(){for(i=i||e.once,r=t=!0;a.length;u=-1){n=a.shift();while(++u-1)o.splice(n,1),n<=u&&u--}),this},has:function(e){return e?w.inArray(e,o)>-1:o.length>0},empty:function(){return o&&(o=[]),this},disable:function(){return i=a=[],o=n="",this},disabled:function(){return!o},lock:function(){return i=a=[],n||t||(o=n=""),this},locked:function(){return!!i},fireWith:function(e,n){return i||(n=[e,(n=n||[]).slice?n.slice():n],a.push(n),t||s()),this},fire:function(){return l.fireWith(this,arguments),this},fired:function(){return!!r}};return l};function B(e){return e}function M(e){throw e}function W(e,t,n,r){var i;try{e&&g(i=e.promise)?i.call(e).done(t).fail(n):e&&g(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}w.extend({Deferred:function(t){var n=[["notify","progress",w.Callbacks("memory"),w.Callbacks("memory"),2],["resolve","done",w.Callbacks("once memory"),w.Callbacks("once memory"),0,"resolved"],["reject","fail",w.Callbacks("once memory"),w.Callbacks("once memory"),1,"rejected"]],r="pending",i={state:function(){return r},always:function(){return o.done(arguments).fail(arguments),this},"catch":function(e){return i.then(null,e)},pipe:function(){var e=arguments;return w.Deferred(function(t){w.each(n,function(n,r){var i=g(e[r[4]])&&e[r[4]];o[r[1]](function(){var e=i&&i.apply(this,arguments);e&&g(e.promise)?e.promise().progress(t.notify).done(t.resolve).fail(t.reject):t[r[0]+"With"](this,i?[e]:arguments)})}),e=null}).promise()},then:function(t,r,i){var o=0;function a(t,n,r,i){return function(){var u=this,s=arguments,l=function(){var e,l;if(!(t=o&&(r!==M&&(u=void 0,s=[e]),n.rejectWith(u,s))}};t?c():(w.Deferred.getStackHook&&(c.stackTrace=w.Deferred.getStackHook()),e.setTimeout(c))}}return w.Deferred(function(e){n[0][3].add(a(0,e,g(i)?i:B,e.notifyWith)),n[1][3].add(a(0,e,g(t)?t:B)),n[2][3].add(a(0,e,g(r)?r:M))}).promise()},promise:function(e){return null!=e?w.extend(e,i):i}},o={};return w.each(n,function(e,t){var a=t[2],u=t[5];i[t[1]]=a.add,u&&a.add(function(){r=u},n[3-e][2].disable,n[3-e][3].disable,n[0][2].lock,n[0][3].lock),a.add(t[3].fire),o[t[0]]=function(){return o[t[0]+"With"](this===o?void 0:this,arguments),this},o[t[0]+"With"]=a.fireWith}),i.promise(o),t&&t.call(o,o),o},when:function(e){var t=arguments.length,n=t,r=Array(n),i=o.call(arguments),a=w.Deferred(),u=function(e){return function(n){r[e]=this,i[e]=arguments.length>1?o.call(arguments):n,--t||a.resolveWith(r,i)}};if(t<=1&&(W(e,a.done(u(n)).resolve,a.reject,!t),"pending"===a.state()||g(i[n]&&i[n].then)))return a.then();while(n--)W(i[n],u(n),a.reject);return a.promise()}});var $=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;w.Deferred.exceptionHook=function(t,n){e.console&&e.console.warn&&t&&$.test(t.name)&&e.console.warn("jQuery.Deferred exception: "+t.message,t.stack,n)},w.readyException=function(t){e.setTimeout(function(){throw t})};var F=w.Deferred();w.fn.ready=function(e){return F.then(e)["catch"](function(e){w.readyException(e)}),this},w.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--w.readyWait:w.isReady)||(w.isReady=!0,!0!==e&&--w.readyWait>0||F.resolveWith(r,[w]))}}),w.ready.then=F.then;function z(){r.removeEventListener("DOMContentLoaded",z),e.removeEventListener("load",z),w.ready()}"complete"===r.readyState||"loading"!==r.readyState&&!r.documentElement.doScroll?e.setTimeout(w.ready):(r.addEventListener("DOMContentLoaded",z),e.addEventListener("load",z));var _=function(e,t,n,r,i,o,a){var u=0,s=e.length,l=null==n;if("object"===b(n)){i=!0;for(u in n)_(e,t,u,n[u],!0,o,a)}else if(void 0!==r&&(i=!0,g(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(w(e),n)})),t))for(;u1,null,!0)},removeData:function(e){return this.each(function(){J.remove(this,e)})}}),w.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=K.get(e,t),n&&(!r||Array.isArray(n)?r=K.access(e,t,w.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=w.queue(e,t),r=n.length,i=n.shift(),o=w._queueHooks(e,t),a=function(){w.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return K.get(e,n)||K.access(e,n,{empty:w.Callbacks("once memory").add(function(){K.remove(e,[t+"queue",n])})})}}),w.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),arguments.length\x20\t\r\n\f]+)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,""],thead:[1,"","
        "],col:[2,"","
        "],tr:[2,"","
        "],td:[3,"","
        "],_default:[0,"",""]};ge.optgroup=ge.option,ge.tbody=ge.tfoot=ge.colgroup=ge.caption=ge.thead,ge.th=ge.td;function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&D(e,t)?w.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n-1)i&&i.push(o);else if(l=w.contains(o.ownerDocument,o),a=ve(f.appendChild(o),"script"),l&&ye(a),n){c=0;while(o=a[c++])he.test(o.type||"")&&n.push(o)}return f}!function(){var e=r.createDocumentFragment().appendChild(r.createElement("div")),t=r.createElement("input");t.setAttribute("type","radio"),t.setAttribute("checked","checked"),t.setAttribute("name","t"),e.appendChild(t),h.checkClone=e.cloneNode(!0).cloneNode(!0).lastChild.checked,e.innerHTML="",h.noCloneChecked=!!e.cloneNode(!0).lastChild.defaultValue}();var xe=r.documentElement,we=/^key/,Ce=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Te=/^([^.]*)(?:\.(.+)|)/;function Ee(){return!0}function Ne(){return!1}function ke(){try{return r.activeElement}catch(e){}}function Ae(e,t,n,r,i,o){var a,u;if("object"==typeof t){"string"!=typeof n&&(r=r||n,n=void 0);for(u in t)Ae(e,u,n,r,t[u],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Ne;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return w().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=w.guid++)),e.each(function(){w.event.add(this,t,i,r,n)})}w.event={global:{},add:function(e,t,n,r,i){var o,a,u,s,l,c,f,d,p,h,g,v=K.get(e);if(v){n.handler&&(n=(o=n).handler,i=o.selector),i&&w.find.matchesSelector(xe,i),n.guid||(n.guid=w.guid++),(s=v.events)||(s=v.events={}),(a=v.handle)||(a=v.handle=function(t){return"undefined"!=typeof w&&w.event.triggered!==t.type?w.event.dispatch.apply(e,arguments):void 0}),l=(t=(t||"").match(I)||[""]).length;while(l--)p=g=(u=Te.exec(t[l])||[])[1],h=(u[2]||"").split(".").sort(),p&&(f=w.event.special[p]||{},p=(i?f.delegateType:f.bindType)||p,f=w.event.special[p]||{},c=w.extend({type:p,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&w.expr.match.needsContext.test(i),namespace:h.join(".")},o),(d=s[p])||((d=s[p]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(e,r,h,a)||e.addEventListener&&e.addEventListener(p,a)),f.add&&(f.add.call(e,c),c.handler.guid||(c.handler.guid=n.guid)),i?d.splice(d.delegateCount++,0,c):d.push(c),w.event.global[p]=!0)}},remove:function(e,t,n,r,i){var o,a,u,s,l,c,f,d,p,h,g,v=K.hasData(e)&&K.get(e);if(v&&(s=v.events)){l=(t=(t||"").match(I)||[""]).length;while(l--)if(u=Te.exec(t[l])||[],p=g=u[1],h=(u[2]||"").split(".").sort(),p){f=w.event.special[p]||{},d=s[p=(r?f.delegateType:f.bindType)||p]||[],u=u[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=d.length;while(o--)c=d[o],!i&&g!==c.origType||n&&n.guid!==c.guid||u&&!u.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(d.splice(o,1),c.selector&&d.delegateCount--,f.remove&&f.remove.call(e,c));a&&!d.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||w.removeEvent(e,p,v.handle),delete s[p])}else for(p in s)w.event.remove(e,p+t[l],n,r,!0);w.isEmptyObject(s)&&K.remove(e,"handle events")}},dispatch:function(e){var t=w.event.fix(e),n,r,i,o,a,u,s=new Array(arguments.length),l=(K.get(this,"events")||{})[t.type]||[],c=w.event.special[t.type]||{};for(s[0]=t,n=1;n=1))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&("click"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n-1:w.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&u.push({elem:l,handlers:o})}return l=this,s\x20\t\r\n\f]*)[^>]*)\/>/gi,Se=/\s*$/g;function qe(e,t){return D(e,"table")&&D(11!==t.nodeType?t:t.firstChild,"tr")?w(e).children("tbody")[0]||e:e}function Oe(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Pe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function He(e,t){var n,r,i,o,a,u,s,l;if(1===t.nodeType){if(K.hasData(e)&&(o=K.access(e),a=K.set(t,o),l=o.events)){delete a.handle,a.events={};for(i in l)for(n=0,r=l[i].length;n1&&"string"==typeof v&&!h.checkClone&&Le.test(v))return e.each(function(i){var o=e.eq(i);y&&(t[0]=v.call(this,i,o.html())),Re(o,t,n,r)});if(d&&(i=be(t,e[0].ownerDocument,!1,e,r),o=i.firstChild,1===i.childNodes.length&&(i=o),o||r)){for(s=(u=w.map(ve(i,"script"),Oe)).length;f")},clone:function(e,t,n){var r,i,o,a,u=e.cloneNode(!0),s=w.contains(e.ownerDocument,e);if(!(h.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||w.isXMLDoc(e)))for(a=ve(u),r=0,i=(o=ve(e)).length;r0&&ye(a,!s&&ve(e,"script")),u},cleanData:function(e){for(var t,n,r,i=w.event.special,o=0;void 0!==(n=e[o]);o++)if(Y(n)){if(t=n[K.expando]){if(t.events)for(r in t.events)i[r]?w.event.remove(n,r):w.removeEvent(n,r,t.handle);n[K.expando]=void 0}n[J.expando]&&(n[J.expando]=void 0)}}}),w.fn.extend({detach:function(e){return Be(this,e,!0)},remove:function(e){return Be(this,e)},text:function(e){return _(this,function(e){return void 0===e?w.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return Re(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||qe(this,e).appendChild(e)})},prepend:function(){return Re(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=qe(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return Re(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return Re(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(w.cleanData(ve(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return w.clone(this,e,t)})},html:function(e){return _(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!Se.test(e)&&!ge[(pe.exec(e)||["",""])[1].toLowerCase()]){e=w.htmlPrefilter(e);try{for(;n=0&&(s+=Math.max(0,Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-o-s-u-.5))),s}function et(e,t,n){var r=We(e),i=Fe(e,t,r),o="border-box"===w.css(e,"boxSizing",!1,r),a=o;if(Me.test(i)){if(!n)return i;i="auto"}return a=a&&(h.boxSizingReliable()||i===e.style[t]),("auto"===i||!parseFloat(i)&&"inline"===w.css(e,"display",!1,r))&&(i=e["offset"+t[0].toUpperCase()+t.slice(1)],a=!0),(i=parseFloat(i)||0)+Ze(e,t,n||(o?"border":"content"),a,r,i)+"px"}w.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Fe(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,u=Q(t),s=Ue.test(t),l=e.style;if(s||(t=Ke(u)),a=w.cssHooks[t]||w.cssHooks[u],void 0===n)return a&&"get"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];"string"==(o=typeof n)&&(i=ie.exec(n))&&i[1]&&(n=se(e,t,i),o="number"),null!=n&&n===n&&("number"===o&&(n+=i&&i[3]||(w.cssNumber[u]?"":"px")),h.clearCloneStyle||""!==n||0!==t.indexOf("background")||(l[t]="inherit"),a&&"set"in a&&void 0===(n=a.set(e,n,r))||(s?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,u=Q(t);return Ue.test(t)||(t=Ke(u)),(a=w.cssHooks[t]||w.cssHooks[u])&&"get"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=Fe(e,t,r)),"normal"===i&&t in Xe&&(i=Xe[t]),""===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),w.each(["height","width"],function(e,t){w.cssHooks[t]={get:function(e,n,r){if(n)return!_e.test(w.css(e,"display"))||e.getClientRects().length&&e.getBoundingClientRect().width?et(e,t,r):ue(e,Ve,function(){return et(e,t,r)})},set:function(e,n,r){var i,o=We(e),a="border-box"===w.css(e,"boxSizing",!1,o),u=r&&Ze(e,t,r,a,o);return a&&h.scrollboxSize()===o.position&&(u-=Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-parseFloat(o[t])-Ze(e,t,"border",!1,o)-.5)),u&&(i=ie.exec(n))&&"px"!==(i[3]||"px")&&(e.style[t]=n,n=w.css(e,t)),Je(e,n,u)}}}),w.cssHooks.marginLeft=ze(h.reliableMarginLeft,function(e,t){if(t)return(parseFloat(Fe(e,"marginLeft"))||e.getBoundingClientRect().left-ue(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+"px"}),w.each({margin:"",padding:"",border:"Width"},function(e,t){w.cssHooks[e+t]={expand:function(n){for(var r=0,i={},o="string"==typeof n?n.split(" "):[n];r<4;r++)i[e+oe[r]+t]=o[r]||o[r-2]||o[0];return i}},"margin"!==e&&(w.cssHooks[e+t].set=Je)}),w.fn.extend({css:function(e,t){return _(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=We(e),i=t.length;a1)}}),w.fn.delay=function(t,n){return t=w.fx?w.fx.speeds[t]||t:t,n=n||"fx",this.queue(n,function(n,r){var i=e.setTimeout(n,t);r.stop=function(){e.clearTimeout(i)}})},function(){var e=r.createElement("input"),t=r.createElement("select").appendChild(r.createElement("option"));e.type="checkbox",h.checkOn=""!==e.value,h.optSelected=t.selected,(e=r.createElement("input")).value="t",e.type="radio",h.radioValue="t"===e.value}();var tt,nt=w.expr.attrHandle;w.fn.extend({attr:function(e,t){return _(this,w.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){w.removeAttr(this,e)})}}),w.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return"undefined"==typeof e.getAttribute?w.prop(e,t,n):(1===o&&w.isXMLDoc(e)||(i=w.attrHooks[t.toLowerCase()]||(w.expr.match.bool.test(t)?tt:void 0)),void 0!==n?null===n?void w.removeAttr(e,t):i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+""),n):i&&"get"in i&&null!==(r=i.get(e,t))?r:null==(r=w.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!h.radioValue&&"radio"===t&&D(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(I);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),tt={set:function(e,t,n){return!1===t?w.removeAttr(e,n):e.setAttribute(n,n),n}},w.each(w.expr.match.bool.source.match(/\w+/g),function(e,t){var n=nt[t]||w.find.attr;nt[t]=function(e,t,r){var i,o,a=t.toLowerCase();return r||(o=nt[a],nt[a]=i,i=null!=n(e,t,r)?a:null,nt[a]=o),i}});var rt=/^(?:input|select|textarea|button)$/i,it=/^(?:a|area)$/i;w.fn.extend({prop:function(e,t){return _(this,w.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each(function(){delete this[w.propFix[e]||e]})}}),w.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&w.isXMLDoc(e)||(t=w.propFix[t]||t,i=w.propHooks[t]),void 0!==n?i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=w.find.attr(e,"tabindex");return t?parseInt(t,10):rt.test(e.nodeName)||it.test(e.nodeName)&&e.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),h.optSelected||(w.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),w.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){w.propFix[this.toLowerCase()]=this});function ot(e){return(e.match(I)||[]).join(" ")}function at(e){return e.getAttribute&&e.getAttribute("class")||""}function ut(e){return Array.isArray(e)?e:"string"==typeof e?e.match(I)||[]:[]}w.fn.extend({addClass:function(e){var t,n,r,i,o,a,u,s=0;if(g(e))return this.each(function(t){w(this).addClass(e.call(this,t,at(this)))});if((t=ut(e)).length)while(n=this[s++])if(i=at(n),r=1===n.nodeType&&" "+ot(i)+" "){a=0;while(o=t[a++])r.indexOf(" "+o+" ")<0&&(r+=o+" ");i!==(u=ot(r))&&n.setAttribute("class",u)}return this},removeClass:function(e){var t,n,r,i,o,a,u,s=0;if(g(e))return this.each(function(t){w(this).removeClass(e.call(this,t,at(this)))});if(!arguments.length)return this.attr("class","");if((t=ut(e)).length)while(n=this[s++])if(i=at(n),r=1===n.nodeType&&" "+ot(i)+" "){a=0;while(o=t[a++])while(r.indexOf(" "+o+" ")>-1)r=r.replace(" "+o+" "," ");i!==(u=ot(r))&&n.setAttribute("class",u)}return this},toggleClass:function(e,t){var n=typeof e,r="string"===n||Array.isArray(e);return"boolean"==typeof t&&r?t?this.addClass(e):this.removeClass(e):g(e)?this.each(function(n){w(this).toggleClass(e.call(this,n,at(this),t),t)}):this.each(function(){var t,i,o,a;if(r){i=0,o=w(this),a=ut(e);while(t=a[i++])o.hasClass(t)?o.removeClass(t):o.addClass(t)}else void 0!==e&&"boolean"!==n||((t=at(this))&&K.set(this,"__className__",t),this.setAttribute&&this.setAttribute("class",t||!1===e?"":K.get(this,"__className__")||""))})},hasClass:function(e){var t,n,r=0;t=" "+e+" ";while(n=this[r++])if(1===n.nodeType&&(" "+ot(at(n))+" ").indexOf(t)>-1)return!0;return!1}});var st=/\r/g;w.fn.extend({val:function(e){var t,n,r,i=this[0];{if(arguments.length)return r=g(e),this.each(function(n){var i;1===this.nodeType&&(null==(i=r?e.call(this,n,w(this).val()):e)?i="":"number"==typeof i?i+="":Array.isArray(i)&&(i=w.map(i,function(e){return null==e?"":e+""})),(t=w.valHooks[this.type]||w.valHooks[this.nodeName.toLowerCase()])&&"set"in t&&void 0!==t.set(this,i,"value")||(this.value=i))});if(i)return(t=w.valHooks[i.type]||w.valHooks[i.nodeName.toLowerCase()])&&"get"in t&&void 0!==(n=t.get(i,"value"))?n:"string"==typeof(n=i.value)?n.replace(st,""):null==n?"":n}}}),w.extend({valHooks:{option:{get:function(e){var t=w.find.attr(e,"value");return null!=t?t:ot(w.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a="select-one"===e.type,u=a?null:[],s=a?o+1:i.length;for(r=o<0?s:a?o:0;r-1)&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),w.each(["radio","checkbox"],function(){w.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=w.inArray(w(e).val(),t)>-1}},h.checkOn||(w.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})}),h.focusin="onfocusin"in e;var lt=/^(?:focusinfocus|focusoutblur)$/,ct=function(e){e.stopPropagation()};w.extend(w.event,{trigger:function(t,n,i,o){var a,u,s,l,c,d,p,h,y=[i||r],m=f.call(t,"type")?t.type:t,b=f.call(t,"namespace")?t.namespace.split("."):[];if(u=h=s=i=i||r,3!==i.nodeType&&8!==i.nodeType&&!lt.test(m+w.event.triggered)&&(m.indexOf(".")>-1&&(m=(b=m.split(".")).shift(),b.sort()),c=m.indexOf(":")<0&&"on"+m,t=t[w.expando]?t:new w.Event(m,"object"==typeof t&&t),t.isTrigger=o?2:3,t.namespace=b.join("."),t.rnamespace=t.namespace?new RegExp("(^|\\.)"+b.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,t.result=void 0,t.target||(t.target=i),n=null==n?[t]:w.makeArray(n,[t]),p=w.event.special[m]||{},o||!p.trigger||!1!==p.trigger.apply(i,n))){if(!o&&!p.noBubble&&!v(i)){for(l=p.delegateType||m,lt.test(l+m)||(u=u.parentNode);u;u=u.parentNode)y.push(u),s=u;s===(i.ownerDocument||r)&&y.push(s.defaultView||s.parentWindow||e)}a=0;while((u=y[a++])&&!t.isPropagationStopped())h=u,t.type=a>1?l:p.bindType||m,(d=(K.get(u,"events")||{})[t.type]&&K.get(u,"handle"))&&d.apply(u,n),(d=c&&u[c])&&d.apply&&Y(u)&&(t.result=d.apply(u,n),!1===t.result&&t.preventDefault());return t.type=m,o||t.isDefaultPrevented()||p._default&&!1!==p._default.apply(y.pop(),n)||!Y(i)||c&&g(i[m])&&!v(i)&&((s=i[c])&&(i[c]=null),w.event.triggered=m,t.isPropagationStopped()&&h.addEventListener(m,ct),i[m](),t.isPropagationStopped()&&h.removeEventListener(m,ct),w.event.triggered=void 0,s&&(i[c]=s)),t.result}},simulate:function(e,t,n){var r=w.extend(new w.Event,n,{type:e,isSimulated:!0});w.event.trigger(r,null,t)}}),w.fn.extend({trigger:function(e,t){return this.each(function(){w.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return w.event.trigger(e,t,n,!0)}}),h.focusin||w.each({focus:"focusin",blur:"focusout"},function(e,t){var n=function(e){w.event.simulate(t,e.target,w.event.fix(e))};w.event.special[t]={setup:function(){var r=this.ownerDocument||this,i=K.access(r,t);i||r.addEventListener(e,n,!0),K.access(r,t,(i||0)+1)},teardown:function(){var r=this.ownerDocument||this,i=K.access(r,t)-1;i?K.access(r,t,i):(r.removeEventListener(e,n,!0),K.remove(r,t))}}});var ft=/\[\]$/,dt=/\r?\n/g,pt=/^(?:submit|button|image|reset|file)$/i,ht=/^(?:input|select|textarea|keygen)/i;function gt(e,t,n,r){var i;if(Array.isArray(t))w.each(t,function(t,i){n||ft.test(e)?r(e,i):gt(e+"["+("object"==typeof i&&null!=i?t:"")+"]",i,n,r)});else if(n||"object"!==b(t))r(e,t);else for(i in t)gt(e+"["+i+"]",t[i],n,r)}w.param=function(e,t){var n,r=[],i=function(e,t){var n=g(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(Array.isArray(e)||e.jquery&&!w.isPlainObject(e))w.each(e,function(){i(this.name,this.value)});else for(n in e)gt(n,e[n],t,i);return r.join("&")},w.fn.extend({serialize:function(){return w.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=w.prop(this,"elements");return e?w.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!w(this).is(":disabled")&&ht.test(this.nodeName)&&!pt.test(e)&&(this.checked||!de.test(e))}).map(function(e,t){var n=w(this).val();return null==n?null:Array.isArray(n)?w.map(n,function(e){return{name:t.name,value:e.replace(dt,"\r\n")}}):{name:t.name,value:n.replace(dt,"\r\n")}}).get()}}),w.fn.extend({wrapAll:function(e){var t;return this[0]&&(g(e)&&(e=e.call(this[0])),t=w(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(e){return g(e)?this.each(function(t){w(this).wrapInner(e.call(this,t))}):this.each(function(){var t=w(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=g(e);return this.each(function(n){w(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(e){return this.parent(e).not("body").each(function(){w(this).replaceWith(this.childNodes)}),this}}),w.expr.pseudos.hidden=function(e){return!w.expr.pseudos.visible(e)},w.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},h.createHTMLDocument=function(){var e=r.implementation.createHTMLDocument("").body;return e.innerHTML="
        ",2===e.childNodes.length}(),w.parseHTML=function(e,t,n){if("string"!=typeof e)return[];"boolean"==typeof t&&(n=t,t=!1);var i,o,a;return t||(h.createHTMLDocument?((i=(t=r.implementation.createHTMLDocument("")).createElement("base")).href=r.location.href,t.head.appendChild(i)):t=r),o=S.exec(e),a=!n&&[],o?[t.createElement(o[1])]:(o=be([e],t,a),a&&a.length&&w(a).remove(),w.merge([],o.childNodes))},w.offset={setOffset:function(e,t,n){var r,i,o,a,u,s,l,c=w.css(e,"position"),f=w(e),d={};"static"===c&&(e.style.position="relative"),u=f.offset(),o=w.css(e,"top"),s=w.css(e,"left"),(l=("absolute"===c||"fixed"===c)&&(o+s).indexOf("auto")>-1)?(a=(r=f.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(s)||0),g(t)&&(t=t.call(e,n,w.extend({},u))),null!=t.top&&(d.top=t.top-u.top+a),null!=t.left&&(d.left=t.left-u.left+i),"using"in t?t.using.call(e,d):f.css(d)}},w.fn.extend({offset:function(e){if(arguments.length)return void 0===e?this:this.each(function(t){w.offset.setOffset(this,e,t)});var t,n,r=this[0];if(r)return r.getClientRects().length?(t=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:t.top+n.pageYOffset,left:t.left+n.pageXOffset}):{top:0,left:0}},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===w.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===w.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=w(e).offset()).top+=w.css(e,"borderTopWidth",!0),i.left+=w.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-w.css(r,"marginTop",!0),left:t.left-i.left-w.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===w.css(e,"position"))e=e.offsetParent;return e||xe})}}),w.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,t){var n="pageYOffset"===t;w.fn[e]=function(r){return _(this,function(e,r,i){var o;if(v(e)?o=e:9===e.nodeType&&(o=e.defaultView),void 0===i)return o?o[t]:e[r];o?o.scrollTo(n?o.pageXOffset:i,n?i:o.pageYOffset):e[r]=i},e,r,arguments.length)}}),w.each(["top","left"],function(e,t){w.cssHooks[t]=ze(h.pixelPosition,function(e,n){if(n)return n=Fe(e,t),Me.test(n)?w(e).position()[t]+"px":n})}),w.each({Height:"height",Width:"width"},function(e,t){w.each({padding:"inner"+e,content:t,"":"outer"+e},function(n,r){w.fn[r]=function(i,o){var a=arguments.length&&(n||"boolean"!=typeof i),u=n||(!0===i||!0===o?"margin":"border");return _(this,function(t,n,i){var o;return v(t)?0===r.indexOf("outer")?t["inner"+e]:t.document.documentElement["client"+e]:9===t.nodeType?(o=t.documentElement,Math.max(t.body["scroll"+e],o["scroll"+e],t.body["offset"+e],o["offset"+e],o["client"+e])):void 0===i?w.css(t,n,u):w.style(t,n,i,u)},t,a?i:void 0,a)}})}),w.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,t){w.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)}}),w.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),w.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)}}),w.proxy=function(e,t){var n,r,i;if("string"==typeof t&&(n=e[t],t=e,e=n),g(e))return r=o.call(arguments,2),i=function(){return e.apply(t||this,r.concat(o.call(arguments)))},i.guid=e.guid=e.guid||w.guid++,i},w.holdReady=function(e){e?w.readyWait++:w.ready(!0)},w.isArray=Array.isArray,w.parseJSON=JSON.parse,w.nodeName=D,w.isFunction=g,w.isWindow=v,w.camelCase=Q,w.type=b,w.now=Date.now,w.isNumeric=function(e){var t=w.type(e);return("number"===t||"string"===t)&&!isNaN(e-parseFloat(e))},"function"==typeof define&&define.amd&&define("jquery",[],function(){return w});var vt=e.jQuery,yt=e.$;return w.noConflict=function(t){return e.$===w&&(e.$=yt),t&&e.jQuery===w&&(e.jQuery=vt),w},t||(e.jQuery=e.$=w),w}); 3 | -------------------------------------------------------------------------------- /doc/download-chrome-web-store.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentin-st/Material-Freebox-OS/2523bc5a6437c851341007258eab8fd989c85a83/doc/download-chrome-web-store.png -------------------------------------------------------------------------------- /doc/download-firefox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentin-st/Material-Freebox-OS/2523bc5a6437c851341007258eab8fd989c85a83/doc/download-firefox.png -------------------------------------------------------------------------------- /doc/download-opera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentin-st/Material-Freebox-OS/2523bc5a6437c851341007258eab8fd989c85a83/doc/download-opera.png -------------------------------------------------------------------------------- /doc/opera/opera-en.md: -------------------------------------------------------------------------------- 1 | # Installing Material Freebox OS on Opera 2 | 3 | [[FR] Installer Material Freebox OS sur Opera](opera-fr.md) 4 | 5 | Opera allows you to install & use Google Chrome extensions. Follow these steps to install Material Freebox OS: 6 | 7 | 1. Install [Download Chrome Extension](https://addons.opera.com/fr/extensions/details/download-chrome-extension-9/) 8 | 2. Navigate to [Material Freebox OS](https://chrome.google.com/webstore/detail/material-freebox-os/lhdfonhgkclaigpfmclbahllambeednh/) 9 | - Hit "Add to Opera" 10 | - "*The extension was disabled because it is from an unknown source. Go to the extensions manager to enable it.*": hit "Go" 11 | ![The extension was disabled because it is from an unknown source. Go to the extensions manager to disable it.](opera-warning.png) 12 | - Hit "Install" 13 | ![Install](opera-install.png) 14 | - "*The extension "Material Freebox OS" was added from outside the official add-ons website.*": hit "Install" 15 | 16 | That's it! 17 | -------------------------------------------------------------------------------- /doc/opera/opera-fr.md: -------------------------------------------------------------------------------- 1 | # Installer Material Freebox OS sur Opera 2 | 3 | [[EN] Installing Material Freebox OS on Opera](opera-en.md) 4 | 5 | Opera permet d'installer et d'utiliser des extensions Google Chrome. Suivez les étapes suivantes afin d'installer 6 | Material Freebox OS : 7 | 8 | 1. Installer [Download Chrome Extension](https://addons.opera.com/fr/extensions/details/download-chrome-extension-9/) 9 | 2. Aller sur [Material Freebox OS](https://chrome.google.com/webstore/detail/material-freebox-os/lhdfonhgkclaigpfmclbahllambeednh/) 10 | - Cliquer sur "Ajouter à Opera" 11 | - "*Cette extension a été désactivée parce qu'elle provient d'une source inconnue. Allez sur le gestionnaire d'extension pour l'activer.*": cliquez sur "Go" 12 | ![Cette extension a été désactivée parce qu'elle provient d'une source inconnue. Allez sur le gestionnaire d'extension pour l'activer.](opera-warning.png) 13 | - Cliquer sur "Installer" 14 | ![Installer](opera-install.png) 15 | - "*L'extension "Material Freebox OS" a été ajoutée depuis une source externe au site officiel.*": cliquer sur "Installer" 16 | -------------------------------------------------------------------------------- /doc/opera/opera-install.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentin-st/Material-Freebox-OS/2523bc5a6437c851341007258eab8fd989c85a83/doc/opera/opera-install.png -------------------------------------------------------------------------------- /doc/opera/opera-warning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentin-st/Material-Freebox-OS/2523bc5a6437c851341007258eab8fd989c85a83/doc/opera/opera-warning.png -------------------------------------------------------------------------------- /doc/screenshot1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentin-st/Material-Freebox-OS/2523bc5a6437c851341007258eab8fd989c85a83/doc/screenshot1.png -------------------------------------------------------------------------------- /doc/screenshot2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentin-st/Material-Freebox-OS/2523bc5a6437c851341007258eab8fd989c85a83/doc/screenshot2.png -------------------------------------------------------------------------------- /doc/screenshot3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentin-st/Material-Freebox-OS/2523bc5a6437c851341007258eab8fd989c85a83/doc/screenshot3.png -------------------------------------------------------------------------------- /generate-icons.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -*- coding: utf-8 -*- 3 | # 4 | # This script allows us to generate static PNG icons from the SVG version. 5 | # It on svgexport npm package: https://github.com/shakiba/svgexport 6 | # 7 | 8 | import os 9 | import json 10 | 11 | manifest = 'manifest.json' 12 | destination = 'data/img' 13 | 14 | # Open manifest & read required icons dimensions 15 | with open(manifest) as manifest_file: 16 | manifest_json = json.load(manifest_file) 17 | 18 | icons_dicts = [ 19 | manifest_json['icons'], 20 | manifest_json['browser_action']['default_icon'] 21 | ] 22 | 23 | dimensions = [] 24 | for icons_dict in icons_dicts: 25 | for key in icons_dict.keys(): 26 | if key not in dimensions: 27 | dimensions.append(key) 28 | 29 | # Generate! 30 | os.chdir(destination) 31 | for dimension in dimensions: 32 | icon_name = 'icon-{}x{}.png'.format(dimension, dimension) 33 | print('\tGenerating {}'.format(icon_name)) 34 | 35 | command = "svgexport {input} {output} {width}:{height}".format( 36 | input='icon.svg', 37 | output=icon_name, 38 | width=dimension, 39 | height=dimension 40 | ) 41 | 42 | print(command) 43 | os.system(command) 44 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 2, 3 | 4 | "name": "Material Freebox OS", 5 | "description": "Redesign de l'interface de Freebox OS", 6 | "version": "2.6.0", 7 | "icons": { 8 | "16": "data/img/icon-16x16.png", 9 | "32": "data/img/icon-32x32.png", 10 | "48": "data/img/icon-48x48.png", 11 | "64": "data/img/icon-64x64.png", 12 | "90": "data/img/icon-90x90.png", 13 | "128": "data/img/icon-128x128.png", 14 | "256": "data/img/icon-256x256.png" 15 | }, 16 | "author": "Quentin S.", 17 | 18 | "applications": { 19 | "gecko": { 20 | "id": "material-freebox-os@s-quent.in", 21 | "strict_min_version": "48.0" 22 | } 23 | }, 24 | 25 | "browser_action": { 26 | "default_popup": "data/browser-action/index.html", 27 | "default_icon": { 28 | "18": "data/img/icon-18x18.png", 29 | "19": "data/img/icon-19x19.png", 30 | "32": "data/img/icon-32x32.png", 31 | "36": "data/img/icon-36x36.png", 32 | "38": "data/img/icon-38x38.png", 33 | "64": "data/img/icon-64x64.png" 34 | } 35 | }, 36 | 37 | "permissions": [ 38 | "tabs", 39 | "activeTab", 40 | "storage" 41 | ], 42 | "content_scripts": [ 43 | { 44 | "matches": [ 45 | "http://mafreebox.freebox.fr/*", 46 | "http://*/*", 47 | "https://*/*" 48 | ], 49 | "js": [ 50 | "data/js/material-freebox-os.js", 51 | "data/js/injector.js" 52 | ] 53 | } 54 | ], 55 | "web_accessible_resources": [ 56 | "data/js/material-freebox-os.js", 57 | "data/js/content-script.js", 58 | 59 | "data/img/mdi-check.png", 60 | "data/img/wallpaper*.jpg", 61 | 62 | "data/css/style.css", 63 | "data/css/fonts/roboto.css", 64 | "data/css/fonts/materialdesignicons.css" 65 | ] 66 | } 67 | -------------------------------------------------------------------------------- /prepare-release.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import argparse 5 | import sys 6 | import os 7 | import glob 8 | import shutil 9 | import json 10 | import zipfile 11 | 12 | 13 | release_dir = 'release/' 14 | base_dir = os.path.dirname(os.path.realpath(__file__)) 15 | flavours = ['Chrome', 'Firefox'] 16 | files_generic = [ 17 | 'data/browser-action/css/style.css', 18 | 'data/browser-action/js/script.js', 19 | 'data/browser-action/index.html', 20 | 'data/vendor/jquery-3.3.1.slim.min.js', 21 | 22 | 'data/css/style.css', 23 | 'data/css/fonts/roboto.css', 24 | 'data/css/fonts/materialdesignicons.css', 25 | 26 | 'data/img/icon-*x*.png', 27 | 'data/img/mdi-check.png', 28 | 'data/img/wallpaper*.jpg', 29 | 30 | 'data/js/injector.js', 31 | 'data/js/material-freebox-os.js', 32 | 'data/js/content-script.js', 33 | 34 | 'manifest.json' 35 | ] 36 | files_flavours = { 37 | 'Chrome': [], 38 | 'Firefox': [] 39 | } 40 | manifest = 'manifest.json' 41 | 42 | 43 | def do_release(flavour): 44 | # Open manifest & read version name 45 | with open(manifest) as manifest_file: 46 | manifest_json = json.load(manifest_file) 47 | version = manifest_json['version'] 48 | output_dir_name = 'Material-Freebox-OS-{}-{}'.format(flavour, version) 49 | output_dir = os.path.join(release_dir, output_dir_name) 50 | 51 | # Expand files list (js/* => [js/content-script.js, js/injector.js] 52 | expanded_files = [] 53 | files = files_generic + files_flavours[flavour] 54 | for file in files: 55 | if file.endswith('/*'): # That's a directory: include all its elements 56 | real_name = file[:-1] 57 | expanded_files.extend( 58 | [os.path.join(dp, f) for dp, dn, filenames in os.walk(real_name) for f in filenames] 59 | ) 60 | elif '*' in file: # Find all files matching this pattern 61 | expanded_files.extend( 62 | glob.glob(file) 63 | ) 64 | else: 65 | expanded_files.append(file) 66 | 67 | # Copy these! 68 | print('Copying resources in {}...'.format(output_dir)) 69 | for file in expanded_files: 70 | destination = os.path.join(output_dir, file) 71 | destination_dirs = os.path.dirname(destination) 72 | 73 | if not os.path.isdir(destination_dirs): 74 | os.makedirs(destination_dirs) 75 | 76 | shutil.copy(file, destination) 77 | print('\tCopied {}'.format(file, destination)) 78 | 79 | # With Chrome flavour: rewrite manifest to remove Firefox's specific nodes 80 | if flavour == 'Chrome': 81 | with open(os.path.join(output_dir, manifest), 'w') as output_manifest_file: 82 | del manifest_json['applications'] 83 | json.dump(manifest_json, output_manifest_file) 84 | 85 | # Create final ZIP package 86 | zip_extension = 'xpi' if flavour == 'Firefox' else 'zip' 87 | zip_name = 'Material-Freebox-OS-{}-{}.{}'.format(flavour, version, zip_extension) 88 | 89 | with zipfile.ZipFile(os.path.join(release_dir, zip_name), 'w') as zip: 90 | print('Creating package {}'.format(zip_name)) 91 | 92 | for root, dirs, files in os.walk(output_dir): 93 | for file in files: 94 | zip_filepath = os.path.relpath(os.path.join(root, file), output_dir) 95 | zip.write(os.path.join(root, file), zip_filepath) 96 | 97 | print('\tAdded {}'.format(zip_filepath)) 98 | 99 | # Note: ignore_errors=True allows us to ignore "directory is not empty" errors on Windows 100 | shutil.rmtree(output_dir, ignore_errors=True) 101 | print('Deleted working directory {}'.format(output_dir)) 102 | 103 | print('Release file {} created for flavour {}'.format(zip_name, flavour)) 104 | 105 | 106 | parser = argparse.ArgumentParser(description='Prepare release packages for different flavours') 107 | parser.add_argument('--flavour') 108 | args = parser.parse_args() 109 | flavour = args.flavour 110 | 111 | if flavour is None: 112 | print('Please specify a flavour using --flavour') 113 | sys.exit(1) 114 | elif flavour != 'all' and flavour not in flavours: 115 | print('Unknown flavour, exiting') 116 | sys.exit(1) 117 | 118 | # Create output dir if necessary 119 | if not os.path.isdir(release_dir): 120 | print('Creating output dir') 121 | os.makedirs(release_dir) 122 | 123 | if flavour == 'all': 124 | for flavour in flavours: 125 | do_release(flavour) 126 | else: 127 | do_release(flavour) 128 | --------------------------------------------------------------------------------