pax_global_header00006660000000000000000000000064121725664220014521gustar00rootroot0000000000000052 comment=3235042f0f808aa87304df1caff67400b830f406 less.js-1.4.2/000077500000000000000000000000001217256642200131065ustar00rootroot00000000000000less.js-1.4.2/.gitattributes000066400000000000000000000002021217256642200157730ustar00rootroot00000000000000*.js text eol=lf lessc text eol=lf *.less text eol=lf *.css text eol=lf *.htm text eol=lf *.jpg binary *.png binary *.jpeg binaryless.js-1.4.2/.gitignore000066400000000000000000000001401217256642200150710ustar00rootroot00000000000000node_modules .emacs* *.flymake *~ .#* .idea test/browser/less.js test/browser/test-runner-*.htm less.js-1.4.2/.npmignore000066400000000000000000000000171217256642200151030ustar00rootroot00000000000000.gitattributes less.js-1.4.2/CHANGELOG.md000066400000000000000000000170021217256642200147170ustar00rootroot00000000000000# 1.4.2 2013-07-20 - if you don't pass a strict maths option, font size/line height options are output correctly again - npmignore now include .gitattributes - property names may include capital letters - various windows path fixes (capital letters, multiple // in a path) # 1.4.1 2013-07-05 - fix syncImports and yui-compress option, as they were being ignored - fixed several global variable leaks - handle getting null or undefined passed as the options object # 1.4.0 2013-06-05 - fix passing of strict maths option # 1.4.0 Beta 4 2013-05-04 - change strictMaths to strictMath. Enable this with --strict-math=on in lessc and strictMath:true in JavaScript. - change lessc option for strict units to --strict-units=off # 1.4.0 Beta 3 2013-04-30 - strictUnits now defaults to false and the true case now gives more useful but less correct results, e.g. 2px/1px = 2px - Process ./ when having relative paths - add isunit function for mixin guards and non basic units - extends recognise attributes - exception errors extend the JavaScript Error - remove es-5-shim as standard from the browser - Fix path issues with windows/linux local paths # 1.4.0 Beta 1 & 2 2013-03-07 - support for `:extend()` in selectors (e.g. `input:extend(.button) {}`) and `&:extend();` in ruleset (e.g. `input { &:extend(.button all); }`) - maths is now only done inside brackets. This means font: statements, media queries and the calc function can use a simpler format without being escaped. Disable this with --strict-maths-off in lessc and strictMaths:false in JavaScript. - units are calculated, e.g. 200cm+1m = 3m, 3px/1px = 3. If you use units inconsistently you will get an error. Suppress this error with --strict-units-off in lessc or strictUnits:false in JavaScript - `(~"@var")` selector interpolation is removed. Use @{var} in selectors to have variable selectors - default behaviour of import is to import each file once. `@import-once` has been removed. - You can specify options on imports to force it to behave as css or less `@import (less) "file.css"` will process the file as less - variables in mixins no longer 'leak' into their calling scope - added data-uri function which will inline an image into the output css. If ieCompat option is true and file is too large, it will fallback to a url() - significant bug fixes to our debug options - other parameters can be used as defaults in mixins e.g. .a(@a, @b:@a) - an error is shown if properties are used outside of a ruleset - added extract function which picks a value out of a list, e.g. extract(12 13 14, 3) => 3 - added luma, hsvhue, hsvsaturation, hsvvalue functions - added pow, pi, mod, tan, sin, cos, atan, asin, acos and sqrt math functions - added convert function, e.g. convert(1rad, deg) => value in degrees - lessc makes output directories if they don't exist - lessc `@import` supports https and 301's - lessc "-depends" option for lessc writes out the list of import files used in makefile format - lessc "-lint" option just reports errors - support for namespaces in attributes and selector interpolation in attributes - other bug fixes # 1.3.3 2012-12-30 - Fix critical bug with mixin call if using multiple brackets - when using the filter contrast function, the function is passed through if the first argument is not a color # 1.3.2 2012-12-28 - browser and server url re-writing is now aligned to not re-write (previous lessc behaviour) - url-rewriting can be made to re-write to be relative to the entry file using the relative-urls option (less.relativeUrls option) - rootpath option can be used to add a base path to every url - Support mixin argument seperator of ';' so you can pass comma seperated values. e.g. `.mixin(23px, 12px;);` - Fix lots of problems with named arguments in corner cases, not behaving as expected - hsv, hsva, unit functions - fixed lots more bad error messages - fix `@import-once` to use the full path, not the relative one for determining if an import has been imported already - support `:not(:nth-child(3))` - mixin guards take units into account - support unicode descriptors (`U+00A1-00A9`) - support calling mixins with a stack when using `&` (broken in 1.3.1) - support `@namespace` and namespace combinators - when using % with colour functions, take into account a colour is out of 256 - when doing maths with a % do not divide by 100 and keep the unit - allow url to contain % (e.g. %20 for a space) - if a mixin guard stops execution a default mixin is not required - units are output in strings (use the unit function if you need to get the value without unit) - do not infinite recurse when mixins call mixins of the same name - fix issue on important on mixin calls - fix issue with multiple comments being confused - tolerate multiple semi-colons on rules - ignore subsequant `@charset` - syncImport option for node.js to read files syncronously - write the output directory if it is missing - change dependency on cssmin to ycssmin - lessc can load files over http - allow calling less.watch() in non dev mode - don't cache in dev mode - less files cope with query parameters better - sass debug statements are now chrome compatible - modifyVars function added to re-render with different root variables # 1.3.1 2012-10-18 - Support for comment and @media debugging statements - bug fix for async access in chrome extensions - new functions tint, shade, multiply, screen, overlay, hardlight, difference, exclusion, average, negation, softlight, red, green, blue, contrast - allow escaped characters in attributes - in selectors support @{a} directly, e.g. .a.@{a} { color: black; } - add fraction parameter to round function - much better support for & selector - preserve order of link statements client side - lessc has better help - rhino version fixed - fix bugs in clientside error handling - support dpi, vmin, vm, dppx, dpcm units - Fix ratios in media statements - in mixin guards allow comparing colors and strings - support for -*-keyframes (for -khtml but now supports any) - in mix function, default weight to 50% - support @import-once - remove duplicate rules in output - implement named parameters when calling mixins - many numerous bug fixes # 1.3.0 2012-03-10 - @media bubbling - Support arbitrary entities as selectors - [Variadic argument support](https://gist.github.com/1933613) - Behaviour of zero-arity mixins has [changed](https://gist.github.com/1933613) - Allow `@import` directives in any selector - Media-query features can now be a variable - Automatic merging of media-query conditions - Fix global variable leaks - Fix error message on wrong-arity call - Fix an `@arguments` behaviour bug - Fix `::` selector output - Fix a bug when using @media with mixins # 1.2.1 2012-01-15 - Fix imports in browser - Improve error reporting in browser - Fix Runtime error reports from imported files - Fix `File not found` import error reporting # 1.2.0 2012-01-07 - Mixin guards - New function `percentage` - New `color` function to parse hex color strings - New type-checking stylesheet functions - Fix Rhino support - Fix bug in string arguments to mixin call - Fix error reporting when index is 0 - Fix browser support in WebKit and IE - Fix string interpolation bug when var is empty - Support `!important` after mixin calls - Support vanilla @keyframes directive - Support variables in certain css selectors, like `nth-child` - Support @media and @import features properly - Improve @import support with media features - Improve error reports from imported files - Improve function call error reporting - Improve error-reporting less.js-1.4.2/CONTRIBUTING.md000066400000000000000000000061561217256642200153470ustar00rootroot00000000000000# Contributing to Less.js > We welcome feature requests and bug reports. Please read these guidelines before submitting one. **Words that begin with the at sign (`@`) must be wrapped in backticks!** . as a courtesy to avoid sending notifications to any user that might have the `@username` being referenced. Remember, usernames start with the at sign. GitHub has other great markdown features as well, [go here to learn more about them](https://help.github.com/articles/github-flavored-markdown). ## Reporting Issues We only accept issues that are bug reports or feature requests. Bugs must be isolated and reproducible problems that we can fix within the Less.js core. Please read the following guidelines before opening any issue. 1. **Search for existing issues.** We get a lot of duplicate issues, and you'd help us out a lot by first checking if someone else has reported the same issue. Moreover, the issue may have already been resolved with a fix available. 2. **Create an isolated and reproducible test case.** Be sure the problem exists in Less.js's code with [reduced test cases](http://css-tricks.com/reduced-test-cases/) that should be included in each bug report. 3. **Test with the latest version**. We get a lot of issues that could be resolved by updating your version of Less.js. 3. **Include a live example.** Please use [less2css.org](http://less2css.org/) for sharing your isolated test cases. 4. **Share as much information as possible.** Include operating system and version. Describe how you use Less. If you use it in the browser, please include browser and version, and the version of Less.js you're using. Let us know if you're using the command line (`lessc`) or an external tool. And try to include steps to reproduce the bug. ## Feature Requests * Please search for existing feature requests first to see if something similar already exists. * Include a clear and specific use-case. We love new ideas, but we do not add language features without a reason. * Consider whether or not your language feature would be better as a function or implemented in a 3rd-party build system such as [assemble-less](http://github.com/assemble/assemble-less). ## Pull Requests _Pull requests are encouraged!_ * Start by adding a feature request to get feedback and see how your idea is received. * If your pull request solves an existing issue, but it's different in some way, _please create a new issue_ and make sure to discuss it with the core contributors. Otherwise you risk your hard work being rejected. * Do not change the **./dist/** folder, we do this when releasing * _Please add tests_ for your work. Use `make test` to see if they pass node.js tests and `make browser-test` to see the browser ([PhantomJS](http://phantomjs.org/)) tests pass. ### Coding Standards * Always use spaces, never tabs * End lines in semi-colons. * Loosely aim towards jsHint standards ## Developing If you want to take an issue just add a small comment saying you are having a go at something, so we don't get duplication. Learn more about [developing Less.js](https://github.com/less/less.js/wiki/Developing-less.js). less.js-1.4.2/LICENSE000066400000000000000000000230441217256642200141160ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS Copyright (c) 2009-2010 Alexis Sellier less.js-1.4.2/Makefile000066400000000000000000000043271217256642200145540ustar00rootroot00000000000000# # Run all tests # test: node test/less-test.js # # Run benchmark # benchmark: node benchmark/less-benchmark.js # # Build less.js # SRC = lib/less HEADER = build/header.js VERSION = `cat package.json | grep version \ | grep -o '[0-9]\.[0-9]\.[0-9]\+'` DIST = dist/less-${VERSION}.js RHINO = dist/less-rhino-${VERSION}.js DIST_MIN = dist/less-${VERSION}.min.js browser-prepare: DIST := test/browser/less.js alpha: DIST := dist/less-${VERSION}-alpha.js alpha: DIST_MIN := dist/less-${VERSION}-alpha.min.js beta: DIST := dist/less-${VERSION}-beta.js beta: DIST_MIN := dist/less-${VERSION}-beta.min.js less: @@mkdir -p dist @@touch ${DIST} @@cat ${HEADER} | sed s/@VERSION/${VERSION}/ > ${DIST} @@echo "(function (window, undefined) {" >> ${DIST} @@cat build/require.js\ ${SRC}/parser.js\ ${SRC}/functions.js\ ${SRC}/colors.js\ ${SRC}/tree/*.js\ ${SRC}/tree.js\ ${SRC}/env.js\ ${SRC}/visitor.js\ ${SRC}/import-visitor.js\ ${SRC}/join-selector-visitor.js\ ${SRC}/extend-visitor.js\ ${SRC}/browser.js\ build/amd.js >> ${DIST} @@echo "})(window);" >> ${DIST} @@echo ${DIST} built. browser-prepare: less node test/browser-test-prepare.js browser-test: browser-prepare phantomjs test/browser/phantom-runner.js browser-test-server: browser-prepare phantomjs test/browser/phantom-runner.js --no-tests rhino: @@mkdir -p dist @@touch ${RHINO} @@cat build/require-rhino.js\ ${SRC}/parser.js\ ${SRC}/env.js\ ${SRC}/visitor.js\ ${SRC}/import-visitor.js\ ${SRC}/join-selector-visitor.js\ ${SRC}/extend-visitor.js\ ${SRC}/functions.js\ ${SRC}/colors.js\ ${SRC}/tree/*.js\ ${SRC}/tree.js\ ${SRC}/rhino.js > ${RHINO} @@echo ${RHINO} built. min: less @@echo minifying... @@uglifyjs ${DIST} > ${DIST_MIN} @@echo ${DIST_MIN} built. alpha: min beta: min alpha-release: alpha git add dist/*.js git commit -m "Update alpha ${VERSION}" dist: min rhino git add dist/* git commit -a -m "(dist) build ${VERSION}" git archive master --prefix=less/ -o less-${VERSION}.tar.gz npm publish less-${VERSION}.tar.gz stable: npm tag less@${VERSION} stable .PHONY: test benchmark less.js-1.4.2/README.md000066400000000000000000000006561217256642200143740ustar00rootroot00000000000000less.js ======= The **dynamic** stylesheet language. about ----- This is the JavaScript, and now official, stable version of LESS. For more information on the language and usage visit [lesscss.org](http://lesscss.org). More information also available [in our wiki](https://github.com/less/less.js/wiki) license ------- See `LICENSE` file. > Copyright (c) 2009-2013 Alexis Sellier & The Core Less Team less.js-1.4.2/benchmark/000077500000000000000000000000001217256642200150405ustar00rootroot00000000000000less.js-1.4.2/benchmark/benchmark.less000066400000000000000000002751161217256642200176760ustar00rootroot00000000000000@bg: #f01; @white: #fff; @grey: #eee; @black: #000; @blue: #000; @accent_colour: #000; @light_grey: #eee; @dark_grey: #eee; @yellow: #422; @red: #ff0000; @colour_positive: #ff0000; @colour_negative: #ff0000; .box_shadow (...) { } .text_shadow (...) { } .border_radius (...) { } .border_radius_top_left (...) { } .border_radius_top_right (...) { } .border_radius_bottom_right (...) { } .border_radius_bottom_left (...) { } .border_radius_top (...) { } .border_radius_right (...) { } .border_radius_bottom (...) { } .border_radius_left (...) { } div.browse { margin: 0 0 20px; &.class { padding: 0; } div.header { padding: 10px 10px 9px; text-align: left; background: @bg url('/images/panel_header_bg.png') repeat-x top left; border-bottom: 1px solid (@bg * 0.66 + @black * 0.33); line-height: 1; height: 18px; .border_radius_top(3); color: @light_grey; h3 { font-size: 16px; margin: 0; color: @white; .text_shadow(1, 1, 0, @bg * 0.66 + @black * 0.33); } span.filter { float: left; display: block; overflow: hidden; position: relative; z-index: 5; a { margin: 0 1px 0 0; display: block; float: left; padding: 0 8px; height: 18px; font-weight: bold; font-size: 10px; line-height: 18px; text-transform: uppercase; background: url('/images/transparent_backgrounds/black_50.png'); color: @light_grey; text-decoration: none; position: relative; z-index: 3; .active { background: @white; color: @black; z-index: 4; :hover { color: @black; } } :hover { color: @white; } :first-child { .border_radius_left(2); } :last-child { .border_radius_right(2); margin-right: 0; } } } span.filter.dropdown { margin: 0; position: relative; overflow: visible; a { .border_radius(2); background: @white; color: @black; margin: 0; position: relative; padding-right: 25px; img { float: left; margin: 4px 5px 0 0; } b.arrow { float: right; display: block; height: 0; width: 0; border: 5px solid transparent; border-top: 5px solid @black; border-bottom: none; position: absolute; top: 6px; right: 10px; } :hover { background: @accent_colour; color: @white; b.arrow { border-top: 5px solid @white; } } } ul { position: absolute; top: 100%; left: 0; margin: 1px 0 0; padding: 0; background: @white; .border_radius(2); .box_shadow(0, 1, 1, @black); li { list-style: none; display: block; padding: 0; margin: 0; a { display: block; height: 18px; line-height: 18px; color: @black; font-size: 10px; text-transform: uppercase; background: transparent; border-bottom: 1px solid (@light_grey * 0.66 + @white * 0.33); float: none; margin: 0; .border_radius(0); white-space: nowrap; :hover { background: url('/images/transparent_backgrounds/accent_colour_25.png'); color: @black; } } :last-child { a { border: none; } } } } } span.filter.dropdown.sort { float: left; margin: 0 0 0 10px; } span.filter.dropdown.localisation { float: left; margin: 0 0 0 10px; } a.more { float: right; color: @white; .text_shadow(1, 1, 0, @bg * 0.66 + @black * 0.33); font-size: 14px; font-weight: bold; position: relative; top: 2px; :hover { text-decoration: none; } } } > ul { margin: 0; background: @white; padding: 10px 0 0 10px; .border_radius(3); position: relative; li { display: block; float: left; list-style: none; margin: 0 10px 10px 0; padding: 5px; position: relative; background: @white; width: 130px; border: 1px solid (@light_grey * 0.33 + @white * 0.66); .border_radius(2); a.remove { position: absolute; height: 16px; width: 16px; padding: 3px; background: @accent_colour; .border_radius(99); display: none; z-index: 3; top: -8px; right: -8px; img { vertical-align: middle; } } div.thumbnail { .border_radius_top(3); position: relative; z-index: 3; .marker { position: absolute; padding: 2px; .border_radius(2); z-index: 3; background: url('/images/transparent_backgrounds/white_75.png'); height: 12px; width: 12px; } .marker.coupon { height: auto; width: auto; top: 10px; right: -3px; padding: 0; background: transparent; overflow: hidden; position: absolute; b { display: block; height: 0; width: 0; float: left; border: 14px solid transparent; border-top: 14px solid @accent_colour; border-bottom: none; border-right: none; float: left; } span { color: @white; font-size: 10px; font-weight: bold; text-transform: uppercase; height: 14px; line-height: 14px; display: block; padding: 0 4px 0 2px; background: @accent_colour; .text_shadow(1, 1, 0px, (@accent_colour * 0.75 + @black * 0.25)); margin: 0 0 0 14px; } } .marker.video { position: absolute; left: 50%; top: 50%; background: @white; width: 10px; height: 10px; b { display: block; width: 0; height: 0; border: 5px solid transparent; border-left: 10px solid @black; border-right: none; } } .marker.endorsed_by_me { background: none; padding: 0; right: 0; bottom: -32px; .border_radius(2); background: @white; } a.thumbnail { display: block; overflow: hidden; position: relative; text-align: center; img { position: relative; display: block; margin: auto; } } } div.text { margin: 3px 0 0; display: block; a { text-decoration: none; } a.title { display: block; text-decoration: none; font-weight: bold; font-size: 12px; line-height: 16px; white-space: nowrap; height: 16px; overflow: hidden; :before { display: block; height: 32px; width: 20px; content: " "; float: right; right: -15px; top: -8px; background: @white; position: relative; z-index: 1; .box_shadow(-5, 0, 10, @white); } } small { font-size: 11px; line-height: 13px; color: @grey; display: block; height: 13px; overflow: hidden; white-space: nowrap; a { font-weight: bold; } :before { display: block; height: 32px; width: 20px; content: " "; float: right; right: -15px; top: -8px; background: @white; position: relative; z-index: 1; .box_shadow(-5, 0, 10, @white); } } } :hover { background: @accent_colour; a.remove { display: block; } div.thumbnail { a.marker.remove, a.marker.video { b { display: inline-block; } } a.marker.video { .box_shadow(0, 0, 2, @black); } } div.text { a { color: @white; } a.title:before { background: @accent_colour; .box_shadow(-5, 0, 10, @accent_colour); } small { color: @white * 0.75 + @accent_colour * 0.25; :before { background: @accent_colour; .box_shadow(-5, 0, 10, @accent_colour); } } } div.footer a { color: @white; } } } > li.ad div.thumbnail a.thumbnail { width: 130px; height: 97px; img { width: 100%; height: 100%; } } > li.brand div.thumbnail a.thumbnail { width: 120px; height: 87px; padding: 5px; background: @white; .border_radius(2); img { max-width: 120px; max-height: 87px; } } li.paginate { margin-bottom: 0; a { display: block; position: relative; text-decoration: none; height: 131px; div.arrow { background: #81c153 url('/images/button_bg.png') repeat-x left top; border: 1px solid (@accent_colour * 0.75 + @black * 0.25); height: 44px; .border_radius(99); width: 44px; margin: 0 auto; position: relative; top: 32px; b { text-indent: -9000px; display: block; border: 10px solid transparent; width: 0; height: 0; position: relative; top: 12px; } } div.label { position: absolute; bottom: 5px; left: 0; right: 0; line-height: 13px; color: @accent_colour * 0.85 + @black * 0.15; text-decoration: none; font-weight: bold; font-size: 12px; text-align: center; } :hover { div.arrow { background: #abd56e url('/images/button_bg.png') repeat-x left -44px; } } } :hover { background: transparent; } } li.paginate.previous a div b { border-right: 15px solid @white; border-left: none; left: 12px; } li.paginate.next a div b { border-left: 15px solid @white; border-right: none; left: 16px; } } > div.footer { padding: 9px 10px 10px; background: @light_grey * 0.75 + @white * 0.25; overflow: hidden; border-top: 1px solid @light_grey; .border_radius_bottom(3); div.info { float: left; color: @grey; strong { color: @black; font-weight: normal; } } div.pagination { float: right; > * { display: inline-block; line-height: 1; padding: 0 6px; line-height: 18px; height: 18px; background: @white; .border_radius(3); text-decoration: none; font-weight: bold; font-size: 10px; text-transform: uppercase; } a { color: @grey; } a:hover { color: @black; } span.disabled { color: @light_grey; } span.current { color: @white; background: @bg; border: none; } span.current:hover { color: @white; } } } } div.browse.with_categories { margin: 0 0 0 160px; } div.browse.with_options > ul { .border_radius_top(0); } div.browse.with_footer > ul { .border_radius_bottom(0); } /* Browse List */ div.browse.list { > ul { margin: 0; min-height: 320px; padding: 10px 0 0 10px; overflow: hidden; > li { display: block; list-style: none; margin: 0 10px 10px 0; padding: 5px; .border_radius(3); position: relative; line-height: normal; .marker { position: absolute; padding: 2px; .border_radius(2); background: url('/images/transparent_backgrounds/white_75.png'); img { height: 12px; width: 12px; } } img.marker { height: 12px; width: 12px; } span.marker.new { color: black; left: -5px; top: -5px; background: none; background-color: @white * 0.1 + @yellow * 0.6 + @red * 0.3; line-height: 1; padding: 2px 5px; font-weight: bold; } a.marker.media_type { display: inline-block; text-decoration: none; top: 39px; left: 8px; font-size: 10px; b { font-weight: normal; margin: 0 0 0 2px; line-height: 1; display: none; } img { vertical-align: middle; } } a.thumbnail { float: left; width: 68px; display: block; overflow: hidden; border: 1px solid @light_grey; :hover { border-color: @accent_colour; } } span.title_brand { display: block; margin: 0 0 2px 75px; a { margin: 0; display: inline; } a.brand_name { font-weight: normal; font-size: 12px; } } a.ad_title { font-weight: bold; font-size: 14px; margin: 0 0 0 75px; display: block; } a.brand_name { font-weight: bold; font-size: 14px; margin: 0 0 0 75px; display: block; } small { display: block; color: @grey; margin: 0 0 0 75px; font-size: 12px; } small.brand_name { display: inline; margin: 0; } ul.chart { margin: 0 0 0 80px; height: 39px; } ul.networks { margin: 3px 0 0 75px; padding: 0; overflow: hidden; li { display: block; float: left; margin: 0 5px 0 0; line-height: 1; } } div.points { display: none; font-size: 12px; text-align: right; label { color: @grey; } } a.remove { bottom: -3px; right: -3px; } } li.ad { a.thumbnail { height: 51px; } span.title_brand { small.brand_name { display: block; } } } li.brand { a.thumbnail { height: 68px; } } } } div.browse.list.with_options ul { .border_radius_top(0); } div.browse.list.with_footer ul { .border_radius_bottom(0); } div.browse.list.cols_2 { > ul { > li { width: 285px; float: left; :hover { background: @white; } } } } div.browse.ads.list { > ul { > li { height: 53px; a.thumbnail { height: 51px; } } } } div.browse.brands.list { > ul { > li { height: 68px; a.thumbnail { height: 66px; } } } } /* Categories List */ #categories { margin: 40px 0 0; width: 160px; float: left; position: relative; z-index: 1; ul { margin: 0; padding: 10px 0 0; li { list-style: none; margin: 0; padding: 0; font-size: 14px; a { color: @grey; display: block; padding: 5px 10px 5px 15px; text-decoration: none; .border_radius_left(3); } a:hover { color: @black; background: @light_grey * 0.15 + @white * 0.85; } } .all a { font-weight: bold; } .current a { background: @white; color: @black; border: 1px solid (@light_grey * 0.25 + @white * 0.75); border-right: none; border-left: 5px solid @bg; padding-left: 10px; } } } /* Ads > Show */ #ad { div.header { overflow: hidden; h3 { font-size: 16px; margin: 0 0 3px; } small { a.category { font-weight: bold; color: @accent_colour; } span.networks img { position: relative; top: 3px; } } span.brand { float: right; color: @white; a.brand_name { font-weight: bold; color: @accent_colour; } } } div.content { padding: 0; position: relative; a.toggle_size { display: block; .border_radius(3); background-color: @black; padding: 0 5px 0 26px; background-position: 5px center; background-repeat: no-repeat; text-decoration: none; margin: 5px 5px 0 0; position: absolute; top: 0; right: 0; line-height: 25px; z-index: 45; } img.creative { margin: 0 auto; max-width: 540px; display: block; } object { position: relative; z-index: 44; } object.video { line-height: 0; font-size: 0; } object embed { position: relative; z-index: 45; line-height: 0; font-size: 0; } } div.content.not_video { padding: 40px; text-align: center; * { margin-left: auto; margin-right: auto; } object.flash { margin-bottom: 0; } } div.footer { padding: 0; div.vote_views { padding: 5px 10px; overflow: hidden; div.share { float: right; margin: 2px 0 0 0; } #login_register_msg, #encourage_vote_msg { line-height: 22px; font-weight: bold; color: @black; } } } } #sidebar { #meta { table { margin: 0; tr:last-child td { padding-bottom: 0; } td { padding: 0 0 5px; ul.networks { margin: 0; padding: 0; li { list-style: none; display: inline; } li { } } } td.label { color: @grey; white-space: nowrap; width: 1%; text-align: right; padding-right: 5px; } } } } /* Voting */ div.voted { font-size: 12px; line-height: 22px; color: @black; display: inline-block; font-weight: bold; img { float: left; margin-right: 5px; padding: 3px; .border_radius(3); } } #voted_up { img { background: @colour_positive * 0.66 + @bg * 0.15; } } #voted_down { img { background: @colour_negative * 0.66 + @bg * 0.15; } } #encourage_comment { display: inline-block; line-height: 22px; font-weight: bold; } #vote { overflow: hidden; font-size: 12px; line-height: 22px; color: @black; float: left; a { color: @white; font-weight: bold; overflow: hidden; display: block; width: 16px; text-decoration: none; text-align: center; font-size: 10px; padding: 3px; text-transform: uppercase; } a.up { float: left; background: @colour_positive * 0.66 + @bg * 0.15; .border_radius_left(3); :hover { background: @colour_positive * 0.85 + @bg * 0.15; } } a.down { float: left; background: @colour_negative * 0.66 + @bg * 0.15; .border_radius_right(3); margin: 0 5px 0 1px; :hover { background: @colour_negative * 0.85 + @bg * 0.15; } } } #vote.disabled { a.up { background: (@colour_positive * 0.66 + @bg * 0.15) * 0.15 + @grey * 0.85; :hover { background: (@colour_positive * 0.85 + @bg * 0.15) * 0.25 + @grey * 0.75; } } a.down { background: (@colour_negative * 0.66 + @bg * 0.15) * 0.15 + @grey * 0.85; :hover { background: (@colour_negative * 0.85 + @bg * 0.15) * 0.25 + @grey * 0.75; } } } /* Panels */ div.panel { margin: 0 0 20px; position: relative; .box_shadow(0, 0, 3, @light_grey * 0.66 + @white * 0.33); .border_radius(3); > div.header { background: @bg url('/images/panel_header_bg.png') repeat-x top left; border-bottom: 1px solid (@bg * 0.66 + @black * 0.33); padding: 5px 10px 4px; .border_radius_top(3); min-height: 18px; h2 { font-size: 16px; margin: 0; color: @white; .text_shadow(1, 1, 0, @bg * 0.66 + @black * 0.33); } h3 { color: @white; font-size: 14px; margin: 0; line-height: 18px; .text_shadow(1, 1, 0, @bg * 0.66 + @black * 0.33); } small { display: block; font-size: 12px; color: @light_grey * 0.25 + @white * 0.75; } span.filter { float: left; display: block; overflow: hidden; position: relative; z-index: 5; a { margin: 0 1px 0 0; display: block; float: left; padding: 0 8px; height: 18px; font-weight: bold; font-size: 10px; line-height: 18px; text-transform: uppercase; background: url('/images/transparent_backgrounds/black_50.png'); color: @light_grey; text-decoration: none; position: relative; z-index: 3; } a:first-child { .border_radius_left(2); } a:last-child { .border_radius_right(2); margin-right: 0; } a.active { background: @white; color: @black; z-index: 4; } a:hover { color: @white; } a.active:hover { color: @black; } } span.filter.dropdown { margin: 0; position: relative; overflow: visible; a { .border_radius(2); background: @white; color: @black; margin: 0; position: relative; padding-right: 25px; img { float: left; margin: 4px 5px 0 0; } b.arrow { float: right; display: block; height: 0; width: 0; border: 5px solid transparent; border-top: 5px solid @black; border-bottom: none; position: absolute; top: 6px; right: 10px; } :hover { background: @accent_colour; color: @white; b.arrow { border-top: 5px solid @white; } } } ul { position: absolute; top: 100%; left: 0; margin: 1px 0 0; padding: 0; background: @white; .border_radius(2); .box_shadow(0, 1, 1, @black); li { list-style: none; display: block; padding: 0; margin: 0; a { display: block; height: 18px; line-height: 18px; color: @black; font-size: 10px; text-transform: uppercase; background: transparent; border-bottom: 1px solid (@light_grey * 0.66 + @white * 0.33); float: none; margin: 0; .border_radius(0); white-space: nowrap; :hover { background: url('/images/transparent_backgrounds/accent_colour_25.png'); color: @black; } } } li:last-child { a { border: none; } } } } span.filter.dropdown.sort { float: left; margin: 0 0 0 10px; } span.filter.dropdown.localisation { float: left; margin: 0 0 0 10px; } a.more { float: right; color: @white; .text_shadow(1, 1, 0, @bg * 0.66 + @black * 0.33); font-size: 14px; font-weight: bold; position: relative; top: 2px; :hover { text-decoration: none; } } } > div.content { background: @white; padding: 10px; .no_padding { padding: 0; } } > div.footer { background: @light_grey * 0.33 + @white * 0.66; border-top: 1px solid (@light_grey * 0.5 + @white * 0.5); padding: 4px 10px 5px; .border_radius_bottom(3); } } div.panel.no_footer div.content { .border_radius_bottom(3); } div.panel.no_header div.content { .border_radius_top(3); } div.panel.collapsable { div.header { cursor: pointer; b.toggle { float: right; border: 5px solid transparent; border-bottom: 5px solid @white; border-top: none; display: block; width: 0; height: 0; margin: 6px 0 0 0; } } div.header:hover { background-color: @bg * 0.75 + @white * 0.25; } } div.panel.collapsed { div.header { border-bottom: none; .border_radius(3); b.toggle { border-bottom: none; border-top: 5px solid @white; } } div.blank { border-bottom: none; .border_radius_bottom(3); } div.content, div.footer { display: none; } } /* Sidebar Actions */ #sidebar { #actions { .box_shadow(0, 0, 0, transparent); div.content { background: url('/images/transparent_backgrounds/accent_colour_10.png'); text-align: center; p.endorsement { margin: 0 0 10px; font-size: 14px; font-weight: bold; small { font-weight: normal; line-height: inherit; margin: 10px 0 0; } :last-child { margin: 0; } } div.share { margin: 5px 0 0; } a.button { font-size: 16px; line-height: normal; height: auto; padding: 5px 10px 5px 35px; font-weight: bold; margin: 0; position: relative; img { position: absolute; top: 3px; left: 6px; } } div.flash.notice { margin: 10px 0 0; font-size: 22px; small { font-weight: normal; margin: 0 0 10px; } } div.flash.notice.done { margin: 0; } small { display: block; margin: 10px 0 0; font-size: 11px; color: #808080; line-height: 12px; img.favicon { vertical-align: middle; } } div.blank { border: none; background: none; padding: 10px 0 0; border-top: 1px solid (@accent_colour * 0.5 + @white * 0.5); margin: 10px 0 0; } } } } /* People Lists */ ul.people { margin: 0; padding: 10px 0 0 10px; background: @white; > li { display: block; margin: 0 10px 10px 0; float: left; padding: 2px; width: 57px; position: relative; .border_radius(2); background: @white; list-style: none; border: 1px solid (@light_grey * 0.33 + @white * 0.66); a.avatar { display: block; width: 59px; height: 59px; overflow: hidden; img { width: 100%; height: 100%; } } a.name { display: block; font-size: 10px; text-align: center; } :hover { background: @accent_colour; a.name { color: @white; } } } } ul.people.list { padding: 0; > li { margin: 0 0 10px; padding: 0 0 10px; overflow: hidden; float: none; width: auto; .border_radius(0); border: none; border-bottom: 1px solid (@light_grey * 0.33 + @white * 0.66); span.points { float: right; display: block; padding: 5px; background: @light_grey * 0.15 + @white * 0.85; line-height: 1; text-align: center; width: 50px; height: 30px; .border_radius(3); margin: 0 0 0 10px; strong { display: block; color: @black; font-size: 16px; margin: 2px 0 0; } label { color: @grey; text-transform: uppercase; font-size: 10px; } label.long { display: block; } label.short { display: none; } } a.avatar { float: left; width: 40px; height: 40px; } a.name { font-size: 14px; font-weight: bold; margin: 0 0 0 50px; text-align: left; } a.name.long { display: inline; } a.name.short { display: none; } span.networks { display: block; margin: 0 0 0 50px; img.favicon { vertical-align: middle; } } :hover { background: transparent; a.name { color: @accent_colour * 0.85 + @black * 0.15; } } :last-child { padding-bottom: 0; border-bottom: none; margin-bottom: 0; } } } ul.people.list.small { > li { span.points { padding: 3px 6px; height: 18px; font-size: 9px; line-height: 17px; width: 60px; strong { font-size: 12px; margin: 0; display: inline; } label { font-size: 9px; } label.long { display: none; } label.short { display: inline; } } a.avatar { width: 24px; height: 24px; } a.name { display: inline; line-height: 24px; margin: 0 0 0 5px; font-size: 12px; height: 24px; } a.name.long { display: none; } a.name.short { display: inline; } span.networks { display: inline; margin: 0; } :last-child { padding-bottom: 0; border-bottom: none; margin-bottom: 0; } } } ul.people.tiled { > li { width: 28px; padding: 2px; a.avatar { width: 24px; height: 24px; background: @white; padding: 2px; } a.name, small, span.networks, span.points { display: none; } } } /* Comments */ #comments { ul { margin: 0 0 20px; padding: 0; li { display: block; list-style: none; padding: 0; margin: 0 0 10px; span.meta { margin: 0; overflow: hidden; display: block; small { font-size: 12px; color: @light_grey; float: right; line-height: 16px; display: inline-block; } a.avatar { display: inline-block; height: 16px; width: 16px; position: relative; top: 3px; img { height: 100%; width: 100%; } } a.name { font-weight: bold; line-height: 16px; display: inline-block; } span.inactive { color: @grey; font-weight: bold; line-height: 16px; display: inline-block; } } b.tail { display: block; width: 0; height: 0; margin: 3px 0 0 10px; border: 5px solid transparent; border-top: none; border-bottom: 5px solid @white; position: relative; z-index: 2; } blockquote { margin: 0; padding: 10px; .border_radius(3); font-style: normal; background: @white; color: @dark_grey; .box_shadow(0, 0, 3, @light_grey * 0.66 + @white * 0.33); } } } form { margin: 0; textarea { width: 500px; } } } /* Sidebar Categories */ #sidebar { #categories { margin: 0 0 20px; width: auto; p { margin: 0; } } } #sidebar { #ads > ul li, #recommendations > ul li { width: 81px; div.thumbnail { a.thumbnail { height: 60px; width: 81px; } } div.text { a.title { font-size: 11px; height: 14px; line-height: 14px; } small { display: none; } } } #brands > ul li { width: 55px; div.thumbnail { a.thumbnail { height: 45px; width: 45px; img { max-height: 45px; max-width: 45px; } } } div.text { display: none; } } } /* My Account */ #accounts_controller { #top { #page_title { #page_options { a.button.public_profile { float: right; font-size: 16px; line-height: 1; height: auto; padding: 8px 35px 8px 15px; position: relative; b.arrow { display: block; height: 0; width: 0; position: absolute; top: 10px; right: 15px; border: 6px solid transparent; border-right: none; border-left: 6px solid @white; margin: 0; } } a.button.goto_dashboard { float: right; font-size: 16px; line-height: 1; height: auto; padding: 8px 15px 8px 35px; margin-right: 5px; position: relative; b.arrow { display: block; height: 0; width: 0; position: absolute; top: 10px; left: 15px; border: 6px solid transparent; border-left: none; border-right: 6px solid @white; margin: 0; } } } } } #account_nav { float: left; width: 200px; margin: 0 20px 0 0; ul.nav { margin: 0; padding: 0; li { margin: 0 0 5px; display: block; list-style: none; padding: 0; a { display: block; height: 30px; text-decoration: none; color: @white; b { border: 15px solid transparent; border-right: none; border-left: 10px solid transparent; width: 0; height: 0; float: right; display: none; } span { .border_radius(3); background: @bg; display: block; line-height: 30px; padding: 0 10px; font-size: 14px; font-weight: bold; margin: 0 10px 0 0; } } :hover { a { color: @white; b { border-left-color: @bg; display: block; } span { background: @bg; .border_radius_right(0); } } } } li.current a { b { border-left-color: @accent_colour; display: block; } span { background: @accent_colour; color: @white; .border_radius_right(0); } } } } #main { > div { margin: 0 0 20px; form { margin: 0; } } #profile { a.avatar { float: left; display: block; width: 70px; overflow: hidden; position: relative; text-decoration: none; img { width: 100%; } span { display: block; line-height: 1; padding: 3px; margin: 5px 0 0; color: @white; background: @accent_colour; .border_radius(3); .text_shadow(1, 1, 0, @grey); text-align: center; font-size: 10px; font-weight: bold; text-transform: uppercase; } } form { margin: 0 0 0 90px; h4 { margin: 10px 0 20px; border-bottom: 1px solid (@light_grey * 0.5 + @white * 0.5); padding: 0; color: @bg; font-size: 16px; } ul.choices { li { width: 30%; } } div.extra { margin-top: 20px; } } } #networks { ul { margin: 0 -10px -10px 0; padding: 0; overflow: hidden; li:hover { background: @light_grey; display: block; float: left; width: 180px; padding: 10px; margin: 0 10px 10px 0; list-style: none; .border_radius(3); position: relative; * { line-height: normal; } img { vertical-align: middle; float: left; } .name { font-weight: bold; font-size: 14px; display: block; margin: -2px 0 0 42px; } small { font-size: 12px; color: @grey; display: block; margin-left: 42px; strong { color: @black; font-weight: normal; } } :hover { } } li.installed { background: @white; border: 2px solid @accent_colour; padding: 8px; } li.unavailable { .name { color: @black; } :hover { background: @light_grey; } } li:hover { background: @light_grey * 0.5 + @white * 0.5; } } } } } /* Shopping Style Panel */ #shopping_style { div.header a.button.small { float: right; } div.content { p { margin: 0 0 10px; label { text-transform: uppercase; font-size: 11px; display: block; color: @bg; font-weight: bold; } span { color: @black; } span.toggle { white-space: nowrap; color: @grey; } :last-child { margin: 0; } } p.more { text-align: left; font-weight: normal; } p.less { display: none; margin: 0; } } } /* People Controller */ #people_controller.index { #main { div.panel { float: left; width: 300px; margin: 0 20px 0 0; :last-child { margin-right: 0; } } } } #people_controller.show { #person_overview, #shopping_style { a.button.small { } } #content { #shopping_style { float: left; width: 240px; margin: 0 20px 0 0; } #main { width: 360px; } } } /* Search Results */ #search_results { margin: 0 0 20px; li { :hover { small { color: @white * 0.75 + @accent_colour * 0.25; } } } } #search { div.content { padding: 20px; form { margin: 0; float: none; span.submit_and_options { display: block; } } p { margin: 0 0 15px; } h4 { font-weight: normal; margin: 0 0 5px; } } } /* Recommendations */ #recommendations { div.browse { margin: 0; padding: 0; background: none; ul { min-height: 0; .border_radius(0); } } } /* Blank States */ div.blank { padding: 20px; background: @bg * 0.05 + @blue * 0.05 + @white * 0.9; position: relative; border: 1px solid (@bg * 0.1 + @blue * 0.1 + @white * 0.8); z-index: 1; h4 { font-size: 18px; margin: 0 0 10px; } h4:last-child { margin: 0; } p { font-size: 16px; margin: 0 0 10px; } p:last-child { margin: 0; } p.with_list_number.large { span { margin-left: 48px; display: block; color: @white; } } p.earn span { font-size: 22px; color: @white; line-height: 48px; font-weight: bold; } a { white-space: nowrap; } a.hide { position: absolute; top: -5px; right: -5px; display: block; height: 16px; width: 16px; padding: 3px; background: #E7E9F6; .border_radius(99); } } div.blank.small { padding: 10px 20px; h4 { font-weight: normal; font-size: 16px; } p { margin: 0; } } div.blank.tiny { padding: 10px 20px; h4 { font-weight: normal; font-size: 14px; } p { margin: 0; font-size: 12px; } } div.blank.rounded { .border_radius(3); margin: 0 0 20px; } div.blank.rounded.bottom { .border_radius_top(0); } div.blank.with_border_bottom { border-bottom: 1px solid (@bg * 0.1 + @blue * 0.1 + @white * 0.8); } div.blank.no_border_top { border-top: none; } div.blank.no_border_bottom { border-bottom: none; } div.blank.no_side_borders { border-right: none; border-left: none; } div.panel { div.blank { padding: 10px 20px; overflow: hidden; margin: 0; h4 { font-weight: normal; font-size: 14px; } p, ul { margin: 0 0 10px; font-size: 12px; } p:last-child, ul:last-child { margin: 0; } } } /* Sidebar Browse */ #sidebar { div.panel { div.content.browse { padding: 0; margin: 0; > ul { min-height: 0; .border_radius(0); > li { div.thumbnail { a.thumbnail { padding: 5px; } img.marker.media_type { top: 48px; left: 8px; } } div.footer { a.title, a.name { font-size: 11px; font-weight: normal; } } } } } div.content.browse.ads > ul > li { width: 93px; > div.thumbnail a.thumbnail { width: 83px; height: 62px; } } div.content.browse.brands { .border_radius(3); > ul { background: none; > li { width: 52px; > div.thumbnail { padding: 3px; a.thumbnail { width: 42px; height: 42px; padding: 2px; } } li.active { background: @accent_colour; } } } } div.footer { div.info { float: none; } div.pagination { float: none; margin: 3px 0 0; } } } } /* List Numbers */ label.list_number { float: left; background: url('/images/transparent_backgrounds/black_15.png'); padding: 2px; width: 24px; height: 24px; display: block; .border_radius(99); b { display: block; font-weight: bold; font-size: 14px; color: @white; background: @accent_colour; height: 20px; width: 20px; line-height: 20px; text-align: center; .border_radius(99); .text_shadow(1, 1, 0px, (@accent_colour * 0.75 + @black * 0.25)); border: 2px solid @white; } } label.list_number.large { padding: 4px; width: 48px; height: 48px; .border_radius(99); position: relative; left: -10px; b { font-size: 28px; height: 40px; width: 40px; .border_radius(99); line-height: 40px; .text_shadow(2, 2, 0px, (@accent_colour * 0.75 + @black * 0.25)); border-width: 4px; } } /* Dashboard */ #dashboard_controller { #ads { span.filter.state { float: right; } } #sidebar { #shopping_style div.content { p.less { display: block; } p.more { display: none; } } #influences { div.header { padding-bottom: 0; ul.tabs { position: relative; top: 1px; z-index: 3; li { margin: 0 5px 0 0; a { border: none; background: url('/images/transparent_backgrounds/white_75.png'); :hover { color: @black; } } } li.active { a { background: @white; border: none; :hover { color: @black; } } } } } div.tab_content { overflow: hidden; padding: 0; > ul { padding: 10px 10px 0; max-height: 280px; min-height: 120px; overflow-y: scroll; .border_radius_bottom(3px); } } div.footer { form { p { margin: 0 0 5px; img.marker { float: right; margin: 5px 0 0 0; } span.invitee { line-height: 26px; padding: 3px 3px 0; font-size: 14px; small { color: @grey; font-size: 12px; } } } p.indent { margin-left: 36px; } p.submit { margin-top: 10px; } } } } } div.panel.full { > div.content { margin: 0; padding: 0; background: none; ul { li { width: 148px; div.thumbnail { img.marker.media_type { top: 90px; } a.thumbnail { width: 138px; height: 104px; } } } } } } #people { form { padding: 0 0 5px; input { width: 225px; float: left; margin: 0 5px 0 0; } a.button { height: 23px; line-height: 23px; width: 60px; padding: 0; text-align: center; } } } } /* Remove Pages Titles when Browsing */ #ads_controller, #brands_controller { #page_title { display: none; } } /* Brands > Show */ #brands_controller.show { #ads { div.filters { h3 { font-size: 16px; margin: 0; } span.show { float: right; } span.filter.dropdown.localisation { float: right; margin: 0 0 0 10px; } span.filter.state { float: right; margin: 0 0 0 10px; } } } } /* FAQ */ #pages_controller.faq { #answers { h3 { margin-top: 20px; padding-top: 20px; border-top: 1px solid (@light_grey * 0.75 + @white * 0.25); } h3.first { margin-top: 0; padding-top: 0; border: none; } } #questions { div.content { padding: 20px; ul { margin: 0; padding: 0; li { margin: 0 0 10px; list-style: none; display: block; padding: 0; a { font-size: 14px; } } li:last-child { margin: 0; } } } } } /* Person Overview */ #person_overview { padding: 20px 10px; position: relative; z-index: 25; #person { float: left; width: 620px; a.avatar { display: block; float: left; width: 60px; height: 60px; img { height: 100%; width: 100%; } } > div { margin: 0 0 0 75px; color: @white; font-size: 14px; .text_shadow(1, 1, 0, @bg * 0.66 + @black * 0.33); } div.name { h2 { margin: 0 0 5px; display: inline; a { font-size: 20px; font-weight: bold; .text_shadow(1, 1, 0, @bg * 0.66 + @black * 0.33); line-height: 1; color: @white; text-decoration: none; :hover { text-decoration: underline; } } a.button.small { font-size: 10px; :hover { text-decoration: none; } } } span.points { float: right; display: block; padding: 5px 10px; .border_radius(2); text-align: center; background: @white; position: relative; min-width: 45px; strong { color: @black; font-weight: bold; font-size: 24px; line-height: 1; display: block; .text_shadow(0, 0, 0, transparent); } label { font-size: 9px; text-transform: uppercase; color: @grey; display: block; .text_shadow(0, 0, 0, transparent); font-weight: bold; } } span.points.with_redeem { .border_radius_bottom(0); a.button { display: block; text-align: center; .border_radius_top(0); font-size: 10px; font-weight: bold; padding: 0; position: absolute; height: 18px; left: 0; right: 0; bottom: -19px; line-height: 18px; text-transform: uppercase; border: none; } } div.options { margin: 0; } } div.meta { color: @white * 0.66 + @bg * 0.33; span { color: @white; } label { color: @white * 0.66 + @bg * 0.33; } ul.networks { display: inline; margin: 0; padding: 0; li { display: inline; line-height: 1; img { position: relative; vertical-align: middle; top: -1px; } } } } div.extra { font-size: 12px; margin-top: 20px; margin-bottom: 20px; span.toggle { .text_shadow(1, 1, 0, @bg * 0.66 + @black * 0.33); a { font-size: 10px; font-weight: bold; text-transform: uppercase; text-decoration: none; color: @accent_colour; } b.arrow { display: inline-block; width: 0; height: 0; border: 5px solid transparent; position: relative; top: -2px; } } #less_info { span.toggle { b.arrow { border-top: 5px solid @accent_colour; border-bottom: 0; } } } #more_info { span.toggle { float: right; b.arrow { border-bottom: 5px solid @accent_colour; border-top: 0; } } h4 { color: @white; margin: 0 0 10px 0; border-bottom: 1px solid (@white * 0.25 + @bg * 0.75); .text_shadow(1, 1, 0, @bg * 0.66 + @black * 0.33); span { font-size: 12px; } } p { margin: 0 0 5px; label { display: block; float: left; width: 120px; color: @white * 0.66 + @bg * 0.33; } span { display: block; margin: 0 0 0 130px; } } p:last-child { margin: 0; } } } div.login { margin: 0 0 0 75px; a.button { font-weight: bold; } } } } /* Dashboard Nav */ #dashboard_nav { position: absolute; bottom: 0; left: 10px; margin: 0; padding: 0; overflow: hidden; li { display: block; float: left; margin: 0 5px 0 0; a { display: block; height: 28px; padding: 0 10px; line-height: 28px; .border_radius_top(2); text-decoration: none; color: @white; background: url('/images/transparent_backgrounds/accent_colour_30.png'); font-size: 14px; font-weight: bold; :hover { background: url('/images/transparent_backgrounds/accent_colour_45.png'); } } } li.active { a { background: @white; color: @black; :hover { color: @black; } } } } /* Dwellometer */ #dwellometer { z-index: 45; float: right; .box_shadow(0, 0, 0, transparent); margin: 0; div.content { text-align: center; position: relative; object, object embed { position: relative; z-index: 46; line-height: 0; } div.title { position: absolute; bottom: 10px; left: 0; right: 0; z-index: 50; img { width: 120px; display: block; margin: 0 auto; position: relative; left: -5px; } } } } /* Activity Stream */ #activity { div.content { ul.events { padding: 0; margin: 0 0 -10px; li { margin: 0; padding: 10px 0; border-bottom: 1px solid (@light_grey * 0.33 + @white * 0.66); list-style: none; overflow: hidden; small.meta { font-size: 12px; color: @light_grey; float: right; } a.button { float: right; margin: 0 0 10px 10px; } a.avatar, a.logo, a.thumbnail { height: 32px; display: block; float: left; img { width: 100%; height: 100%; } } a.avatar, a.logo, a.icon { width: 32px; } a.thumbnail { width: 42px; } div.symbols { float: left; overflow: hidden; b { display: block; float: left; margin: 10px 5px 0; img { height: 12px; width: 12px; } } b.voted { margin: 10px 3px 0; padding: 2px; .border_radius(2); } b.voted.for { background: @colour_positive * 0.33 + @white * 0.66; } b.voted.against { background: @colour_negative * 0.33 + @white * 0.66; } } /* Temporarily removed avatar and symbol */ /* div.symbols a.agent, b { display: none; }*/ div.description { font-size: 12px; color: @grey; a.agent { font-weight: bold; } } div.comment { margin-top: 2px; b.tail { display: block; margin: 0 0 0 10px; width: 0; height: 0; border: 5px solid transparent; border-top: none; border-bottom: 5px solid (@light_grey * 0.25 + @white * 0.75); } blockquote { margin: 0; font-style: normal; color: @dark_grey; .border_radius(3); background: @light_grey * 0.25 + @white * 0.75; padding: 5px 10px; span.view_comment { color: @grey; } } } div.content { overflow: hidden; } } li.new_comment.ad, li.endorsed.ad, li.voted { div.description, div.content { margin-left: 106px; } /* div.description, div.content { margin-left: 53px; }*/ } li.new_comment.brand, li.replied_to, li.endorsed.brand, li.connected, li.sn_setup { div.description, div.content { margin-left: 96px; } /* div.description, div.content { margin-left: 43px; }*/ } li.replied_to { div.content { a.thumbnail, a.logo { margin-top: 7px; } } } li.replied_to.ad { div.content { div.comment { margin-left: 52px; } } } li.replied_to.brand { div.content { div.comment { margin-left: 42px; } } } li.voted div.description span.action { .border_radius(2); color: @dark_grey; padding: 0 3px; white-space: nowrap; } li.voted.for div.description span.action { background: @colour_positive * 0.15 + @white * 0.85; } li.voted.against div.description span.action { background: @colour_negative * 0.15 + @white * 0.85; } li:first-child { padding-top: 0; } li:last-child { border-bottom: none; } li:hover div.content div.comment blockquote span.view_comment { } } } } /* Login/Register Modal */ #login_register { div.location_select, div.location_search { margin-left: 130px; } h3 { small { font-size: 14px; font-weight: normal; display: block; color: @grey; text-align: left; margin: 0; display: block; } } } /* Contact Form in Pages */ #pages_controller { #sidebar { #contact { margin: 15px 0 0; form { label { text-align: left; float: none; width: auto; font-size: 12px; font-weight: bold; line-height: 1; margin: 0 0 5px; } p.submit.indent { margin: 0; span.with_cancel { display: none; } } } } } } /* Exclusive Offers */ #offers { div.content { a.gift { display: block; text-align: center; img { height: 100px; } } } } div.browse { margin: 0 0 20px; &.class { padding: 0; } div.header { padding: 10px 10px 9px; text-align: left; background: @bg url('/images/panel_header_bg.png') repeat-x top left; border-bottom: 1px solid (@bg * 0.66 + @black * 0.33); line-height: 1; height: 18px; .border_radius_top(3); color: @light_grey; h3 { font-size: 16px; margin: 0; color: @white; .text_shadow(1, 1, 0, @bg * 0.66 + @black * 0.33); } span.filter { float: left; display: block; overflow: hidden; position: relative; z-index: 5; a { margin: 0 1px 0 0; display: block; float: left; padding: 0 8px; height: 18px; font-weight: bold; font-size: 10px; line-height: 18px; text-transform: uppercase; background: url('/images/transparent_backgrounds/black_50.png'); color: @light_grey; text-decoration: none; position: relative; z-index: 3; .active { background: @white; color: @black; z-index: 4; :hover { color: @black; } } :hover { color: @white; } :first-child { .border_radius_left(2); } :last-child { .border_radius_right(2); margin-right: 0; } } } span.filter.dropdown { margin: 0; position: relative; overflow: visible; a { .border_radius(2); background: @white; color: @black; margin: 0; position: relative; padding-right: 25px; img { float: left; margin: 4px 5px 0 0; } b.arrow { float: right; display: block; height: 0; width: 0; border: 5px solid transparent; border-top: 5px solid @black; border-bottom: none; position: absolute; top: 6px; right: 10px; } :hover { background: @accent_colour; color: @white; b.arrow { border-top: 5px solid @white; } } } ul { position: absolute; top: 100%; left: 0; margin: 1px 0 0; padding: 0; background: @white; .border_radius(2); .box_shadow(0, 1, 1, @black); li { list-style: none; display: block; padding: 0; margin: 0; a { display: block; height: 18px; line-height: 18px; color: @black; font-size: 10px; text-transform: uppercase; background: transparent; border-bottom: 1px solid (@light_grey * 0.66 + @white * 0.33); float: none; margin: 0; .border_radius(0); white-space: nowrap; :hover { background: url('/images/transparent_backgrounds/accent_colour_25.png'); color: @black; } } :last-child { a { border: none; } } } } } span.filter.dropdown.sort { float: left; margin: 0 0 0 10px; } span.filter.dropdown.localisation { float: left; margin: 0 0 0 10px; } a.more { float: right; color: @white; .text_shadow(1, 1, 0, @bg * 0.66 + @black * 0.33); font-size: 14px; font-weight: bold; position: relative; top: 2px; :hover { text-decoration: none; } } } > ul { margin: 0; background: @white; padding: 10px 0 0 10px; .border_radius(3); position: relative; li { display: block; float: left; list-style: none; margin: 0 10px 10px 0; padding: 5px; position: relative; background: @white; width: 130px; border: 1px solid (@light_grey * 0.33 + @white * 0.66); .border_radius(2); a.remove { position: absolute; height: 16px; width: 16px; padding: 3px; background: @accent_colour; .border_radius(99); display: none; z-index: 3; top: -8px; right: -8px; img { vertical-align: middle; } } div.thumbnail { .border_radius_top(3); position: relative; z-index: 3; .marker { position: absolute; padding: 2px; .border_radius(2); z-index: 3; background: url('/images/transparent_backgrounds/white_75.png'); height: 12px; width: 12px; } .marker.coupon { height: auto; width: auto; top: 10px; right: -3px; padding: 0; background: transparent; overflow: hidden; position: absolute; b { display: block; height: 0; width: 0; float: left; border: 14px solid transparent; border-top: 14px solid @accent_colour; border-bottom: none; border-right: none; float: left; } span { color: @white; font-size: 10px; font-weight: bold; text-transform: uppercase; height: 14px; line-height: 14px; display: block; padding: 0 4px 0 2px; background: @accent_colour; .text_shadow(1, 1, 0px, (@accent_colour * 0.75 + @black * 0.25)); margin: 0 0 0 14px; } } .marker.video { position: absolute; left: 50%; top: 50%; background: @white; width: 10px; height: 10px; b { display: block; width: 0; height: 0; border: 5px solid transparent; border-left: 10px solid @black; border-right: none; } } .marker.endorsed_by_me { background: none; padding: 0; right: 0; bottom: -32px; .border_radius(2); background: @white; } a.thumbnail { display: block; overflow: hidden; position: relative; text-align: center; img { position: relative; display: block; margin: auto; } } } div.text { margin: 3px 0 0; display: block; a { text-decoration: none; } a.title { display: block; text-decoration: none; font-weight: bold; font-size: 12px; line-height: 16px; white-space: nowrap; height: 16px; overflow: hidden; :before { display: block; height: 32px; width: 20px; content: " "; float: right; right: -15px; top: -8px; background: @white; position: relative; z-index: 1; .box_shadow(-5, 0, 10, @white); } } small { font-size: 11px; line-height: 13px; color: @grey; display: block; height: 13px; overflow: hidden; white-space: nowrap; a { font-weight: bold; } :before { display: block; height: 32px; width: 20px; content: " "; float: right; right: -15px; top: -8px; background: @white; position: relative; z-index: 1; .box_shadow(-5, 0, 10, @white); } } } :hover { background: @accent_colour; a.remove { display: block; } div.thumbnail { a.marker.remove, a.marker.video { b { display: inline-block; } } a.marker.video { .box_shadow(0, 0, 2, @black); } } div.text { a { color: @white; } a.title:before { background: @accent_colour; .box_shadow(-5, 0, 10, @accent_colour); } small { color: @white * 0.75 + @accent_colour * 0.25; :before { background: @accent_colour; .box_shadow(-5, 0, 10, @accent_colour); } } } div.footer a { color: @white; } } } > li.ad div.thumbnail a.thumbnail { width: 130px; height: 97px; img { width: 100%; height: 100%; } } > li.brand div.thumbnail a.thumbnail { width: 120px; height: 87px; padding: 5px; background: @white; .border_radius(2); img { max-width: 120px; max-height: 87px; } } li.paginate { margin-bottom: 0; a { display: block; position: relative; text-decoration: none; height: 131px; div.arrow { background: #81c153 url('/images/button_bg.png') repeat-x left top; border: 1px solid (@accent_colour * 0.75 + @black * 0.25); height: 44px; .border_radius(99); width: 44px; margin: 0 auto; position: relative; top: 32px; b { text-indent: -9000px; display: block; border: 10px solid transparent; width: 0; height: 0; position: relative; top: 12px; } } div.label { position: absolute; bottom: 5px; left: 0; right: 0; line-height: 13px; color: @accent_colour * 0.85 + @black * 0.15; text-decoration: none; font-weight: bold; font-size: 12px; text-align: center; } :hover { div.arrow { background: #abd56e url('/images/button_bg.png') repeat-x left -44px; } } } :hover { background: transparent; } } li.paginate.previous a div b { border-right: 15px solid @white; border-left: none; left: 12px; } li.paginate.next a div b { border-left: 15px solid @white; border-right: none; left: 16px; } } > div.footer { padding: 9px 10px 10px; background: @light_grey * 0.75 + @white * 0.25; overflow: hidden; border-top: 1px solid @light_grey; .border_radius_bottom(3); div.info { float: left; color: @grey; strong { color: @black; font-weight: normal; } } div.pagination { float: right; > * { display: inline-block; line-height: 1; padding: 0 6px; line-height: 18px; height: 18px; background: @white; .border_radius(3); text-decoration: none; font-weight: bold; font-size: 10px; text-transform: uppercase; } a { color: @grey; } a:hover { color: @black; } span.disabled { color: @light_grey; } span.current { color: @white; background: @bg; border: none; } span.current:hover { color: @white; } } } } div.browse.with_categories { margin: 0 0 0 160px; } div.browse.with_options > ul { .border_radius_top(0); } div.browse.with_footer > ul { .border_radius_bottom(0); } /* Browse List */ div.browse.list { > ul { margin: 0; min-height: 320px; padding: 10px 0 0 10px; overflow: hidden; > li { display: block; list-style: none; margin: 0 10px 10px 0; padding: 5px; .border_radius(3); position: relative; line-height: normal; .marker { position: absolute; padding: 2px; .border_radius(2); background: url('/images/transparent_backgrounds/white_75.png'); img { height: 12px; width: 12px; } } img.marker { height: 12px; width: 12px; } span.marker.new { color: black; left: -5px; top: -5px; background: none; background-color: @white * 0.1 + @yellow * 0.6 + @red * 0.3; line-height: 1; padding: 2px 5px; font-weight: bold; } a.marker.media_type { display: inline-block; text-decoration: none; top: 39px; left: 8px; font-size: 10px; b { font-weight: normal; margin: 0 0 0 2px; line-height: 1; display: none; } img { vertical-align: middle; } } a.thumbnail { float: left; width: 68px; display: block; overflow: hidden; border: 1px solid @light_grey; :hover { border-color: @accent_colour; } } span.title_brand { display: block; margin: 0 0 2px 75px; a { margin: 0; display: inline; } a.brand_name { font-weight: normal; font-size: 12px; } } a.ad_title { font-weight: bold; font-size: 14px; margin: 0 0 0 75px; display: block; } a.brand_name { font-weight: bold; font-size: 14px; margin: 0 0 0 75px; display: block; } small { display: block; color: @grey; margin: 0 0 0 75px; font-size: 12px; } small.brand_name { display: inline; margin: 0; } ul.chart { margin: 0 0 0 80px; height: 39px; } ul.networks { margin: 3px 0 0 75px; padding: 0; overflow: hidden; li { display: block; float: left; margin: 0 5px 0 0; line-height: 1; } } div.points { display: none; font-size: 12px; text-align: right; label { color: @grey; } } a.remove { bottom: -3px; right: -3px; } } li.ad { a.thumbnail { height: 51px; } span.title_brand { small.brand_name { display: block; } } } li.brand { a.thumbnail { height: 68px; } } } } div.browse.list.with_options ul { .border_radius_top(0); } div.browse.list.with_footer ul { .border_radius_bottom(0); } div.browse.list.cols_2 { > ul { > li { width: 285px; float: left; :hover { background: @white; } } } } div.browse.ads.list { > ul { > li { height: 53px; a.thumbnail { height: 51px; } } } } div.browse.brands.list { > ul { > li { height: 68px; a.thumbnail { height: 66px; } } } } /* Categories List */ #categories { margin: 40px 0 0; width: 160px; float: left; position: relative; z-index: 1; ul { margin: 0; padding: 10px 0 0; li { list-style: none; margin: 0; padding: 0; font-size: 14px; a { color: @grey; display: block; padding: 5px 10px 5px 15px; text-decoration: none; .border_radius_left(3); } a:hover { color: @black; background: @light_grey * 0.15 + @white * 0.85; } } .all a { font-weight: bold; } .current a { background: @white; color: @black; border: 1px solid (@light_grey * 0.25 + @white * 0.75); border-right: none; border-left: 5px solid @bg; padding-left: 10px; } } } /* Ads > Show */ #ad { div.header { overflow: hidden; h3 { font-size: 16px; margin: 0 0 3px; } small { a.category { font-weight: bold; color: @accent_colour; } span.networks img { position: relative; top: 3px; } } span.brand { float: right; color: @white; a.brand_name { font-weight: bold; color: @accent_colour; } } } div.content { padding: 0; position: relative; a.toggle_size { display: block; .border_radius(3); background-color: @black; padding: 0 5px 0 26px; background-position: 5px center; background-repeat: no-repeat; text-decoration: none; margin: 5px 5px 0 0; position: absolute; top: 0; right: 0; line-height: 25px; z-index: 45; } img.creative { margin: 0 auto; max-width: 540px; display: block; } object { position: relative; z-index: 44; } object.video { line-height: 0; font-size: 0; } object embed { position: relative; z-index: 45; line-height: 0; font-size: 0; } } div.content.not_video { padding: 40px; text-align: center; * { margin-left: auto; margin-right: auto; } object.flash { margin-bottom: 0; } } div.footer { padding: 0; div.vote_views { padding: 5px 10px; overflow: hidden; div.share { float: right; margin: 2px 0 0 0; } #login_register_msg, #encourage_vote_msg { line-height: 22px; font-weight: bold; color: @black; } } } } #sidebar { #meta { table { margin: 0; tr:last-child td { padding-bottom: 0; } td { padding: 0 0 5px; ul.networks { margin: 0; padding: 0; li { list-style: none; display: inline; } li { } } } td.label { color: @grey; white-space: nowrap; width: 1%; text-align: right; padding-right: 5px; } } } } /* Voting */ div.voted { font-size: 12px; line-height: 22px; color: @black; display: inline-block; font-weight: bold; img { float: left; margin-right: 5px; padding: 3px; .border_radius(3); } } #voted_up { img { background: @colour_positive * 0.66 + @bg * 0.15; } } #voted_down { img { background: @colour_negative * 0.66 + @bg * 0.15; } } #encourage_comment { display: inline-block; line-height: 22px; font-weight: bold; } #vote { overflow: hidden; font-size: 12px; line-height: 22px; color: @black; float: left; a { color: @white; font-weight: bold; overflow: hidden; display: block; width: 16px; text-decoration: none; text-align: center; font-size: 10px; padding: 3px; text-transform: uppercase; } a.up { float: left; background: @colour_positive * 0.66 + @bg * 0.15; .border_radius_left(3); :hover { background: @colour_positive * 0.85 + @bg * 0.15; } } a.down { float: left; background: @colour_negative * 0.66 + @bg * 0.15; .border_radius_right(3); margin: 0 5px 0 1px; :hover { background: @colour_negative * 0.85 + @bg * 0.15; } } } #vote.disabled { a.up { background: (@colour_positive * 0.66 + @bg * 0.15) * 0.15 + @grey * 0.85; :hover { background: (@colour_positive * 0.85 + @bg * 0.15) * 0.25 + @grey * 0.75; } } a.down { background: (@colour_negative * 0.66 + @bg * 0.15) * 0.15 + @grey * 0.85; :hover { background: (@colour_negative * 0.85 + @bg * 0.15) * 0.25 + @grey * 0.75; } } } #sidebar { #ads > ul li, #recommendations > ul li { width: 81px; div.thumbnail { a.thumbnail { height: 60px; width: 81px; } } div.text { a.title { font-size: 11px; height: 14px; line-height: 14px; } small { display: none; } } } #brands > ul li { width: 55px; div.thumbnail { a.thumbnail { height: 45px; width: 45px; img { max-height: 45px; max-width: 45px; } } } div.text { display: none; } } } /* My Account */ #accounts_controller { #top { #page_title { #page_options { a.button.public_profile { float: right; font-size: 16px; line-height: 1; height: auto; padding: 8px 35px 8px 15px; position: relative; b.arrow { display: block; height: 0; width: 0; position: absolute; top: 10px; right: 15px; border: 6px solid transparent; border-right: none; border-left: 6px solid @white; margin: 0; } } a.button.goto_dashboard { float: right; font-size: 16px; line-height: 1; height: auto; padding: 8px 15px 8px 35px; margin-right: 5px; position: relative; b.arrow { display: block; height: 0; width: 0; position: absolute; top: 10px; left: 15px; border: 6px solid transparent; border-left: none; border-right: 6px solid @white; margin: 0; } } } } } #account_nav { float: left; width: 200px; margin: 0 20px 0 0; ul.nav { margin: 0; padding: 0; li { margin: 0 0 5px; display: block; list-style: none; padding: 0; a { display: block; height: 30px; text-decoration: none; color: @white; b { border: 15px solid transparent; border-right: none; border-left: 10px solid transparent; width: 0; height: 0; float: right; display: none; } span { .border_radius(3); background: @bg; display: block; line-height: 30px; padding: 0 10px; font-size: 14px; font-weight: bold; margin: 0 10px 0 0; } } :hover { a { color: @white; b { border-left-color: @bg; display: block; } span { background: @bg; .border_radius_right(0); } } } } li.current a { b { border-left-color: @accent_colour; display: block; } span { background: @accent_colour; color: @white; .border_radius_right(0); } } } } #main { > div { margin: 0 0 20px; form { margin: 0; } } #profile { a.avatar { float: left; display: block; width: 70px; overflow: hidden; position: relative; text-decoration: none; img { width: 100%; } span { display: block; line-height: 1; padding: 3px; margin: 5px 0 0; color: @white; background: @accent_colour; .border_radius(3); .text_shadow(1, 1, 0, @grey); text-align: center; font-size: 10px; font-weight: bold; text-transform: uppercase; } } form { margin: 0 0 0 90px; h4 { margin: 10px 0 20px; border-bottom: 1px solid (@light_grey * 0.5 + @white * 0.5); padding: 0; color: @bg; font-size: 16px; } ul.choices { li { width: 30%; } } div.extra { margin-top: 20px; } } } #networks { ul { margin: 0 -10px -10px 0; padding: 0; overflow: hidden; li:hover { background: @light_grey; display: block; float: left; width: 180px; padding: 10px; margin: 0 10px 10px 0; list-style: none; .border_radius(3); position: relative; * { line-height: normal; } img { vertical-align: middle; float: left; } .name { font-weight: bold; font-size: 14px; display: block; margin: -2px 0 0 42px; } small { font-size: 12px; color: @grey; display: block; margin-left: 42px; strong { color: @black; font-weight: normal; } } :hover { } } li.installed { background: @white; border: 2px solid @accent_colour; padding: 8px; } li.unavailable { .name { color: @black; } :hover { background: @light_grey; } } li:hover { background: @light_grey * 0.5 + @white * 0.5; } } } } } /* Shopping Style Panel */ #shopping_style { div.header a.button.small { float: right; } div.content { p { margin: 0 0 10px; label { text-transform: uppercase; font-size: 11px; display: block; color: @bg; font-weight: bold; } span { color: @black; } span.toggle { white-space: nowrap; color: @grey; } :last-child { margin: 0; } } p.more { text-align: left; font-weight: normal; } p.less { display: none; margin: 0; } } } /* People Controller */ #people_controller.index { #main { div.panel { float: left; width: 300px; margin: 0 20px 0 0; :last-child { margin-right: 0; } } } } #people_controller.show { #person_overview, #shopping_style { a.button.small { } } #content { #shopping_style { float: left; width: 240px; margin: 0 20px 0 0; } #main { width: 360px; } } } /* Search Results */ #search_results { margin: 0 0 20px; li { :hover { small { color: @white * 0.75 + @accent_colour * 0.25; } } } } #search { div.content { padding: 20px; form { margin: 0; float: none; span.submit_and_options { display: block; } } p { margin: 0 0 15px; } h4 { font-weight: normal; margin: 0 0 5px; } } } /* Recommendations */ #recommendations { div.browse { margin: 0; padding: 0; background: none; ul { min-height: 0; .border_radius(0); } } } /* Blank States */ div.blank { padding: 20px; background: @bg * 0.05 + @blue * 0.05 + @white * 0.9; position: relative; border: 1px solid (@bg * 0.1 + @blue * 0.1 + @white * 0.8); z-index: 1; h4 { font-size: 18px; margin: 0 0 10px; } h4:last-child { margin: 0; } p { font-size: 16px; margin: 0 0 10px; } p:last-child { margin: 0; } p.with_list_number.large { span { margin-left: 48px; display: block; color: @white; } } p.earn span { font-size: 22px; color: @white; line-height: 48px; font-weight: bold; } a { white-space: nowrap; } a.hide { position: absolute; top: -5px; right: -5px; display: block; height: 16px; width: 16px; padding: 3px; background: #E7E9F6; .border_radius(99); } } div.blank.small { padding: 10px 20px; h4 { font-weight: normal; font-size: 16px; } p { margin: 0; } } div.blank.tiny { padding: 10px 20px; h4 { font-weight: normal; font-size: 14px; } p { margin: 0; font-size: 12px; } } div.blank.rounded { .border_radius(3); margin: 0 0 20px; } div.blank.rounded.bottom { .border_radius_top(0); } div.blank.with_border_bottom { border-bottom: 1px solid (@bg * 0.1 + @blue * 0.1 + @white * 0.8); } div.blank.no_border_top { border-top: none; } div.blank.no_border_bottom { border-bottom: none; } div.blank.no_side_borders { border-right: none; border-left: none; } div.panel { div.blank { padding: 10px 20px; overflow: hidden; margin: 0; h4 { font-weight: normal; font-size: 14px; } p, ul { margin: 0 0 10px; font-size: 12px; } p:last-child, ul:last-child { margin: 0; } } } #yelow { #short { color: #fea; } #long { color: #ffeeaa; } #rgba { color: rgba(255, 238, 170, 0.1); } } #blue { #short { color: #00f; } #long { color: #0000ff; } #rgba { color: rgba(0, 0, 255, 0.1); } } #overflow { .a { color: #111111 - #444444; } // #000000 .b { color: #eee + #fff; } // #ffffff .c { color: #aaa * 3; } // #ffffff .d { color: #00ee00 + #009900; } // #00ff00 } #grey { color: rgb(200, 200, 200); } #808080 { color: hsl(50, 0%, 50%); } #00ff00 { color: hsl(120, 100%, 50%); } /******************\ * * * Comment Header * * * \******************/ /* Comment */ /* * Comment Test * * - cloudhead (http://cloudhead.net) * */ //////////////// @var: "content"; //////////////// /* Colors * ------ * #EDF8FC (background blue) * #166C89 (darkest blue) * * Text: * #333 (standard text) // A comment within a comment! * #1F9EC9 (standard link) * */ /* @group Variables ------------------- */ #comments /* boo */ { /**/ // An empty comment color: red; /* A C-style comment */ background-color: orange; // A little comment font-size: 12px; /* lost comment */ content: @var; border: 1px solid black; // padding & margin // padding: 0; margin: 2em; } // /* commented out #more-comments { color: grey; } */ #last { color: blue } // .comma-delimited { background: url(bg.jpg) no-repeat, url(bg.png) repeat-x top left, url(bg); text-shadow: -1px -1px 1px red, 6px 5px 5px yellow; -moz-box-shadow: 0pt 0pt 2px rgba(255, 255, 255, 0.4) inset, 0pt 4px 6px rgba(255, 255, 255, 0.4) inset; } @font-face { font-family: Headline; src: local(Futura-Medium), url(fonts.svg#MyGeometricModern) format("svg"); } .other { -moz-transform: translate(0, 11em) rotate(-90deg); } p:not([class*="lead"]) { color: black; } input[type="text"].class#id[attr=32]:not(1) { color: white; } div#id.class[a=1][b=2].class:not(1) { color: white; } ul.comma > li:not(:only-child)::after { color: white; } ol.comma > li:nth-last-child(2)::after { color: white; } li:nth-child(4n+1), li:nth-child(-5n), li:nth-child(-n+2) { color: white; } a[href^="http://"] { color: black; } a[href$="http://"] { color: black; } form[data-disabled] { color: black; } p::before { color: black; } @charset "utf-8"; div { color: black; } div { width: 99%; } * { min-width: 45em; } h1, h2 > a > p, h3 { color: none; } div.class { color: blue; } div#id { color: green; } .class#id { color: purple; } .one.two.three { color: grey; } @media print { font-size: 3em; } @media screen { font-size: 10px; } @font-face { font-family: 'Garamond Pro'; src: url("/fonts/garamond-pro.ttf"); } a:hover, a:link { color: #999; } p, p:first-child { text-transform: none; } q:lang(no) { quotes: none; } p + h1 { font-size: 2.2em; } #shorthands { border: 1px solid #000; font: 12px/16px Arial; margin: 1px 0; padding: 0 auto; background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px; } #more-shorthands { margin: 0; padding: 1px 0 2px 0; font: normal small/20px 'Trebuchet MS', Verdana, sans-serif; } .misc { -moz-border-radius: 2px; display: -moz-inline-stack; width: .1em; background-color: #009998; background-image: url(images/image.jpg); background: -webkit-gradient(linear, left top, left bottom, from(red), to(blue)); margin: ; } #important { color: red !important; width: 100%!important; height: 20px ! important; } #functions { @var: 10; color: color("evil red"); // #660000 width: increment(15); height: undefined("self"); border-width: add(2, 3); variable: increment(@var); } #built-in { @r: 32; escaped: e("-Some::weird(#thing, y)"); lighten: lighten(#ff0000, 50%); darken: darken(#ff0000, 50%); saturate: saturate(#29332f, 20%); desaturate: desaturate(#203c31, 20%); greyscale: greyscale(#203c31); format: %("rgb(%d, %d, %d)", @r, 128, 64); format-string: %("hello %s", "world"); eformat: e(%("rgb(%d, %d, %d)", @r, 128, 64)); } @var: @a; @a: 100%; .lazy-eval { width: @var; } .mixin (@a: 1px, @b: 50%) { width: @a * 5; height: @b - 1%; } .mixina (@style, @width, @color: black) { border: @width @style @color; } .mixiny (@a: 0, @b: 0) { margin: @a; padding: @b; } .hidden() { color: transparent; } .two-args { color: blue; .mixin(2px, 100%); .mixina(dotted, 2px); } .one-arg { .mixin(3px); } .no-parens { .mixin; } .no-args { .mixin(); } .var-args { @var: 9; .mixin(@var, @var * 2); } .multi-mix { .mixin(2px, 30%); .mixiny(4, 5); } .maxa(@arg1: 10, @arg2: #f00) { padding: @arg1 * 2px; color: @arg2; } body { .maxa(15); } @glob: 5; .global-mixin(@a:2) { width: @glob + @a; } .scope-mix { .global-mixin(3); } .nested-ruleset (@width: 200px) { width: @width; .column { margin: @width; } } .content { .nested-ruleset(600px); } // .same-var-name2(@radius) { radius: @radius; } .same-var-name(@radius) { .same-var-name2(@radius); } #same-var-name { .same-var-name(5px); } // .var-inside () { @var: 10px; width: @var; } #var-inside { .var-inside; } .mix-inner (@var) { border-width: @var; } .mix (@a: 10) { .inner { height: @a * 10; .innest { width: @a; .mix-inner(@a * 2); } } } .class { .mix(30); } .mixin () { zero: 0; } .mixin (@a: 1px) { one: 1; } .mixin (@a) { one-req: 1; } .mixin (@a: 1px, @b: 2px) { two: 2; } .mixin (@a, @b, @c) { three-req: 3; } .mixin (@a: 1px, @b: 2px, @c: 3px) { three: 3; } .zero { .mixin(); } .one { .mixin(1); } .two { .mixin(1, 2); } .three { .mixin(1, 2, 3); } // .mixout ('left') { left: 1; } .mixout ('right') { right: 1; } .left { .mixout('left'); } .right { .mixout('right'); } // .border (@side, @width) { color: black; .border-side(@side, @width); } .border-side (left, @w) { border-left: @w; } .border-side (right, @w) { border-right: @w; } .border-right { .border(right, 4px); } .border-left { .border(left, 4px); } // .border-radius (@r) { both: @r * 10; } .border-radius (@r, left) { left: @r; } .border-radius (@r, right) { right: @r; } .only-right { .border-radius(33, right); } .only-left { .border-radius(33, left); } .left-right { .border-radius(33); } .mixin { border: 1px solid black; } .mixout { border-color: orange; } .borders { border-style: dashed; } #namespace { .borders { border-style: dotted; } .biohazard { content: "death"; .man { color: transparent; } } } #theme { > .mixin { background-color: grey; } } #container { color: black; .mixin; .mixout; #theme > .mixin; } #header { .milk { color: white; .mixin; #theme > .mixin; } #cookie { .chips { #namespace .borders; .calories { #container; } } .borders; } } .secure-zone { #namespace .biohazard .man; } .direct { #namespace > .borders; } #operations { color: #110000 + #000011 + #001100; // #111111 height: 10px / 2px + 6px - 1px * 2; // 9px width: 2 * 4 - 5em; // 3em .spacing { height: 10px / 2px+6px-1px*2; width: 2 * 4-5em; } substraction: 20 - 10 - 5 - 5; // 0 division: 20 / 5 / 4; // 1 } @x: 4; @y: 12em; .with-variables { height: @x + @y; // 16em width: 12 + @y; // 24em size: 5cm - @x; // 1cm } @z: -2; .negative { height: 2px + @z; // 0px width: 2px - @z; // 4px } .shorthands { padding: -1px 2px 0 -4px; // } .colors { color: #123; // #112233 border-color: #234 + #111111; // #334455 background-color: #222222 - #fff; // #000000 .other { color: 2 * #111; // #222222 border-color: #333333 / 3 + #111; // #222222 } } .parens { @var: 1px; border: (@var * 2) solid black; margin: (@var * 1) (@var + 2) (4 * 4) 3; width: (6 * 6); padding: 2px (6px * 6px); } .more-parens { @var: (2 * 2); padding: (2 * @var) 4 4 (@var * 1px); width: (@var * @var) * 6; height: (7 * 7) + (8 * 8); margin: 4 * (5 + 5) / 2 - (@var * 2); //margin: (6 * 6)px; } .nested-parens { width: 2 * (4 * (2 + (1 + 6))) - 1; height: ((2+3)*(2+3) / (9-4)) + 1; } .mixed-units { margin: 2px 4em 1 5pc; padding: (2px + 4px) 1em 2px 2; } #first > .one { > #second .two > #deux { width: 50%; #third { &:focus { color: black; #fifth { > #sixth { .seventh #eighth { + #ninth { color: purple; } } } } } height: 100%; } #fourth, #five, #six { color: #110000; .seven, .eight > #nine { border: 1px solid black; } #ten { color: red; } } } font-size: 2em; } @x: blue; @z: transparent; @mix: none; .mixin { @mix: #989; } .tiny-scope { color: @mix; // #989 .mixin; } .scope1 { @y: orange; @z: black; color: @x; // blue border-color: @z; // black .hidden { @x: #131313; } .scope2 { @y: red; color: @x; // blue .scope3 { @local: white; color: @y; // red border-color: @z; // black background-color: @local; // white } } }h1, h2, h3 { a, p { &:hover { color: red; } } } #all { color: blue; } #the { color: blue; } #same { color: blue; } ul, li, div, q, blockquote, textarea { margin: 0; } td { margin: 0; padding: 0; } td, input { line-height: 1em; } #strings { background-image: url("http://son-of-a-banana.com"); quotes: "~" "~"; content: "#*%:&^,)!.(~*})"; empty: ""; brackets: "{" "}"; } #comments { content: "/* hello */ // not-so-secret"; } #single-quote { quotes: "'" "'"; content: '""#!&""'; empty: ''; } @a: 2; @x: @a * @a; @y: @x + 1; @z: @x * 2 + @y; .variables { width: @z + 1cm; // 14cm } @b: @a * 10; @c: #888; @fonts: "Trebuchet MS", Verdana, sans-serif; @f: @fonts; @quotes: "~" "~"; @q: @quotes; .variables { height: @b + @x + 0px; // 24px color: @c; font-family: @f; quotes: @q; } .redefinition { @var: 4; @var: 2; @var: 3; three: @var; } .values { @a: 'Trebuchet'; font-family: @a, @a, @a; } .whitespace { color: white; } .whitespace { color: white; } .whitespace { color: white; } .whitespace{color:white;} .whitespace { color : white ; } .white, .space, .mania { color: white; } .no-semi-column { color: white } .no-semi-column { color: white; white-space: pre } .no-semi-column {border: 2px solid white} .newlines { background: the, great, wall; border: 2px solid black; } .empty { } #yelow { #short { color: #fea; } #long { color: #ffeeaa; } #rgba { color: rgba(255, 238, 170, 0.1); } } #blue { #short { color: #00f; } #long { color: #0000ff; } #rgba { color: rgba(0, 0, 255, 0.1); } } #overflow { .a { color: #111111 - #444444; } // #000000 .b { color: #eee + #fff; } // #ffffff .c { color: #aaa * 3; } // #ffffff .d { color: #00ee00 + #009900; } // #00ff00 } #grey { color: rgb(200, 200, 200); } #808080 { color: hsl(50, 0%, 50%); } #00ff00 { color: hsl(120, 100%, 50%); } /******************\ * * * Comment Header * * * \******************/ /* Comment */ /* * Comment Test * * - cloudhead (http://cloudhead.net) * */ //////////////// @var: "content"; //////////////// /* Colors * ------ * #EDF8FC (background blue) * #166C89 (darkest blue) * * Text: * #333 (standard text) // A comment within a comment! * #1F9EC9 (standard link) * */ /* @group Variables ------------------- */ #comments /* boo */ { /**/ // An empty comment color: red; /* A C-style comment */ background-color: orange; // A little comment font-size: 12px; /* lost comment */ content: @var; border: 1px solid black; // padding & margin // padding: 0; margin: 2em; } // /* commented out #more-comments { color: grey; } */ #last { color: blue } // .comma-delimited { background: url(bg.jpg) no-repeat, url(bg.png) repeat-x top left, url(bg); text-shadow: -1px -1px 1px red, 6px 5px 5px yellow; -moz-box-shadow: 0pt 0pt 2px rgba(255, 255, 255, 0.4) inset, 0pt 4px 6px rgba(255, 255, 255, 0.4) inset; } @font-face { font-family: Headline; src: local(Futura-Medium), url(fonts.svg#MyGeometricModern) format("svg"); } .other { -moz-transform: translate(0, 11em) rotate(-90deg); } p:not([class*="lead"]) { color: black; } input[type="text"].class#id[attr=32]:not(1) { color: white; } div#id.class[a=1][b=2].class:not(1) { color: white; } ul.comma > li:not(:only-child)::after { color: white; } ol.comma > li:nth-last-child(2)::after { color: white; } li:nth-child(4n+1), li:nth-child(-5n), li:nth-child(-n+2) { color: white; } a[href^="http://"] { color: black; } a[href$="http://"] { color: black; } form[data-disabled] { color: black; } p::before { color: black; } @charset "utf-8"; div { color: black; } div { width: 99%; } * { min-width: 45em; } h1, h2 > a > p, h3 { color: none; } div.class { color: blue; } div#id { color: green; } .class#id { color: purple; } .one.two.three { color: grey; } @media print { font-size: 3em; } @media screen { font-size: 10px; } @font-face { font-family: 'Garamond Pro'; src: url("/fonts/garamond-pro.ttf"); } a:hover, a:link { color: #999; } p, p:first-child { text-transform: none; } q:lang(no) { quotes: none; } p + h1 { font-size: 2.2em; } #shorthands { border: 1px solid #000; font: 12px/16px Arial; margin: 1px 0; padding: 0 auto; background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px; } #more-shorthands { margin: 0; padding: 1px 0 2px 0; font: normal small/20px 'Trebuchet MS', Verdana, sans-serif; } .misc { -moz-border-radius: 2px; display: -moz-inline-stack; width: .1em; background-color: #009998; background-image: url(images/image.jpg); background: -webkit-gradient(linear, left top, left bottom, from(red), to(blue)); margin: ; } #important { color: red !important; width: 100%!important; height: 20px ! important; } #functions { @var: 10; color: color("evil red"); // #660000 width: increment(15); height: undefined("self"); border-width: add(2, 3); variable: increment(@var); } #built-in { @r: 32; escaped: e("-Some::weird(#thing, y)"); lighten: lighten(#ff0000, 50%); darken: darken(#ff0000, 50%); saturate: saturate(#29332f, 20%); desaturate: desaturate(#203c31, 20%); greyscale: greyscale(#203c31); format: %("rgb(%d, %d, %d)", @r, 128, 64); format-string: %("hello %s", "world"); eformat: e(%("rgb(%d, %d, %d)", @r, 128, 64)); } @var: @a; @a: 100%; .lazy-eval { width: @var; } .mixin (@a: 1px, @b: 50%) { width: @a * 5; height: @b - 1%; } .mixina (@style, @width, @color: black) { border: @width @style @color; } .mixiny (@a: 0, @b: 0) { margin: @a; padding: @b; } .hidden() { color: transparent; } .two-args { color: blue; .mixin(2px, 100%); .mixina(dotted, 2px); } .one-arg { .mixin(3px); } .no-parens { .mixin; } .no-args { .mixin(); } .var-args { @var: 9; .mixin(@var, @var * 2); } .multi-mix { .mixin(2px, 30%); .mixiny(4, 5); } .maxa(@arg1: 10, @arg2: #f00) { padding: @arg1 * 2px; color: @arg2; } body { .maxa(15); } @glob: 5; .global-mixin(@a:2) { width: @glob + @a; } .scope-mix { .global-mixin(3); } .nested-ruleset (@width: 200px) { width: @width; .column { margin: @width; } } .content { .nested-ruleset(600px); } // .same-var-name2(@radius) { radius: @radius; } .same-var-name(@radius) { .same-var-name2(@radius); } #same-var-name { .same-var-name(5px); } // .var-inside () { @var: 10px; width: @var; } #var-inside { .var-inside; } .mix-inner (@var) { border-width: @var; } .mix (@a: 10) { .inner { height: @a * 10; .innest { width: @a; .mix-inner(@a * 2); } } } .class { .mix(30); } .mixin () { zero: 0; } .mixin (@a: 1px) { one: 1; } .mixin (@a) { one-req: 1; } .mixin (@a: 1px, @b: 2px) { two: 2; } .mixin (@a, @b, @c) { three-req: 3; } .mixin (@a: 1px, @b: 2px, @c: 3px) { three: 3; } .zero { .mixin(); } .one { .mixin(1); } .two { .mixin(1, 2); } .three { .mixin(1, 2, 3); } // .mixout ('left') { left: 1; } .mixout ('right') { right: 1; } .left { .mixout('left'); } .right { .mixout('right'); } // .border (@side, @width) { color: black; .border-side(@side, @width); } .border-side (left, @w) { border-left: @w; } .border-side (right, @w) { border-right: @w; } .border-right { .border(right, 4px); } .border-left { .border(left, 4px); } // .border-radius (@r) { both: @r * 10; } .border-radius (@r, left) { left: @r; } .border-radius (@r, right) { right: @r; } .only-right { .border-radius(33, right); } .only-left { .border-radius(33, left); } .left-right { .border-radius(33); } .mixin { border: 1px solid black; } .mixout { border-color: orange; } .borders { border-style: dashed; } #namespace { .borders { border-style: dotted; } .biohazard { content: "death"; .man { color: transparent; } } } #theme { > .mixin { background-color: grey; } } #container { color: black; .mixin; .mixout; #theme > .mixin; } #header { .milk { color: white; .mixin; #theme > .mixin; } #cookie { .chips { #namespace .borders; .calories { #container; } } .borders; } } .secure-zone { #namespace .biohazard .man; } .direct { #namespace > .borders; } #operations { color: #110000 + #000011 + #001100; // #111111 height: 10px / 2px + 6px - 1px * 2; // 9px width: 2 * 4 - 5em; // 3em .spacing { height: 10px / 2px+6px-1px*2; width: 2 * 4-5em; } substraction: 20 - 10 - 5 - 5; // 0 division: 20 / 5 / 4; // 1 } @x: 4; @y: 12em; .with-variables { height: @x + @y; // 16em width: 12 + @y; // 24em size: 5cm - @x; // 1cm } @z: -2; .negative { height: 2px + @z; // 0px width: 2px - @z; // 4px } .shorthands { padding: -1px 2px 0 -4px; // } .colors { color: #123; // #112233 border-color: #234 + #111111; // #334455 background-color: #222222 - #fff; // #000000 .other { color: 2 * #111; // #222222 border-color: #333333 / 3 + #111; // #222222 } } .parens { @var: 1px; border: (@var * 2) solid black; margin: (@var * 1) (@var + 2) (4 * 4) 3; width: (6 * 6); padding: 2px (6px * 6px); } .more-parens { @var: (2 * 2); padding: (2 * @var) 4 4 (@var * 1px); width: (@var * @var) * 6; height: (7 * 7) + (8 * 8); margin: 4 * (5 + 5) / 2 - (@var * 2); //margin: (6 * 6)px; } .nested-parens { width: 2 * (4 * (2 + (1 + 6))) - 1; height: ((2+3)*(2+3) / (9-4)) + 1; } .mixed-units { margin: 2px 4em 1 5pc; padding: (2px + 4px) 1em 2px 2; } #first > .one { > #second .two > #deux { width: 50%; #third { &:focus { color: black; #fifth { > #sixth { .seventh #eighth { + #ninth { color: purple; } } } } } height: 100%; } #fourth, #five, #six { color: #110000; .seven, .eight > #nine { border: 1px solid black; } #ten { color: red; } } } font-size: 2em; } @x: blue; @z: transparent; @mix: none; .mixin { @mix: #989; } .tiny-scope { color: @mix; // #989 .mixin; } .scope1 { @y: orange; @z: black; color: @x; // blue border-color: @z; // black .hidden { @x: #131313; } .scope2 { @y: red; color: @x; // blue .scope3 { @local: white; color: @y; // red border-color: @z; // black background-color: @local; // white } } }h1, h2, h3 { a, p { &:hover { color: red; } } } #all { color: blue; } #the { color: blue; } #same { color: blue; } ul, li, div, q, blockquote, textarea { margin: 0; } td { margin: 0; padding: 0; } td, input { line-height: 1em; } #strings { background-image: url("http://son-of-a-banana.com"); quotes: "~" "~"; content: "#*%:&^,)!.(~*})"; empty: ""; brackets: "{" "}"; } #comments { content: "/* hello */ // not-so-secret"; } #single-quote { quotes: "'" "'"; content: '""#!&""'; empty: ''; } @a: 2; @x: @a * @a; @y: @x + 1; @z: @x * 2 + @y; .variables { width: @z + 1cm; // 14cm } @b: @a * 10; @c: #888; @fonts: "Trebuchet MS", Verdana, sans-serif; @f: @fonts; @quotes: "~" "~"; @q: @quotes; .variables { height: @b + @x + 0px; // 24px color: @c; font-family: @f; quotes: @q; } .redefinition { @var: 4; @var: 2; @var: 3; three: @var; } .values { @a: 'Trebuchet'; font-family: @a, @a, @a; } .whitespace { color: white; } .whitespace { color: white; } .whitespace { color: white; } .whitespace{color:white;} .whitespace { color : white ; } .white, .space, .mania { color: white; } .no-semi-column { color: white } .no-semi-column { color: white; white-space: pre } .no-semi-column {border: 2px solid white} .newlines { background: the, great, wall; border: 2px solid black; } .empty { } #yelow { #short { color: #fea; } #long { color: #ffeeaa; } #rgba { color: rgba(255, 238, 170, 0.1); } } #blue { #short { color: #00f; } #long { color: #0000ff; } #rgba { color: rgba(0, 0, 255, 0.1); } } #overflow { .a { color: #111111 - #444444; } // #000000 .b { color: #eee + #fff; } // #ffffff .c { color: #aaa * 3; } // #ffffff .d { color: #00ee00 + #009900; } // #00ff00 } #grey { color: rgb(200, 200, 200); } #808080 { color: hsl(50, 0%, 50%); } #00ff00 { color: hsl(120, 100%, 50%); } /******************\ * * * Comment Header * * * \******************/ /* Comment */ /* * Comment Test * * - cloudhead (http://cloudhead.net) * */ //////////////// @var: "content"; //////////////// /* Colors * ------ * #EDF8FC (background blue) * #166C89 (darkest blue) * * Text: * #333 (standard text) // A comment within a comment! * #1F9EC9 (standard link) * */ /* @group Variables ------------------- */ #comments /* boo */ { /**/ // An empty comment color: red; /* A C-style comment */ background-color: orange; // A little comment font-size: 12px; /* lost comment */ content: @var; border: 1px solid black; // padding & margin // padding: 0; margin: 2em; } // /* commented out #more-comments { color: grey; } */ #last { color: blue } // .comma-delimited { background: url(bg.jpg) no-repeat, url(bg.png) repeat-x top left, url(bg); text-shadow: -1px -1px 1px red, 6px 5px 5px yellow; -moz-box-shadow: 0pt 0pt 2px rgba(255, 255, 255, 0.4) inset, 0pt 4px 6px rgba(255, 255, 255, 0.4) inset; } @font-face { font-family: Headline; src: local(Futura-Medium), url(fonts.svg#MyGeometricModern) format("svg"); } .other { -moz-transform: translate(0, 11em) rotate(-90deg); } p:not([class*="lead"]) { color: black; } input[type="text"].class#id[attr=32]:not(1) { color: white; } div#id.class[a=1][b=2].class:not(1) { color: white; } ul.comma > li:not(:only-child)::after { color: white; } ol.comma > li:nth-last-child(2)::after { color: white; } li:nth-child(4n+1), li:nth-child(-5n), li:nth-child(-n+2) { color: white; } a[href^="http://"] { color: black; } a[href$="http://"] { color: black; } form[data-disabled] { color: black; } p::before { color: black; } @charset "utf-8"; div { color: black; } div { width: 99%; } * { min-width: 45em; } h1, h2 > a > p, h3 { color: none; } div.class { color: blue; } div#id { color: green; } .class#id { color: purple; } .one.two.three { color: grey; } @media print { font-size: 3em; } @media screen { font-size: 10px; } @font-face { font-family: 'Garamond Pro'; src: url("/fonts/garamond-pro.ttf"); } a:hover, a:link { color: #999; } p, p:first-child { text-transform: none; } q:lang(no) { quotes: none; } p + h1 { font-size: 2.2em; } #shorthands { border: 1px solid #000; font: 12px/16px Arial; margin: 1px 0; padding: 0 auto; background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px; } #more-shorthands { margin: 0; padding: 1px 0 2px 0; font: normal small/20px 'Trebuchet MS', Verdana, sans-serif; } .misc { -moz-border-radius: 2px; display: -moz-inline-stack; width: .1em; background-color: #009998; background-image: url(images/image.jpg); background: -webkit-gradient(linear, left top, left bottom, from(red), to(blue)); margin: ; } #important { color: red !important; width: 100%!important; height: 20px ! important; } #functions { @var: 10; color: color("evil red"); // #660000 width: increment(15); height: undefined("self"); border-width: add(2, 3); variable: increment(@var); } #built-in { @r: 32; escaped: e("-Some::weird(#thing, y)"); lighten: lighten(#ff0000, 50%); darken: darken(#ff0000, 50%); saturate: saturate(#29332f, 20%); desaturate: desaturate(#203c31, 20%); greyscale: greyscale(#203c31); format: %("rgb(%d, %d, %d)", @r, 128, 64); format-string: %("hello %s", "world"); eformat: e(%("rgb(%d, %d, %d)", @r, 128, 64)); } @var: @a; @a: 100%; .lazy-eval { width: @var; } .mixin (@a: 1px, @b: 50%) { width: @a * 5; height: @b - 1%; } .mixina (@style, @width, @color: black) { border: @width @style @color; } .mixiny (@a: 0, @b: 0) { margin: @a; padding: @b; } .hidden() { color: transparent; } .two-args { color: blue; .mixin(2px, 100%); .mixina(dotted, 2px); } .one-arg { .mixin(3px); } .no-parens { .mixin; } .no-args { .mixin(); } .var-args { @var: 9; .mixin(@var, @var * 2); } .multi-mix { .mixin(2px, 30%); .mixiny(4, 5); } .maxa(@arg1: 10, @arg2: #f00) { padding: @arg1 * 2px; color: @arg2; } body { .maxa(15); } @glob: 5; .global-mixin(@a:2) { width: @glob + @a; } .scope-mix { .global-mixin(3); } .nested-ruleset (@width: 200px) { width: @width; .column { margin: @width; } } .content { .nested-ruleset(600px); } // .same-var-name2(@radius) { radius: @radius; } .same-var-name(@radius) { .same-var-name2(@radius); } #same-var-name { .same-var-name(5px); } // .var-inside () { @var: 10px; width: @var; } #var-inside { .var-inside; } .mix-inner (@var) { border-width: @var; } .mix (@a: 10) { .inner { height: @a * 10; .innest { width: @a; .mix-inner(@a * 2); } } } .class { .mix(30); } .mixin () { zero: 0; } .mixin (@a: 1px) { one: 1; } .mixin (@a) { one-req: 1; } .mixin (@a: 1px, @b: 2px) { two: 2; } .mixin (@a, @b, @c) { three-req: 3; } .mixin (@a: 1px, @b: 2px, @c: 3px) { three: 3; } .zero { .mixin(); } .one { .mixin(1); } .two { .mixin(1, 2); } .three { .mixin(1, 2, 3); } // .mixout ('left') { left: 1; } less.js-1.4.2/benchmark/less-benchmark.js000066400000000000000000000023601217256642200202750ustar00rootroot00000000000000var path = require('path'), fs = require('fs'), sys = require('util'); var less = require('../lib/less'); var file = path.join(__dirname, 'benchmark.less'); if (process.argv[2]) { file = path.join(process.cwd(), process.argv[2]) } fs.readFile(file, 'utf8', function (e, data) { var tree, css, start, end, total; sys.puts("Benchmarking...\n", path.basename(file) + " (" + parseInt(data.length / 1024) + " KB)", ""); start = new(Date); new(less.Parser)({ optimization: 2 }).parse(data, function (err, tree) { end = new(Date); total = end - start; sys.puts("Parsing: " + total + " ms (" + parseInt(1000 / total * data.length / 1024) + " KB\/s)"); start = new(Date); css = tree.toCSS(); end = new(Date); sys.puts("Generation: " + (end - start) + " ms (" + parseInt(1000 / (end - start) * data.length / 1024) + " KB\/s)"); total += end - start; sys.puts("Total: " + total + "ms (" + parseInt(1000 / total * data.length / 1024) + " KB/s)"); if (err) { less.writeError(err); process.exit(3); } }); }); less.js-1.4.2/bin/000077500000000000000000000000001217256642200136565ustar00rootroot00000000000000less.js-1.4.2/bin/lessc000077500000000000000000000163321217256642200147220ustar00rootroot00000000000000#!/usr/bin/env node var path = require('path'), fs = require('fs'), sys = require('util'), os = require('os'), mkdirp; var less = require('../lib/less'); var args = process.argv.slice(1); var options = { depends: false, compress: false, yuicompress: false, max_line_len: -1, optimization: 1, silent: false, verbose: false, lint: false, paths: [], color: true, strictImports: false, rootpath: '', relativeUrls: false, ieCompat: true, strictMath: false, strictUnits: false }; var continueProcessing = true, currentErrorcode; // calling process.exit does not flush stdout always // so use this to set the exit code process.on('exit', function() { process.reallyExit(currentErrorcode) }); var checkArgFunc = function(arg, option) { if (!option) { sys.puts(arg + " option requires a parameter"); continueProcessing = false; return false; } return true; }; var checkBooleanArg = function(arg) { var onOff = /^((on|t|true|y|yes)|(off|f|false|n|no))$/i.exec(arg); if (!onOff) { sys.puts(" unable to parse "+arg+" as a boolean. use one of on/t/true/y/yes/off/f/false/n/no"); continueProcessing = false; return false; } return Boolean(onOff[2]); }; args = args.filter(function (arg) { var match; if (match = arg.match(/^-I(.+)$/)) { options.paths.push(match[1]); return false; } if (match = arg.match(/^--?([a-z][0-9a-z-]*)(?:=([^\s]*))?$/i)) { arg = match[1] } else { return arg } switch (arg) { case 'v': case 'version': sys.puts("lessc " + less.version.join('.') + " (LESS Compiler) [JavaScript]"); continueProcessing = false; case 'verbose': options.verbose = true; break; case 's': case 'silent': options.silent = true; break; case 'l': case 'lint': options.lint = true; break; case 'strict-imports': options.strictImports = true; break; case 'h': case 'help': require('../lib/less/lessc_helper').printUsage(); continueProcessing = false; case 'x': case 'compress': options.compress = true; break; case 'M': case 'depends': options.depends = true; break; case 'yui-compress': options.yuicompress = true; break; case 'max-line-len': if (checkArgFunc(arg, match[2])) { options.maxLineLen = parseInt(match[2], 10); if (options.maxLineLen <= 0) { options.maxLineLen = -1; } } break; case 'no-color': options.color = false; break; case 'no-ie-compat': options.ieCompat = false; break; case 'include-path': if (checkArgFunc(arg, match[2])) { options.paths = match[2].split(os.type().match(/Windows/) ? ';' : ':') .map(function(p) { if (p) { return path.resolve(process.cwd(), p); } }); } break; case 'O0': options.optimization = 0; break; case 'O1': options.optimization = 1; break; case 'O2': options.optimization = 2; break; case 'line-numbers': if (checkArgFunc(arg, match[2])) { options.dumpLineNumbers = match[2]; } break; case 'rp': case 'rootpath': if (checkArgFunc(arg, match[2])) { options.rootpath = match[2].replace(/\\/g, '/'); } break; case "ru": case "relative-urls": options.relativeUrls = true; break; case "sm": case "strict-math": if (checkArgFunc(arg, match[2])) { options.strictMath = checkBooleanArg(match[2]); } break; case "su": case "strict-units": if (checkArgFunc(arg, match[2])) { options.strictUnits = checkBooleanArg(match[2]); } break; } }); if (!continueProcessing) { return; } var input = args[1]; var inputbase = args[1]; if (input && input != '-') { input = path.resolve(process.cwd(), input); } var output = args[2]; var outputbase = args[2]; if (output) { output = path.resolve(process.cwd(), output); } if (! input) { sys.puts("lessc: no input files"); sys.puts(""); require('../lib/less/lessc_helper').printUsage(); currentErrorcode = 1; return; } var ensureDirectory = function (filepath) { var dir = path.dirname(filepath), cmd, existsSync = fs.existsSync || path.existsSync; if (!existsSync(dir)) { if (mkdirp === undefined) { try {mkdirp = require('mkdirp');} catch(e) { mkdirp = null; } } cmd = mkdirp && mkdirp.sync || fs.mkdirSync; cmd(dir); } }; if (options.depends) { if (!outputbase) { sys.print("option --depends requires an output path to be specified"); return; } sys.print(outputbase + ": "); } var parseLessFile = function (e, data) { if (e) { sys.puts("lessc: " + e.message); currentErrorcode = 1; return; } options.paths = [path.dirname(input)].concat(options.paths); options.filename = input; var parser = new(less.Parser)(options); parser.parse(data, function (err, tree) { if (err) { less.writeError(err, options); currentErrorcode = 1; return; } else if (options.depends) { for(var file in parser.imports.files) { sys.print(file + " ") } sys.print("\n"); } else if(!options.lint) { try { var css = tree.toCSS({ silent: options.silent, verbose: options.verbose, ieCompat: options.ieCompat, compress: options.compress, yuicompress: options.yuicompress, maxLineLen: options.maxLineLen, strictMath: options.strictMath, strictUnits: options.strictUnits }); if (output) { ensureDirectory(output); fs.writeFileSync(output, css, 'utf8'); if (options.verbose) { console.log('lessc: wrote ' + output); } } else { sys.print(css); } } catch (e) { less.writeError(e, options); currentErrorcode = 2; return; } } }); }; if (input != '-') { fs.readFile(input, 'utf8', parseLessFile); } else { process.stdin.resume(); process.stdin.setEncoding('utf8'); var buffer = ''; process.stdin.on('data', function(data) { buffer += data; }); process.stdin.on('end', function() { parseLessFile(false, buffer); }); } less.js-1.4.2/build/000077500000000000000000000000001217256642200142055ustar00rootroot00000000000000less.js-1.4.2/build/amd.js000066400000000000000000000002151217256642200153020ustar00rootroot00000000000000// amd.js // // Define Less as an AMD module. if (typeof define === "function" && define.amd) { define(function () { return less; } ); } less.js-1.4.2/build/header.js000066400000000000000000000002431217256642200157720ustar00rootroot00000000000000/* * LESS - Leaner CSS v@VERSION * http://lesscss.org * * Copyright (c) 2009-2013, Alexis Sellier * Licensed under the Apache 2.0 License. * * @licence */ less.js-1.4.2/build/require-rhino.js000066400000000000000000000001451217256642200173340ustar00rootroot00000000000000// // Stub out `require` in rhino // function require(arg) { return less[arg.split('/')[1]]; }; less.js-1.4.2/build/require.js000066400000000000000000000001621217256642200162160ustar00rootroot00000000000000// // Stub out `require` in the browser // function require(arg) { return window.less[arg.split('/')[1]]; }; less.js-1.4.2/dist/000077500000000000000000000000001217256642200140515ustar00rootroot00000000000000less.js-1.4.2/dist/less-1.1.0.js000066400000000000000000002605171217256642200160230ustar00rootroot00000000000000// // LESS - Leaner CSS v1.1.0 // http://lesscss.org // // Copyright (c) 2009-2011, Alexis Sellier // Licensed under the Apache 2.0 License. // (function (window, undefined) { // // Stub out `require` in the browser // function require(arg) { return window.less[arg.split('/')[1]]; }; // ecma-5.js // // -- kriskowal Kris Kowal Copyright (C) 2009-2010 MIT License // -- tlrobinson Tom Robinson // dantman Daniel Friesen // // Array // if (!Array.isArray) { Array.isArray = function(obj) { return Object.prototype.toString.call(obj) === "[object Array]" || (obj instanceof Array); }; } if (!Array.prototype.forEach) { Array.prototype.forEach = function(block, thisObject) { var len = this.length >>> 0; for (var i = 0; i < len; i++) { if (i in this) { block.call(thisObject, this[i], i, this); } } }; } if (!Array.prototype.map) { Array.prototype.map = function(fun /*, thisp*/) { var len = this.length >>> 0; var res = new Array(len); var thisp = arguments[1]; for (var i = 0; i < len; i++) { if (i in this) { res[i] = fun.call(thisp, this[i], i, this); } } return res; }; } if (!Array.prototype.filter) { Array.prototype.filter = function (block /*, thisp */) { var values = []; var thisp = arguments[1]; for (var i = 0; i < this.length; i++) { if (block.call(thisp, this[i])) { values.push(this[i]); } } return values; }; } if (!Array.prototype.reduce) { Array.prototype.reduce = function(fun /*, initial*/) { var len = this.length >>> 0; var i = 0; // no value to return if no initial value and an empty array if (len === 0 && arguments.length === 1) throw new TypeError(); if (arguments.length >= 2) { var rv = arguments[1]; } else { do { if (i in this) { rv = this[i++]; break; } // if array contains no values, no initial value to return if (++i >= len) throw new TypeError(); } while (true); } for (; i < len; i++) { if (i in this) { rv = fun.call(null, rv, this[i], i, this); } } return rv; }; } if (!Array.prototype.indexOf) { Array.prototype.indexOf = function (value /*, fromIndex */ ) { var length = this.length; var i = arguments[1] || 0; if (!length) return -1; if (i >= length) return -1; if (i < 0) i += length; for (; i < length; i++) { if (!Object.prototype.hasOwnProperty.call(this, i)) { continue } if (value === this[i]) return i; } return -1; }; } // // Object // if (!Object.keys) { Object.keys = function (object) { var keys = []; for (var name in object) { if (Object.prototype.hasOwnProperty.call(object, name)) { keys.push(name); } } return keys; }; } // // String // if (!String.prototype.trim) { String.prototype.trim = function () { return String(this).replace(/^\s\s*/, '').replace(/\s\s*$/, ''); }; } var less, tree; if (typeof(window) === 'undefined') { less = exports, tree = require('less/tree'); } else { if (typeof(window.less) === 'undefined') { window.less = {} } less = window.less, tree = window.less.tree = {}; } // // less.js - parser // // A relatively straight-forward predictive parser. // There is no tokenization/lexing stage, the input is parsed // in one sweep. // // To make the parser fast enough to run in the browser, several // optimization had to be made: // // - Matching and slicing on a huge input is often cause of slowdowns. // The solution is to chunkify the input into smaller strings. // The chunks are stored in the `chunks` var, // `j` holds the current chunk index, and `current` holds // the index of the current chunk in relation to `input`. // This gives us an almost 4x speed-up. // // - In many cases, we don't need to match individual tokens; // for example, if a value doesn't hold any variables, operations // or dynamic references, the parser can effectively 'skip' it, // treating it as a literal. // An example would be '1px solid #000' - which evaluates to itself, // we don't need to know what the individual components are. // The drawback, of course is that you don't get the benefits of // syntax-checking on the CSS. This gives us a 50% speed-up in the parser, // and a smaller speed-up in the code-gen. // // // Token matching is done with the `$` function, which either takes // a terminal string or regexp, or a non-terminal function to call. // It also takes care of moving all the indices forwards. // // less.Parser = function Parser(env) { var input, // LeSS input string i, // current index in `input` j, // current chunk temp, // temporarily holds a chunk's state, for backtracking memo, // temporarily holds `i`, when backtracking furthest, // furthest index the parser has gone to chunks, // chunkified input current, // index of current chunk, in `input` parser; var that = this; // This function is called after all files // have been imported through `@import`. var finish = function () {}; var imports = this.imports = { paths: env && env.paths || [], // Search paths, when importing queue: [], // Files which haven't been imported yet files: {}, // Holds the imported parse trees mime: env && env.mime, // MIME type of .less files push: function (path, callback) { var that = this; this.queue.push(path); // // Import a file asynchronously // less.Parser.importer(path, this.paths, function (root) { that.queue.splice(that.queue.indexOf(path), 1); // Remove the path from the queue that.files[path] = root; // Store the root callback(root); if (that.queue.length === 0) { finish() } // Call `finish` if we're done importing }, env); } }; function save() { temp = chunks[j], memo = i, current = i } function restore() { chunks[j] = temp, i = memo, current = i } function sync() { if (i > current) { chunks[j] = chunks[j].slice(i - current); current = i; } } // // Parse from a token, regexp or string, and move forward if match // function $(tok) { var match, args, length, c, index, endIndex, k, mem; // // Non-terminal // if (tok instanceof Function) { return tok.call(parser.parsers); // // Terminal // // Either match a single character in the input, // or match a regexp in the current chunk (chunk[j]). // } else if (typeof(tok) === 'string') { match = input.charAt(i) === tok ? tok : null; length = 1; sync (); } else { sync (); if (match = tok.exec(chunks[j])) { length = match[0].length; } else { return null; } } // The match is confirmed, add the match length to `i`, // and consume any extra white-space characters (' ' || '\n') // which come after that. The reason for this is that LeSS's // grammar is mostly white-space insensitive. // if (match) { mem = i += length; endIndex = i + chunks[j].length - length; while (i < endIndex) { c = input.charCodeAt(i); if (! (c === 32 || c === 10 || c === 9)) { break } i++; } chunks[j] = chunks[j].slice(length + (i - mem)); current = i; if (chunks[j].length === 0 && j < chunks.length - 1) { j++ } if(typeof(match) === 'string') { return match; } else { return match.length === 1 ? match[0] : match; } } } // Same as $(), but don't change the state of the parser, // just return the match. function peek(tok) { if (typeof(tok) === 'string') { return input.charAt(i) === tok; } else { if (tok.test(chunks[j])) { return true; } else { return false; } } } this.env = env = env || {}; // The optimization level dictates the thoroughness of the parser, // the lower the number, the less nodes it will create in the tree. // This could matter for debugging, or if you want to access // the individual nodes in the tree. this.optimization = ('optimization' in this.env) ? this.env.optimization : 1; this.env.filename = this.env.filename || null; // // The Parser // return parser = { imports: imports, // // Parse an input string into an abstract syntax tree, // call `callback` when done. // parse: function (str, callback) { var root, start, end, zone, line, lines, buff = [], c, error = null; i = j = current = furthest = 0; chunks = []; input = str.replace(/\r\n/g, '\n'); // Split the input into chunks. chunks = (function (chunks) { var j = 0, skip = /[^"'`\{\}\/\(\)]+/g, comment = /\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g, level = 0, match, chunk = chunks[0], inParam, inString; for (var i = 0, c, cc; i < input.length; i++) { skip.lastIndex = i; if (match = skip.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); } } c = input.charAt(i); comment.lastIndex = i; if (!inString && !inParam && c === '/') { cc = input.charAt(i + 1); if (cc === '/' || cc === '*') { if (match = comment.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); c = input.charAt(i); } } } } if (c === '{' && !inString && !inParam) { level ++; chunk.push(c); } else if (c === '}' && !inString && !inParam) { level --; chunk.push(c); chunks[++j] = chunk = []; } else if (c === '(' && !inString && !inParam) { chunk.push(c); inParam = true; } else if (c === ')' && !inString && inParam) { chunk.push(c); inParam = false; } else { if (c === '"' || c === "'" || c === '`') { if (! inString) { inString = c; } else { inString = inString === c ? false : inString; } } chunk.push(c); } } if (level > 0) { throw { type: 'Syntax', message: "Missing closing `}`", filename: env.filename }; } return chunks.map(function (c) { return c.join('') });; })([[]]); // Start with the primary rule. // The whole syntax tree is held under a Ruleset node, // with the `root` property set to true, so no `{}` are // output. The callback is called when the input is parsed. root = new(tree.Ruleset)([], $(this.parsers.primary)); root.root = true; root.toCSS = (function (evaluate) { var line, lines, column; return function (options, variables) { var frames = []; options = options || {}; // // Allows setting variables with a hash, so: // // `{ color: new(tree.Color)('#f01') }` will become: // // new(tree.Rule)('@color', // new(tree.Value)([ // new(tree.Expression)([ // new(tree.Color)('#f01') // ]) // ]) // ) // if (typeof(variables) === 'object' && !Array.isArray(variables)) { variables = Object.keys(variables).map(function (k) { var value = variables[k]; if (! (value instanceof tree.Value)) { if (! (value instanceof tree.Expression)) { value = new(tree.Expression)([value]); } value = new(tree.Value)([value]); } return new(tree.Rule)('@' + k, value, false, 0); }); frames = [new(tree.Ruleset)(null, variables)]; } try { var css = evaluate.call(this, { frames: frames }) .toCSS([], { compress: options.compress || false }); } catch (e) { lines = input.split('\n'); line = getLine(e.index); for (var n = e.index, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } throw { type: e.type, message: e.message, filename: env.filename, index: e.index, line: typeof(line) === 'number' ? line + 1 : null, callLine: e.call && (getLine(e.call) + 1), callExtract: lines[getLine(e.call)], stack: e.stack, column: column, extract: [ lines[line - 1], lines[line], lines[line + 1] ] }; } if (options.compress) { return css.replace(/(\s)+/g, "$1"); } else { return css; } function getLine(index) { return index ? (input.slice(0, index).match(/\n/g) || "").length : null; } }; })(root.eval); // If `i` is smaller than the `input.length - 1`, // it means the parser wasn't able to parse the whole // string, so we've got a parsing error. // // We try to extract a \n delimited string, // showing the line where the parse error occured. // We split it up into two parts (the part which parsed, // and the part which didn't), so we can color them differently. if (i < input.length - 1) { i = furthest; lines = input.split('\n'); line = (input.slice(0, i).match(/\n/g) || "").length + 1; for (var n = i, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } error = { name: "ParseError", message: "Syntax Error on line " + line, index: i, filename: env.filename, line: line, column: column, extract: [ lines[line - 2], lines[line - 1], lines[line] ] }; } if (this.imports.queue.length > 0) { finish = function () { callback(error, root) }; } else { callback(error, root); } }, // // Here in, the parsing rules/functions // // The basic structure of the syntax tree generated is as follows: // // Ruleset -> Rule -> Value -> Expression -> Entity // // Here's some LESS code: // // .class { // color: #fff; // border: 1px solid #000; // width: @w + 4px; // > .child {...} // } // // And here's what the parse tree might look like: // // Ruleset (Selector '.class', [ // Rule ("color", Value ([Expression [Color #fff]])) // Rule ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]])) // Rule ("width", Value ([Expression [Operation "+" [Variable "@w"][Dimension 4px]]])) // Ruleset (Selector [Element '>', '.child'], [...]) // ]) // // In general, most rules will try to parse a token with the `$()` function, and if the return // value is truly, will return a new node, of the relevant type. Sometimes, we need to check // first, before parsing, that's when we use `peek()`. // parsers: { // // The `primary` rule is the *entry* and *exit* point of the parser. // The rules here can appear at any level of the parse tree. // // The recursive nature of the grammar is an interplay between the `block` // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule, // as represented by this simplified grammar: // // primary → (ruleset | rule)+ // ruleset → selector+ block // block → '{' primary '}' // // Only at one point is the primary rule not called from the // block rule: at the root level. // primary: function () { var node, root = []; while ((node = $(this.mixin.definition) || $(this.rule) || $(this.ruleset) || $(this.mixin.call) || $(this.comment) || $(this.directive)) || $(/^[\s\n]+/)) { node && root.push(node); } return root; }, // We create a Comment node for CSS comments `/* */`, // but keep the LeSS comments `//` silent, by just skipping // over them. comment: function () { var comment; if (input.charAt(i) !== '/') return; if (input.charAt(i + 1) === '/') { return new(tree.Comment)($(/^\/\/.*/), true); } else if (comment = $(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/)) { return new(tree.Comment)(comment); } }, // // Entities are tokens which can be found inside an Expression // entities: { // // A string, which supports escaping " and ' // // "milky way" 'he\'s the one!' // quoted: function () { var str, j = i, e; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '"' && input.charAt(j) !== "'") return; e && $('~'); if (str = $(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/)) { return new(tree.Quoted)(str[0], str[1] || str[2], e); } }, // // A catch-all word, such as: // // black border-collapse // keyword: function () { var k; if (k = $(/^[A-Za-z-]+/)) { return new(tree.Keyword)(k) } }, // // A function call // // rgb(255, 0, 255) // // We also try to catch IE's `alpha()`, but let the `alpha` parser // deal with the details. // // The arguments are parsed with the `entities.arguments` parser. // call: function () { var name, args; if (! (name = /^([\w-]+|%)\(/.exec(chunks[j]))) return; name = name[1].toLowerCase(); if (name === 'url') { return null } else { i += name.length } if (name === 'alpha') { return $(this.alpha) } $('('); // Parse the '(' and consume whitespace. args = $(this.entities.arguments); if (! $(')')) return; if (name) { return new(tree.Call)(name, args) } }, arguments: function () { var args = [], arg; while (arg = $(this.expression)) { args.push(arg); if (! $(',')) { break } } return args; }, literal: function () { return $(this.entities.dimension) || $(this.entities.color) || $(this.entities.quoted); }, // // Parse url() tokens // // We use a specific rule for urls, because they don't really behave like // standard function calls. The difference is that the argument doesn't have // to be enclosed within a string, so it can't be parsed as an Expression. // url: function () { var value; if (input.charAt(i) !== 'u' || !$(/^url\(/)) return; value = $(this.entities.quoted) || $(this.entities.variable) || $(this.entities.dataURI) || $(/^[-\w%@$\/.&=:;#+?~]+/) || ""; if (! $(')')) throw new(Error)("missing closing ) for url()"); return new(tree.URL)((value.value || value.data || value instanceof tree.Variable) ? value : new(tree.Anonymous)(value), imports.paths); }, dataURI: function () { var obj; if ($(/^data:/)) { obj = {}; obj.mime = $(/^[^\/]+\/[^,;)]+/) || ''; obj.charset = $(/^;\s*charset=[^,;)]+/) || ''; obj.base64 = $(/^;\s*base64/) || ''; obj.data = $(/^,\s*[^)]+/); if (obj.data) { return obj } } }, // // A Variable entity, such as `@fink`, in // // width: @fink + 2px // // We use a different parser for variable definitions, // see `parsers.variable`. // variable: function () { var name, index = i; if (input.charAt(i) === '@' && (name = $(/^@@?[\w-]+/))) { return new(tree.Variable)(name, index); } }, // // A Hexadecimal color // // #4F3C2F // // `rgb` and `hsl` colors are parsed through the `entities.call` parser. // color: function () { var rgb; if (input.charAt(i) === '#' && (rgb = $(/^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})/))) { return new(tree.Color)(rgb[1]); } }, // // A Dimension, that is, a number and a unit // // 0.5em 95% // dimension: function () { var value, c = input.charCodeAt(i); if ((c > 57 || c < 45) || c === 47) return; if (value = $(/^(-?\d*\.?\d+)(px|%|em|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn)?/)) { return new(tree.Dimension)(value[1], value[2]); } }, // // JavaScript code to be evaluated // // `window.location.href` // javascript: function () { var str, j = i, e; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '`') { return } e && $('~'); if (str = $(/^`([^`]*)`/)) { return new(tree.JavaScript)(str[1], i, e); } } }, // // The variable part of a variable definition. Used in the `rule` parser // // @fink: // variable: function () { var name; if (input.charAt(i) === '@' && (name = $(/^(@[\w-]+)\s*:/))) { return name[1] } }, // // A font size/line-height shorthand // // small/12px // // We need to peek first, or we'll match on keywords and dimensions // shorthand: function () { var a, b; if (! peek(/^[@\w.%-]+\/[@\w.-]+/)) return; if ((a = $(this.entity)) && $('/') && (b = $(this.entity))) { return new(tree.Shorthand)(a, b); } }, // // Mixins // mixin: { // // A Mixin call, with an optional argument list // // #mixins > .square(#fff); // .rounded(4px, black); // .button; // // The `while` loop is there because mixins can be // namespaced, but we only support the child and descendant // selector for now. // call: function () { var elements = [], e, c, args, index = i, s = input.charAt(i); if (s !== '.' && s !== '#') { return } while (e = $(/^[#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/)) { elements.push(new(tree.Element)(c, e)); c = $('>'); } $('(') && (args = $(this.entities.arguments)) && $(')'); if (elements.length > 0 && ($(';') || peek('}'))) { return new(tree.mixin.Call)(elements, args, index); } }, // // A Mixin definition, with a list of parameters // // .rounded (@radius: 2px, @color) { // ... // } // // Until we have a finer grained state-machine, we have to // do a look-ahead, to make sure we don't have a mixin call. // See the `rule` function for more information. // // We start by matching `.rounded (`, and then proceed on to // the argument list, which has optional default values. // We store the parameters in `params`, with a `value` key, // if there is a value, such as in the case of `@radius`. // // Once we've got our params list, and a closing `)`, we parse // the `{...}` block. // definition: function () { var name, params = [], match, ruleset, param, value; if ((input.charAt(i) !== '.' && input.charAt(i) !== '#') || peek(/^[^{]*(;|})/)) return; if (match = $(/^([#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+)\s*\(/)) { name = match[1]; while (param = $(this.entities.variable) || $(this.entities.literal) || $(this.entities.keyword)) { // Variable if (param instanceof tree.Variable) { if ($(':')) { if (value = $(this.expression)) { params.push({ name: param.name, value: value }); } else { throw new(Error)("Expected value"); } } else { params.push({ name: param.name }); } } else { params.push({ value: param }); } if (! $(',')) { break } } if (! $(')')) throw new(Error)("Expected )"); ruleset = $(this.block); if (ruleset) { return new(tree.mixin.Definition)(name, params, ruleset); } } } }, // // Entities are the smallest recognized token, // and can be found inside a rule's value. // entity: function () { return $(this.entities.literal) || $(this.entities.variable) || $(this.entities.url) || $(this.entities.call) || $(this.entities.keyword) || $(this.entities.javascript) || $(this.comment); }, // // A Rule terminator. Note that we use `peek()` to check for '}', // because the `block` rule will be expecting it, but we still need to make sure // it's there, if ';' was ommitted. // end: function () { return $(';') || peek('}'); }, // // IE's alpha function // // alpha(opacity=88) // alpha: function () { var value; if (! $(/^opacity=/i)) return; if (value = $(/^\d+/) || $(this.entities.variable)) { if (! $(')')) throw new(Error)("missing closing ) for alpha()"); return new(tree.Alpha)(value); } }, // // A Selector Element // // div // + h1 // #socks // input[type="text"] // // Elements are the building blocks for Selectors, // they are made out of a `Combinator` (see combinator rule), // and an element name, such as a tag a class, or `*`. // element: function () { var e, t, c; c = $(this.combinator); e = $(/^(?:[.#]?|:*)(?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/) || $('*') || $(this.attribute) || $(/^\([^)@]+\)/); if (e) { return new(tree.Element)(c, e) } }, // // Combinators combine elements together, in a Selector. // // Because our parser isn't white-space sensitive, special care // has to be taken, when parsing the descendant combinator, ` `, // as it's an empty space. We have to check the previous character // in the input, to see if it's a ` ` character. More info on how // we deal with this in *combinator.js*. // combinator: function () { var match, c = input.charAt(i); if (c === '>' || c === '&' || c === '+' || c === '~') { i++; while (input.charAt(i) === ' ') { i++ } return new(tree.Combinator)(c); } else if (c === ':' && input.charAt(i + 1) === ':') { i += 2; while (input.charAt(i) === ' ') { i++ } return new(tree.Combinator)('::'); } else if (input.charAt(i - 1) === ' ') { return new(tree.Combinator)(" "); } else { return new(tree.Combinator)(null); } }, // // A CSS Selector // // .class > div + h1 // li a:hover // // Selectors are made out of one or more Elements, see above. // selector: function () { var sel, e, elements = [], c, match; while (e = $(this.element)) { c = input.charAt(i); elements.push(e) if (c === '{' || c === '}' || c === ';' || c === ',') { break } } if (elements.length > 0) { return new(tree.Selector)(elements) } }, tag: function () { return $(/^[a-zA-Z][a-zA-Z-]*[0-9]?/) || $('*'); }, attribute: function () { var attr = '', key, val, op; if (! $('[')) return; if (key = $(/^[a-zA-Z-]+/) || $(this.entities.quoted)) { if ((op = $(/^[|~*$^]?=/)) && (val = $(this.entities.quoted) || $(/^[\w-]+/))) { attr = [key, op, val.toCSS ? val.toCSS() : val].join(''); } else { attr = key } } if (! $(']')) return; if (attr) { return "[" + attr + "]" } }, // // The `block` rule is used by `ruleset` and `mixin.definition`. // It's a wrapper around the `primary` rule, with added `{}`. // block: function () { var content; if ($('{') && (content = $(this.primary)) && $('}')) { return content; } }, // // div, .class, body > p {...} // ruleset: function () { var selectors = [], s, rules, match; save(); if (match = /^([.#: \w-]+)[\s\n]*\{/.exec(chunks[j])) { i += match[0].length - 1; selectors = [new(tree.Selector)([new(tree.Element)(null, match[1])])]; } else { while (s = $(this.selector)) { selectors.push(s); $(this.comment); if (! $(',')) { break } $(this.comment); } } if (selectors.length > 0 && (rules = $(this.block))) { return new(tree.Ruleset)(selectors, rules); } else { // Backtrack furthest = i; restore(); } }, rule: function () { var name, value, c = input.charAt(i), important, match; save(); if (c === '.' || c === '#' || c === '&') { return } if (name = $(this.variable) || $(this.property)) { if ((name.charAt(0) != '@') && (match = /^([^@+\/'"*`(;{}-]*);/.exec(chunks[j]))) { i += match[0].length - 1; value = new(tree.Anonymous)(match[1]); } else if (name === "font") { value = $(this.font); } else { value = $(this.value); } important = $(this.important); if (value && $(this.end)) { return new(tree.Rule)(name, value, important, memo); } else { furthest = i; restore(); } } }, // // An @import directive // // @import "lib"; // // Depending on our environemnt, importing is done differently: // In the browser, it's an XHR request, in Node, it would be a // file-system operation. The function used for importing is // stored in `import`, which we pass to the Import constructor. // "import": function () { var path; if ($(/^@import\s+/) && (path = $(this.entities.quoted) || $(this.entities.url)) && $(';')) { return new(tree.Import)(path, imports); } }, // // A CSS Directive // // @charset "utf-8"; // directive: function () { var name, value, rules, types; if (input.charAt(i) !== '@') return; if (value = $(this['import'])) { return value; } else if (name = $(/^@media|@page|@-[-a-z]+/)) { types = ($(/^[^{]+/) || '').trim(); if (rules = $(this.block)) { return new(tree.Directive)(name + " " + types, rules); } } else if (name = $(/^@[-a-z]+/)) { if (name === '@font-face') { if (rules = $(this.block)) { return new(tree.Directive)(name, rules); } } else if ((value = $(this.entity)) && $(';')) { return new(tree.Directive)(name, value); } } }, font: function () { var value = [], expression = [], weight, shorthand, font, e; while (e = $(this.shorthand) || $(this.entity)) { expression.push(e); } value.push(new(tree.Expression)(expression)); if ($(',')) { while (e = $(this.expression)) { value.push(e); if (! $(',')) { break } } } return new(tree.Value)(value); }, // // A Value is a comma-delimited list of Expressions // // font-family: Baskerville, Georgia, serif; // // In a Rule, a Value represents everything after the `:`, // and before the `;`. // value: function () { var e, expressions = [], important; while (e = $(this.expression)) { expressions.push(e); if (! $(',')) { break } } if (expressions.length > 0) { return new(tree.Value)(expressions); } }, important: function () { if (input.charAt(i) === '!') { return $(/^! *important/); } }, sub: function () { var e; if ($('(') && (e = $(this.expression)) && $(')')) { return e; } }, multiplication: function () { var m, a, op, operation; if (m = $(this.operand)) { while ((op = ($('/') || $('*'))) && (a = $(this.operand))) { operation = new(tree.Operation)(op, [operation || m, a]); } return operation || m; } }, addition: function () { var m, a, op, operation; if (m = $(this.multiplication)) { while ((op = $(/^[-+]\s+/) || (input.charAt(i - 1) != ' ' && ($('+') || $('-')))) && (a = $(this.multiplication))) { operation = new(tree.Operation)(op, [operation || m, a]); } return operation || m; } }, // // An operand is anything that can be part of an operation, // such as a Color, or a Variable // operand: function () { var negate, p = input.charAt(i + 1); if (input.charAt(i) === '-' && (p === '@' || p === '(')) { negate = $('-') } var o = $(this.sub) || $(this.entities.dimension) || $(this.entities.color) || $(this.entities.variable) || $(this.entities.call); return negate ? new(tree.Operation)('*', [new(tree.Dimension)(-1), o]) : o; }, // // Expressions either represent mathematical operations, // or white-space delimited Entities. // // 1px solid black // @var * 2 // expression: function () { var e, delim, entities = [], d; while (e = $(this.addition) || $(this.entity)) { entities.push(e); } if (entities.length > 0) { return new(tree.Expression)(entities); } }, property: function () { var name; if (name = $(/^(\*?-?[-a-z_0-9]+)\s*:/)) { return name[1]; } } } }; }; if (typeof(window) !== 'undefined') { // // Used by `@import` directives // less.Parser.importer = function (path, paths, callback, env) { if (path.charAt(0) !== '/' && paths.length > 0) { path = paths[0] + path; } // We pass `true` as 3rd argument, to force the reload of the import. // This is so we can get the syntax tree as opposed to just the CSS output, // as we need this to evaluate the current stylesheet. loadStyleSheet({ href: path, title: path, type: env.mime }, callback, true); }; } (function (tree) { tree.functions = { rgb: function (r, g, b) { return this.rgba(r, g, b, 1.0); }, rgba: function (r, g, b, a) { var rgb = [r, g, b].map(function (c) { return number(c) }), a = number(a); return new(tree.Color)(rgb, a); }, hsl: function (h, s, l) { return this.hsla(h, s, l, 1.0); }, hsla: function (h, s, l, a) { h = (number(h) % 360) / 360; s = number(s); l = number(l); a = number(a); var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s; var m1 = l * 2 - m2; return this.rgba(hue(h + 1/3) * 255, hue(h) * 255, hue(h - 1/3) * 255, a); function hue(h) { h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h); if (h * 6 < 1) return m1 + (m2 - m1) * h * 6; else if (h * 2 < 1) return m2; else if (h * 3 < 2) return m1 + (m2 - m1) * (2/3 - h) * 6; else return m1; } }, hue: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().h)); }, saturation: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().s * 100), '%'); }, lightness: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().l * 100), '%'); }, alpha: function (color) { return new(tree.Dimension)(color.toHSL().a); }, saturate: function (color, amount) { var hsl = color.toHSL(); hsl.s += amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, desaturate: function (color, amount) { var hsl = color.toHSL(); hsl.s -= amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, lighten: function (color, amount) { var hsl = color.toHSL(); hsl.l += amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, darken: function (color, amount) { var hsl = color.toHSL(); hsl.l -= amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, fadein: function (color, amount) { var hsl = color.toHSL(); hsl.a += amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, fadeout: function (color, amount) { var hsl = color.toHSL(); hsl.a -= amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, spin: function (color, amount) { var hsl = color.toHSL(); var hue = (hsl.h + amount.value) % 360; hsl.h = hue < 0 ? 360 + hue : hue; return hsla(hsl); }, // // Copyright (c) 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein // http://sass-lang.com // mix: function (color1, color2, weight) { var p = weight.value / 100.0; var w = p * 2 - 1; var a = color1.toHSL().a - color2.toHSL().a; var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0; var w2 = 1 - w1; var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2, color1.rgb[1] * w1 + color2.rgb[1] * w2, color1.rgb[2] * w1 + color2.rgb[2] * w2]; var alpha = color1.alpha * p + color2.alpha * (1 - p); return new(tree.Color)(rgb, alpha); }, greyscale: function (color) { return this.desaturate(color, new(tree.Dimension)(100)); }, e: function (str) { return new(tree.Anonymous)(str instanceof tree.JavaScript ? str.evaluated : str); }, escape: function (str) { return new(tree.Anonymous)(encodeURI(str.value).replace(/=/g, "%3D").replace(/:/g, "%3A").replace(/#/g, "%23").replace(/;/g, "%3B").replace(/\(/g, "%28").replace(/\)/g, "%29")); }, '%': function (quoted /* arg, arg, ...*/) { var args = Array.prototype.slice.call(arguments, 1), str = quoted.value; for (var i = 0; i < args.length; i++) { str = str.replace(/%[sda]/i, function(token) { var value = token.match(/s/i) ? args[i].value : args[i].toCSS(); return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value; }); } str = str.replace(/%%/g, '%'); return new(tree.Quoted)('"' + str + '"', str); }, round: function (n) { if (n instanceof tree.Dimension) { return new(tree.Dimension)(Math.round(number(n)), n.unit); } else if (typeof(n) === 'number') { return Math.round(n); } else { throw { error: "RuntimeError", message: "math functions take numbers as parameters" }; } } }; function hsla(hsla) { return tree.functions.hsla(hsla.h, hsla.s, hsla.l, hsla.a); } function number(n) { if (n instanceof tree.Dimension) { return parseFloat(n.unit == '%' ? n.value / 100 : n.value); } else if (typeof(n) === 'number') { return n; } else { throw { error: "RuntimeError", message: "color functions take numbers as parameters" }; } } function clamp(val) { return Math.min(1, Math.max(0, val)); } })(require('less/tree')); (function (tree) { tree.Alpha = function (val) { this.value = val; }; tree.Alpha.prototype = { toCSS: function () { return "alpha(opacity=" + (this.value.toCSS ? this.value.toCSS() : this.value) + ")"; }, eval: function () { return this } }; })(require('less/tree')); (function (tree) { tree.Anonymous = function (string) { this.value = string.value || string; }; tree.Anonymous.prototype = { toCSS: function () { return this.value; }, eval: function () { return this } }; })(require('less/tree')); (function (tree) { // // A function call node. // tree.Call = function (name, args) { this.name = name; this.args = args; }; tree.Call.prototype = { // // When evaluating a function call, // we either find the function in `tree.functions` [1], // in which case we call it, passing the evaluated arguments, // or we simply print it out as it appeared originally [2]. // // The *functions.js* file contains the built-in functions. // // The reason why we evaluate the arguments, is in the case where // we try to pass a variable to a function, like: `saturate(@color)`. // The function should receive the value, not the variable. // eval: function (env) { var args = this.args.map(function (a) { return a.eval(env) }); if (this.name in tree.functions) { // 1. return tree.functions[this.name].apply(tree.functions, args); } else { // 2. return new(tree.Anonymous)(this.name + "(" + args.map(function (a) { return a.toCSS() }).join(', ') + ")"); } }, toCSS: function (env) { return this.eval(env).toCSS(); } }; })(require('less/tree')); (function (tree) { // // RGB Colors - #ff0014, #eee // tree.Color = function (rgb, a) { // // The end goal here, is to parse the arguments // into an integer triplet, such as `128, 255, 0` // // This facilitates operations and conversions. // if (Array.isArray(rgb)) { this.rgb = rgb; } else if (rgb.length == 6) { this.rgb = rgb.match(/.{2}/g).map(function (c) { return parseInt(c, 16); }); } else if (rgb.length == 8) { this.alpha = parseInt(rgb.substring(0,2), 16) / 255.0; this.rgb = rgb.substr(2).match(/.{2}/g).map(function (c) { return parseInt(c, 16); }); } else { this.rgb = rgb.split('').map(function (c) { return parseInt(c + c, 16); }); } this.alpha = typeof(a) === 'number' ? a : 1; }; tree.Color.prototype = { eval: function () { return this }, // // If we have some transparency, the only way to represent it // is via `rgba`. Otherwise, we use the hex representation, // which has better compatibility with older browsers. // Values are capped between `0` and `255`, rounded and zero-padded. // toCSS: function () { if (this.alpha < 1.0) { return "rgba(" + this.rgb.map(function (c) { return Math.round(c); }).concat(this.alpha).join(', ') + ")"; } else { return '#' + this.rgb.map(function (i) { i = Math.round(i); i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16); return i.length === 1 ? '0' + i : i; }).join(''); } }, // // Operations have to be done per-channel, if not, // channels will spill onto each other. Once we have // our result, in the form of an integer triplet, // we create a new Color node to hold the result. // operate: function (op, other) { var result = []; if (! (other instanceof tree.Color)) { other = other.toColor(); } for (var c = 0; c < 3; c++) { result[c] = tree.operate(op, this.rgb[c], other.rgb[c]); } return new(tree.Color)(result, this.alpha + other.alpha); }, toHSL: function () { var r = this.rgb[0] / 255, g = this.rgb[1] / 255, b = this.rgb[2] / 255, a = this.alpha; var max = Math.max(r, g, b), min = Math.min(r, g, b); var h, s, l = (max + min) / 2, d = max - min; if (max === min) { h = s = 0; } else { s = l > 0.5 ? d / (2 - max - min) : d / (max + min); switch (max) { case r: h = (g - b) / d + (g < b ? 6 : 0); break; case g: h = (b - r) / d + 2; break; case b: h = (r - g) / d + 4; break; } h /= 6; } return { h: h * 360, s: s, l: l, a: a }; } }; })(require('less/tree')); (function (tree) { tree.Comment = function (value, silent) { this.value = value; this.silent = !!silent; }; tree.Comment.prototype = { toCSS: function (env) { return env.compress ? '' : this.value; }, eval: function () { return this } }; })(require('less/tree')); (function (tree) { // // A number with a unit // tree.Dimension = function (value, unit) { this.value = parseFloat(value); this.unit = unit || null; }; tree.Dimension.prototype = { eval: function () { return this }, toColor: function () { return new(tree.Color)([this.value, this.value, this.value]); }, toCSS: function () { var css = this.value + this.unit; return css; }, // In an operation between two Dimensions, // we default to the first Dimension's unit, // so `1px + 2em` will yield `3px`. // In the future, we could implement some unit // conversions such that `100cm + 10mm` would yield // `101cm`. operate: function (op, other) { return new(tree.Dimension) (tree.operate(op, this.value, other.value), this.unit || other.unit); } }; })(require('less/tree')); (function (tree) { tree.Directive = function (name, value) { this.name = name; if (Array.isArray(value)) { this.ruleset = new(tree.Ruleset)([], value); } else { this.value = value; } }; tree.Directive.prototype = { toCSS: function (ctx, env) { if (this.ruleset) { this.ruleset.root = true; return this.name + (env.compress ? '{' : ' {\n ') + this.ruleset.toCSS(ctx, env).trim().replace(/\n/g, '\n ') + (env.compress ? '}': '\n}\n'); } else { return this.name + ' ' + this.value.toCSS() + ';\n'; } }, eval: function (env) { env.frames.unshift(this); this.ruleset = this.ruleset && this.ruleset.eval(env); env.frames.shift(); return this; }, variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) }, find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) }, rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) } }; })(require('less/tree')); (function (tree) { tree.Element = function (combinator, value) { this.combinator = combinator instanceof tree.Combinator ? combinator : new(tree.Combinator)(combinator); this.value = value.trim(); }; tree.Element.prototype.toCSS = function (env) { return this.combinator.toCSS(env || {}) + this.value; }; tree.Combinator = function (value) { if (value === ' ') { this.value = ' '; } else { this.value = value ? value.trim() : ""; } }; tree.Combinator.prototype.toCSS = function (env) { return { '' : '', ' ' : ' ', '&' : '', ':' : ' :', '::': '::', '+' : env.compress ? '+' : ' + ', '~' : env.compress ? '~' : ' ~ ', '>' : env.compress ? '>' : ' > ' }[this.value]; }; })(require('less/tree')); (function (tree) { tree.Expression = function (value) { this.value = value }; tree.Expression.prototype = { eval: function (env) { if (this.value.length > 1) { return new(tree.Expression)(this.value.map(function (e) { return e.eval(env); })); } else { return this.value[0].eval(env); } }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS(env); }).join(' '); } }; })(require('less/tree')); (function (tree) { // // CSS @import node // // The general strategy here is that we don't want to wait // for the parsing to be completed, before we start importing // the file. That's because in the context of a browser, // most of the time will be spent waiting for the server to respond. // // On creation, we push the import path to our import queue, though // `import,push`, we also pass it a callback, which it'll call once // the file has been fetched, and parsed. // tree.Import = function (path, imports) { var that = this; this._path = path; // The '.less' extension is optional if (path instanceof tree.Quoted) { this.path = /\.(le?|c)ss$/.test(path.value) ? path.value : path.value + '.less'; } else { this.path = path.value.value || path.value; } this.css = /css$/.test(this.path); // Only pre-compile .less files if (! this.css) { imports.push(this.path, function (root) { if (! root) { throw new(Error)("Error parsing " + that.path); } that.root = root; }); } }; // // The actual import node doesn't return anything, when converted to CSS. // The reason is that it's used at the evaluation stage, so that the rules // it imports can be treated like any other rules. // // In `eval`, we make sure all Import nodes get evaluated, recursively, so // we end up with a flat structure, which can easily be imported in the parent // ruleset. // tree.Import.prototype = { toCSS: function () { if (this.css) { return "@import " + this._path.toCSS() + ';\n'; } else { return ""; } }, eval: function (env) { var ruleset; if (this.css) { return this; } else { ruleset = new(tree.Ruleset)(null, this.root.rules.slice(0)); for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.Import) { Array.prototype .splice .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env))); } } return ruleset.rules; } } }; })(require('less/tree')); (function (tree) { tree.JavaScript = function (string, index, escaped) { this.escaped = escaped; this.expression = string; this.index = index; }; tree.JavaScript.prototype = { toCSS: function () { if (this.escaped) { return this.evaluated; } else { return JSON.stringify(this.evaluated); } }, eval: function (env) { var result, context = {}; var expression = this.expression.replace(/@\{([\w-]+)\}/g, function (_, name) { return new(tree.Variable)('@' + name).eval(env).value; }); expression = new(Function)('return (' + expression + ')'); for (var k in env.frames[0].variables()) { context[k.slice(1)] = { value: env.frames[0].variables()[k].value, toJS: function () { return this.value.eval(env).toCSS(); } }; } try { this.evaluated = expression.call(context); } catch (e) { throw { message: "JavaScript evaluation error: '" + e.name + ': ' + e.message + "'" , index: this.index }; } return this; } }; })(require('less/tree')); (function (tree) { tree.Keyword = function (value) { this.value = value }; tree.Keyword.prototype = { eval: function () { return this }, toCSS: function () { return this.value } }; })(require('less/tree')); (function (tree) { tree.mixin = {}; tree.mixin.Call = function (elements, args, index) { this.selector = new(tree.Selector)(elements); this.arguments = args; this.index = index; }; tree.mixin.Call.prototype = { eval: function (env) { var mixins, rules = [], match = false; for (var i = 0; i < env.frames.length; i++) { if ((mixins = env.frames[i].find(this.selector)).length > 0) { for (var m = 0; m < mixins.length; m++) { if (mixins[m].match(this.arguments, env)) { try { Array.prototype.push.apply( rules, mixins[m].eval(env, this.arguments).rules); match = true; } catch (e) { throw { message: e.message, index: e.index, stack: e.stack, call: this.index }; } } } if (match) { return rules; } else { throw { message: 'No matching definition was found for `' + this.selector.toCSS().trim() + '(' + this.arguments.map(function (a) { return a.toCSS(); }).join(', ') + ")`", index: this.index }; } } } throw { message: this.selector.toCSS().trim() + " is undefined", index: this.index }; } }; tree.mixin.Definition = function (name, params, rules) { this.name = name; this.selectors = [new(tree.Selector)([new(tree.Element)(null, name)])]; this.params = params; this.arity = params.length; this.rules = rules; this._lookups = {}; this.required = params.reduce(function (count, p) { if (!p.name || (p.name && !p.value)) { return count + 1 } else { return count } }, 0); this.parent = tree.Ruleset.prototype; this.frames = []; }; tree.mixin.Definition.prototype = { toCSS: function () { return "" }, variable: function (name) { return this.parent.variable.call(this, name) }, variables: function () { return this.parent.variables.call(this) }, find: function () { return this.parent.find.apply(this, arguments) }, rulesets: function () { return this.parent.rulesets.apply(this) }, eval: function (env, args) { var frame = new(tree.Ruleset)(null, []), context, _arguments = []; for (var i = 0, val; i < this.params.length; i++) { if (this.params[i].name) { if (val = (args && args[i]) || this.params[i].value) { frame.rules.unshift(new(tree.Rule)(this.params[i].name, val.eval(env))); } else { throw { message: "wrong number of arguments for " + this.name + ' (' + args.length + ' for ' + this.arity + ')' }; } } } for (var i = 0; i < Math.max(this.params.length, args && args.length); i++) { _arguments.push(args[i] || this.params[i].value); } frame.rules.unshift(new(tree.Rule)('@arguments', new(tree.Expression)(_arguments))); return new(tree.Ruleset)(null, this.rules.slice(0)).eval({ frames: [this, frame].concat(this.frames, env.frames) }); }, match: function (args, env) { var argsLength = (args && args.length) || 0, len; if (argsLength < this.required) { return false } if ((this.required > 0) && (argsLength > this.params.length)) { return false } len = Math.min(argsLength, this.arity); for (var i = 0; i < len; i++) { if (!this.params[i].name) { if (args[i].eval(env).toCSS() != this.params[i].value.eval(env).toCSS()) { return false; } } } return true; } }; })(require('less/tree')); (function (tree) { tree.Operation = function (op, operands) { this.op = op.trim(); this.operands = operands; }; tree.Operation.prototype.eval = function (env) { var a = this.operands[0].eval(env), b = this.operands[1].eval(env), temp; if (a instanceof tree.Dimension && b instanceof tree.Color) { if (this.op === '*' || this.op === '+') { temp = b, b = a, a = temp; } else { throw { name: "OperationError", message: "Can't substract or divide a color from a number" }; } } return a.operate(this.op, b); }; tree.operate = function (op, a, b) { switch (op) { case '+': return a + b; case '-': return a - b; case '*': return a * b; case '/': return a / b; } }; })(require('less/tree')); (function (tree) { tree.Quoted = function (str, content, escaped, i) { this.escaped = escaped; this.value = content || ''; this.quote = str.charAt(0); this.index = i; }; tree.Quoted.prototype = { toCSS: function () { if (this.escaped) { return this.value; } else { return this.quote + this.value + this.quote; } }, eval: function (env) { this.value = this.value.replace(/@\{([\w-]+)\}/g, function (_, name) { return new(tree.Variable)('@' + name).eval(env).value; }).replace(/`([^`]+)`/g, function (_, exp) { return new(tree.JavaScript)(exp, this.index, true).eval(env).toCSS(); }); return this; } }; })(require('less/tree')); (function (tree) { tree.Rule = function (name, value, important, index) { this.name = name; this.value = (value instanceof tree.Value) ? value : new(tree.Value)([value]); this.important = important ? ' ' + important.trim() : ''; this.index = index; if (name.charAt(0) === '@') { this.variable = true; } else { this.variable = false } }; tree.Rule.prototype.toCSS = function (env) { if (this.variable) { return "" } else { return this.name + (env.compress ? ':' : ': ') + this.value.toCSS(env) + this.important + ";"; } }; tree.Rule.prototype.eval = function (context) { return new(tree.Rule)(this.name, this.value.eval(context), this.important, this.index); }; tree.Shorthand = function (a, b) { this.a = a; this.b = b; }; tree.Shorthand.prototype = { toCSS: function (env) { return this.a.toCSS(env) + "/" + this.b.toCSS(env); }, eval: function () { return this } }; })(require('less/tree')); (function (tree) { tree.Ruleset = function (selectors, rules) { this.selectors = selectors; this.rules = rules; this._lookups = {}; }; tree.Ruleset.prototype = { eval: function (env) { var ruleset = new(tree.Ruleset)(this.selectors, this.rules.slice(0)); ruleset.root = this.root; // push the current ruleset to the frames stack env.frames.unshift(ruleset); // Evaluate imports if (ruleset.root) { for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.Import) { Array.prototype.splice .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env))); } } } // Store the frames around mixin definitions, // so they can be evaluated like closures when the time comes. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Definition) { ruleset.rules[i].frames = env.frames.slice(0); } } // Evaluate mixin calls. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Call) { Array.prototype.splice .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env))); } } // Evaluate everything else for (var i = 0, rule; i < ruleset.rules.length; i++) { rule = ruleset.rules[i]; if (! (rule instanceof tree.mixin.Definition)) { ruleset.rules[i] = rule.eval ? rule.eval(env) : rule; } } // Pop the stack env.frames.shift(); return ruleset; }, match: function (args) { return !args || args.length === 0; }, variables: function () { if (this._variables) { return this._variables } else { return this._variables = this.rules.reduce(function (hash, r) { if (r instanceof tree.Rule && r.variable === true) { hash[r.name] = r; } return hash; }, {}); } }, variable: function (name) { return this.variables()[name]; }, rulesets: function () { if (this._rulesets) { return this._rulesets } else { return this._rulesets = this.rules.filter(function (r) { return (r instanceof tree.Ruleset) || (r instanceof tree.mixin.Definition); }); } }, find: function (selector, self) { self = self || this; var rules = [], rule, match, key = selector.toCSS(); if (key in this._lookups) { return this._lookups[key] } this.rulesets().forEach(function (rule) { if (rule !== self) { for (var j = 0; j < rule.selectors.length; j++) { if (match = selector.match(rule.selectors[j])) { if (selector.elements.length > 1) { Array.prototype.push.apply(rules, rule.find( new(tree.Selector)(selector.elements.slice(1)), self)); } else { rules.push(rule); } break; } } } }); return this._lookups[key] = rules; }, // // Entry point for code generation // // `context` holds an array of arrays. // toCSS: function (context, env) { var css = [], // The CSS output rules = [], // node.Rule instances rulesets = [], // node.Ruleset instances paths = [], // Current selectors selector, // The fully rendered selector rule; if (! this.root) { if (context.length === 0) { paths = this.selectors.map(function (s) { return [s] }); } else { for (var s = 0; s < this.selectors.length; s++) { for (var c = 0; c < context.length; c++) { paths.push(context[c].concat([this.selectors[s]])); } } } } // Compile rules and rulesets for (var i = 0; i < this.rules.length; i++) { rule = this.rules[i]; if (rule.rules || (rule instanceof tree.Directive)) { rulesets.push(rule.toCSS(paths, env)); } else if (rule instanceof tree.Comment) { if (!rule.silent) { if (this.root) { rulesets.push(rule.toCSS(env)); } else { rules.push(rule.toCSS(env)); } } } else { if (rule.toCSS && !rule.variable) { rules.push(rule.toCSS(env)); } else if (rule.value && !rule.variable) { rules.push(rule.value.toString()); } } } rulesets = rulesets.join(''); // If this is the root node, we don't render // a selector, or {}. // Otherwise, only output if this ruleset has rules. if (this.root) { css.push(rules.join(env.compress ? '' : '\n')); } else { if (rules.length > 0) { selector = paths.map(function (p) { return p.map(function (s) { return s.toCSS(env); }).join('').trim(); }).join(env.compress ? ',' : (paths.length > 3 ? ',\n' : ', ')); css.push(selector, (env.compress ? '{' : ' {\n ') + rules.join(env.compress ? '' : '\n ') + (env.compress ? '}' : '\n}\n')); } } css.push(rulesets); return css.join('') + (env.compress ? '\n' : ''); } }; })(require('less/tree')); (function (tree) { tree.Selector = function (elements) { this.elements = elements; if (this.elements[0].combinator.value === "") { this.elements[0].combinator.value = ' '; } }; tree.Selector.prototype.match = function (other) { if (this.elements[0].value === other.elements[0].value) { return true; } else { return false; } }; tree.Selector.prototype.toCSS = function (env) { if (this._css) { return this._css } return this._css = this.elements.map(function (e) { if (typeof(e) === 'string') { return ' ' + e.trim(); } else { return e.toCSS(env); } }).join(''); }; })(require('less/tree')); (function (tree) { tree.URL = function (val, paths) { if (val.data) { this.attrs = val; } else { // Add the base path if the URL is relative and we are in the browser if (!/^(?:https?:\/|file:\/|data:\/)?\//.test(val.value) && paths.length > 0 && typeof(window) !== 'undefined') { val.value = paths[0] + (val.value.charAt(0) === '/' ? val.value.slice(1) : val.value); } this.value = val; this.paths = paths; } }; tree.URL.prototype = { toCSS: function () { return "url(" + (this.attrs ? 'data:' + this.attrs.mime + this.attrs.charset + this.attrs.base64 + this.attrs.data : this.value.toCSS()) + ")"; }, eval: function (ctx) { return this.attrs ? this : new(tree.URL)(this.value.eval(ctx), this.paths); } }; })(require('less/tree')); (function (tree) { tree.Value = function (value) { this.value = value; this.is = 'value'; }; tree.Value.prototype = { eval: function (env) { if (this.value.length === 1) { return this.value[0].eval(env); } else { return new(tree.Value)(this.value.map(function (v) { return v.eval(env); })); } }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS(env); }).join(env.compress ? ',' : ', '); } }; })(require('less/tree')); (function (tree) { tree.Variable = function (name, index) { this.name = name, this.index = index }; tree.Variable.prototype = { eval: function (env) { var variable, v, name = this.name; if (name.indexOf('@@') == 0) { name = '@' + new(tree.Variable)(name.slice(1)).eval(env).value; } if (variable = tree.find(env.frames, function (frame) { if (v = frame.variable(name)) { return v.value.eval(env); } })) { return variable } else { throw { message: "variable " + name + " is undefined", index: this.index }; } } }; })(require('less/tree')); require('less/tree').find = function (obj, fun) { for (var i = 0, r; i < obj.length; i++) { if (r = fun.call(obj, obj[i])) { return r } } return null; }; // // browser.js - client-side engine // var isFileProtocol = (location.protocol === 'file:' || location.protocol === 'chrome:' || location.protocol === 'chrome-extension:' || location.protocol === 'resource:'); less.env = less.env || (location.hostname == '127.0.0.1' || location.hostname == '0.0.0.0' || location.hostname == 'localhost' || location.port.length > 0 || isFileProtocol ? 'development' : 'production'); // Load styles asynchronously (default: false) // // This is set to `false` by default, so that the body // doesn't start loading before the stylesheets are parsed. // Setting this to `true` can result in flickering. // less.async = false; // Interval between watch polls less.poll = less.poll || (isFileProtocol ? 1000 : 1500); // // Watch mode // less.watch = function () { return this.watchMode = true }; less.unwatch = function () { return this.watchMode = false }; if (less.env === 'development') { less.optimization = 0; if (/!watch/.test(location.hash)) { less.watch(); } less.watchTimer = setInterval(function () { if (less.watchMode) { loadStyleSheets(function (root, sheet, env) { if (root) { createCSS(root.toCSS(), sheet, env.lastModified); } }); } }, less.poll); } else { less.optimization = 3; } var cache; try { cache = (typeof(window.localStorage) === 'undefined') ? null : window.localStorage; } catch (_) { cache = null; } // // Get all tags with the 'rel' attribute set to "stylesheet/less" // var links = document.getElementsByTagName('link'); var typePattern = /^text\/(x-)?less$/; less.sheets = []; for (var i = 0; i < links.length; i++) { if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) && (links[i].type.match(typePattern)))) { less.sheets.push(links[i]); } } less.refresh = function (reload) { var startTime, endTime; startTime = endTime = new(Date); loadStyleSheets(function (root, sheet, env) { if (env.local) { log("loading " + sheet.href + " from cache."); } else { log("parsed " + sheet.href + " successfully."); createCSS(root.toCSS(), sheet, env.lastModified); } log("css for " + sheet.href + " generated in " + (new(Date) - endTime) + 'ms'); (env.remaining === 0) && log("css generated in " + (new(Date) - startTime) + 'ms'); endTime = new(Date); }, reload); loadStyles(); }; less.refreshStyles = loadStyles; less.refresh(less.env === 'development'); function loadStyles() { var styles = document.getElementsByTagName('style'); for (var i = 0; i < styles.length; i++) { if (styles[i].type.match(typePattern)) { new(less.Parser)().parse(styles[i].innerHTML || '', function (e, tree) { styles[i].type = 'text/css'; styles[i].innerHTML = tree.toCSS(); }); } } } function loadStyleSheets(callback, reload) { for (var i = 0; i < less.sheets.length; i++) { loadStyleSheet(less.sheets[i], callback, reload, less.sheets.length - (i + 1)); } } function loadStyleSheet(sheet, callback, reload, remaining) { var url = window.location.href.replace(/[#?].*$/, ''); var href = sheet.href.replace(/\?.*$/, ''); var css = cache && cache.getItem(href); var timestamp = cache && cache.getItem(href + ':timestamp'); var styles = { css: css, timestamp: timestamp }; // Stylesheets in IE don't always return the full path if (! /^(https?|file):/.test(href)) { if (href.charAt(0) == "/") { href = window.location.protocol + "//" + window.location.host + href; } else { href = url.slice(0, url.lastIndexOf('/') + 1) + href; } } xhr(sheet.href, sheet.type, function (data, lastModified) { if (!reload && styles && lastModified && (new(Date)(lastModified).valueOf() === new(Date)(styles.timestamp).valueOf())) { // Use local copy createCSS(styles.css, sheet); callback(null, sheet, { local: true, remaining: remaining }); } else { // Use remote copy (re-parse) try { new(less.Parser)({ optimization: less.optimization, paths: [href.replace(/[\w\.-]+$/, '')], mime: sheet.type }).parse(data, function (e, root) { if (e) { return error(e, href) } try { callback(root, sheet, { local: false, lastModified: lastModified, remaining: remaining }); removeNode(document.getElementById('less-error-message:' + extractId(href))); } catch (e) { error(e, href); } }); } catch (e) { error(e, href); } } }, function (status, url) { throw new(Error)("Couldn't load " + url + " (" + status + ")"); }); } function extractId(href) { return href.replace(/^[a-z]+:\/\/?[^\/]+/, '' ) // Remove protocol & domain .replace(/^\//, '' ) // Remove root / .replace(/\?.*$/, '' ) // Remove query .replace(/\.[^\.\/]+$/, '' ) // Remove file extension .replace(/[^\.\w-]+/g, '-') // Replace illegal characters .replace(/\./g, ':'); // Replace dots with colons(for valid id) } function createCSS(styles, sheet, lastModified) { var css; // Strip the query-string var href = sheet.href ? sheet.href.replace(/\?.*$/, '') : ''; // If there is no title set, use the filename, minus the extension var id = 'less:' + (sheet.title || extractId(href)); // If the stylesheet doesn't exist, create a new node if ((css = document.getElementById(id)) === null) { css = document.createElement('style'); css.type = 'text/css'; css.media = sheet.media || 'screen'; css.id = id; document.getElementsByTagName('head')[0].appendChild(css); } if (css.styleSheet) { // IE try { css.styleSheet.cssText = styles; } catch (e) { throw new(Error)("Couldn't reassign styleSheet.cssText."); } } else { (function (node) { if (css.childNodes.length > 0) { if (css.firstChild.nodeValue !== node.nodeValue) { css.replaceChild(node, css.firstChild); } } else { css.appendChild(node); } })(document.createTextNode(styles)); } // Don't update the local store if the file wasn't modified if (lastModified && cache) { log('saving ' + href + ' to cache.'); cache.setItem(href, styles); cache.setItem(href + ':timestamp', lastModified); } } function xhr(url, type, callback, errback) { var xhr = getXMLHttpRequest(); var async = isFileProtocol ? false : less.async; if (typeof(xhr.overrideMimeType) === 'function') { xhr.overrideMimeType('text/css'); } xhr.open('GET', url, async); xhr.setRequestHeader('Accept', type || 'text/x-less, text/css; q=0.9, */*; q=0.5'); xhr.send(null); if (isFileProtocol) { if (xhr.status === 0) { callback(xhr.responseText); } else { errback(xhr.status, url); } } else if (async) { xhr.onreadystatechange = function () { if (xhr.readyState == 4) { handleResponse(xhr, callback, errback); } }; } else { handleResponse(xhr, callback, errback); } function handleResponse(xhr, callback, errback) { if (xhr.status >= 200 && xhr.status < 300) { callback(xhr.responseText, xhr.getResponseHeader("Last-Modified")); } else if (typeof(errback) === 'function') { errback(xhr.status, url); } } } function getXMLHttpRequest() { if (window.XMLHttpRequest) { return new(XMLHttpRequest); } else { try { return new(ActiveXObject)("MSXML2.XMLHTTP.3.0"); } catch (e) { log("browser doesn't support AJAX."); return null; } } } function removeNode(node) { return node && node.parentNode.removeChild(node); } function log(str) { if (less.env == 'development' && typeof(console) !== "undefined") { console.log('less: ' + str) } } function error(e, href) { var id = 'less-error-message:' + extractId(href); var template = [''].join('\n'); var elem = document.createElement('div'), timer, content; elem.id = id; elem.className = "less-error-message"; content = '

' + (e.message || 'There is an error in your .less file') + '

' + '

' + href + " "; if (e.extract) { content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':

' + template.replace(/\[(-?\d)\]/g, function (_, i) { return (parseInt(e.line) + parseInt(i)) || ''; }).replace(/\{(\d)\}/g, function (_, i) { return e.extract[parseInt(i)] || ''; }).replace(/\{current\}/, e.extract[1].slice(0, e.column) + '' + e.extract[1].slice(e.column) + ''); } elem.innerHTML = content; // CSS for error messages createCSS([ '.less-error-message ul, .less-error-message li {', 'list-style-type: none;', 'margin-right: 15px;', 'padding: 4px 0;', 'margin: 0;', '}', '.less-error-message label {', 'font-size: 12px;', 'margin-right: 15px;', 'padding: 4px 0;', 'color: #cc7777;', '}', '.less-error-message pre {', 'color: #ee4444;', 'padding: 4px 0;', 'margin: 0;', 'display: inline-block;', '}', '.less-error-message pre.ctx {', 'color: #dd4444;', '}', '.less-error-message h3 {', 'font-size: 20px;', 'font-weight: bold;', 'padding: 15px 0 5px 0;', 'margin: 0;', '}', '.less-error-message a {', 'color: #10a', '}', '.less-error-message .error {', 'color: red;', 'font-weight: bold;', 'padding-bottom: 2px;', 'border-bottom: 1px dashed red;', '}' ].join('\n'), { title: 'error-message' }); elem.style.cssText = [ "font-family: Arial, sans-serif", "border: 1px solid #e00", "background-color: #eee", "border-radius: 5px", "-webkit-border-radius: 5px", "-moz-border-radius: 5px", "color: #e00", "padding: 15px", "margin-bottom: 15px" ].join(';'); if (less.env == 'development') { timer = setInterval(function () { if (document.body) { if (document.getElementById(id)) { document.body.replaceChild(elem, document.getElementById(id)); } else { document.body.insertBefore(elem, document.body.firstChild); } clearInterval(timer); } }, 10); } } })(window); less.js-1.4.2/dist/less-1.1.0.min.js000066400000000000000000001025331217256642200165760ustar00rootroot00000000000000// // LESS - Leaner CSS v1.1.0 // http://lesscss.org // // Copyright (c) 2009-2011, Alexis Sellier // Licensed under the Apache 2.0 License. // // // LESS - Leaner CSS v1.1.0 // http://lesscss.org // // Copyright (c) 2009-2011, Alexis Sellier // Licensed under the Apache 2.0 License. // (function(a,b){function v(a,b){var c="less-error-message:"+p(b),e=[""].join("\n"),f=document.createElement("div"),g,h;f.id=c,f.className="less-error-message",h="

"+(a.message||"There is an error in your .less file")+"

"+'

'+b+" ",a.extract&&(h+="on line "+a.line+", column "+(a.column+1)+":

"+e.replace(/\[(-?\d)\]/g,function(b,c){return parseInt(a.line)+parseInt(c)||""}).replace(/\{(\d)\}/g,function(b,c){return a.extract[parseInt(c)]||""}).replace(/\{current\}/,a.extract[1].slice(0,a.column)+''+a.extract[1].slice(a.column)+"")),f.innerHTML=h,q([".less-error-message ul, .less-error-message li {","list-style-type: none;","margin-right: 15px;","padding: 4px 0;","margin: 0;","}",".less-error-message label {","font-size: 12px;","margin-right: 15px;","padding: 4px 0;","color: #cc7777;","}",".less-error-message pre {","color: #ee4444;","padding: 4px 0;","margin: 0;","display: inline-block;","}",".less-error-message pre.ctx {","color: #dd4444;","}",".less-error-message h3 {","font-size: 20px;","font-weight: bold;","padding: 15px 0 5px 0;","margin: 0;","}",".less-error-message a {","color: #10a","}",".less-error-message .error {","color: red;","font-weight: bold;","padding-bottom: 2px;","border-bottom: 1px dashed red;","}"].join("\n"),{title:"error-message"}),f.style.cssText=["font-family: Arial, sans-serif","border: 1px solid #e00","background-color: #eee","border-radius: 5px","-webkit-border-radius: 5px","-moz-border-radius: 5px","color: #e00","padding: 15px","margin-bottom: 15px"].join(";"),d.env=="development"&&(g=setInterval(function(){document.body&&(document.getElementById(c)?document.body.replaceChild(f,document.getElementById(c)):document.body.insertBefore(f,document.body.firstChild),clearInterval(g))},10))}function u(a){d.env=="development"&&typeof console!="undefined"&&console.log("less: "+a)}function t(a){return a&&a.parentNode.removeChild(a)}function s(){if(a.XMLHttpRequest)return new XMLHttpRequest;try{return new ActiveXObject("MSXML2.XMLHTTP.3.0")}catch(b){u("browser doesn't support AJAX.");return null}}function r(a,b,c,e){function i(b,c,d){b.status>=200&&b.status<300?c(b.responseText,b.getResponseHeader("Last-Modified")):typeof d=="function"&&d(b.status,a)}var f=s(),h=g?!1:d.async;typeof f.overrideMimeType=="function"&&f.overrideMimeType("text/css"),f.open("GET",a,h),f.setRequestHeader("Accept",b||"text/x-less, text/css; q=0.9, */*; q=0.5"),f.send(null),g?f.status===0?c(f.responseText):e(f.status,a):h?f.onreadystatechange=function(){f.readyState==4&&i(f,c,e)}:i(f,c,e)}function q(a,b,c){var d,e=b.href?b.href.replace(/\?.*$/,""):"",f="less:"+(b.title||p(e));(d=document.getElementById(f))===null&&(d=document.createElement("style"),d.type="text/css",d.media=b.media||"screen",d.id=f,document.getElementsByTagName("head")[0].appendChild(d));if(d.styleSheet)try{d.styleSheet.cssText=a}catch(g){throw new Error("Couldn't reassign styleSheet.cssText.")}else(function(a){d.childNodes.length>0?d.firstChild.nodeValue!==a.nodeValue&&d.replaceChild(a,d.firstChild):d.appendChild(a)})(document.createTextNode(a));c&&h&&(u("saving "+e+" to cache."),h.setItem(e,a),h.setItem(e+":timestamp",c))}function p(a){return a.replace(/^[a-z]+:\/\/?[^\/]+/,"").replace(/^\//,"").replace(/\?.*$/,"").replace(/\.[^\.\/]+$/,"").replace(/[^\.\w-]+/g,"-").replace(/\./g,":")}function o(b,c,e,f){var g=a.location.href.replace(/[#?].*$/,""),i=b.href.replace(/\?.*$/,""),j=h&&h.getItem(i),k=h&&h.getItem(i+":timestamp"),l={css:j,timestamp:k};/^(https?|file):/.test(i)||(i.charAt(0)=="/"?i=a.location.protocol+"//"+a.location.host+i:i=g.slice(0,g.lastIndexOf("/")+1)+i),r(b.href,b.type,function(a,g){if(!e&&l&&g&&(new Date(g)).valueOf()===(new Date(l.timestamp)).valueOf())q(l.css,b),c(null,b,{local:!0,remaining:f});else try{(new d.Parser({optimization:d.optimization,paths:[i.replace(/[\w\.-]+$/,"")],mime:b.type})).parse(a,function(a,d){if(a)return v(a,i);try{c(d,b,{local:!1,lastModified:g,remaining:f}),t(document.getElementById("less-error-message:"+p(i)))}catch(a){v(a,i)}})}catch(h){v(h,i)}},function(a,b){throw new Error("Couldn't load "+b+" ("+a+")")})}function n(a,b){for(var c=0;c>>0;for(var d=0;d>>0,c=Array(b),d=arguments[1];for(var e=0;e>>0,c=0;if(b===0&&arguments.length===1)throw new TypeError;if(arguments.length>=2)var d=arguments[1];else for(;;){if(c in this){d=this[c++];break}if(++c>=b)throw new TypeError}for(;c=b)return-1;c<0&&(c+=b);for(;ck&&(j[f]=j[f].slice(c-k),k=c)}function q(){j[f]=g,c=h,k=c}function p(){g=j[f],h=c,k=c}var b,c,f,g,h,i,j,k,l,m=this,n=function(){},o=this.imports={paths:a&&a.paths||[],queue:[],files:{},mime:a&&a.mime,push:function(b,c){var e=this;this.queue.push(b),d.Parser.importer(b,this.paths,function(a){e.queue.splice(e.queue.indexOf(b),1),e.files[b]=a,c(a),e.queue.length===0&&n()},a)}};this.env=a=a||{},this.optimization="optimization"in this.env?this.env.optimization:1,this.env.filename=this.env.filename||null;return l={imports:o,parse:function(d,g){var h,l,m,o,p,q,r=[],t,u=null;c=f=k=i=0,j=[],b=d.replace(/\r\n/g,"\n"),j=function(c){var d=0,e=/[^"'`\{\}\/\(\)]+/g,f=/\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g,g=0,h,i=c[0],j,k;for(var l=0,m,n;l0)throw{type:"Syntax",message:"Missing closing `}`",filename:a.filename};return c.map(function(a){return a.join("")})}([[]]),h=new e.Ruleset([],s(this.parsers.primary)),h.root=!0,h.toCSS=function(c){var d,f,g;return function(g,h){function n(a){return a?(b.slice(0,a).match(/\n/g)||"").length:null}var i=[];g=g||{},typeof h=="object"&&!Array.isArray(h)&&(h=Object.keys(h).map(function(a){var b=h[a];b instanceof e.Value||(b instanceof e.Expression||(b=new e.Expression([b])),b=new e.Value([b]));return new e.Rule("@"+a,b,!1,0)}),i=[new e.Ruleset(null,h)]);try{var j=c.call(this,{frames:i}).toCSS([],{compress:g.compress||!1})}catch(k){f=b.split("\n"),d=n(k.index);for(var l=k.index,m=-1;l>=0&&b.charAt(l)!=="\n";l--)m++;throw{type:k.type,message:k.message,filename:a.filename,index:k.index,line:typeof d=="number"?d+1:null,callLine:k.call&&n(k.call)+1,callExtract:f[n(k.call)],stack:k.stack,column:m,extract:[f[d-1],f[d],f[d+1]]}}return g.compress?j.replace(/(\s)+/g,"$1"):j}}(h.eval);if(c=0&&b.charAt(v)!=="\n";v--)w++;u={name:"ParseError",message:"Syntax Error on line "+p,index:c,filename:a.filename,line:p,column:w,extract:[q[p-2],q[p-1],q[p]]}}this.imports.queue.length>0?n=function(){g(u,h)}:g(u,h)},parsers:{primary:function(){var a,b=[];while((a=s(this.mixin.definition)||s(this.rule)||s(this.ruleset)||s(this.mixin.call)||s(this.comment)||s(this.directive))||s(/^[\s\n]+/))a&&b.push(a);return b},comment:function(){var a;if(b.charAt(c)==="/"){if(b.charAt(c+1)==="/")return new e.Comment(s(/^\/\/.*/),!0);if(a=s(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/))return new e.Comment(a)}},entities:{quoted:function(){var a,d=c,f;b.charAt(d)==="~"&&(d++,f=!0);if(b.charAt(d)==='"'||b.charAt(d)==="'"){f&&s("~");if(a=s(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/))return new e.Quoted(a[0],a[1]||a[2],f)}},keyword:function(){var a;if(a=s(/^[A-Za-z-]+/))return new e.Keyword(a)},call:function(){var a,b;if(!!(a=/^([\w-]+|%)\(/.exec(j[f]))){a=a[1].toLowerCase();if(a==="url")return null;c+=a.length;if(a==="alpha")return s(this.alpha);s("("),b=s(this.entities.arguments);if(!s(")"))return;if(a)return new e.Call(a,b)}},arguments:function(){var a=[],b;while(b=s(this.expression)){a.push(b);if(!s(","))break}return a},literal:function(){return s(this.entities.dimension)||s(this.entities.color)||s(this.entities.quoted)},url:function(){var a;if(b.charAt(c)==="u"&&!!s(/^url\(/)){a=s(this.entities.quoted)||s(this.entities.variable)||s(this.entities.dataURI)||s(/^[-\w%@$\/.&=:;#+?~]+/)||"";if(!s(")"))throw new Error("missing closing ) for url()");return new e.URL(a.value||a.data||a instanceof e.Variable?a:new e.Anonymous(a),o.paths)}},dataURI:function(){var a;if(s(/^data:/)){a={},a.mime=s(/^[^\/]+\/[^,;)]+/)||"",a.charset=s(/^;\s*charset=[^,;)]+/)||"",a.base64=s(/^;\s*base64/)||"",a.data=s(/^,\s*[^)]+/);if(a.data)return a}},variable:function(){var a,d=c;if(b.charAt(c)==="@"&&(a=s(/^@@?[\w-]+/)))return new e.Variable(a,d)},color:function(){var a;if(b.charAt(c)==="#"&&(a=s(/^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})/)))return new e.Color(a[1])},dimension:function(){var a,d=b.charCodeAt(c);if(!(d>57||d<45||d===47))if(a=s(/^(-?\d*\.?\d+)(px|%|em|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn)?/))return new e.Dimension(a[1],a[2])},javascript:function(){var a,d=c,f;b.charAt(d)==="~"&&(d++,f=!0);if(b.charAt(d)==="`"){f&&s("~");if(a=s(/^`([^`]*)`/))return new e.JavaScript(a[1],c,f)}}},variable:function(){var a;if(b.charAt(c)==="@"&&(a=s(/^(@[\w-]+)\s*:/)))return a[1]},shorthand:function(){var a,b;if(!!t(/^[@\w.%-]+\/[@\w.-]+/)&&(a=s(this.entity))&&s("/")&&(b=s(this.entity)))return new e.Shorthand(a,b)},mixin:{call:function(){var a=[],d,f,g,h=c,i=b.charAt(c);if(i==="."||i==="#"){while(d=s(/^[#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/))a.push(new e.Element(f,d)),f=s(">");s("(")&&(g=s(this.entities.arguments))&&s(")");if(a.length>0&&(s(";")||t("}")))return new e.mixin.Call(a,g,h)}},definition:function(){var a,d=[],f,g,h,i;if(!(b.charAt(c)!=="."&&b.charAt(c)!=="#"||t(/^[^{]*(;|})/)))if(f=s(/^([#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+)\s*\(/)){a=f[1];while(h=s(this.entities.variable)||s(this.entities.literal)||s(this.entities.keyword)){if(h instanceof e.Variable)if(s(":"))if(i=s(this.expression))d.push({name:h.name,value:i});else throw new Error("Expected value");else d.push({name:h.name});else d.push({value:h});if(!s(","))break}if(!s(")"))throw new Error("Expected )");g=s(this.block);if(g)return new e.mixin.Definition(a,d,g)}}},entity:function(){return s(this.entities.literal)||s(this.entities.variable)||s(this.entities.url)||s(this.entities.call)||s(this.entities.keyword)||s(this.entities.javascript)||s(this.comment)},end:function(){return s(";")||t("}")},alpha:function(){var a;if(!!s(/^opacity=/i))if(a=s(/^\d+/)||s(this.entities.variable)){if(!s(")"))throw new Error("missing closing ) for alpha()");return new e.Alpha(a)}},element:function(){var a,b,c;c=s(this.combinator),a=s(/^(?:[.#]?|:*)(?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/)||s("*")||s(this.attribute)||s(/^\([^)@]+\)/);if(a)return new e.Element(c,a)},combinator:function(){var a,d=b.charAt(c);if(d===">"||d==="&"||d==="+"||d==="~"){c++;while(b.charAt(c)===" ")c++;return new e.Combinator(d)}if(d===":"&&b.charAt(c+1)===":"){c+=2;while(b.charAt(c)===" ")c++;return new e.Combinator("::")}return b.charAt(c-1)===" "?new e.Combinator(" "):new e.Combinator(null)},selector:function(){var a,d,f=[],g,h;while(d=s(this.element)){g=b.charAt(c),f.push(d);if(g==="{"||g==="}"||g===";"||g===",")break}if(f.length>0)return new e.Selector(f)},tag:function(){return s(/^[a-zA-Z][a-zA-Z-]*[0-9]?/)||s("*")},attribute:function(){var a="",b,c,d;if(!!s("[")){if(b=s(/^[a-zA-Z-]+/)||s(this.entities.quoted))(d=s(/^[|~*$^]?=/))&&(c=s(this.entities.quoted)||s(/^[\w-]+/))?a=[b,d,c.toCSS?c.toCSS():c].join(""):a=b;if(!s("]"))return;if(a)return"["+a+"]"}},block:function(){var a;if(s("{")&&(a=s(this.primary))&&s("}"))return a},ruleset:function(){var a=[],b,d,g;p();if(g=/^([.#: \w-]+)[\s\n]*\{/.exec(j[f]))c+=g[0].length-1,a=[new e.Selector([new e.Element(null,g[1])])];else while(b=s(this.selector)){a.push(b),s(this.comment);if(!s(","))break;s(this.comment)}if(a.length>0&&(d=s(this.block)))return new e.Ruleset(a,d);i=c,q()},rule:function(){var a,d,g=b.charAt(c),k,l;p();if(g!=="."&&g!=="#"&&g!=="&")if(a=s(this.variable)||s(this.property)){a.charAt(0)!="@"&&(l=/^([^@+\/'"*`(;{}-]*);/.exec(j[f]))?(c+=l[0].length-1,d=new e.Anonymous(l[1])):a==="font"?d=s(this.font):d=s(this.value),k=s(this.important);if(d&&s(this.end))return new e.Rule(a,d,k,h);i=c,q()}},"import":function(){var a;if(s(/^@import\s+/)&&(a=s(this.entities.quoted)||s(this.entities.url))&&s(";"))return new e.Import(a,o)},directive:function(){var a,d,f,g;if(b.charAt(c)==="@"){if(d=s(this["import"]))return d;if(a=s(/^@media|@page|@-[-a-z]+/)){g=(s(/^[^{]+/)||"").trim();if(f=s(this.block))return new e.Directive(a+" "+g,f)}else if(a=s(/^@[-a-z]+/))if(a==="@font-face"){if(f=s(this.block))return new e.Directive(a,f)}else if((d=s(this.entity))&&s(";"))return new e.Directive(a,d)}},font:function(){var a=[],b=[],c,d,f,g;while(g=s(this.shorthand)||s(this.entity))b.push(g);a.push(new e.Expression(b));if(s(","))while(g=s(this.expression)){a.push(g);if(!s(","))break}return new e.Value(a)},value:function(){var a,b=[],c;while(a=s(this.expression)){b.push(a);if(!s(","))break}if(b.length>0)return new e.Value(b)},important:function(){if(b.charAt(c)==="!")return s(/^! *important/)},sub:function(){var a;if(s("(")&&(a=s(this.expression))&&s(")"))return a},multiplication:function(){var a,b,c,d;if(a=s(this.operand)){while((c=s("/")||s("*"))&&(b=s(this.operand)))d=new e.Operation(c,[d||a,b]);return d||a}},addition:function(){var a,d,f,g;if(a=s(this.multiplication)){while((f=s(/^[-+]\s+/)||b.charAt(c-1)!=" "&&(s("+")||s("-")))&&(d=s(this.multiplication)))g=new e.Operation(f,[g||a,d]);return g||a}},operand:function(){var a,d=b.charAt(c+1);b.charAt(c)==="-"&&(d==="@"||d==="(")&&(a=s("-"));var f=s(this.sub)||s(this.entities.dimension)||s(this.entities.color)||s(this.entities.variable)||s(this.entities.call);return a?new e.Operation("*",[new e.Dimension(-1),f]):f},expression:function(){var a,b,c=[],d;while(a=s(this.addition)||s(this.entity))c.push(a);if(c.length>0)return new e.Expression(c)},property:function(){var a;if(a=s(/^(\*?-?[-a-z_0-9]+)\s*:/))return a[1]}}}},typeof a!="undefined"&&(d.Parser.importer=function(a,b,c,d){a.charAt(0)!=="/"&&b.length>0&&(a=b[0]+a),o({href:a,title:a,type:d.mime},c,!0)}),function(a){function d(a){return Math.min(1,Math.max(0,a))}function c(b){if(b instanceof a.Dimension)return parseFloat(b.unit=="%"?b.value/100:b.value);if(typeof b=="number")return b;throw{error:"RuntimeError",message:"color functions take numbers as parameters"}}function b(b){return a.functions.hsla(b.h,b.s,b.l,b.a)}a.functions={rgb:function(a,b,c){return this.rgba(a,b,c,1)},rgba:function(b,d,e,f){var g=[b,d,e].map(function(a){return c(a)}),f=c(f);return new a.Color(g,f)},hsl:function(a,b,c){return this.hsla(a,b,c,1)},hsla:function(a,b,d,e){function h(a){a=a<0?a+1:a>1?a-1:a;return a*6<1?g+(f-g)*a*6:a*2<1?f:a*3<2?g+(f-g)*(2/3-a)*6:g}a=c(a)%360/360,b=c(b),d=c(d),e=c(e);var f=d<=.5?d*(b+1):d+b-d*b,g=d*2-f;return this.rgba(h(a+1/3)*255,h(a)*255,h(a-1/3)*255,e)},hue:function(b){return new a.Dimension(Math.round(b.toHSL().h))},saturation:function(b){return new a.Dimension(Math.round(b.toHSL().s*100),"%")},lightness:function(b){return new a.Dimension(Math.round(b.toHSL().l*100),"%")},alpha:function(b){return new a.Dimension(b.toHSL().a)},saturate:function(a,c){var e=a.toHSL();e.s+=c.value/100,e.s=d(e.s);return b(e)},desaturate:function(a,c){var e=a.toHSL();e.s-=c.value/100,e.s=d(e.s);return b(e)},lighten:function(a,c){var e=a.toHSL();e.l+=c.value/100,e.l=d(e.l);return b(e)},darken:function(a,c){var e=a.toHSL();e.l-=c.value/100,e.l=d(e.l);return b(e)},fadein:function(a,c){var e=a.toHSL();e.a+=c.value/100,e.a=d(e.a);return b(e)},fadeout:function(a,c){var e=a.toHSL();e.a-=c.value/100,e.a=d(e.a);return b(e)},spin:function(a,c){var d=a.toHSL(),e=(d.h+c.value)%360;d.h=e<0?360+e:e;return b(d)},mix:function(b,c,d){var e=d.value/100,f=e*2-1,g=b.toHSL().a-c.toHSL().a,h=((f*g==-1?f:(f+g)/(1+f*g))+1)/2,i=1-h,j=[b.rgb[0]*h+c.rgb[0]*i,b.rgb[1]*h+c.rgb[1]*i,b.rgb[2]*h+c.rgb[2]*i],k=b.alpha*e+c.alpha*(1-e);return new a.Color(j,k)},greyscale:function(b){return this.desaturate(b,new a.Dimension(100))},e:function(b){return new a.Anonymous(b instanceof a.JavaScript?b.evaluated:b)},escape:function(b){return new a.Anonymous(encodeURI(b.value).replace(/=/g,"%3D").replace(/:/g,"%3A").replace(/#/g,"%23").replace(/;/g,"%3B").replace(/\(/g,"%28").replace(/\)/g,"%29"))},"%":function(b){var c=Array.prototype.slice.call(arguments,1),d=b.value;for(var e=0;e255?255:a<0?0:a).toString(16);return a.length===1?"0"+a:a}).join("")},operate:function(b,c){var d=[];c instanceof a.Color||(c=c.toColor());for(var e=0;e<3;e++)d[e]=a.operate(b,this.rgb[e],c.rgb[e]);return new a.Color(d,this.alpha+c.alpha)},toHSL:function(){var a=this.rgb[0]/255,b=this.rgb[1]/255,c=this.rgb[2]/255,d=this.alpha,e=Math.max(a,b,c),f=Math.min(a,b,c),g,h,i=(e+f)/2,j=e-f;if(e===f)g=h=0;else{h=i>.5?j/(2-e-f):j/(e+f);switch(e){case a:g=(b-c)/j+(b":a.compress?">":" > "}[this.value]}}(c("less/tree")),function(a){a.Expression=function(a){this.value=a},a.Expression.prototype={eval:function(b){return this.value.length>1?new a.Expression(this.value.map(function(a){return a.eval(b)})):this.value[0].eval(b)},toCSS:function(a){return this.value.map(function(b){return b.toCSS(a)}).join(" ")}}}(c("less/tree")),function(a){a.Import=function(b,c){var d=this;this._path=b,b instanceof a.Quoted?this.path=/\.(le?|c)ss$/.test(b.value)?b.value:b.value+".less":this.path=b.value.value||b.value,this.css=/css$/.test(this.path),this.css||c.push(this.path,function(a){if(!a)throw new Error("Error parsing "+d.path);d.root=a})},a.Import.prototype={toCSS:function(){return this.css?"@import "+this._path.toCSS()+";\n":""},eval:function(b){var c;if(this.css)return this;c=new a.Ruleset(null,this.root.rules.slice(0));for(var d=0;d0){for(var f=0;f0&&c>this.params.length)return!1;d=Math.min(c,this.arity);for(var e=0;e1?Array.prototype.push.apply(d,e.find(new a.Selector(b.elements.slice(1)),c)):d.push(e);break}});return this._lookups[g]=d},toCSS:function(b,c){var d=[],e=[],f=[],g=[],h,i;if(!this.root)if(b.length===0)g=this.selectors.map(function(a){return[a]});else for(var j=0;j0&&(h=g.map(function(a){return a.map(function(a){return a.toCSS(c)}).join("").trim()}).join(c.compress?",":g.length>3?",\n":", "),d.push(h,(c.compress?"{":" {\n ")+e.join(c.compress?"":"\n ")+(c.compress?"}":"\n}\n"))),d.push(f);return d.join("")+(c.compress?"\n":"")}}}(c("less/tree")),function(a){a.Selector=function(a){this.elements=a,this.elements[0].combinator.value===""&&(this.elements[0].combinator.value=" ")},a.Selector.prototype.match=function(a){return this.elements[0].value===a.elements[0].value?!0:!1},a.Selector.prototype.toCSS=function(a){if(this._css)return this._css;return this._css=this.elements.map(function(b){return typeof b=="string"?" "+b.trim():b.toCSS(a)}).join("")}}(c("less/tree")),function(b){b.URL=function(b,c){b.data?this.attrs=b:(!/^(?:https?:\/|file:\/|data:\/)?\//.test(b.value)&&c.length>0&&typeof a!="undefined"&&(b.value=c[0]+(b.value.charAt(0)==="/"?b.value.slice(1):b.value)),this.value=b,this.paths=c)},b.URL.prototype={toCSS:function(){return"url("+(this.attrs?"data:"+this.attrs.mime+this.attrs.charset+this.attrs.base64+this.attrs.data:this.value.toCSS())+")"},eval:function(a){return this.attrs?this:new b.URL(this.value.eval(a),this.paths)}}}(c("less/tree")),function(a){a.Value=function(a){this.value=a,this.is="value"},a.Value.prototype={eval:function(b){return this.value.length===1?this.value[0].eval(b):new a.Value(this.value.map(function(a){return a.eval(b)}))},toCSS:function(a){return this.value.map(function(b){return b.toCSS(a)}).join(a.compress?",":", ")}}}(c("less/tree")),function(a){a.Variable=function(a,b){this.name=a,this.index=b},a.Variable.prototype={eval:function(b){var c,d,e=this.name;e.indexOf("@@")==0&&(e="@"+(new a.Variable(e.slice(1))).eval(b).value);if(c=a.find(b.frames,function(a){if(d=a.variable(e))return d.value.eval(b)}))return c;throw{message:"variable "+e+" is undefined",index:this.index}}}}(c("less/tree")),c("less/tree").find=function(a,b){for(var c=0,d;c0||g?"development":"production"),d.async=!1,d.poll=d.poll||(g?1e3:1500),d.watch=function(){return this.watchMode=!0},d.unwatch=function(){return this.watchMode=!1},d.env==="development"?(d.optimization=0,/!watch/.test(location.hash)&&d.watch(),d.watchTimer=setInterval(function(){d.watchMode&&n(function(a,b,c){a&&q(a.toCSS(),b,c.lastModified)})},d.poll)):d.optimization=3;var h;try{h=typeof a.localStorage=="undefined"?null:a.localStorage}catch(i){h=null}var j=document.getElementsByTagName("link"),k=/^text\/(x-)?less$/;d.sheets=[];for(var l=0;l>> 0; for (var i = 0; i < len; i++) { if (i in this) { block.call(thisObject, this[i], i, this); } } }; } if (!Array.prototype.map) { Array.prototype.map = function(fun /*, thisp*/) { var len = this.length >>> 0; var res = new Array(len); var thisp = arguments[1]; for (var i = 0; i < len; i++) { if (i in this) { res[i] = fun.call(thisp, this[i], i, this); } } return res; }; } if (!Array.prototype.filter) { Array.prototype.filter = function (block /*, thisp */) { var values = []; var thisp = arguments[1]; for (var i = 0; i < this.length; i++) { if (block.call(thisp, this[i])) { values.push(this[i]); } } return values; }; } if (!Array.prototype.reduce) { Array.prototype.reduce = function(fun /*, initial*/) { var len = this.length >>> 0; var i = 0; // no value to return if no initial value and an empty array if (len === 0 && arguments.length === 1) throw new TypeError(); if (arguments.length >= 2) { var rv = arguments[1]; } else { do { if (i in this) { rv = this[i++]; break; } // if array contains no values, no initial value to return if (++i >= len) throw new TypeError(); } while (true); } for (; i < len; i++) { if (i in this) { rv = fun.call(null, rv, this[i], i, this); } } return rv; }; } if (!Array.prototype.indexOf) { Array.prototype.indexOf = function (value /*, fromIndex */ ) { var length = this.length; var i = arguments[1] || 0; if (!length) return -1; if (i >= length) return -1; if (i < 0) i += length; for (; i < length; i++) { if (!Object.prototype.hasOwnProperty.call(this, i)) { continue } if (value === this[i]) return i; } return -1; }; } // // Object // if (!Object.keys) { Object.keys = function (object) { var keys = []; for (var name in object) { if (Object.prototype.hasOwnProperty.call(object, name)) { keys.push(name); } } return keys; }; } // // String // if (!String.prototype.trim) { String.prototype.trim = function () { return String(this).replace(/^\s\s*/, '').replace(/\s\s*$/, ''); }; } var less, tree; if (typeof(window) === 'undefined') { less = exports, tree = require('less/tree'); } else { if (typeof(window.less) === 'undefined') { window.less = {} } less = window.less, tree = window.less.tree = {}; } // // less.js - parser // // A relatively straight-forward predictive parser. // There is no tokenization/lexing stage, the input is parsed // in one sweep. // // To make the parser fast enough to run in the browser, several // optimization had to be made: // // - Matching and slicing on a huge input is often cause of slowdowns. // The solution is to chunkify the input into smaller strings. // The chunks are stored in the `chunks` var, // `j` holds the current chunk index, and `current` holds // the index of the current chunk in relation to `input`. // This gives us an almost 4x speed-up. // // - In many cases, we don't need to match individual tokens; // for example, if a value doesn't hold any variables, operations // or dynamic references, the parser can effectively 'skip' it, // treating it as a literal. // An example would be '1px solid #000' - which evaluates to itself, // we don't need to know what the individual components are. // The drawback, of course is that you don't get the benefits of // syntax-checking on the CSS. This gives us a 50% speed-up in the parser, // and a smaller speed-up in the code-gen. // // // Token matching is done with the `$` function, which either takes // a terminal string or regexp, or a non-terminal function to call. // It also takes care of moving all the indices forwards. // // less.Parser = function Parser(env) { var input, // LeSS input string i, // current index in `input` j, // current chunk temp, // temporarily holds a chunk's state, for backtracking memo, // temporarily holds `i`, when backtracking furthest, // furthest index the parser has gone to chunks, // chunkified input current, // index of current chunk, in `input` parser; var that = this; // This function is called after all files // have been imported through `@import`. var finish = function () {}; var imports = this.imports = { paths: env && env.paths || [], // Search paths, when importing queue: [], // Files which haven't been imported yet files: {}, // Holds the imported parse trees mime: env && env.mime, // MIME type of .less files push: function (path, callback) { var that = this; this.queue.push(path); // // Import a file asynchronously // less.Parser.importer(path, this.paths, function (root) { that.queue.splice(that.queue.indexOf(path), 1); // Remove the path from the queue that.files[path] = root; // Store the root callback(root); if (that.queue.length === 0) { finish() } // Call `finish` if we're done importing }, env); } }; function save() { temp = chunks[j], memo = i, current = i } function restore() { chunks[j] = temp, i = memo, current = i } function sync() { if (i > current) { chunks[j] = chunks[j].slice(i - current); current = i; } } // // Parse from a token, regexp or string, and move forward if match // function $(tok) { var match, args, length, c, index, endIndex, k, mem; // // Non-terminal // if (tok instanceof Function) { return tok.call(parser.parsers); // // Terminal // // Either match a single character in the input, // or match a regexp in the current chunk (chunk[j]). // } else if (typeof(tok) === 'string') { match = input.charAt(i) === tok ? tok : null; length = 1; sync (); } else { sync (); if (match = tok.exec(chunks[j])) { length = match[0].length; } else { return null; } } // The match is confirmed, add the match length to `i`, // and consume any extra white-space characters (' ' || '\n') // which come after that. The reason for this is that LeSS's // grammar is mostly white-space insensitive. // if (match) { mem = i += length; endIndex = i + chunks[j].length - length; while (i < endIndex) { c = input.charCodeAt(i); if (! (c === 32 || c === 10 || c === 9)) { break } i++; } chunks[j] = chunks[j].slice(length + (i - mem)); current = i; if (chunks[j].length === 0 && j < chunks.length - 1) { j++ } if(typeof(match) === 'string') { return match; } else { return match.length === 1 ? match[0] : match; } } } // Same as $(), but don't change the state of the parser, // just return the match. function peek(tok) { if (typeof(tok) === 'string') { return input.charAt(i) === tok; } else { if (tok.test(chunks[j])) { return true; } else { return false; } } } this.env = env = env || {}; // The optimization level dictates the thoroughness of the parser, // the lower the number, the less nodes it will create in the tree. // This could matter for debugging, or if you want to access // the individual nodes in the tree. this.optimization = ('optimization' in this.env) ? this.env.optimization : 1; this.env.filename = this.env.filename || null; // // The Parser // return parser = { imports: imports, // // Parse an input string into an abstract syntax tree, // call `callback` when done. // parse: function (str, callback) { var root, start, end, zone, line, lines, buff = [], c, error = null; i = j = current = furthest = 0; chunks = []; input = str.replace(/\r\n/g, '\n'); // Split the input into chunks. chunks = (function (chunks) { var j = 0, skip = /[^"'`\{\}\/\(\)]+/g, comment = /\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g, level = 0, match, chunk = chunks[0], inParam, inString; for (var i = 0, c, cc; i < input.length; i++) { skip.lastIndex = i; if (match = skip.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); } } c = input.charAt(i); comment.lastIndex = i; if (!inString && !inParam && c === '/') { cc = input.charAt(i + 1); if (cc === '/' || cc === '*') { if (match = comment.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); c = input.charAt(i); } } } } if (c === '{' && !inString && !inParam) { level ++; chunk.push(c); } else if (c === '}' && !inString && !inParam) { level --; chunk.push(c); chunks[++j] = chunk = []; } else if (c === '(' && !inString && !inParam) { chunk.push(c); inParam = true; } else if (c === ')' && !inString && inParam) { chunk.push(c); inParam = false; } else { if (c === '"' || c === "'" || c === '`') { if (! inString) { inString = c; } else { inString = inString === c ? false : inString; } } chunk.push(c); } } if (level > 0) { throw { type: 'Syntax', message: "Missing closing `}`", filename: env.filename }; } return chunks.map(function (c) { return c.join('') });; })([[]]); // Start with the primary rule. // The whole syntax tree is held under a Ruleset node, // with the `root` property set to true, so no `{}` are // output. The callback is called when the input is parsed. root = new(tree.Ruleset)([], $(this.parsers.primary)); root.root = true; root.toCSS = (function (evaluate) { var line, lines, column; return function (options, variables) { var frames = []; options = options || {}; // // Allows setting variables with a hash, so: // // `{ color: new(tree.Color)('#f01') }` will become: // // new(tree.Rule)('@color', // new(tree.Value)([ // new(tree.Expression)([ // new(tree.Color)('#f01') // ]) // ]) // ) // if (typeof(variables) === 'object' && !Array.isArray(variables)) { variables = Object.keys(variables).map(function (k) { var value = variables[k]; if (! (value instanceof tree.Value)) { if (! (value instanceof tree.Expression)) { value = new(tree.Expression)([value]); } value = new(tree.Value)([value]); } return new(tree.Rule)('@' + k, value, false, 0); }); frames = [new(tree.Ruleset)(null, variables)]; } try { var css = evaluate.call(this, { frames: frames }) .toCSS([], { compress: options.compress || false }); } catch (e) { lines = input.split('\n'); line = getLine(e.index); for (var n = e.index, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } throw { type: e.type, message: e.message, filename: env.filename, index: e.index, line: typeof(line) === 'number' ? line + 1 : null, callLine: e.call && (getLine(e.call) + 1), callExtract: lines[getLine(e.call)], stack: e.stack, column: column, extract: [ lines[line - 1], lines[line], lines[line + 1] ] }; } if (options.compress) { return css.replace(/(\s)+/g, "$1"); } else { return css; } function getLine(index) { return index ? (input.slice(0, index).match(/\n/g) || "").length : null; } }; })(root.eval); // If `i` is smaller than the `input.length - 1`, // it means the parser wasn't able to parse the whole // string, so we've got a parsing error. // // We try to extract a \n delimited string, // showing the line where the parse error occured. // We split it up into two parts (the part which parsed, // and the part which didn't), so we can color them differently. if (i < input.length - 1) { i = furthest; lines = input.split('\n'); line = (input.slice(0, i).match(/\n/g) || "").length + 1; for (var n = i, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } error = { name: "ParseError", message: "Syntax Error on line " + line, index: i, filename: env.filename, line: line, column: column, extract: [ lines[line - 2], lines[line - 1], lines[line] ] }; } if (this.imports.queue.length > 0) { finish = function () { callback(error, root) }; } else { callback(error, root); } }, // // Here in, the parsing rules/functions // // The basic structure of the syntax tree generated is as follows: // // Ruleset -> Rule -> Value -> Expression -> Entity // // Here's some LESS code: // // .class { // color: #fff; // border: 1px solid #000; // width: @w + 4px; // > .child {...} // } // // And here's what the parse tree might look like: // // Ruleset (Selector '.class', [ // Rule ("color", Value ([Expression [Color #fff]])) // Rule ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]])) // Rule ("width", Value ([Expression [Operation "+" [Variable "@w"][Dimension 4px]]])) // Ruleset (Selector [Element '>', '.child'], [...]) // ]) // // In general, most rules will try to parse a token with the `$()` function, and if the return // value is truly, will return a new node, of the relevant type. Sometimes, we need to check // first, before parsing, that's when we use `peek()`. // parsers: { // // The `primary` rule is the *entry* and *exit* point of the parser. // The rules here can appear at any level of the parse tree. // // The recursive nature of the grammar is an interplay between the `block` // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule, // as represented by this simplified grammar: // // primary → (ruleset | rule)+ // ruleset → selector+ block // block → '{' primary '}' // // Only at one point is the primary rule not called from the // block rule: at the root level. // primary: function () { var node, root = []; while ((node = $(this.mixin.definition) || $(this.rule) || $(this.ruleset) || $(this.mixin.call) || $(this.comment) || $(this.directive)) || $(/^[\s\n]+/)) { node && root.push(node); } return root; }, // We create a Comment node for CSS comments `/* */`, // but keep the LeSS comments `//` silent, by just skipping // over them. comment: function () { var comment; if (input.charAt(i) !== '/') return; if (input.charAt(i + 1) === '/') { return new(tree.Comment)($(/^\/\/.*/), true); } else if (comment = $(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/)) { return new(tree.Comment)(comment); } }, // // Entities are tokens which can be found inside an Expression // entities: { // // A string, which supports escaping " and ' // // "milky way" 'he\'s the one!' // quoted: function () { var str, j = i, e; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '"' && input.charAt(j) !== "'") return; e && $('~'); if (str = $(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/)) { return new(tree.Quoted)(str[0], str[1] || str[2], e); } }, // // A catch-all word, such as: // // black border-collapse // keyword: function () { var k; if (k = $(/^[A-Za-z-]+/)) { return new(tree.Keyword)(k) } }, // // A function call // // rgb(255, 0, 255) // // We also try to catch IE's `alpha()`, but let the `alpha` parser // deal with the details. // // The arguments are parsed with the `entities.arguments` parser. // call: function () { var name, args; if (! (name = /^([\w-]+|%)\(/.exec(chunks[j]))) return; name = name[1].toLowerCase(); if (name === 'url') { return null } else { i += name.length } if (name === 'alpha') { return $(this.alpha) } $('('); // Parse the '(' and consume whitespace. args = $(this.entities.arguments); if (! $(')')) return; if (name) { return new(tree.Call)(name, args) } }, arguments: function () { var args = [], arg; while (arg = $(this.expression)) { args.push(arg); if (! $(',')) { break } } return args; }, literal: function () { return $(this.entities.dimension) || $(this.entities.color) || $(this.entities.quoted); }, // // Parse url() tokens // // We use a specific rule for urls, because they don't really behave like // standard function calls. The difference is that the argument doesn't have // to be enclosed within a string, so it can't be parsed as an Expression. // url: function () { var value; if (input.charAt(i) !== 'u' || !$(/^url\(/)) return; value = $(this.entities.quoted) || $(this.entities.variable) || $(this.entities.dataURI) || $(/^[-\w%@$\/.&=:;#+?~]+/) || ""; if (! $(')')) throw new(Error)("missing closing ) for url()"); return new(tree.URL)((value.value || value.data || value instanceof tree.Variable) ? value : new(tree.Anonymous)(value), imports.paths); }, dataURI: function () { var obj; if ($(/^data:/)) { obj = {}; obj.mime = $(/^[^\/]+\/[^,;)]+/) || ''; obj.charset = $(/^;\s*charset=[^,;)]+/) || ''; obj.base64 = $(/^;\s*base64/) || ''; obj.data = $(/^,\s*[^)]+/); if (obj.data) { return obj } } }, // // A Variable entity, such as `@fink`, in // // width: @fink + 2px // // We use a different parser for variable definitions, // see `parsers.variable`. // variable: function () { var name, index = i; if (input.charAt(i) === '@' && (name = $(/^@@?[\w-]+/))) { return new(tree.Variable)(name, index); } }, // // A Hexadecimal color // // #4F3C2F // // `rgb` and `hsl` colors are parsed through the `entities.call` parser. // color: function () { var rgb; if (input.charAt(i) === '#' && (rgb = $(/^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})/))) { return new(tree.Color)(rgb[1]); } }, // // A Dimension, that is, a number and a unit // // 0.5em 95% // dimension: function () { var value, c = input.charCodeAt(i); if ((c > 57 || c < 45) || c === 47) return; if (value = $(/^(-?\d*\.?\d+)(px|%|em|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn)?/)) { return new(tree.Dimension)(value[1], value[2]); } }, // // JavaScript code to be evaluated // // `window.location.href` // javascript: function () { var str, j = i, e; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '`') { return } e && $('~'); if (str = $(/^`([^`]*)`/)) { return new(tree.JavaScript)(str[1], i, e); } } }, // // The variable part of a variable definition. Used in the `rule` parser // // @fink: // variable: function () { var name; if (input.charAt(i) === '@' && (name = $(/^(@[\w-]+)\s*:/))) { return name[1] } }, // // A font size/line-height shorthand // // small/12px // // We need to peek first, or we'll match on keywords and dimensions // shorthand: function () { var a, b; if (! peek(/^[@\w.%-]+\/[@\w.-]+/)) return; if ((a = $(this.entity)) && $('/') && (b = $(this.entity))) { return new(tree.Shorthand)(a, b); } }, // // Mixins // mixin: { // // A Mixin call, with an optional argument list // // #mixins > .square(#fff); // .rounded(4px, black); // .button; // // The `while` loop is there because mixins can be // namespaced, but we only support the child and descendant // selector for now. // call: function () { var elements = [], e, c, args, index = i, s = input.charAt(i); if (s !== '.' && s !== '#') { return } while (e = $(/^[#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/)) { elements.push(new(tree.Element)(c, e)); c = $('>'); } $('(') && (args = $(this.entities.arguments)) && $(')'); if (elements.length > 0 && ($(';') || peek('}'))) { return new(tree.mixin.Call)(elements, args, index); } }, // // A Mixin definition, with a list of parameters // // .rounded (@radius: 2px, @color) { // ... // } // // Until we have a finer grained state-machine, we have to // do a look-ahead, to make sure we don't have a mixin call. // See the `rule` function for more information. // // We start by matching `.rounded (`, and then proceed on to // the argument list, which has optional default values. // We store the parameters in `params`, with a `value` key, // if there is a value, such as in the case of `@radius`. // // Once we've got our params list, and a closing `)`, we parse // the `{...}` block. // definition: function () { var name, params = [], match, ruleset, param, value; if ((input.charAt(i) !== '.' && input.charAt(i) !== '#') || peek(/^[^{]*(;|})/)) return; if (match = $(/^([#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+)\s*\(/)) { name = match[1]; while (param = $(this.entities.variable) || $(this.entities.literal) || $(this.entities.keyword)) { // Variable if (param instanceof tree.Variable) { if ($(':')) { if (value = $(this.expression)) { params.push({ name: param.name, value: value }); } else { throw new(Error)("Expected value"); } } else { params.push({ name: param.name }); } } else { params.push({ value: param }); } if (! $(',')) { break } } if (! $(')')) throw new(Error)("Expected )"); ruleset = $(this.block); if (ruleset) { return new(tree.mixin.Definition)(name, params, ruleset); } } } }, // // Entities are the smallest recognized token, // and can be found inside a rule's value. // entity: function () { return $(this.entities.literal) || $(this.entities.variable) || $(this.entities.url) || $(this.entities.call) || $(this.entities.keyword) || $(this.entities.javascript) || $(this.comment); }, // // A Rule terminator. Note that we use `peek()` to check for '}', // because the `block` rule will be expecting it, but we still need to make sure // it's there, if ';' was ommitted. // end: function () { return $(';') || peek('}'); }, // // IE's alpha function // // alpha(opacity=88) // alpha: function () { var value; if (! $(/^opacity=/i)) return; if (value = $(/^\d+/) || $(this.entities.variable)) { if (! $(')')) throw new(Error)("missing closing ) for alpha()"); return new(tree.Alpha)(value); } }, // // A Selector Element // // div // + h1 // #socks // input[type="text"] // // Elements are the building blocks for Selectors, // they are made out of a `Combinator` (see combinator rule), // and an element name, such as a tag a class, or `*`. // element: function () { var e, t, c; c = $(this.combinator); e = $(/^(?:[.#]?|:*)(?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/) || $('*') || $(this.attribute) || $(/^\([^)@]+\)/); if (e) { return new(tree.Element)(c, e) } }, // // Combinators combine elements together, in a Selector. // // Because our parser isn't white-space sensitive, special care // has to be taken, when parsing the descendant combinator, ` `, // as it's an empty space. We have to check the previous character // in the input, to see if it's a ` ` character. More info on how // we deal with this in *combinator.js*. // combinator: function () { var match, c = input.charAt(i); if (c === '>' || c === '&' || c === '+' || c === '~') { i++; while (input.charAt(i) === ' ') { i++ } return new(tree.Combinator)(c); } else if (c === ':' && input.charAt(i + 1) === ':') { i += 2; while (input.charAt(i) === ' ') { i++ } return new(tree.Combinator)('::'); } else if (input.charAt(i - 1) === ' ') { return new(tree.Combinator)(" "); } else { return new(tree.Combinator)(null); } }, // // A CSS Selector // // .class > div + h1 // li a:hover // // Selectors are made out of one or more Elements, see above. // selector: function () { var sel, e, elements = [], c, match; while (e = $(this.element)) { c = input.charAt(i); elements.push(e) if (c === '{' || c === '}' || c === ';' || c === ',') { break } } if (elements.length > 0) { return new(tree.Selector)(elements) } }, tag: function () { return $(/^[a-zA-Z][a-zA-Z-]*[0-9]?/) || $('*'); }, attribute: function () { var attr = '', key, val, op; if (! $('[')) return; if (key = $(/^[a-zA-Z-]+/) || $(this.entities.quoted)) { if ((op = $(/^[|~*$^]?=/)) && (val = $(this.entities.quoted) || $(/^[\w-]+/))) { attr = [key, op, val.toCSS ? val.toCSS() : val].join(''); } else { attr = key } } if (! $(']')) return; if (attr) { return "[" + attr + "]" } }, // // The `block` rule is used by `ruleset` and `mixin.definition`. // It's a wrapper around the `primary` rule, with added `{}`. // block: function () { var content; if ($('{') && (content = $(this.primary)) && $('}')) { return content; } }, // // div, .class, body > p {...} // ruleset: function () { var selectors = [], s, rules, match; save(); if (match = /^([.#: \w-]+)[\s\n]*\{/.exec(chunks[j])) { i += match[0].length - 1; selectors = [new(tree.Selector)([new(tree.Element)(null, match[1])])]; } else { while (s = $(this.selector)) { selectors.push(s); $(this.comment); if (! $(',')) { break } $(this.comment); } } if (selectors.length > 0 && (rules = $(this.block))) { return new(tree.Ruleset)(selectors, rules); } else { // Backtrack furthest = i; restore(); } }, rule: function () { var name, value, c = input.charAt(i), important, match; save(); if (c === '.' || c === '#' || c === '&') { return } if (name = $(this.variable) || $(this.property)) { if ((name.charAt(0) != '@') && (match = /^([^@+\/'"*`(;{}-]*);/.exec(chunks[j]))) { i += match[0].length - 1; value = new(tree.Anonymous)(match[1]); } else if (name === "font") { value = $(this.font); } else { value = $(this.value); } important = $(this.important); if (value && $(this.end)) { return new(tree.Rule)(name, value, important, memo); } else { furthest = i; restore(); } } }, // // An @import directive // // @import "lib"; // // Depending on our environemnt, importing is done differently: // In the browser, it's an XHR request, in Node, it would be a // file-system operation. The function used for importing is // stored in `import`, which we pass to the Import constructor. // "import": function () { var path; if ($(/^@import\s+/) && (path = $(this.entities.quoted) || $(this.entities.url)) && $(';')) { return new(tree.Import)(path, imports); } }, // // A CSS Directive // // @charset "utf-8"; // directive: function () { var name, value, rules, types; if (input.charAt(i) !== '@') return; if (value = $(this['import'])) { return value; } else if (name = $(/^@media|@page|@-[-a-z]+/)) { types = ($(/^[^{]+/) || '').trim(); if (rules = $(this.block)) { return new(tree.Directive)(name + " " + types, rules); } } else if (name = $(/^@[-a-z]+/)) { if (name === '@font-face') { if (rules = $(this.block)) { return new(tree.Directive)(name, rules); } } else if ((value = $(this.entity)) && $(';')) { return new(tree.Directive)(name, value); } } }, font: function () { var value = [], expression = [], weight, shorthand, font, e; while (e = $(this.shorthand) || $(this.entity)) { expression.push(e); } value.push(new(tree.Expression)(expression)); if ($(',')) { while (e = $(this.expression)) { value.push(e); if (! $(',')) { break } } } return new(tree.Value)(value); }, // // A Value is a comma-delimited list of Expressions // // font-family: Baskerville, Georgia, serif; // // In a Rule, a Value represents everything after the `:`, // and before the `;`. // value: function () { var e, expressions = [], important; while (e = $(this.expression)) { expressions.push(e); if (! $(',')) { break } } if (expressions.length > 0) { return new(tree.Value)(expressions); } }, important: function () { if (input.charAt(i) === '!') { return $(/^! *important/); } }, sub: function () { var e; if ($('(') && (e = $(this.expression)) && $(')')) { return e; } }, multiplication: function () { var m, a, op, operation; if (m = $(this.operand)) { while ((op = ($('/') || $('*'))) && (a = $(this.operand))) { operation = new(tree.Operation)(op, [operation || m, a]); } return operation || m; } }, addition: function () { var m, a, op, operation; if (m = $(this.multiplication)) { while ((op = $(/^[-+]\s+/) || (input.charAt(i - 1) != ' ' && ($('+') || $('-')))) && (a = $(this.multiplication))) { operation = new(tree.Operation)(op, [operation || m, a]); } return operation || m; } }, // // An operand is anything that can be part of an operation, // such as a Color, or a Variable // operand: function () { var negate, p = input.charAt(i + 1); if (input.charAt(i) === '-' && (p === '@' || p === '(')) { negate = $('-') } var o = $(this.sub) || $(this.entities.dimension) || $(this.entities.color) || $(this.entities.variable) || $(this.entities.call); return negate ? new(tree.Operation)('*', [new(tree.Dimension)(-1), o]) : o; }, // // Expressions either represent mathematical operations, // or white-space delimited Entities. // // 1px solid black // @var * 2 // expression: function () { var e, delim, entities = [], d; while (e = $(this.addition) || $(this.entity)) { entities.push(e); } if (entities.length > 0) { return new(tree.Expression)(entities); } }, property: function () { var name; if (name = $(/^(\*?-?[-a-z_0-9]+)\s*:/)) { return name[1]; } } } }; }; if (typeof(window) !== 'undefined') { // // Used by `@import` directives // less.Parser.importer = function (path, paths, callback, env) { if (path.charAt(0) !== '/' && paths.length > 0) { path = paths[0] + path; } // We pass `true` as 3rd argument, to force the reload of the import. // This is so we can get the syntax tree as opposed to just the CSS output, // as we need this to evaluate the current stylesheet. loadStyleSheet({ href: path, title: path, type: env.mime }, callback, true); }; } (function (tree) { tree.functions = { rgb: function (r, g, b) { return this.rgba(r, g, b, 1.0); }, rgba: function (r, g, b, a) { var rgb = [r, g, b].map(function (c) { return number(c) }), a = number(a); return new(tree.Color)(rgb, a); }, hsl: function (h, s, l) { return this.hsla(h, s, l, 1.0); }, hsla: function (h, s, l, a) { h = (number(h) % 360) / 360; s = number(s); l = number(l); a = number(a); var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s; var m1 = l * 2 - m2; return this.rgba(hue(h + 1/3) * 255, hue(h) * 255, hue(h - 1/3) * 255, a); function hue(h) { h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h); if (h * 6 < 1) return m1 + (m2 - m1) * h * 6; else if (h * 2 < 1) return m2; else if (h * 3 < 2) return m1 + (m2 - m1) * (2/3 - h) * 6; else return m1; } }, hue: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().h)); }, saturation: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().s * 100), '%'); }, lightness: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().l * 100), '%'); }, alpha: function (color) { return new(tree.Dimension)(color.toHSL().a); }, saturate: function (color, amount) { var hsl = color.toHSL(); hsl.s += amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, desaturate: function (color, amount) { var hsl = color.toHSL(); hsl.s -= amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, lighten: function (color, amount) { var hsl = color.toHSL(); hsl.l += amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, darken: function (color, amount) { var hsl = color.toHSL(); hsl.l -= amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, fadein: function (color, amount) { var hsl = color.toHSL(); hsl.a += amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, fadeout: function (color, amount) { var hsl = color.toHSL(); hsl.a -= amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, spin: function (color, amount) { var hsl = color.toHSL(); var hue = (hsl.h + amount.value) % 360; hsl.h = hue < 0 ? 360 + hue : hue; return hsla(hsl); }, // // Copyright (c) 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein // http://sass-lang.com // mix: function (color1, color2, weight) { var p = weight.value / 100.0; var w = p * 2 - 1; var a = color1.toHSL().a - color2.toHSL().a; var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0; var w2 = 1 - w1; var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2, color1.rgb[1] * w1 + color2.rgb[1] * w2, color1.rgb[2] * w1 + color2.rgb[2] * w2]; var alpha = color1.alpha * p + color2.alpha * (1 - p); return new(tree.Color)(rgb, alpha); }, greyscale: function (color) { return this.desaturate(color, new(tree.Dimension)(100)); }, e: function (str) { return new(tree.Anonymous)(str instanceof tree.JavaScript ? str.evaluated : str); }, escape: function (str) { return new(tree.Anonymous)(encodeURI(str.value).replace(/=/g, "%3D").replace(/:/g, "%3A").replace(/#/g, "%23").replace(/;/g, "%3B").replace(/\(/g, "%28").replace(/\)/g, "%29")); }, '%': function (quoted /* arg, arg, ...*/) { var args = Array.prototype.slice.call(arguments, 1), str = quoted.value; for (var i = 0; i < args.length; i++) { str = str.replace(/%[sda]/i, function(token) { var value = token.match(/s/i) ? args[i].value : args[i].toCSS(); return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value; }); } str = str.replace(/%%/g, '%'); return new(tree.Quoted)('"' + str + '"', str); }, round: function (n) { if (n instanceof tree.Dimension) { return new(tree.Dimension)(Math.round(number(n)), n.unit); } else if (typeof(n) === 'number') { return Math.round(n); } else { throw { error: "RuntimeError", message: "math functions take numbers as parameters" }; } } }; function hsla(hsla) { return tree.functions.hsla(hsla.h, hsla.s, hsla.l, hsla.a); } function number(n) { if (n instanceof tree.Dimension) { return parseFloat(n.unit == '%' ? n.value / 100 : n.value); } else if (typeof(n) === 'number') { return n; } else { throw { error: "RuntimeError", message: "color functions take numbers as parameters" }; } } function clamp(val) { return Math.min(1, Math.max(0, val)); } })(require('less/tree')); (function (tree) { tree.Alpha = function (val) { this.value = val; }; tree.Alpha.prototype = { toCSS: function () { return "alpha(opacity=" + (this.value.toCSS ? this.value.toCSS() : this.value) + ")"; }, eval: function () { return this } }; })(require('less/tree')); (function (tree) { tree.Anonymous = function (string) { this.value = string.value || string; }; tree.Anonymous.prototype = { toCSS: function () { return this.value; }, eval: function () { return this } }; })(require('less/tree')); (function (tree) { // // A function call node. // tree.Call = function (name, args) { this.name = name; this.args = args; }; tree.Call.prototype = { // // When evaluating a function call, // we either find the function in `tree.functions` [1], // in which case we call it, passing the evaluated arguments, // or we simply print it out as it appeared originally [2]. // // The *functions.js* file contains the built-in functions. // // The reason why we evaluate the arguments, is in the case where // we try to pass a variable to a function, like: `saturate(@color)`. // The function should receive the value, not the variable. // eval: function (env) { var args = this.args.map(function (a) { return a.eval(env) }); if (this.name in tree.functions) { // 1. return tree.functions[this.name].apply(tree.functions, args); } else { // 2. return new(tree.Anonymous)(this.name + "(" + args.map(function (a) { return a.toCSS() }).join(', ') + ")"); } }, toCSS: function (env) { return this.eval(env).toCSS(); } }; })(require('less/tree')); (function (tree) { // // RGB Colors - #ff0014, #eee // tree.Color = function (rgb, a) { // // The end goal here, is to parse the arguments // into an integer triplet, such as `128, 255, 0` // // This facilitates operations and conversions. // if (Array.isArray(rgb)) { this.rgb = rgb; } else if (rgb.length == 6) { this.rgb = rgb.match(/.{2}/g).map(function (c) { return parseInt(c, 16); }); } else if (rgb.length == 8) { this.alpha = parseInt(rgb.substring(0,2), 16) / 255.0; this.rgb = rgb.substr(2).match(/.{2}/g).map(function (c) { return parseInt(c, 16); }); } else { this.rgb = rgb.split('').map(function (c) { return parseInt(c + c, 16); }); } this.alpha = typeof(a) === 'number' ? a : 1; }; tree.Color.prototype = { eval: function () { return this }, // // If we have some transparency, the only way to represent it // is via `rgba`. Otherwise, we use the hex representation, // which has better compatibility with older browsers. // Values are capped between `0` and `255`, rounded and zero-padded. // toCSS: function () { if (this.alpha < 1.0) { return "rgba(" + this.rgb.map(function (c) { return Math.round(c); }).concat(this.alpha).join(', ') + ")"; } else { return '#' + this.rgb.map(function (i) { i = Math.round(i); i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16); return i.length === 1 ? '0' + i : i; }).join(''); } }, // // Operations have to be done per-channel, if not, // channels will spill onto each other. Once we have // our result, in the form of an integer triplet, // we create a new Color node to hold the result. // operate: function (op, other) { var result = []; if (! (other instanceof tree.Color)) { other = other.toColor(); } for (var c = 0; c < 3; c++) { result[c] = tree.operate(op, this.rgb[c], other.rgb[c]); } return new(tree.Color)(result, this.alpha + other.alpha); }, toHSL: function () { var r = this.rgb[0] / 255, g = this.rgb[1] / 255, b = this.rgb[2] / 255, a = this.alpha; var max = Math.max(r, g, b), min = Math.min(r, g, b); var h, s, l = (max + min) / 2, d = max - min; if (max === min) { h = s = 0; } else { s = l > 0.5 ? d / (2 - max - min) : d / (max + min); switch (max) { case r: h = (g - b) / d + (g < b ? 6 : 0); break; case g: h = (b - r) / d + 2; break; case b: h = (r - g) / d + 4; break; } h /= 6; } return { h: h * 360, s: s, l: l, a: a }; } }; })(require('less/tree')); (function (tree) { tree.Comment = function (value, silent) { this.value = value; this.silent = !!silent; }; tree.Comment.prototype = { toCSS: function (env) { return env.compress ? '' : this.value; }, eval: function () { return this } }; })(require('less/tree')); (function (tree) { // // A number with a unit // tree.Dimension = function (value, unit) { this.value = parseFloat(value); this.unit = unit || null; }; tree.Dimension.prototype = { eval: function () { return this }, toColor: function () { return new(tree.Color)([this.value, this.value, this.value]); }, toCSS: function () { var css = this.value + this.unit; return css; }, // In an operation between two Dimensions, // we default to the first Dimension's unit, // so `1px + 2em` will yield `3px`. // In the future, we could implement some unit // conversions such that `100cm + 10mm` would yield // `101cm`. operate: function (op, other) { return new(tree.Dimension) (tree.operate(op, this.value, other.value), this.unit || other.unit); } }; })(require('less/tree')); (function (tree) { tree.Directive = function (name, value) { this.name = name; if (Array.isArray(value)) { this.ruleset = new(tree.Ruleset)([], value); } else { this.value = value; } }; tree.Directive.prototype = { toCSS: function (ctx, env) { if (this.ruleset) { this.ruleset.root = true; return this.name + (env.compress ? '{' : ' {\n ') + this.ruleset.toCSS(ctx, env).trim().replace(/\n/g, '\n ') + (env.compress ? '}': '\n}\n'); } else { return this.name + ' ' + this.value.toCSS() + ';\n'; } }, eval: function (env) { env.frames.unshift(this); this.ruleset = this.ruleset && this.ruleset.eval(env); env.frames.shift(); return this; }, variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) }, find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) }, rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) } }; })(require('less/tree')); (function (tree) { tree.Element = function (combinator, value) { this.combinator = combinator instanceof tree.Combinator ? combinator : new(tree.Combinator)(combinator); this.value = value.trim(); }; tree.Element.prototype.toCSS = function (env) { return this.combinator.toCSS(env || {}) + this.value; }; tree.Combinator = function (value) { if (value === ' ') { this.value = ' '; } else { this.value = value ? value.trim() : ""; } }; tree.Combinator.prototype.toCSS = function (env) { return { '' : '', ' ' : ' ', '&' : '', ':' : ' :', '::': '::', '+' : env.compress ? '+' : ' + ', '~' : env.compress ? '~' : ' ~ ', '>' : env.compress ? '>' : ' > ' }[this.value]; }; })(require('less/tree')); (function (tree) { tree.Expression = function (value) { this.value = value }; tree.Expression.prototype = { eval: function (env) { if (this.value.length > 1) { return new(tree.Expression)(this.value.map(function (e) { return e.eval(env); })); } else if (this.value.length === 1) { return this.value[0].eval(env); } else { return this; } }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS(env); }).join(' '); } }; })(require('less/tree')); (function (tree) { // // CSS @import node // // The general strategy here is that we don't want to wait // for the parsing to be completed, before we start importing // the file. That's because in the context of a browser, // most of the time will be spent waiting for the server to respond. // // On creation, we push the import path to our import queue, though // `import,push`, we also pass it a callback, which it'll call once // the file has been fetched, and parsed. // tree.Import = function (path, imports) { var that = this; this._path = path; // The '.less' extension is optional if (path instanceof tree.Quoted) { this.path = /\.(le?|c)ss$/.test(path.value) ? path.value : path.value + '.less'; } else { this.path = path.value.value || path.value; } this.css = /css$/.test(this.path); // Only pre-compile .less files if (! this.css) { imports.push(this.path, function (root) { if (! root) { throw new(Error)("Error parsing " + that.path); } that.root = root; }); } }; // // The actual import node doesn't return anything, when converted to CSS. // The reason is that it's used at the evaluation stage, so that the rules // it imports can be treated like any other rules. // // In `eval`, we make sure all Import nodes get evaluated, recursively, so // we end up with a flat structure, which can easily be imported in the parent // ruleset. // tree.Import.prototype = { toCSS: function () { if (this.css) { return "@import " + this._path.toCSS() + ';\n'; } else { return ""; } }, eval: function (env) { var ruleset; if (this.css) { return this; } else { ruleset = new(tree.Ruleset)(null, this.root.rules.slice(0)); for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.Import) { Array.prototype .splice .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env))); } } return ruleset.rules; } } }; })(require('less/tree')); (function (tree) { tree.JavaScript = function (string, index, escaped) { this.escaped = escaped; this.expression = string; this.index = index; }; tree.JavaScript.prototype = { eval: function (env) { var result, that = this, context = {}; var expression = this.expression.replace(/@\{([\w-]+)\}/g, function (_, name) { return tree.jsify(new(tree.Variable)('@' + name, that.index).eval(env)); }); try { expression = new(Function)('return (' + expression + ')'); } catch (e) { throw { message: "JavaScript evaluation error: `" + expression + "`" , index: this.index }; } for (var k in env.frames[0].variables()) { context[k.slice(1)] = { value: env.frames[0].variables()[k].value, toJS: function () { return this.value.eval(env).toCSS(); } }; } try { result = expression.call(context); } catch (e) { throw { message: "JavaScript evaluation error: '" + e.name + ': ' + e.message + "'" , index: this.index }; } if (typeof(result) === 'string') { return new(tree.Quoted)('"' + result + '"', result, this.escaped, this.index); } else if (Array.isArray(result)) { return new(tree.Anonymous)(result.join(', ')); } else { return new(tree.Anonymous)(result); } } }; })(require('less/tree')); (function (tree) { tree.Keyword = function (value) { this.value = value }; tree.Keyword.prototype = { eval: function () { return this }, toCSS: function () { return this.value } }; })(require('less/tree')); (function (tree) { tree.mixin = {}; tree.mixin.Call = function (elements, args, index) { this.selector = new(tree.Selector)(elements); this.arguments = args; this.index = index; }; tree.mixin.Call.prototype = { eval: function (env) { var mixins, rules = [], match = false; for (var i = 0; i < env.frames.length; i++) { if ((mixins = env.frames[i].find(this.selector)).length > 0) { for (var m = 0; m < mixins.length; m++) { if (mixins[m].match(this.arguments, env)) { try { Array.prototype.push.apply( rules, mixins[m].eval(env, this.arguments).rules); match = true; } catch (e) { throw { message: e.message, index: e.index, stack: e.stack, call: this.index }; } } } if (match) { return rules; } else { throw { message: 'No matching definition was found for `' + this.selector.toCSS().trim() + '(' + this.arguments.map(function (a) { return a.toCSS(); }).join(', ') + ")`", index: this.index }; } } } throw { message: this.selector.toCSS().trim() + " is undefined", index: this.index }; } }; tree.mixin.Definition = function (name, params, rules) { this.name = name; this.selectors = [new(tree.Selector)([new(tree.Element)(null, name)])]; this.params = params; this.arity = params.length; this.rules = rules; this._lookups = {}; this.required = params.reduce(function (count, p) { if (!p.name || (p.name && !p.value)) { return count + 1 } else { return count } }, 0); this.parent = tree.Ruleset.prototype; this.frames = []; }; tree.mixin.Definition.prototype = { toCSS: function () { return "" }, variable: function (name) { return this.parent.variable.call(this, name) }, variables: function () { return this.parent.variables.call(this) }, find: function () { return this.parent.find.apply(this, arguments) }, rulesets: function () { return this.parent.rulesets.apply(this) }, eval: function (env, args) { var frame = new(tree.Ruleset)(null, []), context, _arguments = []; for (var i = 0, val; i < this.params.length; i++) { if (this.params[i].name) { if (val = (args && args[i]) || this.params[i].value) { frame.rules.unshift(new(tree.Rule)(this.params[i].name, val.eval(env))); } else { throw { message: "wrong number of arguments for " + this.name + ' (' + args.length + ' for ' + this.arity + ')' }; } } } for (var i = 0; i < Math.max(this.params.length, args && args.length); i++) { _arguments.push(args[i] || this.params[i].value); } frame.rules.unshift(new(tree.Rule)('@arguments', new(tree.Expression)(_arguments).eval(env))); return new(tree.Ruleset)(null, this.rules.slice(0)).eval({ frames: [this, frame].concat(this.frames, env.frames) }); }, match: function (args, env) { var argsLength = (args && args.length) || 0, len; if (argsLength < this.required) { return false } if ((this.required > 0) && (argsLength > this.params.length)) { return false } len = Math.min(argsLength, this.arity); for (var i = 0; i < len; i++) { if (!this.params[i].name) { if (args[i].eval(env).toCSS() != this.params[i].value.eval(env).toCSS()) { return false; } } } return true; } }; })(require('less/tree')); (function (tree) { tree.Operation = function (op, operands) { this.op = op.trim(); this.operands = operands; }; tree.Operation.prototype.eval = function (env) { var a = this.operands[0].eval(env), b = this.operands[1].eval(env), temp; if (a instanceof tree.Dimension && b instanceof tree.Color) { if (this.op === '*' || this.op === '+') { temp = b, b = a, a = temp; } else { throw { name: "OperationError", message: "Can't substract or divide a color from a number" }; } } return a.operate(this.op, b); }; tree.operate = function (op, a, b) { switch (op) { case '+': return a + b; case '-': return a - b; case '*': return a * b; case '/': return a / b; } }; })(require('less/tree')); (function (tree) { tree.Quoted = function (str, content, escaped, i) { this.escaped = escaped; this.value = content || ''; this.quote = str.charAt(0); this.index = i; }; tree.Quoted.prototype = { toCSS: function () { if (this.escaped) { return this.value; } else { return this.quote + this.value + this.quote; } }, eval: function (env) { var that = this; this.value = this.value.replace(/`([^`]+)`/g, function (_, exp) { return new(tree.JavaScript)(exp, that.index, true).eval(env).value; }).replace(/@\{([\w-]+)\}/g, function (_, name) { return new(tree.Variable)('@' + name, that.index).eval(env).value; }); return this; } }; })(require('less/tree')); (function (tree) { tree.Rule = function (name, value, important, index) { this.name = name; this.value = (value instanceof tree.Value) ? value : new(tree.Value)([value]); this.important = important ? ' ' + important.trim() : ''; this.index = index; if (name.charAt(0) === '@') { this.variable = true; } else { this.variable = false } }; tree.Rule.prototype.toCSS = function (env) { if (this.variable) { return "" } else { return this.name + (env.compress ? ':' : ': ') + this.value.toCSS(env) + this.important + ";"; } }; tree.Rule.prototype.eval = function (context) { return new(tree.Rule)(this.name, this.value.eval(context), this.important, this.index); }; tree.Shorthand = function (a, b) { this.a = a; this.b = b; }; tree.Shorthand.prototype = { toCSS: function (env) { return this.a.toCSS(env) + "/" + this.b.toCSS(env); }, eval: function () { return this } }; })(require('less/tree')); (function (tree) { tree.Ruleset = function (selectors, rules) { this.selectors = selectors; this.rules = rules; this._lookups = {}; }; tree.Ruleset.prototype = { eval: function (env) { var ruleset = new(tree.Ruleset)(this.selectors, this.rules.slice(0)); ruleset.root = this.root; // push the current ruleset to the frames stack env.frames.unshift(ruleset); // Evaluate imports if (ruleset.root) { for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.Import) { Array.prototype.splice .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env))); } } } // Store the frames around mixin definitions, // so they can be evaluated like closures when the time comes. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Definition) { ruleset.rules[i].frames = env.frames.slice(0); } } // Evaluate mixin calls. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Call) { Array.prototype.splice .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env))); } } // Evaluate everything else for (var i = 0, rule; i < ruleset.rules.length; i++) { rule = ruleset.rules[i]; if (! (rule instanceof tree.mixin.Definition)) { ruleset.rules[i] = rule.eval ? rule.eval(env) : rule; } } // Pop the stack env.frames.shift(); return ruleset; }, match: function (args) { return !args || args.length === 0; }, variables: function () { if (this._variables) { return this._variables } else { return this._variables = this.rules.reduce(function (hash, r) { if (r instanceof tree.Rule && r.variable === true) { hash[r.name] = r; } return hash; }, {}); } }, variable: function (name) { return this.variables()[name]; }, rulesets: function () { if (this._rulesets) { return this._rulesets } else { return this._rulesets = this.rules.filter(function (r) { return (r instanceof tree.Ruleset) || (r instanceof tree.mixin.Definition); }); } }, find: function (selector, self) { self = self || this; var rules = [], rule, match, key = selector.toCSS(); if (key in this._lookups) { return this._lookups[key] } this.rulesets().forEach(function (rule) { if (rule !== self) { for (var j = 0; j < rule.selectors.length; j++) { if (match = selector.match(rule.selectors[j])) { if (selector.elements.length > 1) { Array.prototype.push.apply(rules, rule.find( new(tree.Selector)(selector.elements.slice(1)), self)); } else { rules.push(rule); } break; } } } }); return this._lookups[key] = rules; }, // // Entry point for code generation // // `context` holds an array of arrays. // toCSS: function (context, env) { var css = [], // The CSS output rules = [], // node.Rule instances rulesets = [], // node.Ruleset instances paths = [], // Current selectors selector, // The fully rendered selector rule; if (! this.root) { if (context.length === 0) { paths = this.selectors.map(function (s) { return [s] }); } else { for (var s = 0; s < this.selectors.length; s++) { for (var c = 0; c < context.length; c++) { paths.push(context[c].concat([this.selectors[s]])); } } } } // Compile rules and rulesets for (var i = 0; i < this.rules.length; i++) { rule = this.rules[i]; if (rule.rules || (rule instanceof tree.Directive)) { rulesets.push(rule.toCSS(paths, env)); } else if (rule instanceof tree.Comment) { if (!rule.silent) { if (this.root) { rulesets.push(rule.toCSS(env)); } else { rules.push(rule.toCSS(env)); } } } else { if (rule.toCSS && !rule.variable) { rules.push(rule.toCSS(env)); } else if (rule.value && !rule.variable) { rules.push(rule.value.toString()); } } } rulesets = rulesets.join(''); // If this is the root node, we don't render // a selector, or {}. // Otherwise, only output if this ruleset has rules. if (this.root) { css.push(rules.join(env.compress ? '' : '\n')); } else { if (rules.length > 0) { selector = paths.map(function (p) { return p.map(function (s) { return s.toCSS(env); }).join('').trim(); }).join(env.compress ? ',' : (paths.length > 3 ? ',\n' : ', ')); css.push(selector, (env.compress ? '{' : ' {\n ') + rules.join(env.compress ? '' : '\n ') + (env.compress ? '}' : '\n}\n')); } } css.push(rulesets); return css.join('') + (env.compress ? '\n' : ''); } }; })(require('less/tree')); (function (tree) { tree.Selector = function (elements) { this.elements = elements; if (this.elements[0].combinator.value === "") { this.elements[0].combinator.value = ' '; } }; tree.Selector.prototype.match = function (other) { if (this.elements[0].value === other.elements[0].value) { return true; } else { return false; } }; tree.Selector.prototype.toCSS = function (env) { if (this._css) { return this._css } return this._css = this.elements.map(function (e) { if (typeof(e) === 'string') { return ' ' + e.trim(); } else { return e.toCSS(env); } }).join(''); }; })(require('less/tree')); (function (tree) { tree.URL = function (val, paths) { if (val.data) { this.attrs = val; } else { // Add the base path if the URL is relative and we are in the browser if (!/^(?:https?:\/|file:\/|data:\/)?\//.test(val.value) && paths.length > 0 && typeof(window) !== 'undefined') { val.value = paths[0] + (val.value.charAt(0) === '/' ? val.value.slice(1) : val.value); } this.value = val; this.paths = paths; } }; tree.URL.prototype = { toCSS: function () { return "url(" + (this.attrs ? 'data:' + this.attrs.mime + this.attrs.charset + this.attrs.base64 + this.attrs.data : this.value.toCSS()) + ")"; }, eval: function (ctx) { return this.attrs ? this : new(tree.URL)(this.value.eval(ctx), this.paths); } }; })(require('less/tree')); (function (tree) { tree.Value = function (value) { this.value = value; this.is = 'value'; }; tree.Value.prototype = { eval: function (env) { if (this.value.length === 1) { return this.value[0].eval(env); } else { return new(tree.Value)(this.value.map(function (v) { return v.eval(env); })); } }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS(env); }).join(env.compress ? ',' : ', '); } }; })(require('less/tree')); (function (tree) { tree.Variable = function (name, index) { this.name = name, this.index = index }; tree.Variable.prototype = { eval: function (env) { var variable, v, name = this.name; if (name.indexOf('@@') == 0) { name = '@' + new(tree.Variable)(name.slice(1)).eval(env).value; } if (variable = tree.find(env.frames, function (frame) { if (v = frame.variable(name)) { return v.value.eval(env); } })) { return variable } else { throw { message: "variable " + name + " is undefined", index: this.index }; } } }; })(require('less/tree')); require('less/tree').find = function (obj, fun) { for (var i = 0, r; i < obj.length; i++) { if (r = fun.call(obj, obj[i])) { return r } } return null; }; require('less/tree').jsify = function (obj) { if (Array.isArray(obj.value) && (obj.value.length > 1)) { return '[' + obj.value.map(function (v) { return v.toCSS(false) }).join(', ') + ']'; } else { return obj.toCSS(false); } }; // // browser.js - client-side engine // var isFileProtocol = (location.protocol === 'file:' || location.protocol === 'chrome:' || location.protocol === 'chrome-extension:' || location.protocol === 'resource:'); less.env = less.env || (location.hostname == '127.0.0.1' || location.hostname == '0.0.0.0' || location.hostname == 'localhost' || location.port.length > 0 || isFileProtocol ? 'development' : 'production'); // Load styles asynchronously (default: false) // // This is set to `false` by default, so that the body // doesn't start loading before the stylesheets are parsed. // Setting this to `true` can result in flickering. // less.async = false; // Interval between watch polls less.poll = less.poll || (isFileProtocol ? 1000 : 1500); // // Watch mode // less.watch = function () { return this.watchMode = true }; less.unwatch = function () { return this.watchMode = false }; if (less.env === 'development') { less.optimization = 0; if (/!watch/.test(location.hash)) { less.watch(); } less.watchTimer = setInterval(function () { if (less.watchMode) { loadStyleSheets(function (root, sheet, env) { if (root) { createCSS(root.toCSS(), sheet, env.lastModified); } }); } }, less.poll); } else { less.optimization = 3; } var cache; try { cache = (typeof(window.localStorage) === 'undefined') ? null : window.localStorage; } catch (_) { cache = null; } // // Get all tags with the 'rel' attribute set to "stylesheet/less" // var links = document.getElementsByTagName('link'); var typePattern = /^text\/(x-)?less$/; less.sheets = []; for (var i = 0; i < links.length; i++) { if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) && (links[i].type.match(typePattern)))) { less.sheets.push(links[i]); } } less.refresh = function (reload) { var startTime, endTime; startTime = endTime = new(Date); loadStyleSheets(function (root, sheet, env) { if (env.local) { log("loading " + sheet.href + " from cache."); } else { log("parsed " + sheet.href + " successfully."); createCSS(root.toCSS(), sheet, env.lastModified); } log("css for " + sheet.href + " generated in " + (new(Date) - endTime) + 'ms'); (env.remaining === 0) && log("css generated in " + (new(Date) - startTime) + 'ms'); endTime = new(Date); }, reload); loadStyles(); }; less.refreshStyles = loadStyles; less.refresh(less.env === 'development'); function loadStyles() { var styles = document.getElementsByTagName('style'); for (var i = 0; i < styles.length; i++) { if (styles[i].type.match(typePattern)) { new(less.Parser)().parse(styles[i].innerHTML || '', function (e, tree) { styles[i].type = 'text/css'; styles[i].innerHTML = tree.toCSS(); }); } } } function loadStyleSheets(callback, reload) { for (var i = 0; i < less.sheets.length; i++) { loadStyleSheet(less.sheets[i], callback, reload, less.sheets.length - (i + 1)); } } function loadStyleSheet(sheet, callback, reload, remaining) { var url = window.location.href.replace(/[#?].*$/, ''); var href = sheet.href.replace(/\?.*$/, ''); var css = cache && cache.getItem(href); var timestamp = cache && cache.getItem(href + ':timestamp'); var styles = { css: css, timestamp: timestamp }; // Stylesheets in IE don't always return the full path if (! /^(https?|file):/.test(href)) { if (href.charAt(0) == "/") { href = window.location.protocol + "//" + window.location.host + href; } else { href = url.slice(0, url.lastIndexOf('/') + 1) + href; } } xhr(sheet.href, sheet.type, function (data, lastModified) { if (!reload && styles && lastModified && (new(Date)(lastModified).valueOf() === new(Date)(styles.timestamp).valueOf())) { // Use local copy createCSS(styles.css, sheet); callback(null, sheet, { local: true, remaining: remaining }); } else { // Use remote copy (re-parse) try { new(less.Parser)({ optimization: less.optimization, paths: [href.replace(/[\w\.-]+$/, '')], mime: sheet.type }).parse(data, function (e, root) { if (e) { return error(e, href) } try { callback(root, sheet, { local: false, lastModified: lastModified, remaining: remaining }); removeNode(document.getElementById('less-error-message:' + extractId(href))); } catch (e) { error(e, href); } }); } catch (e) { error(e, href); } } }, function (status, url) { throw new(Error)("Couldn't load " + url + " (" + status + ")"); }); } function extractId(href) { return href.replace(/^[a-z]+:\/\/?[^\/]+/, '' ) // Remove protocol & domain .replace(/^\//, '' ) // Remove root / .replace(/\?.*$/, '' ) // Remove query .replace(/\.[^\.\/]+$/, '' ) // Remove file extension .replace(/[^\.\w-]+/g, '-') // Replace illegal characters .replace(/\./g, ':'); // Replace dots with colons(for valid id) } function createCSS(styles, sheet, lastModified) { var css; // Strip the query-string var href = sheet.href ? sheet.href.replace(/\?.*$/, '') : ''; // If there is no title set, use the filename, minus the extension var id = 'less:' + (sheet.title || extractId(href)); // If the stylesheet doesn't exist, create a new node if ((css = document.getElementById(id)) === null) { css = document.createElement('style'); css.type = 'text/css'; css.media = sheet.media || 'screen'; css.id = id; document.getElementsByTagName('head')[0].appendChild(css); } if (css.styleSheet) { // IE try { css.styleSheet.cssText = styles; } catch (e) { throw new(Error)("Couldn't reassign styleSheet.cssText."); } } else { (function (node) { if (css.childNodes.length > 0) { if (css.firstChild.nodeValue !== node.nodeValue) { css.replaceChild(node, css.firstChild); } } else { css.appendChild(node); } })(document.createTextNode(styles)); } // Don't update the local store if the file wasn't modified if (lastModified && cache) { log('saving ' + href + ' to cache.'); cache.setItem(href, styles); cache.setItem(href + ':timestamp', lastModified); } } function xhr(url, type, callback, errback) { var xhr = getXMLHttpRequest(); var async = isFileProtocol ? false : less.async; if (typeof(xhr.overrideMimeType) === 'function') { xhr.overrideMimeType('text/css'); } xhr.open('GET', url, async); xhr.setRequestHeader('Accept', type || 'text/x-less, text/css; q=0.9, */*; q=0.5'); xhr.send(null); if (isFileProtocol) { if (xhr.status === 0) { callback(xhr.responseText); } else { errback(xhr.status, url); } } else if (async) { xhr.onreadystatechange = function () { if (xhr.readyState == 4) { handleResponse(xhr, callback, errback); } }; } else { handleResponse(xhr, callback, errback); } function handleResponse(xhr, callback, errback) { if (xhr.status >= 200 && xhr.status < 300) { callback(xhr.responseText, xhr.getResponseHeader("Last-Modified")); } else if (typeof(errback) === 'function') { errback(xhr.status, url); } } } function getXMLHttpRequest() { if (window.XMLHttpRequest) { return new(XMLHttpRequest); } else { try { return new(ActiveXObject)("MSXML2.XMLHTTP.3.0"); } catch (e) { log("browser doesn't support AJAX."); return null; } } } function removeNode(node) { return node && node.parentNode.removeChild(node); } function log(str) { if (less.env == 'development' && typeof(console) !== "undefined") { console.log('less: ' + str) } } function error(e, href) { var id = 'less-error-message:' + extractId(href); var template = ['
    ', '
  • {0}
  • ', '
  • {current}
  • ', '
  • {2}
  • ', '
'].join('\n'); var elem = document.createElement('div'), timer, content; elem.id = id; elem.className = "less-error-message"; content = '

' + (e.message || 'There is an error in your .less file') + '

' + '

' + href + " "; if (e.extract) { content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':

' + template.replace(/\[(-?\d)\]/g, function (_, i) { return (parseInt(e.line) + parseInt(i)) || ''; }).replace(/\{(\d)\}/g, function (_, i) { return e.extract[parseInt(i)] || ''; }).replace(/\{current\}/, e.extract[1].slice(0, e.column) + '' + e.extract[1].slice(e.column) + ''); } elem.innerHTML = content; // CSS for error messages createCSS([ '.less-error-message ul, .less-error-message li {', 'list-style-type: none;', 'margin-right: 15px;', 'padding: 4px 0;', 'margin: 0;', '}', '.less-error-message label {', 'font-size: 12px;', 'margin-right: 15px;', 'padding: 4px 0;', 'color: #cc7777;', '}', '.less-error-message pre {', 'color: #ee4444;', 'padding: 4px 0;', 'margin: 0;', 'display: inline-block;', '}', '.less-error-message pre.ctx {', 'color: #dd4444;', '}', '.less-error-message h3 {', 'font-size: 20px;', 'font-weight: bold;', 'padding: 15px 0 5px 0;', 'margin: 0;', '}', '.less-error-message a {', 'color: #10a', '}', '.less-error-message .error {', 'color: red;', 'font-weight: bold;', 'padding-bottom: 2px;', 'border-bottom: 1px dashed red;', '}' ].join('\n'), { title: 'error-message' }); elem.style.cssText = [ "font-family: Arial, sans-serif", "border: 1px solid #e00", "background-color: #eee", "border-radius: 5px", "-webkit-border-radius: 5px", "-moz-border-radius: 5px", "color: #e00", "padding: 15px", "margin-bottom: 15px" ].join(';'); if (less.env == 'development') { timer = setInterval(function () { if (document.body) { if (document.getElementById(id)) { document.body.replaceChild(elem, document.getElementById(id)); } else { document.body.insertBefore(elem, document.body.firstChild); } clearInterval(timer); } }, 10); } } })(window); less.js-1.4.2/dist/less-1.1.1.min.js000066400000000000000000001032641217256642200166010ustar00rootroot00000000000000// // LESS - Leaner CSS v1.1.1 // http://lesscss.org // // Copyright (c) 2009-2011, Alexis Sellier // Licensed under the Apache 2.0 License. // // // LESS - Leaner CSS v1.1.1 // http://lesscss.org // // Copyright (c) 2009-2011, Alexis Sellier // Licensed under the Apache 2.0 License. // (function(a,b){function v(a,b){var c="less-error-message:"+p(b),e=["
    ",'
  • {0}
  • ',"
  • {current}
  • ",'
  • {2}
  • ',"
"].join("\n"),f=document.createElement("div"),g,h;f.id=c,f.className="less-error-message",h="

"+(a.message||"There is an error in your .less file")+"

"+'

'+b+" ",a.extract&&(h+="on line "+a.line+", column "+(a.column+1)+":

"+e.replace(/\[(-?\d)\]/g,function(b,c){return parseInt(a.line)+parseInt(c)||""}).replace(/\{(\d)\}/g,function(b,c){return a.extract[parseInt(c)]||""}).replace(/\{current\}/,a.extract[1].slice(0,a.column)+''+a.extract[1].slice(a.column)+"")),f.innerHTML=h,q([".less-error-message ul, .less-error-message li {","list-style-type: none;","margin-right: 15px;","padding: 4px 0;","margin: 0;","}",".less-error-message label {","font-size: 12px;","margin-right: 15px;","padding: 4px 0;","color: #cc7777;","}",".less-error-message pre {","color: #ee4444;","padding: 4px 0;","margin: 0;","display: inline-block;","}",".less-error-message pre.ctx {","color: #dd4444;","}",".less-error-message h3 {","font-size: 20px;","font-weight: bold;","padding: 15px 0 5px 0;","margin: 0;","}",".less-error-message a {","color: #10a","}",".less-error-message .error {","color: red;","font-weight: bold;","padding-bottom: 2px;","border-bottom: 1px dashed red;","}"].join("\n"),{title:"error-message"}),f.style.cssText=["font-family: Arial, sans-serif","border: 1px solid #e00","background-color: #eee","border-radius: 5px","-webkit-border-radius: 5px","-moz-border-radius: 5px","color: #e00","padding: 15px","margin-bottom: 15px"].join(";"),d.env=="development"&&(g=setInterval(function(){document.body&&(document.getElementById(c)?document.body.replaceChild(f,document.getElementById(c)):document.body.insertBefore(f,document.body.firstChild),clearInterval(g))},10))}function u(a){d.env=="development"&&typeof console!="undefined"&&console.log("less: "+a)}function t(a){return a&&a.parentNode.removeChild(a)}function s(){if(a.XMLHttpRequest)return new XMLHttpRequest;try{return new ActiveXObject("MSXML2.XMLHTTP.3.0")}catch(b){u("browser doesn't support AJAX.");return null}}function r(a,b,c,e){function i(b,c,d){b.status>=200&&b.status<300?c(b.responseText,b.getResponseHeader("Last-Modified")):typeof d=="function"&&d(b.status,a)}var f=s(),h=g?!1:d.async;typeof f.overrideMimeType=="function"&&f.overrideMimeType("text/css"),f.open("GET",a,h),f.setRequestHeader("Accept",b||"text/x-less, text/css; q=0.9, */*; q=0.5"),f.send(null),g?f.status===0?c(f.responseText):e(f.status,a):h?f.onreadystatechange=function(){f.readyState==4&&i(f,c,e)}:i(f,c,e)}function q(a,b,c){var d,e=b.href?b.href.replace(/\?.*$/,""):"",f="less:"+(b.title||p(e));(d=document.getElementById(f))===null&&(d=document.createElement("style"),d.type="text/css",d.media=b.media||"screen",d.id=f,document.getElementsByTagName("head")[0].appendChild(d));if(d.styleSheet)try{d.styleSheet.cssText=a}catch(g){throw new Error("Couldn't reassign styleSheet.cssText.")}else(function(a){d.childNodes.length>0?d.firstChild.nodeValue!==a.nodeValue&&d.replaceChild(a,d.firstChild):d.appendChild(a)})(document.createTextNode(a));c&&h&&(u("saving "+e+" to cache."),h.setItem(e,a),h.setItem(e+":timestamp",c))}function p(a){return a.replace(/^[a-z]+:\/\/?[^\/]+/,"").replace(/^\//,"").replace(/\?.*$/,"").replace(/\.[^\.\/]+$/,"").replace(/[^\.\w-]+/g,"-").replace(/\./g,":")}function o(b,c,e,f){var g=a.location.href.replace(/[#?].*$/,""),i=b.href.replace(/\?.*$/,""),j=h&&h.getItem(i),k=h&&h.getItem(i+":timestamp"),l={css:j,timestamp:k};/^(https?|file):/.test(i)||(i.charAt(0)=="/"?i=a.location.protocol+"//"+a.location.host+i:i=g.slice(0,g.lastIndexOf("/")+1)+i),r(b.href,b.type,function(a,g){if(!e&&l&&g&&(new Date(g)).valueOf()===(new Date(l.timestamp)).valueOf())q(l.css,b),c(null,b,{local:!0,remaining:f});else try{(new d.Parser({optimization:d.optimization,paths:[i.replace(/[\w\.-]+$/,"")],mime:b.type})).parse(a,function(a,d){if(a)return v(a,i);try{c(d,b,{local:!1,lastModified:g,remaining:f}),t(document.getElementById("less-error-message:"+p(i)))}catch(a){v(a,i)}})}catch(h){v(h,i)}},function(a,b){throw new Error("Couldn't load "+b+" ("+a+")")})}function n(a,b){for(var c=0;c>>0;for(var d=0;d>>0,c=Array(b),d=arguments[1];for(var e=0;e>>0,c=0;if(b===0&&arguments.length===1)throw new TypeError;if(arguments.length>=2)var d=arguments[1];else for(;;){if(c in this){d=this[c++];break}if(++c>=b)throw new TypeError}for(;c=b)return-1;c<0&&(c+=b);for(;ck&&(j[f]=j[f].slice(c-k),k=c)}function q(){j[f]=g,c=h,k=c}function p(){g=j[f],h=c,k=c}var b,c,f,g,h,i,j,k,l,m=this,n=function(){},o=this.imports={paths:a&&a.paths||[],queue:[],files:{},mime:a&&a.mime,push:function(b,c){var e=this;this.queue.push(b),d.Parser.importer(b,this.paths,function(a){e.queue.splice(e.queue.indexOf(b),1),e.files[b]=a,c(a),e.queue.length===0&&n()},a)}};this.env=a=a||{},this.optimization="optimization"in this.env?this.env.optimization:1,this.env.filename=this.env.filename||null;return l={imports:o,parse:function(d,g){var h,l,m,o,p,q,r=[],t,u=null;c=f=k=i=0,j=[],b=d.replace(/\r\n/g,"\n"),j=function(c){var d=0,e=/[^"'`\{\}\/\(\)]+/g,f=/\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g,g=0,h,i=c[0],j,k;for(var l=0,m,n;l0)throw{type:"Syntax",message:"Missing closing `}`",filename:a.filename};return c.map(function(a){return a.join("")})}([[]]),h=new e.Ruleset([],s(this.parsers.primary)),h.root=!0,h.toCSS=function(c){var d,f,g;return function(g,h){function n(a){return a?(b.slice(0,a).match(/\n/g)||"").length:null}var i=[];g=g||{},typeof h=="object"&&!Array.isArray(h)&&(h=Object.keys(h).map(function(a){var b=h[a];b instanceof e.Value||(b instanceof e.Expression||(b=new e.Expression([b])),b=new e.Value([b]));return new e.Rule("@"+a,b,!1,0)}),i=[new e.Ruleset(null,h)]);try{var j=c.call(this,{frames:i}).toCSS([],{compress:g.compress||!1})}catch(k){f=b.split("\n"),d=n(k.index);for(var l=k.index,m=-1;l>=0&&b.charAt(l)!=="\n";l--)m++;throw{type:k.type,message:k.message,filename:a.filename,index:k.index,line:typeof d=="number"?d+1:null,callLine:k.call&&n(k.call)+1,callExtract:f[n(k.call)],stack:k.stack,column:m,extract:[f[d-1],f[d],f[d+1]]}}return g.compress?j.replace(/(\s)+/g,"$1"):j}}(h.eval);if(c=0&&b.charAt(v)!=="\n";v--)w++;u={name:"ParseError",message:"Syntax Error on line "+p,index:c,filename:a.filename,line:p,column:w,extract:[q[p-2],q[p-1],q[p]]}}this.imports.queue.length>0?n=function(){g(u,h)}:g(u,h)},parsers:{primary:function(){var a,b=[];while((a=s(this.mixin.definition)||s(this.rule)||s(this.ruleset)||s(this.mixin.call)||s(this.comment)||s(this.directive))||s(/^[\s\n]+/))a&&b.push(a);return b},comment:function(){var a;if(b.charAt(c)==="/"){if(b.charAt(c+1)==="/")return new e.Comment(s(/^\/\/.*/),!0);if(a=s(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/))return new e.Comment(a)}},entities:{quoted:function(){var a,d=c,f;b.charAt(d)==="~"&&(d++,f=!0);if(b.charAt(d)==='"'||b.charAt(d)==="'"){f&&s("~");if(a=s(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/))return new e.Quoted(a[0],a[1]||a[2],f)}},keyword:function(){var a;if(a=s(/^[A-Za-z-]+/))return new e.Keyword(a)},call:function(){var a,b;if(!!(a=/^([\w-]+|%)\(/.exec(j[f]))){a=a[1].toLowerCase();if(a==="url")return null;c+=a.length;if(a==="alpha")return s(this.alpha);s("("),b=s(this.entities.arguments);if(!s(")"))return;if(a)return new e.Call(a,b)}},arguments:function(){var a=[],b;while(b=s(this.expression)){a.push(b);if(!s(","))break}return a},literal:function(){return s(this.entities.dimension)||s(this.entities.color)||s(this.entities.quoted)},url:function(){var a;if(b.charAt(c)==="u"&&!!s(/^url\(/)){a=s(this.entities.quoted)||s(this.entities.variable)||s(this.entities.dataURI)||s(/^[-\w%@$\/.&=:;#+?~]+/)||"";if(!s(")"))throw new Error("missing closing ) for url()");return new e.URL(a.value||a.data||a instanceof e.Variable?a:new e.Anonymous(a),o.paths)}},dataURI:function(){var a;if(s(/^data:/)){a={},a.mime=s(/^[^\/]+\/[^,;)]+/)||"",a.charset=s(/^;\s*charset=[^,;)]+/)||"",a.base64=s(/^;\s*base64/)||"",a.data=s(/^,\s*[^)]+/);if(a.data)return a}},variable:function(){var a,d=c;if(b.charAt(c)==="@"&&(a=s(/^@@?[\w-]+/)))return new e.Variable(a,d)},color:function(){var a;if(b.charAt(c)==="#"&&(a=s(/^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})/)))return new e.Color(a[1])},dimension:function(){var a,d=b.charCodeAt(c);if(!(d>57||d<45||d===47))if(a=s(/^(-?\d*\.?\d+)(px|%|em|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn)?/))return new e.Dimension(a[1],a[2])},javascript:function(){var a,d=c,f;b.charAt(d)==="~"&&(d++,f=!0);if(b.charAt(d)==="`"){f&&s("~");if(a=s(/^`([^`]*)`/))return new e.JavaScript(a[1],c,f)}}},variable:function(){var a;if(b.charAt(c)==="@"&&(a=s(/^(@[\w-]+)\s*:/)))return a[1]},shorthand:function(){var a,b;if(!!t(/^[@\w.%-]+\/[@\w.-]+/)&&(a=s(this.entity))&&s("/")&&(b=s(this.entity)))return new e.Shorthand(a,b)},mixin:{call:function(){var a=[],d,f,g,h=c,i=b.charAt(c);if(i==="."||i==="#"){while(d=s(/^[#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/))a.push(new e.Element(f,d)),f=s(">");s("(")&&(g=s(this.entities.arguments))&&s(")");if(a.length>0&&(s(";")||t("}")))return new e.mixin.Call(a,g,h)}},definition:function(){var a,d=[],f,g,h,i;if(!(b.charAt(c)!=="."&&b.charAt(c)!=="#"||t(/^[^{]*(;|})/)))if(f=s(/^([#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+)\s*\(/)){a=f[1];while(h=s(this.entities.variable)||s(this.entities.literal)||s(this.entities.keyword)){if(h instanceof e.Variable)if(s(":"))if(i=s(this.expression))d.push({name:h.name,value:i});else throw new Error("Expected value");else d.push({name:h.name});else d.push({value:h});if(!s(","))break}if(!s(")"))throw new Error("Expected )");g=s(this.block);if(g)return new e.mixin.Definition(a,d,g)}}},entity:function(){return s(this.entities.literal)||s(this.entities.variable)||s(this.entities.url)||s(this.entities.call)||s(this.entities.keyword)||s(this.entities.javascript)||s(this.comment)},end:function(){return s(";")||t("}")},alpha:function(){var a;if(!!s(/^opacity=/i))if(a=s(/^\d+/)||s(this.entities.variable)){if(!s(")"))throw new Error("missing closing ) for alpha()");return new e.Alpha(a)}},element:function(){var a,b,c;c=s(this.combinator),a=s(/^(?:[.#]?|:*)(?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/)||s("*")||s(this.attribute)||s(/^\([^)@]+\)/);if(a)return new e.Element(c,a)},combinator:function(){var a,d=b.charAt(c);if(d===">"||d==="&"||d==="+"||d==="~"){c++;while(b.charAt(c)===" ")c++;return new e.Combinator(d)}if(d===":"&&b.charAt(c+1)===":"){c+=2;while(b.charAt(c)===" ")c++;return new e.Combinator("::")}return b.charAt(c-1)===" "?new e.Combinator(" "):new e.Combinator(null)},selector:function(){var a,d,f=[],g,h;while(d=s(this.element)){g=b.charAt(c),f.push(d);if(g==="{"||g==="}"||g===";"||g===",")break}if(f.length>0)return new e.Selector(f)},tag:function(){return s(/^[a-zA-Z][a-zA-Z-]*[0-9]?/)||s("*")},attribute:function(){var a="",b,c,d;if(!!s("[")){if(b=s(/^[a-zA-Z-]+/)||s(this.entities.quoted))(d=s(/^[|~*$^]?=/))&&(c=s(this.entities.quoted)||s(/^[\w-]+/))?a=[b,d,c.toCSS?c.toCSS():c].join(""):a=b;if(!s("]"))return;if(a)return"["+a+"]"}},block:function(){var a;if(s("{")&&(a=s(this.primary))&&s("}"))return a},ruleset:function(){var a=[],b,d,g;p();if(g=/^([.#: \w-]+)[\s\n]*\{/.exec(j[f]))c+=g[0].length-1,a=[new e.Selector([new e.Element(null,g[1])])];else while(b=s(this.selector)){a.push(b),s(this.comment);if(!s(","))break;s(this.comment)}if(a.length>0&&(d=s(this.block)))return new e.Ruleset(a,d);i=c,q()},rule:function(){var a,d,g=b.charAt(c),k,l;p();if(g!=="."&&g!=="#"&&g!=="&")if(a=s(this.variable)||s(this.property)){a.charAt(0)!="@"&&(l=/^([^@+\/'"*`(;{}-]*);/.exec(j[f]))?(c+=l[0].length-1,d=new e.Anonymous(l[1])):a==="font"?d=s(this.font):d=s(this.value),k=s(this.important);if(d&&s(this.end))return new e.Rule(a,d,k,h);i=c,q()}},"import":function(){var a;if(s(/^@import\s+/)&&(a=s(this.entities.quoted)||s(this.entities.url))&&s(";"))return new e.Import(a,o)},directive:function(){var a,d,f,g;if(b.charAt(c)==="@"){if(d=s(this["import"]))return d;if(a=s(/^@media|@page|@-[-a-z]+/)){g=(s(/^[^{]+/)||"").trim();if(f=s(this.block))return new e.Directive(a+" "+g,f)}else if(a=s(/^@[-a-z]+/))if(a==="@font-face"){if(f=s(this.block))return new e.Directive(a,f)}else if((d=s(this.entity))&&s(";"))return new e.Directive(a,d)}},font:function(){var a=[],b=[],c,d,f,g;while(g=s(this.shorthand)||s(this.entity))b.push(g);a.push(new e.Expression(b));if(s(","))while(g=s(this.expression)){a.push(g);if(!s(","))break}return new e.Value(a)},value:function(){var a,b=[],c;while(a=s(this.expression)){b.push(a);if(!s(","))break}if(b.length>0)return new e.Value(b)},important:function(){if(b.charAt(c)==="!")return s(/^! *important/)},sub:function(){var a;if(s("(")&&(a=s(this.expression))&&s(")"))return a},multiplication:function(){var a,b,c,d;if(a=s(this.operand)){while((c=s("/")||s("*"))&&(b=s(this.operand)))d=new e.Operation(c,[d||a,b]);return d||a}},addition:function(){var a,d,f,g;if(a=s(this.multiplication)){while((f=s(/^[-+]\s+/)||b.charAt(c-1)!=" "&&(s("+")||s("-")))&&(d=s(this.multiplication)))g=new e.Operation(f,[g||a,d]);return g||a}},operand:function(){var a,d=b.charAt(c+1);b.charAt(c)==="-"&&(d==="@"||d==="(")&&(a=s("-"));var f=s(this.sub)||s(this.entities.dimension)||s(this.entities.color)||s(this.entities.variable)||s(this.entities.call);return a?new e.Operation("*",[new e.Dimension(-1),f]):f},expression:function(){var a,b,c=[],d;while(a=s(this.addition)||s(this.entity))c.push(a);if(c.length>0)return new e.Expression(c)},property:function(){var a;if(a=s(/^(\*?-?[-a-z_0-9]+)\s*:/))return a[1]}}}},typeof a!="undefined"&&(d.Parser.importer=function(a,b,c,d){a.charAt(0)!=="/"&&b.length>0&&(a=b[0]+a),o({href:a,title:a,type:d.mime},c,!0)}),function(a){function d(a){return Math.min(1,Math.max(0,a))}function c(b){if(b instanceof a.Dimension)return parseFloat(b.unit=="%"?b.value/100:b.value);if(typeof b=="number")return b;throw{error:"RuntimeError",message:"color functions take numbers as parameters"}}function b(b){return a.functions.hsla(b.h,b.s,b.l,b.a)}a.functions={rgb:function(a,b,c){return this.rgba(a,b,c,1)},rgba:function(b,d,e,f){var g=[b,d,e].map(function(a){return c(a)}),f=c(f);return new a.Color(g,f)},hsl:function(a,b,c){return this.hsla(a,b,c,1)},hsla:function(a,b,d,e){function h(a){a=a<0?a+1:a>1?a-1:a;return a*6<1?g+(f-g)*a*6:a*2<1?f:a*3<2?g+(f-g)*(2/3-a)*6:g}a=c(a)%360/360,b=c(b),d=c(d),e=c(e);var f=d<=.5?d*(b+1):d+b-d*b,g=d*2-f;return this.rgba(h(a+1/3)*255,h(a)*255,h(a-1/3)*255,e)},hue:function(b){return new a.Dimension(Math.round(b.toHSL().h))},saturation:function(b){return new a.Dimension(Math.round(b.toHSL().s*100),"%")},lightness:function(b){return new a.Dimension(Math.round(b.toHSL().l*100),"%")},alpha:function(b){return new a.Dimension(b.toHSL().a)},saturate:function(a,c){var e=a.toHSL();e.s+=c.value/100,e.s=d(e.s);return b(e)},desaturate:function(a,c){var e=a.toHSL();e.s-=c.value/100,e.s=d(e.s);return b(e)},lighten:function(a,c){var e=a.toHSL();e.l+=c.value/100,e.l=d(e.l);return b(e)},darken:function(a,c){var e=a.toHSL();e.l-=c.value/100,e.l=d(e.l);return b(e)},fadein:function(a,c){var e=a.toHSL();e.a+=c.value/100,e.a=d(e.a);return b(e)},fadeout:function(a,c){var e=a.toHSL();e.a-=c.value/100,e.a=d(e.a);return b(e)},spin:function(a,c){var d=a.toHSL(),e=(d.h+c.value)%360;d.h=e<0?360+e:e;return b(d)},mix:function(b,c,d){var e=d.value/100,f=e*2-1,g=b.toHSL().a-c.toHSL().a,h=((f*g==-1?f:(f+g)/(1+f*g))+1)/2,i=1-h,j=[b.rgb[0]*h+c.rgb[0]*i,b.rgb[1]*h+c.rgb[1]*i,b.rgb[2]*h+c.rgb[2]*i],k=b.alpha*e+c.alpha*(1-e);return new a.Color(j,k)},greyscale:function(b){return this.desaturate(b,new a.Dimension(100))},e:function(b){return new a.Anonymous(b instanceof a.JavaScript?b.evaluated:b)},escape:function(b){return new a.Anonymous(encodeURI(b.value).replace(/=/g,"%3D").replace(/:/g,"%3A").replace(/#/g,"%23").replace(/;/g,"%3B").replace(/\(/g,"%28").replace(/\)/g,"%29"))},"%":function(b){var c=Array.prototype.slice.call(arguments,1),d=b.value;for(var e=0;e255?255:a<0?0:a).toString(16);return a.length===1?"0"+a:a}).join("")},operate:function(b,c){var d=[];c instanceof a.Color||(c=c.toColor());for(var e=0;e<3;e++)d[e]=a.operate(b,this.rgb[e],c.rgb[e]);return new a.Color(d,this.alpha+c.alpha)},toHSL:function(){var a=this.rgb[0]/255,b=this.rgb[1]/255,c=this.rgb[2]/255,d=this.alpha,e=Math.max(a,b,c),f=Math.min(a,b,c),g,h,i=(e+f)/2,j=e-f;if(e===f)g=h=0;else{h=i>.5?j/(2-e-f):j/(e+f);switch(e){case a:g=(b-c)/j+(b":a.compress?">":" > "}[this.value]}}(c("less/tree")),function(a){a.Expression=function(a){this.value=a},a.Expression.prototype={eval:function(b){return this.value.length>1?new a.Expression(this.value.map(function(a){return a.eval(b)})):this.value.length===1?this.value[0].eval(b):this},toCSS:function(a){return this.value.map(function(b){return b.toCSS(a)}).join(" ")}}}(c("less/tree")),function(a){a.Import=function(b,c){var d=this;this._path=b,b instanceof a.Quoted?this.path=/\.(le?|c)ss$/.test(b.value)?b.value:b.value+".less":this.path=b.value.value||b.value,this.css=/css$/.test(this.path),this.css||c.push(this.path,function(a){if(!a)throw new Error("Error parsing "+d.path);d.root=a})},a.Import.prototype={toCSS:function(){return this.css?"@import "+this._path.toCSS()+";\n":""},eval:function(b){var c;if(this.css)return this;c=new a.Ruleset(null,this.root.rules.slice(0));for(var d=0;d0){for(var f=0;f0&&c>this.params.length)return!1;d=Math.min(c,this.arity);for(var e=0;e1?Array.prototype.push.apply(d,e.find(new a.Selector(b.elements.slice(1)),c)):d.push(e);break}});return this._lookups[g]=d},toCSS:function(b,c){var d=[],e=[],f=[],g=[],h,i;if(!this.root)if(b.length===0)g=this.selectors.map(function(a){return[a]});else for(var j=0;j0&&(h=g.map(function(a){return a.map(function(a){return a.toCSS(c)}).join("").trim()}).join(c.compress?",":g.length>3?",\n":", "),d.push(h,(c.compress?"{":" {\n ")+e.join(c.compress?"":"\n ")+(c.compress?"}":"\n}\n"))),d.push(f);return d.join("")+(c.compress?"\n":"")}}}(c("less/tree")),function(a){a.Selector=function(a){this.elements=a,this.elements[0].combinator.value===""&&(this.elements[0].combinator.value=" ")},a.Selector.prototype.match=function(a){return this.elements[0].value===a.elements[0].value?!0:!1},a.Selector.prototype.toCSS=function(a){if(this._css)return this._css;return this._css=this.elements.map(function(b){return typeof b=="string"?" "+b.trim():b.toCSS(a)}).join("")}}(c("less/tree")),function(b){b.URL=function(b,c){b.data?this.attrs=b:(!/^(?:https?:\/|file:\/|data:\/)?\//.test(b.value)&&c.length>0&&typeof a!="undefined"&&(b.value=c[0]+(b.value.charAt(0)==="/"?b.value.slice(1):b.value)),this.value=b,this.paths=c)},b.URL.prototype={toCSS:function(){return"url("+(this.attrs?"data:"+this.attrs.mime+this.attrs.charset+this.attrs.base64+this.attrs.data:this.value.toCSS())+")"},eval:function(a){return this.attrs?this:new b.URL(this.value.eval(a),this.paths)}}}(c("less/tree")),function(a){a.Value=function(a){this.value=a,this.is="value"},a.Value.prototype={eval:function(b){return this.value.length===1?this.value[0].eval(b):new a.Value(this.value.map(function(a){return a.eval(b)}))},toCSS:function(a){return this.value.map(function(b){return b.toCSS(a)}).join(a.compress?",":", ")}}}(c("less/tree")),function(a){a.Variable=function(a,b){this.name=a,this.index=b},a.Variable.prototype={eval:function(b){var c,d,e=this.name;e.indexOf("@@")==0&&(e="@"+(new a.Variable(e.slice(1))).eval(b).value);if(c=a.find(b.frames,function(a){if(d=a.variable(e))return d.value.eval(b)}))return c;throw{message:"variable "+e+" is undefined",index:this.index}}}}(c("less/tree" )),c("less/tree").find=function(a,b){for(var c=0,d;c1?"["+a.value.map(function(a){return a.toCSS(!1)}).join(", ")+"]":a.toCSS(!1)};var g=location.protocol==="file:"||location.protocol==="chrome:"||location.protocol==="chrome-extension:"||location.protocol==="resource:";d.env=d.env||(location.hostname=="127.0.0.1"||location.hostname=="0.0.0.0"||location.hostname=="localhost"||location.port.length>0||g?"development":"production"),d.async=!1,d.poll=d.poll||(g?1e3:1500),d.watch=function(){return this.watchMode=!0},d.unwatch=function(){return this.watchMode=!1},d.env==="development"?(d.optimization=0,/!watch/.test(location.hash)&&d.watch(),d.watchTimer=setInterval(function(){d.watchMode&&n(function(a,b,c){a&&q(a.toCSS(),b,c.lastModified)})},d.poll)):d.optimization=3;var h;try{h=typeof a.localStorage=="undefined"?null:a.localStorage}catch(i){h=null}var j=document.getElementsByTagName("link"),k=/^text\/(x-)?less$/;d.sheets=[];for(var l=0;l>> 0; for (var i = 0; i < len; i++) { if (i in this) { block.call(thisObject, this[i], i, this); } } }; } if (!Array.prototype.map) { Array.prototype.map = function(fun /*, thisp*/) { var len = this.length >>> 0; var res = new Array(len); var thisp = arguments[1]; for (var i = 0; i < len; i++) { if (i in this) { res[i] = fun.call(thisp, this[i], i, this); } } return res; }; } if (!Array.prototype.filter) { Array.prototype.filter = function (block /*, thisp */) { var values = []; var thisp = arguments[1]; for (var i = 0; i < this.length; i++) { if (block.call(thisp, this[i])) { values.push(this[i]); } } return values; }; } if (!Array.prototype.reduce) { Array.prototype.reduce = function(fun /*, initial*/) { var len = this.length >>> 0; var i = 0; // no value to return if no initial value and an empty array if (len === 0 && arguments.length === 1) throw new TypeError(); if (arguments.length >= 2) { var rv = arguments[1]; } else { do { if (i in this) { rv = this[i++]; break; } // if array contains no values, no initial value to return if (++i >= len) throw new TypeError(); } while (true); } for (; i < len; i++) { if (i in this) { rv = fun.call(null, rv, this[i], i, this); } } return rv; }; } if (!Array.prototype.indexOf) { Array.prototype.indexOf = function (value /*, fromIndex */ ) { var length = this.length; var i = arguments[1] || 0; if (!length) return -1; if (i >= length) return -1; if (i < 0) i += length; for (; i < length; i++) { if (!Object.prototype.hasOwnProperty.call(this, i)) { continue } if (value === this[i]) return i; } return -1; }; } // // Object // if (!Object.keys) { Object.keys = function (object) { var keys = []; for (var name in object) { if (Object.prototype.hasOwnProperty.call(object, name)) { keys.push(name); } } return keys; }; } // // String // if (!String.prototype.trim) { String.prototype.trim = function () { return String(this).replace(/^\s\s*/, '').replace(/\s\s*$/, ''); }; } var less, tree; if (typeof(window) === 'undefined') { less = exports, tree = require('less/tree'); } else { if (typeof(window.less) === 'undefined') { window.less = {} } less = window.less, tree = window.less.tree = {}; } // // less.js - parser // // A relatively straight-forward predictive parser. // There is no tokenization/lexing stage, the input is parsed // in one sweep. // // To make the parser fast enough to run in the browser, several // optimization had to be made: // // - Matching and slicing on a huge input is often cause of slowdowns. // The solution is to chunkify the input into smaller strings. // The chunks are stored in the `chunks` var, // `j` holds the current chunk index, and `current` holds // the index of the current chunk in relation to `input`. // This gives us an almost 4x speed-up. // // - In many cases, we don't need to match individual tokens; // for example, if a value doesn't hold any variables, operations // or dynamic references, the parser can effectively 'skip' it, // treating it as a literal. // An example would be '1px solid #000' - which evaluates to itself, // we don't need to know what the individual components are. // The drawback, of course is that you don't get the benefits of // syntax-checking on the CSS. This gives us a 50% speed-up in the parser, // and a smaller speed-up in the code-gen. // // // Token matching is done with the `$` function, which either takes // a terminal string or regexp, or a non-terminal function to call. // It also takes care of moving all the indices forwards. // // less.Parser = function Parser(env) { var input, // LeSS input string i, // current index in `input` j, // current chunk temp, // temporarily holds a chunk's state, for backtracking memo, // temporarily holds `i`, when backtracking furthest, // furthest index the parser has gone to chunks, // chunkified input current, // index of current chunk, in `input` parser; var that = this; // This function is called after all files // have been imported through `@import`. var finish = function () {}; var imports = this.imports = { paths: env && env.paths || [], // Search paths, when importing queue: [], // Files which haven't been imported yet files: {}, // Holds the imported parse trees mime: env && env.mime, // MIME type of .less files push: function (path, callback) { var that = this; this.queue.push(path); // // Import a file asynchronously // less.Parser.importer(path, this.paths, function (root) { that.queue.splice(that.queue.indexOf(path), 1); // Remove the path from the queue that.files[path] = root; // Store the root callback(root); if (that.queue.length === 0) { finish() } // Call `finish` if we're done importing }, env); } }; function save() { temp = chunks[j], memo = i, current = i } function restore() { chunks[j] = temp, i = memo, current = i } function sync() { if (i > current) { chunks[j] = chunks[j].slice(i - current); current = i; } } // // Parse from a token, regexp or string, and move forward if match // function $(tok) { var match, args, length, c, index, endIndex, k, mem; // // Non-terminal // if (tok instanceof Function) { return tok.call(parser.parsers); // // Terminal // // Either match a single character in the input, // or match a regexp in the current chunk (chunk[j]). // } else if (typeof(tok) === 'string') { match = input.charAt(i) === tok ? tok : null; length = 1; sync (); } else { sync (); if (match = tok.exec(chunks[j])) { length = match[0].length; } else { return null; } } // The match is confirmed, add the match length to `i`, // and consume any extra white-space characters (' ' || '\n') // which come after that. The reason for this is that LeSS's // grammar is mostly white-space insensitive. // if (match) { mem = i += length; endIndex = i + chunks[j].length - length; while (i < endIndex) { c = input.charCodeAt(i); if (! (c === 32 || c === 10 || c === 9)) { break } i++; } chunks[j] = chunks[j].slice(length + (i - mem)); current = i; if (chunks[j].length === 0 && j < chunks.length - 1) { j++ } if(typeof(match) === 'string') { return match; } else { return match.length === 1 ? match[0] : match; } } } // Same as $(), but don't change the state of the parser, // just return the match. function peek(tok) { if (typeof(tok) === 'string') { return input.charAt(i) === tok; } else { if (tok.test(chunks[j])) { return true; } else { return false; } } } this.env = env = env || {}; // The optimization level dictates the thoroughness of the parser, // the lower the number, the less nodes it will create in the tree. // This could matter for debugging, or if you want to access // the individual nodes in the tree. this.optimization = ('optimization' in this.env) ? this.env.optimization : 1; this.env.filename = this.env.filename || null; // // The Parser // return parser = { imports: imports, // // Parse an input string into an abstract syntax tree, // call `callback` when done. // parse: function (str, callback) { var root, start, end, zone, line, lines, buff = [], c, error = null; i = j = current = furthest = 0; chunks = []; input = str.replace(/\r\n/g, '\n'); // Split the input into chunks. chunks = (function (chunks) { var j = 0, skip = /[^"'`\{\}\/\(\)]+/g, comment = /\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g, level = 0, match, chunk = chunks[0], inParam, inString; for (var i = 0, c, cc; i < input.length; i++) { skip.lastIndex = i; if (match = skip.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); } } c = input.charAt(i); comment.lastIndex = i; if (!inString && !inParam && c === '/') { cc = input.charAt(i + 1); if (cc === '/' || cc === '*') { if (match = comment.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); c = input.charAt(i); } } } } if (c === '{' && !inString && !inParam) { level ++; chunk.push(c); } else if (c === '}' && !inString && !inParam) { level --; chunk.push(c); chunks[++j] = chunk = []; } else if (c === '(' && !inString && !inParam) { chunk.push(c); inParam = true; } else if (c === ')' && !inString && inParam) { chunk.push(c); inParam = false; } else { if (c === '"' || c === "'" || c === '`') { if (! inString) { inString = c; } else { inString = inString === c ? false : inString; } } chunk.push(c); } } if (level > 0) { throw { type: 'Syntax', message: "Missing closing `}`", filename: env.filename }; } return chunks.map(function (c) { return c.join('') });; })([[]]); // Start with the primary rule. // The whole syntax tree is held under a Ruleset node, // with the `root` property set to true, so no `{}` are // output. The callback is called when the input is parsed. root = new(tree.Ruleset)([], $(this.parsers.primary)); root.root = true; root.toCSS = (function (evaluate) { var line, lines, column; return function (options, variables) { var frames = []; options = options || {}; // // Allows setting variables with a hash, so: // // `{ color: new(tree.Color)('#f01') }` will become: // // new(tree.Rule)('@color', // new(tree.Value)([ // new(tree.Expression)([ // new(tree.Color)('#f01') // ]) // ]) // ) // if (typeof(variables) === 'object' && !Array.isArray(variables)) { variables = Object.keys(variables).map(function (k) { var value = variables[k]; if (! (value instanceof tree.Value)) { if (! (value instanceof tree.Expression)) { value = new(tree.Expression)([value]); } value = new(tree.Value)([value]); } return new(tree.Rule)('@' + k, value, false, 0); }); frames = [new(tree.Ruleset)(null, variables)]; } try { var css = evaluate.call(this, { frames: frames }) .toCSS([], { compress: options.compress || false }); } catch (e) { lines = input.split('\n'); line = getLine(e.index); for (var n = e.index, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } throw { type: e.type, message: e.message, filename: env.filename, index: e.index, line: typeof(line) === 'number' ? line + 1 : null, callLine: e.call && (getLine(e.call) + 1), callExtract: lines[getLine(e.call)], stack: e.stack, column: column, extract: [ lines[line - 1], lines[line], lines[line + 1] ] }; } if (options.compress) { return css.replace(/(\s)+/g, "$1"); } else { return css; } function getLine(index) { return index ? (input.slice(0, index).match(/\n/g) || "").length : null; } }; })(root.eval); // If `i` is smaller than the `input.length - 1`, // it means the parser wasn't able to parse the whole // string, so we've got a parsing error. // // We try to extract a \n delimited string, // showing the line where the parse error occured. // We split it up into two parts (the part which parsed, // and the part which didn't), so we can color them differently. if (i < input.length - 1) { i = furthest; lines = input.split('\n'); line = (input.slice(0, i).match(/\n/g) || "").length + 1; for (var n = i, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } error = { name: "ParseError", message: "Syntax Error on line " + line, index: i, filename: env.filename, line: line, column: column, extract: [ lines[line - 2], lines[line - 1], lines[line] ] }; } if (this.imports.queue.length > 0) { finish = function () { callback(error, root) }; } else { callback(error, root); } }, // // Here in, the parsing rules/functions // // The basic structure of the syntax tree generated is as follows: // // Ruleset -> Rule -> Value -> Expression -> Entity // // Here's some LESS code: // // .class { // color: #fff; // border: 1px solid #000; // width: @w + 4px; // > .child {...} // } // // And here's what the parse tree might look like: // // Ruleset (Selector '.class', [ // Rule ("color", Value ([Expression [Color #fff]])) // Rule ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]])) // Rule ("width", Value ([Expression [Operation "+" [Variable "@w"][Dimension 4px]]])) // Ruleset (Selector [Element '>', '.child'], [...]) // ]) // // In general, most rules will try to parse a token with the `$()` function, and if the return // value is truly, will return a new node, of the relevant type. Sometimes, we need to check // first, before parsing, that's when we use `peek()`. // parsers: { // // The `primary` rule is the *entry* and *exit* point of the parser. // The rules here can appear at any level of the parse tree. // // The recursive nature of the grammar is an interplay between the `block` // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule, // as represented by this simplified grammar: // // primary → (ruleset | rule)+ // ruleset → selector+ block // block → '{' primary '}' // // Only at one point is the primary rule not called from the // block rule: at the root level. // primary: function () { var node, root = []; while ((node = $(this.mixin.definition) || $(this.rule) || $(this.ruleset) || $(this.mixin.call) || $(this.comment) || $(this.directive)) || $(/^[\s\n]+/)) { node && root.push(node); } return root; }, // We create a Comment node for CSS comments `/* */`, // but keep the LeSS comments `//` silent, by just skipping // over them. comment: function () { var comment; if (input.charAt(i) !== '/') return; if (input.charAt(i + 1) === '/') { return new(tree.Comment)($(/^\/\/.*/), true); } else if (comment = $(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/)) { return new(tree.Comment)(comment); } }, // // Entities are tokens which can be found inside an Expression // entities: { // // A string, which supports escaping " and ' // // "milky way" 'he\'s the one!' // quoted: function () { var str, j = i, e; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '"' && input.charAt(j) !== "'") return; e && $('~'); if (str = $(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/)) { return new(tree.Quoted)(str[0], str[1] || str[2], e); } }, // // A catch-all word, such as: // // black border-collapse // keyword: function () { var k; if (k = $(/^[A-Za-z-]+/)) { return new(tree.Keyword)(k) } }, // // A function call // // rgb(255, 0, 255) // // We also try to catch IE's `alpha()`, but let the `alpha` parser // deal with the details. // // The arguments are parsed with the `entities.arguments` parser. // call: function () { var name, args; if (! (name = /^([\w-]+|%)\(/.exec(chunks[j]))) return; name = name[1].toLowerCase(); if (name === 'url') { return null } else { i += name.length } if (name === 'alpha') { return $(this.alpha) } $('('); // Parse the '(' and consume whitespace. args = $(this.entities.arguments); if (! $(')')) return; if (name) { return new(tree.Call)(name, args) } }, arguments: function () { var args = [], arg; while (arg = $(this.expression)) { args.push(arg); if (! $(',')) { break } } return args; }, literal: function () { return $(this.entities.dimension) || $(this.entities.color) || $(this.entities.quoted); }, // // Parse url() tokens // // We use a specific rule for urls, because they don't really behave like // standard function calls. The difference is that the argument doesn't have // to be enclosed within a string, so it can't be parsed as an Expression. // url: function () { var value; if (input.charAt(i) !== 'u' || !$(/^url\(/)) return; value = $(this.entities.quoted) || $(this.entities.variable) || $(this.entities.dataURI) || $(/^[-\w%@$\/.&=:;#+?~]+/) || ""; if (! $(')')) throw new(Error)("missing closing ) for url()"); return new(tree.URL)((value.value || value.data || value instanceof tree.Variable) ? value : new(tree.Anonymous)(value), imports.paths); }, dataURI: function () { var obj; if ($(/^data:/)) { obj = {}; obj.mime = $(/^[^\/]+\/[^,;)]+/) || ''; obj.charset = $(/^;\s*charset=[^,;)]+/) || ''; obj.base64 = $(/^;\s*base64/) || ''; obj.data = $(/^,\s*[^)]+/); if (obj.data) { return obj } } }, // // A Variable entity, such as `@fink`, in // // width: @fink + 2px // // We use a different parser for variable definitions, // see `parsers.variable`. // variable: function () { var name, index = i; if (input.charAt(i) === '@' && (name = $(/^@@?[\w-]+/))) { return new(tree.Variable)(name, index); } }, // // A Hexadecimal color // // #4F3C2F // // `rgb` and `hsl` colors are parsed through the `entities.call` parser. // color: function () { var rgb; if (input.charAt(i) === '#' && (rgb = $(/^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})/))) { return new(tree.Color)(rgb[1]); } }, // // A Dimension, that is, a number and a unit // // 0.5em 95% // dimension: function () { var value, c = input.charCodeAt(i); if ((c > 57 || c < 45) || c === 47) return; if (value = $(/^(-?\d*\.?\d+)(px|%|em|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn)?/)) { return new(tree.Dimension)(value[1], value[2]); } }, // // JavaScript code to be evaluated // // `window.location.href` // javascript: function () { var str, j = i, e; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '`') { return } e && $('~'); if (str = $(/^`([^`]*)`/)) { return new(tree.JavaScript)(str[1], i, e); } } }, // // The variable part of a variable definition. Used in the `rule` parser // // @fink: // variable: function () { var name; if (input.charAt(i) === '@' && (name = $(/^(@[\w-]+)\s*:/))) { return name[1] } }, // // A font size/line-height shorthand // // small/12px // // We need to peek first, or we'll match on keywords and dimensions // shorthand: function () { var a, b; if (! peek(/^[@\w.%-]+\/[@\w.-]+/)) return; if ((a = $(this.entity)) && $('/') && (b = $(this.entity))) { return new(tree.Shorthand)(a, b); } }, // // Mixins // mixin: { // // A Mixin call, with an optional argument list // // #mixins > .square(#fff); // .rounded(4px, black); // .button; // // The `while` loop is there because mixins can be // namespaced, but we only support the child and descendant // selector for now. // call: function () { var elements = [], e, c, args, index = i, s = input.charAt(i); if (s !== '.' && s !== '#') { return } while (e = $(/^[#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/)) { elements.push(new(tree.Element)(c, e)); c = $('>'); } $('(') && (args = $(this.entities.arguments)) && $(')'); if (elements.length > 0 && ($(';') || peek('}'))) { return new(tree.mixin.Call)(elements, args, index); } }, // // A Mixin definition, with a list of parameters // // .rounded (@radius: 2px, @color) { // ... // } // // Until we have a finer grained state-machine, we have to // do a look-ahead, to make sure we don't have a mixin call. // See the `rule` function for more information. // // We start by matching `.rounded (`, and then proceed on to // the argument list, which has optional default values. // We store the parameters in `params`, with a `value` key, // if there is a value, such as in the case of `@radius`. // // Once we've got our params list, and a closing `)`, we parse // the `{...}` block. // definition: function () { var name, params = [], match, ruleset, param, value; if ((input.charAt(i) !== '.' && input.charAt(i) !== '#') || peek(/^[^{]*(;|})/)) return; if (match = $(/^([#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+)\s*\(/)) { name = match[1]; while (param = $(this.entities.variable) || $(this.entities.literal) || $(this.entities.keyword)) { // Variable if (param instanceof tree.Variable) { if ($(':')) { if (value = $(this.expression)) { params.push({ name: param.name, value: value }); } else { throw new(Error)("Expected value"); } } else { params.push({ name: param.name }); } } else { params.push({ value: param }); } if (! $(',')) { break } } if (! $(')')) throw new(Error)("Expected )"); ruleset = $(this.block); if (ruleset) { return new(tree.mixin.Definition)(name, params, ruleset); } } } }, // // Entities are the smallest recognized token, // and can be found inside a rule's value. // entity: function () { return $(this.entities.literal) || $(this.entities.variable) || $(this.entities.url) || $(this.entities.call) || $(this.entities.keyword) || $(this.entities.javascript) || $(this.comment); }, // // A Rule terminator. Note that we use `peek()` to check for '}', // because the `block` rule will be expecting it, but we still need to make sure // it's there, if ';' was ommitted. // end: function () { return $(';') || peek('}'); }, // // IE's alpha function // // alpha(opacity=88) // alpha: function () { var value; if (! $(/^opacity=/i)) return; if (value = $(/^\d+/) || $(this.entities.variable)) { if (! $(')')) throw new(Error)("missing closing ) for alpha()"); return new(tree.Alpha)(value); } }, // // A Selector Element // // div // + h1 // #socks // input[type="text"] // // Elements are the building blocks for Selectors, // they are made out of a `Combinator` (see combinator rule), // and an element name, such as a tag a class, or `*`. // element: function () { var e, t, c; c = $(this.combinator); e = $(/^(?:[.#]?|:*)(?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/) || $('*') || $(this.attribute) || $(/^\([^)@]+\)/); if (e) { return new(tree.Element)(c, e) } }, // // Combinators combine elements together, in a Selector. // // Because our parser isn't white-space sensitive, special care // has to be taken, when parsing the descendant combinator, ` `, // as it's an empty space. We have to check the previous character // in the input, to see if it's a ` ` character. More info on how // we deal with this in *combinator.js*. // combinator: function () { var match, c = input.charAt(i); if (c === '>' || c === '&' || c === '+' || c === '~') { i++; while (input.charAt(i) === ' ') { i++ } return new(tree.Combinator)(c); } else if (c === ':' && input.charAt(i + 1) === ':') { i += 2; while (input.charAt(i) === ' ') { i++ } return new(tree.Combinator)('::'); } else if (input.charAt(i - 1) === ' ') { return new(tree.Combinator)(" "); } else { return new(tree.Combinator)(null); } }, // // A CSS Selector // // .class > div + h1 // li a:hover // // Selectors are made out of one or more Elements, see above. // selector: function () { var sel, e, elements = [], c, match; while (e = $(this.element)) { c = input.charAt(i); elements.push(e) if (c === '{' || c === '}' || c === ';' || c === ',') { break } } if (elements.length > 0) { return new(tree.Selector)(elements) } }, tag: function () { return $(/^[a-zA-Z][a-zA-Z-]*[0-9]?/) || $('*'); }, attribute: function () { var attr = '', key, val, op; if (! $('[')) return; if (key = $(/^[a-zA-Z-]+/) || $(this.entities.quoted)) { if ((op = $(/^[|~*$^]?=/)) && (val = $(this.entities.quoted) || $(/^[\w-]+/))) { attr = [key, op, val.toCSS ? val.toCSS() : val].join(''); } else { attr = key } } if (! $(']')) return; if (attr) { return "[" + attr + "]" } }, // // The `block` rule is used by `ruleset` and `mixin.definition`. // It's a wrapper around the `primary` rule, with added `{}`. // block: function () { var content; if ($('{') && (content = $(this.primary)) && $('}')) { return content; } }, // // div, .class, body > p {...} // ruleset: function () { var selectors = [], s, rules, match; save(); if (match = /^([.#: \w-]+)[\s\n]*\{/.exec(chunks[j])) { i += match[0].length - 1; selectors = [new(tree.Selector)([new(tree.Element)(null, match[1])])]; } else { while (s = $(this.selector)) { selectors.push(s); $(this.comment); if (! $(',')) { break } $(this.comment); } } if (selectors.length > 0 && (rules = $(this.block))) { return new(tree.Ruleset)(selectors, rules); } else { // Backtrack furthest = i; restore(); } }, rule: function () { var name, value, c = input.charAt(i), important, match; save(); if (c === '.' || c === '#' || c === '&') { return } if (name = $(this.variable) || $(this.property)) { if ((name.charAt(0) != '@') && (match = /^([^@+\/'"*`(;{}-]*);/.exec(chunks[j]))) { i += match[0].length - 1; value = new(tree.Anonymous)(match[1]); } else if (name === "font") { value = $(this.font); } else { value = $(this.value); } important = $(this.important); if (value && $(this.end)) { return new(tree.Rule)(name, value, important, memo); } else { furthest = i; restore(); } } }, // // An @import directive // // @import "lib"; // // Depending on our environemnt, importing is done differently: // In the browser, it's an XHR request, in Node, it would be a // file-system operation. The function used for importing is // stored in `import`, which we pass to the Import constructor. // "import": function () { var path; if ($(/^@import\s+/) && (path = $(this.entities.quoted) || $(this.entities.url)) && $(';')) { return new(tree.Import)(path, imports); } }, // // A CSS Directive // // @charset "utf-8"; // directive: function () { var name, value, rules, types; if (input.charAt(i) !== '@') return; if (value = $(this['import'])) { return value; } else if (name = $(/^@media|@page|@-[-a-z]+/)) { types = ($(/^[^{]+/) || '').trim(); if (rules = $(this.block)) { return new(tree.Directive)(name + " " + types, rules); } } else if (name = $(/^@[-a-z]+/)) { if (name === '@font-face') { if (rules = $(this.block)) { return new(tree.Directive)(name, rules); } } else if ((value = $(this.entity)) && $(';')) { return new(tree.Directive)(name, value); } } }, font: function () { var value = [], expression = [], weight, shorthand, font, e; while (e = $(this.shorthand) || $(this.entity)) { expression.push(e); } value.push(new(tree.Expression)(expression)); if ($(',')) { while (e = $(this.expression)) { value.push(e); if (! $(',')) { break } } } return new(tree.Value)(value); }, // // A Value is a comma-delimited list of Expressions // // font-family: Baskerville, Georgia, serif; // // In a Rule, a Value represents everything after the `:`, // and before the `;`. // value: function () { var e, expressions = [], important; while (e = $(this.expression)) { expressions.push(e); if (! $(',')) { break } } if (expressions.length > 0) { return new(tree.Value)(expressions); } }, important: function () { if (input.charAt(i) === '!') { return $(/^! *important/); } }, sub: function () { var e; if ($('(') && (e = $(this.expression)) && $(')')) { return e; } }, multiplication: function () { var m, a, op, operation; if (m = $(this.operand)) { while ((op = ($('/') || $('*'))) && (a = $(this.operand))) { operation = new(tree.Operation)(op, [operation || m, a]); } return operation || m; } }, addition: function () { var m, a, op, operation; if (m = $(this.multiplication)) { while ((op = $(/^[-+]\s+/) || (input.charAt(i - 1) != ' ' && ($('+') || $('-')))) && (a = $(this.multiplication))) { operation = new(tree.Operation)(op, [operation || m, a]); } return operation || m; } }, // // An operand is anything that can be part of an operation, // such as a Color, or a Variable // operand: function () { var negate, p = input.charAt(i + 1); if (input.charAt(i) === '-' && (p === '@' || p === '(')) { negate = $('-') } var o = $(this.sub) || $(this.entities.dimension) || $(this.entities.color) || $(this.entities.variable) || $(this.entities.call); return negate ? new(tree.Operation)('*', [new(tree.Dimension)(-1), o]) : o; }, // // Expressions either represent mathematical operations, // or white-space delimited Entities. // // 1px solid black // @var * 2 // expression: function () { var e, delim, entities = [], d; while (e = $(this.addition) || $(this.entity)) { entities.push(e); } if (entities.length > 0) { return new(tree.Expression)(entities); } }, property: function () { var name; if (name = $(/^(\*?-?[-a-z_0-9]+)\s*:/)) { return name[1]; } } } }; }; if (typeof(window) !== 'undefined') { // // Used by `@import` directives // less.Parser.importer = function (path, paths, callback, env) { if (path.charAt(0) !== '/' && paths.length > 0) { path = paths[0] + path; } // We pass `true` as 3rd argument, to force the reload of the import. // This is so we can get the syntax tree as opposed to just the CSS output, // as we need this to evaluate the current stylesheet. loadStyleSheet({ href: path, title: path, type: env.mime }, callback, true); }; } (function (tree) { tree.functions = { rgb: function (r, g, b) { return this.rgba(r, g, b, 1.0); }, rgba: function (r, g, b, a) { var rgb = [r, g, b].map(function (c) { return number(c) }), a = number(a); return new(tree.Color)(rgb, a); }, hsl: function (h, s, l) { return this.hsla(h, s, l, 1.0); }, hsla: function (h, s, l, a) { h = (number(h) % 360) / 360; s = number(s); l = number(l); a = number(a); var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s; var m1 = l * 2 - m2; return this.rgba(hue(h + 1/3) * 255, hue(h) * 255, hue(h - 1/3) * 255, a); function hue(h) { h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h); if (h * 6 < 1) return m1 + (m2 - m1) * h * 6; else if (h * 2 < 1) return m2; else if (h * 3 < 2) return m1 + (m2 - m1) * (2/3 - h) * 6; else return m1; } }, hue: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().h)); }, saturation: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().s * 100), '%'); }, lightness: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().l * 100), '%'); }, alpha: function (color) { return new(tree.Dimension)(color.toHSL().a); }, saturate: function (color, amount) { var hsl = color.toHSL(); hsl.s += amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, desaturate: function (color, amount) { var hsl = color.toHSL(); hsl.s -= amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, lighten: function (color, amount) { var hsl = color.toHSL(); hsl.l += amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, darken: function (color, amount) { var hsl = color.toHSL(); hsl.l -= amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, fadein: function (color, amount) { var hsl = color.toHSL(); hsl.a += amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, fadeout: function (color, amount) { var hsl = color.toHSL(); hsl.a -= amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, spin: function (color, amount) { var hsl = color.toHSL(); var hue = (hsl.h + amount.value) % 360; hsl.h = hue < 0 ? 360 + hue : hue; return hsla(hsl); }, // // Copyright (c) 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein // http://sass-lang.com // mix: function (color1, color2, weight) { var p = weight.value / 100.0; var w = p * 2 - 1; var a = color1.toHSL().a - color2.toHSL().a; var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0; var w2 = 1 - w1; var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2, color1.rgb[1] * w1 + color2.rgb[1] * w2, color1.rgb[2] * w1 + color2.rgb[2] * w2]; var alpha = color1.alpha * p + color2.alpha * (1 - p); return new(tree.Color)(rgb, alpha); }, greyscale: function (color) { return this.desaturate(color, new(tree.Dimension)(100)); }, e: function (str) { return new(tree.Anonymous)(str instanceof tree.JavaScript ? str.evaluated : str); }, escape: function (str) { return new(tree.Anonymous)(encodeURI(str.value).replace(/=/g, "%3D").replace(/:/g, "%3A").replace(/#/g, "%23").replace(/;/g, "%3B").replace(/\(/g, "%28").replace(/\)/g, "%29")); }, '%': function (quoted /* arg, arg, ...*/) { var args = Array.prototype.slice.call(arguments, 1), str = quoted.value; for (var i = 0; i < args.length; i++) { str = str.replace(/%[sda]/i, function(token) { var value = token.match(/s/i) ? args[i].value : args[i].toCSS(); return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value; }); } str = str.replace(/%%/g, '%'); return new(tree.Quoted)('"' + str + '"', str); }, round: function (n) { if (n instanceof tree.Dimension) { return new(tree.Dimension)(Math.round(number(n)), n.unit); } else if (typeof(n) === 'number') { return Math.round(n); } else { throw { error: "RuntimeError", message: "math functions take numbers as parameters" }; } } }; function hsla(hsla) { return tree.functions.hsla(hsla.h, hsla.s, hsla.l, hsla.a); } function number(n) { if (n instanceof tree.Dimension) { return parseFloat(n.unit == '%' ? n.value / 100 : n.value); } else if (typeof(n) === 'number') { return n; } else { throw { error: "RuntimeError", message: "color functions take numbers as parameters" }; } } function clamp(val) { return Math.min(1, Math.max(0, val)); } })(require('less/tree')); (function (tree) { tree.Alpha = function (val) { this.value = val; }; tree.Alpha.prototype = { toCSS: function () { return "alpha(opacity=" + (this.value.toCSS ? this.value.toCSS() : this.value) + ")"; }, eval: function () { return this } }; })(require('less/tree')); (function (tree) { tree.Anonymous = function (string) { this.value = string.value || string; }; tree.Anonymous.prototype = { toCSS: function () { return this.value; }, eval: function () { return this } }; })(require('less/tree')); (function (tree) { // // A function call node. // tree.Call = function (name, args) { this.name = name; this.args = args; }; tree.Call.prototype = { // // When evaluating a function call, // we either find the function in `tree.functions` [1], // in which case we call it, passing the evaluated arguments, // or we simply print it out as it appeared originally [2]. // // The *functions.js* file contains the built-in functions. // // The reason why we evaluate the arguments, is in the case where // we try to pass a variable to a function, like: `saturate(@color)`. // The function should receive the value, not the variable. // eval: function (env) { var args = this.args.map(function (a) { return a.eval(env) }); if (this.name in tree.functions) { // 1. return tree.functions[this.name].apply(tree.functions, args); } else { // 2. return new(tree.Anonymous)(this.name + "(" + args.map(function (a) { return a.toCSS() }).join(', ') + ")"); } }, toCSS: function (env) { return this.eval(env).toCSS(); } }; })(require('less/tree')); (function (tree) { // // RGB Colors - #ff0014, #eee // tree.Color = function (rgb, a) { // // The end goal here, is to parse the arguments // into an integer triplet, such as `128, 255, 0` // // This facilitates operations and conversions. // if (Array.isArray(rgb)) { this.rgb = rgb; } else if (rgb.length == 6) { this.rgb = rgb.match(/.{2}/g).map(function (c) { return parseInt(c, 16); }); } else if (rgb.length == 8) { this.alpha = parseInt(rgb.substring(0,2), 16) / 255.0; this.rgb = rgb.substr(2).match(/.{2}/g).map(function (c) { return parseInt(c, 16); }); } else { this.rgb = rgb.split('').map(function (c) { return parseInt(c + c, 16); }); } this.alpha = typeof(a) === 'number' ? a : 1; }; tree.Color.prototype = { eval: function () { return this }, // // If we have some transparency, the only way to represent it // is via `rgba`. Otherwise, we use the hex representation, // which has better compatibility with older browsers. // Values are capped between `0` and `255`, rounded and zero-padded. // toCSS: function () { if (this.alpha < 1.0) { return "rgba(" + this.rgb.map(function (c) { return Math.round(c); }).concat(this.alpha).join(', ') + ")"; } else { return '#' + this.rgb.map(function (i) { i = Math.round(i); i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16); return i.length === 1 ? '0' + i : i; }).join(''); } }, // // Operations have to be done per-channel, if not, // channels will spill onto each other. Once we have // our result, in the form of an integer triplet, // we create a new Color node to hold the result. // operate: function (op, other) { var result = []; if (! (other instanceof tree.Color)) { other = other.toColor(); } for (var c = 0; c < 3; c++) { result[c] = tree.operate(op, this.rgb[c], other.rgb[c]); } return new(tree.Color)(result, this.alpha + other.alpha); }, toHSL: function () { var r = this.rgb[0] / 255, g = this.rgb[1] / 255, b = this.rgb[2] / 255, a = this.alpha; var max = Math.max(r, g, b), min = Math.min(r, g, b); var h, s, l = (max + min) / 2, d = max - min; if (max === min) { h = s = 0; } else { s = l > 0.5 ? d / (2 - max - min) : d / (max + min); switch (max) { case r: h = (g - b) / d + (g < b ? 6 : 0); break; case g: h = (b - r) / d + 2; break; case b: h = (r - g) / d + 4; break; } h /= 6; } return { h: h * 360, s: s, l: l, a: a }; } }; })(require('less/tree')); (function (tree) { tree.Comment = function (value, silent) { this.value = value; this.silent = !!silent; }; tree.Comment.prototype = { toCSS: function (env) { return env.compress ? '' : this.value; }, eval: function () { return this } }; })(require('less/tree')); (function (tree) { // // A number with a unit // tree.Dimension = function (value, unit) { this.value = parseFloat(value); this.unit = unit || null; }; tree.Dimension.prototype = { eval: function () { return this }, toColor: function () { return new(tree.Color)([this.value, this.value, this.value]); }, toCSS: function () { var css = this.value + this.unit; return css; }, // In an operation between two Dimensions, // we default to the first Dimension's unit, // so `1px + 2em` will yield `3px`. // In the future, we could implement some unit // conversions such that `100cm + 10mm` would yield // `101cm`. operate: function (op, other) { return new(tree.Dimension) (tree.operate(op, this.value, other.value), this.unit || other.unit); } }; })(require('less/tree')); (function (tree) { tree.Directive = function (name, value) { this.name = name; if (Array.isArray(value)) { this.ruleset = new(tree.Ruleset)([], value); } else { this.value = value; } }; tree.Directive.prototype = { toCSS: function (ctx, env) { if (this.ruleset) { this.ruleset.root = true; return this.name + (env.compress ? '{' : ' {\n ') + this.ruleset.toCSS(ctx, env).trim().replace(/\n/g, '\n ') + (env.compress ? '}': '\n}\n'); } else { return this.name + ' ' + this.value.toCSS() + ';\n'; } }, eval: function (env) { env.frames.unshift(this); this.ruleset = this.ruleset && this.ruleset.eval(env); env.frames.shift(); return this; }, variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) }, find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) }, rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) } }; })(require('less/tree')); (function (tree) { tree.Element = function (combinator, value) { this.combinator = combinator instanceof tree.Combinator ? combinator : new(tree.Combinator)(combinator); this.value = value.trim(); }; tree.Element.prototype.toCSS = function (env) { return this.combinator.toCSS(env || {}) + this.value; }; tree.Combinator = function (value) { if (value === ' ') { this.value = ' '; } else { this.value = value ? value.trim() : ""; } }; tree.Combinator.prototype.toCSS = function (env) { return { '' : '', ' ' : ' ', '&' : '', ':' : ' :', '::': '::', '+' : env.compress ? '+' : ' + ', '~' : env.compress ? '~' : ' ~ ', '>' : env.compress ? '>' : ' > ' }[this.value]; }; })(require('less/tree')); (function (tree) { tree.Expression = function (value) { this.value = value }; tree.Expression.prototype = { eval: function (env) { if (this.value.length > 1) { return new(tree.Expression)(this.value.map(function (e) { return e.eval(env); })); } else if (this.value.length === 1) { return this.value[0].eval(env); } else { return this; } }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS(env); }).join(' '); } }; })(require('less/tree')); (function (tree) { // // CSS @import node // // The general strategy here is that we don't want to wait // for the parsing to be completed, before we start importing // the file. That's because in the context of a browser, // most of the time will be spent waiting for the server to respond. // // On creation, we push the import path to our import queue, though // `import,push`, we also pass it a callback, which it'll call once // the file has been fetched, and parsed. // tree.Import = function (path, imports) { var that = this; this._path = path; // The '.less' extension is optional if (path instanceof tree.Quoted) { this.path = /\.(le?|c)ss$/.test(path.value) ? path.value : path.value + '.less'; } else { this.path = path.value.value || path.value; } this.css = /css$/.test(this.path); // Only pre-compile .less files if (! this.css) { imports.push(this.path, function (root) { if (! root) { throw new(Error)("Error parsing " + that.path); } that.root = root; }); } }; // // The actual import node doesn't return anything, when converted to CSS. // The reason is that it's used at the evaluation stage, so that the rules // it imports can be treated like any other rules. // // In `eval`, we make sure all Import nodes get evaluated, recursively, so // we end up with a flat structure, which can easily be imported in the parent // ruleset. // tree.Import.prototype = { toCSS: function () { if (this.css) { return "@import " + this._path.toCSS() + ';\n'; } else { return ""; } }, eval: function (env) { var ruleset; if (this.css) { return this; } else { ruleset = new(tree.Ruleset)(null, this.root.rules.slice(0)); for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.Import) { Array.prototype .splice .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env))); } } return ruleset.rules; } } }; })(require('less/tree')); (function (tree) { tree.JavaScript = function (string, index, escaped) { this.escaped = escaped; this.expression = string; this.index = index; }; tree.JavaScript.prototype = { eval: function (env) { var result, that = this, context = {}; var expression = this.expression.replace(/@\{([\w-]+)\}/g, function (_, name) { return tree.jsify(new(tree.Variable)('@' + name, that.index).eval(env)); }); try { expression = new(Function)('return (' + expression + ')'); } catch (e) { throw { message: "JavaScript evaluation error: `" + expression + "`" , index: this.index }; } for (var k in env.frames[0].variables()) { context[k.slice(1)] = { value: env.frames[0].variables()[k].value, toJS: function () { return this.value.eval(env).toCSS(); } }; } try { result = expression.call(context); } catch (e) { throw { message: "JavaScript evaluation error: '" + e.name + ': ' + e.message + "'" , index: this.index }; } if (typeof(result) === 'string') { return new(tree.Quoted)('"' + result + '"', result, this.escaped, this.index); } else if (Array.isArray(result)) { return new(tree.Anonymous)(result.join(', ')); } else { return new(tree.Anonymous)(result); } } }; })(require('less/tree')); (function (tree) { tree.Keyword = function (value) { this.value = value }; tree.Keyword.prototype = { eval: function () { return this }, toCSS: function () { return this.value } }; })(require('less/tree')); (function (tree) { tree.mixin = {}; tree.mixin.Call = function (elements, args, index) { this.selector = new(tree.Selector)(elements); this.arguments = args; this.index = index; }; tree.mixin.Call.prototype = { eval: function (env) { var mixins, args, rules = [], match = false; for (var i = 0; i < env.frames.length; i++) { if ((mixins = env.frames[i].find(this.selector)).length > 0) { args = this.arguments && this.arguments.map(function (a) { return a.eval(env) }); for (var m = 0; m < mixins.length; m++) { if (mixins[m].match(args, env)) { try { Array.prototype.push.apply( rules, mixins[m].eval(env, this.arguments).rules); match = true; } catch (e) { throw { message: e.message, index: e.index, stack: e.stack, call: this.index }; } } } if (match) { return rules; } else { throw { message: 'No matching definition was found for `' + this.selector.toCSS().trim() + '(' + this.arguments.map(function (a) { return a.toCSS(); }).join(', ') + ")`", index: this.index }; } } } throw { message: this.selector.toCSS().trim() + " is undefined", index: this.index }; } }; tree.mixin.Definition = function (name, params, rules) { this.name = name; this.selectors = [new(tree.Selector)([new(tree.Element)(null, name)])]; this.params = params; this.arity = params.length; this.rules = rules; this._lookups = {}; this.required = params.reduce(function (count, p) { if (!p.name || (p.name && !p.value)) { return count + 1 } else { return count } }, 0); this.parent = tree.Ruleset.prototype; this.frames = []; }; tree.mixin.Definition.prototype = { toCSS: function () { return "" }, variable: function (name) { return this.parent.variable.call(this, name) }, variables: function () { return this.parent.variables.call(this) }, find: function () { return this.parent.find.apply(this, arguments) }, rulesets: function () { return this.parent.rulesets.apply(this) }, eval: function (env, args) { var frame = new(tree.Ruleset)(null, []), context, _arguments = []; for (var i = 0, val; i < this.params.length; i++) { if (this.params[i].name) { if (val = (args && args[i]) || this.params[i].value) { frame.rules.unshift(new(tree.Rule)(this.params[i].name, val.eval(env))); } else { throw { message: "wrong number of arguments for " + this.name + ' (' + args.length + ' for ' + this.arity + ')' }; } } } for (var i = 0; i < Math.max(this.params.length, args && args.length); i++) { _arguments.push(args[i] || this.params[i].value); } frame.rules.unshift(new(tree.Rule)('@arguments', new(tree.Expression)(_arguments).eval(env))); return new(tree.Ruleset)(null, this.rules.slice(0)).eval({ frames: [this, frame].concat(this.frames, env.frames) }); }, match: function (args, env) { var argsLength = (args && args.length) || 0, len; if (argsLength < this.required) { return false } if ((this.required > 0) && (argsLength > this.params.length)) { return false } len = Math.min(argsLength, this.arity); for (var i = 0; i < len; i++) { if (!this.params[i].name) { if (args[i].eval(env).toCSS() != this.params[i].value.eval(env).toCSS()) { return false; } } } return true; } }; })(require('less/tree')); (function (tree) { tree.Operation = function (op, operands) { this.op = op.trim(); this.operands = operands; }; tree.Operation.prototype.eval = function (env) { var a = this.operands[0].eval(env), b = this.operands[1].eval(env), temp; if (a instanceof tree.Dimension && b instanceof tree.Color) { if (this.op === '*' || this.op === '+') { temp = b, b = a, a = temp; } else { throw { name: "OperationError", message: "Can't substract or divide a color from a number" }; } } return a.operate(this.op, b); }; tree.operate = function (op, a, b) { switch (op) { case '+': return a + b; case '-': return a - b; case '*': return a * b; case '/': return a / b; } }; })(require('less/tree')); (function (tree) { tree.Quoted = function (str, content, escaped, i) { this.escaped = escaped; this.value = content || ''; this.quote = str.charAt(0); this.index = i; }; tree.Quoted.prototype = { toCSS: function () { if (this.escaped) { return this.value; } else { return this.quote + this.value + this.quote; } }, eval: function (env) { var that = this; var value = this.value.replace(/`([^`]+)`/g, function (_, exp) { return new(tree.JavaScript)(exp, that.index, true).eval(env).value; }).replace(/@\{([\w-]+)\}/g, function (_, name) { var v = new(tree.Variable)('@' + name, that.index).eval(env); return v.value || v.toCSS(); }); return new(tree.Quoted)(this.quote + value + this.quote, value, this.escaped, this.index); } }; })(require('less/tree')); (function (tree) { tree.Rule = function (name, value, important, index) { this.name = name; this.value = (value instanceof tree.Value) ? value : new(tree.Value)([value]); this.important = important ? ' ' + important.trim() : ''; this.index = index; if (name.charAt(0) === '@') { this.variable = true; } else { this.variable = false } }; tree.Rule.prototype.toCSS = function (env) { if (this.variable) { return "" } else { return this.name + (env.compress ? ':' : ': ') + this.value.toCSS(env) + this.important + ";"; } }; tree.Rule.prototype.eval = function (context) { return new(tree.Rule)(this.name, this.value.eval(context), this.important, this.index); }; tree.Shorthand = function (a, b) { this.a = a; this.b = b; }; tree.Shorthand.prototype = { toCSS: function (env) { return this.a.toCSS(env) + "/" + this.b.toCSS(env); }, eval: function () { return this } }; })(require('less/tree')); (function (tree) { tree.Ruleset = function (selectors, rules) { this.selectors = selectors; this.rules = rules; this._lookups = {}; }; tree.Ruleset.prototype = { eval: function (env) { var ruleset = new(tree.Ruleset)(this.selectors, this.rules.slice(0)); ruleset.root = this.root; // push the current ruleset to the frames stack env.frames.unshift(ruleset); // Evaluate imports if (ruleset.root) { for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.Import) { Array.prototype.splice .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env))); } } } // Store the frames around mixin definitions, // so they can be evaluated like closures when the time comes. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Definition) { ruleset.rules[i].frames = env.frames.slice(0); } } // Evaluate mixin calls. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Call) { Array.prototype.splice .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env))); } } // Evaluate everything else for (var i = 0, rule; i < ruleset.rules.length; i++) { rule = ruleset.rules[i]; if (! (rule instanceof tree.mixin.Definition)) { ruleset.rules[i] = rule.eval ? rule.eval(env) : rule; } } // Pop the stack env.frames.shift(); return ruleset; }, match: function (args) { return !args || args.length === 0; }, variables: function () { if (this._variables) { return this._variables } else { return this._variables = this.rules.reduce(function (hash, r) { if (r instanceof tree.Rule && r.variable === true) { hash[r.name] = r; } return hash; }, {}); } }, variable: function (name) { return this.variables()[name]; }, rulesets: function () { if (this._rulesets) { return this._rulesets } else { return this._rulesets = this.rules.filter(function (r) { return (r instanceof tree.Ruleset) || (r instanceof tree.mixin.Definition); }); } }, find: function (selector, self) { self = self || this; var rules = [], rule, match, key = selector.toCSS(); if (key in this._lookups) { return this._lookups[key] } this.rulesets().forEach(function (rule) { if (rule !== self) { for (var j = 0; j < rule.selectors.length; j++) { if (match = selector.match(rule.selectors[j])) { if (selector.elements.length > 1) { Array.prototype.push.apply(rules, rule.find( new(tree.Selector)(selector.elements.slice(1)), self)); } else { rules.push(rule); } break; } } } }); return this._lookups[key] = rules; }, // // Entry point for code generation // // `context` holds an array of arrays. // toCSS: function (context, env) { var css = [], // The CSS output rules = [], // node.Rule instances rulesets = [], // node.Ruleset instances paths = [], // Current selectors selector, // The fully rendered selector rule; if (! this.root) { if (context.length === 0) { paths = this.selectors.map(function (s) { return [s] }); } else { for (var s = 0; s < this.selectors.length; s++) { for (var c = 0; c < context.length; c++) { paths.push(context[c].concat([this.selectors[s]])); } } } } // Compile rules and rulesets for (var i = 0; i < this.rules.length; i++) { rule = this.rules[i]; if (rule.rules || (rule instanceof tree.Directive)) { rulesets.push(rule.toCSS(paths, env)); } else if (rule instanceof tree.Comment) { if (!rule.silent) { if (this.root) { rulesets.push(rule.toCSS(env)); } else { rules.push(rule.toCSS(env)); } } } else { if (rule.toCSS && !rule.variable) { rules.push(rule.toCSS(env)); } else if (rule.value && !rule.variable) { rules.push(rule.value.toString()); } } } rulesets = rulesets.join(''); // If this is the root node, we don't render // a selector, or {}. // Otherwise, only output if this ruleset has rules. if (this.root) { css.push(rules.join(env.compress ? '' : '\n')); } else { if (rules.length > 0) { selector = paths.map(function (p) { return p.map(function (s) { return s.toCSS(env); }).join('').trim(); }).join(env.compress ? ',' : (paths.length > 3 ? ',\n' : ', ')); css.push(selector, (env.compress ? '{' : ' {\n ') + rules.join(env.compress ? '' : '\n ') + (env.compress ? '}' : '\n}\n')); } } css.push(rulesets); return css.join('') + (env.compress ? '\n' : ''); } }; })(require('less/tree')); (function (tree) { tree.Selector = function (elements) { this.elements = elements; if (this.elements[0].combinator.value === "") { this.elements[0].combinator.value = ' '; } }; tree.Selector.prototype.match = function (other) { if (this.elements[0].value === other.elements[0].value) { return true; } else { return false; } }; tree.Selector.prototype.toCSS = function (env) { if (this._css) { return this._css } return this._css = this.elements.map(function (e) { if (typeof(e) === 'string') { return ' ' + e.trim(); } else { return e.toCSS(env); } }).join(''); }; })(require('less/tree')); (function (tree) { tree.URL = function (val, paths) { if (val.data) { this.attrs = val; } else { // Add the base path if the URL is relative and we are in the browser if (!/^(?:https?:\/|file:\/|data:\/)?\//.test(val.value) && paths.length > 0 && typeof(window) !== 'undefined') { val.value = paths[0] + (val.value.charAt(0) === '/' ? val.value.slice(1) : val.value); } this.value = val; this.paths = paths; } }; tree.URL.prototype = { toCSS: function () { return "url(" + (this.attrs ? 'data:' + this.attrs.mime + this.attrs.charset + this.attrs.base64 + this.attrs.data : this.value.toCSS()) + ")"; }, eval: function (ctx) { return this.attrs ? this : new(tree.URL)(this.value.eval(ctx), this.paths); } }; })(require('less/tree')); (function (tree) { tree.Value = function (value) { this.value = value; this.is = 'value'; }; tree.Value.prototype = { eval: function (env) { if (this.value.length === 1) { return this.value[0].eval(env); } else { return new(tree.Value)(this.value.map(function (v) { return v.eval(env); })); } }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS(env); }).join(env.compress ? ',' : ', '); } }; })(require('less/tree')); (function (tree) { tree.Variable = function (name, index) { this.name = name, this.index = index }; tree.Variable.prototype = { eval: function (env) { var variable, v, name = this.name; if (name.indexOf('@@') == 0) { name = '@' + new(tree.Variable)(name.slice(1)).eval(env).value; } if (variable = tree.find(env.frames, function (frame) { if (v = frame.variable(name)) { return v.value.eval(env); } })) { return variable } else { throw { message: "variable " + name + " is undefined", index: this.index }; } } }; })(require('less/tree')); require('less/tree').find = function (obj, fun) { for (var i = 0, r; i < obj.length; i++) { if (r = fun.call(obj, obj[i])) { return r } } return null; }; require('less/tree').jsify = function (obj) { if (Array.isArray(obj.value) && (obj.value.length > 1)) { return '[' + obj.value.map(function (v) { return v.toCSS(false) }).join(', ') + ']'; } else { return obj.toCSS(false); } }; // // browser.js - client-side engine // var isFileProtocol = (location.protocol === 'file:' || location.protocol === 'chrome:' || location.protocol === 'chrome-extension:' || location.protocol === 'resource:'); less.env = less.env || (location.hostname == '127.0.0.1' || location.hostname == '0.0.0.0' || location.hostname == 'localhost' || location.port.length > 0 || isFileProtocol ? 'development' : 'production'); // Load styles asynchronously (default: false) // // This is set to `false` by default, so that the body // doesn't start loading before the stylesheets are parsed. // Setting this to `true` can result in flickering. // less.async = false; // Interval between watch polls less.poll = less.poll || (isFileProtocol ? 1000 : 1500); // // Watch mode // less.watch = function () { return this.watchMode = true }; less.unwatch = function () { return this.watchMode = false }; if (less.env === 'development') { less.optimization = 0; if (/!watch/.test(location.hash)) { less.watch(); } less.watchTimer = setInterval(function () { if (less.watchMode) { loadStyleSheets(function (root, sheet, env) { if (root) { createCSS(root.toCSS(), sheet, env.lastModified); } }); } }, less.poll); } else { less.optimization = 3; } var cache; try { cache = (typeof(window.localStorage) === 'undefined') ? null : window.localStorage; } catch (_) { cache = null; } // // Get all tags with the 'rel' attribute set to "stylesheet/less" // var links = document.getElementsByTagName('link'); var typePattern = /^text\/(x-)?less$/; less.sheets = []; for (var i = 0; i < links.length; i++) { if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) && (links[i].type.match(typePattern)))) { less.sheets.push(links[i]); } } less.refresh = function (reload) { var startTime, endTime; startTime = endTime = new(Date); loadStyleSheets(function (root, sheet, env) { if (env.local) { log("loading " + sheet.href + " from cache."); } else { log("parsed " + sheet.href + " successfully."); createCSS(root.toCSS(), sheet, env.lastModified); } log("css for " + sheet.href + " generated in " + (new(Date) - endTime) + 'ms'); (env.remaining === 0) && log("css generated in " + (new(Date) - startTime) + 'ms'); endTime = new(Date); }, reload); loadStyles(); }; less.refreshStyles = loadStyles; less.refresh(less.env === 'development'); function loadStyles() { var styles = document.getElementsByTagName('style'); for (var i = 0; i < styles.length; i++) { if (styles[i].type.match(typePattern)) { new(less.Parser)().parse(styles[i].innerHTML || '', function (e, tree) { styles[i].type = 'text/css'; styles[i].innerHTML = tree.toCSS(); }); } } } function loadStyleSheets(callback, reload) { for (var i = 0; i < less.sheets.length; i++) { loadStyleSheet(less.sheets[i], callback, reload, less.sheets.length - (i + 1)); } } function loadStyleSheet(sheet, callback, reload, remaining) { var url = window.location.href.replace(/[#?].*$/, ''); var href = sheet.href.replace(/\?.*$/, ''); var css = cache && cache.getItem(href); var timestamp = cache && cache.getItem(href + ':timestamp'); var styles = { css: css, timestamp: timestamp }; // Stylesheets in IE don't always return the full path if (! /^(https?|file):/.test(href)) { if (href.charAt(0) == "/") { href = window.location.protocol + "//" + window.location.host + href; } else { href = url.slice(0, url.lastIndexOf('/') + 1) + href; } } xhr(sheet.href, sheet.type, function (data, lastModified) { if (!reload && styles && lastModified && (new(Date)(lastModified).valueOf() === new(Date)(styles.timestamp).valueOf())) { // Use local copy createCSS(styles.css, sheet); callback(null, sheet, { local: true, remaining: remaining }); } else { // Use remote copy (re-parse) try { new(less.Parser)({ optimization: less.optimization, paths: [href.replace(/[\w\.-]+$/, '')], mime: sheet.type }).parse(data, function (e, root) { if (e) { return error(e, href) } try { callback(root, sheet, { local: false, lastModified: lastModified, remaining: remaining }); removeNode(document.getElementById('less-error-message:' + extractId(href))); } catch (e) { error(e, href); } }); } catch (e) { error(e, href); } } }, function (status, url) { throw new(Error)("Couldn't load " + url + " (" + status + ")"); }); } function extractId(href) { return href.replace(/^[a-z]+:\/\/?[^\/]+/, '' ) // Remove protocol & domain .replace(/^\//, '' ) // Remove root / .replace(/\?.*$/, '' ) // Remove query .replace(/\.[^\.\/]+$/, '' ) // Remove file extension .replace(/[^\.\w-]+/g, '-') // Replace illegal characters .replace(/\./g, ':'); // Replace dots with colons(for valid id) } function createCSS(styles, sheet, lastModified) { var css; // Strip the query-string var href = sheet.href ? sheet.href.replace(/\?.*$/, '') : ''; // If there is no title set, use the filename, minus the extension var id = 'less:' + (sheet.title || extractId(href)); // If the stylesheet doesn't exist, create a new node if ((css = document.getElementById(id)) === null) { css = document.createElement('style'); css.type = 'text/css'; css.media = sheet.media || 'screen'; css.id = id; document.getElementsByTagName('head')[0].appendChild(css); } if (css.styleSheet) { // IE try { css.styleSheet.cssText = styles; } catch (e) { throw new(Error)("Couldn't reassign styleSheet.cssText."); } } else { (function (node) { if (css.childNodes.length > 0) { if (css.firstChild.nodeValue !== node.nodeValue) { css.replaceChild(node, css.firstChild); } } else { css.appendChild(node); } })(document.createTextNode(styles)); } // Don't update the local store if the file wasn't modified if (lastModified && cache) { log('saving ' + href + ' to cache.'); cache.setItem(href, styles); cache.setItem(href + ':timestamp', lastModified); } } function xhr(url, type, callback, errback) { var xhr = getXMLHttpRequest(); var async = isFileProtocol ? false : less.async; if (typeof(xhr.overrideMimeType) === 'function') { xhr.overrideMimeType('text/css'); } xhr.open('GET', url, async); xhr.setRequestHeader('Accept', type || 'text/x-less, text/css; q=0.9, */*; q=0.5'); xhr.send(null); if (isFileProtocol) { if (xhr.status === 0) { callback(xhr.responseText); } else { errback(xhr.status, url); } } else if (async) { xhr.onreadystatechange = function () { if (xhr.readyState == 4) { handleResponse(xhr, callback, errback); } }; } else { handleResponse(xhr, callback, errback); } function handleResponse(xhr, callback, errback) { if (xhr.status >= 200 && xhr.status < 300) { callback(xhr.responseText, xhr.getResponseHeader("Last-Modified")); } else if (typeof(errback) === 'function') { errback(xhr.status, url); } } } function getXMLHttpRequest() { if (window.XMLHttpRequest) { return new(XMLHttpRequest); } else { try { return new(ActiveXObject)("MSXML2.XMLHTTP.3.0"); } catch (e) { log("browser doesn't support AJAX."); return null; } } } function removeNode(node) { return node && node.parentNode.removeChild(node); } function log(str) { if (less.env == 'development' && typeof(console) !== "undefined") { console.log('less: ' + str) } } function error(e, href) { var id = 'less-error-message:' + extractId(href); var template = ['
    ', '
  • {0}
  • ', '
  • {current}
  • ', '
  • {2}
  • ', '
'].join('\n'); var elem = document.createElement('div'), timer, content; elem.id = id; elem.className = "less-error-message"; content = '

' + (e.message || 'There is an error in your .less file') + '

' + '

' + href + " "; if (e.extract) { content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':

' + template.replace(/\[(-?\d)\]/g, function (_, i) { return (parseInt(e.line) + parseInt(i)) || ''; }).replace(/\{(\d)\}/g, function (_, i) { return e.extract[parseInt(i)] || ''; }).replace(/\{current\}/, e.extract[1].slice(0, e.column) + '' + e.extract[1].slice(e.column) + ''); } elem.innerHTML = content; // CSS for error messages createCSS([ '.less-error-message ul, .less-error-message li {', 'list-style-type: none;', 'margin-right: 15px;', 'padding: 4px 0;', 'margin: 0;', '}', '.less-error-message label {', 'font-size: 12px;', 'margin-right: 15px;', 'padding: 4px 0;', 'color: #cc7777;', '}', '.less-error-message pre {', 'color: #ee4444;', 'padding: 4px 0;', 'margin: 0;', 'display: inline-block;', '}', '.less-error-message pre.ctx {', 'color: #dd4444;', '}', '.less-error-message h3 {', 'font-size: 20px;', 'font-weight: bold;', 'padding: 15px 0 5px 0;', 'margin: 0;', '}', '.less-error-message a {', 'color: #10a', '}', '.less-error-message .error {', 'color: red;', 'font-weight: bold;', 'padding-bottom: 2px;', 'border-bottom: 1px dashed red;', '}' ].join('\n'), { title: 'error-message' }); elem.style.cssText = [ "font-family: Arial, sans-serif", "border: 1px solid #e00", "background-color: #eee", "border-radius: 5px", "-webkit-border-radius: 5px", "-moz-border-radius: 5px", "color: #e00", "padding: 15px", "margin-bottom: 15px" ].join(';'); if (less.env == 'development') { timer = setInterval(function () { if (document.body) { if (document.getElementById(id)) { document.body.replaceChild(elem, document.getElementById(id)); } else { document.body.insertBefore(elem, document.body.firstChild); } clearInterval(timer); } }, 10); } } })(window); less.js-1.4.2/dist/less-1.1.2.min.js000066400000000000000000001034631217256642200166030ustar00rootroot00000000000000// // LESS - Leaner CSS v1.1.2 // http://lesscss.org // // Copyright (c) 2009-2011, Alexis Sellier // Licensed under the Apache 2.0 License. // // // LESS - Leaner CSS v1.1.2 // http://lesscss.org // // Copyright (c) 2009-2011, Alexis Sellier // Licensed under the Apache 2.0 License. // (function(a,b){function v(a,b){var c="less-error-message:"+p(b),e=["
    ",'
  • {0}
  • ',"
  • {current}
  • ",'
  • {2}
  • ',"
"].join("\n"),f=document.createElement("div"),g,h;f.id=c,f.className="less-error-message",h="

"+(a.message||"There is an error in your .less file")+"

"+'

'+b+" ",a.extract&&(h+="on line "+a.line+", column "+(a.column+1)+":

"+e.replace(/\[(-?\d)\]/g,function(b,c){return parseInt(a.line)+parseInt(c)||""}).replace(/\{(\d)\}/g,function(b,c){return a.extract[parseInt(c)]||""}).replace(/\{current\}/,a.extract[1].slice(0,a.column)+''+a.extract[1].slice(a.column)+"")),f.innerHTML=h,q([".less-error-message ul, .less-error-message li {","list-style-type: none;","margin-right: 15px;","padding: 4px 0;","margin: 0;","}",".less-error-message label {","font-size: 12px;","margin-right: 15px;","padding: 4px 0;","color: #cc7777;","}",".less-error-message pre {","color: #ee4444;","padding: 4px 0;","margin: 0;","display: inline-block;","}",".less-error-message pre.ctx {","color: #dd4444;","}",".less-error-message h3 {","font-size: 20px;","font-weight: bold;","padding: 15px 0 5px 0;","margin: 0;","}",".less-error-message a {","color: #10a","}",".less-error-message .error {","color: red;","font-weight: bold;","padding-bottom: 2px;","border-bottom: 1px dashed red;","}"].join("\n"),{title:"error-message"}),f.style.cssText=["font-family: Arial, sans-serif","border: 1px solid #e00","background-color: #eee","border-radius: 5px","-webkit-border-radius: 5px","-moz-border-radius: 5px","color: #e00","padding: 15px","margin-bottom: 15px"].join(";"),d.env=="development"&&(g=setInterval(function(){document.body&&(document.getElementById(c)?document.body.replaceChild(f,document.getElementById(c)):document.body.insertBefore(f,document.body.firstChild),clearInterval(g))},10))}function u(a){d.env=="development"&&typeof console!="undefined"&&console.log("less: "+a)}function t(a){return a&&a.parentNode.removeChild(a)}function s(){if(a.XMLHttpRequest)return new XMLHttpRequest;try{return new ActiveXObject("MSXML2.XMLHTTP.3.0")}catch(b){u("browser doesn't support AJAX.");return null}}function r(a,b,c,e){function i(b,c,d){b.status>=200&&b.status<300?c(b.responseText,b.getResponseHeader("Last-Modified")):typeof d=="function"&&d(b.status,a)}var f=s(),h=g?!1:d.async;typeof f.overrideMimeType=="function"&&f.overrideMimeType("text/css"),f.open("GET",a,h),f.setRequestHeader("Accept",b||"text/x-less, text/css; q=0.9, */*; q=0.5"),f.send(null),g?f.status===0?c(f.responseText):e(f.status,a):h?f.onreadystatechange=function(){f.readyState==4&&i(f,c,e)}:i(f,c,e)}function q(a,b,c){var d,e=b.href?b.href.replace(/\?.*$/,""):"",f="less:"+(b.title||p(e));(d=document.getElementById(f))===null&&(d=document.createElement("style"),d.type="text/css",d.media=b.media||"screen",d.id=f,document.getElementsByTagName("head")[0].appendChild(d));if(d.styleSheet)try{d.styleSheet.cssText=a}catch(g){throw new Error("Couldn't reassign styleSheet.cssText.")}else(function(a){d.childNodes.length>0?d.firstChild.nodeValue!==a.nodeValue&&d.replaceChild(a,d.firstChild):d.appendChild(a)})(document.createTextNode(a));c&&h&&(u("saving "+e+" to cache."),h.setItem(e,a),h.setItem(e+":timestamp",c))}function p(a){return a.replace(/^[a-z]+:\/\/?[^\/]+/,"").replace(/^\//,"").replace(/\?.*$/,"").replace(/\.[^\.\/]+$/,"").replace(/[^\.\w-]+/g,"-").replace(/\./g,":")}function o(b,c,e,f){var g=a.location.href.replace(/[#?].*$/,""),i=b.href.replace(/\?.*$/,""),j=h&&h.getItem(i),k=h&&h.getItem(i+":timestamp"),l={css:j,timestamp:k};/^(https?|file):/.test(i)||(i.charAt(0)=="/"?i=a.location.protocol+"//"+a.location.host+i:i=g.slice(0,g.lastIndexOf("/")+1)+i),r(b.href,b.type,function(a,g){if(!e&&l&&g&&(new Date(g)).valueOf()===(new Date(l.timestamp)).valueOf())q(l.css,b),c(null,b,{local:!0,remaining:f});else try{(new d.Parser({optimization:d.optimization,paths:[i.replace(/[\w\.-]+$/,"")],mime:b.type})).parse(a,function(a,d){if(a)return v(a,i);try{c(d,b,{local:!1,lastModified:g,remaining:f}),t(document.getElementById("less-error-message:"+p(i)))}catch(a){v(a,i)}})}catch(h){v(h,i)}},function(a,b){throw new Error("Couldn't load "+b+" ("+a+")")})}function n(a,b){for(var c=0;c>>0;for(var d=0;d>>0,c=Array(b),d=arguments[1];for(var e=0;e>>0,c=0;if(b===0&&arguments.length===1)throw new TypeError;if(arguments.length>=2)var d=arguments[1];else for(;;){if(c in this){d=this[c++];break}if(++c>=b)throw new TypeError}for(;c=b)return-1;c<0&&(c+=b);for(;ck&&(j[f]=j[f].slice(c-k),k=c)}function q(){j[f]=g,c=h,k=c}function p(){g=j[f],h=c,k=c}var b,c,f,g,h,i,j,k,l,m=this,n=function(){},o=this.imports={paths:a&&a.paths||[],queue:[],files:{},mime:a&&a.mime,push:function(b,c){var e=this;this.queue.push(b),d.Parser.importer(b,this.paths,function(a){e.queue.splice(e.queue.indexOf(b),1),e.files[b]=a,c(a),e.queue.length===0&&n()},a)}};this.env=a=a||{},this.optimization="optimization"in this.env?this.env.optimization:1,this.env.filename=this.env.filename||null;return l={imports:o,parse:function(d,g){var h,l,m,o,p,q,r=[],t,u=null;c=f=k=i=0,j=[],b=d.replace(/\r\n/g,"\n"),j=function(c){var d=0,e=/[^"'`\{\}\/\(\)]+/g,f=/\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g,g=0,h,i=c[0],j,k;for(var l=0,m,n;l0)throw{type:"Syntax",message:"Missing closing `}`",filename:a.filename};return c.map(function(a){return a.join("")})}([[]]),h=new e.Ruleset([],s(this.parsers.primary)),h.root=!0,h.toCSS=function(c){var d,f,g;return function(g,h){function n(a){return a?(b.slice(0,a).match(/\n/g)||"").length:null}var i=[];g=g||{},typeof h=="object"&&!Array.isArray(h)&&(h=Object.keys(h).map(function(a){var b=h[a];b instanceof e.Value||(b instanceof e.Expression||(b=new e.Expression([b])),b=new e.Value([b]));return new e.Rule("@"+a,b,!1,0)}),i=[new e.Ruleset(null,h)]);try{var j=c.call(this,{frames:i}).toCSS([],{compress:g.compress||!1})}catch(k){f=b.split("\n"),d=n(k.index);for(var l=k.index,m=-1;l>=0&&b.charAt(l)!=="\n";l--)m++;throw{type:k.type,message:k.message,filename:a.filename,index:k.index,line:typeof d=="number"?d+1:null,callLine:k.call&&n(k.call)+1,callExtract:f[n(k.call)],stack:k.stack,column:m,extract:[f[d-1],f[d],f[d+1]]}}return g.compress?j.replace(/(\s)+/g,"$1"):j}}(h.eval);if(c=0&&b.charAt(v)!=="\n";v--)w++;u={name:"ParseError",message:"Syntax Error on line "+p,index:c,filename:a.filename,line:p,column:w,extract:[q[p-2],q[p-1],q[p]]}}this.imports.queue.length>0?n=function(){g(u,h)}:g(u,h)},parsers:{primary:function(){var a,b=[];while((a=s(this.mixin.definition)||s(this.rule)||s(this.ruleset)||s(this.mixin.call)||s(this.comment)||s(this.directive))||s(/^[\s\n]+/))a&&b.push(a);return b},comment:function(){var a;if(b.charAt(c)==="/"){if(b.charAt(c+1)==="/")return new e.Comment(s(/^\/\/.*/),!0);if(a=s(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/))return new e.Comment(a)}},entities:{quoted:function(){var a,d=c,f;b.charAt(d)==="~"&&(d++,f=!0);if(b.charAt(d)==='"'||b.charAt(d)==="'"){f&&s("~");if(a=s(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/))return new e.Quoted(a[0],a[1]||a[2],f)}},keyword:function(){var a;if(a=s(/^[A-Za-z-]+/))return new e.Keyword(a)},call:function(){var a,b;if(!!(a=/^([\w-]+|%)\(/.exec(j[f]))){a=a[1].toLowerCase();if(a==="url")return null;c+=a.length;if(a==="alpha")return s(this.alpha);s("("),b=s(this.entities.arguments);if(!s(")"))return;if(a)return new e.Call(a,b)}},arguments:function(){var a=[],b;while(b=s(this.expression)){a.push(b);if(!s(","))break}return a},literal:function(){return s(this.entities.dimension)||s(this.entities.color)||s(this.entities.quoted)},url:function(){var a;if(b.charAt(c)==="u"&&!!s(/^url\(/)){a=s(this.entities.quoted)||s(this.entities.variable)||s(this.entities.dataURI)||s(/^[-\w%@$\/.&=:;#+?~]+/)||"";if(!s(")"))throw new Error("missing closing ) for url()");return new e.URL(a.value||a.data||a instanceof e.Variable?a:new e.Anonymous(a),o.paths)}},dataURI:function(){var a;if(s(/^data:/)){a={},a.mime=s(/^[^\/]+\/[^,;)]+/)||"",a.charset=s(/^;\s*charset=[^,;)]+/)||"",a.base64=s(/^;\s*base64/)||"",a.data=s(/^,\s*[^)]+/);if(a.data)return a}},variable:function(){var a,d=c;if(b.charAt(c)==="@"&&(a=s(/^@@?[\w-]+/)))return new e.Variable(a,d)},color:function(){var a;if(b.charAt(c)==="#"&&(a=s(/^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})/)))return new e.Color(a[1])},dimension:function(){var a,d=b.charCodeAt(c);if(!(d>57||d<45||d===47))if(a=s(/^(-?\d*\.?\d+)(px|%|em|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn)?/))return new e.Dimension(a[1],a[2])},javascript:function(){var a,d=c,f;b.charAt(d)==="~"&&(d++,f=!0);if(b.charAt(d)==="`"){f&&s("~");if(a=s(/^`([^`]*)`/))return new e.JavaScript(a[1],c,f)}}},variable:function(){var a;if(b.charAt(c)==="@"&&(a=s(/^(@[\w-]+)\s*:/)))return a[1]},shorthand:function(){var a,b;if(!!t(/^[@\w.%-]+\/[@\w.-]+/)&&(a=s(this.entity))&&s("/")&&(b=s(this.entity)))return new e.Shorthand(a,b)},mixin:{call:function(){var a=[],d,f,g,h=c,i=b.charAt(c);if(i==="."||i==="#"){while(d=s(/^[#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/))a.push(new e.Element(f,d)),f=s(">");s("(")&&(g=s(this.entities.arguments))&&s(")");if(a.length>0&&(s(";")||t("}")))return new e.mixin.Call(a,g,h)}},definition:function(){var a,d=[],f,g,h,i;if(!(b.charAt(c)!=="."&&b.charAt(c)!=="#"||t(/^[^{]*(;|})/)))if(f=s(/^([#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+)\s*\(/)){a=f[1];while(h=s(this.entities.variable)||s(this.entities.literal)||s(this.entities.keyword)){if(h instanceof e.Variable)if(s(":"))if(i=s(this.expression))d.push({name:h.name,value:i});else throw new Error("Expected value");else d.push({name:h.name});else d.push({value:h});if(!s(","))break}if(!s(")"))throw new Error("Expected )");g=s(this.block);if(g)return new e.mixin.Definition(a,d,g)}}},entity:function(){return s(this.entities.literal)||s(this.entities.variable)||s(this.entities.url)||s(this.entities.call)||s(this.entities.keyword)||s(this.entities.javascript)||s(this.comment)},end:function(){return s(";")||t("}")},alpha:function(){var a;if(!!s(/^opacity=/i))if(a=s(/^\d+/)||s(this.entities.variable)){if(!s(")"))throw new Error("missing closing ) for alpha()");return new e.Alpha(a)}},element:function(){var a,b,c;c=s(this.combinator),a=s(/^(?:[.#]?|:*)(?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/)||s("*")||s(this.attribute)||s(/^\([^)@]+\)/);if(a)return new e.Element(c,a)},combinator:function(){var a,d=b.charAt(c);if(d===">"||d==="&"||d==="+"||d==="~"){c++;while(b.charAt(c)===" ")c++;return new e.Combinator(d)}if(d===":"&&b.charAt(c+1)===":"){c+=2;while(b.charAt(c)===" ")c++;return new e.Combinator("::")}return b.charAt(c-1)===" "?new e.Combinator(" "):new e.Combinator(null)},selector:function(){var a,d,f=[],g,h;while(d=s(this.element)){g=b.charAt(c),f.push(d);if(g==="{"||g==="}"||g===";"||g===",")break}if(f.length>0)return new e.Selector(f)},tag:function(){return s(/^[a-zA-Z][a-zA-Z-]*[0-9]?/)||s("*")},attribute:function(){var a="",b,c,d;if(!!s("[")){if(b=s(/^[a-zA-Z-]+/)||s(this.entities.quoted))(d=s(/^[|~*$^]?=/))&&(c=s(this.entities.quoted)||s(/^[\w-]+/))?a=[b,d,c.toCSS?c.toCSS():c].join(""):a=b;if(!s("]"))return;if(a)return"["+a+"]"}},block:function(){var a;if(s("{")&&(a=s(this.primary))&&s("}"))return a},ruleset:function(){var a=[],b,d,g;p();if(g=/^([.#: \w-]+)[\s\n]*\{/.exec(j[f]))c+=g[0].length-1,a=[new e.Selector([new e.Element(null,g[1])])];else while(b=s(this.selector)){a.push(b),s(this.comment);if(!s(","))break;s(this.comment)}if(a.length>0&&(d=s(this.block)))return new e.Ruleset(a,d);i=c,q()},rule:function(){var a,d,g=b.charAt(c),k,l;p();if(g!=="."&&g!=="#"&&g!=="&")if(a=s(this.variable)||s(this.property)){a.charAt(0)!="@"&&(l=/^([^@+\/'"*`(;{}-]*);/.exec(j[f]))?(c+=l[0].length-1,d=new e.Anonymous(l[1])):a==="font"?d=s(this.font):d=s(this.value),k=s(this.important);if(d&&s(this.end))return new e.Rule(a,d,k,h);i=c,q()}},"import":function(){var a;if(s(/^@import\s+/)&&(a=s(this.entities.quoted)||s(this.entities.url))&&s(";"))return new e.Import(a,o)},directive:function(){var a,d,f,g;if(b.charAt(c)==="@"){if(d=s(this["import"]))return d;if(a=s(/^@media|@page|@-[-a-z]+/)){g=(s(/^[^{]+/)||"").trim();if(f=s(this.block))return new e.Directive(a+" "+g,f)}else if(a=s(/^@[-a-z]+/))if(a==="@font-face"){if(f=s(this.block))return new e.Directive(a,f)}else if((d=s(this.entity))&&s(";"))return new e.Directive(a,d)}},font:function(){var a=[],b=[],c,d,f,g;while(g=s(this.shorthand)||s(this.entity))b.push(g);a.push(new e.Expression(b));if(s(","))while(g=s(this.expression)){a.push(g);if(!s(","))break}return new e.Value(a)},value:function(){var a,b=[],c;while(a=s(this.expression)){b.push(a);if(!s(","))break}if(b.length>0)return new e.Value(b)},important:function(){if(b.charAt(c)==="!")return s(/^! *important/)},sub:function(){var a;if(s("(")&&(a=s(this.expression))&&s(")"))return a},multiplication:function(){var a,b,c,d;if(a=s(this.operand)){while((c=s("/")||s("*"))&&(b=s(this.operand)))d=new e.Operation(c,[d||a,b]);return d||a}},addition:function(){var a,d,f,g;if(a=s(this.multiplication)){while((f=s(/^[-+]\s+/)||b.charAt(c-1)!=" "&&(s("+")||s("-")))&&(d=s(this.multiplication)))g=new e.Operation(f,[g||a,d]);return g||a}},operand:function(){var a,d=b.charAt(c+1);b.charAt(c)==="-"&&(d==="@"||d==="(")&&(a=s("-"));var f=s(this.sub)||s(this.entities.dimension)||s(this.entities.color)||s(this.entities.variable)||s(this.entities.call);return a?new e.Operation("*",[new e.Dimension(-1),f]):f},expression:function(){var a,b,c=[],d;while(a=s(this.addition)||s(this.entity))c.push(a);if(c.length>0)return new e.Expression(c)},property:function(){var a;if(a=s(/^(\*?-?[-a-z_0-9]+)\s*:/))return a[1]}}}},typeof a!="undefined"&&(d.Parser.importer=function(a,b,c,d){a.charAt(0)!=="/"&&b.length>0&&(a=b[0]+a),o({href:a,title:a,type:d.mime},c,!0)}),function(a){function d(a){return Math.min(1,Math.max(0,a))}function c(b){if(b instanceof a.Dimension)return parseFloat(b.unit=="%"?b.value/100:b.value);if(typeof b=="number")return b;throw{error:"RuntimeError",message:"color functions take numbers as parameters"}}function b(b){return a.functions.hsla(b.h,b.s,b.l,b.a)}a.functions={rgb:function(a,b,c){return this.rgba(a,b,c,1)},rgba:function(b,d,e,f){var g=[b,d,e].map(function(a){return c(a)}),f=c(f);return new a.Color(g,f)},hsl:function(a,b,c){return this.hsla(a,b,c,1)},hsla:function(a,b,d,e){function h(a){a=a<0?a+1:a>1?a-1:a;return a*6<1?g+(f-g)*a*6:a*2<1?f:a*3<2?g+(f-g)*(2/3-a)*6:g}a=c(a)%360/360,b=c(b),d=c(d),e=c(e);var f=d<=.5?d*(b+1):d+b-d*b,g=d*2-f;return this.rgba(h(a+1/3)*255,h(a)*255,h(a-1/3)*255,e)},hue:function(b){return new a.Dimension(Math.round(b.toHSL().h))},saturation:function(b){return new a.Dimension(Math.round(b.toHSL().s*100),"%")},lightness:function(b){return new a.Dimension(Math.round(b.toHSL().l*100),"%")},alpha:function(b){return new a.Dimension(b.toHSL().a)},saturate:function(a,c){var e=a.toHSL();e.s+=c.value/100,e.s=d(e.s);return b(e)},desaturate:function(a,c){var e=a.toHSL();e.s-=c.value/100,e.s=d(e.s);return b(e)},lighten:function(a,c){var e=a.toHSL();e.l+=c.value/100,e.l=d(e.l);return b(e)},darken:function(a,c){var e=a.toHSL();e.l-=c.value/100,e.l=d(e.l);return b(e)},fadein:function(a,c){var e=a.toHSL();e.a+=c.value/100,e.a=d(e.a);return b(e)},fadeout:function(a,c){var e=a.toHSL();e.a-=c.value/100,e.a=d(e.a);return b(e)},spin:function(a,c){var d=a.toHSL(),e=(d.h+c.value)%360;d.h=e<0?360+e:e;return b(d)},mix:function(b,c,d){var e=d.value/100,f=e*2-1,g=b.toHSL().a-c.toHSL().a,h=((f*g==-1?f:(f+g)/(1+f*g))+1)/2,i=1-h,j=[b.rgb[0]*h+c.rgb[0]*i,b.rgb[1]*h+c.rgb[1]*i,b.rgb[2]*h+c.rgb[2]*i],k=b.alpha*e+c.alpha*(1-e);return new a.Color(j,k)},greyscale:function(b){return this.desaturate(b,new a.Dimension(100))},e:function(b){return new a.Anonymous(b instanceof a.JavaScript?b.evaluated:b)},escape:function(b){return new a.Anonymous(encodeURI(b.value).replace(/=/g,"%3D").replace(/:/g,"%3A").replace(/#/g,"%23").replace(/;/g,"%3B").replace(/\(/g,"%28").replace(/\)/g,"%29"))},"%":function(b){var c=Array.prototype.slice.call(arguments,1),d=b.value;for(var e=0;e255?255:a<0?0:a).toString(16);return a.length===1?"0"+a:a}).join("")},operate:function(b,c){var d=[];c instanceof a.Color||(c=c.toColor());for(var e=0;e<3;e++)d[e]=a.operate(b,this.rgb[e],c.rgb[e]);return new a.Color(d,this.alpha+c.alpha)},toHSL:function(){var a=this.rgb[0]/255,b=this.rgb[1]/255,c=this.rgb[2]/255,d=this.alpha,e=Math.max(a,b,c),f=Math.min(a,b,c),g,h,i=(e+f)/2,j=e-f;if(e===f)g=h=0;else{h=i>.5?j/(2-e-f):j/(e+f);switch(e){case a:g=(b-c)/j+(b":a.compress?">":" > "}[this.value]}}(c("less/tree")),function(a){a.Expression=function(a){this.value=a},a.Expression.prototype={eval:function(b){return this.value.length>1?new a.Expression(this.value.map(function(a){return a.eval(b)})):this.value.length===1?this.value[0].eval(b):this},toCSS:function(a){return this.value.map(function(b){return b.toCSS(a)}).join(" ")}}}(c("less/tree")),function(a){a.Import=function(b,c){var d=this;this._path=b,b instanceof a.Quoted?this.path=/\.(le?|c)ss$/.test(b.value)?b.value:b.value+".less":this.path=b.value.value||b.value,this.css=/css$/.test(this.path),this.css||c.push(this.path,function(a){if(!a)throw new Error("Error parsing "+d.path);d.root=a})},a.Import.prototype={toCSS:function(){return this.css?"@import "+this._path.toCSS()+";\n":""},eval:function(b){var c;if(this.css)return this;c=new a.Ruleset(null,this.root.rules.slice(0));for(var d=0;d0){c=this.arguments&&this.arguments.map(function(b){return b.eval(a)});for(var g=0;g0&&c>this.params.length)return!1;d=Math.min(c,this.arity);for(var e=0;e1?Array.prototype.push.apply(d,e.find(new a.Selector(b.elements.slice(1)),c)):d.push(e);break}});return this._lookups[g]=d},toCSS:function(b,c){var d=[],e=[],f=[],g=[],h,i;if(!this.root)if(b.length===0)g=this.selectors.map(function(a){return[a]});else for(var j=0;j0&&(h=g.map(function(a){return a.map(function(a){return a.toCSS(c)}).join("").trim()}).join(c.compress?",":g.length>3?",\n":", "),d.push(h,(c.compress?"{":" {\n ")+e.join(c.compress?"":"\n ")+(c.compress?"}":"\n}\n"))),d.push(f);return d.join("")+(c.compress?"\n":"")}}}(c("less/tree")),function(a){a.Selector=function(a){this.elements=a,this.elements[0].combinator.value===""&&(this.elements[0].combinator.value=" ")},a.Selector.prototype.match=function(a){return this.elements[0].value===a.elements[0].value?!0:!1},a.Selector.prototype.toCSS=function(a){if(this._css)return this._css;return this._css=this.elements.map(function(b){return typeof b=="string"?" "+b.trim():b.toCSS(a)}).join("")}}(c("less/tree")),function(b){b.URL=function(b,c){b.data?this.attrs=b:(!/^(?:https?:\/|file:\/|data:\/)?\//.test(b.value)&&c.length>0&&typeof a!="undefined"&&(b.value=c[0]+(b.value.charAt(0)==="/"?b.value.slice(1):b.value)),this.value=b,this.paths=c)},b.URL.prototype={toCSS:function(){return"url("+(this.attrs?"data:"+this.attrs.mime+this.attrs.charset+this.attrs.base64+this.attrs.data:this.value.toCSS())+")"},eval:function(a){return this.attrs?this:new b.URL(this.value.eval(a),this.paths)}}}(c("less/tree")),function(a){a.Value=function(a){this.value=a,this.is="value"},a.Value.prototype={eval:function(b){return this.value.length===1?this.value[0].eval(b):new a.Value(this.value.map(function(a){return a.eval(b)}))},toCSS:function(a){return this.value.map(function(b){return b.toCSS(a)}).join(a.compress?",":", ")}}}(c("less/tree")),function(a){a.Variable=function(a,b){this.name=a,this.index=b},a.Variable.prototype={eval:function(b){var c,d,e=this.name;e.indexOf("@@")==0&&(e="@"+(new a.Variable(e.slice(1))).eval(b).value);if(c=a.find(b.frames,function(a){ if(d=a.variable(e))return d.value.eval(b)}))return c;throw{message:"variable "+e+" is undefined",index:this.index}}}}(c("less/tree")),c("less/tree").find=function(a,b){for(var c=0,d;c1?"["+a.value.map(function(a){return a.toCSS(!1)}).join(", ")+"]":a.toCSS(!1)};var g=location.protocol==="file:"||location.protocol==="chrome:"||location.protocol==="chrome-extension:"||location.protocol==="resource:";d.env=d.env||(location.hostname=="127.0.0.1"||location.hostname=="0.0.0.0"||location.hostname=="localhost"||location.port.length>0||g?"development":"production"),d.async=!1,d.poll=d.poll||(g?1e3:1500),d.watch=function(){return this.watchMode=!0},d.unwatch=function(){return this.watchMode=!1},d.env==="development"?(d.optimization=0,/!watch/.test(location.hash)&&d.watch(),d.watchTimer=setInterval(function(){d.watchMode&&n(function(a,b,c){a&&q(a.toCSS(),b,c.lastModified)})},d.poll)):d.optimization=3;var h;try{h=typeof a.localStorage=="undefined"?null:a.localStorage}catch(i){h=null}var j=document.getElementsByTagName("link"),k=/^text\/(x-)?less$/;d.sheets=[];for(var l=0;l>> 0; for (var i = 0; i < len; i++) { if (i in this) { block.call(thisObject, this[i], i, this); } } }; } if (!Array.prototype.map) { Array.prototype.map = function(fun /*, thisp*/) { var len = this.length >>> 0; var res = new Array(len); var thisp = arguments[1]; for (var i = 0; i < len; i++) { if (i in this) { res[i] = fun.call(thisp, this[i], i, this); } } return res; }; } if (!Array.prototype.filter) { Array.prototype.filter = function (block /*, thisp */) { var values = []; var thisp = arguments[1]; for (var i = 0; i < this.length; i++) { if (block.call(thisp, this[i])) { values.push(this[i]); } } return values; }; } if (!Array.prototype.reduce) { Array.prototype.reduce = function(fun /*, initial*/) { var len = this.length >>> 0; var i = 0; // no value to return if no initial value and an empty array if (len === 0 && arguments.length === 1) throw new TypeError(); if (arguments.length >= 2) { var rv = arguments[1]; } else { do { if (i in this) { rv = this[i++]; break; } // if array contains no values, no initial value to return if (++i >= len) throw new TypeError(); } while (true); } for (; i < len; i++) { if (i in this) { rv = fun.call(null, rv, this[i], i, this); } } return rv; }; } if (!Array.prototype.indexOf) { Array.prototype.indexOf = function (value /*, fromIndex */ ) { var length = this.length; var i = arguments[1] || 0; if (!length) return -1; if (i >= length) return -1; if (i < 0) i += length; for (; i < length; i++) { if (!Object.prototype.hasOwnProperty.call(this, i)) { continue } if (value === this[i]) return i; } return -1; }; } // // Object // if (!Object.keys) { Object.keys = function (object) { var keys = []; for (var name in object) { if (Object.prototype.hasOwnProperty.call(object, name)) { keys.push(name); } } return keys; }; } // // String // if (!String.prototype.trim) { String.prototype.trim = function () { return String(this).replace(/^\s\s*/, '').replace(/\s\s*$/, ''); }; } var less, tree; if (typeof(window) === 'undefined') { less = exports, tree = require('less/tree'); } else { if (typeof(window.less) === 'undefined') { window.less = {} } less = window.less, tree = window.less.tree = {}; } // // less.js - parser // // A relatively straight-forward predictive parser. // There is no tokenization/lexing stage, the input is parsed // in one sweep. // // To make the parser fast enough to run in the browser, several // optimization had to be made: // // - Matching and slicing on a huge input is often cause of slowdowns. // The solution is to chunkify the input into smaller strings. // The chunks are stored in the `chunks` var, // `j` holds the current chunk index, and `current` holds // the index of the current chunk in relation to `input`. // This gives us an almost 4x speed-up. // // - In many cases, we don't need to match individual tokens; // for example, if a value doesn't hold any variables, operations // or dynamic references, the parser can effectively 'skip' it, // treating it as a literal. // An example would be '1px solid #000' - which evaluates to itself, // we don't need to know what the individual components are. // The drawback, of course is that you don't get the benefits of // syntax-checking on the CSS. This gives us a 50% speed-up in the parser, // and a smaller speed-up in the code-gen. // // // Token matching is done with the `$` function, which either takes // a terminal string or regexp, or a non-terminal function to call. // It also takes care of moving all the indices forwards. // // less.Parser = function Parser(env) { var input, // LeSS input string i, // current index in `input` j, // current chunk temp, // temporarily holds a chunk's state, for backtracking memo, // temporarily holds `i`, when backtracking furthest, // furthest index the parser has gone to chunks, // chunkified input current, // index of current chunk, in `input` parser; var that = this; // This function is called after all files // have been imported through `@import`. var finish = function () {}; var imports = this.imports = { paths: env && env.paths || [], // Search paths, when importing queue: [], // Files which haven't been imported yet files: {}, // Holds the imported parse trees mime: env && env.mime, // MIME type of .less files push: function (path, callback) { var that = this; this.queue.push(path); // // Import a file asynchronously // less.Parser.importer(path, this.paths, function (root) { that.queue.splice(that.queue.indexOf(path), 1); // Remove the path from the queue that.files[path] = root; // Store the root callback(root); if (that.queue.length === 0) { finish() } // Call `finish` if we're done importing }, env); } }; function save() { temp = chunks[j], memo = i, current = i } function restore() { chunks[j] = temp, i = memo, current = i } function sync() { if (i > current) { chunks[j] = chunks[j].slice(i - current); current = i; } } // // Parse from a token, regexp or string, and move forward if match // function $(tok) { var match, args, length, c, index, endIndex, k, mem; // // Non-terminal // if (tok instanceof Function) { return tok.call(parser.parsers); // // Terminal // // Either match a single character in the input, // or match a regexp in the current chunk (chunk[j]). // } else if (typeof(tok) === 'string') { match = input.charAt(i) === tok ? tok : null; length = 1; sync (); } else { sync (); if (match = tok.exec(chunks[j])) { length = match[0].length; } else { return null; } } // The match is confirmed, add the match length to `i`, // and consume any extra white-space characters (' ' || '\n') // which come after that. The reason for this is that LeSS's // grammar is mostly white-space insensitive. // if (match) { mem = i += length; endIndex = i + chunks[j].length - length; while (i < endIndex) { c = input.charCodeAt(i); if (! (c === 32 || c === 10 || c === 9)) { break } i++; } chunks[j] = chunks[j].slice(length + (i - mem)); current = i; if (chunks[j].length === 0 && j < chunks.length - 1) { j++ } if(typeof(match) === 'string') { return match; } else { return match.length === 1 ? match[0] : match; } } } // Same as $(), but don't change the state of the parser, // just return the match. function peek(tok) { if (typeof(tok) === 'string') { return input.charAt(i) === tok; } else { if (tok.test(chunks[j])) { return true; } else { return false; } } } this.env = env = env || {}; // The optimization level dictates the thoroughness of the parser, // the lower the number, the less nodes it will create in the tree. // This could matter for debugging, or if you want to access // the individual nodes in the tree. this.optimization = ('optimization' in this.env) ? this.env.optimization : 1; this.env.filename = this.env.filename || null; // // The Parser // return parser = { imports: imports, // // Parse an input string into an abstract syntax tree, // call `callback` when done. // parse: function (str, callback) { var root, start, end, zone, line, lines, buff = [], c, error = null; i = j = current = furthest = 0; chunks = []; input = str.replace(/\r\n/g, '\n'); // Split the input into chunks. chunks = (function (chunks) { var j = 0, skip = /[^"'`\{\}\/\(\)]+/g, comment = /\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g, level = 0, match, chunk = chunks[0], inParam, inString; for (var i = 0, c, cc; i < input.length; i++) { skip.lastIndex = i; if (match = skip.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); } } c = input.charAt(i); comment.lastIndex = i; if (!inString && !inParam && c === '/') { cc = input.charAt(i + 1); if (cc === '/' || cc === '*') { if (match = comment.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); c = input.charAt(i); } } } } if (c === '{' && !inString && !inParam) { level ++; chunk.push(c); } else if (c === '}' && !inString && !inParam) { level --; chunk.push(c); chunks[++j] = chunk = []; } else if (c === '(' && !inString && !inParam) { chunk.push(c); inParam = true; } else if (c === ')' && !inString && inParam) { chunk.push(c); inParam = false; } else { if (c === '"' || c === "'" || c === '`') { if (! inString) { inString = c; } else { inString = inString === c ? false : inString; } } chunk.push(c); } } if (level > 0) { throw { type: 'Syntax', message: "Missing closing `}`", filename: env.filename }; } return chunks.map(function (c) { return c.join('') });; })([[]]); // Start with the primary rule. // The whole syntax tree is held under a Ruleset node, // with the `root` property set to true, so no `{}` are // output. The callback is called when the input is parsed. root = new(tree.Ruleset)([], $(this.parsers.primary)); root.root = true; root.toCSS = (function (evaluate) { var line, lines, column; return function (options, variables) { var frames = []; options = options || {}; // // Allows setting variables with a hash, so: // // `{ color: new(tree.Color)('#f01') }` will become: // // new(tree.Rule)('@color', // new(tree.Value)([ // new(tree.Expression)([ // new(tree.Color)('#f01') // ]) // ]) // ) // if (typeof(variables) === 'object' && !Array.isArray(variables)) { variables = Object.keys(variables).map(function (k) { var value = variables[k]; if (! (value instanceof tree.Value)) { if (! (value instanceof tree.Expression)) { value = new(tree.Expression)([value]); } value = new(tree.Value)([value]); } return new(tree.Rule)('@' + k, value, false, 0); }); frames = [new(tree.Ruleset)(null, variables)]; } try { var css = evaluate.call(this, { frames: frames }) .toCSS([], { compress: options.compress || false }); } catch (e) { lines = input.split('\n'); line = getLine(e.index); for (var n = e.index, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } throw { type: e.type, message: e.message, filename: env.filename, index: e.index, line: typeof(line) === 'number' ? line + 1 : null, callLine: e.call && (getLine(e.call) + 1), callExtract: lines[getLine(e.call)], stack: e.stack, column: column, extract: [ lines[line - 1], lines[line], lines[line + 1] ] }; } if (options.compress) { return css.replace(/(\s)+/g, "$1"); } else { return css; } function getLine(index) { return index ? (input.slice(0, index).match(/\n/g) || "").length : null; } }; })(root.eval); // If `i` is smaller than the `input.length - 1`, // it means the parser wasn't able to parse the whole // string, so we've got a parsing error. // // We try to extract a \n delimited string, // showing the line where the parse error occured. // We split it up into two parts (the part which parsed, // and the part which didn't), so we can color them differently. if (i < input.length - 1) { i = furthest; lines = input.split('\n'); line = (input.slice(0, i).match(/\n/g) || "").length + 1; for (var n = i, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } error = { name: "ParseError", message: "Syntax Error on line " + line, index: i, filename: env.filename, line: line, column: column, extract: [ lines[line - 2], lines[line - 1], lines[line] ] }; } if (this.imports.queue.length > 0) { finish = function () { callback(error, root) }; } else { callback(error, root); } }, // // Here in, the parsing rules/functions // // The basic structure of the syntax tree generated is as follows: // // Ruleset -> Rule -> Value -> Expression -> Entity // // Here's some LESS code: // // .class { // color: #fff; // border: 1px solid #000; // width: @w + 4px; // > .child {...} // } // // And here's what the parse tree might look like: // // Ruleset (Selector '.class', [ // Rule ("color", Value ([Expression [Color #fff]])) // Rule ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]])) // Rule ("width", Value ([Expression [Operation "+" [Variable "@w"][Dimension 4px]]])) // Ruleset (Selector [Element '>', '.child'], [...]) // ]) // // In general, most rules will try to parse a token with the `$()` function, and if the return // value is truly, will return a new node, of the relevant type. Sometimes, we need to check // first, before parsing, that's when we use `peek()`. // parsers: { // // The `primary` rule is the *entry* and *exit* point of the parser. // The rules here can appear at any level of the parse tree. // // The recursive nature of the grammar is an interplay between the `block` // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule, // as represented by this simplified grammar: // // primary → (ruleset | rule)+ // ruleset → selector+ block // block → '{' primary '}' // // Only at one point is the primary rule not called from the // block rule: at the root level. // primary: function () { var node, root = []; while ((node = $(this.mixin.definition) || $(this.rule) || $(this.ruleset) || $(this.mixin.call) || $(this.comment) || $(this.directive)) || $(/^[\s\n]+/)) { node && root.push(node); } return root; }, // We create a Comment node for CSS comments `/* */`, // but keep the LeSS comments `//` silent, by just skipping // over them. comment: function () { var comment; if (input.charAt(i) !== '/') return; if (input.charAt(i + 1) === '/') { return new(tree.Comment)($(/^\/\/.*/), true); } else if (comment = $(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/)) { return new(tree.Comment)(comment); } }, // // Entities are tokens which can be found inside an Expression // entities: { // // A string, which supports escaping " and ' // // "milky way" 'he\'s the one!' // quoted: function () { var str, j = i, e; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '"' && input.charAt(j) !== "'") return; e && $('~'); if (str = $(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/)) { return new(tree.Quoted)(str[0], str[1] || str[2], e); } }, // // A catch-all word, such as: // // black border-collapse // keyword: function () { var k; if (k = $(/^[A-Za-z-]+/)) { return new(tree.Keyword)(k) } }, // // A function call // // rgb(255, 0, 255) // // We also try to catch IE's `alpha()`, but let the `alpha` parser // deal with the details. // // The arguments are parsed with the `entities.arguments` parser. // call: function () { var name, args, index = i; if (! (name = /^([\w-]+|%)\(/.exec(chunks[j]))) return; name = name[1].toLowerCase(); if (name === 'url') { return null } else { i += name.length } if (name === 'alpha') { return $(this.alpha) } $('('); // Parse the '(' and consume whitespace. args = $(this.entities.arguments); if (! $(')')) return; if (name) { return new(tree.Call)(name, args, index) } }, arguments: function () { var args = [], arg; while (arg = $(this.expression)) { args.push(arg); if (! $(',')) { break } } return args; }, literal: function () { return $(this.entities.dimension) || $(this.entities.color) || $(this.entities.quoted); }, // // Parse url() tokens // // We use a specific rule for urls, because they don't really behave like // standard function calls. The difference is that the argument doesn't have // to be enclosed within a string, so it can't be parsed as an Expression. // url: function () { var value; if (input.charAt(i) !== 'u' || !$(/^url\(/)) return; value = $(this.entities.quoted) || $(this.entities.variable) || $(this.entities.dataURI) || $(/^[-\w%@$\/.&=:;#+?~]+/) || ""; if (! $(')')) throw new(Error)("missing closing ) for url()"); return new(tree.URL)((value.value || value.data || value instanceof tree.Variable) ? value : new(tree.Anonymous)(value), imports.paths); }, dataURI: function () { var obj; if ($(/^data:/)) { obj = {}; obj.mime = $(/^[^\/]+\/[^,;)]+/) || ''; obj.charset = $(/^;\s*charset=[^,;)]+/) || ''; obj.base64 = $(/^;\s*base64/) || ''; obj.data = $(/^,\s*[^)]+/); if (obj.data) { return obj } } }, // // A Variable entity, such as `@fink`, in // // width: @fink + 2px // // We use a different parser for variable definitions, // see `parsers.variable`. // variable: function () { var name, index = i; if (input.charAt(i) === '@' && (name = $(/^@@?[\w-]+/))) { return new(tree.Variable)(name, index); } }, // // A Hexadecimal color // // #4F3C2F // // `rgb` and `hsl` colors are parsed through the `entities.call` parser. // color: function () { var rgb; if (input.charAt(i) === '#' && (rgb = $(/^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})/))) { return new(tree.Color)(rgb[1]); } }, // // A Dimension, that is, a number and a unit // // 0.5em 95% // dimension: function () { var value, c = input.charCodeAt(i); if ((c > 57 || c < 45) || c === 47) return; if (value = $(/^(-?\d*\.?\d+)(px|%|em|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn)?/)) { return new(tree.Dimension)(value[1], value[2]); } }, // // JavaScript code to be evaluated // // `window.location.href` // javascript: function () { var str, j = i, e; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '`') { return } e && $('~'); if (str = $(/^`([^`]*)`/)) { return new(tree.JavaScript)(str[1], i, e); } } }, // // The variable part of a variable definition. Used in the `rule` parser // // @fink: // variable: function () { var name; if (input.charAt(i) === '@' && (name = $(/^(@[\w-]+)\s*:/))) { return name[1] } }, // // A font size/line-height shorthand // // small/12px // // We need to peek first, or we'll match on keywords and dimensions // shorthand: function () { var a, b; if (! peek(/^[@\w.%-]+\/[@\w.-]+/)) return; if ((a = $(this.entity)) && $('/') && (b = $(this.entity))) { return new(tree.Shorthand)(a, b); } }, // // Mixins // mixin: { // // A Mixin call, with an optional argument list // // #mixins > .square(#fff); // .rounded(4px, black); // .button; // // The `while` loop is there because mixins can be // namespaced, but we only support the child and descendant // selector for now. // call: function () { var elements = [], e, c, args, index = i, s = input.charAt(i); if (s !== '.' && s !== '#') { return } while (e = $(/^[#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/)) { elements.push(new(tree.Element)(c, e)); c = $('>'); } $('(') && (args = $(this.entities.arguments)) && $(')'); if (elements.length > 0 && ($(';') || peek('}'))) { return new(tree.mixin.Call)(elements, args, index); } }, // // A Mixin definition, with a list of parameters // // .rounded (@radius: 2px, @color) { // ... // } // // Until we have a finer grained state-machine, we have to // do a look-ahead, to make sure we don't have a mixin call. // See the `rule` function for more information. // // We start by matching `.rounded (`, and then proceed on to // the argument list, which has optional default values. // We store the parameters in `params`, with a `value` key, // if there is a value, such as in the case of `@radius`. // // Once we've got our params list, and a closing `)`, we parse // the `{...}` block. // definition: function () { var name, params = [], match, ruleset, param, value; if ((input.charAt(i) !== '.' && input.charAt(i) !== '#') || peek(/^[^{]*(;|})/)) return; if (match = $(/^([#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+)\s*\(/)) { name = match[1]; while (param = $(this.entities.variable) || $(this.entities.literal) || $(this.entities.keyword)) { // Variable if (param instanceof tree.Variable) { if ($(':')) { if (value = $(this.expression)) { params.push({ name: param.name, value: value }); } else { throw new(Error)("Expected value"); } } else { params.push({ name: param.name }); } } else { params.push({ value: param }); } if (! $(',')) { break } } if (! $(')')) throw new(Error)("Expected )"); ruleset = $(this.block); if (ruleset) { return new(tree.mixin.Definition)(name, params, ruleset); } } } }, // // Entities are the smallest recognized token, // and can be found inside a rule's value. // entity: function () { return $(this.entities.literal) || $(this.entities.variable) || $(this.entities.url) || $(this.entities.call) || $(this.entities.keyword) || $(this.entities.javascript) || $(this.comment); }, // // A Rule terminator. Note that we use `peek()` to check for '}', // because the `block` rule will be expecting it, but we still need to make sure // it's there, if ';' was ommitted. // end: function () { return $(';') || peek('}'); }, // // IE's alpha function // // alpha(opacity=88) // alpha: function () { var value; if (! $(/^\(opacity=/i)) return; if (value = $(/^\d+/) || $(this.entities.variable)) { if (! $(')')) throw new(Error)("missing closing ) for alpha()"); return new(tree.Alpha)(value); } }, // // A Selector Element // // div // + h1 // #socks // input[type="text"] // // Elements are the building blocks for Selectors, // they are made out of a `Combinator` (see combinator rule), // and an element name, such as a tag a class, or `*`. // element: function () { var e, t, c; c = $(this.combinator); e = $(/^(?:[.#]?|:*)(?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/) || $('*') || $(this.attribute) || $(/^\([^)@]+\)/); if (e) { return new(tree.Element)(c, e) } }, // // Combinators combine elements together, in a Selector. // // Because our parser isn't white-space sensitive, special care // has to be taken, when parsing the descendant combinator, ` `, // as it's an empty space. We have to check the previous character // in the input, to see if it's a ` ` character. More info on how // we deal with this in *combinator.js*. // combinator: function () { var match, c = input.charAt(i); if (c === '>' || c === '&' || c === '+' || c === '~') { i++; while (input.charAt(i) === ' ') { i++ } return new(tree.Combinator)(c); } else if (c === ':' && input.charAt(i + 1) === ':') { i += 2; while (input.charAt(i) === ' ') { i++ } return new(tree.Combinator)('::'); } else if (input.charAt(i - 1) === ' ') { return new(tree.Combinator)(" "); } else { return new(tree.Combinator)(null); } }, // // A CSS Selector // // .class > div + h1 // li a:hover // // Selectors are made out of one or more Elements, see above. // selector: function () { var sel, e, elements = [], c, match; while (e = $(this.element)) { c = input.charAt(i); elements.push(e) if (c === '{' || c === '}' || c === ';' || c === ',') { break } } if (elements.length > 0) { return new(tree.Selector)(elements) } }, tag: function () { return $(/^[a-zA-Z][a-zA-Z-]*[0-9]?/) || $('*'); }, attribute: function () { var attr = '', key, val, op; if (! $('[')) return; if (key = $(/^[a-zA-Z-]+/) || $(this.entities.quoted)) { if ((op = $(/^[|~*$^]?=/)) && (val = $(this.entities.quoted) || $(/^[\w-]+/))) { attr = [key, op, val.toCSS ? val.toCSS() : val].join(''); } else { attr = key } } if (! $(']')) return; if (attr) { return "[" + attr + "]" } }, // // The `block` rule is used by `ruleset` and `mixin.definition`. // It's a wrapper around the `primary` rule, with added `{}`. // block: function () { var content; if ($('{') && (content = $(this.primary)) && $('}')) { return content; } }, // // div, .class, body > p {...} // ruleset: function () { var selectors = [], s, rules, match; save(); if (match = /^([.#: \w-]+)[\s\n]*\{/.exec(chunks[j])) { i += match[0].length - 1; selectors = [new(tree.Selector)([new(tree.Element)(null, match[1])])]; } else { while (s = $(this.selector)) { selectors.push(s); $(this.comment); if (! $(',')) { break } $(this.comment); } } if (selectors.length > 0 && (rules = $(this.block))) { return new(tree.Ruleset)(selectors, rules); } else { // Backtrack furthest = i; restore(); } }, rule: function () { var name, value, c = input.charAt(i), important, match; save(); if (c === '.' || c === '#' || c === '&') { return } if (name = $(this.variable) || $(this.property)) { if ((name.charAt(0) != '@') && (match = /^([^@+\/'"*`(;{}-]*);/.exec(chunks[j]))) { i += match[0].length - 1; value = new(tree.Anonymous)(match[1]); } else if (name === "font") { value = $(this.font); } else { value = $(this.value); } important = $(this.important); if (value && $(this.end)) { return new(tree.Rule)(name, value, important, memo); } else { furthest = i; restore(); } } }, // // An @import directive // // @import "lib"; // // Depending on our environemnt, importing is done differently: // In the browser, it's an XHR request, in Node, it would be a // file-system operation. The function used for importing is // stored in `import`, which we pass to the Import constructor. // "import": function () { var path; if ($(/^@import\s+/) && (path = $(this.entities.quoted) || $(this.entities.url)) && $(';')) { return new(tree.Import)(path, imports); } }, // // A CSS Directive // // @charset "utf-8"; // directive: function () { var name, value, rules, types; if (input.charAt(i) !== '@') return; if (value = $(this['import'])) { return value; } else if (name = $(/^@media|@page|@-[-a-z]+/)) { types = ($(/^[^{]+/) || '').trim(); if (rules = $(this.block)) { return new(tree.Directive)(name + " " + types, rules); } } else if (name = $(/^@[-a-z]+/)) { if (name === '@font-face') { if (rules = $(this.block)) { return new(tree.Directive)(name, rules); } } else if ((value = $(this.entity)) && $(';')) { return new(tree.Directive)(name, value); } } }, font: function () { var value = [], expression = [], weight, shorthand, font, e; while (e = $(this.shorthand) || $(this.entity)) { expression.push(e); } value.push(new(tree.Expression)(expression)); if ($(',')) { while (e = $(this.expression)) { value.push(e); if (! $(',')) { break } } } return new(tree.Value)(value); }, // // A Value is a comma-delimited list of Expressions // // font-family: Baskerville, Georgia, serif; // // In a Rule, a Value represents everything after the `:`, // and before the `;`. // value: function () { var e, expressions = [], important; while (e = $(this.expression)) { expressions.push(e); if (! $(',')) { break } } if (expressions.length > 0) { return new(tree.Value)(expressions); } }, important: function () { if (input.charAt(i) === '!') { return $(/^! *important/); } }, sub: function () { var e; if ($('(') && (e = $(this.expression)) && $(')')) { return e; } }, multiplication: function () { var m, a, op, operation; if (m = $(this.operand)) { while ((op = ($('/') || $('*'))) && (a = $(this.operand))) { operation = new(tree.Operation)(op, [operation || m, a]); } return operation || m; } }, addition: function () { var m, a, op, operation; if (m = $(this.multiplication)) { while ((op = $(/^[-+]\s+/) || (input.charAt(i - 1) != ' ' && ($('+') || $('-')))) && (a = $(this.multiplication))) { operation = new(tree.Operation)(op, [operation || m, a]); } return operation || m; } }, // // An operand is anything that can be part of an operation, // such as a Color, or a Variable // operand: function () { var negate, p = input.charAt(i + 1); if (input.charAt(i) === '-' && (p === '@' || p === '(')) { negate = $('-') } var o = $(this.sub) || $(this.entities.dimension) || $(this.entities.color) || $(this.entities.variable) || $(this.entities.call); return negate ? new(tree.Operation)('*', [new(tree.Dimension)(-1), o]) : o; }, // // Expressions either represent mathematical operations, // or white-space delimited Entities. // // 1px solid black // @var * 2 // expression: function () { var e, delim, entities = [], d; while (e = $(this.addition) || $(this.entity)) { entities.push(e); } if (entities.length > 0) { return new(tree.Expression)(entities); } }, property: function () { var name; if (name = $(/^(\*?-?[-a-z_0-9]+)\s*:/)) { return name[1]; } } } }; }; if (typeof(window) !== 'undefined') { // // Used by `@import` directives // less.Parser.importer = function (path, paths, callback, env) { if (path.charAt(0) !== '/' && paths.length > 0) { path = paths[0] + path; } // We pass `true` as 3rd argument, to force the reload of the import. // This is so we can get the syntax tree as opposed to just the CSS output, // as we need this to evaluate the current stylesheet. loadStyleSheet({ href: path, title: path, type: env.mime }, callback, true); }; } (function (tree) { tree.functions = { rgb: function (r, g, b) { return this.rgba(r, g, b, 1.0); }, rgba: function (r, g, b, a) { var rgb = [r, g, b].map(function (c) { return number(c) }), a = number(a); return new(tree.Color)(rgb, a); }, hsl: function (h, s, l) { return this.hsla(h, s, l, 1.0); }, hsla: function (h, s, l, a) { h = (number(h) % 360) / 360; s = number(s); l = number(l); a = number(a); var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s; var m1 = l * 2 - m2; return this.rgba(hue(h + 1/3) * 255, hue(h) * 255, hue(h - 1/3) * 255, a); function hue(h) { h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h); if (h * 6 < 1) return m1 + (m2 - m1) * h * 6; else if (h * 2 < 1) return m2; else if (h * 3 < 2) return m1 + (m2 - m1) * (2/3 - h) * 6; else return m1; } }, hue: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().h)); }, saturation: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().s * 100), '%'); }, lightness: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().l * 100), '%'); }, alpha: function (color) { return new(tree.Dimension)(color.toHSL().a); }, saturate: function (color, amount) { var hsl = color.toHSL(); hsl.s += amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, desaturate: function (color, amount) { var hsl = color.toHSL(); hsl.s -= amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, lighten: function (color, amount) { var hsl = color.toHSL(); hsl.l += amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, darken: function (color, amount) { var hsl = color.toHSL(); hsl.l -= amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, fadein: function (color, amount) { var hsl = color.toHSL(); hsl.a += amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, fadeout: function (color, amount) { var hsl = color.toHSL(); hsl.a -= amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, spin: function (color, amount) { var hsl = color.toHSL(); var hue = (hsl.h + amount.value) % 360; hsl.h = hue < 0 ? 360 + hue : hue; return hsla(hsl); }, // // Copyright (c) 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein // http://sass-lang.com // mix: function (color1, color2, weight) { var p = weight.value / 100.0; var w = p * 2 - 1; var a = color1.toHSL().a - color2.toHSL().a; var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0; var w2 = 1 - w1; var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2, color1.rgb[1] * w1 + color2.rgb[1] * w2, color1.rgb[2] * w1 + color2.rgb[2] * w2]; var alpha = color1.alpha * p + color2.alpha * (1 - p); return new(tree.Color)(rgb, alpha); }, greyscale: function (color) { return this.desaturate(color, new(tree.Dimension)(100)); }, e: function (str) { return new(tree.Anonymous)(str instanceof tree.JavaScript ? str.evaluated : str); }, escape: function (str) { return new(tree.Anonymous)(encodeURI(str.value).replace(/=/g, "%3D").replace(/:/g, "%3A").replace(/#/g, "%23").replace(/;/g, "%3B").replace(/\(/g, "%28").replace(/\)/g, "%29")); }, '%': function (quoted /* arg, arg, ...*/) { var args = Array.prototype.slice.call(arguments, 1), str = quoted.value; for (var i = 0; i < args.length; i++) { str = str.replace(/%[sda]/i, function(token) { var value = token.match(/s/i) ? args[i].value : args[i].toCSS(); return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value; }); } str = str.replace(/%%/g, '%'); return new(tree.Quoted)('"' + str + '"', str); }, round: function (n) { if (n instanceof tree.Dimension) { return new(tree.Dimension)(Math.round(number(n)), n.unit); } else if (typeof(n) === 'number') { return Math.round(n); } else { throw { error: "RuntimeError", message: "math functions take numbers as parameters" }; } } }; function hsla(hsla) { return tree.functions.hsla(hsla.h, hsla.s, hsla.l, hsla.a); } function number(n) { if (n instanceof tree.Dimension) { return parseFloat(n.unit == '%' ? n.value / 100 : n.value); } else if (typeof(n) === 'number') { return n; } else { throw { error: "RuntimeError", message: "color functions take numbers as parameters" }; } } function clamp(val) { return Math.min(1, Math.max(0, val)); } })(require('less/tree')); (function (tree) { tree.Alpha = function (val) { this.value = val; }; tree.Alpha.prototype = { toCSS: function () { return "alpha(opacity=" + (this.value.toCSS ? this.value.toCSS() : this.value) + ")"; }, eval: function (env) { if (this.value.eval) { this.value = this.value.eval(env) } return this; } }; })(require('less/tree')); (function (tree) { tree.Anonymous = function (string) { this.value = string.value || string; }; tree.Anonymous.prototype = { toCSS: function () { return this.value; }, eval: function () { return this } }; })(require('less/tree')); (function (tree) { // // A function call node. // tree.Call = function (name, args, index) { this.name = name; this.args = args; this.index = index; }; tree.Call.prototype = { // // When evaluating a function call, // we either find the function in `tree.functions` [1], // in which case we call it, passing the evaluated arguments, // or we simply print it out as it appeared originally [2]. // // The *functions.js* file contains the built-in functions. // // The reason why we evaluate the arguments, is in the case where // we try to pass a variable to a function, like: `saturate(@color)`. // The function should receive the value, not the variable. // eval: function (env) { var args = this.args.map(function (a) { return a.eval(env) }); if (this.name in tree.functions) { // 1. try { return tree.functions[this.name].apply(tree.functions, args); } catch (e) { throw { message: "error evaluating function `" + this.name + "`", index: this.index }; } } else { // 2. return new(tree.Anonymous)(this.name + "(" + args.map(function (a) { return a.toCSS() }).join(', ') + ")"); } }, toCSS: function (env) { return this.eval(env).toCSS(); } }; })(require('less/tree')); (function (tree) { // // RGB Colors - #ff0014, #eee // tree.Color = function (rgb, a) { // // The end goal here, is to parse the arguments // into an integer triplet, such as `128, 255, 0` // // This facilitates operations and conversions. // if (Array.isArray(rgb)) { this.rgb = rgb; } else if (rgb.length == 6) { this.rgb = rgb.match(/.{2}/g).map(function (c) { return parseInt(c, 16); }); } else if (rgb.length == 8) { this.alpha = parseInt(rgb.substring(0,2), 16) / 255.0; this.rgb = rgb.substr(2).match(/.{2}/g).map(function (c) { return parseInt(c, 16); }); } else { this.rgb = rgb.split('').map(function (c) { return parseInt(c + c, 16); }); } this.alpha = typeof(a) === 'number' ? a : 1; }; tree.Color.prototype = { eval: function () { return this }, // // If we have some transparency, the only way to represent it // is via `rgba`. Otherwise, we use the hex representation, // which has better compatibility with older browsers. // Values are capped between `0` and `255`, rounded and zero-padded. // toCSS: function () { if (this.alpha < 1.0) { return "rgba(" + this.rgb.map(function (c) { return Math.round(c); }).concat(this.alpha).join(', ') + ")"; } else { return '#' + this.rgb.map(function (i) { i = Math.round(i); i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16); return i.length === 1 ? '0' + i : i; }).join(''); } }, // // Operations have to be done per-channel, if not, // channels will spill onto each other. Once we have // our result, in the form of an integer triplet, // we create a new Color node to hold the result. // operate: function (op, other) { var result = []; if (! (other instanceof tree.Color)) { other = other.toColor(); } for (var c = 0; c < 3; c++) { result[c] = tree.operate(op, this.rgb[c], other.rgb[c]); } return new(tree.Color)(result, this.alpha + other.alpha); }, toHSL: function () { var r = this.rgb[0] / 255, g = this.rgb[1] / 255, b = this.rgb[2] / 255, a = this.alpha; var max = Math.max(r, g, b), min = Math.min(r, g, b); var h, s, l = (max + min) / 2, d = max - min; if (max === min) { h = s = 0; } else { s = l > 0.5 ? d / (2 - max - min) : d / (max + min); switch (max) { case r: h = (g - b) / d + (g < b ? 6 : 0); break; case g: h = (b - r) / d + 2; break; case b: h = (r - g) / d + 4; break; } h /= 6; } return { h: h * 360, s: s, l: l, a: a }; } }; })(require('less/tree')); (function (tree) { tree.Comment = function (value, silent) { this.value = value; this.silent = !!silent; }; tree.Comment.prototype = { toCSS: function (env) { return env.compress ? '' : this.value; }, eval: function () { return this } }; })(require('less/tree')); (function (tree) { // // A number with a unit // tree.Dimension = function (value, unit) { this.value = parseFloat(value); this.unit = unit || null; }; tree.Dimension.prototype = { eval: function () { return this }, toColor: function () { return new(tree.Color)([this.value, this.value, this.value]); }, toCSS: function () { var css = this.value + this.unit; return css; }, // In an operation between two Dimensions, // we default to the first Dimension's unit, // so `1px + 2em` will yield `3px`. // In the future, we could implement some unit // conversions such that `100cm + 10mm` would yield // `101cm`. operate: function (op, other) { return new(tree.Dimension) (tree.operate(op, this.value, other.value), this.unit || other.unit); } }; })(require('less/tree')); (function (tree) { tree.Directive = function (name, value) { this.name = name; if (Array.isArray(value)) { this.ruleset = new(tree.Ruleset)([], value); } else { this.value = value; } }; tree.Directive.prototype = { toCSS: function (ctx, env) { if (this.ruleset) { this.ruleset.root = true; return this.name + (env.compress ? '{' : ' {\n ') + this.ruleset.toCSS(ctx, env).trim().replace(/\n/g, '\n ') + (env.compress ? '}': '\n}\n'); } else { return this.name + ' ' + this.value.toCSS() + ';\n'; } }, eval: function (env) { env.frames.unshift(this); this.ruleset = this.ruleset && this.ruleset.eval(env); env.frames.shift(); return this; }, variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) }, find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) }, rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) } }; })(require('less/tree')); (function (tree) { tree.Element = function (combinator, value) { this.combinator = combinator instanceof tree.Combinator ? combinator : new(tree.Combinator)(combinator); this.value = value.trim(); }; tree.Element.prototype.toCSS = function (env) { return this.combinator.toCSS(env || {}) + this.value; }; tree.Combinator = function (value) { if (value === ' ') { this.value = ' '; } else { this.value = value ? value.trim() : ""; } }; tree.Combinator.prototype.toCSS = function (env) { return { '' : '', ' ' : ' ', '&' : '', ':' : ' :', '::': '::', '+' : env.compress ? '+' : ' + ', '~' : env.compress ? '~' : ' ~ ', '>' : env.compress ? '>' : ' > ' }[this.value]; }; })(require('less/tree')); (function (tree) { tree.Expression = function (value) { this.value = value }; tree.Expression.prototype = { eval: function (env) { if (this.value.length > 1) { return new(tree.Expression)(this.value.map(function (e) { return e.eval(env); })); } else if (this.value.length === 1) { return this.value[0].eval(env); } else { return this; } }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS(env); }).join(' '); } }; })(require('less/tree')); (function (tree) { // // CSS @import node // // The general strategy here is that we don't want to wait // for the parsing to be completed, before we start importing // the file. That's because in the context of a browser, // most of the time will be spent waiting for the server to respond. // // On creation, we push the import path to our import queue, though // `import,push`, we also pass it a callback, which it'll call once // the file has been fetched, and parsed. // tree.Import = function (path, imports) { var that = this; this._path = path; // The '.less' extension is optional if (path instanceof tree.Quoted) { this.path = /\.(le?|c)ss$/.test(path.value) ? path.value : path.value + '.less'; } else { this.path = path.value.value || path.value; } this.css = /css$/.test(this.path); // Only pre-compile .less files if (! this.css) { imports.push(this.path, function (root) { if (! root) { throw new(Error)("Error parsing " + that.path); } that.root = root; }); } }; // // The actual import node doesn't return anything, when converted to CSS. // The reason is that it's used at the evaluation stage, so that the rules // it imports can be treated like any other rules. // // In `eval`, we make sure all Import nodes get evaluated, recursively, so // we end up with a flat structure, which can easily be imported in the parent // ruleset. // tree.Import.prototype = { toCSS: function () { if (this.css) { return "@import " + this._path.toCSS() + ';\n'; } else { return ""; } }, eval: function (env) { var ruleset; if (this.css) { return this; } else { ruleset = new(tree.Ruleset)(null, this.root.rules.slice(0)); for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.Import) { Array.prototype .splice .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env))); } } return ruleset.rules; } } }; })(require('less/tree')); (function (tree) { tree.JavaScript = function (string, index, escaped) { this.escaped = escaped; this.expression = string; this.index = index; }; tree.JavaScript.prototype = { eval: function (env) { var result, that = this, context = {}; var expression = this.expression.replace(/@\{([\w-]+)\}/g, function (_, name) { return tree.jsify(new(tree.Variable)('@' + name, that.index).eval(env)); }); try { expression = new(Function)('return (' + expression + ')'); } catch (e) { throw { message: "JavaScript evaluation error: `" + expression + "`" , index: this.index }; } for (var k in env.frames[0].variables()) { context[k.slice(1)] = { value: env.frames[0].variables()[k].value, toJS: function () { return this.value.eval(env).toCSS(); } }; } try { result = expression.call(context); } catch (e) { throw { message: "JavaScript evaluation error: '" + e.name + ': ' + e.message + "'" , index: this.index }; } if (typeof(result) === 'string') { return new(tree.Quoted)('"' + result + '"', result, this.escaped, this.index); } else if (Array.isArray(result)) { return new(tree.Anonymous)(result.join(', ')); } else { return new(tree.Anonymous)(result); } } }; })(require('less/tree')); (function (tree) { tree.Keyword = function (value) { this.value = value }; tree.Keyword.prototype = { eval: function () { return this }, toCSS: function () { return this.value } }; })(require('less/tree')); (function (tree) { tree.mixin = {}; tree.mixin.Call = function (elements, args, index) { this.selector = new(tree.Selector)(elements); this.arguments = args; this.index = index; }; tree.mixin.Call.prototype = { eval: function (env) { var mixins, args, rules = [], match = false; for (var i = 0; i < env.frames.length; i++) { if ((mixins = env.frames[i].find(this.selector)).length > 0) { args = this.arguments && this.arguments.map(function (a) { return a.eval(env) }); for (var m = 0; m < mixins.length; m++) { if (mixins[m].match(args, env)) { try { Array.prototype.push.apply( rules, mixins[m].eval(env, this.arguments).rules); match = true; } catch (e) { throw { message: e.message, index: e.index, stack: e.stack, call: this.index }; } } } if (match) { return rules; } else { throw { message: 'No matching definition was found for `' + this.selector.toCSS().trim() + '(' + this.arguments.map(function (a) { return a.toCSS(); }).join(', ') + ")`", index: this.index }; } } } throw { message: this.selector.toCSS().trim() + " is undefined", index: this.index }; } }; tree.mixin.Definition = function (name, params, rules) { this.name = name; this.selectors = [new(tree.Selector)([new(tree.Element)(null, name)])]; this.params = params; this.arity = params.length; this.rules = rules; this._lookups = {}; this.required = params.reduce(function (count, p) { if (!p.name || (p.name && !p.value)) { return count + 1 } else { return count } }, 0); this.parent = tree.Ruleset.prototype; this.frames = []; }; tree.mixin.Definition.prototype = { toCSS: function () { return "" }, variable: function (name) { return this.parent.variable.call(this, name) }, variables: function () { return this.parent.variables.call(this) }, find: function () { return this.parent.find.apply(this, arguments) }, rulesets: function () { return this.parent.rulesets.apply(this) }, eval: function (env, args) { var frame = new(tree.Ruleset)(null, []), context, _arguments = []; for (var i = 0, val; i < this.params.length; i++) { if (this.params[i].name) { if (val = (args && args[i]) || this.params[i].value) { frame.rules.unshift(new(tree.Rule)(this.params[i].name, val.eval(env))); } else { throw { message: "wrong number of arguments for " + this.name + ' (' + args.length + ' for ' + this.arity + ')' }; } } } for (var i = 0; i < Math.max(this.params.length, args && args.length); i++) { _arguments.push(args[i] || this.params[i].value); } frame.rules.unshift(new(tree.Rule)('@arguments', new(tree.Expression)(_arguments).eval(env))); return new(tree.Ruleset)(null, this.rules.slice(0)).eval({ frames: [this, frame].concat(this.frames, env.frames) }); }, match: function (args, env) { var argsLength = (args && args.length) || 0, len; if (argsLength < this.required) { return false } if ((this.required > 0) && (argsLength > this.params.length)) { return false } len = Math.min(argsLength, this.arity); for (var i = 0; i < len; i++) { if (!this.params[i].name) { if (args[i].eval(env).toCSS() != this.params[i].value.eval(env).toCSS()) { return false; } } } return true; } }; })(require('less/tree')); (function (tree) { tree.Operation = function (op, operands) { this.op = op.trim(); this.operands = operands; }; tree.Operation.prototype.eval = function (env) { var a = this.operands[0].eval(env), b = this.operands[1].eval(env), temp; if (a instanceof tree.Dimension && b instanceof tree.Color) { if (this.op === '*' || this.op === '+') { temp = b, b = a, a = temp; } else { throw { name: "OperationError", message: "Can't substract or divide a color from a number" }; } } return a.operate(this.op, b); }; tree.operate = function (op, a, b) { switch (op) { case '+': return a + b; case '-': return a - b; case '*': return a * b; case '/': return a / b; } }; })(require('less/tree')); (function (tree) { tree.Quoted = function (str, content, escaped, i) { this.escaped = escaped; this.value = content || ''; this.quote = str.charAt(0); this.index = i; }; tree.Quoted.prototype = { toCSS: function () { if (this.escaped) { return this.value; } else { return this.quote + this.value + this.quote; } }, eval: function (env) { var that = this; var value = this.value.replace(/`([^`]+)`/g, function (_, exp) { return new(tree.JavaScript)(exp, that.index, true).eval(env).value; }).replace(/@\{([\w-]+)\}/g, function (_, name) { var v = new(tree.Variable)('@' + name, that.index).eval(env); return v.value || v.toCSS(); }); return new(tree.Quoted)(this.quote + value + this.quote, value, this.escaped, this.index); } }; })(require('less/tree')); (function (tree) { tree.Rule = function (name, value, important, index) { this.name = name; this.value = (value instanceof tree.Value) ? value : new(tree.Value)([value]); this.important = important ? ' ' + important.trim() : ''; this.index = index; if (name.charAt(0) === '@') { this.variable = true; } else { this.variable = false } }; tree.Rule.prototype.toCSS = function (env) { if (this.variable) { return "" } else { return this.name + (env.compress ? ':' : ': ') + this.value.toCSS(env) + this.important + ";"; } }; tree.Rule.prototype.eval = function (context) { return new(tree.Rule)(this.name, this.value.eval(context), this.important, this.index); }; tree.Shorthand = function (a, b) { this.a = a; this.b = b; }; tree.Shorthand.prototype = { toCSS: function (env) { return this.a.toCSS(env) + "/" + this.b.toCSS(env); }, eval: function () { return this } }; })(require('less/tree')); (function (tree) { tree.Ruleset = function (selectors, rules) { this.selectors = selectors; this.rules = rules; this._lookups = {}; }; tree.Ruleset.prototype = { eval: function (env) { var ruleset = new(tree.Ruleset)(this.selectors, this.rules.slice(0)); ruleset.root = this.root; // push the current ruleset to the frames stack env.frames.unshift(ruleset); // Evaluate imports if (ruleset.root) { for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.Import) { Array.prototype.splice .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env))); } } } // Store the frames around mixin definitions, // so they can be evaluated like closures when the time comes. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Definition) { ruleset.rules[i].frames = env.frames.slice(0); } } // Evaluate mixin calls. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Call) { Array.prototype.splice .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env))); } } // Evaluate everything else for (var i = 0, rule; i < ruleset.rules.length; i++) { rule = ruleset.rules[i]; if (! (rule instanceof tree.mixin.Definition)) { ruleset.rules[i] = rule.eval ? rule.eval(env) : rule; } } // Pop the stack env.frames.shift(); return ruleset; }, match: function (args) { return !args || args.length === 0; }, variables: function () { if (this._variables) { return this._variables } else { return this._variables = this.rules.reduce(function (hash, r) { if (r instanceof tree.Rule && r.variable === true) { hash[r.name] = r; } return hash; }, {}); } }, variable: function (name) { return this.variables()[name]; }, rulesets: function () { if (this._rulesets) { return this._rulesets } else { return this._rulesets = this.rules.filter(function (r) { return (r instanceof tree.Ruleset) || (r instanceof tree.mixin.Definition); }); } }, find: function (selector, self) { self = self || this; var rules = [], rule, match, key = selector.toCSS(); if (key in this._lookups) { return this._lookups[key] } this.rulesets().forEach(function (rule) { if (rule !== self) { for (var j = 0; j < rule.selectors.length; j++) { if (match = selector.match(rule.selectors[j])) { if (selector.elements.length > 1) { Array.prototype.push.apply(rules, rule.find( new(tree.Selector)(selector.elements.slice(1)), self)); } else { rules.push(rule); } break; } } } }); return this._lookups[key] = rules; }, // // Entry point for code generation // // `context` holds an array of arrays. // toCSS: function (context, env) { var css = [], // The CSS output rules = [], // node.Rule instances rulesets = [], // node.Ruleset instances paths = [], // Current selectors selector, // The fully rendered selector rule; if (! this.root) { if (context.length === 0) { paths = this.selectors.map(function (s) { return [s] }); } else { for (var s = 0; s < this.selectors.length; s++) { for (var c = 0; c < context.length; c++) { paths.push(context[c].concat([this.selectors[s]])); } } } } // Compile rules and rulesets for (var i = 0; i < this.rules.length; i++) { rule = this.rules[i]; if (rule.rules || (rule instanceof tree.Directive)) { rulesets.push(rule.toCSS(paths, env)); } else if (rule instanceof tree.Comment) { if (!rule.silent) { if (this.root) { rulesets.push(rule.toCSS(env)); } else { rules.push(rule.toCSS(env)); } } } else { if (rule.toCSS && !rule.variable) { rules.push(rule.toCSS(env)); } else if (rule.value && !rule.variable) { rules.push(rule.value.toString()); } } } rulesets = rulesets.join(''); // If this is the root node, we don't render // a selector, or {}. // Otherwise, only output if this ruleset has rules. if (this.root) { css.push(rules.join(env.compress ? '' : '\n')); } else { if (rules.length > 0) { selector = paths.map(function (p) { return p.map(function (s) { return s.toCSS(env); }).join('').trim(); }).join(env.compress ? ',' : (paths.length > 3 ? ',\n' : ', ')); css.push(selector, (env.compress ? '{' : ' {\n ') + rules.join(env.compress ? '' : '\n ') + (env.compress ? '}' : '\n}\n')); } } css.push(rulesets); return css.join('') + (env.compress ? '\n' : ''); } }; })(require('less/tree')); (function (tree) { tree.Selector = function (elements) { this.elements = elements; if (this.elements[0].combinator.value === "") { this.elements[0].combinator.value = ' '; } }; tree.Selector.prototype.match = function (other) { if (this.elements[0].value === other.elements[0].value) { return true; } else { return false; } }; tree.Selector.prototype.toCSS = function (env) { if (this._css) { return this._css } return this._css = this.elements.map(function (e) { if (typeof(e) === 'string') { return ' ' + e.trim(); } else { return e.toCSS(env); } }).join(''); }; })(require('less/tree')); (function (tree) { tree.URL = function (val, paths) { if (val.data) { this.attrs = val; } else { // Add the base path if the URL is relative and we are in the browser if (!/^(?:https?:\/|file:\/|data:\/)?\//.test(val.value) && paths.length > 0 && typeof(window) !== 'undefined') { val.value = paths[0] + (val.value.charAt(0) === '/' ? val.value.slice(1) : val.value); } this.value = val; this.paths = paths; } }; tree.URL.prototype = { toCSS: function () { return "url(" + (this.attrs ? 'data:' + this.attrs.mime + this.attrs.charset + this.attrs.base64 + this.attrs.data : this.value.toCSS()) + ")"; }, eval: function (ctx) { return this.attrs ? this : new(tree.URL)(this.value.eval(ctx), this.paths); } }; })(require('less/tree')); (function (tree) { tree.Value = function (value) { this.value = value; this.is = 'value'; }; tree.Value.prototype = { eval: function (env) { if (this.value.length === 1) { return this.value[0].eval(env); } else { return new(tree.Value)(this.value.map(function (v) { return v.eval(env); })); } }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS(env); }).join(env.compress ? ',' : ', '); } }; })(require('less/tree')); (function (tree) { tree.Variable = function (name, index) { this.name = name, this.index = index }; tree.Variable.prototype = { eval: function (env) { var variable, v, name = this.name; if (name.indexOf('@@') == 0) { name = '@' + new(tree.Variable)(name.slice(1)).eval(env).value; } if (variable = tree.find(env.frames, function (frame) { if (v = frame.variable(name)) { return v.value.eval(env); } })) { return variable } else { throw { message: "variable " + name + " is undefined", index: this.index }; } } }; })(require('less/tree')); require('less/tree').find = function (obj, fun) { for (var i = 0, r; i < obj.length; i++) { if (r = fun.call(obj, obj[i])) { return r } } return null; }; require('less/tree').jsify = function (obj) { if (Array.isArray(obj.value) && (obj.value.length > 1)) { return '[' + obj.value.map(function (v) { return v.toCSS(false) }).join(', ') + ']'; } else { return obj.toCSS(false); } }; // // browser.js - client-side engine // var isFileProtocol = (location.protocol === 'file:' || location.protocol === 'chrome:' || location.protocol === 'chrome-extension:' || location.protocol === 'resource:'); less.env = less.env || (location.hostname == '127.0.0.1' || location.hostname == '0.0.0.0' || location.hostname == 'localhost' || location.port.length > 0 || isFileProtocol ? 'development' : 'production'); // Load styles asynchronously (default: false) // // This is set to `false` by default, so that the body // doesn't start loading before the stylesheets are parsed. // Setting this to `true` can result in flickering. // less.async = false; // Interval between watch polls less.poll = less.poll || (isFileProtocol ? 1000 : 1500); // // Watch mode // less.watch = function () { return this.watchMode = true }; less.unwatch = function () { return this.watchMode = false }; if (less.env === 'development') { less.optimization = 0; if (/!watch/.test(location.hash)) { less.watch(); } less.watchTimer = setInterval(function () { if (less.watchMode) { loadStyleSheets(function (root, sheet, env) { if (root) { createCSS(root.toCSS(), sheet, env.lastModified); } }); } }, less.poll); } else { less.optimization = 3; } var cache; try { cache = (typeof(window.localStorage) === 'undefined') ? null : window.localStorage; } catch (_) { cache = null; } // // Get all tags with the 'rel' attribute set to "stylesheet/less" // var links = document.getElementsByTagName('link'); var typePattern = /^text\/(x-)?less$/; less.sheets = []; for (var i = 0; i < links.length; i++) { if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) && (links[i].type.match(typePattern)))) { less.sheets.push(links[i]); } } less.refresh = function (reload) { var startTime, endTime; startTime = endTime = new(Date); loadStyleSheets(function (root, sheet, env) { if (env.local) { log("loading " + sheet.href + " from cache."); } else { log("parsed " + sheet.href + " successfully."); createCSS(root.toCSS(), sheet, env.lastModified); } log("css for " + sheet.href + " generated in " + (new(Date) - endTime) + 'ms'); (env.remaining === 0) && log("css generated in " + (new(Date) - startTime) + 'ms'); endTime = new(Date); }, reload); loadStyles(); }; less.refreshStyles = loadStyles; less.refresh(less.env === 'development'); function loadStyles() { var styles = document.getElementsByTagName('style'); for (var i = 0; i < styles.length; i++) { if (styles[i].type.match(typePattern)) { new(less.Parser)().parse(styles[i].innerHTML || '', function (e, tree) { styles[i].type = 'text/css'; styles[i].innerHTML = tree.toCSS(); }); } } } function loadStyleSheets(callback, reload) { for (var i = 0; i < less.sheets.length; i++) { loadStyleSheet(less.sheets[i], callback, reload, less.sheets.length - (i + 1)); } } function loadStyleSheet(sheet, callback, reload, remaining) { var url = window.location.href.replace(/[#?].*$/, ''); var href = sheet.href.replace(/\?.*$/, ''); var css = cache && cache.getItem(href); var timestamp = cache && cache.getItem(href + ':timestamp'); var styles = { css: css, timestamp: timestamp }; // Stylesheets in IE don't always return the full path if (! /^(https?|file):/.test(href)) { if (href.charAt(0) == "/") { href = window.location.protocol + "//" + window.location.host + href; } else { href = url.slice(0, url.lastIndexOf('/') + 1) + href; } } xhr(sheet.href, sheet.type, function (data, lastModified) { if (!reload && styles && lastModified && (new(Date)(lastModified).valueOf() === new(Date)(styles.timestamp).valueOf())) { // Use local copy createCSS(styles.css, sheet); callback(null, sheet, { local: true, remaining: remaining }); } else { // Use remote copy (re-parse) try { new(less.Parser)({ optimization: less.optimization, paths: [href.replace(/[\w\.-]+$/, '')], mime: sheet.type }).parse(data, function (e, root) { if (e) { return error(e, href) } try { callback(root, sheet, { local: false, lastModified: lastModified, remaining: remaining }); removeNode(document.getElementById('less-error-message:' + extractId(href))); } catch (e) { error(e, href); } }); } catch (e) { error(e, href); } } }, function (status, url) { throw new(Error)("Couldn't load " + url + " (" + status + ")"); }); } function extractId(href) { return href.replace(/^[a-z]+:\/\/?[^\/]+/, '' ) // Remove protocol & domain .replace(/^\//, '' ) // Remove root / .replace(/\?.*$/, '' ) // Remove query .replace(/\.[^\.\/]+$/, '' ) // Remove file extension .replace(/[^\.\w-]+/g, '-') // Replace illegal characters .replace(/\./g, ':'); // Replace dots with colons(for valid id) } function createCSS(styles, sheet, lastModified) { var css; // Strip the query-string var href = sheet.href ? sheet.href.replace(/\?.*$/, '') : ''; // If there is no title set, use the filename, minus the extension var id = 'less:' + (sheet.title || extractId(href)); // If the stylesheet doesn't exist, create a new node if ((css = document.getElementById(id)) === null) { css = document.createElement('style'); css.type = 'text/css'; css.media = sheet.media || 'screen'; css.id = id; document.getElementsByTagName('head')[0].appendChild(css); } if (css.styleSheet) { // IE try { css.styleSheet.cssText = styles; } catch (e) { throw new(Error)("Couldn't reassign styleSheet.cssText."); } } else { (function (node) { if (css.childNodes.length > 0) { if (css.firstChild.nodeValue !== node.nodeValue) { css.replaceChild(node, css.firstChild); } } else { css.appendChild(node); } })(document.createTextNode(styles)); } // Don't update the local store if the file wasn't modified if (lastModified && cache) { log('saving ' + href + ' to cache.'); cache.setItem(href, styles); cache.setItem(href + ':timestamp', lastModified); } } function xhr(url, type, callback, errback) { var xhr = getXMLHttpRequest(); var async = isFileProtocol ? false : less.async; if (typeof(xhr.overrideMimeType) === 'function') { xhr.overrideMimeType('text/css'); } xhr.open('GET', url, async); xhr.setRequestHeader('Accept', type || 'text/x-less, text/css; q=0.9, */*; q=0.5'); xhr.send(null); if (isFileProtocol) { if (xhr.status === 0) { callback(xhr.responseText); } else { errback(xhr.status, url); } } else if (async) { xhr.onreadystatechange = function () { if (xhr.readyState == 4) { handleResponse(xhr, callback, errback); } }; } else { handleResponse(xhr, callback, errback); } function handleResponse(xhr, callback, errback) { if (xhr.status >= 200 && xhr.status < 300) { callback(xhr.responseText, xhr.getResponseHeader("Last-Modified")); } else if (typeof(errback) === 'function') { errback(xhr.status, url); } } } function getXMLHttpRequest() { if (window.XMLHttpRequest) { return new(XMLHttpRequest); } else { try { return new(ActiveXObject)("MSXML2.XMLHTTP.3.0"); } catch (e) { log("browser doesn't support AJAX."); return null; } } } function removeNode(node) { return node && node.parentNode.removeChild(node); } function log(str) { if (less.env == 'development' && typeof(console) !== "undefined") { console.log('less: ' + str) } } function error(e, href) { var id = 'less-error-message:' + extractId(href); var template = ['
    ', '
  • {0}
  • ', '
  • {current}
  • ', '
  • {2}
  • ', '
'].join('\n'); var elem = document.createElement('div'), timer, content; elem.id = id; elem.className = "less-error-message"; content = '

' + (e.message || 'There is an error in your .less file') + '

' + '

' + href + " "; if (e.extract) { content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':

' + template.replace(/\[(-?\d)\]/g, function (_, i) { return (parseInt(e.line) + parseInt(i)) || ''; }).replace(/\{(\d)\}/g, function (_, i) { return e.extract[parseInt(i)] || ''; }).replace(/\{current\}/, e.extract[1].slice(0, e.column) + '' + e.extract[1].slice(e.column) + ''); } elem.innerHTML = content; // CSS for error messages createCSS([ '.less-error-message ul, .less-error-message li {', 'list-style-type: none;', 'margin-right: 15px;', 'padding: 4px 0;', 'margin: 0;', '}', '.less-error-message label {', 'font-size: 12px;', 'margin-right: 15px;', 'padding: 4px 0;', 'color: #cc7777;', '}', '.less-error-message pre {', 'color: #ee4444;', 'padding: 4px 0;', 'margin: 0;', 'display: inline-block;', '}', '.less-error-message pre.ctx {', 'color: #dd4444;', '}', '.less-error-message h3 {', 'font-size: 20px;', 'font-weight: bold;', 'padding: 15px 0 5px 0;', 'margin: 0;', '}', '.less-error-message a {', 'color: #10a', '}', '.less-error-message .error {', 'color: red;', 'font-weight: bold;', 'padding-bottom: 2px;', 'border-bottom: 1px dashed red;', '}' ].join('\n'), { title: 'error-message' }); elem.style.cssText = [ "font-family: Arial, sans-serif", "border: 1px solid #e00", "background-color: #eee", "border-radius: 5px", "-webkit-border-radius: 5px", "-moz-border-radius: 5px", "color: #e00", "padding: 15px", "margin-bottom: 15px" ].join(';'); if (less.env == 'development') { timer = setInterval(function () { if (document.body) { if (document.getElementById(id)) { document.body.replaceChild(elem, document.getElementById(id)); } else { document.body.insertBefore(elem, document.body.firstChild); } clearInterval(timer); } }, 10); } } })(window); less.js-1.4.2/dist/less-1.1.3.min.js000066400000000000000000001037431217256642200166050ustar00rootroot00000000000000// // LESS - Leaner CSS v1.1.3 // http://lesscss.org // // Copyright (c) 2009-2011, Alexis Sellier // Licensed under the Apache 2.0 License. // // // LESS - Leaner CSS v1.1.3 // http://lesscss.org // // Copyright (c) 2009-2011, Alexis Sellier // Licensed under the Apache 2.0 License. // (function(a,b){function v(a,b){var c="less-error-message:"+p(b),e=["
    ",'
  • {0}
  • ',"
  • {current}
  • ",'
  • {2}
  • ',"
"].join("\n"),f=document.createElement("div"),g,h;f.id=c,f.className="less-error-message",h="

"+(a.message||"There is an error in your .less file")+"

"+'

'+b+" ",a.extract&&(h+="on line "+a.line+", column "+(a.column+1)+":

"+e.replace(/\[(-?\d)\]/g,function(b,c){return parseInt(a.line)+parseInt(c)||""}).replace(/\{(\d)\}/g,function(b,c){return a.extract[parseInt(c)]||""}).replace(/\{current\}/,a.extract[1].slice(0,a.column)+''+a.extract[1].slice(a.column)+"")),f.innerHTML=h,q([".less-error-message ul, .less-error-message li {","list-style-type: none;","margin-right: 15px;","padding: 4px 0;","margin: 0;","}",".less-error-message label {","font-size: 12px;","margin-right: 15px;","padding: 4px 0;","color: #cc7777;","}",".less-error-message pre {","color: #ee4444;","padding: 4px 0;","margin: 0;","display: inline-block;","}",".less-error-message pre.ctx {","color: #dd4444;","}",".less-error-message h3 {","font-size: 20px;","font-weight: bold;","padding: 15px 0 5px 0;","margin: 0;","}",".less-error-message a {","color: #10a","}",".less-error-message .error {","color: red;","font-weight: bold;","padding-bottom: 2px;","border-bottom: 1px dashed red;","}"].join("\n"),{title:"error-message"}),f.style.cssText=["font-family: Arial, sans-serif","border: 1px solid #e00","background-color: #eee","border-radius: 5px","-webkit-border-radius: 5px","-moz-border-radius: 5px","color: #e00","padding: 15px","margin-bottom: 15px"].join(";"),d.env=="development"&&(g=setInterval(function(){document.body&&(document.getElementById(c)?document.body.replaceChild(f,document.getElementById(c)):document.body.insertBefore(f,document.body.firstChild),clearInterval(g))},10))}function u(a){d.env=="development"&&typeof console!="undefined"&&console.log("less: "+a)}function t(a){return a&&a.parentNode.removeChild(a)}function s(){if(a.XMLHttpRequest)return new XMLHttpRequest;try{return new ActiveXObject("MSXML2.XMLHTTP.3.0")}catch(b){u("browser doesn't support AJAX.");return null}}function r(a,b,c,e){function i(b,c,d){b.status>=200&&b.status<300?c(b.responseText,b.getResponseHeader("Last-Modified")):typeof d=="function"&&d(b.status,a)}var f=s(),h=g?!1:d.async;typeof f.overrideMimeType=="function"&&f.overrideMimeType("text/css"),f.open("GET",a,h),f.setRequestHeader("Accept",b||"text/x-less, text/css; q=0.9, */*; q=0.5"),f.send(null),g?f.status===0?c(f.responseText):e(f.status,a):h?f.onreadystatechange=function(){f.readyState==4&&i(f,c,e)}:i(f,c,e)}function q(a,b,c){var d,e=b.href?b.href.replace(/\?.*$/,""):"",f="less:"+(b.title||p(e));(d=document.getElementById(f))===null&&(d=document.createElement("style"),d.type="text/css",d.media=b.media||"screen",d.id=f,document.getElementsByTagName("head")[0].appendChild(d));if(d.styleSheet)try{d.styleSheet.cssText=a}catch(g){throw new Error("Couldn't reassign styleSheet.cssText.")}else(function(a){d.childNodes.length>0?d.firstChild.nodeValue!==a.nodeValue&&d.replaceChild(a,d.firstChild):d.appendChild(a)})(document.createTextNode(a));c&&h&&(u("saving "+e+" to cache."),h.setItem(e,a),h.setItem(e+":timestamp",c))}function p(a){return a.replace(/^[a-z]+:\/\/?[^\/]+/,"").replace(/^\//,"").replace(/\?.*$/,"").replace(/\.[^\.\/]+$/,"").replace(/[^\.\w-]+/g,"-").replace(/\./g,":")}function o(b,c,e,f){var g=a.location.href.replace(/[#?].*$/,""),i=b.href.replace(/\?.*$/,""),j=h&&h.getItem(i),k=h&&h.getItem(i+":timestamp"),l={css:j,timestamp:k};/^(https?|file):/.test(i)||(i.charAt(0)=="/"?i=a.location.protocol+"//"+a.location.host+i:i=g.slice(0,g.lastIndexOf("/")+1)+i),r(b.href,b.type,function(a,g){if(!e&&l&&g&&(new Date(g)).valueOf()===(new Date(l.timestamp)).valueOf())q(l.css,b),c(null,b,{local:!0,remaining:f});else try{(new d.Parser({optimization:d.optimization,paths:[i.replace(/[\w\.-]+$/,"")],mime:b.type})).parse(a,function(a,d){if(a)return v(a,i);try{c(d,b,{local:!1,lastModified:g,remaining:f}),t(document.getElementById("less-error-message:"+p(i)))}catch(a){v(a,i)}})}catch(h){v(h,i)}},function(a,b){throw new Error("Couldn't load "+b+" ("+a+")")})}function n(a,b){for(var c=0;c>>0;for(var d=0;d>>0,c=Array(b),d=arguments[1];for(var e=0;e>>0,c=0;if(b===0&&arguments.length===1)throw new TypeError;if(arguments.length>=2)var d=arguments[1];else for(;;){if(c in this){d=this[c++];break}if(++c>=b)throw new TypeError}for(;c=b)return-1;c<0&&(c+=b);for(;ck&&(j[f]=j[f].slice(c-k),k=c)}function q(){j[f]=g,c=h,k=c}function p(){g=j[f],h=c,k=c}var b,c,f,g,h,i,j,k,l,m=this,n=function(){},o=this.imports={paths:a&&a.paths||[],queue:[],files:{},mime:a&&a.mime,push:function(b,c){var e=this;this.queue.push(b),d.Parser.importer(b,this.paths,function(a){e.queue.splice(e.queue.indexOf(b),1),e.files[b]=a,c(a),e.queue.length===0&&n()},a)}};this.env=a=a||{},this.optimization="optimization"in this.env?this.env.optimization:1,this.env.filename=this.env.filename||null;return l={imports:o,parse:function(d,g){var h,l,m,o,p,q,r=[],t,u=null;c=f=k=i=0,j=[],b=d.replace(/\r\n/g,"\n"),j=function(c){var d=0,e=/[^"'`\{\}\/\(\)]+/g,f=/\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g,g=0,h,i=c[0],j,k;for(var l=0,m,n;l0)throw{type:"Syntax",message:"Missing closing `}`",filename:a.filename};return c.map(function(a){return a.join("")})}([[]]),h=new e.Ruleset([],s(this.parsers.primary)),h.root=!0,h.toCSS=function(c){var d,f,g;return function(g,h){function n(a){return a?(b.slice(0,a).match(/\n/g)||"").length:null}var i=[];g=g||{},typeof h=="object"&&!Array.isArray(h)&&(h=Object.keys(h).map(function(a){var b=h[a];b instanceof e.Value||(b instanceof e.Expression||(b=new e.Expression([b])),b=new e.Value([b]));return new e.Rule("@"+a,b,!1,0)}),i=[new e.Ruleset(null,h)]);try{var j=c.call(this,{frames:i}).toCSS([],{compress:g.compress||!1})}catch(k){f=b.split("\n"),d=n(k.index);for(var l=k.index,m=-1;l>=0&&b.charAt(l)!=="\n";l--)m++;throw{type:k.type,message:k.message,filename:a.filename,index:k.index,line:typeof d=="number"?d+1:null,callLine:k.call&&n(k.call)+1,callExtract:f[n(k.call)],stack:k.stack,column:m,extract:[f[d-1],f[d],f[d+1]]}}return g.compress?j.replace(/(\s)+/g,"$1"):j}}(h.eval);if(c=0&&b.charAt(v)!=="\n";v--)w++;u={name:"ParseError",message:"Syntax Error on line "+p,index:c,filename:a.filename,line:p,column:w,extract:[q[p-2],q[p-1],q[p]]}}this.imports.queue.length>0?n=function(){g(u,h)}:g(u,h)},parsers:{primary:function(){var a,b=[];while((a=s(this.mixin.definition)||s(this.rule)||s(this.ruleset)||s(this.mixin.call)||s(this.comment)||s(this.directive))||s(/^[\s\n]+/))a&&b.push(a);return b},comment:function(){var a;if(b.charAt(c)==="/"){if(b.charAt(c+1)==="/")return new e.Comment(s(/^\/\/.*/),!0);if(a=s(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/))return new e.Comment(a)}},entities:{quoted:function(){var a,d=c,f;b.charAt(d)==="~"&&(d++,f=!0);if(b.charAt(d)==='"'||b.charAt(d)==="'"){f&&s("~");if(a=s(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/))return new e.Quoted(a[0],a[1]||a[2],f)}},keyword:function(){var a;if(a=s(/^[A-Za-z-]+/))return new e.Keyword(a)},call:function(){var a,b,d=c;if(!!(a=/^([\w-]+|%)\(/.exec(j[f]))){a=a[1].toLowerCase();if(a==="url")return null;c+=a.length;if(a==="alpha")return s(this.alpha);s("("),b=s(this.entities.arguments);if(!s(")"))return;if(a)return new e.Call(a,b,d)}},arguments:function(){var a=[],b;while(b=s(this.expression)){a.push(b);if(!s(","))break}return a},literal:function(){return s(this.entities.dimension)||s(this.entities.color)||s(this.entities.quoted)},url:function(){var a;if(b.charAt(c)==="u"&&!!s(/^url\(/)){a=s(this.entities.quoted)||s(this.entities.variable)||s(this.entities.dataURI)||s(/^[-\w%@$\/.&=:;#+?~]+/)||"";if(!s(")"))throw new Error("missing closing ) for url()");return new e.URL(a.value||a.data||a instanceof e.Variable?a:new e.Anonymous(a),o.paths)}},dataURI:function(){var a;if(s(/^data:/)){a={},a.mime=s(/^[^\/]+\/[^,;)]+/)||"",a.charset=s(/^;\s*charset=[^,;)]+/)||"",a.base64=s(/^;\s*base64/)||"",a.data=s(/^,\s*[^)]+/);if(a.data)return a}},variable:function(){var a,d=c;if(b.charAt(c)==="@"&&(a=s(/^@@?[\w-]+/)))return new e.Variable(a,d)},color:function(){var a;if(b.charAt(c)==="#"&&(a=s(/^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})/)))return new e.Color(a[1])},dimension:function(){var a,d=b.charCodeAt(c);if(!(d>57||d<45||d===47))if(a=s(/^(-?\d*\.?\d+)(px|%|em|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn)?/))return new e.Dimension(a[1],a[2])},javascript:function(){var a,d=c,f;b.charAt(d)==="~"&&(d++,f=!0);if(b.charAt(d)==="`"){f&&s("~");if(a=s(/^`([^`]*)`/))return new e.JavaScript(a[1],c,f)}}},variable:function(){var a;if(b.charAt(c)==="@"&&(a=s(/^(@[\w-]+)\s*:/)))return a[1]},shorthand:function(){var a,b;if(!!t(/^[@\w.%-]+\/[@\w.-]+/)&&(a=s(this.entity))&&s("/")&&(b=s(this.entity)))return new e.Shorthand(a,b)},mixin:{call:function(){var a=[],d,f,g,h=c,i=b.charAt(c);if(i==="."||i==="#"){while(d=s(/^[#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/))a.push(new e.Element(f,d)),f=s(">");s("(")&&(g=s(this.entities.arguments))&&s(")");if(a.length>0&&(s(";")||t("}")))return new e.mixin.Call(a,g,h)}},definition:function(){var a,d=[],f,g,h,i;if(!(b.charAt(c)!=="."&&b.charAt(c)!=="#"||t(/^[^{]*(;|})/)))if(f=s(/^([#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+)\s*\(/)){a=f[1];while(h=s(this.entities.variable)||s(this.entities.literal)||s(this.entities.keyword)){if(h instanceof e.Variable)if(s(":"))if(i=s(this.expression))d.push({name:h.name,value:i});else throw new Error("Expected value");else d.push({name:h.name});else d.push({value:h});if(!s(","))break}if(!s(")"))throw new Error("Expected )");g=s(this.block);if(g)return new e.mixin.Definition(a,d,g)}}},entity:function(){return s(this.entities.literal)||s(this.entities.variable)||s(this.entities.url)||s(this.entities.call)||s(this.entities.keyword)||s(this.entities.javascript)||s(this.comment)},end:function(){return s(";")||t("}")},alpha:function(){var a;if(!!s(/^\(opacity=/i))if(a=s(/^\d+/)||s(this.entities.variable)){if(!s(")"))throw new Error("missing closing ) for alpha()");return new e.Alpha(a)}},element:function(){var a,b,c;c=s(this.combinator),a=s(/^(?:[.#]?|:*)(?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/)||s("*")||s(this.attribute)||s(/^\([^)@]+\)/);if(a)return new e.Element(c,a)},combinator:function(){var a,d=b.charAt(c);if(d===">"||d==="&"||d==="+"||d==="~"){c++;while(b.charAt(c)===" ")c++;return new e.Combinator(d)}if(d===":"&&b.charAt(c+1)===":"){c+=2;while(b.charAt(c)===" ")c++;return new e.Combinator("::")}return b.charAt(c-1)===" "?new e.Combinator(" "):new e.Combinator(null)},selector:function(){var a,d,f=[],g,h;while(d=s(this.element)){g=b.charAt(c),f.push(d);if(g==="{"||g==="}"||g===";"||g===",")break}if(f.length>0)return new e.Selector(f)},tag:function(){return s(/^[a-zA-Z][a-zA-Z-]*[0-9]?/)||s("*")},attribute:function(){var a="",b,c,d;if(!!s("[")){if(b=s(/^[a-zA-Z-]+/)||s(this.entities.quoted))(d=s(/^[|~*$^]?=/))&&(c=s(this.entities.quoted)||s(/^[\w-]+/))?a=[b,d,c.toCSS?c.toCSS():c].join(""):a=b;if(!s("]"))return;if(a)return"["+a+"]"}},block:function(){var a;if(s("{")&&(a=s(this.primary))&&s("}"))return a},ruleset:function(){var a=[],b,d,g;p();if(g=/^([.#: \w-]+)[\s\n]*\{/.exec(j[f]))c+=g[0].length-1,a=[new e.Selector([new e.Element(null,g[1])])];else while(b=s(this.selector)){a.push(b),s(this.comment);if(!s(","))break;s(this.comment)}if(a.length>0&&(d=s(this.block)))return new e.Ruleset(a,d);i=c,q()},rule:function(){var a,d,g=b.charAt(c),k,l;p();if(g!=="."&&g!=="#"&&g!=="&")if(a=s(this.variable)||s(this.property)){a.charAt(0)!="@"&&(l=/^([^@+\/'"*`(;{}-]*);/.exec(j[f]))?(c+=l[0].length-1,d=new e.Anonymous(l[1])):a==="font"?d=s(this.font):d=s(this.value),k=s(this.important);if(d&&s(this.end))return new e.Rule(a,d,k,h);i=c,q()}},"import":function(){var a;if(s(/^@import\s+/)&&(a=s(this.entities.quoted)||s(this.entities.url))&&s(";"))return new e.Import(a,o)},directive:function(){var a,d,f,g;if(b.charAt(c)==="@"){if(d=s(this["import"]))return d;if(a=s(/^@media|@page|@-[-a-z]+/)){g=(s(/^[^{]+/)||"").trim();if(f=s(this.block))return new e.Directive(a+" "+g,f)}else if(a=s(/^@[-a-z]+/))if(a==="@font-face"){if(f=s(this.block))return new e.Directive(a,f)}else if((d=s(this.entity))&&s(";"))return new e.Directive(a,d)}},font:function(){var a=[],b=[],c,d,f,g;while(g=s(this.shorthand)||s(this.entity))b.push(g);a.push(new e.Expression(b));if(s(","))while(g=s(this.expression)){a.push(g);if(!s(","))break}return new e.Value(a)},value:function(){var a,b=[],c;while(a=s(this.expression)){b.push(a);if(!s(","))break}if(b.length>0)return new e.Value(b)},important:function(){if(b.charAt(c)==="!")return s(/^! *important/)},sub:function(){var a;if(s("(")&&(a=s(this.expression))&&s(")"))return a},multiplication:function(){var a,b,c,d;if(a=s(this.operand)){while((c=s("/")||s("*"))&&(b=s(this.operand)))d=new e.Operation(c,[d||a,b]);return d||a}},addition:function(){var a,d,f,g;if(a=s(this.multiplication)){while((f=s(/^[-+]\s+/)||b.charAt(c-1)!=" "&&(s("+")||s("-")))&&(d=s(this.multiplication)))g=new e.Operation(f,[g||a,d]);return g||a}},operand:function(){var a,d=b.charAt(c+1);b.charAt(c)==="-"&&(d==="@"||d==="(")&&(a=s("-"));var f=s(this.sub)||s(this.entities.dimension)||s(this.entities.color)||s(this.entities.variable)||s(this.entities.call);return a?new e.Operation("*",[new e.Dimension(-1),f]):f},expression:function(){var a,b,c=[],d;while(a=s(this.addition)||s(this.entity))c.push(a);if(c.length>0)return new e.Expression(c)},property:function(){var a;if(a=s(/^(\*?-?[-a-z_0-9]+)\s*:/))return a[1]}}}},typeof a!="undefined"&&(d.Parser.importer=function(a,b,c,d){a.charAt(0)!=="/"&&b.length>0&&(a=b[0]+a),o({href:a,title:a,type:d.mime},c,!0)}),function(a){function d(a){return Math.min(1,Math.max(0,a))}function c(b){if(b instanceof a.Dimension)return parseFloat(b.unit=="%"?b.value/100:b.value);if(typeof b=="number")return b;throw{error:"RuntimeError",message:"color functions take numbers as parameters"}}function b(b){return a.functions.hsla(b.h,b.s,b.l,b.a)}a.functions={rgb:function(a,b,c){return this.rgba(a,b,c,1)},rgba:function(b,d,e,f){var g=[b,d,e].map(function(a){return c(a)}),f=c(f);return new a.Color(g,f)},hsl:function(a,b,c){return this.hsla(a,b,c,1)},hsla:function(a,b,d,e){function h(a){a=a<0?a+1:a>1?a-1:a;return a*6<1?g+(f-g)*a*6:a*2<1?f:a*3<2?g+(f-g)*(2/3-a)*6:g}a=c(a)%360/360,b=c(b),d=c(d),e=c(e);var f=d<=.5?d*(b+1):d+b-d*b,g=d*2-f;return this.rgba(h(a+1/3)*255,h(a)*255,h(a-1/3)*255,e)},hue:function(b){return new a.Dimension(Math.round(b.toHSL().h))},saturation:function(b){return new a.Dimension(Math.round(b.toHSL().s*100),"%")},lightness:function(b){return new a.Dimension(Math.round(b.toHSL().l*100),"%")},alpha:function(b){return new a.Dimension(b.toHSL().a)},saturate:function(a,c){var e=a.toHSL();e.s+=c.value/100,e.s=d(e.s);return b(e)},desaturate:function(a,c){var e=a.toHSL();e.s-=c.value/100,e.s=d(e.s);return b(e)},lighten:function(a,c){var e=a.toHSL();e.l+=c.value/100,e.l=d(e.l);return b(e)},darken:function(a,c){var e=a.toHSL();e.l-=c.value/100,e.l=d(e.l);return b(e)},fadein:function(a,c){var e=a.toHSL();e.a+=c.value/100,e.a=d(e.a);return b(e)},fadeout:function(a,c){var e=a.toHSL();e.a-=c.value/100,e.a=d(e.a);return b(e)},spin:function(a,c){var d=a.toHSL(),e=(d.h+c.value)%360;d.h=e<0?360+e:e;return b(d)},mix:function(b,c,d){var e=d.value/100,f=e*2-1,g=b.toHSL().a-c.toHSL().a,h=((f*g==-1?f:(f+g)/(1+f*g))+1)/2,i=1-h,j=[b.rgb[0]*h+c.rgb[0]*i,b.rgb[1]*h+c.rgb[1]*i,b.rgb[2]*h+c.rgb[2]*i],k=b.alpha*e+c.alpha*(1-e);return new a.Color(j,k)},greyscale:function(b){return this.desaturate(b,new a.Dimension(100))},e:function(b){return new a.Anonymous(b instanceof a.JavaScript?b.evaluated:b)},escape:function(b){return new a.Anonymous(encodeURI(b.value).replace(/=/g,"%3D").replace(/:/g,"%3A").replace(/#/g,"%23").replace(/;/g,"%3B").replace(/\(/g,"%28").replace(/\)/g,"%29"))},"%":function(b){var c=Array.prototype.slice.call(arguments,1),d=b.value;for(var e=0;e255?255:a<0?0:a).toString(16);return a.length===1?"0"+a:a}).join("")},operate:function(b,c){var d=[];c instanceof a.Color||(c=c.toColor());for(var e=0;e<3;e++)d[e]=a.operate(b,this.rgb[e],c.rgb[e]);return new a.Color(d,this.alpha+c.alpha)},toHSL:function(){var a=this.rgb[0]/255,b=this.rgb[1]/255,c=this.rgb[2]/255,d=this.alpha,e=Math.max(a,b,c),f=Math.min(a,b,c),g,h,i=(e+f)/2,j=e-f;if(e===f)g=h=0;else{h=i>.5?j/(2-e-f):j/(e+f);switch(e){case a:g=(b-c)/j+(b":a.compress?">":" > "}[this.value]}}(c("less/tree")),function(a){a.Expression=function(a){this.value=a},a.Expression.prototype={eval:function(b){return this.value.length>1?new a.Expression(this.value.map(function(a){return a.eval(b)})):this.value.length===1?this.value[0].eval(b):this},toCSS:function(a){return this.value.map(function(b){return b.toCSS(a)}).join(" ")}}}(c("less/tree")),function(a){a.Import=function(b,c){var d=this;this._path=b,b instanceof a.Quoted?this.path=/\.(le?|c)ss$/.test(b.value)?b.value:b.value+".less":this.path=b.value.value||b.value,this.css=/css$/.test(this.path),this.css||c.push(this.path,function(a){if(!a)throw new Error("Error parsing "+d.path);d.root=a})},a.Import.prototype={toCSS:function(){return this.css?"@import "+this._path.toCSS()+";\n":""},eval:function(b){var c;if(this.css)return this;c=new a.Ruleset(null,this.root.rules.slice(0));for(var d=0;d0){c=this.arguments&&this.arguments.map(function(b){return b.eval(a)});for(var g=0;g0&&c>this.params.length)return!1;d=Math.min(c,this.arity);for(var e=0;e1?Array.prototype.push.apply(d,e.find(new a.Selector(b.elements.slice(1)),c)):d.push(e);break}});return this._lookups[g]=d},toCSS:function(b,c){var d=[],e=[],f=[],g=[],h,i;if(!this.root)if(b.length===0)g=this.selectors.map(function(a){return[a]});else for(var j=0;j0&&(h=g.map(function(a){return a.map(function(a){return a.toCSS(c)}).join("").trim()}).join(c.compress?",":g.length>3?",\n":", "),d.push(h,(c.compress?"{":" {\n ")+e.join(c.compress?"":"\n ")+(c.compress?"}":"\n}\n"))),d.push(f);return d.join("")+(c.compress?"\n":"")}}}(c("less/tree")),function(a){a.Selector=function(a){this.elements=a,this.elements[0].combinator.value===""&&(this.elements[0].combinator.value=" ")},a.Selector.prototype.match=function(a){return this.elements[0].value===a.elements[0].value?!0:!1},a.Selector.prototype.toCSS=function(a){if(this._css)return this._css;return this._css=this.elements.map(function(b){return typeof b=="string"?" "+b.trim():b.toCSS(a)}).join("")}}(c("less/tree")),function(b){b.URL=function(b,c){b.data?this.attrs=b:(!/^(?:https?:\/|file:\/|data:\/)?\//.test(b.value)&&c.length>0&&typeof a!="undefined"&&(b.value=c[0]+(b.value.charAt(0)==="/"?b.value.slice(1):b.value)),this.value=b,this.paths=c)},b.URL.prototype={toCSS:function(){return"url("+(this.attrs?"data:"+this.attrs.mime+this.attrs.charset+this.attrs.base64+this.attrs.data:this.value.toCSS())+")"},eval:function(a){return this.attrs?this:new b.URL(this.value.eval(a),this.paths)}}}(c("less/tree")),function(a){a.Value=function(a){this.value=a,this.is="value"},a.Value.prototype={eval:function(b){return this.value.length===1?this.value[0].eval(b):new a.Value(this.value.map(function(a){return a.eval(b)}))},toCSS:function(a){return this.value.map(function(b){return b.toCSS(a)}).join(a.compress?",":", ")}}}(c("less/tree")),function(a){a.Variable=function(a,b){this.name=a,this .index=b},a.Variable.prototype={eval:function(b){var c,d,e=this.name;e.indexOf("@@")==0&&(e="@"+(new a.Variable(e.slice(1))).eval(b).value);if(c=a.find(b.frames,function(a){if(d=a.variable(e))return d.value.eval(b)}))return c;throw{message:"variable "+e+" is undefined",index:this.index}}}}(c("less/tree")),c("less/tree").find=function(a,b){for(var c=0,d;c1?"["+a.value.map(function(a){return a.toCSS(!1)}).join(", ")+"]":a.toCSS(!1)};var g=location.protocol==="file:"||location.protocol==="chrome:"||location.protocol==="chrome-extension:"||location.protocol==="resource:";d.env=d.env||(location.hostname=="127.0.0.1"||location.hostname=="0.0.0.0"||location.hostname=="localhost"||location.port.length>0||g?"development":"production"),d.async=!1,d.poll=d.poll||(g?1e3:1500),d.watch=function(){return this.watchMode=!0},d.unwatch=function(){return this.watchMode=!1},d.env==="development"?(d.optimization=0,/!watch/.test(location.hash)&&d.watch(),d.watchTimer=setInterval(function(){d.watchMode&&n(function(a,b,c){a&&q(a.toCSS(),b,c.lastModified)})},d.poll)):d.optimization=3;var h;try{h=typeof a.localStorage=="undefined"?null:a.localStorage}catch(i){h=null}var j=document.getElementsByTagName("link"),k=/^text\/(x-)?less$/;d.sheets=[];for(var l=0;l>> 0; for (var i = 0; i < len; i++) { if (i in this) { block.call(thisObject, this[i], i, this); } } }; } if (!Array.prototype.map) { Array.prototype.map = function(fun /*, thisp*/) { var len = this.length >>> 0; var res = new Array(len); var thisp = arguments[1]; for (var i = 0; i < len; i++) { if (i in this) { res[i] = fun.call(thisp, this[i], i, this); } } return res; }; } if (!Array.prototype.filter) { Array.prototype.filter = function (block /*, thisp */) { var values = []; var thisp = arguments[1]; for (var i = 0; i < this.length; i++) { if (block.call(thisp, this[i])) { values.push(this[i]); } } return values; }; } if (!Array.prototype.reduce) { Array.prototype.reduce = function(fun /*, initial*/) { var len = this.length >>> 0; var i = 0; // no value to return if no initial value and an empty array if (len === 0 && arguments.length === 1) throw new TypeError(); if (arguments.length >= 2) { var rv = arguments[1]; } else { do { if (i in this) { rv = this[i++]; break; } // if array contains no values, no initial value to return if (++i >= len) throw new TypeError(); } while (true); } for (; i < len; i++) { if (i in this) { rv = fun.call(null, rv, this[i], i, this); } } return rv; }; } if (!Array.prototype.indexOf) { Array.prototype.indexOf = function (value /*, fromIndex */ ) { var length = this.length; var i = arguments[1] || 0; if (!length) return -1; if (i >= length) return -1; if (i < 0) i += length; for (; i < length; i++) { if (!Object.prototype.hasOwnProperty.call(this, i)) { continue } if (value === this[i]) return i; } return -1; }; } // // Object // if (!Object.keys) { Object.keys = function (object) { var keys = []; for (var name in object) { if (Object.prototype.hasOwnProperty.call(object, name)) { keys.push(name); } } return keys; }; } // // String // if (!String.prototype.trim) { String.prototype.trim = function () { return String(this).replace(/^\s\s*/, '').replace(/\s\s*$/, ''); }; } var less, tree; if (typeof(window) === 'undefined') { less = exports, tree = require('less/tree'); } else { if (typeof(window.less) === 'undefined') { window.less = {} } less = window.less, tree = window.less.tree = {}; } // // less.js - parser // // A relatively straight-forward predictive parser. // There is no tokenization/lexing stage, the input is parsed // in one sweep. // // To make the parser fast enough to run in the browser, several // optimization had to be made: // // - Matching and slicing on a huge input is often cause of slowdowns. // The solution is to chunkify the input into smaller strings. // The chunks are stored in the `chunks` var, // `j` holds the current chunk index, and `current` holds // the index of the current chunk in relation to `input`. // This gives us an almost 4x speed-up. // // - In many cases, we don't need to match individual tokens; // for example, if a value doesn't hold any variables, operations // or dynamic references, the parser can effectively 'skip' it, // treating it as a literal. // An example would be '1px solid #000' - which evaluates to itself, // we don't need to know what the individual components are. // The drawback, of course is that you don't get the benefits of // syntax-checking on the CSS. This gives us a 50% speed-up in the parser, // and a smaller speed-up in the code-gen. // // // Token matching is done with the `$` function, which either takes // a terminal string or regexp, or a non-terminal function to call. // It also takes care of moving all the indices forwards. // // less.Parser = function Parser(env) { var input, // LeSS input string i, // current index in `input` j, // current chunk temp, // temporarily holds a chunk's state, for backtracking memo, // temporarily holds `i`, when backtracking furthest, // furthest index the parser has gone to chunks, // chunkified input current, // index of current chunk, in `input` parser; var that = this; // This function is called after all files // have been imported through `@import`. var finish = function () {}; var imports = this.imports = { paths: env && env.paths || [], // Search paths, when importing queue: [], // Files which haven't been imported yet files: {}, // Holds the imported parse trees mime: env && env.mime, // MIME type of .less files push: function (path, callback) { var that = this; this.queue.push(path); // // Import a file asynchronously // less.Parser.importer(path, this.paths, function (root) { that.queue.splice(that.queue.indexOf(path), 1); // Remove the path from the queue that.files[path] = root; // Store the root callback(root); if (that.queue.length === 0) { finish() } // Call `finish` if we're done importing }, env); } }; function save() { temp = chunks[j], memo = i, current = i } function restore() { chunks[j] = temp, i = memo, current = i } function sync() { if (i > current) { chunks[j] = chunks[j].slice(i - current); current = i; } } // // Parse from a token, regexp or string, and move forward if match // function $(tok) { var match, args, length, c, index, endIndex, k, mem; // // Non-terminal // if (tok instanceof Function) { return tok.call(parser.parsers); // // Terminal // // Either match a single character in the input, // or match a regexp in the current chunk (chunk[j]). // } else if (typeof(tok) === 'string') { match = input.charAt(i) === tok ? tok : null; length = 1; sync (); } else { sync (); if (match = tok.exec(chunks[j])) { length = match[0].length; } else { return null; } } // The match is confirmed, add the match length to `i`, // and consume any extra white-space characters (' ' || '\n') // which come after that. The reason for this is that LeSS's // grammar is mostly white-space insensitive. // if (match) { mem = i += length; endIndex = i + chunks[j].length - length; while (i < endIndex) { c = input.charCodeAt(i); if (! (c === 32 || c === 10 || c === 9)) { break } i++; } chunks[j] = chunks[j].slice(length + (i - mem)); current = i; if (chunks[j].length === 0 && j < chunks.length - 1) { j++ } if(typeof(match) === 'string') { return match; } else { return match.length === 1 ? match[0] : match; } } } // Same as $(), but don't change the state of the parser, // just return the match. function peek(tok) { if (typeof(tok) === 'string') { return input.charAt(i) === tok; } else { if (tok.test(chunks[j])) { return true; } else { return false; } } } this.env = env = env || {}; // The optimization level dictates the thoroughness of the parser, // the lower the number, the less nodes it will create in the tree. // This could matter for debugging, or if you want to access // the individual nodes in the tree. this.optimization = ('optimization' in this.env) ? this.env.optimization : 1; this.env.filename = this.env.filename || null; // // The Parser // return parser = { imports: imports, // // Parse an input string into an abstract syntax tree, // call `callback` when done. // parse: function (str, callback) { var root, start, end, zone, line, lines, buff = [], c, error = null; i = j = current = furthest = 0; chunks = []; input = str.replace(/\r\n/g, '\n'); // Split the input into chunks. chunks = (function (chunks) { var j = 0, skip = /[^"'`\{\}\/\(\)]+/g, comment = /\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g, level = 0, match, chunk = chunks[0], inParam, inString; for (var i = 0, c, cc; i < input.length; i++) { skip.lastIndex = i; if (match = skip.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); } } c = input.charAt(i); comment.lastIndex = i; if (!inString && !inParam && c === '/') { cc = input.charAt(i + 1); if (cc === '/' || cc === '*') { if (match = comment.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); c = input.charAt(i); } } } } if (c === '{' && !inString && !inParam) { level ++; chunk.push(c); } else if (c === '}' && !inString && !inParam) { level --; chunk.push(c); chunks[++j] = chunk = []; } else if (c === '(' && !inString && !inParam) { chunk.push(c); inParam = true; } else if (c === ')' && !inString && inParam) { chunk.push(c); inParam = false; } else { if (c === '"' || c === "'" || c === '`') { if (! inString) { inString = c; } else { inString = inString === c ? false : inString; } } chunk.push(c); } } if (level > 0) { throw { type: 'Syntax', message: "Missing closing `}`", filename: env.filename }; } return chunks.map(function (c) { return c.join('') });; })([[]]); // Start with the primary rule. // The whole syntax tree is held under a Ruleset node, // with the `root` property set to true, so no `{}` are // output. The callback is called when the input is parsed. root = new(tree.Ruleset)([], $(this.parsers.primary)); root.root = true; root.toCSS = (function (evaluate) { var line, lines, column; return function (options, variables) { var frames = []; options = options || {}; // // Allows setting variables with a hash, so: // // `{ color: new(tree.Color)('#f01') }` will become: // // new(tree.Rule)('@color', // new(tree.Value)([ // new(tree.Expression)([ // new(tree.Color)('#f01') // ]) // ]) // ) // if (typeof(variables) === 'object' && !Array.isArray(variables)) { variables = Object.keys(variables).map(function (k) { var value = variables[k]; if (! (value instanceof tree.Value)) { if (! (value instanceof tree.Expression)) { value = new(tree.Expression)([value]); } value = new(tree.Value)([value]); } return new(tree.Rule)('@' + k, value, false, 0); }); frames = [new(tree.Ruleset)(null, variables)]; } try { var css = evaluate.call(this, { frames: frames }) .toCSS([], { compress: options.compress || false }); } catch (e) { lines = input.split('\n'); line = getLine(e.index); for (var n = e.index, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } throw { type: e.type, message: e.message, filename: env.filename, index: e.index, line: typeof(line) === 'number' ? line + 1 : null, callLine: e.call && (getLine(e.call) + 1), callExtract: lines[getLine(e.call)], stack: e.stack, column: column, extract: [ lines[line - 1], lines[line], lines[line + 1] ] }; } if (options.compress) { return css.replace(/(\s)+/g, "$1"); } else { return css; } function getLine(index) { return index ? (input.slice(0, index).match(/\n/g) || "").length : null; } }; })(root.eval); // If `i` is smaller than the `input.length - 1`, // it means the parser wasn't able to parse the whole // string, so we've got a parsing error. // // We try to extract a \n delimited string, // showing the line where the parse error occured. // We split it up into two parts (the part which parsed, // and the part which didn't), so we can color them differently. if (i < input.length - 1) { i = furthest; lines = input.split('\n'); line = (input.slice(0, i).match(/\n/g) || "").length + 1; for (var n = i, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } error = { name: "ParseError", message: "Syntax Error on line " + line, index: i, filename: env.filename, line: line, column: column, extract: [ lines[line - 2], lines[line - 1], lines[line] ] }; } if (this.imports.queue.length > 0) { finish = function () { callback(error, root) }; } else { callback(error, root); } }, // // Here in, the parsing rules/functions // // The basic structure of the syntax tree generated is as follows: // // Ruleset -> Rule -> Value -> Expression -> Entity // // Here's some LESS code: // // .class { // color: #fff; // border: 1px solid #000; // width: @w + 4px; // > .child {...} // } // // And here's what the parse tree might look like: // // Ruleset (Selector '.class', [ // Rule ("color", Value ([Expression [Color #fff]])) // Rule ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]])) // Rule ("width", Value ([Expression [Operation "+" [Variable "@w"][Dimension 4px]]])) // Ruleset (Selector [Element '>', '.child'], [...]) // ]) // // In general, most rules will try to parse a token with the `$()` function, and if the return // value is truly, will return a new node, of the relevant type. Sometimes, we need to check // first, before parsing, that's when we use `peek()`. // parsers: { // // The `primary` rule is the *entry* and *exit* point of the parser. // The rules here can appear at any level of the parse tree. // // The recursive nature of the grammar is an interplay between the `block` // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule, // as represented by this simplified grammar: // // primary → (ruleset | rule)+ // ruleset → selector+ block // block → '{' primary '}' // // Only at one point is the primary rule not called from the // block rule: at the root level. // primary: function () { var node, root = []; while ((node = $(this.mixin.definition) || $(this.rule) || $(this.ruleset) || $(this.mixin.call) || $(this.comment) || $(this.directive)) || $(/^[\s\n]+/)) { node && root.push(node); } return root; }, // We create a Comment node for CSS comments `/* */`, // but keep the LeSS comments `//` silent, by just skipping // over them. comment: function () { var comment; if (input.charAt(i) !== '/') return; if (input.charAt(i + 1) === '/') { return new(tree.Comment)($(/^\/\/.*/), true); } else if (comment = $(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/)) { return new(tree.Comment)(comment); } }, // // Entities are tokens which can be found inside an Expression // entities: { // // A string, which supports escaping " and ' // // "milky way" 'he\'s the one!' // quoted: function () { var str, j = i, e; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '"' && input.charAt(j) !== "'") return; e && $('~'); if (str = $(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/)) { return new(tree.Quoted)(str[0], str[1] || str[2], e); } }, // // A catch-all word, such as: // // black border-collapse // keyword: function () { var k; if (k = $(/^[A-Za-z-]+/)) { return new(tree.Keyword)(k) } }, // // A function call // // rgb(255, 0, 255) // // We also try to catch IE's `alpha()`, but let the `alpha` parser // deal with the details. // // The arguments are parsed with the `entities.arguments` parser. // call: function () { var name, args, index = i; if (! (name = /^([\w-]+|%)\(/.exec(chunks[j]))) return; name = name[1].toLowerCase(); if (name === 'url') { return null } else { i += name.length } if (name === 'alpha') { return $(this.alpha) } $('('); // Parse the '(' and consume whitespace. args = $(this.entities.arguments); if (! $(')')) return; if (name) { return new(tree.Call)(name, args, index) } }, arguments: function () { var args = [], arg; while (arg = $(this.expression)) { args.push(arg); if (! $(',')) { break } } return args; }, literal: function () { return $(this.entities.dimension) || $(this.entities.color) || $(this.entities.quoted); }, // // Parse url() tokens // // We use a specific rule for urls, because they don't really behave like // standard function calls. The difference is that the argument doesn't have // to be enclosed within a string, so it can't be parsed as an Expression. // url: function () { var value; if (input.charAt(i) !== 'u' || !$(/^url\(/)) return; value = $(this.entities.quoted) || $(this.entities.variable) || $(this.entities.dataURI) || $(/^[-\w%@$\/.&=:;#+?~]+/) || ""; if (! $(')')) throw new(Error)("missing closing ) for url()"); return new(tree.URL)((value.value || value.data || value instanceof tree.Variable) ? value : new(tree.Anonymous)(value), imports.paths); }, dataURI: function () { var obj; if ($(/^data:/)) { obj = {}; obj.mime = $(/^[^\/]+\/[^,;)]+/) || ''; obj.charset = $(/^;\s*charset=[^,;)]+/) || ''; obj.base64 = $(/^;\s*base64/) || ''; obj.data = $(/^,\s*[^)]+/); if (obj.data) { return obj } } }, // // A Variable entity, such as `@fink`, in // // width: @fink + 2px // // We use a different parser for variable definitions, // see `parsers.variable`. // variable: function () { var name, index = i; if (input.charAt(i) === '@' && (name = $(/^@@?[\w-]+/))) { return new(tree.Variable)(name, index); } }, // // A Hexadecimal color // // #4F3C2F // // `rgb` and `hsl` colors are parsed through the `entities.call` parser. // color: function () { var rgb; if (input.charAt(i) === '#' && (rgb = $(/^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})/))) { return new(tree.Color)(rgb[1]); } }, // // A Dimension, that is, a number and a unit // // 0.5em 95% // dimension: function () { var value, c = input.charCodeAt(i); if ((c > 57 || c < 45) || c === 47) return; if (value = $(/^(-?\d*\.?\d+)(px|%|em|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn)?/)) { return new(tree.Dimension)(value[1], value[2]); } }, // // JavaScript code to be evaluated // // `window.location.href` // javascript: function () { var str, j = i, e; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '`') { return } e && $('~'); if (str = $(/^`([^`]*)`/)) { return new(tree.JavaScript)(str[1], i, e); } } }, // // The variable part of a variable definition. Used in the `rule` parser // // @fink: // variable: function () { var name; if (input.charAt(i) === '@' && (name = $(/^(@[\w-]+)\s*:/))) { return name[1] } }, // // A font size/line-height shorthand // // small/12px // // We need to peek first, or we'll match on keywords and dimensions // shorthand: function () { var a, b; if (! peek(/^[@\w.%-]+\/[@\w.-]+/)) return; if ((a = $(this.entity)) && $('/') && (b = $(this.entity))) { return new(tree.Shorthand)(a, b); } }, // // Mixins // mixin: { // // A Mixin call, with an optional argument list // // #mixins > .square(#fff); // .rounded(4px, black); // .button; // // The `while` loop is there because mixins can be // namespaced, but we only support the child and descendant // selector for now. // call: function () { var elements = [], e, c, args, index = i, s = input.charAt(i); if (s !== '.' && s !== '#') { return } while (e = $(/^[#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/)) { elements.push(new(tree.Element)(c, e)); c = $('>'); } $('(') && (args = $(this.entities.arguments)) && $(')'); if (elements.length > 0 && ($(';') || peek('}'))) { return new(tree.mixin.Call)(elements, args, index); } }, // // A Mixin definition, with a list of parameters // // .rounded (@radius: 2px, @color) { // ... // } // // Until we have a finer grained state-machine, we have to // do a look-ahead, to make sure we don't have a mixin call. // See the `rule` function for more information. // // We start by matching `.rounded (`, and then proceed on to // the argument list, which has optional default values. // We store the parameters in `params`, with a `value` key, // if there is a value, such as in the case of `@radius`. // // Once we've got our params list, and a closing `)`, we parse // the `{...}` block. // definition: function () { var name, params = [], match, ruleset, param, value; if ((input.charAt(i) !== '.' && input.charAt(i) !== '#') || peek(/^[^{]*(;|})/)) return; if (match = $(/^([#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+)\s*\(/)) { name = match[1]; while (param = $(this.entities.variable) || $(this.entities.literal) || $(this.entities.keyword)) { // Variable if (param instanceof tree.Variable) { if ($(':')) { if (value = $(this.expression)) { params.push({ name: param.name, value: value }); } else { throw new(Error)("Expected value"); } } else { params.push({ name: param.name }); } } else { params.push({ value: param }); } if (! $(',')) { break } } if (! $(')')) throw new(Error)("Expected )"); ruleset = $(this.block); if (ruleset) { return new(tree.mixin.Definition)(name, params, ruleset); } } } }, // // Entities are the smallest recognized token, // and can be found inside a rule's value. // entity: function () { return $(this.entities.literal) || $(this.entities.variable) || $(this.entities.url) || $(this.entities.call) || $(this.entities.keyword) || $(this.entities.javascript) || $(this.comment); }, // // A Rule terminator. Note that we use `peek()` to check for '}', // because the `block` rule will be expecting it, but we still need to make sure // it's there, if ';' was ommitted. // end: function () { return $(';') || peek('}'); }, // // IE's alpha function // // alpha(opacity=88) // alpha: function () { var value; if (! $(/^\(opacity=/i)) return; if (value = $(/^\d+/) || $(this.entities.variable)) { if (! $(')')) throw new(Error)("missing closing ) for alpha()"); return new(tree.Alpha)(value); } }, // // A Selector Element // // div // + h1 // #socks // input[type="text"] // // Elements are the building blocks for Selectors, // they are made out of a `Combinator` (see combinator rule), // and an element name, such as a tag a class, or `*`. // element: function () { var e, t, c; c = $(this.combinator); e = $(/^(?:[.#]?|:*)(?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/) || $('*') || $(this.attribute) || $(/^\([^)@]+\)/) || $(/^(?:\d*\.)?\d+%/); if (e) { return new(tree.Element)(c, e) } if (c.value && c.value[0] === '&') { return new(tree.Element)(c, null); } }, // // Combinators combine elements together, in a Selector. // // Because our parser isn't white-space sensitive, special care // has to be taken, when parsing the descendant combinator, ` `, // as it's an empty space. We have to check the previous character // in the input, to see if it's a ` ` character. More info on how // we deal with this in *combinator.js*. // combinator: function () { var match, c = input.charAt(i); if (c === '>' || c === '+' || c === '~') { i++; while (input.charAt(i) === ' ') { i++ } return new(tree.Combinator)(c); } else if (c === '&') { match = '&'; i++; if(input.charAt(i) === ' ') { match = '& '; } while (input.charAt(i) === ' ') { i++ } return new(tree.Combinator)(match); } else if (c === ':' && input.charAt(i + 1) === ':') { i += 2; while (input.charAt(i) === ' ') { i++ } return new(tree.Combinator)('::'); } else if (input.charAt(i - 1) === ' ') { return new(tree.Combinator)(" "); } else { return new(tree.Combinator)(null); } }, // // A CSS Selector // // .class > div + h1 // li a:hover // // Selectors are made out of one or more Elements, see above. // selector: function () { var sel, e, elements = [], c, match; while (e = $(this.element)) { c = input.charAt(i); elements.push(e) if (c === '{' || c === '}' || c === ';' || c === ',') { break } } if (elements.length > 0) { return new(tree.Selector)(elements) } }, tag: function () { return $(/^[a-zA-Z][a-zA-Z-]*[0-9]?/) || $('*'); }, attribute: function () { var attr = '', key, val, op; if (! $('[')) return; if (key = $(/^[a-zA-Z-]+/) || $(this.entities.quoted)) { if ((op = $(/^[|~*$^]?=/)) && (val = $(this.entities.quoted) || $(/^[\w-]+/))) { attr = [key, op, val.toCSS ? val.toCSS() : val].join(''); } else { attr = key } } if (! $(']')) return; if (attr) { return "[" + attr + "]" } }, // // The `block` rule is used by `ruleset` and `mixin.definition`. // It's a wrapper around the `primary` rule, with added `{}`. // block: function () { var content; if ($('{') && (content = $(this.primary)) && $('}')) { return content; } }, // // div, .class, body > p {...} // ruleset: function () { var selectors = [], s, rules, match; save(); if (match = /^([.#:% \w-]+)[\s\n]*\{/.exec(chunks[j])) { i += match[0].length - 1; selectors = [new(tree.Selector)([new(tree.Element)(null, match[1])])]; } else { while (s = $(this.selector)) { selectors.push(s); $(this.comment); if (! $(',')) { break } $(this.comment); } } if (selectors.length > 0 && (rules = $(this.block))) { return new(tree.Ruleset)(selectors, rules); } else { // Backtrack furthest = i; restore(); } }, rule: function () { var name, value, c = input.charAt(i), important, match; save(); if (c === '.' || c === '#' || c === '&') { return } if (name = $(this.variable) || $(this.property)) { if ((name.charAt(0) != '@') && (match = /^([^@+\/'"*`(;{}-]*);/.exec(chunks[j]))) { i += match[0].length - 1; value = new(tree.Anonymous)(match[1]); } else if (name === "font") { value = $(this.font); } else { value = $(this.value); } important = $(this.important); if (value && $(this.end)) { return new(tree.Rule)(name, value, important, memo); } else { furthest = i; restore(); } } }, // // An @import directive // // @import "lib"; // // Depending on our environemnt, importing is done differently: // In the browser, it's an XHR request, in Node, it would be a // file-system operation. The function used for importing is // stored in `import`, which we pass to the Import constructor. // "import": function () { var path; if ($(/^@import\s+/) && (path = $(this.entities.quoted) || $(this.entities.url)) && $(';')) { return new(tree.Import)(path, imports); } }, // // A CSS Directive // // @charset "utf-8"; // directive: function () { var name, value, rules, types; if (input.charAt(i) !== '@') return; if (value = $(this['import'])) { return value; } else if (name = $(/^@media|@page/) || $(/^@(?:-webkit-)?keyframes/)) { types = ($(/^[^{]+/) || '').trim(); if (rules = $(this.block)) { return new(tree.Directive)(name + " " + types, rules); } } else if (name = $(/^@[-a-z]+/)) { if (name === '@font-face') { if (rules = $(this.block)) { return new(tree.Directive)(name, rules); } } else if ((value = $(this.entity)) && $(';')) { return new(tree.Directive)(name, value); } } }, font: function () { var value = [], expression = [], weight, shorthand, font, e; while (e = $(this.shorthand) || $(this.entity)) { expression.push(e); } value.push(new(tree.Expression)(expression)); if ($(',')) { while (e = $(this.expression)) { value.push(e); if (! $(',')) { break } } } return new(tree.Value)(value); }, // // A Value is a comma-delimited list of Expressions // // font-family: Baskerville, Georgia, serif; // // In a Rule, a Value represents everything after the `:`, // and before the `;`. // value: function () { var e, expressions = [], important; while (e = $(this.expression)) { expressions.push(e); if (! $(',')) { break } } if (expressions.length > 0) { return new(tree.Value)(expressions); } }, important: function () { if (input.charAt(i) === '!') { return $(/^! *important/); } }, sub: function () { var e; if ($('(') && (e = $(this.expression)) && $(')')) { return e; } }, multiplication: function () { var m, a, op, operation; if (m = $(this.operand)) { while ((op = ($('/') || $('*'))) && (a = $(this.operand))) { operation = new(tree.Operation)(op, [operation || m, a]); } return operation || m; } }, addition: function () { var m, a, op, operation; if (m = $(this.multiplication)) { while ((op = $(/^[-+]\s+/) || (input.charAt(i - 1) != ' ' && ($('+') || $('-')))) && (a = $(this.multiplication))) { operation = new(tree.Operation)(op, [operation || m, a]); } return operation || m; } }, // // An operand is anything that can be part of an operation, // such as a Color, or a Variable // operand: function () { var negate, p = input.charAt(i + 1); if (input.charAt(i) === '-' && (p === '@' || p === '(')) { negate = $('-') } var o = $(this.sub) || $(this.entities.dimension) || $(this.entities.color) || $(this.entities.variable) || $(this.entities.call); return negate ? new(tree.Operation)('*', [new(tree.Dimension)(-1), o]) : o; }, // // Expressions either represent mathematical operations, // or white-space delimited Entities. // // 1px solid black // @var * 2 // expression: function () { var e, delim, entities = [], d; while (e = $(this.addition) || $(this.entity)) { entities.push(e); } if (entities.length > 0) { return new(tree.Expression)(entities); } }, property: function () { var name; if (name = $(/^(\*?-?[-a-z_0-9]+)\s*:/)) { return name[1]; } } } }; }; if (typeof(window) !== 'undefined') { // // Used by `@import` directives // less.Parser.importer = function (path, paths, callback, env) { if (path.charAt(0) !== '/' && paths.length > 0) { path = paths[0] + path; } // We pass `true` as 3rd argument, to force the reload of the import. // This is so we can get the syntax tree as opposed to just the CSS output, // as we need this to evaluate the current stylesheet. loadStyleSheet({ href: path, title: path, type: env.mime }, callback, true); }; } (function (tree) { tree.functions = { rgb: function (r, g, b) { return this.rgba(r, g, b, 1.0); }, rgba: function (r, g, b, a) { var rgb = [r, g, b].map(function (c) { return number(c) }), a = number(a); return new(tree.Color)(rgb, a); }, hsl: function (h, s, l) { return this.hsla(h, s, l, 1.0); }, hsla: function (h, s, l, a) { h = (number(h) % 360) / 360; s = number(s); l = number(l); a = number(a); var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s; var m1 = l * 2 - m2; return this.rgba(hue(h + 1/3) * 255, hue(h) * 255, hue(h - 1/3) * 255, a); function hue(h) { h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h); if (h * 6 < 1) return m1 + (m2 - m1) * h * 6; else if (h * 2 < 1) return m2; else if (h * 3 < 2) return m1 + (m2 - m1) * (2/3 - h) * 6; else return m1; } }, hue: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().h)); }, saturation: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().s * 100), '%'); }, lightness: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().l * 100), '%'); }, alpha: function (color) { return new(tree.Dimension)(color.toHSL().a); }, saturate: function (color, amount) { var hsl = color.toHSL(); hsl.s += amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, desaturate: function (color, amount) { var hsl = color.toHSL(); hsl.s -= amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, lighten: function (color, amount) { var hsl = color.toHSL(); hsl.l += amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, darken: function (color, amount) { var hsl = color.toHSL(); hsl.l -= amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, fadein: function (color, amount) { var hsl = color.toHSL(); hsl.a += amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, fadeout: function (color, amount) { var hsl = color.toHSL(); hsl.a -= amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, spin: function (color, amount) { var hsl = color.toHSL(); var hue = (hsl.h + amount.value) % 360; hsl.h = hue < 0 ? 360 + hue : hue; return hsla(hsl); }, // // Copyright (c) 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein // http://sass-lang.com // mix: function (color1, color2, weight) { var p = weight.value / 100.0; var w = p * 2 - 1; var a = color1.toHSL().a - color2.toHSL().a; var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0; var w2 = 1 - w1; var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2, color1.rgb[1] * w1 + color2.rgb[1] * w2, color1.rgb[2] * w1 + color2.rgb[2] * w2]; var alpha = color1.alpha * p + color2.alpha * (1 - p); return new(tree.Color)(rgb, alpha); }, greyscale: function (color) { return this.desaturate(color, new(tree.Dimension)(100)); }, e: function (str) { return new(tree.Anonymous)(str instanceof tree.JavaScript ? str.evaluated : str); }, escape: function (str) { return new(tree.Anonymous)(encodeURI(str.value).replace(/=/g, "%3D").replace(/:/g, "%3A").replace(/#/g, "%23").replace(/;/g, "%3B").replace(/\(/g, "%28").replace(/\)/g, "%29")); }, '%': function (quoted /* arg, arg, ...*/) { var args = Array.prototype.slice.call(arguments, 1), str = quoted.value; for (var i = 0; i < args.length; i++) { str = str.replace(/%[sda]/i, function(token) { var value = token.match(/s/i) ? args[i].value : args[i].toCSS(); return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value; }); } str = str.replace(/%%/g, '%'); return new(tree.Quoted)('"' + str + '"', str); }, round: function (n) { if (n instanceof tree.Dimension) { return new(tree.Dimension)(Math.round(number(n)), n.unit); } else if (typeof(n) === 'number') { return Math.round(n); } else { throw { error: "RuntimeError", message: "math functions take numbers as parameters" }; } } }; function hsla(hsla) { return tree.functions.hsla(hsla.h, hsla.s, hsla.l, hsla.a); } function number(n) { if (n instanceof tree.Dimension) { return parseFloat(n.unit == '%' ? n.value / 100 : n.value); } else if (typeof(n) === 'number') { return n; } else { throw { error: "RuntimeError", message: "color functions take numbers as parameters" }; } } function clamp(val) { return Math.min(1, Math.max(0, val)); } })(require('less/tree')); (function (tree) { tree.Alpha = function (val) { this.value = val; }; tree.Alpha.prototype = { toCSS: function () { return "alpha(opacity=" + (this.value.toCSS ? this.value.toCSS() : this.value) + ")"; }, eval: function (env) { if (this.value.eval) { this.value = this.value.eval(env) } return this; } }; })(require('less/tree')); (function (tree) { tree.Anonymous = function (string) { this.value = string.value || string; }; tree.Anonymous.prototype = { toCSS: function () { return this.value; }, eval: function () { return this } }; })(require('less/tree')); (function (tree) { // // A function call node. // tree.Call = function (name, args, index) { this.name = name; this.args = args; this.index = index; }; tree.Call.prototype = { // // When evaluating a function call, // we either find the function in `tree.functions` [1], // in which case we call it, passing the evaluated arguments, // or we simply print it out as it appeared originally [2]. // // The *functions.js* file contains the built-in functions. // // The reason why we evaluate the arguments, is in the case where // we try to pass a variable to a function, like: `saturate(@color)`. // The function should receive the value, not the variable. // eval: function (env) { var args = this.args.map(function (a) { return a.eval(env) }); if (this.name in tree.functions) { // 1. try { return tree.functions[this.name].apply(tree.functions, args); } catch (e) { throw { message: "error evaluating function `" + this.name + "`", index: this.index }; } } else { // 2. return new(tree.Anonymous)(this.name + "(" + args.map(function (a) { return a.toCSS() }).join(', ') + ")"); } }, toCSS: function (env) { return this.eval(env).toCSS(); } }; })(require('less/tree')); (function (tree) { // // RGB Colors - #ff0014, #eee // tree.Color = function (rgb, a) { // // The end goal here, is to parse the arguments // into an integer triplet, such as `128, 255, 0` // // This facilitates operations and conversions. // if (Array.isArray(rgb)) { this.rgb = rgb; } else if (rgb.length == 6) { this.rgb = rgb.match(/.{2}/g).map(function (c) { return parseInt(c, 16); }); } else if (rgb.length == 8) { this.alpha = parseInt(rgb.substring(0,2), 16) / 255.0; this.rgb = rgb.substr(2).match(/.{2}/g).map(function (c) { return parseInt(c, 16); }); } else { this.rgb = rgb.split('').map(function (c) { return parseInt(c + c, 16); }); } this.alpha = typeof(a) === 'number' ? a : 1; }; tree.Color.prototype = { eval: function () { return this }, // // If we have some transparency, the only way to represent it // is via `rgba`. Otherwise, we use the hex representation, // which has better compatibility with older browsers. // Values are capped between `0` and `255`, rounded and zero-padded. // toCSS: function () { if (this.alpha < 1.0) { return "rgba(" + this.rgb.map(function (c) { return Math.round(c); }).concat(this.alpha).join(', ') + ")"; } else { return '#' + this.rgb.map(function (i) { i = Math.round(i); i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16); return i.length === 1 ? '0' + i : i; }).join(''); } }, // // Operations have to be done per-channel, if not, // channels will spill onto each other. Once we have // our result, in the form of an integer triplet, // we create a new Color node to hold the result. // operate: function (op, other) { var result = []; if (! (other instanceof tree.Color)) { other = other.toColor(); } for (var c = 0; c < 3; c++) { result[c] = tree.operate(op, this.rgb[c], other.rgb[c]); } return new(tree.Color)(result, this.alpha + other.alpha); }, toHSL: function () { var r = this.rgb[0] / 255, g = this.rgb[1] / 255, b = this.rgb[2] / 255, a = this.alpha; var max = Math.max(r, g, b), min = Math.min(r, g, b); var h, s, l = (max + min) / 2, d = max - min; if (max === min) { h = s = 0; } else { s = l > 0.5 ? d / (2 - max - min) : d / (max + min); switch (max) { case r: h = (g - b) / d + (g < b ? 6 : 0); break; case g: h = (b - r) / d + 2; break; case b: h = (r - g) / d + 4; break; } h /= 6; } return { h: h * 360, s: s, l: l, a: a }; } }; })(require('less/tree')); (function (tree) { tree.Comment = function (value, silent) { this.value = value; this.silent = !!silent; }; tree.Comment.prototype = { toCSS: function (env) { return env.compress ? '' : this.value; }, eval: function () { return this } }; })(require('less/tree')); (function (tree) { // // A number with a unit // tree.Dimension = function (value, unit) { this.value = parseFloat(value); this.unit = unit || null; }; tree.Dimension.prototype = { eval: function () { return this }, toColor: function () { return new(tree.Color)([this.value, this.value, this.value]); }, toCSS: function () { var css = this.value + this.unit; return css; }, // In an operation between two Dimensions, // we default to the first Dimension's unit, // so `1px + 2em` will yield `3px`. // In the future, we could implement some unit // conversions such that `100cm + 10mm` would yield // `101cm`. operate: function (op, other) { return new(tree.Dimension) (tree.operate(op, this.value, other.value), this.unit || other.unit); } }; })(require('less/tree')); (function (tree) { tree.Directive = function (name, value) { this.name = name; if (Array.isArray(value)) { this.ruleset = new(tree.Ruleset)([], value); } else { this.value = value; } }; tree.Directive.prototype = { toCSS: function (ctx, env) { if (this.ruleset) { this.ruleset.root = true; return this.name + (env.compress ? '{' : ' {\n ') + this.ruleset.toCSS(ctx, env).trim().replace(/\n/g, '\n ') + (env.compress ? '}': '\n}\n'); } else { return this.name + ' ' + this.value.toCSS() + ';\n'; } }, eval: function (env) { env.frames.unshift(this); this.ruleset = this.ruleset && this.ruleset.eval(env); env.frames.shift(); return this; }, variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) }, find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) }, rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) } }; })(require('less/tree')); (function (tree) { tree.Element = function (combinator, value) { this.combinator = combinator instanceof tree.Combinator ? combinator : new(tree.Combinator)(combinator); this.value = value ? value.trim() : ""; }; tree.Element.prototype.toCSS = function (env) { return this.combinator.toCSS(env || {}) + this.value; }; tree.Combinator = function (value) { if (value === ' ') { this.value = ' '; } else if (value === '& ') { this.value = '& '; } else { this.value = value ? value.trim() : ""; } }; tree.Combinator.prototype.toCSS = function (env) { return { '' : '', ' ' : ' ', '&' : '', '& ' : ' ', ':' : ' :', '::': '::', '+' : env.compress ? '+' : ' + ', '~' : env.compress ? '~' : ' ~ ', '>' : env.compress ? '>' : ' > ' }[this.value]; }; })(require('less/tree')); (function (tree) { tree.Expression = function (value) { this.value = value }; tree.Expression.prototype = { eval: function (env) { if (this.value.length > 1) { return new(tree.Expression)(this.value.map(function (e) { return e.eval(env); })); } else if (this.value.length === 1) { return this.value[0].eval(env); } else { return this; } }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS(env); }).join(' '); } }; })(require('less/tree')); (function (tree) { // // CSS @import node // // The general strategy here is that we don't want to wait // for the parsing to be completed, before we start importing // the file. That's because in the context of a browser, // most of the time will be spent waiting for the server to respond. // // On creation, we push the import path to our import queue, though // `import,push`, we also pass it a callback, which it'll call once // the file has been fetched, and parsed. // tree.Import = function (path, imports) { var that = this; this._path = path; // The '.less' extension is optional if (path instanceof tree.Quoted) { this.path = /\.(le?|c)ss$/.test(path.value) ? path.value : path.value + '.less'; } else { this.path = path.value.value || path.value; } this.css = /css$/.test(this.path); // Only pre-compile .less files if (! this.css) { imports.push(this.path, function (root) { if (! root) { throw new(Error)("Error parsing " + that.path); } that.root = root; }); } }; // // The actual import node doesn't return anything, when converted to CSS. // The reason is that it's used at the evaluation stage, so that the rules // it imports can be treated like any other rules. // // In `eval`, we make sure all Import nodes get evaluated, recursively, so // we end up with a flat structure, which can easily be imported in the parent // ruleset. // tree.Import.prototype = { toCSS: function () { if (this.css) { return "@import " + this._path.toCSS() + ';\n'; } else { return ""; } }, eval: function (env) { var ruleset; if (this.css) { return this; } else { ruleset = new(tree.Ruleset)(null, this.root.rules.slice(0)); for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.Import) { Array.prototype .splice .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env))); } } return ruleset.rules; } } }; })(require('less/tree')); (function (tree) { tree.JavaScript = function (string, index, escaped) { this.escaped = escaped; this.expression = string; this.index = index; }; tree.JavaScript.prototype = { eval: function (env) { var result, that = this, context = {}; var expression = this.expression.replace(/@\{([\w-]+)\}/g, function (_, name) { return tree.jsify(new(tree.Variable)('@' + name, that.index).eval(env)); }); try { expression = new(Function)('return (' + expression + ')'); } catch (e) { throw { message: "JavaScript evaluation error: `" + expression + "`" , index: this.index }; } for (var k in env.frames[0].variables()) { context[k.slice(1)] = { value: env.frames[0].variables()[k].value, toJS: function () { return this.value.eval(env).toCSS(); } }; } try { result = expression.call(context); } catch (e) { throw { message: "JavaScript evaluation error: '" + e.name + ': ' + e.message + "'" , index: this.index }; } if (typeof(result) === 'string') { return new(tree.Quoted)('"' + result + '"', result, this.escaped, this.index); } else if (Array.isArray(result)) { return new(tree.Anonymous)(result.join(', ')); } else { return new(tree.Anonymous)(result); } } }; })(require('less/tree')); (function (tree) { tree.Keyword = function (value) { this.value = value }; tree.Keyword.prototype = { eval: function () { return this }, toCSS: function () { return this.value } }; })(require('less/tree')); (function (tree) { tree.mixin = {}; tree.mixin.Call = function (elements, args, index) { this.selector = new(tree.Selector)(elements); this.arguments = args; this.index = index; }; tree.mixin.Call.prototype = { eval: function (env) { var mixins, args, rules = [], match = false; for (var i = 0; i < env.frames.length; i++) { if ((mixins = env.frames[i].find(this.selector)).length > 0) { args = this.arguments && this.arguments.map(function (a) { return a.eval(env) }); for (var m = 0; m < mixins.length; m++) { if (mixins[m].match(args, env)) { try { Array.prototype.push.apply( rules, mixins[m].eval(env, this.arguments).rules); match = true; } catch (e) { throw { message: e.message, index: e.index, stack: e.stack, call: this.index }; } } } if (match) { return rules; } else { throw { message: 'No matching definition was found for `' + this.selector.toCSS().trim() + '(' + this.arguments.map(function (a) { return a.toCSS(); }).join(', ') + ")`", index: this.index }; } } } throw { message: this.selector.toCSS().trim() + " is undefined", index: this.index }; } }; tree.mixin.Definition = function (name, params, rules) { this.name = name; this.selectors = [new(tree.Selector)([new(tree.Element)(null, name)])]; this.params = params; this.arity = params.length; this.rules = rules; this._lookups = {}; this.required = params.reduce(function (count, p) { if (!p.name || (p.name && !p.value)) { return count + 1 } else { return count } }, 0); this.parent = tree.Ruleset.prototype; this.frames = []; }; tree.mixin.Definition.prototype = { toCSS: function () { return "" }, variable: function (name) { return this.parent.variable.call(this, name) }, variables: function () { return this.parent.variables.call(this) }, find: function () { return this.parent.find.apply(this, arguments) }, rulesets: function () { return this.parent.rulesets.apply(this) }, eval: function (env, args) { var frame = new(tree.Ruleset)(null, []), context, _arguments = []; for (var i = 0, val; i < this.params.length; i++) { if (this.params[i].name) { if (val = (args && args[i]) || this.params[i].value) { frame.rules.unshift(new(tree.Rule)(this.params[i].name, val.eval(env))); } else { throw { message: "wrong number of arguments for " + this.name + ' (' + args.length + ' for ' + this.arity + ')' }; } } } for (var i = 0; i < Math.max(this.params.length, args && args.length); i++) { _arguments.push(args[i] || this.params[i].value); } frame.rules.unshift(new(tree.Rule)('@arguments', new(tree.Expression)(_arguments).eval(env))); return new(tree.Ruleset)(null, this.rules.slice(0)).eval({ frames: [this, frame].concat(this.frames, env.frames) }); }, match: function (args, env) { var argsLength = (args && args.length) || 0, len; if (argsLength < this.required) { return false } if ((this.required > 0) && (argsLength > this.params.length)) { return false } len = Math.min(argsLength, this.arity); for (var i = 0; i < len; i++) { if (!this.params[i].name) { if (args[i].eval(env).toCSS() != this.params[i].value.eval(env).toCSS()) { return false; } } } return true; } }; })(require('less/tree')); (function (tree) { tree.Operation = function (op, operands) { this.op = op.trim(); this.operands = operands; }; tree.Operation.prototype.eval = function (env) { var a = this.operands[0].eval(env), b = this.operands[1].eval(env), temp; if (a instanceof tree.Dimension && b instanceof tree.Color) { if (this.op === '*' || this.op === '+') { temp = b, b = a, a = temp; } else { throw { name: "OperationError", message: "Can't substract or divide a color from a number" }; } } return a.operate(this.op, b); }; tree.operate = function (op, a, b) { switch (op) { case '+': return a + b; case '-': return a - b; case '*': return a * b; case '/': return a / b; } }; })(require('less/tree')); (function (tree) { tree.Quoted = function (str, content, escaped, i) { this.escaped = escaped; this.value = content || ''; this.quote = str.charAt(0); this.index = i; }; tree.Quoted.prototype = { toCSS: function () { if (this.escaped) { return this.value; } else { return this.quote + this.value + this.quote; } }, eval: function (env) { var that = this; var value = this.value.replace(/`([^`]+)`/g, function (_, exp) { return new(tree.JavaScript)(exp, that.index, true).eval(env).value; }).replace(/@\{([\w-]+)\}/g, function (_, name) { var v = new(tree.Variable)('@' + name, that.index).eval(env); return v.value || v.toCSS(); }); return new(tree.Quoted)(this.quote + value + this.quote, value, this.escaped, this.index); } }; })(require('less/tree')); (function (tree) { tree.Rule = function (name, value, important, index) { this.name = name; this.value = (value instanceof tree.Value) ? value : new(tree.Value)([value]); this.important = important ? ' ' + important.trim() : ''; this.index = index; if (name.charAt(0) === '@') { this.variable = true; } else { this.variable = false } }; tree.Rule.prototype.toCSS = function (env) { if (this.variable) { return "" } else { return this.name + (env.compress ? ':' : ': ') + this.value.toCSS(env) + this.important + ";"; } }; tree.Rule.prototype.eval = function (context) { return new(tree.Rule)(this.name, this.value.eval(context), this.important, this.index); }; tree.Shorthand = function (a, b) { this.a = a; this.b = b; }; tree.Shorthand.prototype = { toCSS: function (env) { return this.a.toCSS(env) + "/" + this.b.toCSS(env); }, eval: function () { return this } }; })(require('less/tree')); (function (tree) { tree.Ruleset = function (selectors, rules) { this.selectors = selectors; this.rules = rules; this._lookups = {}; }; tree.Ruleset.prototype = { eval: function (env) { var ruleset = new(tree.Ruleset)(this.selectors, this.rules.slice(0)); ruleset.root = this.root; // push the current ruleset to the frames stack env.frames.unshift(ruleset); // Evaluate imports if (ruleset.root) { for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.Import) { Array.prototype.splice .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env))); } } } // Store the frames around mixin definitions, // so they can be evaluated like closures when the time comes. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Definition) { ruleset.rules[i].frames = env.frames.slice(0); } } // Evaluate mixin calls. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Call) { Array.prototype.splice .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env))); } } // Evaluate everything else for (var i = 0, rule; i < ruleset.rules.length; i++) { rule = ruleset.rules[i]; if (! (rule instanceof tree.mixin.Definition)) { ruleset.rules[i] = rule.eval ? rule.eval(env) : rule; } } // Pop the stack env.frames.shift(); return ruleset; }, match: function (args) { return !args || args.length === 0; }, variables: function () { if (this._variables) { return this._variables } else { return this._variables = this.rules.reduce(function (hash, r) { if (r instanceof tree.Rule && r.variable === true) { hash[r.name] = r; } return hash; }, {}); } }, variable: function (name) { return this.variables()[name]; }, rulesets: function () { if (this._rulesets) { return this._rulesets } else { return this._rulesets = this.rules.filter(function (r) { return (r instanceof tree.Ruleset) || (r instanceof tree.mixin.Definition); }); } }, find: function (selector, self) { self = self || this; var rules = [], rule, match, key = selector.toCSS(); if (key in this._lookups) { return this._lookups[key] } this.rulesets().forEach(function (rule) { if (rule !== self) { for (var j = 0; j < rule.selectors.length; j++) { if (match = selector.match(rule.selectors[j])) { if (selector.elements.length > 1) { Array.prototype.push.apply(rules, rule.find( new(tree.Selector)(selector.elements.slice(1)), self)); } else { rules.push(rule); } break; } } } }); return this._lookups[key] = rules; }, // // Entry point for code generation // // `context` holds an array of arrays. // toCSS: function (context, env) { var css = [], // The CSS output rules = [], // node.Rule instances rulesets = [], // node.Ruleset instances paths = [], // Current selectors selector, // The fully rendered selector rule; if (! this.root) { if (context.length === 0) { paths = this.selectors.map(function (s) { return [s] }); } else { this.joinSelectors( paths, context, this.selectors ); } } // Compile rules and rulesets for (var i = 0; i < this.rules.length; i++) { rule = this.rules[i]; if (rule.rules || (rule instanceof tree.Directive)) { rulesets.push(rule.toCSS(paths, env)); } else if (rule instanceof tree.Comment) { if (!rule.silent) { if (this.root) { rulesets.push(rule.toCSS(env)); } else { rules.push(rule.toCSS(env)); } } } else { if (rule.toCSS && !rule.variable) { rules.push(rule.toCSS(env)); } else if (rule.value && !rule.variable) { rules.push(rule.value.toString()); } } } rulesets = rulesets.join(''); // If this is the root node, we don't render // a selector, or {}. // Otherwise, only output if this ruleset has rules. if (this.root) { css.push(rules.join(env.compress ? '' : '\n')); } else { if (rules.length > 0) { selector = paths.map(function (p) { return p.map(function (s) { return s.toCSS(env); }).join('').trim(); }).join(env.compress ? ',' : (paths.length > 3 ? ',\n' : ', ')); css.push(selector, (env.compress ? '{' : ' {\n ') + rules.join(env.compress ? '' : '\n ') + (env.compress ? '}' : '\n}\n')); } } css.push(rulesets); return css.join('') + (env.compress ? '\n' : ''); }, joinSelectors: function (paths, context, selectors) { for (var s = 0; s < selectors.length; s++) { this.joinSelector(paths, context, selectors[s]); } }, joinSelector: function (paths, context, selector) { var before = [], after = [], beforeElements = [], afterElements = [], hasParentSelector = false, el; for (var i = 0; i < selector.elements.length; i++) { el = selector.elements[i]; if (el.combinator.value[0] === '&') { hasParentSelector = true; } if (hasParentSelector) afterElements.push(el); else beforeElements.push(el); } if (! hasParentSelector) { afterElements = beforeElements; beforeElements = []; } if (beforeElements.length > 0) { before.push(new(tree.Selector)(beforeElements)); } if (afterElements.length > 0) { after.push(new(tree.Selector)(afterElements)); } for (var c = 0; c < context.length; c++) { paths.push(before.concat(context[c]).concat(after)); } } }; })(require('less/tree')); (function (tree) { tree.Selector = function (elements) { this.elements = elements; if (this.elements[0].combinator.value === "") { this.elements[0].combinator.value = ' '; } }; tree.Selector.prototype.match = function (other) { if (this.elements[0].value === other.elements[0].value) { return true; } else { return false; } }; tree.Selector.prototype.toCSS = function (env) { if (this._css) { return this._css } return this._css = this.elements.map(function (e) { if (typeof(e) === 'string') { return ' ' + e.trim(); } else { return e.toCSS(env); } }).join(''); }; })(require('less/tree')); (function (tree) { tree.URL = function (val, paths) { if (val.data) { this.attrs = val; } else { // Add the base path if the URL is relative and we are in the browser if (!/^(?:https?:\/|file:\/|data:\/)?\//.test(val.value) && paths.length > 0 && typeof(window) !== 'undefined') { val.value = paths[0] + (val.value.charAt(0) === '/' ? val.value.slice(1) : val.value); } this.value = val; this.paths = paths; } }; tree.URL.prototype = { toCSS: function () { return "url(" + (this.attrs ? 'data:' + this.attrs.mime + this.attrs.charset + this.attrs.base64 + this.attrs.data : this.value.toCSS()) + ")"; }, eval: function (ctx) { return this.attrs ? this : new(tree.URL)(this.value.eval(ctx), this.paths); } }; })(require('less/tree')); (function (tree) { tree.Value = function (value) { this.value = value; this.is = 'value'; }; tree.Value.prototype = { eval: function (env) { if (this.value.length === 1) { return this.value[0].eval(env); } else { return new(tree.Value)(this.value.map(function (v) { return v.eval(env); })); } }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS(env); }).join(env.compress ? ',' : ', '); } }; })(require('less/tree')); (function (tree) { tree.Variable = function (name, index) { this.name = name, this.index = index }; tree.Variable.prototype = { eval: function (env) { var variable, v, name = this.name; if (name.indexOf('@@') == 0) { name = '@' + new(tree.Variable)(name.slice(1)).eval(env).value; } if (variable = tree.find(env.frames, function (frame) { if (v = frame.variable(name)) { return v.value.eval(env); } })) { return variable } else { throw { message: "variable " + name + " is undefined", index: this.index }; } } }; })(require('less/tree')); require('less/tree').find = function (obj, fun) { for (var i = 0, r; i < obj.length; i++) { if (r = fun.call(obj, obj[i])) { return r } } return null; }; require('less/tree').jsify = function (obj) { if (Array.isArray(obj.value) && (obj.value.length > 1)) { return '[' + obj.value.map(function (v) { return v.toCSS(false) }).join(', ') + ']'; } else { return obj.toCSS(false); } }; // // browser.js - client-side engine // var isFileProtocol = (location.protocol === 'file:' || location.protocol === 'chrome:' || location.protocol === 'chrome-extension:' || location.protocol === 'resource:'); less.env = less.env || (location.hostname == '127.0.0.1' || location.hostname == '0.0.0.0' || location.hostname == 'localhost' || location.port.length > 0 || isFileProtocol ? 'development' : 'production'); // Load styles asynchronously (default: false) // // This is set to `false` by default, so that the body // doesn't start loading before the stylesheets are parsed. // Setting this to `true` can result in flickering. // less.async = false; // Interval between watch polls less.poll = less.poll || (isFileProtocol ? 1000 : 1500); // // Watch mode // less.watch = function () { return this.watchMode = true }; less.unwatch = function () { return this.watchMode = false }; if (less.env === 'development') { less.optimization = 0; if (/!watch/.test(location.hash)) { less.watch(); } less.watchTimer = setInterval(function () { if (less.watchMode) { loadStyleSheets(function (root, sheet, env) { if (root) { createCSS(root.toCSS(), sheet, env.lastModified); } }); } }, less.poll); } else { less.optimization = 3; } var cache; try { cache = (typeof(window.localStorage) === 'undefined') ? null : window.localStorage; } catch (_) { cache = null; } // // Get all tags with the 'rel' attribute set to "stylesheet/less" // var links = document.getElementsByTagName('link'); var typePattern = /^text\/(x-)?less$/; less.sheets = []; for (var i = 0; i < links.length; i++) { if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) && (links[i].type.match(typePattern)))) { less.sheets.push(links[i]); } } less.refresh = function (reload) { var startTime, endTime; startTime = endTime = new(Date); loadStyleSheets(function (root, sheet, env) { if (env.local) { log("loading " + sheet.href + " from cache."); } else { log("parsed " + sheet.href + " successfully."); createCSS(root.toCSS(), sheet, env.lastModified); } log("css for " + sheet.href + " generated in " + (new(Date) - endTime) + 'ms'); (env.remaining === 0) && log("css generated in " + (new(Date) - startTime) + 'ms'); endTime = new(Date); }, reload); loadStyles(); }; less.refreshStyles = loadStyles; less.refresh(less.env === 'development'); function loadStyles() { var styles = document.getElementsByTagName('style'); for (var i = 0; i < styles.length; i++) { if (styles[i].type.match(typePattern)) { new(less.Parser)().parse(styles[i].innerHTML || '', function (e, tree) { styles[i].type = 'text/css'; styles[i].innerHTML = tree.toCSS(); }); } } } function loadStyleSheets(callback, reload) { for (var i = 0; i < less.sheets.length; i++) { loadStyleSheet(less.sheets[i], callback, reload, less.sheets.length - (i + 1)); } } function loadStyleSheet(sheet, callback, reload, remaining) { var url = window.location.href.replace(/[#?].*$/, ''); var href = sheet.href.replace(/\?.*$/, ''); var css = cache && cache.getItem(href); var timestamp = cache && cache.getItem(href + ':timestamp'); var styles = { css: css, timestamp: timestamp }; // Stylesheets in IE don't always return the full path if (! /^(https?|file):/.test(href)) { if (href.charAt(0) == "/") { href = window.location.protocol + "//" + window.location.host + href; } else { href = url.slice(0, url.lastIndexOf('/') + 1) + href; } } xhr(sheet.href, sheet.type, function (data, lastModified) { if (!reload && styles && lastModified && (new(Date)(lastModified).valueOf() === new(Date)(styles.timestamp).valueOf())) { // Use local copy createCSS(styles.css, sheet); callback(null, sheet, { local: true, remaining: remaining }); } else { // Use remote copy (re-parse) try { new(less.Parser)({ optimization: less.optimization, paths: [href.replace(/[\w\.-]+$/, '')], mime: sheet.type }).parse(data, function (e, root) { if (e) { return error(e, href) } try { callback(root, sheet, { local: false, lastModified: lastModified, remaining: remaining }); removeNode(document.getElementById('less-error-message:' + extractId(href))); } catch (e) { error(e, href); } }); } catch (e) { error(e, href); } } }, function (status, url) { throw new(Error)("Couldn't load " + url + " (" + status + ")"); }); } function extractId(href) { return href.replace(/^[a-z]+:\/\/?[^\/]+/, '' ) // Remove protocol & domain .replace(/^\//, '' ) // Remove root / .replace(/\?.*$/, '' ) // Remove query .replace(/\.[^\.\/]+$/, '' ) // Remove file extension .replace(/[^\.\w-]+/g, '-') // Replace illegal characters .replace(/\./g, ':'); // Replace dots with colons(for valid id) } function createCSS(styles, sheet, lastModified) { var css; // Strip the query-string var href = sheet.href ? sheet.href.replace(/\?.*$/, '') : ''; // If there is no title set, use the filename, minus the extension var id = 'less:' + (sheet.title || extractId(href)); // If the stylesheet doesn't exist, create a new node if ((css = document.getElementById(id)) === null) { css = document.createElement('style'); css.type = 'text/css'; css.media = sheet.media || 'screen'; css.id = id; document.getElementsByTagName('head')[0].appendChild(css); } if (css.styleSheet) { // IE try { css.styleSheet.cssText = styles; } catch (e) { throw new(Error)("Couldn't reassign styleSheet.cssText."); } } else { (function (node) { if (css.childNodes.length > 0) { if (css.firstChild.nodeValue !== node.nodeValue) { css.replaceChild(node, css.firstChild); } } else { css.appendChild(node); } })(document.createTextNode(styles)); } // Don't update the local store if the file wasn't modified if (lastModified && cache) { log('saving ' + href + ' to cache.'); cache.setItem(href, styles); cache.setItem(href + ':timestamp', lastModified); } } function xhr(url, type, callback, errback) { var xhr = getXMLHttpRequest(); var async = isFileProtocol ? false : less.async; if (typeof(xhr.overrideMimeType) === 'function') { xhr.overrideMimeType('text/css'); } xhr.open('GET', url, async); xhr.setRequestHeader('Accept', type || 'text/x-less, text/css; q=0.9, */*; q=0.5'); xhr.send(null); if (isFileProtocol) { if (xhr.status === 0) { callback(xhr.responseText); } else { errback(xhr.status, url); } } else if (async) { xhr.onreadystatechange = function () { if (xhr.readyState == 4) { handleResponse(xhr, callback, errback); } }; } else { handleResponse(xhr, callback, errback); } function handleResponse(xhr, callback, errback) { if (xhr.status >= 200 && xhr.status < 300) { callback(xhr.responseText, xhr.getResponseHeader("Last-Modified")); } else if (typeof(errback) === 'function') { errback(xhr.status, url); } } } function getXMLHttpRequest() { if (window.XMLHttpRequest) { return new(XMLHttpRequest); } else { try { return new(ActiveXObject)("MSXML2.XMLHTTP.3.0"); } catch (e) { log("browser doesn't support AJAX."); return null; } } } function removeNode(node) { return node && node.parentNode.removeChild(node); } function log(str) { if (less.env == 'development' && typeof(console) !== "undefined") { console.log('less: ' + str) } } function error(e, href) { var id = 'less-error-message:' + extractId(href); var template = ['
    ', '
  • {0}
  • ', '
  • {current}
  • ', '
  • {2}
  • ', '
'].join('\n'); var elem = document.createElement('div'), timer, content; elem.id = id; elem.className = "less-error-message"; content = '

' + (e.message || 'There is an error in your .less file') + '

' + '

' + href + " "; if (e.extract) { content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':

' + template.replace(/\[(-?\d)\]/g, function (_, i) { return (parseInt(e.line) + parseInt(i)) || ''; }).replace(/\{(\d)\}/g, function (_, i) { return e.extract[parseInt(i)] || ''; }).replace(/\{current\}/, e.extract[1].slice(0, e.column) + '' + e.extract[1].slice(e.column) + ''); } elem.innerHTML = content; // CSS for error messages createCSS([ '.less-error-message ul, .less-error-message li {', 'list-style-type: none;', 'margin-right: 15px;', 'padding: 4px 0;', 'margin: 0;', '}', '.less-error-message label {', 'font-size: 12px;', 'margin-right: 15px;', 'padding: 4px 0;', 'color: #cc7777;', '}', '.less-error-message pre {', 'color: #ee4444;', 'padding: 4px 0;', 'margin: 0;', 'display: inline-block;', '}', '.less-error-message pre.ctx {', 'color: #dd4444;', '}', '.less-error-message h3 {', 'font-size: 20px;', 'font-weight: bold;', 'padding: 15px 0 5px 0;', 'margin: 0;', '}', '.less-error-message a {', 'color: #10a', '}', '.less-error-message .error {', 'color: red;', 'font-weight: bold;', 'padding-bottom: 2px;', 'border-bottom: 1px dashed red;', '}' ].join('\n'), { title: 'error-message' }); elem.style.cssText = [ "font-family: Arial, sans-serif", "border: 1px solid #e00", "background-color: #eee", "border-radius: 5px", "-webkit-border-radius: 5px", "-moz-border-radius: 5px", "color: #e00", "padding: 15px", "margin-bottom: 15px" ].join(';'); if (less.env == 'development') { timer = setInterval(function () { if (document.body) { if (document.getElementById(id)) { document.body.replaceChild(elem, document.getElementById(id)); } else { document.body.insertBefore(elem, document.body.firstChild); } clearInterval(timer); } }, 10); } } })(window); less.js-1.4.2/dist/less-1.1.4.min.js000066400000000000000000001050241217256642200166000ustar00rootroot00000000000000// // LESS - Leaner CSS v1.1.4 // http://lesscss.org // // Copyright (c) 2009-2011, Alexis Sellier // Licensed under the Apache 2.0 License. // // // LESS - Leaner CSS v1.1.4 // http://lesscss.org // // Copyright (c) 2009-2011, Alexis Sellier // Licensed under the Apache 2.0 License. // (function(a,b){function u(a,b){var c="less-error-message:"+o(b),e=["
    ",'
  • {0}
  • ',"
  • {current}
  • ",'
  • {2}
  • ',"
"].join("\n"),f=document.createElement("div"),g,h;f.id=c,f.className="less-error-message",h="

"+(a.message||"There is an error in your .less file")+"

"+'

'+b+" ",a.extract&&(h+="on line "+a.line+", column "+(a.column+1)+":

"+e.replace(/\[(-?\d)\]/g,function(b,c){return parseInt(a.line)+parseInt(c)||""}).replace(/\{(\d)\}/g,function(b,c){return a.extract[parseInt(c)]||""}).replace(/\{current\}/,a.extract[1].slice(0,a.column)+''+a.extract[1].slice(a.column)+"")),f.innerHTML=h,p([".less-error-message ul, .less-error-message li {","list-style-type: none;","margin-right: 15px;","padding: 4px 0;","margin: 0;","}",".less-error-message label {","font-size: 12px;","margin-right: 15px;","padding: 4px 0;","color: #cc7777;","}",".less-error-message pre {","color: #ee4444;","padding: 4px 0;","margin: 0;","display: inline-block;","}",".less-error-message pre.ctx {","color: #dd4444;","}",".less-error-message h3 {","font-size: 20px;","font-weight: bold;","padding: 15px 0 5px 0;","margin: 0;","}",".less-error-message a {","color: #10a","}",".less-error-message .error {","color: red;","font-weight: bold;","padding-bottom: 2px;","border-bottom: 1px dashed red;","}"].join("\n"),{title:"error-message"}),f.style.cssText=["font-family: Arial, sans-serif","border: 1px solid #e00","background-color: #eee","border-radius: 5px","-webkit-border-radius: 5px","-moz-border-radius: 5px","color: #e00","padding: 15px","margin-bottom: 15px"].join(";"),d.env=="development"&&(g=setInterval(function(){document.body&&(document.getElementById(c)?document.body.replaceChild(f,document.getElementById(c)):document.body.insertBefore(f,document.body.firstChild),clearInterval(g))},10))}function t(a){d.env=="development"&&typeof console!="undefined"&&console.log("less: "+a)}function s(a){return a&&a.parentNode.removeChild(a)}function r(){if(a.XMLHttpRequest)return new XMLHttpRequest;try{return new ActiveXObject("MSXML2.XMLHTTP.3.0")}catch(b){t("browser doesn't support AJAX.");return null}}function q(a,b,c,e){function i(b,c,d){b.status>=200&&b.status<300?c(b.responseText,b.getResponseHeader("Last-Modified")):typeof d=="function"&&d(b.status,a)}var g=r(),h=f?!1:d.async;typeof g.overrideMimeType=="function"&&g.overrideMimeType("text/css"),g.open("GET",a,h),g.setRequestHeader("Accept",b||"text/x-less, text/css; q=0.9, */*; q=0.5"),g.send(null),f?g.status===0?c(g.responseText):e(g.status,a):h?g.onreadystatechange=function(){g.readyState==4&&i(g,c,e)}:i(g,c,e)}function p(a,b,c){var d,e=b.href?b.href.replace(/\?.*$/,""):"",f="less:"+(b.title||o(e));(d=document.getElementById(f))===null&&(d=document.createElement("style"),d.type="text/css",d.media=b.media||"screen",d.id=f,document.getElementsByTagName("head")[0].appendChild(d));if(d.styleSheet)try{d.styleSheet.cssText=a}catch(h){throw new Error("Couldn't reassign styleSheet.cssText.")}else(function(a){d.childNodes.length>0?d.firstChild.nodeValue!==a.nodeValue&&d.replaceChild(a,d.firstChild):d.appendChild(a)})(document.createTextNode(a));c&&g&&(t("saving "+e+" to cache."),g.setItem(e,a),g.setItem(e+":timestamp",c))}function o(a){return a.replace(/^[a-z]+:\/\/?[^\/]+/,"").replace(/^\//,"").replace(/\?.*$/,"").replace(/\.[^\.\/]+$/,"").replace(/[^\.\w-]+/g,"-").replace(/\./g,":")}function n(b,c,e,f){var h=a.location.href.replace(/[#?].*$/,""),i=b.href.replace(/\?.*$/,""),j=g&&g.getItem(i),k=g&&g.getItem(i+":timestamp"),l={css:j,timestamp:k};/^(https?|file):/.test(i)||(i.charAt(0)=="/"?i=a.location.protocol+"//"+a.location.host+i:i=h.slice(0,h.lastIndexOf("/")+1)+i),q(b.href,b.type,function(a,g){if(!e&&l&&g&&(new Date(g)).valueOf()===(new Date(l.timestamp)).valueOf())p(l.css,b),c(null,b,{local:!0,remaining:f});else try{(new d.Parser({optimization:d.optimization,paths:[i.replace(/[\w\.-]+$/,"")],mime:b.type})).parse(a,function(a,d){if(a)return u(a,i);try{c(d,b,{local:!1,lastModified:g,remaining:f}),s(document.getElementById("less-error-message:"+o(i)))}catch(a){u(a,i)}})}catch(h){u(h,i)}},function(a,b){throw new Error("Couldn't load "+b+" ("+a+")")})}function m(a,b){for(var c=0;c>>0;for(var d=0;d>>0,c=Array(b),d=arguments[1];for(var e=0;e>>0,c=0;if(b===0&&arguments.length===1)throw new TypeError;if(arguments.length>=2)var d=arguments[1];else do{if(c in this){d=this[c++];break}if(++c>=b)throw new TypeError}while(!0);for(;c=b)return-1;c<0&&(c+=b);for(;ck&&(j[f]=j[f].slice(c-k),k=c)}function q(){j[f]=g,c=h,k=c}function p(){g=j[f],h=c,k=c}var b,c,f,g,h,i,j,k,l,m=this,n=function(){},o=this.imports={paths:a&&a.paths||[],queue:[],files:{},mime:a&&a.mime,push:function(b,c){var e=this;this.queue.push(b),d.Parser.importer(b,this.paths,function(a){e.queue.splice(e.queue.indexOf(b),1),e.files[b]=a,c(a),e.queue.length===0&&n()},a)}};this.env=a=a||{},this.optimization="optimization"in this.env?this.env.optimization:1,this.env.filename=this.env.filename||null;return l={imports:o,parse:function(d,g){var h,l,m,o,p,q,r=[],t,u=null;c=f=k=i=0,j=[],b=d.replace(/\r\n/g,"\n"),j=function(c){var d=0,e=/[^"'`\{\}\/\(\)]+/g,f=/\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g,g=0,h,i=c[0],j,k;for(var l=0,m,n;l0)throw{type:"Syntax",message:"Missing closing `}`",filename:a.filename};return c.map(function(a){return a.join("")})}([[]]),h=new e.Ruleset([],s(this.parsers.primary)),h.root=!0,h.toCSS=function(c){var d,f,g;return function(g,h){function n(a){return a?(b.slice(0,a).match(/\n/g)||"").length:null}var i=[];g=g||{},typeof h=="object"&&!Array.isArray(h)&&(h=Object.keys(h).map(function(a){var b=h[a];b instanceof e.Value||(b instanceof e.Expression||(b=new e.Expression([b])),b=new e.Value([b]));return new e.Rule("@"+a,b,!1,0)}),i=[new e.Ruleset(null,h)]);try{var j=c.call(this,{frames:i}).toCSS([],{compress:g.compress||!1})}catch(k){f=b.split("\n"),d=n(k.index);for(var l=k.index,m=-1;l>=0&&b.charAt(l)!=="\n";l--)m++;throw{type:k.type,message:k.message,filename:a.filename,index:k.index,line:typeof d=="number"?d+1:null,callLine:k.call&&n(k.call)+1,callExtract:f[n(k.call)],stack:k.stack,column:m,extract:[f[d-1],f[d],f[d+1]]}}return g.compress?j.replace(/(\s)+/g,"$1"):j}}(h.eval);if(c=0&&b.charAt(v)!=="\n";v--)w++;u={name:"ParseError",message:"Syntax Error on line "+p,index:c,filename:a.filename,line:p,column:w,extract:[q[p-2],q[p-1],q[p]]}}this.imports.queue.length>0?n=function(){g(u,h)}:g(u,h)},parsers:{primary:function(){var a,b=[];while((a=s(this.mixin.definition)||s(this.rule)||s(this.ruleset)||s(this.mixin.call)||s(this.comment)||s(this.directive))||s(/^[\s\n]+/))a&&b.push(a);return b},comment:function(){var a;if(b.charAt(c)==="/"){if(b.charAt(c+1)==="/")return new e.Comment(s(/^\/\/.*/),!0);if(a=s(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/))return new e.Comment(a)}},entities:{quoted:function(){var a,d=c,f;b.charAt(d)==="~"&&(d++,f=!0);if(b.charAt(d)==='"'||b.charAt(d)==="'"){f&&s("~");if(a=s(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/))return new e.Quoted(a[0],a[1]||a[2],f)}},keyword:function(){var a;if(a=s(/^[A-Za-z-]+/))return new e.Keyword(a)},call:function(){var a,b,d=c;if(!!(a=/^([\w-]+|%)\(/.exec(j[f]))){a=a[1].toLowerCase();if(a==="url")return null;c+=a.length;if(a==="alpha")return s(this.alpha);s("("),b=s(this.entities.arguments);if(!s(")"))return;if(a)return new e.Call(a,b,d)}},arguments:function(){var a=[],b;while(b=s(this.expression)){a.push(b);if(!s(","))break}return a},literal:function(){return s(this.entities.dimension)||s(this.entities.color)||s(this.entities.quoted)},url:function(){var a;if(b.charAt(c)==="u"&&!!s(/^url\(/)){a=s(this.entities.quoted)||s(this.entities.variable)||s(this.entities.dataURI)||s(/^[-\w%@$\/.&=:;#+?~]+/)||"";if(!s(")"))throw new Error("missing closing ) for url()");return new e.URL(a.value||a.data||a instanceof e.Variable?a:new e.Anonymous(a),o.paths)}},dataURI:function(){var a;if(s(/^data:/)){a={},a.mime=s(/^[^\/]+\/[^,;)]+/)||"",a.charset=s(/^;\s*charset=[^,;)]+/)||"",a.base64=s(/^;\s*base64/)||"",a.data=s(/^,\s*[^)]+/);if(a.data)return a}},variable:function(){var a,d=c;if(b.charAt(c)==="@"&&(a=s(/^@@?[\w-]+/)))return new e.Variable(a,d)},color:function(){var a;if(b.charAt(c)==="#"&&(a=s(/^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})/)))return new e.Color(a[1])},dimension:function(){var a,d=b.charCodeAt(c);if(!(d>57||d<45||d===47))if(a=s(/^(-?\d*\.?\d+)(px|%|em|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn)?/))return new e.Dimension(a[1],a[2])},javascript:function(){var a,d=c,f;b.charAt(d)==="~"&&(d++,f=!0);if(b.charAt(d)==="`"){f&&s("~");if(a=s(/^`([^`]*)`/))return new e.JavaScript(a[1],c,f)}}},variable:function(){var a;if(b.charAt(c)==="@"&&(a=s(/^(@[\w-]+)\s*:/)))return a[1]},shorthand:function(){var a,b;if(!!t(/^[@\w.%-]+\/[@\w.-]+/)&&(a=s(this.entity))&&s("/")&&(b=s(this.entity)))return new e.Shorthand(a,b)},mixin:{call:function(){var a=[],d,f,g,h=c,i=b.charAt(c);if(i==="."||i==="#"){while(d=s(/^[#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/))a.push(new e.Element(f,d)),f=s(">");s("(")&&(g=s(this.entities.arguments))&&s(")");if(a.length>0&&(s(";")||t("}")))return new e.mixin.Call(a,g,h)}},definition:function(){var a,d=[],f,g,h,i;if(!(b.charAt(c)!=="."&&b.charAt(c)!=="#"||t(/^[^{]*(;|})/)))if(f=s(/^([#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+)\s*\(/)){a=f[1];while(h=s(this.entities.variable)||s(this.entities.literal)||s(this.entities.keyword)){if(h instanceof e.Variable)if(s(":"))if(i=s(this.expression))d.push({name:h.name,value:i});else throw new Error("Expected value");else d.push({name:h.name});else d.push({value:h});if(!s(","))break}if(!s(")"))throw new Error("Expected )");g=s(this.block);if(g)return new e.mixin.Definition(a,d,g)}}},entity:function(){return s(this.entities.literal)||s(this.entities.variable)||s(this.entities.url)||s(this.entities.call)||s(this.entities.keyword)||s(this.entities.javascript)||s(this.comment)},end:function(){return s(";")||t("}")},alpha:function(){var a;if(!!s(/^\(opacity=/i))if(a=s(/^\d+/)||s(this.entities.variable)){if(!s(")"))throw new Error("missing closing ) for alpha()");return new e.Alpha(a)}},element:function(){var a,b,c;c=s(this.combinator),a=s(/^(?:[.#]?|:*)(?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/)||s("*")||s(this.attribute)||s(/^\([^)@]+\)/)||s(/^(?:\d*\.)?\d+%/);if(a)return new e.Element(c,a);if(c.value&&c.value[0]==="&")return new e.Element(c,null)},combinator:function(){var a,d=b.charAt(c);if(d===">"||d==="+"||d==="~"){c++;while(b.charAt(c)===" ")c++;return new e.Combinator(d)}if(d==="&"){a="&",c++,b.charAt(c)===" "&&(a="& ");while(b.charAt(c)===" ")c++;return new e.Combinator(a)}if(d===":"&&b.charAt(c+1)===":"){c+=2;while(b.charAt(c)===" ")c++;return new e.Combinator("::")}return b.charAt(c-1)===" "?new e.Combinator(" "):new e.Combinator(null)},selector:function(){var a,d,f=[],g,h;while(d=s(this.element)){g=b.charAt(c),f.push(d);if(g==="{"||g==="}"||g===";"||g===",")break}if(f.length>0)return new e.Selector(f)},tag:function(){return s(/^[a-zA-Z][a-zA-Z-]*[0-9]?/)||s("*")},attribute:function(){var a="",b,c,d;if(!!s("[")){if(b=s(/^[a-zA-Z-]+/)||s(this.entities.quoted))(d=s(/^[|~*$^]?=/))&&(c=s(this.entities.quoted)||s(/^[\w-]+/))?a=[b,d,c.toCSS?c.toCSS():c].join(""):a=b;if(!s("]"))return;if(a)return"["+a+"]"}},block:function(){var a;if(s("{")&&(a=s(this.primary))&&s("}"))return a},ruleset:function(){var a=[],b,d,g;p();if(g=/^([.#:% \w-]+)[\s\n]*\{/.exec(j[f]))c+=g[0].length-1,a=[new e.Selector([new e.Element(null,g[1])])];else while(b=s(this.selector)){a.push(b),s(this.comment);if(!s(","))break;s(this.comment)}if(a.length>0&&(d=s(this.block)))return new e.Ruleset(a,d);i=c,q()},rule:function(){var a,d,g=b.charAt(c),k,l;p();if(g!=="."&&g!=="#"&&g!=="&")if(a=s(this.variable)||s(this.property)){a.charAt(0)!="@"&&(l=/^([^@+\/'"*`(;{}-]*);/.exec(j[f]))?(c+=l[0].length-1,d=new e.Anonymous(l[1])):a==="font"?d=s(this.font):d=s(this.value),k=s(this.important);if(d&&s(this.end))return new e.Rule(a,d,k,h);i=c,q()}},"import":function(){var a;if(s(/^@import\s+/)&&(a=s(this.entities.quoted)||s(this.entities.url))&&s(";"))return new e.Import(a,o)},directive:function(){var a,d,f,g;if(b.charAt(c)==="@"){if(d=s(this["import"]))return d;if(a=s(/^@media|@page/)||s(/^@(?:-webkit-)?keyframes/)){g=(s(/^[^{]+/)||"").trim();if(f=s(this.block))return new e.Directive(a+" "+g,f)}else if(a=s(/^@[-a-z]+/))if(a==="@font-face"){if(f=s(this.block))return new e.Directive(a,f)}else if((d=s(this.entity))&&s(";"))return new e.Directive(a,d)}},font:function(){var a=[],b=[],c,d,f,g;while(g=s(this.shorthand)||s(this.entity))b.push(g);a.push(new e.Expression(b));if(s(","))while(g=s(this.expression)){a.push(g);if(!s(","))break}return new e.Value(a)},value:function(){var a,b=[],c;while(a=s(this.expression)){b.push(a);if(!s(","))break}if(b.length>0)return new e.Value(b)},important:function(){if(b.charAt(c)==="!")return s(/^! *important/)},sub:function(){var a;if(s("(")&&(a=s(this.expression))&&s(")"))return a},multiplication:function(){var a,b,c,d;if(a=s(this.operand)){while((c=s("/")||s("*"))&&(b=s(this.operand)))d=new e.Operation(c,[d||a,b]);return d||a}},addition:function(){var a,d,f,g;if(a=s(this.multiplication)){while((f=s(/^[-+]\s+/)||b.charAt(c-1)!=" "&&(s("+")||s("-")))&&(d=s(this.multiplication)))g=new e.Operation(f,[g||a,d]);return g||a}},operand:function(){var a,d=b.charAt(c+1);b.charAt(c)==="-"&&(d==="@"||d==="(")&&(a=s("-"));var f=s(this.sub)||s(this.entities.dimension)||s(this.entities.color)||s(this.entities.variable)||s(this.entities.call);return a?new e.Operation("*",[new e.Dimension(-1),f]):f},expression:function(){var a,b,c=[],d;while(a=s(this.addition)||s(this.entity))c.push(a);if(c.length>0)return new e.Expression(c)},property:function(){var a;if(a=s(/^(\*?-?[-a-z_0-9]+)\s*:/))return a[1]}}}},typeof a!="undefined"&&(d.Parser.importer=function(a,b,c,d){a.charAt(0)!=="/"&&b.length>0&&(a=b[0]+a),n({href:a,title:a,type:d.mime},c,!0)}),function(a){function d(a){return Math.min(1,Math.max(0,a))}function c(b){if(b instanceof a.Dimension)return parseFloat(b.unit=="%"?b.value/100:b.value);if(typeof b=="number")return b;throw{error:"RuntimeError",message:"color functions take numbers as parameters"}}function b(b){return a.functions.hsla(b.h,b.s,b.l,b.a)}a.functions={rgb:function(a,b,c){return this.rgba(a,b,c,1)},rgba:function(b,d,e,f){var g=[b,d,e].map(function(a){return c(a)}),f=c(f);return new a.Color(g,f)},hsl:function(a,b,c){return this.hsla(a,b,c,1)},hsla:function(a,b,d,e){function h(a){a=a<0?a+1:a>1?a-1:a;return a*6<1?g+(f-g)*a*6:a*2<1?f:a*3<2?g+(f-g)*(2/3-a)*6:g}a=c(a)%360/360,b=c(b),d=c(d),e=c(e);var f=d<=.5?d*(b+1):d+b-d*b,g=d*2-f;return this.rgba(h(a+1/3)*255,h(a)*255,h(a-1/3)*255,e)},hue:function(b){return new a.Dimension(Math.round(b.toHSL().h))},saturation:function(b){return new a.Dimension(Math.round(b.toHSL().s*100),"%")},lightness:function(b){return new a.Dimension(Math.round(b.toHSL().l*100),"%")},alpha:function(b){return new a.Dimension(b.toHSL().a)},saturate:function(a,c){var e=a.toHSL();e.s+=c.value/100,e.s=d(e.s);return b(e)},desaturate:function(a,c){var e=a.toHSL();e.s-=c.value/100,e.s=d(e.s);return b(e)},lighten:function(a,c){var e=a.toHSL();e.l+=c.value/100,e.l=d(e.l);return b(e)},darken:function(a,c){var e=a.toHSL();e.l-=c.value/100,e.l=d(e.l);return b(e)},fadein:function(a,c){var e=a.toHSL();e.a+=c.value/100,e.a=d(e.a);return b(e)},fadeout:function(a,c){var e=a.toHSL();e.a-=c.value/100,e.a=d(e.a);return b(e)},spin:function(a,c){var d=a.toHSL(),e=(d.h+c.value)%360;d.h=e<0?360+e:e;return b(d)},mix:function(b,c,d){var e=d.value/100,f=e*2-1,g=b.toHSL().a-c.toHSL().a,h=((f*g==-1?f:(f+g)/(1+f*g))+1)/2,i=1-h,j=[b.rgb[0]*h+c.rgb[0]*i,b.rgb[1]*h+c.rgb[1]*i,b.rgb[2]*h+c.rgb[2]*i],k=b.alpha*e+c.alpha*(1-e);return new a.Color(j,k)},greyscale:function(b){return this.desaturate(b,new a.Dimension(100))},e:function(b){return new a.Anonymous(b instanceof a.JavaScript?b.evaluated:b)},escape:function(b){return new a.Anonymous(encodeURI(b.value).replace(/=/g,"%3D").replace(/:/g,"%3A").replace(/#/g,"%23").replace(/;/g,"%3B").replace(/\(/g,"%28").replace(/\)/g,"%29"))},"%":function(b){var c=Array.prototype.slice.call(arguments,1),d=b.value;for(var e=0;e255?255:a<0?0:a).toString(16);return a.length===1?"0"+a:a}).join("")},operate:function(b,c){var d=[];c instanceof a.Color||(c=c.toColor());for(var e=0;e<3;e++)d[e]=a.operate(b,this.rgb[e],c.rgb[e]);return new a.Color(d,this.alpha+c.alpha)},toHSL:function(){var a=this.rgb[0]/255,b=this.rgb[1]/255,c=this.rgb[2]/255,d=this.alpha,e=Math.max(a,b,c),f=Math.min(a,b,c),g,h,i=(e+f)/2,j=e-f;if(e===f)g=h=0;else{h=i>.5?j/(2-e-f):j/(e+f);switch(e){case a:g=(b-c)/j+(b":a.compress?">":" > "}[this.value]}}(c("less/tree")),function(a){a.Expression=function(a){this.value=a},a.Expression.prototype={eval:function(b){return this.value.length>1?new a.Expression(this.value.map(function(a){return a.eval(b)})):this.value.length===1?this.value[0].eval(b):this},toCSS:function(a){return this.value.map(function(b){return b.toCSS(a)}).join(" ")}}}(c("less/tree")),function(a){a.Import=function(b,c){var d=this;this._path=b,b instanceof a.Quoted?this.path=/\.(le?|c)ss$/.test(b.value)?b.value:b.value+".less":this.path=b.value.value||b.value,this.css=/css$/.test(this.path),this.css||c.push(this.path,function(a){if(!a)throw new Error("Error parsing "+d.path);d.root=a})},a.Import.prototype={toCSS:function(){return this.css?"@import "+this._path.toCSS()+";\n":""},eval:function(b){var c;if(this.css)return this;c=new a.Ruleset(null,this.root.rules.slice(0));for(var d=0;d0){c=this.arguments&&this.arguments.map(function(b){return b.eval(a)});for(var g=0;g0&&c>this.params.length)return!1;d=Math.min(c,this.arity);for(var e=0;e1?Array.prototype.push.apply(d,e.find(new a.Selector(b.elements.slice(1)),c)):d.push(e);break}});return this._lookups[g]=d},toCSS:function(b,c){var d=[],e=[],f=[],g=[],h,i;this.root||(b.length===0?g=this.selectors.map(function(a){return[a]}):this.joinSelectors(g,b,this.selectors));for(var j=0;j0&&(h=g.map(function(a){return a.map(function(a){return a.toCSS(c)}).join("").trim()}).join(c.compress?",":g.length>3?",\n":", "),d.push(h,(c.compress?"{":" {\n ")+e.join(c.compress?"":"\n ")+(c.compress?"}":"\n}\n"))),d.push(f);return d.join("")+(c.compress?"\n":"")},joinSelectors:function(a,b,c){for(var d=0;d0&&e.push(new a.Selector(g)),h.length>0&&f.push(new a.Selector(h));for(var l=0;l0&&typeof a!="undefined"&&(b.value=c[0]+(b.value.charAt(0)==="/"?b.value.slice(1):b.value)),this.value=b,this.paths=c)},b.URL.prototype={toCSS:function(){return"url("+(this.attrs?"data:"+this.attrs .mime+this.attrs.charset+this.attrs.base64+this.attrs.data:this.value.toCSS())+")"},eval:function(a){return this.attrs?this:new b.URL(this.value.eval(a),this.paths)}}}(c("less/tree")),function(a){a.Value=function(a){this.value=a,this.is="value"},a.Value.prototype={eval:function(b){return this.value.length===1?this.value[0].eval(b):new a.Value(this.value.map(function(a){return a.eval(b)}))},toCSS:function(a){return this.value.map(function(b){return b.toCSS(a)}).join(a.compress?",":", ")}}}(c("less/tree")),function(a){a.Variable=function(a,b){this.name=a,this.index=b},a.Variable.prototype={eval:function(b){var c,d,e=this.name;e.indexOf("@@")==0&&(e="@"+(new a.Variable(e.slice(1))).eval(b).value);if(c=a.find(b.frames,function(a){if(d=a.variable(e))return d.value.eval(b)}))return c;throw{message:"variable "+e+" is undefined",index:this.index}}}}(c("less/tree")),c("less/tree").find=function(a,b){for(var c=0,d;c1?"["+a.value.map(function(a){return a.toCSS(!1)}).join(", ")+"]":a.toCSS(!1)};var f=location.protocol==="file:"||location.protocol==="chrome:"||location.protocol==="chrome-extension:"||location.protocol==="resource:";d.env=d.env||(location.hostname=="127.0.0.1"||location.hostname=="0.0.0.0"||location.hostname=="localhost"||location.port.length>0||f?"development":"production"),d.async=!1,d.poll=d.poll||(f?1e3:1500),d.watch=function(){return this.watchMode=!0},d.unwatch=function(){return this.watchMode=!1},d.env==="development"?(d.optimization=0,/!watch/.test(location.hash)&&d.watch(),d.watchTimer=setInterval(function(){d.watchMode&&m(function(a,b,c){a&&p(a.toCSS(),b,c.lastModified)})},d.poll)):d.optimization=3;var g;try{g=typeof a.localStorage=="undefined"?null:a.localStorage}catch(h){g=null}var i=document.getElementsByTagName("link"),j=/^text\/(x-)?less$/;d.sheets=[];for(var k=0;k>> 0; for (var i = 0; i < len; i++) { if (i in this) { block.call(thisObject, this[i], i, this); } } }; } if (!Array.prototype.map) { Array.prototype.map = function(fun /*, thisp*/) { var len = this.length >>> 0; var res = new Array(len); var thisp = arguments[1]; for (var i = 0; i < len; i++) { if (i in this) { res[i] = fun.call(thisp, this[i], i, this); } } return res; }; } if (!Array.prototype.filter) { Array.prototype.filter = function (block /*, thisp */) { var values = []; var thisp = arguments[1]; for (var i = 0; i < this.length; i++) { if (block.call(thisp, this[i])) { values.push(this[i]); } } return values; }; } if (!Array.prototype.reduce) { Array.prototype.reduce = function(fun /*, initial*/) { var len = this.length >>> 0; var i = 0; // no value to return if no initial value and an empty array if (len === 0 && arguments.length === 1) throw new TypeError(); if (arguments.length >= 2) { var rv = arguments[1]; } else { do { if (i in this) { rv = this[i++]; break; } // if array contains no values, no initial value to return if (++i >= len) throw new TypeError(); } while (true); } for (; i < len; i++) { if (i in this) { rv = fun.call(null, rv, this[i], i, this); } } return rv; }; } if (!Array.prototype.indexOf) { Array.prototype.indexOf = function (value /*, fromIndex */ ) { var length = this.length; var i = arguments[1] || 0; if (!length) return -1; if (i >= length) return -1; if (i < 0) i += length; for (; i < length; i++) { if (!Object.prototype.hasOwnProperty.call(this, i)) { continue } if (value === this[i]) return i; } return -1; }; } // // Object // if (!Object.keys) { Object.keys = function (object) { var keys = []; for (var name in object) { if (Object.prototype.hasOwnProperty.call(object, name)) { keys.push(name); } } return keys; }; } // // String // if (!String.prototype.trim) { String.prototype.trim = function () { return String(this).replace(/^\s\s*/, '').replace(/\s\s*$/, ''); }; } var less, tree; if (typeof environment === "object" && ({}).toString.call(environment) === "[object Environment]") { // Rhino // Details on how to detect Rhino: https://github.com/ringo/ringojs/issues/88 less = {}; tree = less.tree = {}; less.mode = 'rhino'; } else if (typeof(window) === 'undefined') { // Node.js less = exports, tree = require('./tree'); less.mode = 'node'; } else { // Browser if (typeof(window.less) === 'undefined') { window.less = {} } less = window.less, tree = window.less.tree = {}; less.mode = 'browser'; } // // less.js - parser // // A relatively straight-forward predictive parser. // There is no tokenization/lexing stage, the input is parsed // in one sweep. // // To make the parser fast enough to run in the browser, several // optimization had to be made: // // - Matching and slicing on a huge input is often cause of slowdowns. // The solution is to chunkify the input into smaller strings. // The chunks are stored in the `chunks` var, // `j` holds the current chunk index, and `current` holds // the index of the current chunk in relation to `input`. // This gives us an almost 4x speed-up. // // - In many cases, we don't need to match individual tokens; // for example, if a value doesn't hold any variables, operations // or dynamic references, the parser can effectively 'skip' it, // treating it as a literal. // An example would be '1px solid #000' - which evaluates to itself, // we don't need to know what the individual components are. // The drawback, of course is that you don't get the benefits of // syntax-checking on the CSS. This gives us a 50% speed-up in the parser, // and a smaller speed-up in the code-gen. // // // Token matching is done with the `$` function, which either takes // a terminal string or regexp, or a non-terminal function to call. // It also takes care of moving all the indices forwards. // // less.Parser = function Parser(env) { var input, // LeSS input string i, // current index in `input` j, // current chunk temp, // temporarily holds a chunk's state, for backtracking memo, // temporarily holds `i`, when backtracking furthest, // furthest index the parser has gone to chunks, // chunkified input current, // index of current chunk, in `input` parser; var that = this; // This function is called after all files // have been imported through `@import`. var finish = function () {}; var imports = this.imports = { paths: env && env.paths || [], // Search paths, when importing queue: [], // Files which haven't been imported yet files: {}, // Holds the imported parse trees mime: env && env.mime, // MIME type of .less files push: function (path, callback) { var that = this; this.queue.push(path); // // Import a file asynchronously // less.Parser.importer(path, this.paths, function (root) { that.queue.splice(that.queue.indexOf(path), 1); // Remove the path from the queue that.files[path] = root; // Store the root callback(root); if (that.queue.length === 0) { finish() } // Call `finish` if we're done importing }, env); } }; function save() { temp = chunks[j], memo = i, current = i } function restore() { chunks[j] = temp, i = memo, current = i } function sync() { if (i > current) { chunks[j] = chunks[j].slice(i - current); current = i; } } // // Parse from a token, regexp or string, and move forward if match // function $(tok) { var match, args, length, c, index, endIndex, k, mem; // // Non-terminal // if (tok instanceof Function) { return tok.call(parser.parsers); // // Terminal // // Either match a single character in the input, // or match a regexp in the current chunk (chunk[j]). // } else if (typeof(tok) === 'string') { match = input.charAt(i) === tok ? tok : null; length = 1; sync (); } else { sync (); if (match = tok.exec(chunks[j])) { length = match[0].length; } else { return null; } } // The match is confirmed, add the match length to `i`, // and consume any extra white-space characters (' ' || '\n') // which come after that. The reason for this is that LeSS's // grammar is mostly white-space insensitive. // if (match) { mem = i += length; endIndex = i + chunks[j].length - length; while (i < endIndex) { c = input.charCodeAt(i); if (! (c === 32 || c === 10 || c === 9)) { break } i++; } chunks[j] = chunks[j].slice(length + (i - mem)); current = i; if (chunks[j].length === 0 && j < chunks.length - 1) { j++ } if(typeof(match) === 'string') { return match; } else { return match.length === 1 ? match[0] : match; } } } // Same as $(), but don't change the state of the parser, // just return the match. function peek(tok) { if (typeof(tok) === 'string') { return input.charAt(i) === tok; } else { if (tok.test(chunks[j])) { return true; } else { return false; } } } this.env = env = env || {}; // The optimization level dictates the thoroughness of the parser, // the lower the number, the less nodes it will create in the tree. // This could matter for debugging, or if you want to access // the individual nodes in the tree. this.optimization = ('optimization' in this.env) ? this.env.optimization : 1; this.env.filename = this.env.filename || null; // // The Parser // return parser = { imports: imports, // // Parse an input string into an abstract syntax tree, // call `callback` when done. // parse: function (str, callback) { var root, start, end, zone, line, lines, buff = [], c, error = null; i = j = current = furthest = 0; chunks = []; input = str.replace(/\r\n/g, '\n'); // Split the input into chunks. chunks = (function (chunks) { var j = 0, skip = /[^"'`\{\}\/\(\)]+/g, comment = /\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g, level = 0, match, chunk = chunks[0], inParam, inString; for (var i = 0, c, cc; i < input.length; i++) { skip.lastIndex = i; if (match = skip.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); } } c = input.charAt(i); comment.lastIndex = i; if (!inString && !inParam && c === '/') { cc = input.charAt(i + 1); if (cc === '/' || cc === '*') { if (match = comment.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); c = input.charAt(i); } } } } if (c === '{' && !inString && !inParam) { level ++; chunk.push(c); } else if (c === '}' && !inString && !inParam) { level --; chunk.push(c); chunks[++j] = chunk = []; } else if (c === '(' && !inString && !inParam) { chunk.push(c); inParam = true; } else if (c === ')' && !inString && inParam) { chunk.push(c); inParam = false; } else { if (c === '"' || c === "'" || c === '`') { if (! inString) { inString = c; } else { inString = inString === c ? false : inString; } } chunk.push(c); } } if (level > 0) { throw { type: 'Syntax', message: "Missing closing `}`", filename: env.filename }; } return chunks.map(function (c) { return c.join('') });; })([[]]); // Start with the primary rule. // The whole syntax tree is held under a Ruleset node, // with the `root` property set to true, so no `{}` are // output. The callback is called when the input is parsed. root = new(tree.Ruleset)([], $(this.parsers.primary)); root.root = true; root.toCSS = (function (evaluate) { var line, lines, column; return function (options, variables) { var frames = []; options = options || {}; // // Allows setting variables with a hash, so: // // `{ color: new(tree.Color)('#f01') }` will become: // // new(tree.Rule)('@color', // new(tree.Value)([ // new(tree.Expression)([ // new(tree.Color)('#f01') // ]) // ]) // ) // if (typeof(variables) === 'object' && !Array.isArray(variables)) { variables = Object.keys(variables).map(function (k) { var value = variables[k]; if (! (value instanceof tree.Value)) { if (! (value instanceof tree.Expression)) { value = new(tree.Expression)([value]); } value = new(tree.Value)([value]); } return new(tree.Rule)('@' + k, value, false, 0); }); frames = [new(tree.Ruleset)(null, variables)]; } try { var css = evaluate.call(this, { frames: frames }) .toCSS([], { compress: options.compress || false }); } catch (e) { lines = input.split('\n'); line = getLine(e.index); for (var n = e.index, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } throw { type: e.type, message: e.message, filename: env.filename, index: e.index, line: typeof(line) === 'number' ? line + 1 : null, callLine: e.call && (getLine(e.call) + 1), callExtract: lines[getLine(e.call)], stack: e.stack, column: column, extract: [ lines[line - 1], lines[line], lines[line + 1] ] }; } if (options.compress) { return css.replace(/(\s)+/g, "$1"); } else { return css; } function getLine(index) { return index ? (input.slice(0, index).match(/\n/g) || "").length : null; } }; })(root.eval); // If `i` is smaller than the `input.length - 1`, // it means the parser wasn't able to parse the whole // string, so we've got a parsing error. // // We try to extract a \n delimited string, // showing the line where the parse error occured. // We split it up into two parts (the part which parsed, // and the part which didn't), so we can color them differently. if (i < input.length - 1) { i = furthest; lines = input.split('\n'); line = (input.slice(0, i).match(/\n/g) || "").length + 1; for (var n = i, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } error = { name: "ParseError", message: "Syntax Error on line " + line, index: i, filename: env.filename, line: line, column: column, extract: [ lines[line - 2], lines[line - 1], lines[line] ] }; } if (this.imports.queue.length > 0) { finish = function () { callback(error, root) }; } else { callback(error, root); } }, // // Here in, the parsing rules/functions // // The basic structure of the syntax tree generated is as follows: // // Ruleset -> Rule -> Value -> Expression -> Entity // // Here's some LESS code: // // .class { // color: #fff; // border: 1px solid #000; // width: @w + 4px; // > .child {...} // } // // And here's what the parse tree might look like: // // Ruleset (Selector '.class', [ // Rule ("color", Value ([Expression [Color #fff]])) // Rule ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]])) // Rule ("width", Value ([Expression [Operation "+" [Variable "@w"][Dimension 4px]]])) // Ruleset (Selector [Element '>', '.child'], [...]) // ]) // // In general, most rules will try to parse a token with the `$()` function, and if the return // value is truly, will return a new node, of the relevant type. Sometimes, we need to check // first, before parsing, that's when we use `peek()`. // parsers: { // // The `primary` rule is the *entry* and *exit* point of the parser. // The rules here can appear at any level of the parse tree. // // The recursive nature of the grammar is an interplay between the `block` // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule, // as represented by this simplified grammar: // // primary → (ruleset | rule)+ // ruleset → selector+ block // block → '{' primary '}' // // Only at one point is the primary rule not called from the // block rule: at the root level. // primary: function () { var node, root = []; while ((node = $(this.mixin.definition) || $(this.rule) || $(this.ruleset) || $(this.mixin.call) || $(this.comment) || $(this.directive)) || $(/^[\s\n]+/)) { node && root.push(node); } return root; }, // We create a Comment node for CSS comments `/* */`, // but keep the LeSS comments `//` silent, by just skipping // over them. comment: function () { var comment; if (input.charAt(i) !== '/') return; if (input.charAt(i + 1) === '/') { return new(tree.Comment)($(/^\/\/.*/), true); } else if (comment = $(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/)) { return new(tree.Comment)(comment); } }, // // Entities are tokens which can be found inside an Expression // entities: { // // A string, which supports escaping " and ' // // "milky way" 'he\'s the one!' // quoted: function () { var str, j = i, e; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '"' && input.charAt(j) !== "'") return; e && $('~'); if (str = $(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/)) { return new(tree.Quoted)(str[0], str[1] || str[2], e); } }, // // A catch-all word, such as: // // black border-collapse // keyword: function () { var k; if (k = $(/^[_A-Za-z-][_A-Za-z0-9-]*/)) { return new(tree.Keyword)(k) } }, // // A function call // // rgb(255, 0, 255) // // We also try to catch IE's `alpha()`, but let the `alpha` parser // deal with the details. // // The arguments are parsed with the `entities.arguments` parser. // call: function () { var name, args, index = i; if (! (name = /^([\w-]+|%)\(/.exec(chunks[j]))) return; name = name[1].toLowerCase(); if (name === 'url') { return null } else { i += name.length } if (name === 'alpha') { return $(this.alpha) } $('('); // Parse the '(' and consume whitespace. args = $(this.entities.arguments); if (! $(')')) return; if (name) { return new(tree.Call)(name, args, index) } }, arguments: function () { var args = [], arg; while (arg = $(this.expression)) { args.push(arg); if (! $(',')) { break } } return args; }, literal: function () { return $(this.entities.dimension) || $(this.entities.color) || $(this.entities.quoted); }, // // Parse url() tokens // // We use a specific rule for urls, because they don't really behave like // standard function calls. The difference is that the argument doesn't have // to be enclosed within a string, so it can't be parsed as an Expression. // url: function () { var value; if (input.charAt(i) !== 'u' || !$(/^url\(/)) return; value = $(this.entities.quoted) || $(this.entities.variable) || $(this.entities.dataURI) || $(/^[-\w%@$\/.&=:;#+?~]+/) || ""; if (! $(')')) throw new(Error)("missing closing ) for url()"); return new(tree.URL)((value.value || value.data || value instanceof tree.Variable) ? value : new(tree.Anonymous)(value), imports.paths); }, dataURI: function () { var obj; if ($(/^data:/)) { obj = {}; obj.mime = $(/^[^\/]+\/[^,;)]+/) || ''; obj.charset = $(/^;\s*charset=[^,;)]+/) || ''; obj.base64 = $(/^;\s*base64/) || ''; obj.data = $(/^,\s*[^)]+/); if (obj.data) { return obj } } }, // // A Variable entity, such as `@fink`, in // // width: @fink + 2px // // We use a different parser for variable definitions, // see `parsers.variable`. // variable: function () { var name, index = i; if (input.charAt(i) === '@' && (name = $(/^@@?[\w-]+/))) { return new(tree.Variable)(name, index); } }, // // A Hexadecimal color // // #4F3C2F // // `rgb` and `hsl` colors are parsed through the `entities.call` parser. // color: function () { var rgb; if (input.charAt(i) === '#' && (rgb = $(/^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})/))) { return new(tree.Color)(rgb[1]); } }, // // A Dimension, that is, a number and a unit // // 0.5em 95% // dimension: function () { var value, c = input.charCodeAt(i); if ((c > 57 || c < 45) || c === 47) return; if (value = $(/^(-?\d*\.?\d+)(px|%|em|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn)?/)) { return new(tree.Dimension)(value[1], value[2]); } }, // // JavaScript code to be evaluated // // `window.location.href` // javascript: function () { var str, j = i, e; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '`') { return } e && $('~'); if (str = $(/^`([^`]*)`/)) { return new(tree.JavaScript)(str[1], i, e); } } }, // // The variable part of a variable definition. Used in the `rule` parser // // @fink: // variable: function () { var name; if (input.charAt(i) === '@' && (name = $(/^(@[\w-]+)\s*:/))) { return name[1] } }, // // A font size/line-height shorthand // // small/12px // // We need to peek first, or we'll match on keywords and dimensions // shorthand: function () { var a, b; if (! peek(/^[@\w.%-]+\/[@\w.-]+/)) return; if ((a = $(this.entity)) && $('/') && (b = $(this.entity))) { return new(tree.Shorthand)(a, b); } }, // // Mixins // mixin: { // // A Mixin call, with an optional argument list // // #mixins > .square(#fff); // .rounded(4px, black); // .button; // // The `while` loop is there because mixins can be // namespaced, but we only support the child and descendant // selector for now. // call: function () { var elements = [], e, c, args, index = i, s = input.charAt(i); if (s !== '.' && s !== '#') { return } while (e = $(/^[#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/)) { elements.push(new(tree.Element)(c, e, i)); c = $('>'); } $('(') && (args = $(this.entities.arguments)) && $(')'); if (elements.length > 0 && ($(';') || peek('}'))) { return new(tree.mixin.Call)(elements, args, index); } }, // // A Mixin definition, with a list of parameters // // .rounded (@radius: 2px, @color) { // ... // } // // Until we have a finer grained state-machine, we have to // do a look-ahead, to make sure we don't have a mixin call. // See the `rule` function for more information. // // We start by matching `.rounded (`, and then proceed on to // the argument list, which has optional default values. // We store the parameters in `params`, with a `value` key, // if there is a value, such as in the case of `@radius`. // // Once we've got our params list, and a closing `)`, we parse // the `{...}` block. // definition: function () { var name, params = [], match, ruleset, param, value; if ((input.charAt(i) !== '.' && input.charAt(i) !== '#') || peek(/^[^{]*(;|})/)) return; if (match = $(/^([#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+)\s*\(/)) { name = match[1]; while (param = $(this.entities.variable) || $(this.entities.literal) || $(this.entities.keyword)) { // Variable if (param instanceof tree.Variable) { if ($(':')) { if (value = $(this.expression)) { params.push({ name: param.name, value: value }); } else { throw new(Error)("Expected value"); } } else { params.push({ name: param.name }); } } else { params.push({ value: param }); } if (! $(',')) { break } } if (! $(')')) throw new(Error)("Expected )"); ruleset = $(this.block); if (ruleset) { return new(tree.mixin.Definition)(name, params, ruleset); } } } }, // // Entities are the smallest recognized token, // and can be found inside a rule's value. // entity: function () { return $(this.entities.literal) || $(this.entities.variable) || $(this.entities.url) || $(this.entities.call) || $(this.entities.keyword) || $(this.entities.javascript) || $(this.comment); }, // // A Rule terminator. Note that we use `peek()` to check for '}', // because the `block` rule will be expecting it, but we still need to make sure // it's there, if ';' was ommitted. // end: function () { return $(';') || peek('}'); }, // // IE's alpha function // // alpha(opacity=88) // alpha: function () { var value; if (! $(/^\(opacity=/i)) return; if (value = $(/^\d+/) || $(this.entities.variable)) { if (! $(')')) throw new(Error)("missing closing ) for alpha()"); return new(tree.Alpha)(value); } }, // // A Selector Element // // div // + h1 // #socks // input[type="text"] // // Elements are the building blocks for Selectors, // they are made out of a `Combinator` (see combinator rule), // and an element name, such as a tag a class, or `*`. // element: function () { var e, t, c; c = $(this.combinator); e = $(/^(?:\d+\.\d+|\d+)%/) || $(/^(?:[.#]?|:*)(?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/) || $('*') || $(this.attribute) || $(/^\([^)@]+\)/); if (e) { return new(tree.Element)(c, e, i) } if (c.value && c.value.charAt(0) === '&') { return new(tree.Element)(c, null, i); } }, // // Combinators combine elements together, in a Selector. // // Because our parser isn't white-space sensitive, special care // has to be taken, when parsing the descendant combinator, ` `, // as it's an empty space. We have to check the previous character // in the input, to see if it's a ` ` character. More info on how // we deal with this in *combinator.js*. // combinator: function () { var match, c = input.charAt(i); if (c === '>' || c === '+' || c === '~') { i++; while (input.charAt(i) === ' ') { i++ } return new(tree.Combinator)(c); } else if (c === '&') { match = '&'; i++; if(input.charAt(i) === ' ') { match = '& '; } while (input.charAt(i) === ' ') { i++ } return new(tree.Combinator)(match); } else if (c === ':' && input.charAt(i + 1) === ':') { i += 2; while (input.charAt(i) === ' ') { i++ } return new(tree.Combinator)('::'); } else if (input.charAt(i - 1) === ' ') { return new(tree.Combinator)(" "); } else { return new(tree.Combinator)(null); } }, // // A CSS Selector // // .class > div + h1 // li a:hover // // Selectors are made out of one or more Elements, see above. // selector: function () { var sel, e, elements = [], c, match; while (e = $(this.element)) { c = input.charAt(i); elements.push(e) if (c === '{' || c === '}' || c === ';' || c === ',') { break } } if (elements.length > 0) { return new(tree.Selector)(elements) } }, tag: function () { return $(/^[a-zA-Z][a-zA-Z-]*[0-9]?/) || $('*'); }, attribute: function () { var attr = '', key, val, op; if (! $('[')) return; if (key = $(/^[a-zA-Z-]+/) || $(this.entities.quoted)) { if ((op = $(/^[|~*$^]?=/)) && (val = $(this.entities.quoted) || $(/^[\w-]+/))) { attr = [key, op, val.toCSS ? val.toCSS() : val].join(''); } else { attr = key } } if (! $(']')) return; if (attr) { return "[" + attr + "]" } }, // // The `block` rule is used by `ruleset` and `mixin.definition`. // It's a wrapper around the `primary` rule, with added `{}`. // block: function () { var content; if ($('{') && (content = $(this.primary)) && $('}')) { return content; } }, // // div, .class, body > p {...} // ruleset: function () { var selectors = [], s, rules, match; save(); while (s = $(this.selector)) { selectors.push(s); $(this.comment); if (! $(',')) { break } $(this.comment); } if (selectors.length > 0 && (rules = $(this.block))) { return new(tree.Ruleset)(selectors, rules); } else { // Backtrack furthest = i; restore(); } }, rule: function () { var name, value, c = input.charAt(i), important, match; save(); if (c === '.' || c === '#' || c === '&') { return } if (name = $(this.variable) || $(this.property)) { if ((name.charAt(0) != '@') && (match = /^([^@+\/'"*`(;{}-]*);/.exec(chunks[j]))) { i += match[0].length - 1; value = new(tree.Anonymous)(match[1]); } else if (name === "font") { value = $(this.font); } else { value = $(this.value); } important = $(this.important); if (value && $(this.end)) { return new(tree.Rule)(name, value, important, memo); } else { furthest = i; restore(); } } }, // // An @import directive // // @import "lib"; // // Depending on our environemnt, importing is done differently: // In the browser, it's an XHR request, in Node, it would be a // file-system operation. The function used for importing is // stored in `import`, which we pass to the Import constructor. // "import": function () { var path; if ($(/^@import\s+/) && (path = $(this.entities.quoted) || $(this.entities.url)) && $(';')) { return new(tree.Import)(path, imports); } }, // // A CSS Directive // // @charset "utf-8"; // directive: function () { var name, value, rules, types; if (input.charAt(i) !== '@') return; if (value = $(this['import'])) { return value; } else if (name = $(/^@media|@page/) || $(/^@(?:-webkit-|-moz-)?keyframes/)) { types = ($(/^[^{]+/) || '').trim(); if (rules = $(this.block)) { return new(tree.Directive)(name + " " + types, rules); } } else if (name = $(/^@[-a-z]+/)) { if (name === '@font-face') { if (rules = $(this.block)) { return new(tree.Directive)(name, rules); } } else if ((value = $(this.entity)) && $(';')) { return new(tree.Directive)(name, value); } } }, font: function () { var value = [], expression = [], weight, shorthand, font, e; while (e = $(this.shorthand) || $(this.entity)) { expression.push(e); } value.push(new(tree.Expression)(expression)); if ($(',')) { while (e = $(this.expression)) { value.push(e); if (! $(',')) { break } } } return new(tree.Value)(value); }, // // A Value is a comma-delimited list of Expressions // // font-family: Baskerville, Georgia, serif; // // In a Rule, a Value represents everything after the `:`, // and before the `;`. // value: function () { var e, expressions = [], important; while (e = $(this.expression)) { expressions.push(e); if (! $(',')) { break } } if (expressions.length > 0) { return new(tree.Value)(expressions); } }, important: function () { if (input.charAt(i) === '!') { return $(/^! *important/); } }, sub: function () { var e; if ($('(') && (e = $(this.expression)) && $(')')) { return e; } }, multiplication: function () { var m, a, op, operation; if (m = $(this.operand)) { while ((op = ($('/') || $('*'))) && (a = $(this.operand))) { operation = new(tree.Operation)(op, [operation || m, a]); } return operation || m; } }, addition: function () { var m, a, op, operation; if (m = $(this.multiplication)) { while ((op = $(/^[-+]\s+/) || (input.charAt(i - 1) != ' ' && ($('+') || $('-')))) && (a = $(this.multiplication))) { operation = new(tree.Operation)(op, [operation || m, a]); } return operation || m; } }, // // An operand is anything that can be part of an operation, // such as a Color, or a Variable // operand: function () { var negate, p = input.charAt(i + 1); if (input.charAt(i) === '-' && (p === '@' || p === '(')) { negate = $('-') } var o = $(this.sub) || $(this.entities.dimension) || $(this.entities.color) || $(this.entities.variable) || $(this.entities.call); return negate ? new(tree.Operation)('*', [new(tree.Dimension)(-1), o]) : o; }, // // Expressions either represent mathematical operations, // or white-space delimited Entities. // // 1px solid black // @var * 2 // expression: function () { var e, delim, entities = [], d; while (e = $(this.addition) || $(this.entity)) { entities.push(e); } if (entities.length > 0) { return new(tree.Expression)(entities); } }, property: function () { var name; if (name = $(/^(\*?-?[-a-z_0-9]+)\s*:/)) { return name[1]; } } } }; }; if (less.mode === 'browser' || less.mode === 'rhino') { // // Used by `@import` directives // less.Parser.importer = function (path, paths, callback, env) { if (path.charAt(0) !== '/' && paths.length > 0) { path = paths[0] + path; } // We pass `true` as 3rd argument, to force the reload of the import. // This is so we can get the syntax tree as opposed to just the CSS output, // as we need this to evaluate the current stylesheet. loadStyleSheet({ href: path, title: path, type: env.mime }, callback, true); }; } (function (tree) { tree.functions = { rgb: function (r, g, b) { return this.rgba(r, g, b, 1.0); }, rgba: function (r, g, b, a) { var rgb = [r, g, b].map(function (c) { return number(c) }), a = number(a); return new(tree.Color)(rgb, a); }, hsl: function (h, s, l) { return this.hsla(h, s, l, 1.0); }, hsla: function (h, s, l, a) { h = (number(h) % 360) / 360; s = number(s); l = number(l); a = number(a); var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s; var m1 = l * 2 - m2; return this.rgba(hue(h + 1/3) * 255, hue(h) * 255, hue(h - 1/3) * 255, a); function hue(h) { h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h); if (h * 6 < 1) return m1 + (m2 - m1) * h * 6; else if (h * 2 < 1) return m2; else if (h * 3 < 2) return m1 + (m2 - m1) * (2/3 - h) * 6; else return m1; } }, hue: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().h)); }, saturation: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().s * 100), '%'); }, lightness: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().l * 100), '%'); }, alpha: function (color) { return new(tree.Dimension)(color.toHSL().a); }, saturate: function (color, amount) { var hsl = color.toHSL(); hsl.s += amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, desaturate: function (color, amount) { var hsl = color.toHSL(); hsl.s -= amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, lighten: function (color, amount) { var hsl = color.toHSL(); hsl.l += amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, darken: function (color, amount) { var hsl = color.toHSL(); hsl.l -= amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, fadein: function (color, amount) { var hsl = color.toHSL(); hsl.a += amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, fadeout: function (color, amount) { var hsl = color.toHSL(); hsl.a -= amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, fade: function (color, amount) { var hsl = color.toHSL(); hsl.a = amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, spin: function (color, amount) { var hsl = color.toHSL(); var hue = (hsl.h + amount.value) % 360; hsl.h = hue < 0 ? 360 + hue : hue; return hsla(hsl); }, // // Copyright (c) 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein // http://sass-lang.com // mix: function (color1, color2, weight) { var p = weight.value / 100.0; var w = p * 2 - 1; var a = color1.toHSL().a - color2.toHSL().a; var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0; var w2 = 1 - w1; var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2, color1.rgb[1] * w1 + color2.rgb[1] * w2, color1.rgb[2] * w1 + color2.rgb[2] * w2]; var alpha = color1.alpha * p + color2.alpha * (1 - p); return new(tree.Color)(rgb, alpha); }, greyscale: function (color) { return this.desaturate(color, new(tree.Dimension)(100)); }, e: function (str) { return new(tree.Anonymous)(str instanceof tree.JavaScript ? str.evaluated : str); }, escape: function (str) { return new(tree.Anonymous)(encodeURI(str.value).replace(/=/g, "%3D").replace(/:/g, "%3A").replace(/#/g, "%23").replace(/;/g, "%3B").replace(/\(/g, "%28").replace(/\)/g, "%29")); }, '%': function (quoted /* arg, arg, ...*/) { var args = Array.prototype.slice.call(arguments, 1), str = quoted.value; for (var i = 0; i < args.length; i++) { str = str.replace(/%[sda]/i, function(token) { var value = token.match(/s/i) ? args[i].value : args[i].toCSS(); return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value; }); } str = str.replace(/%%/g, '%'); return new(tree.Quoted)('"' + str + '"', str); }, round: function (n) { if (n instanceof tree.Dimension) { return new(tree.Dimension)(Math.round(number(n)), n.unit); } else if (typeof(n) === 'number') { return Math.round(n); } else { throw { error: "RuntimeError", message: "math functions take numbers as parameters" }; } }, argb: function (color) { return new(tree.Anonymous)(color.toARGB()); } }; function hsla(hsla) { return tree.functions.hsla(hsla.h, hsla.s, hsla.l, hsla.a); } function number(n) { if (n instanceof tree.Dimension) { return parseFloat(n.unit == '%' ? n.value / 100 : n.value); } else if (typeof(n) === 'number') { return n; } else { throw { error: "RuntimeError", message: "color functions take numbers as parameters" }; } } function clamp(val) { return Math.min(1, Math.max(0, val)); } })(require('./tree')); (function (tree) { tree.Alpha = function (val) { this.value = val; }; tree.Alpha.prototype = { toCSS: function () { return "alpha(opacity=" + (this.value.toCSS ? this.value.toCSS() : this.value) + ")"; }, eval: function (env) { if (this.value.eval) { this.value = this.value.eval(env) } return this; } }; })(require('../tree')); (function (tree) { tree.Anonymous = function (string) { this.value = string.value || string; }; tree.Anonymous.prototype = { toCSS: function () { return this.value; }, eval: function () { return this } }; })(require('../tree')); (function (tree) { // // A function call node. // tree.Call = function (name, args, index) { this.name = name; this.args = args; this.index = index; }; tree.Call.prototype = { // // When evaluating a function call, // we either find the function in `tree.functions` [1], // in which case we call it, passing the evaluated arguments, // or we simply print it out as it appeared originally [2]. // // The *functions.js* file contains the built-in functions. // // The reason why we evaluate the arguments, is in the case where // we try to pass a variable to a function, like: `saturate(@color)`. // The function should receive the value, not the variable. // eval: function (env) { var args = this.args.map(function (a) { return a.eval(env) }); if (this.name in tree.functions) { // 1. try { return tree.functions[this.name].apply(tree.functions, args); } catch (e) { throw { message: "error evaluating function `" + this.name + "`", index: this.index }; } } else { // 2. return new(tree.Anonymous)(this.name + "(" + args.map(function (a) { return a.toCSS() }).join(', ') + ")"); } }, toCSS: function (env) { return this.eval(env).toCSS(); } }; })(require('../tree')); (function (tree) { // // RGB Colors - #ff0014, #eee // tree.Color = function (rgb, a) { // // The end goal here, is to parse the arguments // into an integer triplet, such as `128, 255, 0` // // This facilitates operations and conversions. // if (Array.isArray(rgb)) { this.rgb = rgb; } else if (rgb.length == 6) { this.rgb = rgb.match(/.{2}/g).map(function (c) { return parseInt(c, 16); }); } else { this.rgb = rgb.split('').map(function (c) { return parseInt(c + c, 16); }); } this.alpha = typeof(a) === 'number' ? a : 1; }; tree.Color.prototype = { eval: function () { return this }, // // If we have some transparency, the only way to represent it // is via `rgba`. Otherwise, we use the hex representation, // which has better compatibility with older browsers. // Values are capped between `0` and `255`, rounded and zero-padded. // toCSS: function () { if (this.alpha < 1.0) { return "rgba(" + this.rgb.map(function (c) { return Math.round(c); }).concat(this.alpha).join(', ') + ")"; } else { return '#' + this.rgb.map(function (i) { i = Math.round(i); i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16); return i.length === 1 ? '0' + i : i; }).join(''); } }, // // Operations have to be done per-channel, if not, // channels will spill onto each other. Once we have // our result, in the form of an integer triplet, // we create a new Color node to hold the result. // operate: function (op, other) { var result = []; if (! (other instanceof tree.Color)) { other = other.toColor(); } for (var c = 0; c < 3; c++) { result[c] = tree.operate(op, this.rgb[c], other.rgb[c]); } return new(tree.Color)(result, this.alpha + other.alpha); }, toHSL: function () { var r = this.rgb[0] / 255, g = this.rgb[1] / 255, b = this.rgb[2] / 255, a = this.alpha; var max = Math.max(r, g, b), min = Math.min(r, g, b); var h, s, l = (max + min) / 2, d = max - min; if (max === min) { h = s = 0; } else { s = l > 0.5 ? d / (2 - max - min) : d / (max + min); switch (max) { case r: h = (g - b) / d + (g < b ? 6 : 0); break; case g: h = (b - r) / d + 2; break; case b: h = (r - g) / d + 4; break; } h /= 6; } return { h: h * 360, s: s, l: l, a: a }; }, toARGB: function () { var argb = [Math.round(this.alpha * 255)].concat(this.rgb); return '#' + argb.map(function (i) { i = Math.round(i); i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16); return i.length === 1 ? '0' + i : i; }).join(''); } }; })(require('../tree')); (function (tree) { tree.Comment = function (value, silent) { this.value = value; this.silent = !!silent; }; tree.Comment.prototype = { toCSS: function (env) { return env.compress ? '' : this.value; }, eval: function () { return this } }; })(require('../tree')); (function (tree) { // // A number with a unit // tree.Dimension = function (value, unit) { this.value = parseFloat(value); this.unit = unit || null; }; tree.Dimension.prototype = { eval: function () { return this }, toColor: function () { return new(tree.Color)([this.value, this.value, this.value]); }, toCSS: function () { var css = this.value + this.unit; return css; }, // In an operation between two Dimensions, // we default to the first Dimension's unit, // so `1px + 2em` will yield `3px`. // In the future, we could implement some unit // conversions such that `100cm + 10mm` would yield // `101cm`. operate: function (op, other) { return new(tree.Dimension) (tree.operate(op, this.value, other.value), this.unit || other.unit); } }; })(require('../tree')); (function (tree) { tree.Directive = function (name, value) { this.name = name; if (Array.isArray(value)) { this.ruleset = new(tree.Ruleset)([], value); } else { this.value = value; } }; tree.Directive.prototype = { toCSS: function (ctx, env) { if (this.ruleset) { this.ruleset.root = true; return this.name + (env.compress ? '{' : ' {\n ') + this.ruleset.toCSS(ctx, env).trim().replace(/\n/g, '\n ') + (env.compress ? '}': '\n}\n'); } else { return this.name + ' ' + this.value.toCSS() + ';\n'; } }, eval: function (env) { env.frames.unshift(this); this.ruleset = this.ruleset && this.ruleset.eval(env); env.frames.shift(); return this; }, variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) }, find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) }, rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) } }; })(require('../tree')); (function (tree) { tree.Element = function (combinator, value, index) { this.combinator = combinator instanceof tree.Combinator ? combinator : new(tree.Combinator)(combinator); this.value = value ? value.trim() : ""; this.index = index; }; tree.Element.prototype.toCSS = function (env) { return this.combinator.toCSS(env || {}) + this.value; }; tree.Combinator = function (value) { if (value === ' ') { this.value = ' '; } else if (value === '& ') { this.value = '& '; } else { this.value = value ? value.trim() : ""; } }; tree.Combinator.prototype.toCSS = function (env) { return { '' : '', ' ' : ' ', '&' : '', '& ' : ' ', ':' : ' :', '::': '::', '+' : env.compress ? '+' : ' + ', '~' : env.compress ? '~' : ' ~ ', '>' : env.compress ? '>' : ' > ' }[this.value]; }; })(require('../tree')); (function (tree) { tree.Expression = function (value) { this.value = value }; tree.Expression.prototype = { eval: function (env) { if (this.value.length > 1) { return new(tree.Expression)(this.value.map(function (e) { return e.eval(env); })); } else if (this.value.length === 1) { return this.value[0].eval(env); } else { return this; } }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS(env); }).join(' '); } }; })(require('../tree')); (function (tree) { // // CSS @import node // // The general strategy here is that we don't want to wait // for the parsing to be completed, before we start importing // the file. That's because in the context of a browser, // most of the time will be spent waiting for the server to respond. // // On creation, we push the import path to our import queue, though // `import,push`, we also pass it a callback, which it'll call once // the file has been fetched, and parsed. // tree.Import = function (path, imports) { var that = this; this._path = path; // The '.less' extension is optional if (path instanceof tree.Quoted) { this.path = /\.(le?|c)ss(\?.*)?$/.test(path.value) ? path.value : path.value + '.less'; } else { this.path = path.value.value || path.value; } this.css = /css(\?.*)?$/.test(this.path); // Only pre-compile .less files if (! this.css) { imports.push(this.path, function (root) { if (! root) { throw new(Error)("Error parsing " + that.path); } that.root = root; }); } }; // // The actual import node doesn't return anything, when converted to CSS. // The reason is that it's used at the evaluation stage, so that the rules // it imports can be treated like any other rules. // // In `eval`, we make sure all Import nodes get evaluated, recursively, so // we end up with a flat structure, which can easily be imported in the parent // ruleset. // tree.Import.prototype = { toCSS: function () { if (this.css) { return "@import " + this._path.toCSS() + ';\n'; } else { return ""; } }, eval: function (env) { var ruleset; if (this.css) { return this; } else { ruleset = new(tree.Ruleset)(null, this.root.rules.slice(0)); for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.Import) { Array.prototype .splice .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env))); } } return ruleset.rules; } } }; })(require('../tree')); (function (tree) { tree.JavaScript = function (string, index, escaped) { this.escaped = escaped; this.expression = string; this.index = index; }; tree.JavaScript.prototype = { eval: function (env) { var result, that = this, context = {}; var expression = this.expression.replace(/@\{([\w-]+)\}/g, function (_, name) { return tree.jsify(new(tree.Variable)('@' + name, that.index).eval(env)); }); try { expression = new(Function)('return (' + expression + ')'); } catch (e) { throw { message: "JavaScript evaluation error: `" + expression + "`" , index: this.index }; } for (var k in env.frames[0].variables()) { context[k.slice(1)] = { value: env.frames[0].variables()[k].value, toJS: function () { return this.value.eval(env).toCSS(); } }; } try { result = expression.call(context); } catch (e) { throw { message: "JavaScript evaluation error: '" + e.name + ': ' + e.message + "'" , index: this.index }; } if (typeof(result) === 'string') { return new(tree.Quoted)('"' + result + '"', result, this.escaped, this.index); } else if (Array.isArray(result)) { return new(tree.Anonymous)(result.join(', ')); } else { return new(tree.Anonymous)(result); } } }; })(require('../tree')); (function (tree) { tree.Keyword = function (value) { this.value = value }; tree.Keyword.prototype = { eval: function () { return this }, toCSS: function () { return this.value } }; })(require('../tree')); (function (tree) { tree.mixin = {}; tree.mixin.Call = function (elements, args, index) { this.selector = new(tree.Selector)(elements); this.arguments = args; this.index = index; }; tree.mixin.Call.prototype = { eval: function (env) { var mixins, args, rules = [], match = false; for (var i = 0; i < env.frames.length; i++) { if ((mixins = env.frames[i].find(this.selector)).length > 0) { args = this.arguments && this.arguments.map(function (a) { return a.eval(env) }); for (var m = 0; m < mixins.length; m++) { if (mixins[m].match(args, env)) { try { Array.prototype.push.apply( rules, mixins[m].eval(env, this.arguments).rules); match = true; } catch (e) { throw { message: e.message, index: e.index, stack: e.stack, call: this.index }; } } } if (match) { return rules; } else { throw { message: 'No matching definition was found for `' + this.selector.toCSS().trim() + '(' + this.arguments.map(function (a) { return a.toCSS(); }).join(', ') + ")`", index: this.index }; } } } throw { message: this.selector.toCSS().trim() + " is undefined", index: this.index }; } }; tree.mixin.Definition = function (name, params, rules) { this.name = name; this.selectors = [new(tree.Selector)([new(tree.Element)(null, name)])]; this.params = params; this.arity = params.length; this.rules = rules; this._lookups = {}; this.required = params.reduce(function (count, p) { if (!p.name || (p.name && !p.value)) { return count + 1 } else { return count } }, 0); this.parent = tree.Ruleset.prototype; this.frames = []; }; tree.mixin.Definition.prototype = { toCSS: function () { return "" }, variable: function (name) { return this.parent.variable.call(this, name) }, variables: function () { return this.parent.variables.call(this) }, find: function () { return this.parent.find.apply(this, arguments) }, rulesets: function () { return this.parent.rulesets.apply(this) }, eval: function (env, args) { var frame = new(tree.Ruleset)(null, []), context, _arguments = []; for (var i = 0, val; i < this.params.length; i++) { if (this.params[i].name) { if (val = (args && args[i]) || this.params[i].value) { frame.rules.unshift(new(tree.Rule)(this.params[i].name, val.eval(env))); } else { throw { message: "wrong number of arguments for " + this.name + ' (' + args.length + ' for ' + this.arity + ')' }; } } } for (var i = 0; i < Math.max(this.params.length, args && args.length); i++) { _arguments.push(args[i] || this.params[i].value); } frame.rules.unshift(new(tree.Rule)('@arguments', new(tree.Expression)(_arguments).eval(env))); return new(tree.Ruleset)(null, this.rules.slice(0)).eval({ frames: [this, frame].concat(this.frames, env.frames) }); }, match: function (args, env) { var argsLength = (args && args.length) || 0, len; if (argsLength < this.required) { return false } if ((this.required > 0) && (argsLength > this.params.length)) { return false } len = Math.min(argsLength, this.arity); for (var i = 0; i < len; i++) { if (!this.params[i].name) { if (args[i].eval(env).toCSS() != this.params[i].value.eval(env).toCSS()) { return false; } } } return true; } }; })(require('../tree')); (function (tree) { tree.Operation = function (op, operands) { this.op = op.trim(); this.operands = operands; }; tree.Operation.prototype.eval = function (env) { var a = this.operands[0].eval(env), b = this.operands[1].eval(env), temp; if (a instanceof tree.Dimension && b instanceof tree.Color) { if (this.op === '*' || this.op === '+') { temp = b, b = a, a = temp; } else { throw { name: "OperationError", message: "Can't substract or divide a color from a number" }; } } return a.operate(this.op, b); }; tree.operate = function (op, a, b) { switch (op) { case '+': return a + b; case '-': return a - b; case '*': return a * b; case '/': return a / b; } }; })(require('../tree')); (function (tree) { tree.Quoted = function (str, content, escaped, i) { this.escaped = escaped; this.value = content || ''; this.quote = str.charAt(0); this.index = i; }; tree.Quoted.prototype = { toCSS: function () { if (this.escaped) { return this.value; } else { return this.quote + this.value + this.quote; } }, eval: function (env) { var that = this; var value = this.value.replace(/`([^`]+)`/g, function (_, exp) { return new(tree.JavaScript)(exp, that.index, true).eval(env).value; }).replace(/@\{([\w-]+)\}/g, function (_, name) { var v = new(tree.Variable)('@' + name, that.index).eval(env); return v.value || v.toCSS(); }); return new(tree.Quoted)(this.quote + value + this.quote, value, this.escaped, this.index); } }; })(require('../tree')); (function (tree) { tree.Rule = function (name, value, important, index) { this.name = name; this.value = (value instanceof tree.Value) ? value : new(tree.Value)([value]); this.important = important ? ' ' + important.trim() : ''; this.index = index; if (name.charAt(0) === '@') { this.variable = true; } else { this.variable = false } }; tree.Rule.prototype.toCSS = function (env) { if (this.variable) { return "" } else { return this.name + (env.compress ? ':' : ': ') + this.value.toCSS(env) + this.important + ";"; } }; tree.Rule.prototype.eval = function (context) { return new(tree.Rule)(this.name, this.value.eval(context), this.important, this.index); }; tree.Shorthand = function (a, b) { this.a = a; this.b = b; }; tree.Shorthand.prototype = { toCSS: function (env) { return this.a.toCSS(env) + "/" + this.b.toCSS(env); }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.Ruleset = function (selectors, rules) { this.selectors = selectors; this.rules = rules; this._lookups = {}; }; tree.Ruleset.prototype = { eval: function (env) { var ruleset = new(tree.Ruleset)(this.selectors, this.rules.slice(0)); ruleset.root = this.root; // push the current ruleset to the frames stack env.frames.unshift(ruleset); // Evaluate imports if (ruleset.root) { for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.Import) { Array.prototype.splice .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env))); } } } // Store the frames around mixin definitions, // so they can be evaluated like closures when the time comes. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Definition) { ruleset.rules[i].frames = env.frames.slice(0); } } // Evaluate mixin calls. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Call) { Array.prototype.splice .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env))); } } // Evaluate everything else for (var i = 0, rule; i < ruleset.rules.length; i++) { rule = ruleset.rules[i]; if (! (rule instanceof tree.mixin.Definition)) { ruleset.rules[i] = rule.eval ? rule.eval(env) : rule; } } // Pop the stack env.frames.shift(); return ruleset; }, match: function (args) { return !args || args.length === 0; }, variables: function () { if (this._variables) { return this._variables } else { return this._variables = this.rules.reduce(function (hash, r) { if (r instanceof tree.Rule && r.variable === true) { hash[r.name] = r; } return hash; }, {}); } }, variable: function (name) { return this.variables()[name]; }, rulesets: function () { if (this._rulesets) { return this._rulesets } else { return this._rulesets = this.rules.filter(function (r) { return (r instanceof tree.Ruleset) || (r instanceof tree.mixin.Definition); }); } }, find: function (selector, self) { self = self || this; var rules = [], rule, match, key = selector.toCSS(); if (key in this._lookups) { return this._lookups[key] } this.rulesets().forEach(function (rule) { if (rule !== self) { for (var j = 0; j < rule.selectors.length; j++) { if (match = selector.match(rule.selectors[j])) { if (selector.elements.length > rule.selectors[j].elements.length) { Array.prototype.push.apply(rules, rule.find( new(tree.Selector)(selector.elements.slice(1)), self)); } else { rules.push(rule); } break; } } } }); return this._lookups[key] = rules; }, // // Entry point for code generation // // `context` holds an array of arrays. // toCSS: function (context, env) { var css = [], // The CSS output rules = [], // node.Rule instances rulesets = [], // node.Ruleset instances paths = [], // Current selectors selector, // The fully rendered selector rule; if (! this.root) { if (context.length === 0) { paths = this.selectors.map(function (s) { return [s] }); } else { this.joinSelectors( paths, context, this.selectors ); } } // Compile rules and rulesets for (var i = 0; i < this.rules.length; i++) { rule = this.rules[i]; if (rule.rules || (rule instanceof tree.Directive)) { rulesets.push(rule.toCSS(paths, env)); } else if (rule instanceof tree.Comment) { if (!rule.silent) { if (this.root) { rulesets.push(rule.toCSS(env)); } else { rules.push(rule.toCSS(env)); } } } else { if (rule.toCSS && !rule.variable) { rules.push(rule.toCSS(env)); } else if (rule.value && !rule.variable) { rules.push(rule.value.toString()); } } } rulesets = rulesets.join(''); // If this is the root node, we don't render // a selector, or {}. // Otherwise, only output if this ruleset has rules. if (this.root) { css.push(rules.join(env.compress ? '' : '\n')); } else { if (rules.length > 0) { selector = paths.map(function (p) { return p.map(function (s) { return s.toCSS(env); }).join('').trim(); }).join(env.compress ? ',' : (paths.length > 3 ? ',\n' : ', ')); css.push(selector, (env.compress ? '{' : ' {\n ') + rules.join(env.compress ? '' : '\n ') + (env.compress ? '}' : '\n}\n')); } } css.push(rulesets); return css.join('') + (env.compress ? '\n' : ''); }, joinSelectors: function (paths, context, selectors) { for (var s = 0; s < selectors.length; s++) { this.joinSelector(paths, context, selectors[s]); } }, joinSelector: function (paths, context, selector) { var before = [], after = [], beforeElements = [], afterElements = [], hasParentSelector = false, el; for (var i = 0; i < selector.elements.length; i++) { el = selector.elements[i]; if (el.combinator.value.charAt(0) === '&') { hasParentSelector = true; } if (hasParentSelector) afterElements.push(el); else beforeElements.push(el); } if (! hasParentSelector) { afterElements = beforeElements; beforeElements = []; } if (beforeElements.length > 0) { before.push(new(tree.Selector)(beforeElements)); } if (afterElements.length > 0) { after.push(new(tree.Selector)(afterElements)); } for (var c = 0; c < context.length; c++) { paths.push(before.concat(context[c]).concat(after)); } } }; })(require('../tree')); (function (tree) { tree.Selector = function (elements) { this.elements = elements; if (this.elements[0].combinator.value === "") { this.elements[0].combinator.value = ' '; } }; tree.Selector.prototype.match = function (other) { var len = this.elements.length, olen = other.elements.length, max = Math.min(len, olen); if (len < olen) { return false; } else { for (var i = 0; i < max; i++) { if (this.elements[i].value !== other.elements[i].value) { return false; } } } return true; }; tree.Selector.prototype.toCSS = function (env) { if (this._css) { return this._css } return this._css = this.elements.map(function (e) { if (typeof(e) === 'string') { return ' ' + e.trim(); } else { return e.toCSS(env); } }).join(''); }; })(require('../tree')); (function (tree) { tree.URL = function (val, paths) { if (val.data) { this.attrs = val; } else { // Add the base path if the URL is relative and we are in the browser if (less.mode === 'browser' && !/^(?:https?:\/\/|file:\/\/|data:|\/)/.test(val.value) && paths.length > 0) { val.value = paths[0] + (val.value.charAt(0) === '/' ? val.value.slice(1) : val.value); } this.value = val; this.paths = paths; } }; tree.URL.prototype = { toCSS: function () { return "url(" + (this.attrs ? 'data:' + this.attrs.mime + this.attrs.charset + this.attrs.base64 + this.attrs.data : this.value.toCSS()) + ")"; }, eval: function (ctx) { return this.attrs ? this : new(tree.URL)(this.value.eval(ctx), this.paths); } }; })(require('../tree')); (function (tree) { tree.Value = function (value) { this.value = value; this.is = 'value'; }; tree.Value.prototype = { eval: function (env) { if (this.value.length === 1) { return this.value[0].eval(env); } else { return new(tree.Value)(this.value.map(function (v) { return v.eval(env); })); } }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS(env); }).join(env.compress ? ',' : ', '); } }; })(require('../tree')); (function (tree) { tree.Variable = function (name, index) { this.name = name, this.index = index }; tree.Variable.prototype = { eval: function (env) { var variable, v, name = this.name; if (name.indexOf('@@') == 0) { name = '@' + new(tree.Variable)(name.slice(1)).eval(env).value; } if (variable = tree.find(env.frames, function (frame) { if (v = frame.variable(name)) { return v.value.eval(env); } })) { return variable } else { throw { message: "variable " + name + " is undefined", index: this.index }; } } }; })(require('../tree')); require('./tree').find = function (obj, fun) { for (var i = 0, r; i < obj.length; i++) { if (r = fun.call(obj, obj[i])) { return r } } return null; }; require('./tree').jsify = function (obj) { if (Array.isArray(obj.value) && (obj.value.length > 1)) { return '[' + obj.value.map(function (v) { return v.toCSS(false) }).join(', ') + ']'; } else { return obj.toCSS(false); } }; // // browser.js - client-side engine // var isFileProtocol = (location.protocol === 'file:' || location.protocol === 'chrome:' || location.protocol === 'chrome-extension:' || location.protocol === 'resource:'); less.env = less.env || (location.hostname == '127.0.0.1' || location.hostname == '0.0.0.0' || location.hostname == 'localhost' || location.port.length > 0 || isFileProtocol ? 'development' : 'production'); // Load styles asynchronously (default: false) // // This is set to `false` by default, so that the body // doesn't start loading before the stylesheets are parsed. // Setting this to `true` can result in flickering. // less.async = false; // Interval between watch polls less.poll = less.poll || (isFileProtocol ? 1000 : 1500); // // Watch mode // less.watch = function () { return this.watchMode = true }; less.unwatch = function () { return this.watchMode = false }; if (less.env === 'development') { less.optimization = 0; if (/!watch/.test(location.hash)) { less.watch(); } less.watchTimer = setInterval(function () { if (less.watchMode) { loadStyleSheets(function (root, sheet, env) { if (root) { createCSS(root.toCSS(), sheet, env.lastModified); } }); } }, less.poll); } else { less.optimization = 3; } var cache; try { cache = (typeof(window.localStorage) === 'undefined') ? null : window.localStorage; } catch (_) { cache = null; } // // Get all tags with the 'rel' attribute set to "stylesheet/less" // var links = document.getElementsByTagName('link'); var typePattern = /^text\/(x-)?less$/; less.sheets = []; for (var i = 0; i < links.length; i++) { if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) && (links[i].type.match(typePattern)))) { less.sheets.push(links[i]); } } less.refresh = function (reload) { var startTime, endTime; startTime = endTime = new(Date); loadStyleSheets(function (root, sheet, env) { if (env.local) { log("loading " + sheet.href + " from cache."); } else { log("parsed " + sheet.href + " successfully."); createCSS(root.toCSS(), sheet, env.lastModified); } log("css for " + sheet.href + " generated in " + (new(Date) - endTime) + 'ms'); (env.remaining === 0) && log("css generated in " + (new(Date) - startTime) + 'ms'); endTime = new(Date); }, reload); loadStyles(); }; less.refreshStyles = loadStyles; less.refresh(less.env === 'development'); function loadStyles() { var styles = document.getElementsByTagName('style'); for (var i = 0; i < styles.length; i++) { if (styles[i].type.match(typePattern)) { new(less.Parser)().parse(styles[i].innerHTML || '', function (e, tree) { var css = tree.toCSS(); var style = styles[i]; try { style.innerHTML = css; } catch (_) { style.styleSheets.cssText = css; } style.type = 'text/css'; }); } } } function loadStyleSheets(callback, reload) { for (var i = 0; i < less.sheets.length; i++) { loadStyleSheet(less.sheets[i], callback, reload, less.sheets.length - (i + 1)); } } function loadStyleSheet(sheet, callback, reload, remaining) { var url = window.location.href.replace(/[#?].*$/, ''); var href = sheet.href.replace(/\?.*$/, ''); var css = cache && cache.getItem(href); var timestamp = cache && cache.getItem(href + ':timestamp'); var styles = { css: css, timestamp: timestamp }; // Stylesheets in IE don't always return the full path if (! /^(https?|file):/.test(href)) { if (href.charAt(0) == "/") { href = window.location.protocol + "//" + window.location.host + href; } else { href = url.slice(0, url.lastIndexOf('/') + 1) + href; } } xhr(sheet.href, sheet.type, function (data, lastModified) { if (!reload && styles && lastModified && (new(Date)(lastModified).valueOf() === new(Date)(styles.timestamp).valueOf())) { // Use local copy createCSS(styles.css, sheet); callback(null, sheet, { local: true, remaining: remaining }); } else { // Use remote copy (re-parse) try { new(less.Parser)({ optimization: less.optimization, paths: [href.replace(/[\w\.-]+$/, '')], mime: sheet.type }).parse(data, function (e, root) { if (e) { return error(e, href) } try { callback(root, sheet, { local: false, lastModified: lastModified, remaining: remaining }); removeNode(document.getElementById('less-error-message:' + extractId(href))); } catch (e) { error(e, href); } }); } catch (e) { error(e, href); } } }, function (status, url) { throw new(Error)("Couldn't load " + url + " (" + status + ")"); }); } function extractId(href) { return href.replace(/^[a-z]+:\/\/?[^\/]+/, '' ) // Remove protocol & domain .replace(/^\//, '' ) // Remove root / .replace(/\?.*$/, '' ) // Remove query .replace(/\.[^\.\/]+$/, '' ) // Remove file extension .replace(/[^\.\w-]+/g, '-') // Replace illegal characters .replace(/\./g, ':'); // Replace dots with colons(for valid id) } function createCSS(styles, sheet, lastModified) { var css; // Strip the query-string var href = sheet.href ? sheet.href.replace(/\?.*$/, '') : ''; // If there is no title set, use the filename, minus the extension var id = 'less:' + (sheet.title || extractId(href)); // If the stylesheet doesn't exist, create a new node if ((css = document.getElementById(id)) === null) { css = document.createElement('style'); css.type = 'text/css'; css.media = sheet.media || 'screen'; css.id = id; document.getElementsByTagName('head')[0].appendChild(css); } if (css.styleSheet) { // IE try { css.styleSheet.cssText = styles; } catch (e) { throw new(Error)("Couldn't reassign styleSheet.cssText."); } } else { (function (node) { if (css.childNodes.length > 0) { if (css.firstChild.nodeValue !== node.nodeValue) { css.replaceChild(node, css.firstChild); } } else { css.appendChild(node); } })(document.createTextNode(styles)); } // Don't update the local store if the file wasn't modified if (lastModified && cache) { log('saving ' + href + ' to cache.'); cache.setItem(href, styles); cache.setItem(href + ':timestamp', lastModified); } } function xhr(url, type, callback, errback) { var xhr = getXMLHttpRequest(); var async = isFileProtocol ? false : less.async; if (typeof(xhr.overrideMimeType) === 'function') { xhr.overrideMimeType('text/css'); } xhr.open('GET', url, async); xhr.setRequestHeader('Accept', type || 'text/x-less, text/css; q=0.9, */*; q=0.5'); xhr.send(null); if (isFileProtocol) { if (xhr.status === 0) { callback(xhr.responseText); } else { errback(xhr.status, url); } } else if (async) { xhr.onreadystatechange = function () { if (xhr.readyState == 4) { handleResponse(xhr, callback, errback); } }; } else { handleResponse(xhr, callback, errback); } function handleResponse(xhr, callback, errback) { if (xhr.status >= 200 && xhr.status < 300) { callback(xhr.responseText, xhr.getResponseHeader("Last-Modified")); } else if (typeof(errback) === 'function') { errback(xhr.status, url); } } } function getXMLHttpRequest() { if (window.XMLHttpRequest) { return new(XMLHttpRequest); } else { try { return new(ActiveXObject)("MSXML2.XMLHTTP.3.0"); } catch (e) { log("browser doesn't support AJAX."); return null; } } } function removeNode(node) { return node && node.parentNode.removeChild(node); } function log(str) { if (less.env == 'development' && typeof(console) !== "undefined") { console.log('less: ' + str) } } function error(e, href) { var id = 'less-error-message:' + extractId(href); var template = ['
    ', '
  • {0}
  • ', '
  • {current}
  • ', '
  • {2}
  • ', '
'].join('\n'); var elem = document.createElement('div'), timer, content; elem.id = id; elem.className = "less-error-message"; content = '

' + (e.message || 'There is an error in your .less file') + '

' + '

' + href + " "; if (e.extract) { content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':

' + template.replace(/\[(-?\d)\]/g, function (_, i) { return (parseInt(e.line) + parseInt(i)) || ''; }).replace(/\{(\d)\}/g, function (_, i) { return e.extract[parseInt(i)] || ''; }).replace(/\{current\}/, e.extract[1].slice(0, e.column) + '' + e.extract[1].slice(e.column) + ''); } elem.innerHTML = content; // CSS for error messages createCSS([ '.less-error-message ul, .less-error-message li {', 'list-style-type: none;', 'margin-right: 15px;', 'padding: 4px 0;', 'margin: 0;', '}', '.less-error-message label {', 'font-size: 12px;', 'margin-right: 15px;', 'padding: 4px 0;', 'color: #cc7777;', '}', '.less-error-message pre {', 'color: #ee4444;', 'padding: 4px 0;', 'margin: 0;', 'display: inline-block;', '}', '.less-error-message pre.ctx {', 'color: #dd4444;', '}', '.less-error-message h3 {', 'font-size: 20px;', 'font-weight: bold;', 'padding: 15px 0 5px 0;', 'margin: 0;', '}', '.less-error-message a {', 'color: #10a', '}', '.less-error-message .error {', 'color: red;', 'font-weight: bold;', 'padding-bottom: 2px;', 'border-bottom: 1px dashed red;', '}' ].join('\n'), { title: 'error-message' }); elem.style.cssText = [ "font-family: Arial, sans-serif", "border: 1px solid #e00", "background-color: #eee", "border-radius: 5px", "-webkit-border-radius: 5px", "-moz-border-radius: 5px", "color: #e00", "padding: 15px", "margin-bottom: 15px" ].join(';'); if (less.env == 'development') { timer = setInterval(function () { if (document.body) { if (document.getElementById(id)) { document.body.replaceChild(elem, document.getElementById(id)); } else { document.body.insertBefore(elem, document.body.firstChild); } clearInterval(timer); } }, 10); } } })(window); less.js-1.4.2/dist/less-1.1.5.min.js000066400000000000000000001055601217256642200166060ustar00rootroot00000000000000// // LESS - Leaner CSS v1.1.5 // http://lesscss.org // // Copyright (c) 2009-2011, Alexis Sellier // Licensed under the Apache 2.0 License. // (function(a,b){function c(b){return a.less[b.split("/")[1]]}function l(){var a=document.getElementsByTagName("style");for(var b=0;b0?d.firstChild.nodeValue!==a.nodeValue&&d.replaceChild(a,d.firstChild):d.appendChild(a)})(document.createTextNode(a));c&&g&&(t("saving "+e+" to cache."),g.setItem(e,a),g.setItem(e+":timestamp",c))}function q(a,b,c,e){function i(b,c,d){b.status>=200&&b.status<300?c(b.responseText,b.getResponseHeader("Last-Modified")):typeof d=="function"&&d(b.status,a)}var g=r(),h=f?!1:d.async;typeof g.overrideMimeType=="function"&&g.overrideMimeType("text/css"),g.open("GET",a,h),g.setRequestHeader("Accept",b||"text/x-less, text/css; q=0.9, */*; q=0.5"),g.send(null),f?g.status===0?c(g.responseText):e(g.status,a):h?g.onreadystatechange=function(){g.readyState==4&&i(g,c,e)}:i(g,c,e)}function r(){if(a.XMLHttpRequest)return new XMLHttpRequest;try{return new ActiveXObject("MSXML2.XMLHTTP.3.0")}catch(b){return t("browser doesn't support AJAX."),null}}function s(a){return a&&a.parentNode.removeChild(a)}function t(a){d.env=="development"&&typeof console!="undefined"&&console.log("less: "+a)}function u(a,b){var c="less-error-message:"+o(b),e=["
    ",'
  • {0}
  • ',"
  • {current}
  • ",'
  • {2}
  • ',"
"].join("\n"),f=document.createElement("div"),g,h;f.id=c,f.className="less-error-message",h="

"+(a.message||"There is an error in your .less file")+"

"+'

'+b+" ",a.extract&&(h+="on line "+a.line+", column "+(a.column+1)+":

"+e.replace(/\[(-?\d)\]/g,function(b,c){return parseInt(a.line)+parseInt(c)||""}).replace(/\{(\d)\}/g,function(b,c){return a.extract[parseInt(c)]||""}).replace(/\{current\}/,a.extract[1].slice(0,a.column)+''+a.extract[1].slice(a.column)+"")),f.innerHTML=h,p([".less-error-message ul, .less-error-message li {","list-style-type: none;","margin-right: 15px;","padding: 4px 0;","margin: 0;","}",".less-error-message label {","font-size: 12px;","margin-right: 15px;","padding: 4px 0;","color: #cc7777;","}",".less-error-message pre {","color: #ee4444;","padding: 4px 0;","margin: 0;","display: inline-block;","}",".less-error-message pre.ctx {","color: #dd4444;","}",".less-error-message h3 {","font-size: 20px;","font-weight: bold;","padding: 15px 0 5px 0;","margin: 0;","}",".less-error-message a {","color: #10a","}",".less-error-message .error {","color: red;","font-weight: bold;","padding-bottom: 2px;","border-bottom: 1px dashed red;","}"].join("\n"),{title:"error-message"}),f.style.cssText=["font-family: Arial, sans-serif","border: 1px solid #e00","background-color: #eee","border-radius: 5px","-webkit-border-radius: 5px","-moz-border-radius: 5px","color: #e00","padding: 15px","margin-bottom: 15px"].join(";"),d.env=="development"&&(g=setInterval(function(){document.body&&(document.getElementById(c)?document.body.replaceChild(f,document.getElementById(c)):document.body.insertBefore(f,document.body.firstChild),clearInterval(g))},10))}Array.isArray||(Array.isArray=function(a){return Object.prototype.toString.call(a)==="[object Array]"||a instanceof Array}),Array.prototype.forEach||(Array.prototype.forEach=function(a,b){var c=this.length>>>0;for(var d=0;d>>0,c=new Array(b),d=arguments[1];for(var e=0;e>>0,c=0;if(b===0&&arguments.length===1)throw new TypeError;if(arguments.length>=2)var d=arguments[1];else do{if(c in this){d=this[c++];break}if(++c>=b)throw new TypeError}while(!0);for(;c=b)return-1;c<0&&(c+=b);for(;ck&&(j[f]=j[f].slice(c-k),k=c)}function s(a){var d,e,g,h,i,m,n,o;if(a instanceof Function)return a.call(l.parsers);if(typeof a=="string")d=b.charAt(c)===a?a:null,g=1,r();else{r();if(d=a.exec(j[f]))g=d[0].length;else return null}if(d){o=c+=g,m=c+j[f].length-g;while(c0)throw{type:"Syntax",message:"Missing closing `}`",filename:a.filename};return c.map(function(a){return a.join("")})}([[]]),h=new e.Ruleset([],s(this.parsers.primary)),h.root=!0,h.toCSS=function(c){var d,f,g;return function(g,h){function n(a){return a?(b.slice(0,a).match(/\n/g)||"").length:null}var i=[];g=g||{},typeof h=="object"&&!Array.isArray(h)&&(h=Object.keys(h).map(function(a){var b=h[a];return b instanceof e.Value||(b instanceof e.Expression||(b=new e.Expression([b])),b=new e.Value([b])),new e.Rule("@"+a,b,!1,0)}),i=[new e.Ruleset(null,h)]);try{var j=c.call(this,{frames:i}).toCSS([],{compress:g.compress||!1})}catch(k){f=b.split("\n"),d=n(k.index);for(var l=k.index,m=-1;l>=0&&b.charAt(l)!=="\n";l--)m++;throw{type:k.type,message:k.message,filename:a.filename,index:k.index,line:typeof d=="number"?d+1:null,callLine:k.call&&n(k.call)+1,callExtract:f[n(k.call)],stack:k.stack,column:m,extract:[f[d-1],f[d],f[d+1]]}}return g.compress?j.replace(/(\s)+/g,"$1"):j}}(h.eval);if(c=0&&b.charAt(v)!=="\n";v--)w++;u={name:"ParseError",message:"Syntax Error on line "+p,index:c,filename:a.filename,line:p,column:w,extract:[q[p-2],q[p-1],q[p]]}}this.imports.queue.length>0?n=function(){g(u,h)}:g(u,h)},parsers:{primary:function(){var a,b=[];while((a=s(this.mixin.definition)||s(this.rule)||s(this.ruleset)||s(this.mixin.call)||s(this.comment)||s(this.directive))||s(/^[\s\n]+/))a&&b.push(a);return b},comment:function(){var a;if(b.charAt(c)!=="/")return;if(b.charAt(c+1)==="/")return new e.Comment(s(/^\/\/.*/),!0);if(a=s(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/))return new e.Comment(a)},entities:{quoted:function(){var a,d=c,f;b.charAt(d)==="~"&&(d++,f=!0);if(b.charAt(d)!=='"'&&b.charAt(d)!=="'")return;f&&s("~");if(a=s(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/))return new e.Quoted(a[0],a[1]||a[2],f)},keyword:function(){var a;if(a=s(/^[_A-Za-z-][_A-Za-z0-9-]*/))return new e.Keyword(a)},call:function(){var a,b,d=c;if(!(a=/^([\w-]+|%)\(/.exec(j[f])))return;a=a[1].toLowerCase();if(a==="url")return null;c+=a.length;if(a==="alpha")return s(this.alpha);s("("),b=s(this.entities.arguments);if(!s(")"))return;if(a)return new e.Call(a,b,d)},arguments:function(){var a=[],b;while(b=s(this.expression)){a.push(b);if(!s(","))break}return a},literal:function(){return s(this.entities.dimension)||s(this.entities.color)||s(this.entities.quoted)},url:function(){var a;if(b.charAt(c)!=="u"||!s(/^url\(/))return;a=s(this.entities.quoted)||s(this.entities.variable)||s(this.entities.dataURI)||s(/^[-\w%@$\/.&=:;#+?~]+/)||"";if(!s(")"))throw new Error("missing closing ) for url()");return new e.URL(a.value||a.data||a instanceof e.Variable?a:new e.Anonymous(a),o.paths)},dataURI:function(){var a;if(s(/^data:/)){a={},a.mime=s(/^[^\/]+\/[^,;)]+/)||"",a.charset=s(/^;\s*charset=[^,;)]+/)||"",a.base64=s(/^;\s*base64/)||"",a.data=s(/^,\s*[^)]+/);if(a.data)return a}},variable:function(){var a,d=c;if(b.charAt(c)==="@"&&(a=s(/^@@?[\w-]+/)))return new e.Variable(a,d)},color:function(){var a;if(b.charAt(c)==="#"&&(a=s(/^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})/)))return new e.Color(a[1])},dimension:function(){var a,d=b.charCodeAt(c);if(d>57||d<45||d===47)return;if(a=s(/^(-?\d*\.?\d+)(px|%|em|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn)?/))return new e.Dimension(a[1],a[2])},javascript:function(){var a,d=c,f;b.charAt(d)==="~"&&(d++,f=!0);if(b.charAt(d)!=="`")return;f&&s("~");if(a=s(/^`([^`]*)`/))return new e.JavaScript(a[1],c,f)}},variable:function(){var a;if(b.charAt(c)==="@"&&(a=s(/^(@[\w-]+)\s*:/)))return a[1]},shorthand:function(){var a,b;if(!t(/^[@\w.%-]+\/[@\w.-]+/))return;if((a=s(this.entity))&&s("/")&&(b=s(this.entity)))return new e.Shorthand(a,b)},mixin:{call:function(){var a=[],d,f,g,h=c,i=b.charAt(c);if(i!=="."&&i!=="#")return;while(d=s(/^[#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/))a.push(new e.Element(f,d,c)),f=s(">");s("(")&&(g=s(this.entities.arguments))&&s(")");if(a.length>0&&(s(";")||t("}")))return new e.mixin.Call(a,g,h)},definition:function(){var a,d=[],f,g,h,i;if(b.charAt(c)!=="."&&b.charAt(c)!=="#"||t(/^[^{]*(;|})/))return;if(f=s(/^([#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+)\s*\(/)){a=f[1];while(h=s(this.entities.variable)||s(this.entities.literal)||s(this.entities.keyword)){if(h instanceof e.Variable)if(s(":"))if(i=s(this.expression))d.push({name:h.name,value:i});else throw new Error("Expected value");else d.push({name:h.name});else d.push({value:h});if(!s(","))break}if(!s(")"))throw new Error("Expected )");g=s(this.block);if(g)return new e.mixin.Definition(a,d,g)}}},entity:function(){return s(this.entities.literal)||s(this.entities.variable)||s(this.entities.url)||s(this.entities.call)||s(this.entities.keyword)||s(this.entities.javascript)||s(this.comment)},end:function(){return s(";")||t("}")},alpha:function(){var a;if(!s(/^\(opacity=/i))return;if(a=s(/^\d+/)||s(this.entities.variable)){if(!s(")"))throw new Error("missing closing ) for alpha()");return new e.Alpha(a)}},element:function(){var a,b,d;d=s(this.combinator),a=s(/^(?:\d+\.\d+|\d+)%/)||s(/^(?:[.#]?|:*)(?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/)||s("*")||s(this.attribute)||s(/^\([^)@]+\)/);if(a)return new e.Element(d,a,c);if(d.value&&d.value.charAt(0)==="&")return new e.Element(d,null,c)},combinator:function(){var a,d=b.charAt(c);if(d===">"||d==="+"||d==="~"){c++;while(b.charAt(c)===" ")c++;return new e.Combinator(d)}if(d==="&"){a="&",c++,b.charAt(c)===" "&&(a="& ");while(b.charAt(c)===" ")c++;return new e.Combinator(a)}if(d===":"&&b.charAt(c+1)===":"){c+=2;while(b.charAt(c)===" ")c++;return new e.Combinator("::")}return b.charAt(c-1)===" "?new e.Combinator(" "):new e.Combinator(null)},selector:function(){var a,d,f=[],g,h;while(d=s(this.element)){g=b.charAt(c),f.push(d);if(g==="{"||g==="}"||g===";"||g===",")break}if(f.length>0)return new e.Selector(f)},tag:function(){return s(/^[a-zA-Z][a-zA-Z-]*[0-9]?/)||s("*")},attribute:function(){var a="",b,c,d;if(!s("["))return;if(b=s(/^[a-zA-Z-]+/)||s(this.entities.quoted))(d=s(/^[|~*$^]?=/))&&(c=s(this.entities.quoted)||s(/^[\w-]+/))?a=[b,d,c.toCSS?c.toCSS():c].join(""):a=b;if(!s("]"))return;if(a)return"["+a+"]"},block:function(){var a;if(s("{")&&(a=s(this.primary))&&s("}"))return a},ruleset:function(){var a=[],b,d,f;p();while(b=s(this.selector)){a.push(b),s(this.comment);if(!s(","))break;s(this.comment)}if(a.length>0&&(d=s(this.block)))return new e.Ruleset(a,d);i=c,q()},rule:function(){var a,d,g=b.charAt(c),k,l;p();if(g==="."||g==="#"||g==="&")return;if(a=s(this.variable)||s(this.property)){a.charAt(0)!="@"&&(l=/^([^@+\/'"*`(;{}-]*);/.exec(j[f]))?(c+=l[0].length-1,d=new e.Anonymous(l[1])):a==="font"?d=s(this.font):d=s(this.value),k=s(this.important);if(d&&s(this.end))return new e.Rule(a,d,k,h);i=c,q()}},"import":function(){var a;if(s(/^@import\s+/)&&(a=s(this.entities.quoted)||s(this.entities.url))&&s(";"))return new e.Import(a,o)},directive:function(){var a,d,f,g;if(b.charAt(c)!=="@")return;if(d=s(this["import"]))return d;if(a=s(/^@media|@page/)||s(/^@(?:-webkit-|-moz-)?keyframes/)){g=(s(/^[^{]+/)||"").trim();if(f=s(this.block))return new e.Directive(a+" "+g,f)}else if(a=s(/^@[-a-z]+/))if(a==="@font-face"){if(f=s(this.block))return new e.Directive(a,f)}else if((d=s(this.entity))&&s(";"))return new e.Directive(a,d)},font:function(){var a=[],b=[],c,d,f,g;while(g=s(this.shorthand)||s(this.entity))b.push(g);a.push(new e.Expression(b));if(s(","))while(g=s(this.expression)){a.push(g);if(!s(","))break}return new e.Value(a)},value:function(){var a,b=[],c;while(a=s(this.expression)){b.push(a);if(!s(","))break}if(b.length>0)return new e.Value(b)},important:function(){if(b.charAt(c)==="!")return s(/^! *important/)},sub:function(){var a;if(s("(")&&(a=s(this.expression))&&s(")"))return a},multiplication:function(){var a,b,c,d;if(a=s(this.operand)){while((c=s("/")||s("*"))&&(b=s(this.operand)))d=new e.Operation(c,[d||a,b]);return d||a}},addition:function(){var a,d,f,g;if(a=s(this.multiplication)){while((f=s(/^[-+]\s+/)||b.charAt(c-1)!=" "&&(s("+")||s("-")))&&(d=s(this.multiplication)))g=new e.Operation(f,[g||a,d]);return g||a}},operand:function(){var a,d=b.charAt(c+1);b.charAt(c)==="-"&&(d==="@"||d==="(")&&(a=s("-"));var f=s(this.sub)||s(this.entities.dimension)||s(this.entities.color)||s(this.entities.variable)||s(this.entities.call);return a?new e.Operation("*",[new e.Dimension(-1),f]):f},expression:function(){var a,b,c=[],d;while(a=s(this.addition)||s(this.entity))c.push(a);if(c.length>0)return new e.Expression(c)},property:function(){var a;if(a=s(/^(\*?-?[-a-z_0-9]+)\s*:/))return a[1]}}}};if(d.mode==="browser"||d.mode==="rhino")d.Parser.importer=function(a,b,c,d){a.charAt(0)!=="/"&&b.length>0&&(a=b[0]+a),n({href:a,title:a,type:d.mime},c,!0)};(function(a){function b(b){return a.functions.hsla(b.h,b.s,b.l,b.a)}function c(b){if(b instanceof a.Dimension)return parseFloat(b.unit=="%"?b.value/100:b.value);if(typeof b=="number")return b;throw{error:"RuntimeError",message:"color functions take numbers as parameters"}}function d(a){return Math.min(1,Math.max(0,a))}a.functions={rgb:function(a,b,c){return this.rgba(a,b,c,1)},rgba:function(b,d,e,f){var g=[b,d,e].map(function(a){return c(a)}),f=c(f);return new a.Color(g,f)},hsl:function(a,b,c){return this.hsla(a,b,c,1)},hsla:function(a,b,d,e){function h(a){return a=a<0?a+1:a>1?a-1:a,a*6<1?g+(f-g)*a*6:a*2<1?f:a*3<2?g+(f-g)*(2/3-a)*6:g}a=c(a)%360/360,b=c(b),d=c(d),e=c(e);var f=d<=.5?d*(b+1):d+b-d*b,g=d*2-f;return this.rgba(h(a+1/3)*255,h(a)*255,h(a-1/3)*255,e)},hue:function(b){return new a.Dimension(Math.round(b.toHSL().h))},saturation:function(b){return new a.Dimension(Math.round(b.toHSL().s*100),"%")},lightness:function(b){return new a.Dimension(Math.round(b.toHSL().l*100),"%")},alpha:function(b){return new a.Dimension(b.toHSL().a)},saturate:function(a,c){var e=a.toHSL();return e.s+=c.value/100,e.s=d(e.s),b(e)},desaturate:function(a,c){var e=a.toHSL();return e.s-=c.value/100,e.s=d(e.s),b(e)},lighten:function(a,c){var e=a.toHSL();return e.l+=c.value/100,e.l=d(e.l),b(e)},darken:function(a,c){var e=a.toHSL();return e.l-=c.value/100,e.l=d(e.l),b(e)},fadein:function(a,c){var e=a.toHSL();return e.a+=c.value/100,e.a=d(e.a),b(e)},fadeout:function(a,c){var e=a.toHSL();return e.a-=c.value/100,e.a=d(e.a),b(e)},fade:function(a,c){var e=a.toHSL();return e.a=c.value/100,e.a=d(e.a),b(e)},spin:function(a,c){var d=a.toHSL(),e=(d.h+c.value)%360;return d.h=e<0?360+e:e,b(d)},mix:function(b,c,d){var e=d.value/100,f=e*2-1,g=b.toHSL().a-c.toHSL().a,h=((f*g==-1?f:(f+g)/(1+f*g))+1)/2,i=1-h,j=[b.rgb[0]*h+c.rgb[0]*i,b.rgb[1]*h+c.rgb[1]*i,b.rgb[2]*h+c.rgb[2]*i],k=b.alpha*e+c.alpha*(1-e);return new a.Color(j,k)},greyscale:function(b){return this.desaturate(b,new a.Dimension(100))},e:function(b){return new a.Anonymous(b instanceof a.JavaScript?b.evaluated:b)},escape:function(b){return new a.Anonymous(encodeURI(b.value).replace(/=/g,"%3D").replace(/:/g,"%3A").replace(/#/g,"%23").replace(/;/g,"%3B").replace(/\(/g,"%28").replace(/\)/g,"%29"))},"%":function(b){var c=Array.prototype.slice.call(arguments,1),d=b.value;for(var e=0;e255?255:a<0?0:a).toString(16),a.length===1?"0"+a:a}).join("")},operate:function(b,c){var d=[];c instanceof a.Color||(c=c.toColor());for(var e=0;e<3;e++)d[e]=a.operate(b,this.rgb[e],c.rgb[e]);return new a.Color(d,this.alpha+c.alpha)},toHSL:function(){var a=this.rgb[0]/255,b=this.rgb[1]/255,c=this.rgb[2]/255,d=this.alpha,e=Math.max(a,b,c),f=Math.min(a,b,c),g,h,i=(e+f)/2,j=e-f;if(e===f)g=h=0;else{h=i>.5?j/(2-e-f):j/(e+f);switch(e){case a:g=(b-c)/j+(b255?255:a<0?0:a).toString(16),a.length===1?"0"+a:a}).join("")}}}(c("../tree")),function(a){a.Comment=function(a,b){this.value=a,this.silent=!!b},a.Comment.prototype={toCSS:function(a){return a.compress?"":this.value},eval:function(){return this}}}(c("../tree")),function(a){a.Dimension=function(a,b){this.value=parseFloat(a),this.unit=b||null},a.Dimension.prototype={eval:function(){return this},toColor:function(){return new a.Color([this.value,this.value,this.value])},toCSS:function(){var a=this.value+this.unit;return a},operate:function(b,c){return new a.Dimension(a.operate(b,this.value,c.value),this.unit||c.unit)}}}(c("../tree")),function(a){a.Directive=function(b,c){this.name=b,Array.isArray(c)?this.ruleset=new a.Ruleset([],c):this.value=c},a.Directive.prototype={toCSS:function(a,b){return this.ruleset?(this.ruleset.root=!0,this.name+(b.compress?"{":" {\n ")+this.ruleset.toCSS(a,b).trim().replace(/\n/g,"\n ")+(b.compress?"}":"\n}\n")):this.name+" "+this.value.toCSS()+";\n"},eval:function(a){return a.frames.unshift(this),this.ruleset=this.ruleset&&this.ruleset.eval(a),a.frames.shift(),this},variable:function(b){return a.Ruleset.prototype.variable.call(this.ruleset,b)},find:function(){return a.Ruleset.prototype.find.apply(this.ruleset,arguments)},rulesets:function(){return a.Ruleset.prototype.rulesets.apply(this.ruleset)}}}(c("../tree")),function(a){a.Element=function(b,c,d){this.combinator=b instanceof a.Combinator?b:new a.Combinator(b),this.value=c?c.trim():"",this.index=d},a.Element.prototype.toCSS=function(a){return this.combinator.toCSS(a||{})+this.value},a.Combinator=function(a){a===" "?this.value=" ":a==="& "?this.value="& ":this.value=a?a.trim():""},a.Combinator.prototype.toCSS=function(a){return{"":""," ":" ","&":"","& ":" ",":":" :","::":"::","+":a.compress?"+":" + ","~":a.compress?"~":" ~ ",">":a.compress?">":" > "}[this.value]}}(c("../tree")),function(a){a.Expression=function(a){this.value=a},a.Expression.prototype={eval:function(b){return this.value.length>1?new a.Expression(this.value.map(function(a){return a.eval(b)})):this.value.length===1?this.value[0].eval(b):this},toCSS:function(a){return this.value.map(function(b){return b.toCSS(a)}).join(" ")}}}(c("../tree")),function(a){a.Import=function(b,c){var d=this;this._path=b,b instanceof a.Quoted?this.path=/\.(le?|c)ss(\?.*)?$/.test(b.value)?b.value:b.value+".less":this.path=b.value.value||b.value,this.css=/css(\?.*)?$/.test(this.path),this.css||c.push(this.path,function(a){if(!a)throw new Error("Error parsing "+d.path);d.root=a})},a.Import.prototype={toCSS:function(){return this.css?"@import "+this._path.toCSS()+";\n":""},eval:function(b){var c;if(this.css)return this;c=new a.Ruleset(null,this.root.rules.slice(0));for(var d=0;d0){c=this.arguments&&this.arguments.map(function(b){return b.eval(a)});for(var g=0;g0&&c>this.params.length)return!1;d=Math.min(c,this.arity);for(var e=0;ee.selectors[g].elements.length?Array.prototype.push.apply(d,e.find(new a.Selector(b.elements.slice(1)),c)):d.push(e);break}}),this._lookups[g]=d)},toCSS:function(b,c){var d=[],e=[],f=[],g=[],h,i;this.root||(b.length===0?g=this.selectors.map(function(a){return[a]}):this.joinSelectors(g,b,this.selectors));for(var j=0;j0&&(h=g.map(function(a){return a.map(function(a){return a.toCSS(c)}).join("").trim()}).join(c.compress?",":g.length>3?",\n":", "),d.push(h,(c.compress?"{":" {\n ")+e.join(c.compress?"":"\n ")+(c.compress?"}":"\n}\n"))),d.push(f),d.join("")+(c.compress?"\n":"")},joinSelectors:function(a,b,c){for(var d=0;d0&&e.push(new a.Selector(g)),h.length>0&&f.push(new a.Selector(h));for(var l=0;l0&&(a.value=b[0]+(a.value.charAt(0)==="/"?a.value.slice(1):a.value)),this.value=a,this.paths=b)},a.URL.prototype={toCSS:function(){return"url("+(this.attrs?"data:"+this.attrs.mime+this.attrs.charset+this.attrs.base64+this.attrs.data:this.value.toCSS())+")"},eval:function(b){return this.attrs?this:new a.URL(this.value.eval(b),this.paths)}}}(c("../tree")),function(a){a.Value=function(a){this.value=a,this.is="value"},a.Value.prototype={eval:function(b){return this.value.length===1?this.value[0].eval(b):new a.Value(this.value.map(function(a){return a.eval(b)}))},toCSS:function(a){return this.value.map(function(b){return b.toCSS(a)}).join(a.compress?",":", ")}}}(c("../tree")),function(a){a.Variable=function(a,b){this.name=a,this.index=b},a.Variable.prototype={eval:function(b){var c,d,e=this.name;e.indexOf("@@")==0&&(e="@"+(new a.Variable(e.slice(1))).eval(b).value);if(c=a.find(b.frames,function(a){if(d=a.variable(e))return d.value.eval(b)}))return c;throw{message:"variable "+e+" is undefined",index:this.index}}}}(c("../tree")),c("./tree").find=function(a,b){for(var c=0,d;c1?"["+a.value.map(function(a){return a.toCSS(!1)}).join(", ")+"]":a.toCSS(!1)};var f=location.protocol==="file:"||location.protocol==="chrome:"||location.protocol==="chrome-extension:"||location.protocol==="resource:";d.env=d.env||(location.hostname=="127.0.0.1"||location.hostname=="0.0.0.0"||location.hostname=="localhost"||location.port.length>0||f?"development":"production"),d.async=!1,d.poll=d.poll||(f?1e3:1500),d.watch=function(){return this.watchMode=!0},d.unwatch=function(){return this.watchMode=!1},d.env==="development"?(d.optimization=0,/!watch/.test(location.hash)&&d.watch(),d.watchTimer=setInterval(function(){d.watchMode&&m(function(a,b,c){a&&p(a.toCSS(),b,c.lastModified)})},d.poll)):d.optimization=3;var g;try{g=typeof a.localStorage=="undefined"?null:a.localStorage}catch(h){g=null}var i=document.getElementsByTagName("link"),j=/^text\/(x-)?less$/;d.sheets=[];for(var k=0;k>> 0; for (var i = 0; i < len; i++) { if (i in this) { block.call(thisObject, this[i], i, this); } } }; } if (!Array.prototype.map) { Array.prototype.map = function(fun /*, thisp*/) { var len = this.length >>> 0; var res = new Array(len); var thisp = arguments[1]; for (var i = 0; i < len; i++) { if (i in this) { res[i] = fun.call(thisp, this[i], i, this); } } return res; }; } if (!Array.prototype.filter) { Array.prototype.filter = function (block /*, thisp */) { var values = []; var thisp = arguments[1]; for (var i = 0; i < this.length; i++) { if (block.call(thisp, this[i])) { values.push(this[i]); } } return values; }; } if (!Array.prototype.reduce) { Array.prototype.reduce = function(fun /*, initial*/) { var len = this.length >>> 0; var i = 0; // no value to return if no initial value and an empty array if (len === 0 && arguments.length === 1) throw new TypeError(); if (arguments.length >= 2) { var rv = arguments[1]; } else { do { if (i in this) { rv = this[i++]; break; } // if array contains no values, no initial value to return if (++i >= len) throw new TypeError(); } while (true); } for (; i < len; i++) { if (i in this) { rv = fun.call(null, rv, this[i], i, this); } } return rv; }; } if (!Array.prototype.indexOf) { Array.prototype.indexOf = function (value /*, fromIndex */ ) { var length = this.length; var i = arguments[1] || 0; if (!length) return -1; if (i >= length) return -1; if (i < 0) i += length; for (; i < length; i++) { if (!Object.prototype.hasOwnProperty.call(this, i)) { continue } if (value === this[i]) return i; } return -1; }; } // // Object // if (!Object.keys) { Object.keys = function (object) { var keys = []; for (var name in object) { if (Object.prototype.hasOwnProperty.call(object, name)) { keys.push(name); } } return keys; }; } // // String // if (!String.prototype.trim) { String.prototype.trim = function () { return String(this).replace(/^\s\s*/, '').replace(/\s\s*$/, ''); }; } var less, tree; if (typeof environment === "object" && ({}).toString.call(environment) === "[object Environment]") { // Rhino // Details on how to detect Rhino: https://github.com/ringo/ringojs/issues/88 less = {}; tree = less.tree = {}; less.mode = 'rhino'; } else if (typeof(window) === 'undefined') { // Node.js less = exports, tree = require('./tree'); less.mode = 'node'; } else { // Browser if (typeof(window.less) === 'undefined') { window.less = {} } less = window.less, tree = window.less.tree = {}; less.mode = 'browser'; } // // less.js - parser // // A relatively straight-forward predictive parser. // There is no tokenization/lexing stage, the input is parsed // in one sweep. // // To make the parser fast enough to run in the browser, several // optimization had to be made: // // - Matching and slicing on a huge input is often cause of slowdowns. // The solution is to chunkify the input into smaller strings. // The chunks are stored in the `chunks` var, // `j` holds the current chunk index, and `current` holds // the index of the current chunk in relation to `input`. // This gives us an almost 4x speed-up. // // - In many cases, we don't need to match individual tokens; // for example, if a value doesn't hold any variables, operations // or dynamic references, the parser can effectively 'skip' it, // treating it as a literal. // An example would be '1px solid #000' - which evaluates to itself, // we don't need to know what the individual components are. // The drawback, of course is that you don't get the benefits of // syntax-checking on the CSS. This gives us a 50% speed-up in the parser, // and a smaller speed-up in the code-gen. // // // Token matching is done with the `$` function, which either takes // a terminal string or regexp, or a non-terminal function to call. // It also takes care of moving all the indices forwards. // // less.Parser = function Parser(env) { var input, // LeSS input string i, // current index in `input` j, // current chunk temp, // temporarily holds a chunk's state, for backtracking memo, // temporarily holds `i`, when backtracking furthest, // furthest index the parser has gone to chunks, // chunkified input current, // index of current chunk, in `input` parser; var that = this; // This function is called after all files // have been imported through `@import`. var finish = function () {}; var imports = this.imports = { paths: env && env.paths || [], // Search paths, when importing queue: [], // Files which haven't been imported yet files: {}, // Holds the imported parse trees mime: env && env.mime, // MIME type of .less files push: function (path, callback) { var that = this; this.queue.push(path); // // Import a file asynchronously // less.Parser.importer(path, this.paths, function (root) { that.queue.splice(that.queue.indexOf(path), 1); // Remove the path from the queue that.files[path] = root; // Store the root callback(root); if (that.queue.length === 0) { finish() } // Call `finish` if we're done importing }, env); } }; function save() { temp = chunks[j], memo = i, current = i } function restore() { chunks[j] = temp, i = memo, current = i } function sync() { if (i > current) { chunks[j] = chunks[j].slice(i - current); current = i; } } // // Parse from a token, regexp or string, and move forward if match // function $(tok) { var match, args, length, c, index, endIndex, k, mem; // // Non-terminal // if (tok instanceof Function) { return tok.call(parser.parsers); // // Terminal // // Either match a single character in the input, // or match a regexp in the current chunk (chunk[j]). // } else if (typeof(tok) === 'string') { match = input.charAt(i) === tok ? tok : null; length = 1; sync (); } else { sync (); if (match = tok.exec(chunks[j])) { length = match[0].length; } else { return null; } } // The match is confirmed, add the match length to `i`, // and consume any extra white-space characters (' ' || '\n') // which come after that. The reason for this is that LeSS's // grammar is mostly white-space insensitive. // if (match) { mem = i += length; endIndex = i + chunks[j].length - length; while (i < endIndex) { c = input.charCodeAt(i); if (! (c === 32 || c === 10 || c === 9)) { break } i++; } chunks[j] = chunks[j].slice(length + (i - mem)); current = i; if (chunks[j].length === 0 && j < chunks.length - 1) { j++ } if(typeof(match) === 'string') { return match; } else { return match.length === 1 ? match[0] : match; } } } // Same as $(), but don't change the state of the parser, // just return the match. function peek(tok) { if (typeof(tok) === 'string') { return input.charAt(i) === tok; } else { if (tok.test(chunks[j])) { return true; } else { return false; } } } this.env = env = env || {}; // The optimization level dictates the thoroughness of the parser, // the lower the number, the less nodes it will create in the tree. // This could matter for debugging, or if you want to access // the individual nodes in the tree. this.optimization = ('optimization' in this.env) ? this.env.optimization : 1; this.env.filename = this.env.filename || null; // // The Parser // return parser = { imports: imports, // // Parse an input string into an abstract syntax tree, // call `callback` when done. // parse: function (str, callback) { var root, start, end, zone, line, lines, buff = [], c, error = null; i = j = current = furthest = 0; chunks = []; input = str.replace(/\r\n/g, '\n'); // Split the input into chunks. chunks = (function (chunks) { var j = 0, skip = /[^"'`\{\}\/\(\)]+/g, comment = /\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g, level = 0, match, chunk = chunks[0], inParam, inString; for (var i = 0, c, cc; i < input.length; i++) { skip.lastIndex = i; if (match = skip.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); } } c = input.charAt(i); comment.lastIndex = i; if (!inString && !inParam && c === '/') { cc = input.charAt(i + 1); if (cc === '/' || cc === '*') { if (match = comment.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); c = input.charAt(i); } } } } if (c === '{' && !inString && !inParam) { level ++; chunk.push(c); } else if (c === '}' && !inString && !inParam) { level --; chunk.push(c); chunks[++j] = chunk = []; } else if (c === '(' && !inString && !inParam) { chunk.push(c); inParam = true; } else if (c === ')' && !inString && inParam) { chunk.push(c); inParam = false; } else { if (c === '"' || c === "'" || c === '`') { if (! inString) { inString = c; } else { inString = inString === c ? false : inString; } } chunk.push(c); } } if (level > 0) { throw { type: 'Syntax', message: "Missing closing `}`", filename: env.filename }; } return chunks.map(function (c) { return c.join('') });; })([[]]); // Start with the primary rule. // The whole syntax tree is held under a Ruleset node, // with the `root` property set to true, so no `{}` are // output. The callback is called when the input is parsed. root = new(tree.Ruleset)([], $(this.parsers.primary)); root.root = true; root.toCSS = (function (evaluate) { var line, lines, column; return function (options, variables) { var frames = []; options = options || {}; // // Allows setting variables with a hash, so: // // `{ color: new(tree.Color)('#f01') }` will become: // // new(tree.Rule)('@color', // new(tree.Value)([ // new(tree.Expression)([ // new(tree.Color)('#f01') // ]) // ]) // ) // if (typeof(variables) === 'object' && !Array.isArray(variables)) { variables = Object.keys(variables).map(function (k) { var value = variables[k]; if (! (value instanceof tree.Value)) { if (! (value instanceof tree.Expression)) { value = new(tree.Expression)([value]); } value = new(tree.Value)([value]); } return new(tree.Rule)('@' + k, value, false, 0); }); frames = [new(tree.Ruleset)(null, variables)]; } try { var css = evaluate.call(this, { frames: frames }) .toCSS([], { compress: options.compress || false }); } catch (e) { lines = input.split('\n'); line = getLine(e.index); for (var n = e.index, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } throw { type: e.type, message: e.message, filename: env.filename, index: e.index, line: typeof(line) === 'number' ? line + 1 : null, callLine: e.call && (getLine(e.call) + 1), callExtract: lines[getLine(e.call)], stack: e.stack, column: column, extract: [ lines[line - 1], lines[line], lines[line + 1] ] }; } if (options.yuicompress && less.mode === 'node') { return require('./cssmin').compressor.cssmin(css); } else if (options.compress) { return css.replace(/(\s)+/g, "$1"); } else { return css; } function getLine(index) { return index ? (input.slice(0, index).match(/\n/g) || "").length : null; } }; })(root.eval); // If `i` is smaller than the `input.length - 1`, // it means the parser wasn't able to parse the whole // string, so we've got a parsing error. // // We try to extract a \n delimited string, // showing the line where the parse error occured. // We split it up into two parts (the part which parsed, // and the part which didn't), so we can color them differently. if (i < input.length - 1) { i = furthest; lines = input.split('\n'); line = (input.slice(0, i).match(/\n/g) || "").length + 1; for (var n = i, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } error = { name: "ParseError", message: "Syntax Error on line " + line, index: i, filename: env.filename, line: line, column: column, extract: [ lines[line - 2], lines[line - 1], lines[line] ] }; } if (this.imports.queue.length > 0) { finish = function () { callback(error, root) }; } else { callback(error, root); } }, // // Here in, the parsing rules/functions // // The basic structure of the syntax tree generated is as follows: // // Ruleset -> Rule -> Value -> Expression -> Entity // // Here's some LESS code: // // .class { // color: #fff; // border: 1px solid #000; // width: @w + 4px; // > .child {...} // } // // And here's what the parse tree might look like: // // Ruleset (Selector '.class', [ // Rule ("color", Value ([Expression [Color #fff]])) // Rule ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]])) // Rule ("width", Value ([Expression [Operation "+" [Variable "@w"][Dimension 4px]]])) // Ruleset (Selector [Element '>', '.child'], [...]) // ]) // // In general, most rules will try to parse a token with the `$()` function, and if the return // value is truly, will return a new node, of the relevant type. Sometimes, we need to check // first, before parsing, that's when we use `peek()`. // parsers: { // // The `primary` rule is the *entry* and *exit* point of the parser. // The rules here can appear at any level of the parse tree. // // The recursive nature of the grammar is an interplay between the `block` // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule, // as represented by this simplified grammar: // // primary → (ruleset | rule)+ // ruleset → selector+ block // block → '{' primary '}' // // Only at one point is the primary rule not called from the // block rule: at the root level. // primary: function () { var node, root = []; while ((node = $(this.mixin.definition) || $(this.rule) || $(this.ruleset) || $(this.mixin.call) || $(this.comment) || $(this.directive)) || $(/^[\s\n]+/)) { node && root.push(node); } return root; }, // We create a Comment node for CSS comments `/* */`, // but keep the LeSS comments `//` silent, by just skipping // over them. comment: function () { var comment; if (input.charAt(i) !== '/') return; if (input.charAt(i + 1) === '/') { return new(tree.Comment)($(/^\/\/.*/), true); } else if (comment = $(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/)) { return new(tree.Comment)(comment); } }, // // Entities are tokens which can be found inside an Expression // entities: { // // A string, which supports escaping " and ' // // "milky way" 'he\'s the one!' // quoted: function () { var str, j = i, e; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '"' && input.charAt(j) !== "'") return; e && $('~'); if (str = $(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/)) { return new(tree.Quoted)(str[0], str[1] || str[2], e); } }, // // A catch-all word, such as: // // black border-collapse // keyword: function () { var k; if (k = $(/^[_A-Za-z-][_A-Za-z0-9-]*/)) { if (tree.colors.hasOwnProperty(k)) { // detect named color return new(tree.Color)(tree.colors[k].slice(1)); } else { return new(tree.Keyword)(k) } } }, // // A function call // // rgb(255, 0, 255) // // We also try to catch IE's `alpha()`, but let the `alpha` parser // deal with the details. // // The arguments are parsed with the `entities.arguments` parser. // call: function () { var name, args, index = i; if (! (name = /^([\w-]+|%|progid:[\w\.]+)\(/.exec(chunks[j]))) return; name = name[1].toLowerCase(); if (name === 'url') { return null } else { i += name.length } if (name === 'alpha') { return $(this.alpha) } $('('); // Parse the '(' and consume whitespace. args = $(this.entities.arguments); if (! $(')')) return; if (name) { return new(tree.Call)(name, args, index) } }, arguments: function () { var args = [], arg; while (arg = $(this.entities.assignment) || $(this.expression)) { args.push(arg); if (! $(',')) { break } } return args; }, literal: function () { return $(this.entities.dimension) || $(this.entities.color) || $(this.entities.quoted); }, // Assignments are argument entities for calls. // They are present in ie filter properties as shown below. // // filter: progid:DXImageTransform.Microsoft.Alpha( *opacity=50* ) // assignment: function () { var key, value; if ((key = $(/^\w+(?=\s?=)/i)) && $('=') && (value = $(this.entity))) { return new(tree.Assignment)(key, value); } }, // // Parse url() tokens // // We use a specific rule for urls, because they don't really behave like // standard function calls. The difference is that the argument doesn't have // to be enclosed within a string, so it can't be parsed as an Expression. // url: function () { var value; if (input.charAt(i) !== 'u' || !$(/^url\(/)) return; value = $(this.entities.quoted) || $(this.entities.variable) || $(this.entities.dataURI) || $(/^[-\w%@$\/.&=:;#+?~]+/) || ""; if (! $(')')) throw new(Error)("missing closing ) for url()"); return new(tree.URL)((value.value || value.data || value instanceof tree.Variable) ? value : new(tree.Anonymous)(value), imports.paths); }, dataURI: function () { var obj; if ($(/^data:/)) { obj = {}; obj.mime = $(/^[^\/]+\/[^,;)]+/) || ''; obj.charset = $(/^;\s*charset=[^,;)]+/) || ''; obj.base64 = $(/^;\s*base64/) || ''; obj.data = $(/^,\s*[^)]+/); if (obj.data) { return obj } } }, // // A Variable entity, such as `@fink`, in // // width: @fink + 2px // // We use a different parser for variable definitions, // see `parsers.variable`. // variable: function () { var name, index = i; if (input.charAt(i) === '@' && (name = $(/^@@?[\w-]+/))) { return new(tree.Variable)(name, index); } }, // // A Hexadecimal color // // #4F3C2F // // `rgb` and `hsl` colors are parsed through the `entities.call` parser. // color: function () { var rgb; if (input.charAt(i) === '#' && (rgb = $(/^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})/))) { return new(tree.Color)(rgb[1]); } }, // // A Dimension, that is, a number and a unit // // 0.5em 95% // dimension: function () { var value, c = input.charCodeAt(i); if ((c > 57 || c < 45) || c === 47) return; if (value = $(/^(-?\d*\.?\d+)(px|%|em|rem|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn)?/)) { return new(tree.Dimension)(value[1], value[2]); } }, // // JavaScript code to be evaluated // // `window.location.href` // javascript: function () { var str, j = i, e; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '`') { return } e && $('~'); if (str = $(/^`([^`]*)`/)) { return new(tree.JavaScript)(str[1], i, e); } } }, // // The variable part of a variable definition. Used in the `rule` parser // // @fink: // variable: function () { var name; if (input.charAt(i) === '@' && (name = $(/^(@[\w-]+)\s*:/))) { return name[1] } }, // // A font size/line-height shorthand // // small/12px // // We need to peek first, or we'll match on keywords and dimensions // shorthand: function () { var a, b; if (! peek(/^[@\w.%-]+\/[@\w.-]+/)) return; if ((a = $(this.entity)) && $('/') && (b = $(this.entity))) { return new(tree.Shorthand)(a, b); } }, // // Mixins // mixin: { // // A Mixin call, with an optional argument list // // #mixins > .square(#fff); // .rounded(4px, black); // .button; // // The `while` loop is there because mixins can be // namespaced, but we only support the child and descendant // selector for now. // call: function () { var elements = [], e, c, args, index = i, s = input.charAt(i); if (s !== '.' && s !== '#') { return } while (e = $(/^[#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/)) { elements.push(new(tree.Element)(c, e, i)); c = $('>'); } $('(') && (args = $(this.entities.arguments)) && $(')'); if (elements.length > 0 && ($(';') || peek('}'))) { return new(tree.mixin.Call)(elements, args, index); } }, // // A Mixin definition, with a list of parameters // // .rounded (@radius: 2px, @color) { // ... // } // // Until we have a finer grained state-machine, we have to // do a look-ahead, to make sure we don't have a mixin call. // See the `rule` function for more information. // // We start by matching `.rounded (`, and then proceed on to // the argument list, which has optional default values. // We store the parameters in `params`, with a `value` key, // if there is a value, such as in the case of `@radius`. // // Once we've got our params list, and a closing `)`, we parse // the `{...}` block. // definition: function () { var name, params = [], match, ruleset, param, value; if ((input.charAt(i) !== '.' && input.charAt(i) !== '#') || peek(/^[^{]*(;|})/)) return; if (match = $(/^([#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+)\s*\(/)) { name = match[1]; while (param = $(this.entities.variable) || $(this.entities.literal) || $(this.entities.keyword)) { // Variable if (param instanceof tree.Variable) { if ($(':')) { if (value = $(this.expression)) { params.push({ name: param.name, value: value }); } else { throw new(Error)("Expected value"); } } else { params.push({ name: param.name }); } } else { params.push({ value: param }); } if (! $(',')) { break } } if (! $(')')) throw new(Error)("Expected )"); ruleset = $(this.block); if (ruleset) { return new(tree.mixin.Definition)(name, params, ruleset); } } } }, // // Entities are the smallest recognized token, // and can be found inside a rule's value. // entity: function () { return $(this.entities.literal) || $(this.entities.variable) || $(this.entities.url) || $(this.entities.call) || $(this.entities.keyword) || $(this.entities.javascript) || $(this.comment); }, // // A Rule terminator. Note that we use `peek()` to check for '}', // because the `block` rule will be expecting it, but we still need to make sure // it's there, if ';' was ommitted. // end: function () { return $(';') || peek('}'); }, // // IE's alpha function // // alpha(opacity=88) // alpha: function () { var value; if (! $(/^\(opacity=/i)) return; if (value = $(/^\d+/) || $(this.entities.variable)) { if (! $(')')) throw new(Error)("missing closing ) for alpha()"); return new(tree.Alpha)(value); } }, // // A Selector Element // // div // + h1 // #socks // input[type="text"] // // Elements are the building blocks for Selectors, // they are made out of a `Combinator` (see combinator rule), // and an element name, such as a tag a class, or `*`. // element: function () { var e, t, c; c = $(this.combinator); e = $(/^(?:\d+\.\d+|\d+)%/) || $(/^(?:[.#]?|:*)(?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/) || $('*') || $(this.attribute) || $(/^\([^)@]+\)/); if (e) { return new(tree.Element)(c, e, i) } if (c.value && c.value.charAt(0) === '&') { return new(tree.Element)(c, null, i); } }, // // Combinators combine elements together, in a Selector. // // Because our parser isn't white-space sensitive, special care // has to be taken, when parsing the descendant combinator, ` `, // as it's an empty space. We have to check the previous character // in the input, to see if it's a ` ` character. More info on how // we deal with this in *combinator.js*. // combinator: function () { var match, c = input.charAt(i); if (c === '>' || c === '+' || c === '~') { i++; while (input.charAt(i) === ' ') { i++ } return new(tree.Combinator)(c); } else if (c === '&') { match = '&'; i++; if(input.charAt(i) === ' ') { match = '& '; } while (input.charAt(i) === ' ') { i++ } return new(tree.Combinator)(match); } else if (c === ':' && input.charAt(i + 1) === ':') { i += 2; while (input.charAt(i) === ' ') { i++ } return new(tree.Combinator)('::'); } else if (input.charAt(i - 1) === ' ') { return new(tree.Combinator)(" "); } else { return new(tree.Combinator)(null); } }, // // A CSS Selector // // .class > div + h1 // li a:hover // // Selectors are made out of one or more Elements, see above. // selector: function () { var sel, e, elements = [], c, match; while (e = $(this.element)) { c = input.charAt(i); elements.push(e) if (c === '{' || c === '}' || c === ';' || c === ',') { break } } if (elements.length > 0) { return new(tree.Selector)(elements) } }, tag: function () { return $(/^[a-zA-Z][a-zA-Z-]*[0-9]?/) || $('*'); }, attribute: function () { var attr = '', key, val, op; if (! $('[')) return; if (key = $(/^[a-zA-Z-]+/) || $(this.entities.quoted)) { if ((op = $(/^[|~*$^]?=/)) && (val = $(this.entities.quoted) || $(/^[\w-]+/))) { attr = [key, op, val.toCSS ? val.toCSS() : val].join(''); } else { attr = key } } if (! $(']')) return; if (attr) { return "[" + attr + "]" } }, // // The `block` rule is used by `ruleset` and `mixin.definition`. // It's a wrapper around the `primary` rule, with added `{}`. // block: function () { var content; if ($('{') && (content = $(this.primary)) && $('}')) { return content; } }, // // div, .class, body > p {...} // ruleset: function () { var selectors = [], s, rules, match; save(); while (s = $(this.selector)) { selectors.push(s); $(this.comment); if (! $(',')) { break } $(this.comment); } if (selectors.length > 0 && (rules = $(this.block))) { return new(tree.Ruleset)(selectors, rules); } else { // Backtrack furthest = i; restore(); } }, rule: function () { var name, value, c = input.charAt(i), important, match; save(); if (c === '.' || c === '#' || c === '&') { return } if (name = $(this.variable) || $(this.property)) { if ((name.charAt(0) != '@') && (match = /^([^@+\/'"*`(;{}-]*);/.exec(chunks[j]))) { i += match[0].length - 1; value = new(tree.Anonymous)(match[1]); } else if (name === "font") { value = $(this.font); } else { value = $(this.value); } important = $(this.important); if (value && $(this.end)) { return new(tree.Rule)(name, value, important, memo); } else { furthest = i; restore(); } } }, // // An @import directive // // @import "lib"; // // Depending on our environemnt, importing is done differently: // In the browser, it's an XHR request, in Node, it would be a // file-system operation. The function used for importing is // stored in `import`, which we pass to the Import constructor. // "import": function () { var path; if ($(/^@import\s+/) && (path = $(this.entities.quoted) || $(this.entities.url)) && $(';')) { return new(tree.Import)(path, imports); } }, // // A CSS Directive // // @charset "utf-8"; // directive: function () { var name, value, rules, types; if (input.charAt(i) !== '@') return; if (value = $(this['import'])) { return value; } else if (name = $(/^@media|@page/) || $(/^@(?:-webkit-|-moz-|-o-|-ms-)[a-z0-9-]+/) || $('keyframes')) { types = ($(/^[^{]+/) || '').trim(); if (rules = $(this.block)) { return new(tree.Directive)(name + " " + types, rules); } } else if (name = $(/^@[-a-z]+/)) { if (name === '@font-face') { if (rules = $(this.block)) { return new(tree.Directive)(name, rules); } } else if ((value = $(this.entity)) && $(';')) { return new(tree.Directive)(name, value); } } }, font: function () { var value = [], expression = [], weight, shorthand, font, e; while (e = $(this.shorthand) || $(this.entity)) { expression.push(e); } value.push(new(tree.Expression)(expression)); if ($(',')) { while (e = $(this.expression)) { value.push(e); if (! $(',')) { break } } } return new(tree.Value)(value); }, // // A Value is a comma-delimited list of Expressions // // font-family: Baskerville, Georgia, serif; // // In a Rule, a Value represents everything after the `:`, // and before the `;`. // value: function () { var e, expressions = [], important; while (e = $(this.expression)) { expressions.push(e); if (! $(',')) { break } } if (expressions.length > 0) { return new(tree.Value)(expressions); } }, important: function () { if (input.charAt(i) === '!') { return $(/^! *important/); } }, sub: function () { var e; if ($('(') && (e = $(this.expression)) && $(')')) { return e; } }, multiplication: function () { var m, a, op, operation; if (m = $(this.operand)) { while (!peek(/^\/\*/) && (op = ($('/') || $('*'))) && (a = $(this.operand))) { operation = new(tree.Operation)(op, [operation || m, a]); } return operation || m; } }, addition: function () { var m, a, op, operation; if (m = $(this.multiplication)) { while ((op = $(/^[-+]\s+/) || (input.charAt(i - 1) != ' ' && ($('+') || $('-')))) && (a = $(this.multiplication))) { operation = new(tree.Operation)(op, [operation || m, a]); } return operation || m; } }, // // An operand is anything that can be part of an operation, // such as a Color, or a Variable // operand: function () { var negate, p = input.charAt(i + 1); if (input.charAt(i) === '-' && (p === '@' || p === '(')) { negate = $('-') } var o = $(this.sub) || $(this.entities.dimension) || $(this.entities.color) || $(this.entities.variable) || $(this.entities.call); return negate ? new(tree.Operation)('*', [new(tree.Dimension)(-1), o]) : o; }, // // Expressions either represent mathematical operations, // or white-space delimited Entities. // // 1px solid black // @var * 2 // expression: function () { var e, delim, entities = [], d; while (e = $(this.addition) || $(this.entity)) { entities.push(e); } if (entities.length > 0) { return new(tree.Expression)(entities); } }, property: function () { var name; if (name = $(/^(\*?-?[-a-z_0-9]+)\s*:/)) { return name[1]; } } } }; }; if (less.mode === 'browser' || less.mode === 'rhino') { // // Used by `@import` directives // less.Parser.importer = function (path, paths, callback, env) { if (path.charAt(0) !== '/' && paths.length > 0) { path = paths[0] + path; } // We pass `true` as 3rd argument, to force the reload of the import. // This is so we can get the syntax tree as opposed to just the CSS output, // as we need this to evaluate the current stylesheet. loadStyleSheet({ href: path, title: path, type: env.mime }, callback, true); }; } (function (tree) { tree.functions = { rgb: function (r, g, b) { return this.rgba(r, g, b, 1.0); }, rgba: function (r, g, b, a) { var rgb = [r, g, b].map(function (c) { return number(c) }), a = number(a); return new(tree.Color)(rgb, a); }, hsl: function (h, s, l) { return this.hsla(h, s, l, 1.0); }, hsla: function (h, s, l, a) { h = (number(h) % 360) / 360; s = number(s); l = number(l); a = number(a); var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s; var m1 = l * 2 - m2; return this.rgba(hue(h + 1/3) * 255, hue(h) * 255, hue(h - 1/3) * 255, a); function hue(h) { h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h); if (h * 6 < 1) return m1 + (m2 - m1) * h * 6; else if (h * 2 < 1) return m2; else if (h * 3 < 2) return m1 + (m2 - m1) * (2/3 - h) * 6; else return m1; } }, hue: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().h)); }, saturation: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().s * 100), '%'); }, lightness: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().l * 100), '%'); }, alpha: function (color) { return new(tree.Dimension)(color.toHSL().a); }, saturate: function (color, amount) { var hsl = color.toHSL(); hsl.s += amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, desaturate: function (color, amount) { var hsl = color.toHSL(); hsl.s -= amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, lighten: function (color, amount) { var hsl = color.toHSL(); hsl.l += amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, darken: function (color, amount) { var hsl = color.toHSL(); hsl.l -= amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, fadein: function (color, amount) { var hsl = color.toHSL(); hsl.a += amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, fadeout: function (color, amount) { var hsl = color.toHSL(); hsl.a -= amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, fade: function (color, amount) { var hsl = color.toHSL(); hsl.a = amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, spin: function (color, amount) { var hsl = color.toHSL(); var hue = (hsl.h + amount.value) % 360; hsl.h = hue < 0 ? 360 + hue : hue; return hsla(hsl); }, // // Copyright (c) 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein // http://sass-lang.com // mix: function (color1, color2, weight) { var p = weight.value / 100.0; var w = p * 2 - 1; var a = color1.toHSL().a - color2.toHSL().a; var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0; var w2 = 1 - w1; var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2, color1.rgb[1] * w1 + color2.rgb[1] * w2, color1.rgb[2] * w1 + color2.rgb[2] * w2]; var alpha = color1.alpha * p + color2.alpha * (1 - p); return new(tree.Color)(rgb, alpha); }, greyscale: function (color) { return this.desaturate(color, new(tree.Dimension)(100)); }, e: function (str) { return new(tree.Anonymous)(str instanceof tree.JavaScript ? str.evaluated : str); }, escape: function (str) { return new(tree.Anonymous)(encodeURI(str.value).replace(/=/g, "%3D").replace(/:/g, "%3A").replace(/#/g, "%23").replace(/;/g, "%3B").replace(/\(/g, "%28").replace(/\)/g, "%29")); }, '%': function (quoted /* arg, arg, ...*/) { var args = Array.prototype.slice.call(arguments, 1), str = quoted.value; for (var i = 0; i < args.length; i++) { str = str.replace(/%[sda]/i, function(token) { var value = token.match(/s/i) ? args[i].value : args[i].toCSS(); return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value; }); } str = str.replace(/%%/g, '%'); return new(tree.Quoted)('"' + str + '"', str); }, round: function (n) { return this._math('round', n); }, ceil: function (n) { return this._math('ceil', n); }, floor: function (n) { return this._math('floor', n); }, _math: function (fn, n) { if (n instanceof tree.Dimension) { return new(tree.Dimension)(Math[fn](number(n)), n.unit); } else if (typeof(n) === 'number') { return Math[fn](n); } else { throw { error: "RuntimeError", message: "math functions take numbers as parameters" }; } }, argb: function (color) { return new(tree.Anonymous)(color.toARGB()); } }; function hsla(hsla) { return tree.functions.hsla(hsla.h, hsla.s, hsla.l, hsla.a); } function number(n) { if (n instanceof tree.Dimension) { return parseFloat(n.unit == '%' ? n.value / 100 : n.value); } else if (typeof(n) === 'number') { return n; } else { throw { error: "RuntimeError", message: "color functions take numbers as parameters" }; } } function clamp(val) { return Math.min(1, Math.max(0, val)); } })(require('./tree')); (function (tree) { tree.colors = { 'aliceblue':'#f0f8ff', 'antiquewhite':'#faebd7', 'aqua':'#00ffff', 'aquamarine':'#7fffd4', 'azure':'#f0ffff', 'beige':'#f5f5dc', 'bisque':'#ffe4c4', 'black':'#000000', 'blanchedalmond':'#ffebcd', 'blue':'#0000ff', 'blueviolet':'#8a2be2', 'brown':'#a52a2a', 'burlywood':'#deb887', 'cadetblue':'#5f9ea0', 'chartreuse':'#7fff00', 'chocolate':'#d2691e', 'coral':'#ff7f50', 'cornflowerblue':'#6495ed', 'cornsilk':'#fff8dc', 'crimson':'#dc143c', 'cyan':'#00ffff', 'darkblue':'#00008b', 'darkcyan':'#008b8b', 'darkgoldenrod':'#b8860b', 'darkgray':'#a9a9a9', 'darkgrey':'#a9a9a9', 'darkgreen':'#006400', 'darkkhaki':'#bdb76b', 'darkmagenta':'#8b008b', 'darkolivegreen':'#556b2f', 'darkorange':'#ff8c00', 'darkorchid':'#9932cc', 'darkred':'#8b0000', 'darksalmon':'#e9967a', 'darkseagreen':'#8fbc8f', 'darkslateblue':'#483d8b', 'darkslategray':'#2f4f4f', 'darkslategrey':'#2f4f4f', 'darkturquoise':'#00ced1', 'darkviolet':'#9400d3', 'deeppink':'#ff1493', 'deepskyblue':'#00bfff', 'dimgray':'#696969', 'dimgrey':'#696969', 'dodgerblue':'#1e90ff', 'firebrick':'#b22222', 'floralwhite':'#fffaf0', 'forestgreen':'#228b22', 'fuchsia':'#ff00ff', 'gainsboro':'#dcdcdc', 'ghostwhite':'#f8f8ff', 'gold':'#ffd700', 'goldenrod':'#daa520', 'gray':'#808080', 'grey':'#808080', 'green':'#008000', 'greenyellow':'#adff2f', 'honeydew':'#f0fff0', 'hotpink':'#ff69b4', 'indianred':'#cd5c5c', 'indigo':'#4b0082', 'ivory':'#fffff0', 'khaki':'#f0e68c', 'lavender':'#e6e6fa', 'lavenderblush':'#fff0f5', 'lawngreen':'#7cfc00', 'lemonchiffon':'#fffacd', 'lightblue':'#add8e6', 'lightcoral':'#f08080', 'lightcyan':'#e0ffff', 'lightgoldenrodyellow':'#fafad2', 'lightgray':'#d3d3d3', 'lightgrey':'#d3d3d3', 'lightgreen':'#90ee90', 'lightpink':'#ffb6c1', 'lightsalmon':'#ffa07a', 'lightseagreen':'#20b2aa', 'lightskyblue':'#87cefa', 'lightslategray':'#778899', 'lightslategrey':'#778899', 'lightsteelblue':'#b0c4de', 'lightyellow':'#ffffe0', 'lime':'#00ff00', 'limegreen':'#32cd32', 'linen':'#faf0e6', 'magenta':'#ff00ff', 'maroon':'#800000', 'mediumaquamarine':'#66cdaa', 'mediumblue':'#0000cd', 'mediumorchid':'#ba55d3', 'mediumpurple':'#9370d8', 'mediumseagreen':'#3cb371', 'mediumslateblue':'#7b68ee', 'mediumspringgreen':'#00fa9a', 'mediumturquoise':'#48d1cc', 'mediumvioletred':'#c71585', 'midnightblue':'#191970', 'mintcream':'#f5fffa', 'mistyrose':'#ffe4e1', 'moccasin':'#ffe4b5', 'navajowhite':'#ffdead', 'navy':'#000080', 'oldlace':'#fdf5e6', 'olive':'#808000', 'olivedrab':'#6b8e23', 'orange':'#ffa500', 'orangered':'#ff4500', 'orchid':'#da70d6', 'palegoldenrod':'#eee8aa', 'palegreen':'#98fb98', 'paleturquoise':'#afeeee', 'palevioletred':'#d87093', 'papayawhip':'#ffefd5', 'peachpuff':'#ffdab9', 'peru':'#cd853f', 'pink':'#ffc0cb', 'plum':'#dda0dd', 'powderblue':'#b0e0e6', 'purple':'#800080', 'red':'#ff0000', 'rosybrown':'#bc8f8f', 'royalblue':'#4169e1', 'saddlebrown':'#8b4513', 'salmon':'#fa8072', 'sandybrown':'#f4a460', 'seagreen':'#2e8b57', 'seashell':'#fff5ee', 'sienna':'#a0522d', 'silver':'#c0c0c0', 'skyblue':'#87ceeb', 'slateblue':'#6a5acd', 'slategray':'#708090', 'slategrey':'#708090', 'snow':'#fffafa', 'springgreen':'#00ff7f', 'steelblue':'#4682b4', 'tan':'#d2b48c', 'teal':'#008080', 'thistle':'#d8bfd8', 'tomato':'#ff6347', 'turquoise':'#40e0d0', 'violet':'#ee82ee', 'wheat':'#f5deb3', 'white':'#ffffff', 'whitesmoke':'#f5f5f5', 'yellow':'#ffff00', 'yellowgreen':'#9acd32' }; })(require('./tree')); (function (tree) { tree.Alpha = function (val) { this.value = val; }; tree.Alpha.prototype = { toCSS: function () { return "alpha(opacity=" + (this.value.toCSS ? this.value.toCSS() : this.value) + ")"; }, eval: function (env) { if (this.value.eval) { this.value = this.value.eval(env) } return this; } }; })(require('../tree')); (function (tree) { tree.Anonymous = function (string) { this.value = string.value || string; }; tree.Anonymous.prototype = { toCSS: function () { return this.value; }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.Assignment = function (key, val) { this.key = key; this.value = val; }; tree.Assignment.prototype = { toCSS: function () { return this.key + '=' + (this.value.toCSS ? this.value.toCSS() : this.value); }, eval: function (env) { if (this.value.eval) { this.value = this.value.eval(env) } return this; } }; })(require('../tree'));(function (tree) { // // A function call node. // tree.Call = function (name, args, index) { this.name = name; this.args = args; this.index = index; }; tree.Call.prototype = { // // When evaluating a function call, // we either find the function in `tree.functions` [1], // in which case we call it, passing the evaluated arguments, // or we simply print it out as it appeared originally [2]. // // The *functions.js* file contains the built-in functions. // // The reason why we evaluate the arguments, is in the case where // we try to pass a variable to a function, like: `saturate(@color)`. // The function should receive the value, not the variable. // eval: function (env) { var args = this.args.map(function (a) { return a.eval(env) }); if (this.name in tree.functions) { // 1. try { return tree.functions[this.name].apply(tree.functions, args); } catch (e) { throw { message: "error evaluating function `" + this.name + "`", index: this.index }; } } else { // 2. return new(tree.Anonymous)(this.name + "(" + args.map(function (a) { return a.toCSS() }).join(', ') + ")"); } }, toCSS: function (env) { return this.eval(env).toCSS(); } }; })(require('../tree')); (function (tree) { // // RGB Colors - #ff0014, #eee // tree.Color = function (rgb, a) { // // The end goal here, is to parse the arguments // into an integer triplet, such as `128, 255, 0` // // This facilitates operations and conversions. // if (Array.isArray(rgb)) { this.rgb = rgb; } else if (rgb.length == 6) { this.rgb = rgb.match(/.{2}/g).map(function (c) { return parseInt(c, 16); }); } else { this.rgb = rgb.split('').map(function (c) { return parseInt(c + c, 16); }); } this.alpha = typeof(a) === 'number' ? a : 1; }; tree.Color.prototype = { eval: function () { return this }, // // If we have some transparency, the only way to represent it // is via `rgba`. Otherwise, we use the hex representation, // which has better compatibility with older browsers. // Values are capped between `0` and `255`, rounded and zero-padded. // toCSS: function () { if (this.alpha < 1.0) { return "rgba(" + this.rgb.map(function (c) { return Math.round(c); }).concat(this.alpha).join(', ') + ")"; } else { return '#' + this.rgb.map(function (i) { i = Math.round(i); i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16); return i.length === 1 ? '0' + i : i; }).join(''); } }, // // Operations have to be done per-channel, if not, // channels will spill onto each other. Once we have // our result, in the form of an integer triplet, // we create a new Color node to hold the result. // operate: function (op, other) { var result = []; if (! (other instanceof tree.Color)) { other = other.toColor(); } for (var c = 0; c < 3; c++) { result[c] = tree.operate(op, this.rgb[c], other.rgb[c]); } return new(tree.Color)(result, this.alpha + other.alpha); }, toHSL: function () { var r = this.rgb[0] / 255, g = this.rgb[1] / 255, b = this.rgb[2] / 255, a = this.alpha; var max = Math.max(r, g, b), min = Math.min(r, g, b); var h, s, l = (max + min) / 2, d = max - min; if (max === min) { h = s = 0; } else { s = l > 0.5 ? d / (2 - max - min) : d / (max + min); switch (max) { case r: h = (g - b) / d + (g < b ? 6 : 0); break; case g: h = (b - r) / d + 2; break; case b: h = (r - g) / d + 4; break; } h /= 6; } return { h: h * 360, s: s, l: l, a: a }; }, toARGB: function () { var argb = [Math.round(this.alpha * 255)].concat(this.rgb); return '#' + argb.map(function (i) { i = Math.round(i); i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16); return i.length === 1 ? '0' + i : i; }).join(''); } }; })(require('../tree')); (function (tree) { tree.Comment = function (value, silent) { this.value = value; this.silent = !!silent; }; tree.Comment.prototype = { toCSS: function (env) { return env.compress ? '' : this.value; }, eval: function () { return this } }; })(require('../tree')); (function (tree) { // // A number with a unit // tree.Dimension = function (value, unit) { this.value = parseFloat(value); this.unit = unit || null; }; tree.Dimension.prototype = { eval: function () { return this }, toColor: function () { return new(tree.Color)([this.value, this.value, this.value]); }, toCSS: function () { var css = this.value + this.unit; return css; }, // In an operation between two Dimensions, // we default to the first Dimension's unit, // so `1px + 2em` will yield `3px`. // In the future, we could implement some unit // conversions such that `100cm + 10mm` would yield // `101cm`. operate: function (op, other) { return new(tree.Dimension) (tree.operate(op, this.value, other.value), this.unit || other.unit); } }; })(require('../tree')); (function (tree) { tree.Directive = function (name, value) { this.name = name; if (Array.isArray(value)) { this.ruleset = new(tree.Ruleset)([], value); } else { this.value = value; } }; tree.Directive.prototype = { toCSS: function (ctx, env) { if (this.ruleset) { this.ruleset.root = true; return this.name + (env.compress ? '{' : ' {\n ') + this.ruleset.toCSS(ctx, env).trim().replace(/\n/g, '\n ') + (env.compress ? '}': '\n}\n'); } else { return this.name + ' ' + this.value.toCSS() + ';\n'; } }, eval: function (env) { env.frames.unshift(this); this.ruleset = this.ruleset && this.ruleset.eval(env); env.frames.shift(); return this; }, variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) }, find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) }, rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) } }; })(require('../tree')); (function (tree) { tree.Element = function (combinator, value, index) { this.combinator = combinator instanceof tree.Combinator ? combinator : new(tree.Combinator)(combinator); this.value = value ? value.trim() : ""; this.index = index; }; tree.Element.prototype.toCSS = function (env) { return this.combinator.toCSS(env || {}) + this.value; }; tree.Combinator = function (value) { if (value === ' ') { this.value = ' '; } else if (value === '& ') { this.value = '& '; } else { this.value = value ? value.trim() : ""; } }; tree.Combinator.prototype.toCSS = function (env) { return { '' : '', ' ' : ' ', '&' : '', '& ' : ' ', ':' : ' :', '::': '::', '+' : env.compress ? '+' : ' + ', '~' : env.compress ? '~' : ' ~ ', '>' : env.compress ? '>' : ' > ' }[this.value]; }; })(require('../tree')); (function (tree) { tree.Expression = function (value) { this.value = value }; tree.Expression.prototype = { eval: function (env) { if (this.value.length > 1) { return new(tree.Expression)(this.value.map(function (e) { return e.eval(env); })); } else if (this.value.length === 1) { return this.value[0].eval(env); } else { return this; } }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS(env); }).join(' '); } }; })(require('../tree')); (function (tree) { // // CSS @import node // // The general strategy here is that we don't want to wait // for the parsing to be completed, before we start importing // the file. That's because in the context of a browser, // most of the time will be spent waiting for the server to respond. // // On creation, we push the import path to our import queue, though // `import,push`, we also pass it a callback, which it'll call once // the file has been fetched, and parsed. // tree.Import = function (path, imports) { var that = this; this._path = path; // The '.less' extension is optional if (path instanceof tree.Quoted) { this.path = /\.(le?|c)ss(\?.*)?$/.test(path.value) ? path.value : path.value + '.less'; } else { this.path = path.value.value || path.value; } this.css = /css(\?.*)?$/.test(this.path); // Only pre-compile .less files if (! this.css) { imports.push(this.path, function (root) { if (! root) { throw new(Error)("Error parsing " + that.path); } that.root = root; }); } }; // // The actual import node doesn't return anything, when converted to CSS. // The reason is that it's used at the evaluation stage, so that the rules // it imports can be treated like any other rules. // // In `eval`, we make sure all Import nodes get evaluated, recursively, so // we end up with a flat structure, which can easily be imported in the parent // ruleset. // tree.Import.prototype = { toCSS: function () { if (this.css) { return "@import " + this._path.toCSS() + ';\n'; } else { return ""; } }, eval: function (env) { var ruleset; if (this.css) { return this; } else { ruleset = new(tree.Ruleset)(null, this.root.rules.slice(0)); for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.Import) { Array.prototype .splice .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env))); } } return ruleset.rules; } } }; })(require('../tree')); (function (tree) { tree.JavaScript = function (string, index, escaped) { this.escaped = escaped; this.expression = string; this.index = index; }; tree.JavaScript.prototype = { eval: function (env) { var result, that = this, context = {}; var expression = this.expression.replace(/@\{([\w-]+)\}/g, function (_, name) { return tree.jsify(new(tree.Variable)('@' + name, that.index).eval(env)); }); try { expression = new(Function)('return (' + expression + ')'); } catch (e) { throw { message: "JavaScript evaluation error: `" + expression + "`" , index: this.index }; } for (var k in env.frames[0].variables()) { context[k.slice(1)] = { value: env.frames[0].variables()[k].value, toJS: function () { return this.value.eval(env).toCSS(); } }; } try { result = expression.call(context); } catch (e) { throw { message: "JavaScript evaluation error: '" + e.name + ': ' + e.message + "'" , index: this.index }; } if (typeof(result) === 'string') { return new(tree.Quoted)('"' + result + '"', result, this.escaped, this.index); } else if (Array.isArray(result)) { return new(tree.Anonymous)(result.join(', ')); } else { return new(tree.Anonymous)(result); } } }; })(require('../tree')); (function (tree) { tree.Keyword = function (value) { this.value = value }; tree.Keyword.prototype = { eval: function () { return this }, toCSS: function () { return this.value } }; })(require('../tree')); (function (tree) { tree.mixin = {}; tree.mixin.Call = function (elements, args, index) { this.selector = new(tree.Selector)(elements); this.arguments = args; this.index = index; }; tree.mixin.Call.prototype = { eval: function (env) { var mixins, args, rules = [], match = false; for (var i = 0; i < env.frames.length; i++) { if ((mixins = env.frames[i].find(this.selector)).length > 0) { args = this.arguments && this.arguments.map(function (a) { return a.eval(env) }); for (var m = 0; m < mixins.length; m++) { if (mixins[m].match(args, env)) { try { Array.prototype.push.apply( rules, mixins[m].eval(env, this.arguments).rules); match = true; } catch (e) { throw { message: e.message, index: e.index, stack: e.stack, call: this.index }; } } } if (match) { return rules; } else { throw { message: 'No matching definition was found for `' + this.selector.toCSS().trim() + '(' + this.arguments.map(function (a) { return a.toCSS(); }).join(', ') + ")`", index: this.index }; } } } throw { message: this.selector.toCSS().trim() + " is undefined", index: this.index }; } }; tree.mixin.Definition = function (name, params, rules) { this.name = name; this.selectors = [new(tree.Selector)([new(tree.Element)(null, name)])]; this.params = params; this.arity = params.length; this.rules = rules; this._lookups = {}; this.required = params.reduce(function (count, p) { if (!p.name || (p.name && !p.value)) { return count + 1 } else { return count } }, 0); this.parent = tree.Ruleset.prototype; this.frames = []; }; tree.mixin.Definition.prototype = { toCSS: function () { return "" }, variable: function (name) { return this.parent.variable.call(this, name) }, variables: function () { return this.parent.variables.call(this) }, find: function () { return this.parent.find.apply(this, arguments) }, rulesets: function () { return this.parent.rulesets.apply(this) }, eval: function (env, args) { var frame = new(tree.Ruleset)(null, []), context, _arguments = []; for (var i = 0, val; i < this.params.length; i++) { if (this.params[i].name) { if (val = (args && args[i]) || this.params[i].value) { frame.rules.unshift(new(tree.Rule)(this.params[i].name, val.eval(env))); } else { throw { message: "wrong number of arguments for " + this.name + ' (' + args.length + ' for ' + this.arity + ')' }; } } } for (var i = 0; i < Math.max(this.params.length, args && args.length); i++) { _arguments.push(args[i] || this.params[i].value); } frame.rules.unshift(new(tree.Rule)('@arguments', new(tree.Expression)(_arguments).eval(env))); return new(tree.Ruleset)(null, this.rules.slice(0)).eval({ frames: [this, frame].concat(this.frames, env.frames) }); }, match: function (args, env) { var argsLength = (args && args.length) || 0, len; if (argsLength < this.required) { return false } if ((this.required > 0) && (argsLength > this.params.length)) { return false } len = Math.min(argsLength, this.arity); for (var i = 0; i < len; i++) { if (!this.params[i].name) { if (args[i].eval(env).toCSS() != this.params[i].value.eval(env).toCSS()) { return false; } } } return true; } }; })(require('../tree')); (function (tree) { tree.Operation = function (op, operands) { this.op = op.trim(); this.operands = operands; }; tree.Operation.prototype.eval = function (env) { var a = this.operands[0].eval(env), b = this.operands[1].eval(env), temp; if (a instanceof tree.Dimension && b instanceof tree.Color) { if (this.op === '*' || this.op === '+') { temp = b, b = a, a = temp; } else { throw { name: "OperationError", message: "Can't substract or divide a color from a number" }; } } return a.operate(this.op, b); }; tree.operate = function (op, a, b) { switch (op) { case '+': return a + b; case '-': return a - b; case '*': return a * b; case '/': return a / b; } }; })(require('../tree')); (function (tree) { tree.Quoted = function (str, content, escaped, i) { this.escaped = escaped; this.value = content || ''; this.quote = str.charAt(0); this.index = i; }; tree.Quoted.prototype = { toCSS: function () { if (this.escaped) { return this.value; } else { return this.quote + this.value + this.quote; } }, eval: function (env) { var that = this; var value = this.value.replace(/`([^`]+)`/g, function (_, exp) { return new(tree.JavaScript)(exp, that.index, true).eval(env).value; }).replace(/@\{([\w-]+)\}/g, function (_, name) { var v = new(tree.Variable)('@' + name, that.index).eval(env); return v.value || v.toCSS(); }); return new(tree.Quoted)(this.quote + value + this.quote, value, this.escaped, this.index); } }; })(require('../tree')); (function (tree) { tree.Rule = function (name, value, important, index) { this.name = name; this.value = (value instanceof tree.Value) ? value : new(tree.Value)([value]); this.important = important ? ' ' + important.trim() : ''; this.index = index; if (name.charAt(0) === '@') { this.variable = true; } else { this.variable = false } }; tree.Rule.prototype.toCSS = function (env) { if (this.variable) { return "" } else { return this.name + (env.compress ? ':' : ': ') + this.value.toCSS(env) + this.important + ";"; } }; tree.Rule.prototype.eval = function (context) { return new(tree.Rule)(this.name, this.value.eval(context), this.important, this.index); }; tree.Shorthand = function (a, b) { this.a = a; this.b = b; }; tree.Shorthand.prototype = { toCSS: function (env) { return this.a.toCSS(env) + "/" + this.b.toCSS(env); }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.Ruleset = function (selectors, rules) { this.selectors = selectors; this.rules = rules; this._lookups = {}; }; tree.Ruleset.prototype = { eval: function (env) { var ruleset = new(tree.Ruleset)(this.selectors, this.rules.slice(0)); ruleset.root = this.root; // push the current ruleset to the frames stack env.frames.unshift(ruleset); // Evaluate imports if (ruleset.root) { for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.Import) { Array.prototype.splice .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env))); } } } // Store the frames around mixin definitions, // so they can be evaluated like closures when the time comes. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Definition) { ruleset.rules[i].frames = env.frames.slice(0); } } // Evaluate mixin calls. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Call) { Array.prototype.splice .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env))); } } // Evaluate everything else for (var i = 0, rule; i < ruleset.rules.length; i++) { rule = ruleset.rules[i]; if (! (rule instanceof tree.mixin.Definition)) { ruleset.rules[i] = rule.eval ? rule.eval(env) : rule; } } // Pop the stack env.frames.shift(); return ruleset; }, match: function (args) { return !args || args.length === 0; }, variables: function () { if (this._variables) { return this._variables } else { return this._variables = this.rules.reduce(function (hash, r) { if (r instanceof tree.Rule && r.variable === true) { hash[r.name] = r; } return hash; }, {}); } }, variable: function (name) { return this.variables()[name]; }, rulesets: function () { if (this._rulesets) { return this._rulesets } else { return this._rulesets = this.rules.filter(function (r) { return (r instanceof tree.Ruleset) || (r instanceof tree.mixin.Definition); }); } }, find: function (selector, self) { self = self || this; var rules = [], rule, match, key = selector.toCSS(); if (key in this._lookups) { return this._lookups[key] } this.rulesets().forEach(function (rule) { if (rule !== self) { for (var j = 0; j < rule.selectors.length; j++) { if (match = selector.match(rule.selectors[j])) { if (selector.elements.length > rule.selectors[j].elements.length) { Array.prototype.push.apply(rules, rule.find( new(tree.Selector)(selector.elements.slice(1)), self)); } else { rules.push(rule); } break; } } } }); return this._lookups[key] = rules; }, // // Entry point for code generation // // `context` holds an array of arrays. // toCSS: function (context, env) { var css = [], // The CSS output rules = [], // node.Rule instances rulesets = [], // node.Ruleset instances paths = [], // Current selectors selector, // The fully rendered selector rule; if (! this.root) { if (context.length === 0) { paths = this.selectors.map(function (s) { return [s] }); } else { this.joinSelectors( paths, context, this.selectors ); } } // Compile rules and rulesets for (var i = 0; i < this.rules.length; i++) { rule = this.rules[i]; if (rule.rules || (rule instanceof tree.Directive)) { rulesets.push(rule.toCSS(paths, env)); } else if (rule instanceof tree.Comment) { if (!rule.silent) { if (this.root) { rulesets.push(rule.toCSS(env)); } else { rules.push(rule.toCSS(env)); } } } else { if (rule.toCSS && !rule.variable) { rules.push(rule.toCSS(env)); } else if (rule.value && !rule.variable) { rules.push(rule.value.toString()); } } } rulesets = rulesets.join(''); // If this is the root node, we don't render // a selector, or {}. // Otherwise, only output if this ruleset has rules. if (this.root) { css.push(rules.join(env.compress ? '' : '\n')); } else { if (rules.length > 0) { selector = paths.map(function (p) { return p.map(function (s) { return s.toCSS(env); }).join('').trim(); }).join(env.compress ? ',' : (paths.length > 3 ? ',\n' : ', ')); css.push(selector, (env.compress ? '{' : ' {\n ') + rules.join(env.compress ? '' : '\n ') + (env.compress ? '}' : '\n}\n')); } } css.push(rulesets); return css.join('') + (env.compress ? '\n' : ''); }, joinSelectors: function (paths, context, selectors) { for (var s = 0; s < selectors.length; s++) { this.joinSelector(paths, context, selectors[s]); } }, joinSelector: function (paths, context, selector) { var before = [], after = [], beforeElements = [], afterElements = [], hasParentSelector = false, el; for (var i = 0; i < selector.elements.length; i++) { el = selector.elements[i]; if (el.combinator.value.charAt(0) === '&') { hasParentSelector = true; } if (hasParentSelector) afterElements.push(el); else beforeElements.push(el); } if (! hasParentSelector) { afterElements = beforeElements; beforeElements = []; } if (beforeElements.length > 0) { before.push(new(tree.Selector)(beforeElements)); } if (afterElements.length > 0) { after.push(new(tree.Selector)(afterElements)); } for (var c = 0; c < context.length; c++) { paths.push(before.concat(context[c]).concat(after)); } } }; })(require('../tree')); (function (tree) { tree.Selector = function (elements) { this.elements = elements; if (this.elements[0].combinator.value === "") { this.elements[0].combinator.value = ' '; } }; tree.Selector.prototype.match = function (other) { var len = this.elements.length, olen = other.elements.length, max = Math.min(len, olen); if (len < olen) { return false; } else { for (var i = 0; i < max; i++) { if (this.elements[i].value !== other.elements[i].value) { return false; } } } return true; }; tree.Selector.prototype.toCSS = function (env) { if (this._css) { return this._css } return this._css = this.elements.map(function (e) { if (typeof(e) === 'string') { return ' ' + e.trim(); } else { return e.toCSS(env); } }).join(''); }; })(require('../tree')); (function (tree) { tree.URL = function (val, paths) { if (val.data) { this.attrs = val; } else { // Add the base path if the URL is relative and we are in the browser if (typeof(window) !== 'undefined' && !/^(?:https?:\/\/|file:\/\/|data:|\/)/.test(val.value) && paths.length > 0) { val.value = paths[0] + (val.value.charAt(0) === '/' ? val.value.slice(1) : val.value); } this.value = val; this.paths = paths; } }; tree.URL.prototype = { toCSS: function () { return "url(" + (this.attrs ? 'data:' + this.attrs.mime + this.attrs.charset + this.attrs.base64 + this.attrs.data : this.value.toCSS()) + ")"; }, eval: function (ctx) { return this.attrs ? this : new(tree.URL)(this.value.eval(ctx), this.paths); } }; })(require('../tree')); (function (tree) { tree.Value = function (value) { this.value = value; this.is = 'value'; }; tree.Value.prototype = { eval: function (env) { if (this.value.length === 1) { return this.value[0].eval(env); } else { return new(tree.Value)(this.value.map(function (v) { return v.eval(env); })); } }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS(env); }).join(env.compress ? ',' : ', '); } }; })(require('../tree')); (function (tree) { tree.Variable = function (name, index) { this.name = name, this.index = index }; tree.Variable.prototype = { eval: function (env) { var variable, v, name = this.name; if (name.indexOf('@@') == 0) { name = '@' + new(tree.Variable)(name.slice(1)).eval(env).value; } if (variable = tree.find(env.frames, function (frame) { if (v = frame.variable(name)) { return v.value.eval(env); } })) { return variable } else { throw { message: "variable " + name + " is undefined", index: this.index }; } } }; })(require('../tree')); require('./tree').find = function (obj, fun) { for (var i = 0, r; i < obj.length; i++) { if (r = fun.call(obj, obj[i])) { return r } } return null; }; require('./tree').jsify = function (obj) { if (Array.isArray(obj.value) && (obj.value.length > 1)) { return '[' + obj.value.map(function (v) { return v.toCSS(false) }).join(', ') + ']'; } else { return obj.toCSS(false); } }; // // browser.js - client-side engine // var isFileProtocol = (location.protocol === 'file:' || location.protocol === 'chrome:' || location.protocol === 'chrome-extension:' || location.protocol === 'resource:'); less.env = less.env || (location.hostname == '127.0.0.1' || location.hostname == '0.0.0.0' || location.hostname == 'localhost' || location.port.length > 0 || isFileProtocol ? 'development' : 'production'); // Load styles asynchronously (default: false) // // This is set to `false` by default, so that the body // doesn't start loading before the stylesheets are parsed. // Setting this to `true` can result in flickering. // less.async = false; // Interval between watch polls less.poll = less.poll || (isFileProtocol ? 1000 : 1500); // // Watch mode // less.watch = function () { return this.watchMode = true }; less.unwatch = function () { return this.watchMode = false }; if (less.env === 'development') { less.optimization = 0; if (/!watch/.test(location.hash)) { less.watch(); } less.watchTimer = setInterval(function () { if (less.watchMode) { loadStyleSheets(function (root, sheet, env) { if (root) { createCSS(root.toCSS(), sheet, env.lastModified); } }); } }, less.poll); } else { less.optimization = 3; } var cache; try { cache = (typeof(window.localStorage) === 'undefined') ? null : window.localStorage; } catch (_) { cache = null; } // // Get all tags with the 'rel' attribute set to "stylesheet/less" // var links = document.getElementsByTagName('link'); var typePattern = /^text\/(x-)?less$/; less.sheets = []; for (var i = 0; i < links.length; i++) { if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) && (links[i].type.match(typePattern)))) { less.sheets.push(links[i]); } } less.refresh = function (reload) { var startTime, endTime; startTime = endTime = new(Date); loadStyleSheets(function (root, sheet, env) { if (env.local) { log("loading " + sheet.href + " from cache."); } else { log("parsed " + sheet.href + " successfully."); createCSS(root.toCSS(), sheet, env.lastModified); } log("css for " + sheet.href + " generated in " + (new(Date) - endTime) + 'ms'); (env.remaining === 0) && log("css generated in " + (new(Date) - startTime) + 'ms'); endTime = new(Date); }, reload); loadStyles(); }; less.refreshStyles = loadStyles; less.refresh(less.env === 'development'); function loadStyles() { var styles = document.getElementsByTagName('style'); for (var i = 0; i < styles.length; i++) { if (styles[i].type.match(typePattern)) { new(less.Parser)().parse(styles[i].innerHTML || '', function (e, tree) { var css = tree.toCSS(); var style = styles[i]; try { style.innerHTML = css; } catch (_) { style.styleSheets.cssText = css; } style.type = 'text/css'; }); } } } function loadStyleSheets(callback, reload) { for (var i = 0; i < less.sheets.length; i++) { loadStyleSheet(less.sheets[i], callback, reload, less.sheets.length - (i + 1)); } } function loadStyleSheet(sheet, callback, reload, remaining) { var url = window.location.href.replace(/[#?].*$/, ''); var href = sheet.href.replace(/\?.*$/, ''); var css = cache && cache.getItem(href); var timestamp = cache && cache.getItem(href + ':timestamp'); var styles = { css: css, timestamp: timestamp }; // Stylesheets in IE don't always return the full path if (! /^(https?|file):/.test(href)) { if (href.charAt(0) == "/") { href = window.location.protocol + "//" + window.location.host + href; } else { href = url.slice(0, url.lastIndexOf('/') + 1) + href; } } xhr(sheet.href, sheet.type, function (data, lastModified) { if (!reload && styles && lastModified && (new(Date)(lastModified).valueOf() === new(Date)(styles.timestamp).valueOf())) { // Use local copy createCSS(styles.css, sheet); callback(null, sheet, { local: true, remaining: remaining }); } else { // Use remote copy (re-parse) try { new(less.Parser)({ optimization: less.optimization, paths: [href.replace(/[\w\.-]+$/, '')], mime: sheet.type }).parse(data, function (e, root) { if (e) { return error(e, href) } try { callback(root, sheet, { local: false, lastModified: lastModified, remaining: remaining }); removeNode(document.getElementById('less-error-message:' + extractId(href))); } catch (e) { error(e, href); } }); } catch (e) { error(e, href); } } }, function (status, url) { throw new(Error)("Couldn't load " + url + " (" + status + ")"); }); } function extractId(href) { return href.replace(/^[a-z]+:\/\/?[^\/]+/, '' ) // Remove protocol & domain .replace(/^\//, '' ) // Remove root / .replace(/\?.*$/, '' ) // Remove query .replace(/\.[^\.\/]+$/, '' ) // Remove file extension .replace(/[^\.\w-]+/g, '-') // Replace illegal characters .replace(/\./g, ':'); // Replace dots with colons(for valid id) } function createCSS(styles, sheet, lastModified) { var css; // Strip the query-string var href = sheet.href ? sheet.href.replace(/\?.*$/, '') : ''; // If there is no title set, use the filename, minus the extension var id = 'less:' + (sheet.title || extractId(href)); // If the stylesheet doesn't exist, create a new node if ((css = document.getElementById(id)) === null) { css = document.createElement('style'); css.type = 'text/css'; css.media = sheet.media || 'screen'; css.id = id; document.getElementsByTagName('head')[0].appendChild(css); } if (css.styleSheet) { // IE try { css.styleSheet.cssText = styles; } catch (e) { throw new(Error)("Couldn't reassign styleSheet.cssText."); } } else { (function (node) { if (css.childNodes.length > 0) { if (css.firstChild.nodeValue !== node.nodeValue) { css.replaceChild(node, css.firstChild); } } else { css.appendChild(node); } })(document.createTextNode(styles)); } // Don't update the local store if the file wasn't modified if (lastModified && cache) { log('saving ' + href + ' to cache.'); cache.setItem(href, styles); cache.setItem(href + ':timestamp', lastModified); } } function xhr(url, type, callback, errback) { var xhr = getXMLHttpRequest(); var async = isFileProtocol ? false : less.async; if (typeof(xhr.overrideMimeType) === 'function') { xhr.overrideMimeType('text/css'); } xhr.open('GET', url, async); xhr.setRequestHeader('Accept', type || 'text/x-less, text/css; q=0.9, */*; q=0.5'); xhr.send(null); if (isFileProtocol) { if (xhr.status === 0 || (xhr.status >= 200 && xhr.status < 300)) { callback(xhr.responseText); } else { errback(xhr.status, url); } } else if (async) { xhr.onreadystatechange = function () { if (xhr.readyState == 4) { handleResponse(xhr, callback, errback); } }; } else { handleResponse(xhr, callback, errback); } function handleResponse(xhr, callback, errback) { if (xhr.status >= 200 && xhr.status < 300) { callback(xhr.responseText, xhr.getResponseHeader("Last-Modified")); } else if (typeof(errback) === 'function') { errback(xhr.status, url); } } } function getXMLHttpRequest() { if (window.XMLHttpRequest) { return new(XMLHttpRequest); } else { try { return new(ActiveXObject)("MSXML2.XMLHTTP.3.0"); } catch (e) { log("browser doesn't support AJAX."); return null; } } } function removeNode(node) { return node && node.parentNode.removeChild(node); } function log(str) { if (less.env == 'development' && typeof(console) !== "undefined") { console.log('less: ' + str) } } function error(e, href) { var id = 'less-error-message:' + extractId(href); var template = ['
    ', '
  • {0}
  • ', '
  • {current}
  • ', '
  • {2}
  • ', '
'].join('\n'); var elem = document.createElement('div'), timer, content; elem.id = id; elem.className = "less-error-message"; content = '

' + (e.message || 'There is an error in your .less file') + '

' + '

' + href + " "; if (e.extract) { content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':

' + template.replace(/\[(-?\d)\]/g, function (_, i) { return (parseInt(e.line) + parseInt(i)) || ''; }).replace(/\{(\d)\}/g, function (_, i) { return e.extract[parseInt(i)] || ''; }).replace(/\{current\}/, e.extract[1].slice(0, e.column) + '' + e.extract[1].slice(e.column) + ''); } elem.innerHTML = content; // CSS for error messages createCSS([ '.less-error-message ul, .less-error-message li {', 'list-style-type: none;', 'margin-right: 15px;', 'padding: 4px 0;', 'margin: 0;', '}', '.less-error-message label {', 'font-size: 12px;', 'margin-right: 15px;', 'padding: 4px 0;', 'color: #cc7777;', '}', '.less-error-message pre {', 'color: #ee4444;', 'padding: 4px 0;', 'margin: 0;', 'display: inline-block;', '}', '.less-error-message pre.ctx {', 'color: #dd4444;', '}', '.less-error-message h3 {', 'font-size: 20px;', 'font-weight: bold;', 'padding: 15px 0 5px 0;', 'margin: 0;', '}', '.less-error-message a {', 'color: #10a', '}', '.less-error-message .error {', 'color: red;', 'font-weight: bold;', 'padding-bottom: 2px;', 'border-bottom: 1px dashed red;', '}' ].join('\n'), { title: 'error-message' }); elem.style.cssText = [ "font-family: Arial, sans-serif", "border: 1px solid #e00", "background-color: #eee", "border-radius: 5px", "-webkit-border-radius: 5px", "-moz-border-radius: 5px", "color: #e00", "padding: 15px", "margin-bottom: 15px" ].join(';'); if (less.env == 'development') { timer = setInterval(function () { if (document.body) { if (document.getElementById(id)) { document.body.replaceChild(elem, document.getElementById(id)); } else { document.body.insertBefore(elem, document.body.firstChild); } clearInterval(timer); } }, 10); } } })(window); less.js-1.4.2/dist/less-1.1.6.min.js000066400000000000000000001150011217256642200165760ustar00rootroot00000000000000// // LESS - Leaner CSS v1.1.6 // http://lesscss.org // // Copyright (c) 2009-2011, Alexis Sellier // Licensed under the Apache 2.0 License. // (function(a,b){function c(b){return a.less[b.split("/")[1]]}function l(){var a=document.getElementsByTagName("style");for(var b=0;b0?d.firstChild.nodeValue!==a.nodeValue&&d.replaceChild(a,d.firstChild):d.appendChild(a)})(document.createTextNode(a));c&&g&&(t("saving "+e+" to cache."),g.setItem(e,a),g.setItem(e+":timestamp",c))}function q(a,b,c,e){function i(b,c,d){b.status>=200&&b.status<300?c(b.responseText,b.getResponseHeader("Last-Modified")):typeof d=="function"&&d(b.status,a)}var g=r(),h=f?!1:d.async;typeof g.overrideMimeType=="function"&&g.overrideMimeType("text/css"),g.open("GET",a,h),g.setRequestHeader("Accept",b||"text/x-less, text/css; q=0.9, */*; q=0.5"),g.send(null),f?g.status===0||g.status>=200&&g.status<300?c(g.responseText):e(g.status,a):h?g.onreadystatechange=function(){g.readyState==4&&i(g,c,e)}:i(g,c,e)}function r(){if(a.XMLHttpRequest)return new XMLHttpRequest;try{return new ActiveXObject("MSXML2.XMLHTTP.3.0")}catch(b){return t("browser doesn't support AJAX."),null}}function s(a){return a&&a.parentNode.removeChild(a)}function t(a){d.env=="development"&&typeof console!="undefined"&&console.log("less: "+a)}function u(a,b){var c="less-error-message:"+o(b),e=["
    ",'
  • {0}
  • ',"
  • {current}
  • ",'
  • {2}
  • ',"
"].join("\n"),f=document.createElement("div"),g,h;f.id=c,f.className="less-error-message",h="

"+(a.message||"There is an error in your .less file")+"

"+'

'+b+" ",a.extract&&(h+="on line "+a.line+", column "+(a.column+1)+":

"+e.replace(/\[(-?\d)\]/g,function(b,c){return parseInt(a.line)+parseInt(c)||""}).replace(/\{(\d)\}/g,function(b,c){return a.extract[parseInt(c)]||""}).replace(/\{current\}/,a.extract[1].slice(0,a.column)+''+a.extract[1].slice(a.column)+"")),f.innerHTML=h,p([".less-error-message ul, .less-error-message li {","list-style-type: none;","margin-right: 15px;","padding: 4px 0;","margin: 0;","}",".less-error-message label {","font-size: 12px;","margin-right: 15px;","padding: 4px 0;","color: #cc7777;","}",".less-error-message pre {","color: #ee4444;","padding: 4px 0;","margin: 0;","display: inline-block;","}",".less-error-message pre.ctx {","color: #dd4444;","}",".less-error-message h3 {","font-size: 20px;","font-weight: bold;","padding: 15px 0 5px 0;","margin: 0;","}",".less-error-message a {","color: #10a","}",".less-error-message .error {","color: red;","font-weight: bold;","padding-bottom: 2px;","border-bottom: 1px dashed red;","}"].join("\n"),{title:"error-message"}),f.style.cssText=["font-family: Arial, sans-serif","border: 1px solid #e00","background-color: #eee","border-radius: 5px","-webkit-border-radius: 5px","-moz-border-radius: 5px","color: #e00","padding: 15px","margin-bottom: 15px"].join(";"),d.env=="development"&&(g=setInterval(function(){document.body&&(document.getElementById(c)?document.body.replaceChild(f,document.getElementById(c)):document.body.insertBefore(f,document.body.firstChild),clearInterval(g))},10))}Array.isArray||(Array.isArray=function(a){return Object.prototype.toString.call(a)==="[object Array]"||a instanceof Array}),Array.prototype.forEach||(Array.prototype.forEach=function(a,b){var c=this.length>>>0;for(var d=0;d>>0,c=new Array(b),d=arguments[1];for(var e=0;e>>0,c=0;if(b===0&&arguments.length===1)throw new TypeError;if(arguments.length>=2)var d=arguments[1];else do{if(c in this){d=this[c++];break}if(++c>=b)throw new TypeError}while(!0);for(;c=b)return-1;c<0&&(c+=b);for(;cl&&(k[g]=k[g].slice(f-l),l=f)}function t(a){var c,d,e,h,i,j,n,o;if(a instanceof Function)return a.call(m.parsers);if(typeof a=="string")c=b.charAt(f)===a?a:null,e=1,s();else{s();if(c=a.exec(k[g]))e=c[0].length;else return null}if(c){o=f+=e,j=f+k[g].length-e;while(f0)throw{type:"Syntax",message:"Missing closing `}`",filename:a.filename};return c.map(function(a){return a.join("")})}([[]]),m=new e.Ruleset([],t(this.parsers.primary)),m.root=!0,m.toCSS=function(f){var g,h,i;return function(i,j){function p(a){return a?(b.slice(0,a).match(/\n/g)||"").length:null}var k=[];i=i||{},typeof j=="object"&&!Array.isArray(j)&&(j=Object.keys(j).map(function(a){var b=j[a];return b instanceof e.Value||(b instanceof e.Expression||(b=new e.Expression([b])),b=new e.Value([b])),new e.Rule("@"+a,b,!1,0)}),k=[new e.Ruleset(null,j)]);try{var l=f.call(this,{frames:k}).toCSS([],{compress:i.compress||!1})}catch(m){h=b.split("\n"),g=p(m.index);for(var n=m.index,o=-1;n>=0&&b.charAt(n)!=="\n";n--)o++;throw{type:m.type,message:m.message,filename:a.filename,index:m.index,line:typeof g=="number"?g+1:null,callLine:m.call&&p(m.call)+1,callExtract:h[p(m.call)],stack:m.stack,column:o,extract:[h[g-1],h[g],h[g+1]]}}return i.yuicompress&&d.mode==="node"?c("./cssmin").compressor.cssmin(l):i.compress?l.replace(/(\s)+/g,"$1"):l}}(m.eval);if(f=0&&b.charAt(x)!=="\n";x--)y++;w={name:"ParseError",message:"Syntax Error on line "+r,index:f,filename:a.filename,line:r,column:y,extract:[s[r-2],s[r-1],s[r]]}}this.imports.queue.length>0?o=function(){i(w,m)}:i(w,m)},parsers:{primary:function(){var a,b=[];while((a=t(this.mixin.definition)||t(this.rule)||t(this.ruleset)||t(this.mixin.call)||t(this.comment)||t(this.directive))||t(/^[\s\n]+/))a&&b.push(a);return b},comment:function(){var a;if(b.charAt(f)!=="/")return;if(b.charAt(f+1)==="/")return new e.Comment(t(/^\/\/.*/),!0);if(a=t(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/))return new e.Comment(a)},entities:{quoted:function(){var a,c=f,d;b.charAt(c)==="~"&&(c++,d=!0);if(b.charAt(c)!=='"'&&b.charAt(c)!=="'")return;d&&t("~");if(a=t(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/))return new e.Quoted(a[0],a[1]||a[2],d)},keyword:function(){var a;if(a=t(/^[_A-Za-z-][_A-Za-z0-9-]*/))return e.colors.hasOwnProperty(a)?new e.Color(e.colors[a].slice(1)):new e.Keyword(a)},call:function(){var a,b,c=f;if(!(a=/^([\w-]+|%|progid:[\w\.]+)\(/.exec(k[g])))return;a=a[1].toLowerCase();if(a==="url")return null;f+=a.length;if(a==="alpha")return t(this.alpha);t("("),b=t(this.entities.arguments);if(!t(")"))return;if(a)return new e.Call(a,b,c)},arguments:function(){var a=[],b;while(b=t(this.entities.assignment)||t(this.expression)){a.push(b);if(!t(","))break}return a},literal:function(){return t(this.entities.dimension)||t(this.entities.color)||t(this.entities.quoted)},assignment:function(){var a,b;if((a=t(/^\w+(?=\s?=)/i))&&t("=")&&(b=t(this.entity)))return new e.Assignment(a,b)},url:function(){var a;if(b.charAt(f)!=="u"||!t(/^url\(/))return;a=t(this.entities.quoted)||t(this.entities.variable)||t(this.entities.dataURI)||t(/^[-\w%@$\/.&=:;#+?~]+/)||"";if(!t(")"))throw new Error("missing closing ) for url()");return new e.URL(a.value||a.data||a instanceof e.Variable?a:new e.Anonymous(a),p.paths)},dataURI:function(){var a;if(t(/^data:/)){a={},a.mime=t(/^[^\/]+\/[^,;)]+/)||"",a.charset=t(/^;\s*charset=[^,;)]+/)||"",a.base64=t(/^;\s*base64/)||"",a.data=t(/^,\s*[^)]+/);if(a.data)return a}},variable:function(){var a,c=f;if(b.charAt(f)==="@"&&(a=t(/^@@?[\w-]+/)))return new e.Variable(a,c)},color:function(){var a;if(b.charAt(f)==="#"&&(a=t(/^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})/)))return new e.Color(a[1])},dimension:function(){var a,c=b.charCodeAt(f);if(c>57||c<45||c===47)return;if(a=t(/^(-?\d*\.?\d+)(px|%|em|rem|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn)?/))return new e.Dimension(a[1],a[2])},javascript:function(){var a,c=f,d;b.charAt(c)==="~"&&(c++,d=!0);if(b.charAt(c)!=="`")return;d&&t("~");if(a=t(/^`([^`]*)`/))return new e.JavaScript(a[1],f,d)}},variable:function(){var a;if(b.charAt(f)==="@"&&(a=t(/^(@[\w-]+)\s*:/)))return a[1]},shorthand:function(){var a,b;if(!u(/^[@\w.%-]+\/[@\w.-]+/))return;if((a=t(this.entity))&&t("/")&&(b=t(this.entity)))return new e.Shorthand(a,b)},mixin:{call:function(){var a=[],c,d,g,h=f,i=b.charAt(f);if(i!=="."&&i!=="#")return;while(c=t(/^[#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/))a.push(new e.Element(d,c,f)),d=t(">");t("(")&&(g=t(this.entities.arguments))&&t(")");if(a.length>0&&(t(";")||u("}")))return new e.mixin.Call(a,g,h)},definition:function(){var a,c=[],d,g,h,i;if(b.charAt(f)!=="."&&b.charAt(f)!=="#"||u(/^[^{]*(;|})/))return;if(d=t(/^([#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+)\s*\(/)){a=d[1];while(h=t(this.entities.variable)||t(this.entities.literal)||t(this.entities.keyword)){if(h instanceof e.Variable)if(t(":"))if(i=t(this.expression))c.push({name:h.name,value:i});else throw new Error("Expected value");else c.push({name:h.name});else c.push({value:h});if(!t(","))break}if(!t(")"))throw new Error("Expected )");g=t(this.block);if(g)return new e.mixin.Definition(a,c,g)}}},entity:function(){return t(this.entities.literal)||t(this.entities.variable)||t(this.entities.url)||t(this.entities.call)||t(this.entities.keyword)||t(this.entities.javascript)||t(this.comment)},end:function(){return t(";")||u("}")},alpha:function(){var a;if(!t(/^\(opacity=/i))return;if(a=t(/^\d+/)||t(this.entities.variable)){if(!t(")"))throw new Error("missing closing ) for alpha()");return new e.Alpha(a)}},element:function(){var a,b,c;c=t(this.combinator),a=t(/^(?:\d+\.\d+|\d+)%/)||t(/^(?:[.#]?|:*)(?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/)||t("*")||t(this.attribute)||t(/^\([^)@]+\)/);if(a)return new e.Element(c,a,f);if(c.value&&c.value.charAt(0)==="&")return new e.Element(c,null,f)},combinator:function(){var a,c=b.charAt(f);if(c===">"||c==="+"||c==="~"){f++;while(b.charAt(f)===" ")f++;return new e.Combinator(c)}if(c==="&"){a="&",f++,b.charAt(f)===" "&&(a="& ");while(b.charAt(f)===" ")f++;return new e.Combinator(a)}if(c===":"&&b.charAt(f+1)===":"){f+=2;while(b.charAt(f)===" ")f++;return new e.Combinator("::")}return b.charAt(f-1)===" "?new e.Combinator(" "):new e.Combinator(null)},selector:function(){var a,c,d=[],g,h;while(c=t(this.element)){g=b.charAt(f),d.push(c);if(g==="{"||g==="}"||g===";"||g===",")break}if(d.length>0)return new e.Selector(d)},tag:function(){return t(/^[a-zA-Z][a-zA-Z-]*[0-9]?/)||t("*")},attribute:function(){var a="",b,c,d;if(!t("["))return;if(b=t(/^[a-zA-Z-]+/)||t(this.entities.quoted))(d=t(/^[|~*$^]?=/))&&(c=t(this.entities.quoted)||t(/^[\w-]+/))?a=[b,d,c.toCSS?c.toCSS():c].join(""):a=b;if(!t("]"))return;if(a)return"["+a+"]"},block:function(){var a;if(t("{")&&(a=t(this.primary))&&t("}"))return a},ruleset:function(){var a=[],b,c,d;q();while(b=t(this.selector)){a.push(b),t(this.comment);if(!t(","))break;t(this.comment)}if(a.length>0&&(c=t(this.block)))return new e.Ruleset(a,c);j=f,r()},rule:function(){var a,c,d=b.charAt(f),h,l;q();if(d==="."||d==="#"||d==="&")return;if(a=t(this.variable)||t(this.property)){a.charAt(0)!="@"&&(l=/^([^@+\/'"*`(;{}-]*);/.exec(k[g]))?(f+=l[0].length-1,c=new e.Anonymous(l[1])):a==="font"?c=t(this.font):c=t(this.value),h=t(this.important);if(c&&t(this.end))return new e.Rule(a,c,h,i);j=f,r()}},"import":function(){var a;if(t(/^@import\s+/)&&(a=t(this.entities.quoted)||t(this.entities.url))&&t(";"))return new e.Import(a,p)},directive:function(){var a,c,d,g;if(b.charAt(f)!=="@")return;if(c=t(this["import"]))return c;if(a=t(/^@media|@page/)||t(/^@(?:-webkit-|-moz-|-o-|-ms-)[a-z0-9-]+/)||t("keyframes")){g=(t(/^[^{]+/)||"").trim();if(d=t(this.block))return new e.Directive(a+" "+g,d)}else if(a=t(/^@[-a-z]+/))if(a==="@font-face"){if(d=t(this.block))return new e.Directive(a,d)}else if((c=t(this.entity))&&t(";"))return new e.Directive(a,c)},font:function(){var a=[],b=[],c,d,f,g;while(g=t(this.shorthand)||t(this.entity))b.push(g);a.push(new e.Expression(b));if(t(","))while(g=t(this.expression)){a.push(g);if(!t(","))break}return new e.Value(a)},value:function(){var a,b=[],c;while(a=t(this.expression)){b.push(a);if(!t(","))break}if(b.length>0)return new e.Value(b)},important:function(){if(b.charAt(f)==="!")return t(/^! *important/)},sub:function(){var a;if(t("(")&&(a=t(this.expression))&&t(")"))return a},multiplication:function(){var a,b,c,d;if(a=t(this.operand)){while(!u(/^\/\*/)&&(c=t("/")||t("*"))&&(b=t(this.operand)))d=new e.Operation(c,[d||a,b]);return d||a}},addition:function(){var a,c,d,g;if(a=t(this.multiplication)){while((d=t(/^[-+]\s+/)||b.charAt(f-1)!=" "&&(t("+")||t("-")))&&(c=t(this.multiplication)))g=new e.Operation(d,[g||a,c]);return g||a}},operand:function(){var a,c=b.charAt(f+1);b.charAt(f)==="-"&&(c==="@"||c==="(")&&(a=t("-"));var d=t(this.sub)||t(this.entities.dimension)||t(this.entities.color)||t(this.entities.variable)||t(this.entities.call);return a?new e.Operation("*",[new e.Dimension(-1),d]):d},expression:function(){var a,b,c=[],d;while(a=t(this.addition)||t(this.entity))c.push(a);if(c.length>0)return new e.Expression(c)},property:function(){var a;if(a=t(/^(\*?-?[-a-z_0-9]+)\s*:/))return a[1]}}}};if(d.mode==="browser"||d.mode==="rhino")d.Parser.importer=function(a,b,c,d){a.charAt(0)!=="/"&&b.length>0&&(a=b[0]+a),n({href:a,title:a,type:d.mime},c,!0)};(function(a){function b(b){return a.functions.hsla(b.h,b.s,b.l,b.a)}function c(b){if(b instanceof a.Dimension)return parseFloat(b.unit=="%"?b.value/100:b.value);if(typeof b=="number")return b;throw{error:"RuntimeError",message:"color functions take numbers as parameters"}}function d(a){return Math.min(1,Math.max(0,a))}a.functions={rgb:function(a,b,c){return this.rgba(a,b,c,1)},rgba:function(b,d,e,f){var g=[b,d,e].map(function(a){return c(a)}),f=c(f);return new a.Color(g,f)},hsl:function(a,b,c){return this.hsla(a,b,c,1)},hsla:function(a,b,d,e){function h(a){return a=a<0?a+1:a>1?a-1:a,a*6<1?g+(f-g)*a*6:a*2<1?f:a*3<2?g+(f-g)*(2/3-a)*6:g}a=c(a)%360/360,b=c(b),d=c(d),e=c(e);var f=d<=.5?d*(b+1):d+b-d*b,g=d*2-f;return this.rgba(h(a+1/3)*255,h(a)*255,h(a-1/3)*255,e)},hue:function(b){return new a.Dimension(Math.round(b.toHSL().h))},saturation:function(b){return new a.Dimension(Math.round(b.toHSL().s*100),"%")},lightness:function(b){return new a.Dimension(Math.round(b.toHSL().l*100),"%")},alpha:function(b){return new a.Dimension(b.toHSL().a)},saturate:function(a,c){var e=a.toHSL();return e.s+=c.value/100,e.s=d(e.s),b(e)},desaturate:function(a,c){var e=a.toHSL();return e.s-=c.value/100,e.s=d(e.s),b(e)},lighten:function(a,c){var e=a.toHSL();return e.l+=c.value/100,e.l=d(e.l),b(e)},darken:function(a,c){var e=a.toHSL();return e.l-=c.value/100,e.l=d(e.l),b(e)},fadein:function(a,c){var e=a.toHSL();return e.a+=c.value/100,e.a=d(e.a),b(e)},fadeout:function(a,c){var e=a.toHSL();return e.a-=c.value/100,e.a=d(e.a),b(e)},fade:function(a,c){var e=a.toHSL();return e.a=c.value/100,e.a=d(e.a),b(e)},spin:function(a,c){var d=a.toHSL(),e=(d.h+c.value)%360;return d.h=e<0?360+e:e,b(d)},mix:function(b,c,d){var e=d.value/100,f=e*2-1,g=b.toHSL().a-c.toHSL().a,h=((f*g==-1?f:(f+g)/(1+f*g))+1)/2,i=1-h,j=[b.rgb[0]*h+c.rgb[0]*i,b.rgb[1]*h+c.rgb[1]*i,b.rgb[2]*h+c.rgb[2]*i],k=b.alpha*e+c.alpha*(1-e);return new a.Color(j,k)},greyscale:function(b){return this.desaturate(b,new a.Dimension(100))},e:function(b){return new a.Anonymous(b instanceof a.JavaScript?b.evaluated:b)},escape:function(b){return new a.Anonymous(encodeURI(b.value).replace(/=/g,"%3D").replace(/:/g,"%3A").replace(/#/g,"%23").replace(/;/g,"%3B").replace(/\(/g,"%28").replace(/\)/g,"%29"))},"%":function(b){var c=Array.prototype.slice.call(arguments,1),d=b.value;for(var e=0;e255?255:a<0?0:a).toString(16),a.length===1?"0"+a:a}).join("")},operate:function(b,c){var d=[];c instanceof a.Color||(c=c.toColor());for(var e=0;e<3;e++)d[e]=a.operate(b,this.rgb[e],c.rgb[e]);return new a.Color(d,this.alpha+c.alpha)},toHSL:function(){var a=this.rgb[0]/255,b=this.rgb[1]/255,c=this.rgb[2]/255,d=this.alpha,e=Math.max(a,b,c),f=Math.min(a,b,c),g,h,i=(e+f)/2,j=e-f;if(e===f)g=h=0;else{h=i>.5?j/(2-e-f):j/(e+f);switch(e){case a:g=(b-c)/j+(b255?255:a<0?0:a).toString(16),a.length===1?"0"+a:a}).join("")}}}(c("../tree")),function(a){a.Comment=function(a,b){this.value=a,this.silent=!!b},a.Comment.prototype={toCSS:function(a){return a.compress?"":this.value},eval:function(){return this}}}(c("../tree")),function(a){a.Dimension=function(a,b){this.value=parseFloat(a),this.unit=b||null},a.Dimension.prototype={eval:function(){return this},toColor:function(){return new a.Color([this.value,this.value,this.value])},toCSS:function(){var a=this.value+this.unit;return a},operate:function(b,c){return new a.Dimension(a.operate(b,this.value,c.value),this.unit||c.unit)}}}(c("../tree")),function(a){a.Directive=function(b,c){this.name=b,Array.isArray(c)?this.ruleset=new a.Ruleset([],c):this.value=c},a.Directive.prototype={toCSS:function(a,b){return this.ruleset?(this.ruleset.root=!0,this.name+(b.compress?"{":" {\n ")+this.ruleset.toCSS(a,b).trim().replace(/\n/g,"\n ")+(b.compress?"}":"\n}\n")):this.name+" "+this.value.toCSS()+";\n"},eval:function(a){return a.frames.unshift(this),this.ruleset=this.ruleset&&this.ruleset.eval(a),a.frames.shift(),this},variable:function(b){return a.Ruleset.prototype.variable.call(this.ruleset,b)},find:function(){return a.Ruleset.prototype.find.apply(this.ruleset,arguments)},rulesets:function(){return a.Ruleset.prototype.rulesets.apply(this.ruleset)}}}(c("../tree")),function(a){a.Element=function(b,c,d){this.combinator=b instanceof a.Combinator?b:new a.Combinator(b),this.value=c?c.trim():"",this.index=d},a.Element.prototype.toCSS=function(a){return this.combinator.toCSS(a||{})+this.value},a.Combinator=function(a){a===" "?this.value=" ":a==="& "?this.value="& ":this.value=a?a.trim():""},a.Combinator.prototype.toCSS=function(a){return{"":""," ":" ","&":"","& ":" ",":":" :","::":"::","+":a.compress?"+":" + ","~":a.compress?"~":" ~ ",">":a.compress?">":" > "}[this.value]}}(c("../tree")),function(a){a.Expression=function(a){this.value=a},a.Expression.prototype={eval:function(b){return this.value.length>1?new a.Expression(this.value.map(function(a){return a.eval(b)})):this.value.length===1?this.value[0].eval(b):this},toCSS:function(a){return this.value.map(function(b){return b.toCSS(a)}).join(" ")}}}(c("../tree")),function(a){a.Import=function(b,c){var d=this;this._path=b,b instanceof a.Quoted?this.path=/\.(le?|c)ss(\?.*)?$/.test(b.value)?b.value:b.value+".less":this.path=b.value.value||b.value,this.css=/css(\?.*)?$/.test(this.path),this.css||c.push(this.path,function(a){if(!a)throw new Error("Error parsing "+d.path);d.root=a})},a.Import.prototype={toCSS:function(){return this.css?"@import "+this._path.toCSS()+";\n":""},eval:function(b){var c;if(this.css)return this;c=new a.Ruleset(null,this.root.rules.slice(0));for(var d=0;d0){c=this.arguments&&this.arguments.map(function(b){return b.eval(a)});for(var g=0;g0&&c>this.params.length)return!1;d=Math.min(c,this.arity);for(var e=0;ee.selectors[g].elements.length?Array.prototype.push.apply(d,e.find(new a.Selector(b.elements.slice(1)),c)):d.push(e);break}}),this._lookups[g]=d)},toCSS:function(b,c){var d=[],e=[],f=[],g=[],h,i;this.root||(b.length===0?g=this.selectors.map(function(a){return[a]}):this.joinSelectors(g,b,this.selectors));for(var j=0;j0&&(h=g.map(function(a){return a.map(function(a){return a.toCSS(c)}).join("").trim()}).join(c.compress?",":g.length>3?",\n":", "),d.push(h,(c.compress?"{":" {\n ")+e.join(c.compress?"":"\n ")+(c.compress?"}":"\n}\n"))),d.push(f),d.join("")+(c.compress?"\n":"")},joinSelectors:function(a,b,c){for(var d=0;d0&&e.push(new a.Selector(g)),h.length>0&&f.push(new a.Selector(h));for(var l=0;l0&&(b.value=c[0]+(b.value.charAt(0)==="/"?b.value.slice(1):b.value)),this.value=b,this.paths=c)},b.URL.prototype={toCSS:function(){return"url("+(this.attrs?"data:"+this.attrs.mime+this.attrs.charset+this.attrs.base64+this.attrs.data:this.value.toCSS())+")"},eval:function(a){return this.attrs?this:new b.URL(this.value.eval(a),this.paths)}}}(c("../tree")),function(a){a.Value=function(a){this.value=a,this.is="value"},a.Value.prototype={eval:function(b){return this.value.length===1?this.value[0].eval(b):new a.Value(this.value.map(function(a){return a.eval(b)}))},toCSS:function(a){return this.value.map(function(b){return b.toCSS(a)}).join(a.compress?",":", ")}}}(c("../tree")),function(a){a.Variable=function(a,b){this.name=a,this.index=b},a.Variable.prototype={eval:function(b){var c,d,e=this.name;e.indexOf("@@")==0&&(e="@"+(new a.Variable(e.slice(1))).eval(b).value);if(c=a.find(b.frames,function(a){if(d=a.variable(e))return d.value.eval(b)}))return c;throw{message:"variable "+e+" is undefined",index:this.index}}}}(c("../tree")),c("./tree").find=function(a,b){for(var c=0,d;c1?"["+a.value.map(function(a){return a.toCSS(!1)}).join(", ")+"]":a.toCSS(!1)};var f=location.protocol==="file:"||location.protocol==="chrome:"||location.protocol==="chrome-extension:"||location.protocol==="resource:";d.env=d.env||(location.hostname=="127.0.0.1"||location.hostname=="0.0.0.0"||location.hostname=="localhost"||location.port.length>0||f?"development":"production"),d.async=!1,d.poll=d.poll||(f?1e3:1500),d.watch=function(){return this.watchMode=!0},d.unwatch=function(){return this.watchMode=!1},d.env==="development"?(d.optimization=0,/!watch/.test(location.hash)&&d.watch(),d.watchTimer=setInterval(function(){d.watchMode&&m(function(a,b,c){a&&p(a.toCSS(),b,c.lastModified)})},d.poll)):d.optimization=3;var g;try{g=typeof a.localStorage=="undefined"?null:a.localStorage}catch(h){g=null}var i=document.getElementsByTagName("link"),j=/^text\/(x-)?less$/;d.sheets=[];for(var k=0;k>> 0; for (var i = 0; i < len; i++) { if (i in this) { block.call(thisObject, this[i], i, this); } } }; } if (!Array.prototype.map) { Array.prototype.map = function(fun /*, thisp*/) { var len = this.length >>> 0; var res = new Array(len); var thisp = arguments[1]; for (var i = 0; i < len; i++) { if (i in this) { res[i] = fun.call(thisp, this[i], i, this); } } return res; }; } if (!Array.prototype.filter) { Array.prototype.filter = function (block /*, thisp */) { var values = []; var thisp = arguments[1]; for (var i = 0; i < this.length; i++) { if (block.call(thisp, this[i])) { values.push(this[i]); } } return values; }; } if (!Array.prototype.reduce) { Array.prototype.reduce = function(fun /*, initial*/) { var len = this.length >>> 0; var i = 0; // no value to return if no initial value and an empty array if (len === 0 && arguments.length === 1) throw new TypeError(); if (arguments.length >= 2) { var rv = arguments[1]; } else { do { if (i in this) { rv = this[i++]; break; } // if array contains no values, no initial value to return if (++i >= len) throw new TypeError(); } while (true); } for (; i < len; i++) { if (i in this) { rv = fun.call(null, rv, this[i], i, this); } } return rv; }; } if (!Array.prototype.indexOf) { Array.prototype.indexOf = function (value /*, fromIndex */ ) { var length = this.length; var i = arguments[1] || 0; if (!length) return -1; if (i >= length) return -1; if (i < 0) i += length; for (; i < length; i++) { if (!Object.prototype.hasOwnProperty.call(this, i)) { continue } if (value === this[i]) return i; } return -1; }; } // // Object // if (!Object.keys) { Object.keys = function (object) { var keys = []; for (var name in object) { if (Object.prototype.hasOwnProperty.call(object, name)) { keys.push(name); } } return keys; }; } // // String // if (!String.prototype.trim) { String.prototype.trim = function () { return String(this).replace(/^\s\s*/, '').replace(/\s\s*$/, ''); }; } var less, tree; if (typeof environment === "object" && ({}).toString.call(environment) === "[object Environment]") { // Rhino // Details on how to detect Rhino: https://github.com/ringo/ringojs/issues/88 if (typeof(window) === 'undefined') { less = {} } else { less = window.less = {} } tree = less.tree = {}; less.mode = 'rhino'; } else if (typeof(window) === 'undefined') { // Node.js less = exports, tree = require('./tree'); less.mode = 'node'; } else { // Browser if (typeof(window.less) === 'undefined') { window.less = {} } less = window.less, tree = window.less.tree = {}; less.mode = 'browser'; } // // less.js - parser // // A relatively straight-forward predictive parser. // There is no tokenization/lexing stage, the input is parsed // in one sweep. // // To make the parser fast enough to run in the browser, several // optimization had to be made: // // - Matching and slicing on a huge input is often cause of slowdowns. // The solution is to chunkify the input into smaller strings. // The chunks are stored in the `chunks` var, // `j` holds the current chunk index, and `current` holds // the index of the current chunk in relation to `input`. // This gives us an almost 4x speed-up. // // - In many cases, we don't need to match individual tokens; // for example, if a value doesn't hold any variables, operations // or dynamic references, the parser can effectively 'skip' it, // treating it as a literal. // An example would be '1px solid #000' - which evaluates to itself, // we don't need to know what the individual components are. // The drawback, of course is that you don't get the benefits of // syntax-checking on the CSS. This gives us a 50% speed-up in the parser, // and a smaller speed-up in the code-gen. // // // Token matching is done with the `$` function, which either takes // a terminal string or regexp, or a non-terminal function to call. // It also takes care of moving all the indices forwards. // // less.Parser = function Parser(env) { var input, // LeSS input string i, // current index in `input` j, // current chunk temp, // temporarily holds a chunk's state, for backtracking memo, // temporarily holds `i`, when backtracking furthest, // furthest index the parser has gone to chunks, // chunkified input current, // index of current chunk, in `input` parser; var that = this; // This function is called after all files // have been imported through `@import`. var finish = function () {}; var imports = this.imports = { paths: env && env.paths || [], // Search paths, when importing queue: [], // Files which haven't been imported yet files: {}, // Holds the imported parse trees mime: env && env.mime, // MIME type of .less files error: null, // Error in parsing/evaluating an import push: function (path, callback) { var that = this; this.queue.push(path); // // Import a file asynchronously // less.Parser.importer(path, this.paths, function (e, root) { that.queue.splice(that.queue.indexOf(path), 1); // Remove the path from the queue that.files[path] = root; // Store the root if (e && !that.error) { that.error = e } callback(e, root); if (that.queue.length === 0) { finish() } // Call `finish` if we're done importing }, env); } }; function save() { temp = chunks[j], memo = i, current = i } function restore() { chunks[j] = temp, i = memo, current = i } function sync() { if (i > current) { chunks[j] = chunks[j].slice(i - current); current = i; } } // // Parse from a token, regexp or string, and move forward if match // function $(tok) { var match, args, length, c, index, endIndex, k, mem; // // Non-terminal // if (tok instanceof Function) { return tok.call(parser.parsers); // // Terminal // // Either match a single character in the input, // or match a regexp in the current chunk (chunk[j]). // } else if (typeof(tok) === 'string') { match = input.charAt(i) === tok ? tok : null; length = 1; sync (); } else { sync (); if (match = tok.exec(chunks[j])) { length = match[0].length; } else { return null; } } // The match is confirmed, add the match length to `i`, // and consume any extra white-space characters (' ' || '\n') // which come after that. The reason for this is that LeSS's // grammar is mostly white-space insensitive. // if (match) { mem = i += length; endIndex = i + chunks[j].length - length; while (i < endIndex) { c = input.charCodeAt(i); if (! (c === 32 || c === 10 || c === 9)) { break } i++; } chunks[j] = chunks[j].slice(length + (i - mem)); current = i; if (chunks[j].length === 0 && j < chunks.length - 1) { j++ } if(typeof(match) === 'string') { return match; } else { return match.length === 1 ? match[0] : match; } } } function expect(arg, msg) { var result = $(arg); if (! result) { error(msg || (typeof(arg) === 'string' ? "expected '" + arg + "' got '" + input.charAt(i) + "'" : "unexpected token")); } else { return result; } } function error(msg, type) { throw { index: i, type: type || 'Syntax', message: msg }; } // Same as $(), but don't change the state of the parser, // just return the match. function peek(tok) { if (typeof(tok) === 'string') { return input.charAt(i) === tok; } else { if (tok.test(chunks[j])) { return true; } else { return false; } } } function getLocation(index) { for (var n = index, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } return { line: index ? (input.slice(0, index).match(/\n/g) || "").length : null, column: column }; } function LessError(e, env) { var lines = input.split('\n'), loc = getLocation(e.index), line = loc.line, col = loc.column; this.type = e.type || 'SyntaxError'; this.message = e.message; this.filename = e.filename || env.filename; this.index = e.index; this.line = typeof(line) === 'number' ? line + 1 : null; this.callLine = e.call && (getLocation(e.call) + 1); this.callExtract = lines[getLocation(e.call)]; this.stack = e.stack; this.column = col; this.extract = [ lines[line - 1], lines[line], lines[line + 1] ]; } this.env = env = env || {}; // The optimization level dictates the thoroughness of the parser, // the lower the number, the less nodes it will create in the tree. // This could matter for debugging, or if you want to access // the individual nodes in the tree. this.optimization = ('optimization' in this.env) ? this.env.optimization : 1; this.env.filename = this.env.filename || null; // // The Parser // return parser = { imports: imports, // // Parse an input string into an abstract syntax tree, // call `callback` when done. // parse: function (str, callback) { var root, start, end, zone, line, lines, buff = [], c, error = null; i = j = current = furthest = 0; chunks = []; input = str.replace(/\r\n/g, '\n'); // Split the input into chunks. chunks = (function (chunks) { var j = 0, skip = /[^"'`\{\}\/\(\)]+/g, comment = /\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g, level = 0, match, chunk = chunks[0], inParam, inString; for (var i = 0, c, cc; i < input.length; i++) { skip.lastIndex = i; if (match = skip.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); } } c = input.charAt(i); comment.lastIndex = i; if (!inString && !inParam && c === '/') { cc = input.charAt(i + 1); if (cc === '/' || cc === '*') { if (match = comment.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); c = input.charAt(i); } } } } if (c === '{' && !inString && !inParam) { level ++; chunk.push(c); } else if (c === '}' && !inString && !inParam) { level --; chunk.push(c); chunks[++j] = chunk = []; } else if (c === '(' && !inString && !inParam) { chunk.push(c); inParam = true; } else if (c === ')' && !inString && inParam) { chunk.push(c); inParam = false; } else { if (c === '"' || c === "'" || c === '`') { if (! inString) { inString = c; } else { inString = inString === c ? false : inString; } } chunk.push(c); } } if (level > 0) { throw { type: 'Syntax', message: "Missing closing `}`", filename: env.filename }; } return chunks.map(function (c) { return c.join('') });; })([[]]); // Start with the primary rule. // The whole syntax tree is held under a Ruleset node, // with the `root` property set to true, so no `{}` are // output. The callback is called when the input is parsed. try { root = new(tree.Ruleset)([], $(this.parsers.primary)); root.root = true; } catch (e) { return callback(new(LessError)(e, env)); } root.toCSS = (function (evaluate) { var line, lines, column; return function (options, variables) { var frames = []; options = options || {}; // // Allows setting variables with a hash, so: // // `{ color: new(tree.Color)('#f01') }` will become: // // new(tree.Rule)('@color', // new(tree.Value)([ // new(tree.Expression)([ // new(tree.Color)('#f01') // ]) // ]) // ) // if (typeof(variables) === 'object' && !Array.isArray(variables)) { variables = Object.keys(variables).map(function (k) { var value = variables[k]; if (! (value instanceof tree.Value)) { if (! (value instanceof tree.Expression)) { value = new(tree.Expression)([value]); } value = new(tree.Value)([value]); } return new(tree.Rule)('@' + k, value, false, 0); }); frames = [new(tree.Ruleset)(null, variables)]; } try { var css = evaluate.call(this, { frames: frames }) .toCSS([], { compress: options.compress || false }); } catch (e) { throw new(LessError)(e, env); } if (parser.imports.error) { throw parser.imports.error } if (options.yuicompress && less.mode === 'node') { return require('./cssmin').compressor.cssmin(css); } else if (options.compress) { return css.replace(/(\s)+/g, "$1"); } else { return css; } }; })(root.eval); // If `i` is smaller than the `input.length - 1`, // it means the parser wasn't able to parse the whole // string, so we've got a parsing error. // // We try to extract a \n delimited string, // showing the line where the parse error occured. // We split it up into two parts (the part which parsed, // and the part which didn't), so we can color them differently. if (i < input.length - 1) { i = furthest; lines = input.split('\n'); line = (input.slice(0, i).match(/\n/g) || "").length + 1; for (var n = i, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } error = { type: "Parse", message: "Syntax Error on line " + line, index: i, filename: env.filename, line: line, column: column, extract: [ lines[line - 2], lines[line - 1], lines[line] ] }; } if (this.imports.queue.length > 0) { finish = function () { callback(error, root) }; } else { callback(error, root); } }, // // Here in, the parsing rules/functions // // The basic structure of the syntax tree generated is as follows: // // Ruleset -> Rule -> Value -> Expression -> Entity // // Here's some LESS code: // // .class { // color: #fff; // border: 1px solid #000; // width: @w + 4px; // > .child {...} // } // // And here's what the parse tree might look like: // // Ruleset (Selector '.class', [ // Rule ("color", Value ([Expression [Color #fff]])) // Rule ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]])) // Rule ("width", Value ([Expression [Operation "+" [Variable "@w"][Dimension 4px]]])) // Ruleset (Selector [Element '>', '.child'], [...]) // ]) // // In general, most rules will try to parse a token with the `$()` function, and if the return // value is truly, will return a new node, of the relevant type. Sometimes, we need to check // first, before parsing, that's when we use `peek()`. // parsers: { // // The `primary` rule is the *entry* and *exit* point of the parser. // The rules here can appear at any level of the parse tree. // // The recursive nature of the grammar is an interplay between the `block` // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule, // as represented by this simplified grammar: // // primary → (ruleset | rule)+ // ruleset → selector+ block // block → '{' primary '}' // // Only at one point is the primary rule not called from the // block rule: at the root level. // primary: function () { var node, root = []; while ((node = $(this.mixin.definition) || $(this.rule) || $(this.ruleset) || $(this.mixin.call) || $(this.comment) || $(this.directive)) || $(/^[\s\n]+/)) { node && root.push(node); } return root; }, // We create a Comment node for CSS comments `/* */`, // but keep the LeSS comments `//` silent, by just skipping // over them. comment: function () { var comment; if (input.charAt(i) !== '/') return; if (input.charAt(i + 1) === '/') { return new(tree.Comment)($(/^\/\/.*/), true); } else if (comment = $(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/)) { return new(tree.Comment)(comment); } }, // // Entities are tokens which can be found inside an Expression // entities: { // // A string, which supports escaping " and ' // // "milky way" 'he\'s the one!' // quoted: function () { var str, j = i, e; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '"' && input.charAt(j) !== "'") return; e && $('~'); if (str = $(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/)) { return new(tree.Quoted)(str[0], str[1] || str[2], e); } }, // // A catch-all word, such as: // // black border-collapse // keyword: function () { var k; if (k = $(/^[_A-Za-z-][_A-Za-z0-9-]*/)) { if (tree.colors.hasOwnProperty(k)) { // detect named color return new(tree.Color)(tree.colors[k].slice(1)); } else { return new(tree.Keyword)(k); } } }, // // A function call // // rgb(255, 0, 255) // // We also try to catch IE's `alpha()`, but let the `alpha` parser // deal with the details. // // The arguments are parsed with the `entities.arguments` parser. // call: function () { var name, args, index = i; if (! (name = /^([\w-]+|%|progid:[\w\.]+)\(/.exec(chunks[j]))) return; name = name[1].toLowerCase(); if (name === 'url') { return null } else { i += name.length } if (name === 'alpha') { return $(this.alpha) } $('('); // Parse the '(' and consume whitespace. args = $(this.entities.arguments); if (! $(')')) return; if (name) { return new(tree.Call)(name, args, index) } }, arguments: function () { var args = [], arg; while (arg = $(this.entities.assignment) || $(this.expression)) { args.push(arg); if (! $(',')) { break } } return args; }, literal: function () { return $(this.entities.dimension) || $(this.entities.color) || $(this.entities.quoted); }, // Assignments are argument entities for calls. // They are present in ie filter properties as shown below. // // filter: progid:DXImageTransform.Microsoft.Alpha( *opacity=50* ) // assignment: function () { var key, value; if ((key = $(/^\w+(?=\s?=)/i)) && $('=') && (value = $(this.entity))) { return new(tree.Assignment)(key, value); } }, // // Parse url() tokens // // We use a specific rule for urls, because they don't really behave like // standard function calls. The difference is that the argument doesn't have // to be enclosed within a string, so it can't be parsed as an Expression. // url: function () { var value; if (input.charAt(i) !== 'u' || !$(/^url\(/)) return; value = $(this.entities.quoted) || $(this.entities.variable) || $(this.entities.dataURI) || $(/^[-\w%@$\/.&=:;#+?~]+/) || ""; expect(')'); return new(tree.URL)((value.value || value.data || value instanceof tree.Variable) ? value : new(tree.Anonymous)(value), imports.paths); }, dataURI: function () { var obj; if ($(/^data:/)) { obj = {}; obj.mime = $(/^[^\/]+\/[^,;)]+/) || ''; obj.charset = $(/^;\s*charset=[^,;)]+/) || ''; obj.base64 = $(/^;\s*base64/) || ''; obj.data = $(/^,\s*[^)]+/); if (obj.data) { return obj } } }, // // A Variable entity, such as `@fink`, in // // width: @fink + 2px // // We use a different parser for variable definitions, // see `parsers.variable`. // variable: function () { var name, index = i; if (input.charAt(i) === '@' && (name = $(/^@@?[\w-]+/))) { return new(tree.Variable)(name, index); } }, // // A Hexadecimal color // // #4F3C2F // // `rgb` and `hsl` colors are parsed through the `entities.call` parser. // color: function () { var rgb; if (input.charAt(i) === '#' && (rgb = $(/^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})/))) { return new(tree.Color)(rgb[1]); } }, // // A Dimension, that is, a number and a unit // // 0.5em 95% // dimension: function () { var value, c = input.charCodeAt(i); if ((c > 57 || c < 45) || c === 47) return; if (value = $(/^(-?\d*\.?\d+)(px|%|em|rem|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn)?/)) { return new(tree.Dimension)(value[1], value[2]); } }, // // JavaScript code to be evaluated // // `window.location.href` // javascript: function () { var str, j = i, e; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '`') { return } e && $('~'); if (str = $(/^`([^`]*)`/)) { return new(tree.JavaScript)(str[1], i, e); } } }, // // The variable part of a variable definition. Used in the `rule` parser // // @fink: // variable: function () { var name; if (input.charAt(i) === '@' && (name = $(/^(@[\w-]+)\s*:/))) { return name[1] } }, // // A font size/line-height shorthand // // small/12px // // We need to peek first, or we'll match on keywords and dimensions // shorthand: function () { var a, b; if (! peek(/^[@\w.%-]+\/[@\w.-]+/)) return; if ((a = $(this.entity)) && $('/') && (b = $(this.entity))) { return new(tree.Shorthand)(a, b); } }, // // Mixins // mixin: { // // A Mixin call, with an optional argument list // // #mixins > .square(#fff); // .rounded(4px, black); // .button; // // The `while` loop is there because mixins can be // namespaced, but we only support the child and descendant // selector for now. // call: function () { var elements = [], e, c, args, index = i, s = input.charAt(i), important = false; if (s !== '.' && s !== '#') { return } while (e = $(/^[#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/)) { elements.push(new(tree.Element)(c, e, i)); c = $('>'); } $('(') && (args = $(this.entities.arguments)) && $(')'); if ($(this.important)) { important = true; } if (elements.length > 0 && ($(';') || peek('}'))) { return new(tree.mixin.Call)(elements, args, index, important); } }, // // A Mixin definition, with a list of parameters // // .rounded (@radius: 2px, @color) { // ... // } // // Until we have a finer grained state-machine, we have to // do a look-ahead, to make sure we don't have a mixin call. // See the `rule` function for more information. // // We start by matching `.rounded (`, and then proceed on to // the argument list, which has optional default values. // We store the parameters in `params`, with a `value` key, // if there is a value, such as in the case of `@radius`. // // Once we've got our params list, and a closing `)`, we parse // the `{...}` block. // definition: function () { var name, params = [], match, ruleset, param, value, cond; if ((input.charAt(i) !== '.' && input.charAt(i) !== '#') || peek(/^[^{]*(;|})/)) return; save(); if (match = $(/^([#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+)\s*\(/)) { name = match[1]; while (param = $(this.entities.variable) || $(this.entities.literal) || $(this.entities.keyword)) { // Variable if (param instanceof tree.Variable) { if ($(':')) { value = expect(this.expression, 'expected expression'); params.push({ name: param.name, value: value }); } else { params.push({ name: param.name }); } } else { params.push({ value: param }); } if (! $(',')) { break } } expect(')'); if ($(/^when/)) { // Guard cond = expect(this.conditions, 'expected condition'); } ruleset = $(this.block); if (ruleset) { return new(tree.mixin.Definition)(name, params, ruleset, cond); } else { restore(); } } } }, // // Entities are the smallest recognized token, // and can be found inside a rule's value. // entity: function () { return $(this.entities.literal) || $(this.entities.variable) || $(this.entities.url) || $(this.entities.call) || $(this.entities.keyword) || $(this.entities.javascript) || $(this.comment); }, // // A Rule terminator. Note that we use `peek()` to check for '}', // because the `block` rule will be expecting it, but we still need to make sure // it's there, if ';' was ommitted. // end: function () { return $(';') || peek('}'); }, // // IE's alpha function // // alpha(opacity=88) // alpha: function () { var value; if (! $(/^\(opacity=/i)) return; if (value = $(/^\d+/) || $(this.entities.variable)) { expect(')'); return new(tree.Alpha)(value); } }, // // A Selector Element // // div // + h1 // #socks // input[type="text"] // // Elements are the building blocks for Selectors, // they are made out of a `Combinator` (see combinator rule), // and an element name, such as a tag a class, or `*`. // element: function () { var e, t, c, v; c = $(this.combinator); e = $(/^(?:\d+\.\d+|\d+)%/) || $(/^(?:[.#]?|:*)(?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/) || $('*') || $(this.attribute) || $(/^\([^)@]+\)/); if (! e) { $('(') && (v = $(this.entities.variable)) && $(')') && (e = new(tree.Paren)(v)); } if (e) { return new(tree.Element)(c, e, i) } if (c.value && c.value.charAt(0) === '&') { return new(tree.Element)(c, null, i); } }, // // Combinators combine elements together, in a Selector. // // Because our parser isn't white-space sensitive, special care // has to be taken, when parsing the descendant combinator, ` `, // as it's an empty space. We have to check the previous character // in the input, to see if it's a ` ` character. More info on how // we deal with this in *combinator.js*. // combinator: function () { var match, c = input.charAt(i); if (c === '>' || c === '+' || c === '~') { i++; while (input.charAt(i) === ' ') { i++ } return new(tree.Combinator)(c); } else if (c === '&') { match = '&'; i++; if(input.charAt(i) === ' ') { match = '& '; } while (input.charAt(i) === ' ') { i++ } return new(tree.Combinator)(match); } else if (c === ':' && input.charAt(i + 1) === ':') { i += 2; while (input.charAt(i) === ' ') { i++ } return new(tree.Combinator)('::'); } else if (input.charAt(i - 1) === ' ') { return new(tree.Combinator)(" "); } else { return new(tree.Combinator)(null); } }, // // A CSS Selector // // .class > div + h1 // li a:hover // // Selectors are made out of one or more Elements, see above. // selector: function () { var sel, e, elements = [], c, match; while (e = $(this.element)) { c = input.charAt(i); elements.push(e) if (c === '{' || c === '}' || c === ';' || c === ',') { break } } if (elements.length > 0) { return new(tree.Selector)(elements) } }, tag: function () { return $(/^[a-zA-Z][a-zA-Z-]*[0-9]?/) || $('*'); }, attribute: function () { var attr = '', key, val, op; if (! $('[')) return; if (key = $(/^[a-zA-Z-]+/) || $(this.entities.quoted)) { if ((op = $(/^[|~*$^]?=/)) && (val = $(this.entities.quoted) || $(/^[\w-]+/))) { attr = [key, op, val.toCSS ? val.toCSS() : val].join(''); } else { attr = key } } if (! $(']')) return; if (attr) { return "[" + attr + "]" } }, // // The `block` rule is used by `ruleset` and `mixin.definition`. // It's a wrapper around the `primary` rule, with added `{}`. // block: function () { var content; if ($('{') && (content = $(this.primary)) && $('}')) { return content; } }, // // div, .class, body > p {...} // ruleset: function () { var selectors = [], s, rules, match; save(); while (s = $(this.selector)) { selectors.push(s); $(this.comment); if (! $(',')) { break } $(this.comment); } if (selectors.length > 0 && (rules = $(this.block))) { return new(tree.Ruleset)(selectors, rules); } else { // Backtrack furthest = i; restore(); } }, rule: function () { var name, value, c = input.charAt(i), important, match; save(); if (c === '.' || c === '#' || c === '&') { return } if (name = $(this.variable) || $(this.property)) { if ((name.charAt(0) != '@') && (match = /^([^@+\/'"*`(;{}-]*);/.exec(chunks[j]))) { i += match[0].length - 1; value = new(tree.Anonymous)(match[1]); } else if (name === "font") { value = $(this.font); } else { value = $(this.value); } important = $(this.important); if (value && $(this.end)) { return new(tree.Rule)(name, value, important, memo); } else { furthest = i; restore(); } } }, // // An @import directive // // @import "lib"; // // Depending on our environemnt, importing is done differently: // In the browser, it's an XHR request, in Node, it would be a // file-system operation. The function used for importing is // stored in `import`, which we pass to the Import constructor. // "import": function () { var path, features; if ($(/^@import\s+/) && (path = $(this.entities.quoted) || $(this.entities.url))) { features = $(this.mediaFeatures); if ($(';')) { return new(tree.Import)(path, imports, features); } } }, mediaFeature: function () { var nodes = []; do { if (e = $(this.entities.keyword)) { nodes.push(e); } else if ($('(')) { p = $(this.property); e = $(this.entity); if ($(')')) { if (p && e) { nodes.push(new(tree.Paren)(new(tree.Rule)(p, e, null, i, true))); } else if (e) { nodes.push(new(tree.Paren)(e)); } else { return null; } } else { return null } } } while (e); if (nodes.length > 0) { return new(tree.Expression)(nodes); } }, mediaFeatures: function () { var f, features = []; while (f = $(this.mediaFeature)) { features.push(f); if (! $(',')) { break } } return features.length > 0 ? features : null; }, media: function () { var features; if ($(/^@media/)) { features = $(this.mediaFeatures); if (rules = $(this.block)) { return new(tree.Directive)('@media', rules, features); } } }, // // A CSS Directive // // @charset "utf-8"; // directive: function () { var name, value, rules, types, e, nodes; if (input.charAt(i) !== '@') return; if (value = $(this['import']) || $(this.media)) { return value; } else if (name = $(/^@page|@keyframes/) || $(/^@(?:-webkit-|-moz-|-o-|-ms-)[a-z0-9-]+/)) { types = ($(/^[^{]+/) || '').trim(); if (rules = $(this.block)) { return new(tree.Directive)(name + " " + types, rules); } } else if (name = $(/^@[-a-z]+/)) { if (name === '@font-face') { if (rules = $(this.block)) { return new(tree.Directive)(name, rules); } } else if ((value = $(this.entity)) && $(';')) { return new(tree.Directive)(name, value); } } }, font: function () { var value = [], expression = [], weight, shorthand, font, e; while (e = $(this.shorthand) || $(this.entity)) { expression.push(e); } value.push(new(tree.Expression)(expression)); if ($(',')) { while (e = $(this.expression)) { value.push(e); if (! $(',')) { break } } } return new(tree.Value)(value); }, // // A Value is a comma-delimited list of Expressions // // font-family: Baskerville, Georgia, serif; // // In a Rule, a Value represents everything after the `:`, // and before the `;`. // value: function () { var e, expressions = [], important; while (e = $(this.expression)) { expressions.push(e); if (! $(',')) { break } } if (expressions.length > 0) { return new(tree.Value)(expressions); } }, important: function () { if (input.charAt(i) === '!') { return $(/^! *important/); } }, sub: function () { var e; if ($('(') && (e = $(this.expression)) && $(')')) { return e; } }, multiplication: function () { var m, a, op, operation; if (m = $(this.operand)) { while (!peek(/^\/\*/) && (op = ($('/') || $('*'))) && (a = $(this.operand))) { operation = new(tree.Operation)(op, [operation || m, a]); } return operation || m; } }, addition: function () { var m, a, op, operation; if (m = $(this.multiplication)) { while ((op = $(/^[-+]\s+/) || (input.charAt(i - 1) != ' ' && ($('+') || $('-')))) && (a = $(this.multiplication))) { operation = new(tree.Operation)(op, [operation || m, a]); } return operation || m; } }, conditions: function () { var a, b, index = i, condition; if (a = $(this.condition)) { while ($(',') && (b = $(this.condition))) { condition = new(tree.Condition)('or', condition || a, b, index); } return condition || a; } }, condition: function () { var a, b, c, op, index = i, negate = false; if ($(/^not/)) { negate = true } expect('('); if (a = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) { if (op = $(/^(?:>=|=<|[<=>])/)) { if (b = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) { c = new(tree.Condition)(op, a, b, index, negate); } else { error('expected expression'); } } else { c = new(tree.Condition)('=', a, new(tree.Keyword)('true'), index, negate); } expect(')'); return $(/^and/) ? new(tree.Condition)('and', c, $(this.condition)) : c; } }, // // An operand is anything that can be part of an operation, // such as a Color, or a Variable // operand: function () { var negate, p = input.charAt(i + 1); if (input.charAt(i) === '-' && (p === '@' || p === '(')) { negate = $('-') } var o = $(this.sub) || $(this.entities.dimension) || $(this.entities.color) || $(this.entities.variable) || $(this.entities.call); return negate ? new(tree.Operation)('*', [new(tree.Dimension)(-1), o]) : o; }, // // Expressions either represent mathematical operations, // or white-space delimited Entities. // // 1px solid black // @var * 2 // expression: function () { var e, delim, entities = [], d; while (e = $(this.addition) || $(this.entity)) { entities.push(e); } if (entities.length > 0) { return new(tree.Expression)(entities); } }, property: function () { var name; if (name = $(/^(\*?-?[-a-z_0-9]+)\s*:/)) { return name[1]; } } } }; }; if (less.mode === 'browser' || less.mode === 'rhino') { // // Used by `@import` directives // less.Parser.importer = function (path, paths, callback, env) { if (path.charAt(0) !== '/' && paths.length > 0) { path = paths[0] + path; } // We pass `true` as 3rd argument, to force the reload of the import. // This is so we can get the syntax tree as opposed to just the CSS output, // as we need this to evaluate the current stylesheet. loadStyleSheet({ href: path, title: path, type: env.mime }, callback, true); }; } (function (tree) { tree.functions = { rgb: function (r, g, b) { return this.rgba(r, g, b, 1.0); }, rgba: function (r, g, b, a) { var rgb = [r, g, b].map(function (c) { return number(c) }), a = number(a); return new(tree.Color)(rgb, a); }, hsl: function (h, s, l) { return this.hsla(h, s, l, 1.0); }, hsla: function (h, s, l, a) { h = (number(h) % 360) / 360; s = number(s); l = number(l); a = number(a); var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s; var m1 = l * 2 - m2; return this.rgba(hue(h + 1/3) * 255, hue(h) * 255, hue(h - 1/3) * 255, a); function hue(h) { h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h); if (h * 6 < 1) return m1 + (m2 - m1) * h * 6; else if (h * 2 < 1) return m2; else if (h * 3 < 2) return m1 + (m2 - m1) * (2/3 - h) * 6; else return m1; } }, hue: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().h)); }, saturation: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().s * 100), '%'); }, lightness: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().l * 100), '%'); }, alpha: function (color) { return new(tree.Dimension)(color.toHSL().a); }, saturate: function (color, amount) { var hsl = color.toHSL(); hsl.s += amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, desaturate: function (color, amount) { var hsl = color.toHSL(); hsl.s -= amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, lighten: function (color, amount) { var hsl = color.toHSL(); hsl.l += amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, darken: function (color, amount) { var hsl = color.toHSL(); hsl.l -= amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, fadein: function (color, amount) { var hsl = color.toHSL(); hsl.a += amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, fadeout: function (color, amount) { var hsl = color.toHSL(); hsl.a -= amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, fade: function (color, amount) { var hsl = color.toHSL(); hsl.a = amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, spin: function (color, amount) { var hsl = color.toHSL(); var hue = (hsl.h + amount.value) % 360; hsl.h = hue < 0 ? 360 + hue : hue; return hsla(hsl); }, // // Copyright (c) 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein // http://sass-lang.com // mix: function (color1, color2, weight) { var p = weight.value / 100.0; var w = p * 2 - 1; var a = color1.toHSL().a - color2.toHSL().a; var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0; var w2 = 1 - w1; var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2, color1.rgb[1] * w1 + color2.rgb[1] * w2, color1.rgb[2] * w1 + color2.rgb[2] * w2]; var alpha = color1.alpha * p + color2.alpha * (1 - p); return new(tree.Color)(rgb, alpha); }, greyscale: function (color) { return this.desaturate(color, new(tree.Dimension)(100)); }, e: function (str) { return new(tree.Anonymous)(str instanceof tree.JavaScript ? str.evaluated : str); }, escape: function (str) { return new(tree.Anonymous)(encodeURI(str.value).replace(/=/g, "%3D").replace(/:/g, "%3A").replace(/#/g, "%23").replace(/;/g, "%3B").replace(/\(/g, "%28").replace(/\)/g, "%29")); }, '%': function (quoted /* arg, arg, ...*/) { var args = Array.prototype.slice.call(arguments, 1), str = quoted.value; for (var i = 0; i < args.length; i++) { str = str.replace(/%[sda]/i, function(token) { var value = token.match(/s/i) ? args[i].value : args[i].toCSS(); return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value; }); } str = str.replace(/%%/g, '%'); return new(tree.Quoted)('"' + str + '"', str); }, round: function (n) { return this._math('round', n); }, ceil: function (n) { return this._math('ceil', n); }, floor: function (n) { return this._math('floor', n); }, _math: function (fn, n) { if (n instanceof tree.Dimension) { return new(tree.Dimension)(Math[fn](number(n)), n.unit); } else if (typeof(n) === 'number') { return Math[fn](n); } else { throw { type: "Argument", message: "argument must be a number" }; } }, argb: function (color) { return new(tree.Anonymous)(color.toARGB()); }, percentage: function (n) { return new(tree.Dimension)(n.value * 100, '%'); }, color: function (n) { if (n instanceof tree.Quoted) { return new(tree.Color)(n.value.slice(1)); } else { throw { type: "Argument", message: "argument must be a string" }; } }, iscolor: function (n) { return this._isa(n, tree.Color); }, isnumber: function (n) { return this._isa(n, tree.Dimension); }, isstring: function (n) { return this._isa(n, tree.Quoted); }, iskeyword: function (n) { return this._isa(n, tree.Keyword); }, isurl: function (n) { return this._isa(n, tree.URL); }, ispixel: function (n) { return (n instanceof tree.Dimension) && n.unit === 'px' ? tree.True : tree.False; }, ispercentage: function (n) { return (n instanceof tree.Dimension) && n.unit === '%' ? tree.True : tree.False; }, isem: function (n) { return (n instanceof tree.Dimension) && n.unit === 'em' ? tree.True : tree.False; }, _isa: function (n, Type) { return (n instanceof Type) ? tree.True : tree.False; } }; function hsla(hsla) { return tree.functions.hsla(hsla.h, hsla.s, hsla.l, hsla.a); } function number(n) { if (n instanceof tree.Dimension) { return parseFloat(n.unit == '%' ? n.value / 100 : n.value); } else if (typeof(n) === 'number') { return n; } else { throw { error: "RuntimeError", message: "color functions take numbers as parameters" }; } } function clamp(val) { return Math.min(1, Math.max(0, val)); } })(require('./tree')); (function (tree) { tree.colors = { 'aliceblue':'#f0f8ff', 'antiquewhite':'#faebd7', 'aqua':'#00ffff', 'aquamarine':'#7fffd4', 'azure':'#f0ffff', 'beige':'#f5f5dc', 'bisque':'#ffe4c4', 'black':'#000000', 'blanchedalmond':'#ffebcd', 'blue':'#0000ff', 'blueviolet':'#8a2be2', 'brown':'#a52a2a', 'burlywood':'#deb887', 'cadetblue':'#5f9ea0', 'chartreuse':'#7fff00', 'chocolate':'#d2691e', 'coral':'#ff7f50', 'cornflowerblue':'#6495ed', 'cornsilk':'#fff8dc', 'crimson':'#dc143c', 'cyan':'#00ffff', 'darkblue':'#00008b', 'darkcyan':'#008b8b', 'darkgoldenrod':'#b8860b', 'darkgray':'#a9a9a9', 'darkgrey':'#a9a9a9', 'darkgreen':'#006400', 'darkkhaki':'#bdb76b', 'darkmagenta':'#8b008b', 'darkolivegreen':'#556b2f', 'darkorange':'#ff8c00', 'darkorchid':'#9932cc', 'darkred':'#8b0000', 'darksalmon':'#e9967a', 'darkseagreen':'#8fbc8f', 'darkslateblue':'#483d8b', 'darkslategray':'#2f4f4f', 'darkslategrey':'#2f4f4f', 'darkturquoise':'#00ced1', 'darkviolet':'#9400d3', 'deeppink':'#ff1493', 'deepskyblue':'#00bfff', 'dimgray':'#696969', 'dimgrey':'#696969', 'dodgerblue':'#1e90ff', 'firebrick':'#b22222', 'floralwhite':'#fffaf0', 'forestgreen':'#228b22', 'fuchsia':'#ff00ff', 'gainsboro':'#dcdcdc', 'ghostwhite':'#f8f8ff', 'gold':'#ffd700', 'goldenrod':'#daa520', 'gray':'#808080', 'grey':'#808080', 'green':'#008000', 'greenyellow':'#adff2f', 'honeydew':'#f0fff0', 'hotpink':'#ff69b4', 'indianred':'#cd5c5c', 'indigo':'#4b0082', 'ivory':'#fffff0', 'khaki':'#f0e68c', 'lavender':'#e6e6fa', 'lavenderblush':'#fff0f5', 'lawngreen':'#7cfc00', 'lemonchiffon':'#fffacd', 'lightblue':'#add8e6', 'lightcoral':'#f08080', 'lightcyan':'#e0ffff', 'lightgoldenrodyellow':'#fafad2', 'lightgray':'#d3d3d3', 'lightgrey':'#d3d3d3', 'lightgreen':'#90ee90', 'lightpink':'#ffb6c1', 'lightsalmon':'#ffa07a', 'lightseagreen':'#20b2aa', 'lightskyblue':'#87cefa', 'lightslategray':'#778899', 'lightslategrey':'#778899', 'lightsteelblue':'#b0c4de', 'lightyellow':'#ffffe0', 'lime':'#00ff00', 'limegreen':'#32cd32', 'linen':'#faf0e6', 'magenta':'#ff00ff', 'maroon':'#800000', 'mediumaquamarine':'#66cdaa', 'mediumblue':'#0000cd', 'mediumorchid':'#ba55d3', 'mediumpurple':'#9370d8', 'mediumseagreen':'#3cb371', 'mediumslateblue':'#7b68ee', 'mediumspringgreen':'#00fa9a', 'mediumturquoise':'#48d1cc', 'mediumvioletred':'#c71585', 'midnightblue':'#191970', 'mintcream':'#f5fffa', 'mistyrose':'#ffe4e1', 'moccasin':'#ffe4b5', 'navajowhite':'#ffdead', 'navy':'#000080', 'oldlace':'#fdf5e6', 'olive':'#808000', 'olivedrab':'#6b8e23', 'orange':'#ffa500', 'orangered':'#ff4500', 'orchid':'#da70d6', 'palegoldenrod':'#eee8aa', 'palegreen':'#98fb98', 'paleturquoise':'#afeeee', 'palevioletred':'#d87093', 'papayawhip':'#ffefd5', 'peachpuff':'#ffdab9', 'peru':'#cd853f', 'pink':'#ffc0cb', 'plum':'#dda0dd', 'powderblue':'#b0e0e6', 'purple':'#800080', 'red':'#ff0000', 'rosybrown':'#bc8f8f', 'royalblue':'#4169e1', 'saddlebrown':'#8b4513', 'salmon':'#fa8072', 'sandybrown':'#f4a460', 'seagreen':'#2e8b57', 'seashell':'#fff5ee', 'sienna':'#a0522d', 'silver':'#c0c0c0', 'skyblue':'#87ceeb', 'slateblue':'#6a5acd', 'slategray':'#708090', 'slategrey':'#708090', 'snow':'#fffafa', 'springgreen':'#00ff7f', 'steelblue':'#4682b4', 'tan':'#d2b48c', 'teal':'#008080', 'thistle':'#d8bfd8', 'tomato':'#ff6347', 'turquoise':'#40e0d0', 'violet':'#ee82ee', 'wheat':'#f5deb3', 'white':'#ffffff', 'whitesmoke':'#f5f5f5', 'yellow':'#ffff00', 'yellowgreen':'#9acd32' }; })(require('./tree')); (function (tree) { tree.Alpha = function (val) { this.value = val; }; tree.Alpha.prototype = { toCSS: function () { return "alpha(opacity=" + (this.value.toCSS ? this.value.toCSS() : this.value) + ")"; }, eval: function (env) { if (this.value.eval) { this.value = this.value.eval(env) } return this; } }; })(require('../tree')); (function (tree) { tree.Anonymous = function (string) { this.value = string.value || string; }; tree.Anonymous.prototype = { toCSS: function () { return this.value; }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.Assignment = function (key, val) { this.key = key; this.value = val; }; tree.Assignment.prototype = { toCSS: function () { return this.key + '=' + (this.value.toCSS ? this.value.toCSS() : this.value); }, eval: function (env) { if (this.value.eval) { this.value = this.value.eval(env) } return this; } }; })(require('../tree'));(function (tree) { // // A function call node. // tree.Call = function (name, args, index) { this.name = name; this.args = args; this.index = index; }; tree.Call.prototype = { // // When evaluating a function call, // we either find the function in `tree.functions` [1], // in which case we call it, passing the evaluated arguments, // or we simply print it out as it appeared originally [2]. // // The *functions.js* file contains the built-in functions. // // The reason why we evaluate the arguments, is in the case where // we try to pass a variable to a function, like: `saturate(@color)`. // The function should receive the value, not the variable. // eval: function (env) { var args = this.args.map(function (a) { return a.eval(env) }); if (this.name in tree.functions) { // 1. try { return tree.functions[this.name].apply(tree.functions, args); } catch (e) { throw { type: e.type || "Runtime", message: "error evaluating function `" + this.name + "`" + (e.message ? ': ' + e.message : ''), index: this.index }; } } else { // 2. return new(tree.Anonymous)(this.name + "(" + args.map(function (a) { return a.toCSS() }).join(', ') + ")"); } }, toCSS: function (env) { return this.eval(env).toCSS(); } }; })(require('../tree')); (function (tree) { // // RGB Colors - #ff0014, #eee // tree.Color = function (rgb, a) { // // The end goal here, is to parse the arguments // into an integer triplet, such as `128, 255, 0` // // This facilitates operations and conversions. // if (Array.isArray(rgb)) { this.rgb = rgb; } else if (rgb.length == 6) { this.rgb = rgb.match(/.{2}/g).map(function (c) { return parseInt(c, 16); }); } else { this.rgb = rgb.split('').map(function (c) { return parseInt(c + c, 16); }); } this.alpha = typeof(a) === 'number' ? a : 1; }; tree.Color.prototype = { eval: function () { return this }, // // If we have some transparency, the only way to represent it // is via `rgba`. Otherwise, we use the hex representation, // which has better compatibility with older browsers. // Values are capped between `0` and `255`, rounded and zero-padded. // toCSS: function () { if (this.alpha < 1.0) { return "rgba(" + this.rgb.map(function (c) { return Math.round(c); }).concat(this.alpha).join(', ') + ")"; } else { return '#' + this.rgb.map(function (i) { i = Math.round(i); i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16); return i.length === 1 ? '0' + i : i; }).join(''); } }, // // Operations have to be done per-channel, if not, // channels will spill onto each other. Once we have // our result, in the form of an integer triplet, // we create a new Color node to hold the result. // operate: function (op, other) { var result = []; if (! (other instanceof tree.Color)) { other = other.toColor(); } for (var c = 0; c < 3; c++) { result[c] = tree.operate(op, this.rgb[c], other.rgb[c]); } return new(tree.Color)(result, this.alpha + other.alpha); }, toHSL: function () { var r = this.rgb[0] / 255, g = this.rgb[1] / 255, b = this.rgb[2] / 255, a = this.alpha; var max = Math.max(r, g, b), min = Math.min(r, g, b); var h, s, l = (max + min) / 2, d = max - min; if (max === min) { h = s = 0; } else { s = l > 0.5 ? d / (2 - max - min) : d / (max + min); switch (max) { case r: h = (g - b) / d + (g < b ? 6 : 0); break; case g: h = (b - r) / d + 2; break; case b: h = (r - g) / d + 4; break; } h /= 6; } return { h: h * 360, s: s, l: l, a: a }; }, toARGB: function () { var argb = [Math.round(this.alpha * 255)].concat(this.rgb); return '#' + argb.map(function (i) { i = Math.round(i); i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16); return i.length === 1 ? '0' + i : i; }).join(''); } }; })(require('../tree')); (function (tree) { tree.Comment = function (value, silent) { this.value = value; this.silent = !!silent; }; tree.Comment.prototype = { toCSS: function (env) { return env.compress ? '' : this.value; }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.Condition = function (op, l, r, i, negate) { this.op = op.trim(); this.lvalue = l; this.rvalue = r; this.index = i; this.negate = negate; }; tree.Condition.prototype.eval = function (env) { var a = this.lvalue.eval(env), b = this.rvalue.eval(env); var i = this.index, result var result = (function (op) { switch (op) { case 'and': return a && b; case 'or': return a || b; default: if (a.compare) { result = a.compare(b); } else if (b.compare) { result = b.compare(a); } else { throw { type: "Type", message: "Unable to perform comparison", index: i }; } switch (result) { case -1: return op === '<' || op === '=<'; case 0: return op === '=' || op === '>=' || op === '=<'; case 1: return op === '>' || op === '>='; } } })(this.op); return this.negate ? !result : result; }; })(require('../tree')); (function (tree) { // // A number with a unit // tree.Dimension = function (value, unit) { this.value = parseFloat(value); this.unit = unit || null; }; tree.Dimension.prototype = { eval: function () { return this }, toColor: function () { return new(tree.Color)([this.value, this.value, this.value]); }, toCSS: function () { var css = this.value + this.unit; return css; }, // In an operation between two Dimensions, // we default to the first Dimension's unit, // so `1px + 2em` will yield `3px`. // In the future, we could implement some unit // conversions such that `100cm + 10mm` would yield // `101cm`. operate: function (op, other) { return new(tree.Dimension) (tree.operate(op, this.value, other.value), this.unit || other.unit); }, // TODO: Perform unit conversion before comparing compare: function (other) { if (other instanceof tree.Dimension) { if (other.value > this.value) { return -1; } else if (other.value < this.value) { return 1; } else { return 0; } } else { return -1; } } }; })(require('../tree')); (function (tree) { tree.Directive = function (name, value, features) { this.name = name; this.features = features && new(tree.Value)(features); if (Array.isArray(value)) { this.ruleset = new(tree.Ruleset)([], value); this.ruleset.allowImports = true; } else { this.value = value; } }; tree.Directive.prototype = { toCSS: function (ctx, env) { var features = this.features ? ' ' + this.features.toCSS(env) : ''; if (this.ruleset) { this.ruleset.root = true; return this.name + features + (env.compress ? '{' : ' {\n ') + this.ruleset.toCSS(ctx, env).trim().replace(/\n/g, '\n ') + (env.compress ? '}': '\n}\n'); } else { return this.name + ' ' + this.value.toCSS() + ';\n'; } }, eval: function (env) { this.features = this.features && this.features.eval(env); env.frames.unshift(this); this.ruleset = this.ruleset && this.ruleset.eval(env); env.frames.shift(); return this; }, variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) }, find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) }, rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) } }; })(require('../tree')); (function (tree) { tree.Element = function (combinator, value, index) { this.combinator = combinator instanceof tree.Combinator ? combinator : new(tree.Combinator)(combinator); if (typeof(value) === 'string') { this.value = value.trim(); } else if (value) { this.value = value; } else { this.value = ""; } this.index = index; }; tree.Element.prototype.eval = function (env) { return new(tree.Element)(this.combinator, this.value.eval ? this.value.eval(env) : this.value, this.index); }; tree.Element.prototype.toCSS = function (env) { return this.combinator.toCSS(env || {}) + (this.value.toCSS ? this.value.toCSS(env) : this.value); }; tree.Combinator = function (value) { if (value === ' ') { this.value = ' '; } else if (value === '& ') { this.value = '& '; } else { this.value = value ? value.trim() : ""; } }; tree.Combinator.prototype.toCSS = function (env) { return { '' : '', ' ' : ' ', '&' : '', '& ' : ' ', ':' : ' :', '::': '::', '+' : env.compress ? '+' : ' + ', '~' : env.compress ? '~' : ' ~ ', '>' : env.compress ? '>' : ' > ' }[this.value]; }; })(require('../tree')); (function (tree) { tree.Expression = function (value) { this.value = value }; tree.Expression.prototype = { eval: function (env) { if (this.value.length > 1) { return new(tree.Expression)(this.value.map(function (e) { return e.eval(env); })); } else if (this.value.length === 1) { return this.value[0].eval(env); } else { return this; } }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS ? e.toCSS(env) : ''; }).join(' '); } }; })(require('../tree')); (function (tree) { // // CSS @import node // // The general strategy here is that we don't want to wait // for the parsing to be completed, before we start importing // the file. That's because in the context of a browser, // most of the time will be spent waiting for the server to respond. // // On creation, we push the import path to our import queue, though // `import,push`, we also pass it a callback, which it'll call once // the file has been fetched, and parsed. // tree.Import = function (path, imports, features) { var that = this; this._path = path; this.features = features && new(tree.Value)(features); // The '.less' extension is optional if (path instanceof tree.Quoted) { this.path = /\.(le?|c)ss(\?.*)?$/.test(path.value) ? path.value : path.value + '.less'; } else { this.path = path.value.value || path.value; } this.css = /css(\?.*)?$/.test(this.path); // Only pre-compile .less files if (! this.css) { imports.push(this.path, function (e, root) { that.root = root; }); } }; // // The actual import node doesn't return anything, when converted to CSS. // The reason is that it's used at the evaluation stage, so that the rules // it imports can be treated like any other rules. // // In `eval`, we make sure all Import nodes get evaluated, recursively, so // we end up with a flat structure, which can easily be imported in the parent // ruleset. // tree.Import.prototype = { toCSS: function (env) { var features = this.features ? ' ' + this.features.toCSS(env) : ''; if (this.css) { return "@import " + this._path.toCSS() + features + ';\n'; } else { return ""; } }, eval: function (env) { var ruleset, features = this.features && this.features.eval(env); if (this.css) { return this; } else { ruleset = new(tree.Ruleset)([], this.root.rules.slice(0)); for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.Import) { Array.prototype .splice .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env))); } } return this.features ? new(tree.Directive)('@media', ruleset.rules, this.features.value) : ruleset.rules; } } }; })(require('../tree')); (function (tree) { tree.JavaScript = function (string, index, escaped) { this.escaped = escaped; this.expression = string; this.index = index; }; tree.JavaScript.prototype = { eval: function (env) { var result, that = this, context = {}; var expression = this.expression.replace(/@\{([\w-]+)\}/g, function (_, name) { return tree.jsify(new(tree.Variable)('@' + name, that.index).eval(env)); }); try { expression = new(Function)('return (' + expression + ')'); } catch (e) { throw { message: "JavaScript evaluation error: `" + expression + "`" , index: this.index }; } for (var k in env.frames[0].variables()) { context[k.slice(1)] = { value: env.frames[0].variables()[k].value, toJS: function () { return this.value.eval(env).toCSS(); } }; } try { result = expression.call(context); } catch (e) { throw { message: "JavaScript evaluation error: '" + e.name + ': ' + e.message + "'" , index: this.index }; } if (typeof(result) === 'string') { return new(tree.Quoted)('"' + result + '"', result, this.escaped, this.index); } else if (Array.isArray(result)) { return new(tree.Anonymous)(result.join(', ')); } else { return new(tree.Anonymous)(result); } } }; })(require('../tree')); (function (tree) { tree.Keyword = function (value) { this.value = value }; tree.Keyword.prototype = { eval: function () { return this }, toCSS: function () { return this.value }, compare: function (other) { if (other instanceof tree.Keyword) { return other.value === this.value ? 0 : 1; } else { return -1; } } }; tree.True = new(tree.Keyword)('true'); tree.False = new(tree.Keyword)('false'); })(require('../tree')); (function (tree) { tree.mixin = {}; tree.mixin.Call = function (elements, args, index, important) { this.selector = new(tree.Selector)(elements); this.arguments = args; this.index = index; this.important = important; }; tree.mixin.Call.prototype = { eval: function (env) { var mixins, args, rules = [], match = false; for (var i = 0; i < env.frames.length; i++) { if ((mixins = env.frames[i].find(this.selector)).length > 0) { args = this.arguments && this.arguments.map(function (a) { return a.eval(env) }); for (var m = 0; m < mixins.length; m++) { if (mixins[m].match(args, env)) { try { Array.prototype.push.apply( rules, mixins[m].eval(env, this.arguments, this.important).rules); match = true; } catch (e) { throw { message: e.message, index: e.index, stack: e.stack, call: this.index }; } } } if (match) { return rules; } else { throw { type: 'Runtime', message: 'No matching definition was found for `' + this.selector.toCSS().trim() + '(' + this.arguments.map(function (a) { return a.toCSS(); }).join(', ') + ")`", index: this.index }; } } } throw { type: 'Name', message: this.selector.toCSS().trim() + " is undefined", index: this.index }; } }; tree.mixin.Definition = function (name, params, rules, condition) { this.name = name; this.selectors = [new(tree.Selector)([new(tree.Element)(null, name)])]; this.params = params; this.condition = condition; this.arity = params.length; this.rules = rules; this._lookups = {}; this.required = params.reduce(function (count, p) { if (!p.name || (p.name && !p.value)) { return count + 1 } else { return count } }, 0); this.parent = tree.Ruleset.prototype; this.frames = []; }; tree.mixin.Definition.prototype = { toCSS: function () { return "" }, variable: function (name) { return this.parent.variable.call(this, name) }, variables: function () { return this.parent.variables.call(this) }, find: function () { return this.parent.find.apply(this, arguments) }, rulesets: function () { return this.parent.rulesets.apply(this) }, evalParams: function (env, args) { var frame = new(tree.Ruleset)(null, []); for (var i = 0, val; i < this.params.length; i++) { if (this.params[i].name) { if (val = (args && args[i]) || this.params[i].value) { frame.rules.unshift(new(tree.Rule)(this.params[i].name, val.eval(env))); } else { throw { type: 'Runtime', message: "wrong number of arguments for " + this.name + ' (' + args.length + ' for ' + this.arity + ')' }; } } } return frame; }, eval: function (env, args, important) { var frame = this.evalParams(env, args), context, _arguments = [], rules; for (var i = 0; i < Math.max(this.params.length, args && args.length); i++) { _arguments.push(args[i] || this.params[i].value); } frame.rules.unshift(new(tree.Rule)('@arguments', new(tree.Expression)(_arguments).eval(env))); rules = important ? this.rules.map(function (r) { return new(tree.Rule)(r.name, r.value, '!important', r.index); }) : this.rules.slice(0); return new(tree.Ruleset)(null, rules).eval({ frames: [this, frame].concat(this.frames, env.frames) }); }, match: function (args, env) { var argsLength = (args && args.length) || 0, len, frame; if (argsLength < this.required) { return false } if ((this.required > 0) && (argsLength > this.params.length)) { return false } if (this.condition && !this.condition.eval({ frames: [this.evalParams(env, args)].concat(env.frames) })) { return false } len = Math.min(argsLength, this.arity); for (var i = 0; i < len; i++) { if (!this.params[i].name) { if (args[i].eval(env).toCSS() != this.params[i].value.eval(env).toCSS()) { return false; } } } return true; } }; })(require('../tree')); (function (tree) { tree.Operation = function (op, operands) { this.op = op.trim(); this.operands = operands; }; tree.Operation.prototype.eval = function (env) { var a = this.operands[0].eval(env), b = this.operands[1].eval(env), temp; if (a instanceof tree.Dimension && b instanceof tree.Color) { if (this.op === '*' || this.op === '+') { temp = b, b = a, a = temp; } else { throw { name: "OperationError", message: "Can't substract or divide a color from a number" }; } } return a.operate(this.op, b); }; tree.operate = function (op, a, b) { switch (op) { case '+': return a + b; case '-': return a - b; case '*': return a * b; case '/': return a / b; } }; })(require('../tree')); (function (tree) { tree.Paren = function (node) { this.value = node; }; tree.Paren.prototype = { toCSS: function (env) { return '(' + this.value.toCSS(env) + ')'; }, eval: function (env) { return new(tree.Paren)(this.value.eval(env)); } }; })(require('../tree')); (function (tree) { tree.Quoted = function (str, content, escaped, i) { this.escaped = escaped; this.value = content || ''; this.quote = str.charAt(0); this.index = i; }; tree.Quoted.prototype = { toCSS: function () { if (this.escaped) { return this.value; } else { return this.quote + this.value + this.quote; } }, eval: function (env) { var that = this; var value = this.value.replace(/`([^`]+)`/g, function (_, exp) { return new(tree.JavaScript)(exp, that.index, true).eval(env).value; }).replace(/@\{([\w-]+)\}/g, function (_, name) { var v = new(tree.Variable)('@' + name, that.index).eval(env); return ('value' in v) ? v.value : v.toCSS(); }); return new(tree.Quoted)(this.quote + value + this.quote, value, this.escaped, this.index); } }; })(require('../tree')); (function (tree) { tree.Rule = function (name, value, important, index, inline) { this.name = name; this.value = (value instanceof tree.Value) ? value : new(tree.Value)([value]); this.important = important ? ' ' + important.trim() : ''; this.index = index; this.inline = inline || false; if (name.charAt(0) === '@') { this.variable = true; } else { this.variable = false } }; tree.Rule.prototype.toCSS = function (env) { if (this.variable) { return "" } else { return this.name + (env.compress ? ':' : ': ') + this.value.toCSS(env) + this.important + (this.inline ? "" : ";"); } }; tree.Rule.prototype.eval = function (context) { return new(tree.Rule)(this.name, this.value.eval(context), this.important, this.index, this.inline); }; tree.Shorthand = function (a, b) { this.a = a; this.b = b; }; tree.Shorthand.prototype = { toCSS: function (env) { return this.a.toCSS(env) + "/" + this.b.toCSS(env); }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.Ruleset = function (selectors, rules) { this.selectors = selectors; this.rules = rules; this._lookups = {}; }; tree.Ruleset.prototype = { eval: function (env) { var selectors = this.selectors && this.selectors.map(function (s) { return s.eval(env) }); var ruleset = new(tree.Ruleset)(selectors, this.rules.slice(0)); ruleset.root = this.root; ruleset.allowImports = this.allowImports; // push the current ruleset to the frames stack env.frames.unshift(ruleset); // Evaluate imports if (ruleset.root || ruleset.allowImports) { for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.Import) { Array.prototype.splice .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env))); } } } // Store the frames around mixin definitions, // so they can be evaluated like closures when the time comes. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Definition) { ruleset.rules[i].frames = env.frames.slice(0); } } // Evaluate mixin calls. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Call) { Array.prototype.splice .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env))); } } // Evaluate everything else for (var i = 0, rule; i < ruleset.rules.length; i++) { rule = ruleset.rules[i]; if (! (rule instanceof tree.mixin.Definition)) { ruleset.rules[i] = rule.eval ? rule.eval(env) : rule; } } // Pop the stack env.frames.shift(); return ruleset; }, match: function (args) { return !args || args.length === 0; }, variables: function () { if (this._variables) { return this._variables } else { return this._variables = this.rules.reduce(function (hash, r) { if (r instanceof tree.Rule && r.variable === true) { hash[r.name] = r; } return hash; }, {}); } }, variable: function (name) { return this.variables()[name]; }, rulesets: function () { if (this._rulesets) { return this._rulesets } else { return this._rulesets = this.rules.filter(function (r) { return (r instanceof tree.Ruleset) || (r instanceof tree.mixin.Definition); }); } }, find: function (selector, self) { self = self || this; var rules = [], rule, match, key = selector.toCSS(); if (key in this._lookups) { return this._lookups[key] } this.rulesets().forEach(function (rule) { if (rule !== self) { for (var j = 0; j < rule.selectors.length; j++) { if (match = selector.match(rule.selectors[j])) { if (selector.elements.length > rule.selectors[j].elements.length) { Array.prototype.push.apply(rules, rule.find( new(tree.Selector)(selector.elements.slice(1)), self)); } else { rules.push(rule); } break; } } } }); return this._lookups[key] = rules; }, // // Entry point for code generation // // `context` holds an array of arrays. // toCSS: function (context, env) { var css = [], // The CSS output rules = [], // node.Rule instances rulesets = [], // node.Ruleset instances paths = [], // Current selectors selector, // The fully rendered selector rule; if (! this.root) { if (context.length === 0) { paths = this.selectors.map(function (s) { return [s] }); } else { this.joinSelectors(paths, context, this.selectors); } } // Compile rules and rulesets for (var i = 0; i < this.rules.length; i++) { rule = this.rules[i]; if (rule.rules || (rule instanceof tree.Directive)) { rulesets.push(rule.toCSS(paths, env)); } else if (rule instanceof tree.Comment) { if (!rule.silent) { if (this.root) { rulesets.push(rule.toCSS(env)); } else { rules.push(rule.toCSS(env)); } } } else { if (rule.toCSS && !rule.variable) { rules.push(rule.toCSS(env)); } else if (rule.value && !rule.variable) { rules.push(rule.value.toString()); } } } rulesets = rulesets.join(''); // If this is the root node, we don't render // a selector, or {}. // Otherwise, only output if this ruleset has rules. if (this.root) { css.push(rules.join(env.compress ? '' : '\n')); } else { if (rules.length > 0) { selector = paths.map(function (p) { return p.map(function (s) { return s.toCSS(env); }).join('').trim(); }).join(env.compress ? ',' : (paths.length > 3 ? ',\n' : ', ')); css.push(selector, (env.compress ? '{' : ' {\n ') + rules.join(env.compress ? '' : '\n ') + (env.compress ? '}' : '\n}\n')); } } css.push(rulesets); return css.join('') + (env.compress ? '\n' : ''); }, joinSelectors: function (paths, context, selectors) { for (var s = 0; s < selectors.length; s++) { this.joinSelector(paths, context, selectors[s]); } }, joinSelector: function (paths, context, selector) { var before = [], after = [], beforeElements = [], afterElements = [], hasParentSelector = false, el; for (var i = 0; i < selector.elements.length; i++) { el = selector.elements[i]; if (el.combinator.value.charAt(0) === '&') { hasParentSelector = true; } if (hasParentSelector) afterElements.push(el); else beforeElements.push(el); } if (! hasParentSelector) { afterElements = beforeElements; beforeElements = []; } if (beforeElements.length > 0) { before.push(new(tree.Selector)(beforeElements)); } if (afterElements.length > 0) { after.push(new(tree.Selector)(afterElements)); } for (var c = 0; c < context.length; c++) { paths.push(before.concat(context[c]).concat(after)); } } }; })(require('../tree')); (function (tree) { tree.Selector = function (elements) { this.elements = elements; if (this.elements[0].combinator.value === "") { this.elements[0].combinator.value = ' '; } }; tree.Selector.prototype.match = function (other) { var len = this.elements.length, olen = other.elements.length, max = Math.min(len, olen); if (len < olen) { return false; } else { for (var i = 0; i < max; i++) { if (this.elements[i].value !== other.elements[i].value) { return false; } } } return true; }; tree.Selector.prototype.eval = function (env) { return new(tree.Selector)(this.elements.map(function (e) { return e.eval(env); })); }; tree.Selector.prototype.toCSS = function (env) { if (this._css) { return this._css } return this._css = this.elements.map(function (e) { if (typeof(e) === 'string') { return ' ' + e.trim(); } else { return e.toCSS(env); } }).join(''); }; })(require('../tree')); (function (tree) { tree.URL = function (val, paths) { if (val.data) { this.attrs = val; } else { // Add the base path if the URL is relative and we are in the browser if (typeof(window) !== 'undefined' && !/^(?:https?:\/\/|file:\/\/|data:|\/)/.test(val.value) && paths.length > 0) { val.value = paths[0] + (val.value.charAt(0) === '/' ? val.value.slice(1) : val.value); } this.value = val; this.paths = paths; } }; tree.URL.prototype = { toCSS: function () { return "url(" + (this.attrs ? 'data:' + this.attrs.mime + this.attrs.charset + this.attrs.base64 + this.attrs.data : this.value.toCSS()) + ")"; }, eval: function (ctx) { return this.attrs ? this : new(tree.URL)(this.value.eval(ctx), this.paths); } }; })(require('../tree')); (function (tree) { tree.Value = function (value) { this.value = value; this.is = 'value'; }; tree.Value.prototype = { eval: function (env) { if (this.value.length === 1) { return this.value[0].eval(env); } else { return new(tree.Value)(this.value.map(function (v) { return v.eval(env); })); } }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS(env); }).join(env.compress ? ',' : ', '); } }; })(require('../tree')); (function (tree) { tree.Variable = function (name, index) { this.name = name, this.index = index }; tree.Variable.prototype = { eval: function (env) { var variable, v, name = this.name; if (name.indexOf('@@') == 0) { name = '@' + new(tree.Variable)(name.slice(1)).eval(env).value; } if (variable = tree.find(env.frames, function (frame) { if (v = frame.variable(name)) { return v.value.eval(env); } })) { return variable } else { throw { message: "variable " + name + " is undefined", index: this.index }; } } }; })(require('../tree')); (function (tree) { tree.find = function (obj, fun) { for (var i = 0, r; i < obj.length; i++) { if (r = fun.call(obj, obj[i])) { return r } } return null; }; tree.jsify = function (obj) { if (Array.isArray(obj.value) && (obj.value.length > 1)) { return '[' + obj.value.map(function (v) { return v.toCSS(false) }).join(', ') + ']'; } else { return obj.toCSS(false); } }; })(require('./tree')); // // browser.js - client-side engine // var isFileProtocol = (location.protocol === 'file:' || location.protocol === 'chrome:' || location.protocol === 'chrome-extension:' || location.protocol === 'resource:'); less.env = less.env || (location.hostname == '127.0.0.1' || location.hostname == '0.0.0.0' || location.hostname == 'localhost' || location.port.length > 0 || isFileProtocol ? 'development' : 'production'); // Load styles asynchronously (default: false) // // This is set to `false` by default, so that the body // doesn't start loading before the stylesheets are parsed. // Setting this to `true` can result in flickering. // less.async = false; // Interval between watch polls less.poll = less.poll || (isFileProtocol ? 1000 : 1500); // // Watch mode // less.watch = function () { return this.watchMode = true }; less.unwatch = function () { return this.watchMode = false }; if (less.env === 'development') { less.optimization = 0; if (/!watch/.test(location.hash)) { less.watch(); } less.watchTimer = setInterval(function () { if (less.watchMode) { loadStyleSheets(function (root, sheet, env) { if (root) { createCSS(root.toCSS(), sheet, env.lastModified); } }); } }, less.poll); } else { less.optimization = 3; } var cache; try { cache = (typeof(window.localStorage) === 'undefined') ? null : window.localStorage; } catch (_) { cache = null; } // // Get all tags with the 'rel' attribute set to "stylesheet/less" // var links = document.getElementsByTagName('link'); var typePattern = /^text\/(x-)?less$/; less.sheets = []; for (var i = 0; i < links.length; i++) { if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) && (links[i].type.match(typePattern)))) { less.sheets.push(links[i]); } } less.refresh = function (reload) { var startTime, endTime; startTime = endTime = new(Date); loadStyleSheets(function (root, sheet, env) { if (env.local) { log("loading " + sheet.href + " from cache."); } else { log("parsed " + sheet.href + " successfully."); createCSS(root.toCSS(), sheet, env.lastModified); } log("css for " + sheet.href + " generated in " + (new(Date) - endTime) + 'ms'); (env.remaining === 0) && log("css generated in " + (new(Date) - startTime) + 'ms'); endTime = new(Date); }, reload); loadStyles(); }; less.refreshStyles = loadStyles; less.refresh(less.env === 'development'); function loadStyles() { var styles = document.getElementsByTagName('style'); for (var i = 0; i < styles.length; i++) { if (styles[i].type.match(typePattern)) { new(less.Parser)().parse(styles[i].innerHTML || '', function (e, tree) { var css = tree.toCSS(); var style = styles[i]; style.type = 'text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.innerHTML = css; } }); } } } function loadStyleSheets(callback, reload) { for (var i = 0; i < less.sheets.length; i++) { loadStyleSheet(less.sheets[i], callback, reload, less.sheets.length - (i + 1)); } } function loadStyleSheet(sheet, callback, reload, remaining) { var url = window.location.href.replace(/[#?].*$/, ''); var href = sheet.href.replace(/\?.*$/, ''); var css = cache && cache.getItem(href); var timestamp = cache && cache.getItem(href + ':timestamp'); var styles = { css: css, timestamp: timestamp }; // Stylesheets in IE don't always return the full path if (! /^(https?|file):/.test(href)) { if (href.charAt(0) == "/") { href = window.location.protocol + "//" + window.location.host + href; } else { href = url.slice(0, url.lastIndexOf('/') + 1) + href; } } xhr(sheet.href, sheet.type, function (data, lastModified) { if (!reload && styles && lastModified && (new(Date)(lastModified).valueOf() === new(Date)(styles.timestamp).valueOf())) { // Use local copy createCSS(styles.css, sheet); callback(null, sheet, { local: true, remaining: remaining }); } else { // Use remote copy (re-parse) try { new(less.Parser)({ optimization: less.optimization, paths: [href.replace(/[\w\.-]+$/, '')], mime: sheet.type }).parse(data, function (e, root) { if (e) { return error(e, href) } try { callback(root, sheet, { local: false, lastModified: lastModified, remaining: remaining }); removeNode(document.getElementById('less-error-message:' + extractId(href))); } catch (e) { error(e, href); } }); } catch (e) { error(e, href); } } }, function (status, url) { throw new(Error)("Couldn't load " + url + " (" + status + ")"); }); } function extractId(href) { return href.replace(/^[a-z]+:\/\/?[^\/]+/, '' ) // Remove protocol & domain .replace(/^\//, '' ) // Remove root / .replace(/\?.*$/, '' ) // Remove query .replace(/\.[^\.\/]+$/, '' ) // Remove file extension .replace(/[^\.\w-]+/g, '-') // Replace illegal characters .replace(/\./g, ':'); // Replace dots with colons(for valid id) } function createCSS(styles, sheet, lastModified) { var css; // Strip the query-string var href = sheet.href ? sheet.href.replace(/\?.*$/, '') : ''; // If there is no title set, use the filename, minus the extension var id = 'less:' + (sheet.title || extractId(href)); // If the stylesheet doesn't exist, create a new node if ((css = document.getElementById(id)) === null) { css = document.createElement('style'); css.type = 'text/css'; css.media = sheet.media || 'screen'; css.id = id; document.getElementsByTagName('head')[0].appendChild(css); } if (css.styleSheet) { // IE try { css.styleSheet.cssText = styles; } catch (e) { throw new(Error)("Couldn't reassign styleSheet.cssText."); } } else { (function (node) { if (css.childNodes.length > 0) { if (css.firstChild.nodeValue !== node.nodeValue) { css.replaceChild(node, css.firstChild); } } else { css.appendChild(node); } })(document.createTextNode(styles)); } // Don't update the local store if the file wasn't modified if (lastModified && cache) { log('saving ' + href + ' to cache.'); cache.setItem(href, styles); cache.setItem(href + ':timestamp', lastModified); } } function xhr(url, type, callback, errback) { var xhr = getXMLHttpRequest(); var async = isFileProtocol ? false : less.async; if (typeof(xhr.overrideMimeType) === 'function') { xhr.overrideMimeType('text/css'); } xhr.open('GET', url, async); xhr.setRequestHeader('Accept', type || 'text/x-less, text/css; q=0.9, */*; q=0.5'); xhr.send(null); if (isFileProtocol) { if (xhr.status === 0 || (xhr.status >= 200 && xhr.status < 300)) { callback(xhr.responseText); } else { errback(xhr.status, url); } } else if (async) { xhr.onreadystatechange = function () { if (xhr.readyState == 4) { handleResponse(xhr, callback, errback); } }; } else { handleResponse(xhr, callback, errback); } function handleResponse(xhr, callback, errback) { if (xhr.status >= 200 && xhr.status < 300) { callback(xhr.responseText, xhr.getResponseHeader("Last-Modified")); } else if (typeof(errback) === 'function') { errback(xhr.status, url); } } } function getXMLHttpRequest() { if (window.XMLHttpRequest) { return new(XMLHttpRequest); } else { try { return new(ActiveXObject)("MSXML2.XMLHTTP.3.0"); } catch (e) { log("browser doesn't support AJAX."); return null; } } } function removeNode(node) { return node && node.parentNode.removeChild(node); } function log(str) { if (less.env == 'development' && typeof(console) !== "undefined") { console.log('less: ' + str) } } function error(e, href) { var id = 'less-error-message:' + extractId(href); var template = ['
    ', '
  • {0}
  • ', '
  • {current}
  • ', '
  • {2}
  • ', '
'].join('\n'); var elem = document.createElement('div'), timer, content; elem.id = id; elem.className = "less-error-message"; content = '

' + (e.message || 'There is an error in your .less file') + '

' + '

' + href + " "; if (e.extract) { content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':

' + template.replace(/\[(-?\d)\]/g, function (_, i) { return (parseInt(e.line) + parseInt(i)) || ''; }).replace(/\{(\d)\}/g, function (_, i) { return e.extract[parseInt(i)] || ''; }).replace(/\{current\}/, e.extract[1].slice(0, e.column) + '' + e.extract[1].slice(e.column) + ''); } elem.innerHTML = content; // CSS for error messages createCSS([ '.less-error-message ul, .less-error-message li {', 'list-style-type: none;', 'margin-right: 15px;', 'padding: 4px 0;', 'margin: 0;', '}', '.less-error-message label {', 'font-size: 12px;', 'margin-right: 15px;', 'padding: 4px 0;', 'color: #cc7777;', '}', '.less-error-message pre {', 'color: #ee4444;', 'padding: 4px 0;', 'margin: 0;', 'display: inline-block;', '}', '.less-error-message pre.ctx {', 'color: #dd4444;', '}', '.less-error-message h3 {', 'font-size: 20px;', 'font-weight: bold;', 'padding: 15px 0 5px 0;', 'margin: 0;', '}', '.less-error-message a {', 'color: #10a', '}', '.less-error-message .error {', 'color: red;', 'font-weight: bold;', 'padding-bottom: 2px;', 'border-bottom: 1px dashed red;', '}' ].join('\n'), { title: 'error-message' }); elem.style.cssText = [ "font-family: Arial, sans-serif", "border: 1px solid #e00", "background-color: #eee", "border-radius: 5px", "-webkit-border-radius: 5px", "-moz-border-radius: 5px", "color: #e00", "padding: 15px", "margin-bottom: 15px" ].join(';'); if (less.env == 'development') { timer = setInterval(function () { if (document.body) { if (document.getElementById(id)) { document.body.replaceChild(elem, document.getElementById(id)); } else { document.body.insertBefore(elem, document.body.firstChild); } clearInterval(timer); } }, 10); } } })(window); less.js-1.4.2/dist/less-1.2.0.min.js000066400000000000000000001260071217256642200166010ustar00rootroot00000000000000// // LESS - Leaner CSS v1.2.0 // http://lesscss.org // // Copyright (c) 2009-2011, Alexis Sellier // Licensed under the Apache 2.0 License. // (function(a,b){function c(b){return a.less[b.split("/")[1]]}function m(){var a=document.getElementsByTagName("style");for(var b=0;b0?d.firstChild.nodeValue!==a.nodeValue&&d.replaceChild(a,d.firstChild):d.appendChild(a)})(document.createTextNode(a));c&&h&&(v("saving "+e+" to cache."),h.setItem(e,a),h.setItem(e+":timestamp",c))}function s(a,b,c,e){function i(b,c,d){b.status>=200&&b.status<300?c(b.responseText,b.getResponseHeader("Last-Modified")):typeof d=="function"&&d(b.status,a)}var f=t(),h=g?!1:d.async;typeof f.overrideMimeType=="function"&&f.overrideMimeType("text/css"),f.open("GET",a,h),f.setRequestHeader("Accept",b||"text/x-less, text/css; q=0.9, */*; q=0.5"),f.send(null),g?f.status===0||f.status>=200&&f.status<300?c(f.responseText):e(f.status,a):h?f.onreadystatechange=function(){f.readyState==4&&i(f,c,e)}:i(f,c,e)}function t(){if(a.XMLHttpRequest)return new XMLHttpRequest;try{return new ActiveXObject("MSXML2.XMLHTTP.3.0")}catch(b){return v("browser doesn't support AJAX."),null}}function u(a){return a&&a.parentNode.removeChild(a)}function v(a){d.env=="development"&&typeof console!="undefined"&&console.log("less: "+a)}function w(a,b){var c="less-error-message:"+q(b),e=["
    ",'
  • {0}
  • ',"
  • {current}
  • ",'
  • {2}
  • ',"
"].join("\n"),f=document.createElement("div"),g,h;f.id=c,f.className="less-error-message",h="

"+(a.message||"There is an error in your .less file")+"

"+'

'+b+" ",a.extract&&(h+="on line "+a.line+", column "+(a.column+1)+":

"+e.replace(/\[(-?\d)\]/g,function(b,c){return parseInt(a.line)+parseInt(c)||""}).replace(/\{(\d)\}/g,function(b,c){return a.extract[parseInt(c)]||""}).replace(/\{current\}/,a.extract[1].slice(0,a.column)+''+a.extract[1].slice(a.column)+"")),f.innerHTML=h,r([".less-error-message ul, .less-error-message li {","list-style-type: none;","margin-right: 15px;","padding: 4px 0;","margin: 0;","}",".less-error-message label {","font-size: 12px;","margin-right: 15px;","padding: 4px 0;","color: #cc7777;","}",".less-error-message pre {","color: #ee4444;","padding: 4px 0;","margin: 0;","display: inline-block;","}",".less-error-message pre.ctx {","color: #dd4444;","}",".less-error-message h3 {","font-size: 20px;","font-weight: bold;","padding: 15px 0 5px 0;","margin: 0;","}",".less-error-message a {","color: #10a","}",".less-error-message .error {","color: red;","font-weight: bold;","padding-bottom: 2px;","border-bottom: 1px dashed red;","}"].join("\n"),{title:"error-message"}),f.style.cssText=["font-family: Arial, sans-serif","border: 1px solid #e00","background-color: #eee","border-radius: 5px","-webkit-border-radius: 5px","-moz-border-radius: 5px","color: #e00","padding: 15px","margin-bottom: 15px"].join(";"),d.env=="development"&&(g=setInterval(function(){document.body&&(document.getElementById(c)?document.body.replaceChild(f,document.getElementById(c)):document.body.insertBefore(f,document.body.firstChild),clearInterval(g))},10))}Array.isArray||(Array.isArray=function(a){return Object.prototype.toString.call(a)==="[object Array]"||a instanceof Array}),Array.prototype.forEach||(Array.prototype.forEach=function(a,b){var c=this.length>>>0;for(var d=0;d>>0,c=new Array(b),d=arguments[1];for(var e=0;e>>0,c=0;if(b===0&&arguments.length===1)throw new TypeError;if(arguments.length>=2)var d=arguments[1];else do{if(c in this){d=this[c++];break}if(++c>=b)throw new TypeError}while(!0);for(;c=b)return-1;c<0&&(c+=b);for(;cm&&(l[h]=l[h].slice(g-m),m=g)}function v(a){var c,d,e,f,i,j,k,o;if(a instanceof Function)return a.call(n.parsers);if(typeof a=="string")c=b.charAt(g)===a?a:null,e=1,u();else{u();if(c=a.exec(l[h]))e=c[0].length;else return null}if(c){o=g+=e,j=g+l[h].length-e;while(g=0&&b.charAt(c)!=="\n";c--)d++;return{line:a?(b.slice(0,a).match(/\n/g)||"").length:null,column:d}}function A(a,c){var d=b.split("\n"),e=z(a.index),f=e.line,g=e.column;this.type=a.type||"SyntaxError",this.message=a.message,this.filename=a.filename||c.filename,this.index=a.index,this.line=typeof f=="number"?f+1:null,this.callLine=a.call&&z(a.call)+1,this.callExtract=d[z(a.call)],this.stack=a.stack,this.column=g,this.extract=[d[f-1],d[f],d[f+1]]}var b,g,h,i,j,k,l,m,n,o=this,q=function(){},r=this.imports={paths:a&&a.paths||[],queue:[],files:{},mime:a&&a.mime,error:null,push:function(b,c){var e=this;this.queue.push(b),d.Parser.importer(b,this.paths,function(a,d){e.queue.splice(e.queue.indexOf(b),1),e.files[b]=d,a&&!e.error&&(e.error=a),c(a,d),e.queue.length===0&&q()},a)}};return this.env=a=a||{},this.optimization="optimization"in this.env?this.env.optimization:1,this.env.filename=this.env.filename||null,n={imports:r,parse:function(e,i){var j,o,p,r,s,t,u=[],w,x=null;g=h=m=k=0,l=[],b=e.replace(/\r\n/g,"\n"),l=function(c){var d=0,e=/[^"'`\{\}\/\(\)]+/g,f=/\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g,g=0,h,i=c[0],j,k;for(var l=0,m,n;l0)throw{type:"Syntax",message:"Missing closing `}`",filename:a.filename};return c.map(function(a){return a.join("")})}([[]]);try{j=new f.Ruleset([],v(this.parsers.primary)),j.root=!0}catch(y){return i(new A(y,a))}j.toCSS=function(b){var e,g,h;return function(e,g){var h=[];e=e||{},typeof g=="object"&&!Array.isArray(g)&&(g=Object.keys(g).map(function(a){var b=g[a];return b instanceof f.Value||(b instanceof f.Expression||(b=new f.Expression([b])),b=new f.Value([b])),new f.Rule("@"+a,b,!1,0)}),h=[new f.Ruleset(null,g)]);try{var i=b.call(this,{frames:h}).toCSS([],{compress:e.compress||!1})}catch(j){throw new A(j,a)}if(n.imports.error)throw n.imports.error;return e.yuicompress&&d.mode==="node"?c("./cssmin").compressor.cssmin(i):e.compress?i.replace(/(\s)+/g,"$1"):i}}(j.eval);if(g=0&&b.charAt(z)!=="\n";z--)B++;x={type:"Parse",message:"Syntax Error on line "+s,index:g,filename:a.filename,line:s,column:B,extract:[t[s-2],t[s-1],t[s]]}}this.imports.queue.length>0?q=function(){i(x,j)}:i(x,j)},parsers:{primary:function(){var a,b=[];while((a=v(this.mixin.definition)||v(this.rule)||v(this.ruleset)||v(this.mixin.call)||v(this.comment)||v(this.directive))||v(/^[\s\n]+/))a&&b.push(a);return b},comment:function(){var a;if(b.charAt(g)!=="/")return;if(b.charAt(g+1)==="/")return new f.Comment(v(/^\/\/.*/),!0);if(a=v(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/))return new f.Comment(a)},entities:{quoted:function(){var a,c=g,d;b.charAt(c)==="~"&&(c++,d=!0);if(b.charAt(c)!=='"'&&b.charAt(c)!=="'")return;d&&v("~");if(a=v(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/))return new f.Quoted(a[0],a[1]||a[2],d)},keyword:function(){var a;if(a=v(/^[_A-Za-z-][_A-Za-z0-9-]*/))return f.colors.hasOwnProperty(a)?new f.Color(f.colors[a].slice(1)):new f.Keyword(a)},call:function(){var a,b,c=g;if(!(a=/^([\w-]+|%|progid:[\w\.]+)\(/.exec(l[h])))return;a=a[1].toLowerCase();if(a==="url")return null;g+=a.length;if(a==="alpha")return v(this.alpha);v("("),b=v(this.entities.arguments);if(!v(")"))return;if(a)return new f.Call(a,b,c)},arguments:function(){var a=[],b;while(b=v(this.entities.assignment)||v(this.expression)){a.push(b);if(!v(","))break}return a},literal:function(){return v(this.entities.dimension)||v(this.entities.color)||v(this.entities.quoted)},assignment:function(){var a,b;if((a=v(/^\w+(?=\s?=)/i))&&v("=")&&(b=v(this.entity)))return new f.Assignment(a,b)},url:function(){var a;if(b.charAt(g)!=="u"||!v(/^url\(/))return;return a=v(this.entities.quoted)||v(this.entities.variable)||v(this.entities.dataURI)||v(/^[-\w%@$\/.&=:;#+?~]+/)||"",w(")"),new f.URL(a.value||a.data||a instanceof f.Variable?a:new f.Anonymous(a),r.paths)},dataURI:function(){var a;if(v(/^data:/)){a={},a.mime=v(/^[^\/]+\/[^,;)]+/)||"",a.charset=v(/^;\s*charset=[^,;)]+/)||"",a.base64=v(/^;\s*base64/)||"",a.data=v(/^,\s*[^)]+/);if(a.data)return a}},variable:function(){var a,c=g;if(b.charAt(g)==="@"&&(a=v(/^@@?[\w-]+/)))return new f.Variable(a,c)},color:function(){var a;if(b.charAt(g)==="#"&&(a=v(/^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})/)))return new f.Color(a[1])},dimension:function(){var a,c=b.charCodeAt(g);if(c>57||c<45||c===47)return;if(a=v(/^(-?\d*\.?\d+)(px|%|em|rem|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn)?/))return new f.Dimension(a[1],a[2])},javascript:function(){var a,c=g,d;b.charAt(c)==="~"&&(c++,d=!0);if(b.charAt(c)!=="`")return;d&&v("~");if(a=v(/^`([^`]*)`/))return new f.JavaScript(a[1],g,d)}},variable:function(){var a;if(b.charAt(g)==="@"&&(a=v(/^(@[\w-]+)\s*:/)))return a[1]},shorthand:function(){var a,b;if(!y(/^[@\w.%-]+\/[@\w.-]+/))return;if((a=v(this.entity))&&v("/")&&(b=v(this.entity)))return new f.Shorthand(a,b)},mixin:{call:function(){var a=[],c,d,e,h=g,i=b.charAt(g),j=!1;if(i!=="."&&i!=="#")return;while(c=v(/^[#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/))a.push(new f.Element(d,c,g)),d=v(">");v("(")&&(e=v(this.entities.arguments))&&v(")"),v(this.important)&&(j=!0);if(a.length>0&&(v(";")||y("}")))return new f.mixin.Call(a,e,h,j)},definition:function(){var a,c=[],d,e,h,i,j;if(b.charAt(g)!=="."&&b.charAt(g)!=="#"||y(/^[^{]*(;|})/))return;s();if(d=v(/^([#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+)\s*\(/)){a=d[1];while(h=v(this.entities.variable)||v(this.entities.literal)||v(this.entities.keyword)){h instanceof f.Variable?v(":")?(i=w(this.expression,"expected expression"),c.push({name:h.name,value:i})):c.push({name:h.name}):c.push({value:h});if(!v(","))break}w(")"),v(/^when/)&&(j=w(this.conditions,"expected condition")),e=v(this.block);if(e)return new f.mixin.Definition(a,c,e,j);t()}}},entity:function(){return v(this.entities.literal)||v(this.entities.variable)||v(this.entities.url)||v(this.entities.call)||v(this.entities.keyword)||v(this.entities.javascript)||v(this.comment)},end:function(){return v(";")||y("}")},alpha:function(){var a;if(!v(/^\(opacity=/i))return;if(a=v(/^\d+/)||v(this.entities.variable))return w(")"),new f.Alpha(a)},element:function(){var a,b,c,d;c=v(this.combinator),a=v(/^(?:\d+\.\d+|\d+)%/)||v(/^(?:[.#]?|:*)(?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/)||v("*")||v(this.attribute)||v(/^\([^)@]+\)/),a||v("(")&&(d=v(this.entities.variable))&&v(")")&&(a=new f.Paren(d));if(a)return new f.Element(c,a,g);if(c.value&&c.value.charAt(0)==="&")return new f.Element(c,null,g)},combinator:function(){var a,c=b.charAt(g);if(c===">"||c==="+"||c==="~"){g++;while(b.charAt(g)===" ")g++;return new f.Combinator(c)}if(c==="&"){a="&",g++,b.charAt(g)===" "&&(a="& ");while(b.charAt(g)===" ")g++;return new f.Combinator(a)}if(c===":"&&b.charAt(g+1)===":"){g+=2;while(b.charAt(g)===" ")g++;return new f.Combinator("::")}return b.charAt(g-1)===" "?new f.Combinator(" "):new f.Combinator(null)},selector:function(){var a,c,d=[],e,h;while(c=v(this.element)){e=b.charAt(g),d.push(c);if(e==="{"||e==="}"||e===";"||e===",")break}if(d.length>0)return new f.Selector(d)},tag:function(){return v(/^[a-zA-Z][a-zA-Z-]*[0-9]?/)||v("*")},attribute:function(){var a="",b,c,d;if(!v("["))return;if(b=v(/^[a-zA-Z-]+/)||v(this.entities.quoted))(d=v(/^[|~*$^]?=/))&&(c=v(this.entities.quoted)||v(/^[\w-]+/))?a=[b,d,c.toCSS?c.toCSS():c].join(""):a=b;if(!v("]"))return;if(a)return"["+a+"]"},block:function(){var a;if(v("{")&&(a=v(this.primary))&&v("}"))return a},ruleset:function(){var a=[],b,c,d;s();while(b=v(this.selector)){a.push(b),v(this.comment);if(!v(","))break;v(this.comment)}if(a.length>0&&(c=v(this.block)))return new f.Ruleset(a,c);k=g,t()},rule:function(){var a,c,d=b.charAt(g),e,i;s();if(d==="."||d==="#"||d==="&")return;if(a=v(this.variable)||v(this.property)){a.charAt(0)!="@"&&(i=/^([^@+\/'"*`(;{}-]*);/.exec(l[h]))?(g+=i[0].length-1,c=new f.Anonymous(i[1])):a==="font"?c=v(this.font):c=v(this.value),e=v(this.important);if(c&&v(this.end))return new f.Rule(a,c,e,j);k=g,t()}},"import":function(){var a,b;if(v(/^@import\s+/)&&(a=v(this.entities.quoted)||v(this.entities.url))){b=v(this.mediaFeatures);if(v(";"))return new f.Import(a,r,b)}},mediaFeature:function(){var a=[];do if(e=v(this.entities.keyword))a.push(e);else if(v("(")){p=v(this.property),e=v(this.entity);if(!v(")"))return null;if(p&&e)a.push(new f.Paren(new f.Rule(p,e,null,g,!0)));else if(e)a.push(new f.Paren(e));else return null}while(e);if(a.length>0)return new f.Expression(a)},mediaFeatures:function(){var a,b=[];while(a=v(this.mediaFeature)){b.push(a);if(!v(","))break}return b.length>0?b:null},media:function(){var a;if(v(/^@media/)){a=v(this.mediaFeatures);if(rules=v(this.block))return new f.Directive("@media",rules,a)}},directive:function(){var a,c,d,e,h,i;if(b.charAt(g)!=="@")return;if(c=v(this["import"])||v(this.media))return c;if(a=v(/^@page|@keyframes/)||v(/^@(?:-webkit-|-moz-|-o-|-ms-)[a-z0-9-]+/)){e=(v(/^[^{]+/)||"").trim();if(d=v(this.block))return new f.Directive(a+" "+e,d)}else if(a=v(/^@[-a-z]+/))if(a==="@font-face"){if(d=v(this.block))return new f.Directive(a,d)}else if((c=v(this.entity))&&v(";"))return new f.Directive(a,c)},font:function(){var a=[],b=[],c,d,e,g;while(g=v(this.shorthand)||v(this.entity))b.push(g);a.push(new f.Expression(b));if(v(","))while(g=v(this.expression)){a.push(g);if(!v(","))break}return new f.Value(a)},value:function(){var a,b=[],c;while(a=v(this.expression)){b.push(a);if(!v(","))break}if(b.length>0)return new f.Value(b)},important:function(){if(b.charAt(g)==="!")return v(/^! *important/)},sub:function(){var a;if(v("(")&&(a=v(this.expression))&&v(")"))return a},multiplication:function(){var a,b,c,d;if(a=v(this.operand)){while(!y(/^\/\*/)&&(c=v("/")||v("*"))&&(b=v(this.operand)))d=new f.Operation(c,[d||a,b]);return d||a}},addition:function(){var a,c,d,e;if(a=v(this.multiplication)){while((d=v(/^[-+]\s+/)||b.charAt(g-1)!=" "&&(v("+")||v("-")))&&(c=v(this.multiplication)))e=new f.Operation(d,[e||a,c]);return e||a}},conditions:function(){var a,b,c=g,d;if(a=v(this.condition)){while(v(",")&&(b=v(this.condition)))d=new f.Condition("or",d||a,b,c);return d||a}},condition:function(){var a,b,c,d,e=g,h=!1;v(/^not/)&&(h=!0),w("(");if(a=v(this.addition)||v(this.entities.keyword)||v(this.entities.quoted))return(d=v(/^(?:>=|=<|[<=>])/))?(b=v(this.addition)||v(this.entities.keyword)||v(this.entities.quoted))?c=new f.Condition(d,a,b,e,h):x("expected expression"):c=new f.Condition("=",a,new f.Keyword("true"),e,h),w(")"),v(/^and/)?new f.Condition("and",c,v(this.condition)):c},operand:function(){var a,c=b.charAt(g+1);b.charAt(g)==="-"&&(c==="@"||c==="(")&&(a=v("-"));var d=v(this.sub)||v(this.entities.dimension)||v(this.entities.color)||v(this.entities.variable)||v(this.entities.call);return a?new f.Operation("*",[new f.Dimension(-1),d]):d},expression:function(){var a,b,c=[],d;while(a=v(this.addition)||v(this.entity))c.push(a);if(c.length>0)return new f.Expression(c)},property:function(){var a;if(a=v(/^(\*?-?[-a-z_0-9]+)\s*:/))return a[1]}}}};if(d.mode==="browser"||d.mode==="rhino")d.Parser.importer=function(a,b,c,d){a.charAt(0)!=="/"&&b.length>0&&(a=b[0]+a),o({href:a,title:a,type:d.mime},c,!0)};(function(a){function b(b){return a.functions.hsla(b.h,b.s,b.l,b.a)}function c(b){if(b instanceof a.Dimension)return parseFloat(b.unit=="%"?b.value/100:b.value);if(typeof b=="number")return b;throw{error:"RuntimeError",message:"color functions take numbers as parameters"}}function d(a){return Math.min(1,Math.max(0,a))}a.functions={rgb:function(a,b,c){return this.rgba(a,b,c,1)},rgba:function(b,d,e,f){var g=[b,d,e].map(function(a){return c(a)}),f=c(f);return new a.Color(g,f)},hsl:function(a,b,c){return this.hsla(a,b,c,1)},hsla:function(a,b,d,e){function h(a){return a=a<0?a+1:a>1?a-1:a,a*6<1?g+(f-g)*a*6:a*2<1?f:a*3<2?g+(f-g)*(2/3-a)*6:g}a=c(a)%360/360,b=c(b),d=c(d),e=c(e);var f=d<=.5?d*(b+1):d+b-d*b,g=d*2-f;return this.rgba(h(a+1/3)*255,h(a)*255,h(a-1/3)*255,e)},hue:function(b){return new a.Dimension(Math.round(b.toHSL().h))},saturation:function(b){return new a.Dimension(Math.round(b.toHSL().s*100),"%")},lightness:function(b){return new a.Dimension(Math.round(b.toHSL().l*100),"%")},alpha:function(b){return new a.Dimension(b.toHSL().a)},saturate:function(a,c){var e=a.toHSL();return e.s+=c.value/100,e.s=d(e.s),b(e)},desaturate:function(a,c){var e=a.toHSL();return e.s-=c.value/100,e.s=d(e.s),b(e)},lighten:function(a,c){var e=a.toHSL();return e.l+=c.value/100,e.l=d(e.l),b(e)},darken:function(a,c){var e=a.toHSL();return e.l-=c.value/100,e.l=d(e.l),b(e)},fadein:function(a,c){var e=a.toHSL();return e.a+=c.value/100,e.a=d(e.a),b(e)},fadeout:function(a,c){var e=a.toHSL();return e.a-=c.value/100,e.a=d(e.a),b(e)},fade:function(a,c){var e=a.toHSL();return e.a=c.value/100,e.a=d(e.a),b(e)},spin:function(a,c){var d=a.toHSL(),e=(d.h+c.value)%360;return d.h=e<0?360+e:e,b(d)},mix:function(b,c,d){var e=d.value/100,f=e*2-1,g=b.toHSL().a-c.toHSL().a,h=((f*g==-1?f:(f+g)/(1+f*g))+1)/2,i=1-h,j=[b.rgb[0]*h+c.rgb[0]*i,b.rgb[1]*h+c.rgb[1]*i,b.rgb[2]*h+c.rgb[2]*i],k=b.alpha*e+c.alpha*(1-e);return new a.Color(j,k)},greyscale:function(b){return this.desaturate(b,new a.Dimension(100))},e:function(b){return new a.Anonymous(b instanceof a.JavaScript?b.evaluated:b)},escape:function(b){return new a.Anonymous(encodeURI(b.value).replace(/=/g,"%3D").replace(/:/g,"%3A").replace(/#/g,"%23").replace(/;/g,"%3B").replace(/\(/g,"%28").replace(/\)/g,"%29"))},"%":function(b){var c=Array.prototype.slice.call(arguments,1),d=b.value;for(var e=0;e255?255:a<0?0:a).toString(16),a.length===1?"0"+a:a}).join("")},operate:function(b,c){var d=[];c instanceof a.Color||(c=c.toColor());for(var e=0;e<3;e++)d[e]=a.operate(b,this.rgb[e],c.rgb[e]);return new a.Color(d,this.alpha+c.alpha)},toHSL:function(){var a=this.rgb[0]/255,b=this.rgb[1]/255,c=this.rgb[2]/255,d=this.alpha,e=Math.max(a,b,c),f=Math.min(a,b,c),g,h,i=(e+f)/2,j=e-f;if(e===f)g=h=0;else{h=i>.5?j/(2-e-f):j/(e+f);switch(e){case a:g=(b-c)/j+(b255?255:a<0?0:a).toString(16),a.length===1?"0"+a:a}).join("")}}}(c("../tree")),function(a){a.Comment=function(a,b){this.value=a,this.silent=!!b},a.Comment.prototype={toCSS:function(a){return a.compress?"":this.value},eval:function(){return this}}}(c("../tree")),function(a){a.Condition=function(a,b,c,d,e){this.op=a.trim(),this.lvalue=b,this.rvalue=c,this.index=d,this.negate=e},a.Condition.prototype.eval=function(a){var b=this.lvalue.eval(a),c=this.rvalue.eval(a),d=this.index,e,e=function(a){switch(a){case"and":return b&&c;case"or":return b||c;default:if(b.compare)e=b.compare(c);else if(c.compare)e=c.compare(b);else throw{type:"Type",message:"Unable to perform comparison",index:d};switch(e){case-1:return a==="<"||a==="=<";case 0:return a==="="||a===">="||a==="=<";case 1:return a===">"||a===">="}}}(this.op);return this.negate?!e:e}}(c("../tree")),function(a){a.Dimension=function(a,b){this.value=parseFloat(a),this.unit=b||null},a.Dimension.prototype={eval:function(){return this},toColor:function(){return new a.Color([this.value,this.value,this.value])},toCSS:function(){var a=this.value+this.unit;return a},operate:function(b,c){return new a.Dimension(a.operate(b,this.value,c.value),this.unit||c.unit)},compare:function(b){return b instanceof a.Dimension?b.value>this.value?-1:b.value":a.compress?">":" > "}[this.value]}}(c("../tree")),function(a){a.Expression=function(a){this.value=a},a.Expression.prototype={eval:function(b){return this.value.length>1?new a.Expression(this.value.map(function(a){return a.eval(b)})):this.value.length===1?this.value[0].eval(b):this},toCSS:function(a){return this.value.map(function(b){return b.toCSS?b.toCSS(a):""}).join(" ")}}}(c("../tree")),function(a){a.Import=function(b,c,d){var e=this;this._path=b,this.features=d&&new a.Value(d),b instanceof a.Quoted?this.path=/\.(le?|c)ss(\?.*)?$/.test(b.value)?b.value:b.value+".less":this.path=b.value.value||b.value,this.css=/css(\?.*)?$/.test(this.path),this.css||c.push(this.path,function(a,b){e.root=b})},a.Import.prototype={toCSS:function(a){var b=this.features?" "+this.features.toCSS(a):"";return this.css?"@import "+this._path.toCSS()+b+";\n":""},eval:function(b){var c,d=this.features&&this.features.eval(b);if(this.css)return this;c=new a.Ruleset([],this.root.rules.slice(0));for(var e=0;e0){c=this.arguments&&this.arguments.map(function(b){return b.eval(a)});for(var g=0;g0&&c>this.params.length)return!1;if(this.condition&&!this.condition.eval({frames:[this.evalParams(b,a)].concat(b.frames)}))return!1;d=Math.min(c,this.arity);for(var f=0;fe.selectors[g].elements.length?Array.prototype.push.apply(d,e.find(new a.Selector(b.elements.slice(1)),c)):d.push(e);break}}),this._lookups[g]=d)},toCSS:function(b,c){var d=[],e=[],f=[],g=[],h,i;this.root||(b.length===0?g=this.selectors.map(function(a){return[a]}):this.joinSelectors(g,b,this.selectors));for(var j=0;j0&&(h=g.map(function(a){return a.map(function(a){return a.toCSS(c)}).join("").trim()}).join(c.compress?",":g.length>3?",\n":", "),d.push(h,(c.compress?"{":" {\n ")+e.join(c.compress?"":"\n ")+(c.compress?"}":"\n}\n"))),d.push(f),d.join("")+(c.compress?"\n":"")},joinSelectors:function(a,b,c){for(var d=0;d0&&e.push(new a.Selector(g)),h.length>0&&f.push(new a.Selector(h));for(var l=0;l0&&(b.value=c[0]+(b.value.charAt(0)==="/"?b.value.slice(1):b.value)),this.value=b,this.paths=c)},b.URL.prototype={toCSS:function(){return"url("+(this.attrs?"data:"+this.attrs.mime+this.attrs.charset+this.attrs.base64+this.attrs.data:this.value.toCSS())+")"},eval:function(a){return this.attrs?this:new b.URL(this.value.eval(a),this.paths)}}}(c("../tree")),function(a){a.Value=function(a){this.value=a,this.is="value"},a.Value.prototype={eval:function(b){return this.value.length===1?this.value[0].eval(b):new a.Value(this.value.map(function(a){return a.eval(b)}))},toCSS:function(a){return this.value.map(function(b){return b.toCSS(a)}).join(a.compress?",":", ")}}}(c("../tree")),function(a){a.Variable=function(a,b){this.name=a,this.index=b},a.Variable.prototype={eval:function(b){var c,d,e=this.name;e.indexOf("@@")==0&&(e="@"+(new a.Variable(e.slice(1))).eval(b).value);if(c=a.find(b.frames,function(a){if(d=a.variable(e))return d.value.eval(b)}))return c;throw{message:"variable "+e+" is undefined",index:this.index}}}}(c("../tree")),function(a){a.find=function(a,b){for(var c=0,d;c1?"["+a.value.map(function(a){return a.toCSS(!1)}).join(", ")+"]":a.toCSS(!1)}}(c("./tree"));var g=location.protocol==="file:"||location.protocol==="chrome:"||location.protocol==="chrome-extension:"||location.protocol==="resource:";d.env=d.env||(location.hostname=="127.0.0.1"||location.hostname=="0.0.0.0"||location.hostname=="localhost"||location.port.length>0||g?"development":"production"),d.async=!1,d.poll=d.poll||(g?1e3:1500),d.watch=function(){return this.watchMode=!0},d.unwatch=function(){return this.watchMode=!1},d.env==="development"?(d.optimization=0,/!watch/.test(location.hash)&&d.watch(),d.watchTimer=setInterval(function(){d.watchMode&&n(function(a,b,c){a&&r(a.toCSS(),b,c.lastModified)})},d.poll)):d.optimization=3;var h;try{h=typeof a.localStorage=="undefined"?null:a.localStorage}catch(i){h=null}var j=document.getElementsByTagName("link"),k=/^text\/(x-)?less$/;d.sheets=[];for(var l=0;l>> 0; for (var i = 0; i < len; i++) { if (i in this) { block.call(thisObject, this[i], i, this); } } }; } if (!Array.prototype.map) { Array.prototype.map = function(fun /*, thisp*/) { var len = this.length >>> 0; var res = new Array(len); var thisp = arguments[1]; for (var i = 0; i < len; i++) { if (i in this) { res[i] = fun.call(thisp, this[i], i, this); } } return res; }; } if (!Array.prototype.filter) { Array.prototype.filter = function (block /*, thisp */) { var values = []; var thisp = arguments[1]; for (var i = 0; i < this.length; i++) { if (block.call(thisp, this[i])) { values.push(this[i]); } } return values; }; } if (!Array.prototype.reduce) { Array.prototype.reduce = function(fun /*, initial*/) { var len = this.length >>> 0; var i = 0; // no value to return if no initial value and an empty array if (len === 0 && arguments.length === 1) throw new TypeError(); if (arguments.length >= 2) { var rv = arguments[1]; } else { do { if (i in this) { rv = this[i++]; break; } // if array contains no values, no initial value to return if (++i >= len) throw new TypeError(); } while (true); } for (; i < len; i++) { if (i in this) { rv = fun.call(null, rv, this[i], i, this); } } return rv; }; } if (!Array.prototype.indexOf) { Array.prototype.indexOf = function (value /*, fromIndex */ ) { var length = this.length; var i = arguments[1] || 0; if (!length) return -1; if (i >= length) return -1; if (i < 0) i += length; for (; i < length; i++) { if (!Object.prototype.hasOwnProperty.call(this, i)) { continue } if (value === this[i]) return i; } return -1; }; } // // Object // if (!Object.keys) { Object.keys = function (object) { var keys = []; for (var name in object) { if (Object.prototype.hasOwnProperty.call(object, name)) { keys.push(name); } } return keys; }; } // // String // if (!String.prototype.trim) { String.prototype.trim = function () { return String(this).replace(/^\s\s*/, '').replace(/\s\s*$/, ''); }; } var less, tree; if (typeof environment === "object" && ({}).toString.call(environment) === "[object Environment]") { // Rhino // Details on how to detect Rhino: https://github.com/ringo/ringojs/issues/88 if (typeof(window) === 'undefined') { less = {} } else { less = window.less = {} } tree = less.tree = {}; less.mode = 'rhino'; } else if (typeof(window) === 'undefined') { // Node.js less = exports, tree = require('./tree'); less.mode = 'node'; } else { // Browser if (typeof(window.less) === 'undefined') { window.less = {} } less = window.less, tree = window.less.tree = {}; less.mode = 'browser'; } // // less.js - parser // // A relatively straight-forward predictive parser. // There is no tokenization/lexing stage, the input is parsed // in one sweep. // // To make the parser fast enough to run in the browser, several // optimization had to be made: // // - Matching and slicing on a huge input is often cause of slowdowns. // The solution is to chunkify the input into smaller strings. // The chunks are stored in the `chunks` var, // `j` holds the current chunk index, and `current` holds // the index of the current chunk in relation to `input`. // This gives us an almost 4x speed-up. // // - In many cases, we don't need to match individual tokens; // for example, if a value doesn't hold any variables, operations // or dynamic references, the parser can effectively 'skip' it, // treating it as a literal. // An example would be '1px solid #000' - which evaluates to itself, // we don't need to know what the individual components are. // The drawback, of course is that you don't get the benefits of // syntax-checking on the CSS. This gives us a 50% speed-up in the parser, // and a smaller speed-up in the code-gen. // // // Token matching is done with the `$` function, which either takes // a terminal string or regexp, or a non-terminal function to call. // It also takes care of moving all the indices forwards. // // less.Parser = function Parser(env) { var input, // LeSS input string i, // current index in `input` j, // current chunk temp, // temporarily holds a chunk's state, for backtracking memo, // temporarily holds `i`, when backtracking furthest, // furthest index the parser has gone to chunks, // chunkified input current, // index of current chunk, in `input` parser; var that = this; // This function is called after all files // have been imported through `@import`. var finish = function () {}; var imports = this.imports = { paths: env && env.paths || [], // Search paths, when importing queue: [], // Files which haven't been imported yet files: {}, // Holds the imported parse trees contents: {}, // Holds the imported file contents mime: env && env.mime, // MIME type of .less files error: null, // Error in parsing/evaluating an import push: function (path, callback) { var that = this; this.queue.push(path); // // Import a file asynchronously // less.Parser.importer(path, this.paths, function (e, root, contents) { that.queue.splice(that.queue.indexOf(path), 1); // Remove the path from the queue that.files[path] = root; // Store the root that.contents[path] = contents; if (e && !that.error) { that.error = e } callback(e, root); if (that.queue.length === 0) { finish() } // Call `finish` if we're done importing }, env); } }; function save() { temp = chunks[j], memo = i, current = i } function restore() { chunks[j] = temp, i = memo, current = i } function sync() { if (i > current) { chunks[j] = chunks[j].slice(i - current); current = i; } } // // Parse from a token, regexp or string, and move forward if match // function $(tok) { var match, args, length, c, index, endIndex, k, mem; // // Non-terminal // if (tok instanceof Function) { return tok.call(parser.parsers); // // Terminal // // Either match a single character in the input, // or match a regexp in the current chunk (chunk[j]). // } else if (typeof(tok) === 'string') { match = input.charAt(i) === tok ? tok : null; length = 1; sync (); } else { sync (); if (match = tok.exec(chunks[j])) { length = match[0].length; } else { return null; } } // The match is confirmed, add the match length to `i`, // and consume any extra white-space characters (' ' || '\n') // which come after that. The reason for this is that LeSS's // grammar is mostly white-space insensitive. // if (match) { mem = i += length; endIndex = i + chunks[j].length - length; while (i < endIndex) { c = input.charCodeAt(i); if (! (c === 32 || c === 10 || c === 9)) { break } i++; } chunks[j] = chunks[j].slice(length + (i - mem)); current = i; if (chunks[j].length === 0 && j < chunks.length - 1) { j++ } if(typeof(match) === 'string') { return match; } else { return match.length === 1 ? match[0] : match; } } } function expect(arg, msg) { var result = $(arg); if (! result) { error(msg || (typeof(arg) === 'string' ? "expected '" + arg + "' got '" + input.charAt(i) + "'" : "unexpected token")); } else { return result; } } function error(msg, type) { throw { index: i, type: type || 'Syntax', message: msg }; } // Same as $(), but don't change the state of the parser, // just return the match. function peek(tok) { if (typeof(tok) === 'string') { return input.charAt(i) === tok; } else { if (tok.test(chunks[j])) { return true; } else { return false; } } } function getInput(e, env) { if (e.filename && env.filename && (e.filename !== env.filename)) { return parser.imports.contents[e.filename]; } else { return input; } } function getLocation(index, input) { for (var n = index, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } return { line: typeof(index) === 'number' ? (input.slice(0, index).match(/\n/g) || "").length : null, column: column }; } function LessError(e, env) { var input = getInput(e, env), loc = getLocation(e.index, input), line = loc.line, col = loc.column, lines = input.split('\n'); this.type = e.type || 'Syntax'; this.message = e.message; this.filename = e.filename || env.filename; this.index = e.index; this.line = typeof(line) === 'number' ? line + 1 : null; this.callLine = e.call && (getLocation(e.call, input) + 1); this.callExtract = lines[getLocation(e.call, input)]; this.stack = e.stack; this.column = col; this.extract = [ lines[line - 1], lines[line], lines[line + 1] ]; } this.env = env = env || {}; // The optimization level dictates the thoroughness of the parser, // the lower the number, the less nodes it will create in the tree. // This could matter for debugging, or if you want to access // the individual nodes in the tree. this.optimization = ('optimization' in this.env) ? this.env.optimization : 1; this.env.filename = this.env.filename || null; // // The Parser // return parser = { imports: imports, // // Parse an input string into an abstract syntax tree, // call `callback` when done. // parse: function (str, callback) { var root, start, end, zone, line, lines, buff = [], c, error = null; i = j = current = furthest = 0; chunks = []; input = str.replace(/\r\n/g, '\n'); // Split the input into chunks. chunks = (function (chunks) { var j = 0, skip = /[^"'`\{\}\/\(\)]+/g, comment = /\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g, level = 0, match, chunk = chunks[0], inParam, inString; for (var i = 0, c, cc; i < input.length; i++) { skip.lastIndex = i; if (match = skip.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); } } c = input.charAt(i); comment.lastIndex = i; if (!inString && !inParam && c === '/') { cc = input.charAt(i + 1); if (cc === '/' || cc === '*') { if (match = comment.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); c = input.charAt(i); } } } } if (c === '{' && !inString && !inParam) { level ++; chunk.push(c); } else if (c === '}' && !inString && !inParam) { level --; chunk.push(c); chunks[++j] = chunk = []; } else if (c === '(' && !inString && !inParam) { chunk.push(c); inParam = true; } else if (c === ')' && !inString && inParam) { chunk.push(c); inParam = false; } else { if (c === '"' || c === "'" || c === '`') { if (! inString) { inString = c; } else { inString = inString === c ? false : inString; } } chunk.push(c); } } if (level > 0) { throw { type: 'Syntax', message: "Missing closing `}`", filename: env.filename }; } return chunks.map(function (c) { return c.join('') });; })([[]]); // Start with the primary rule. // The whole syntax tree is held under a Ruleset node, // with the `root` property set to true, so no `{}` are // output. The callback is called when the input is parsed. try { root = new(tree.Ruleset)([], $(this.parsers.primary)); root.root = true; } catch (e) { return callback(new(LessError)(e, env)); } root.toCSS = (function (evaluate) { var line, lines, column; return function (options, variables) { var frames = [], importError; options = options || {}; // // Allows setting variables with a hash, so: // // `{ color: new(tree.Color)('#f01') }` will become: // // new(tree.Rule)('@color', // new(tree.Value)([ // new(tree.Expression)([ // new(tree.Color)('#f01') // ]) // ]) // ) // if (typeof(variables) === 'object' && !Array.isArray(variables)) { variables = Object.keys(variables).map(function (k) { var value = variables[k]; if (! (value instanceof tree.Value)) { if (! (value instanceof tree.Expression)) { value = new(tree.Expression)([value]); } value = new(tree.Value)([value]); } return new(tree.Rule)('@' + k, value, false, 0); }); frames = [new(tree.Ruleset)(null, variables)]; } try { var css = evaluate.call(this, { frames: frames }) .toCSS([], { compress: options.compress || false }); } catch (e) { throw new(LessError)(e, env); } if ((importError = parser.imports.error)) { // Check if there was an error during importing if (importError instanceof LessError) throw importError; else throw new(LessError)(importError, env); } if (options.yuicompress && less.mode === 'node') { return require('./cssmin').compressor.cssmin(css); } else if (options.compress) { return css.replace(/(\s)+/g, "$1"); } else { return css; } }; })(root.eval); // If `i` is smaller than the `input.length - 1`, // it means the parser wasn't able to parse the whole // string, so we've got a parsing error. // // We try to extract a \n delimited string, // showing the line where the parse error occured. // We split it up into two parts (the part which parsed, // and the part which didn't), so we can color them differently. if (i < input.length - 1) { i = furthest; lines = input.split('\n'); line = (input.slice(0, i).match(/\n/g) || "").length + 1; for (var n = i, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } error = { type: "Parse", message: "Syntax Error on line " + line, index: i, filename: env.filename, line: line, column: column, extract: [ lines[line - 2], lines[line - 1], lines[line] ] }; } if (this.imports.queue.length > 0) { finish = function () { callback(error, root) }; } else { callback(error, root); } }, // // Here in, the parsing rules/functions // // The basic structure of the syntax tree generated is as follows: // // Ruleset -> Rule -> Value -> Expression -> Entity // // Here's some LESS code: // // .class { // color: #fff; // border: 1px solid #000; // width: @w + 4px; // > .child {...} // } // // And here's what the parse tree might look like: // // Ruleset (Selector '.class', [ // Rule ("color", Value ([Expression [Color #fff]])) // Rule ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]])) // Rule ("width", Value ([Expression [Operation "+" [Variable "@w"][Dimension 4px]]])) // Ruleset (Selector [Element '>', '.child'], [...]) // ]) // // In general, most rules will try to parse a token with the `$()` function, and if the return // value is truly, will return a new node, of the relevant type. Sometimes, we need to check // first, before parsing, that's when we use `peek()`. // parsers: { // // The `primary` rule is the *entry* and *exit* point of the parser. // The rules here can appear at any level of the parse tree. // // The recursive nature of the grammar is an interplay between the `block` // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule, // as represented by this simplified grammar: // // primary → (ruleset | rule)+ // ruleset → selector+ block // block → '{' primary '}' // // Only at one point is the primary rule not called from the // block rule: at the root level. // primary: function () { var node, root = []; while ((node = $(this.mixin.definition) || $(this.rule) || $(this.ruleset) || $(this.mixin.call) || $(this.comment) || $(this.directive)) || $(/^[\s\n]+/)) { node && root.push(node); } return root; }, // We create a Comment node for CSS comments `/* */`, // but keep the LeSS comments `//` silent, by just skipping // over them. comment: function () { var comment; if (input.charAt(i) !== '/') return; if (input.charAt(i + 1) === '/') { return new(tree.Comment)($(/^\/\/.*/), true); } else if (comment = $(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/)) { return new(tree.Comment)(comment); } }, // // Entities are tokens which can be found inside an Expression // entities: { // // A string, which supports escaping " and ' // // "milky way" 'he\'s the one!' // quoted: function () { var str, j = i, e; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '"' && input.charAt(j) !== "'") return; e && $('~'); if (str = $(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/)) { return new(tree.Quoted)(str[0], str[1] || str[2], e); } }, // // A catch-all word, such as: // // black border-collapse // keyword: function () { var k; if (k = $(/^[_A-Za-z-][_A-Za-z0-9-]*/)) { if (tree.colors.hasOwnProperty(k)) { // detect named color return new(tree.Color)(tree.colors[k].slice(1)); } else { return new(tree.Keyword)(k); } } }, // // A function call // // rgb(255, 0, 255) // // We also try to catch IE's `alpha()`, but let the `alpha` parser // deal with the details. // // The arguments are parsed with the `entities.arguments` parser. // call: function () { var name, args, index = i; if (! (name = /^([\w-]+|%|progid:[\w\.]+)\(/.exec(chunks[j]))) return; name = name[1].toLowerCase(); if (name === 'url') { return null } else { i += name.length } if (name === 'alpha') { return $(this.alpha) } $('('); // Parse the '(' and consume whitespace. args = $(this.entities.arguments); if (! $(')')) return; if (name) { return new(tree.Call)(name, args, index, env.filename) } }, arguments: function () { var args = [], arg; while (arg = $(this.entities.assignment) || $(this.expression)) { args.push(arg); if (! $(',')) { break } } return args; }, literal: function () { return $(this.entities.dimension) || $(this.entities.color) || $(this.entities.quoted); }, // Assignments are argument entities for calls. // They are present in ie filter properties as shown below. // // filter: progid:DXImageTransform.Microsoft.Alpha( *opacity=50* ) // assignment: function () { var key, value; if ((key = $(/^\w+(?=\s?=)/i)) && $('=') && (value = $(this.entity))) { return new(tree.Assignment)(key, value); } }, // // Parse url() tokens // // We use a specific rule for urls, because they don't really behave like // standard function calls. The difference is that the argument doesn't have // to be enclosed within a string, so it can't be parsed as an Expression. // url: function () { var value; if (input.charAt(i) !== 'u' || !$(/^url\(/)) return; value = $(this.entities.quoted) || $(this.entities.variable) || $(this.entities.dataURI) || $(/^[-\w%@$\/.&=:;#+?~]+/) || ""; expect(')'); return new(tree.URL)((value.value || value.data || value instanceof tree.Variable) ? value : new(tree.Anonymous)(value), imports.paths); }, dataURI: function () { var obj; if ($(/^data:/)) { obj = {}; obj.mime = $(/^[^\/]+\/[^,;)]+/) || ''; obj.charset = $(/^;\s*charset=[^,;)]+/) || ''; obj.base64 = $(/^;\s*base64/) || ''; obj.data = $(/^,\s*[^)]+/); if (obj.data) { return obj } } }, // // A Variable entity, such as `@fink`, in // // width: @fink + 2px // // We use a different parser for variable definitions, // see `parsers.variable`. // variable: function () { var name, index = i; if (input.charAt(i) === '@' && (name = $(/^@@?[\w-]+/))) { return new(tree.Variable)(name, index, env.filename); } }, // // A Hexadecimal color // // #4F3C2F // // `rgb` and `hsl` colors are parsed through the `entities.call` parser. // color: function () { var rgb; if (input.charAt(i) === '#' && (rgb = $(/^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})/))) { return new(tree.Color)(rgb[1]); } }, // // A Dimension, that is, a number and a unit // // 0.5em 95% // dimension: function () { var value, c = input.charCodeAt(i); if ((c > 57 || c < 45) || c === 47) return; if (value = $(/^(-?\d*\.?\d+)(px|%|em|rem|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn)?/)) { return new(tree.Dimension)(value[1], value[2]); } }, // // JavaScript code to be evaluated // // `window.location.href` // javascript: function () { var str, j = i, e; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '`') { return } e && $('~'); if (str = $(/^`([^`]*)`/)) { return new(tree.JavaScript)(str[1], i, e); } } }, // // The variable part of a variable definition. Used in the `rule` parser // // @fink: // variable: function () { var name; if (input.charAt(i) === '@' && (name = $(/^(@[\w-]+)\s*:/))) { return name[1] } }, // // A font size/line-height shorthand // // small/12px // // We need to peek first, or we'll match on keywords and dimensions // shorthand: function () { var a, b; if (! peek(/^[@\w.%-]+\/[@\w.-]+/)) return; if ((a = $(this.entity)) && $('/') && (b = $(this.entity))) { return new(tree.Shorthand)(a, b); } }, // // Mixins // mixin: { // // A Mixin call, with an optional argument list // // #mixins > .square(#fff); // .rounded(4px, black); // .button; // // The `while` loop is there because mixins can be // namespaced, but we only support the child and descendant // selector for now. // call: function () { var elements = [], e, c, args, index = i, s = input.charAt(i), important = false; if (s !== '.' && s !== '#') { return } while (e = $(/^[#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/)) { elements.push(new(tree.Element)(c, e, i)); c = $('>'); } $('(') && (args = $(this.entities.arguments)) && $(')'); if ($(this.important)) { important = true; } if (elements.length > 0 && ($(';') || peek('}'))) { return new(tree.mixin.Call)(elements, args, index, env.filename, important); } }, // // A Mixin definition, with a list of parameters // // .rounded (@radius: 2px, @color) { // ... // } // // Until we have a finer grained state-machine, we have to // do a look-ahead, to make sure we don't have a mixin call. // See the `rule` function for more information. // // We start by matching `.rounded (`, and then proceed on to // the argument list, which has optional default values. // We store the parameters in `params`, with a `value` key, // if there is a value, such as in the case of `@radius`. // // Once we've got our params list, and a closing `)`, we parse // the `{...}` block. // definition: function () { var name, params = [], match, ruleset, param, value, cond; if ((input.charAt(i) !== '.' && input.charAt(i) !== '#') || peek(/^[^{]*(;|})/)) return; save(); if (match = $(/^([#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+)\s*\(/)) { name = match[1]; while (param = $(this.entities.variable) || $(this.entities.literal) || $(this.entities.keyword)) { // Variable if (param instanceof tree.Variable) { if ($(':')) { value = expect(this.expression, 'expected expression'); params.push({ name: param.name, value: value }); } else { params.push({ name: param.name }); } } else { params.push({ value: param }); } if (! $(',')) { break } } expect(')'); if ($(/^when/)) { // Guard cond = expect(this.conditions, 'expected condition'); } ruleset = $(this.block); if (ruleset) { return new(tree.mixin.Definition)(name, params, ruleset, cond); } else { restore(); } } } }, // // Entities are the smallest recognized token, // and can be found inside a rule's value. // entity: function () { return $(this.entities.literal) || $(this.entities.variable) || $(this.entities.url) || $(this.entities.call) || $(this.entities.keyword) || $(this.entities.javascript) || $(this.comment); }, // // A Rule terminator. Note that we use `peek()` to check for '}', // because the `block` rule will be expecting it, but we still need to make sure // it's there, if ';' was ommitted. // end: function () { return $(';') || peek('}'); }, // // IE's alpha function // // alpha(opacity=88) // alpha: function () { var value; if (! $(/^\(opacity=/i)) return; if (value = $(/^\d+/) || $(this.entities.variable)) { expect(')'); return new(tree.Alpha)(value); } }, // // A Selector Element // // div // + h1 // #socks // input[type="text"] // // Elements are the building blocks for Selectors, // they are made out of a `Combinator` (see combinator rule), // and an element name, such as a tag a class, or `*`. // element: function () { var e, t, c, v; c = $(this.combinator); e = $(/^(?:\d+\.\d+|\d+)%/) || $(/^(?:[.#]?|:*)(?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/) || $('*') || $(this.attribute) || $(/^\([^)@]+\)/); if (! e) { $('(') && (v = $(this.entities.variable)) && $(')') && (e = new(tree.Paren)(v)); } if (e) { return new(tree.Element)(c, e, i) } if (c.value && c.value.charAt(0) === '&') { return new(tree.Element)(c, null, i); } }, // // Combinators combine elements together, in a Selector. // // Because our parser isn't white-space sensitive, special care // has to be taken, when parsing the descendant combinator, ` `, // as it's an empty space. We have to check the previous character // in the input, to see if it's a ` ` character. More info on how // we deal with this in *combinator.js*. // combinator: function () { var match, c = input.charAt(i); if (c === '>' || c === '+' || c === '~') { i++; while (input.charAt(i) === ' ') { i++ } return new(tree.Combinator)(c); } else if (c === '&') { match = '&'; i++; if(input.charAt(i) === ' ') { match = '& '; } while (input.charAt(i) === ' ') { i++ } return new(tree.Combinator)(match); } else if (c === ':' && input.charAt(i + 1) === ':') { i += 2; while (input.charAt(i) === ' ') { i++ } return new(tree.Combinator)('::'); } else if (input.charAt(i - 1) === ' ') { return new(tree.Combinator)(" "); } else { return new(tree.Combinator)(null); } }, // // A CSS Selector // // .class > div + h1 // li a:hover // // Selectors are made out of one or more Elements, see above. // selector: function () { var sel, e, elements = [], c, match; while (e = $(this.element)) { c = input.charAt(i); elements.push(e) if (c === '{' || c === '}' || c === ';' || c === ',') { break } } if (elements.length > 0) { return new(tree.Selector)(elements) } }, tag: function () { return $(/^[a-zA-Z][a-zA-Z-]*[0-9]?/) || $('*'); }, attribute: function () { var attr = '', key, val, op; if (! $('[')) return; if (key = $(/^[a-zA-Z-]+/) || $(this.entities.quoted)) { if ((op = $(/^[|~*$^]?=/)) && (val = $(this.entities.quoted) || $(/^[\w-]+/))) { attr = [key, op, val.toCSS ? val.toCSS() : val].join(''); } else { attr = key } } if (! $(']')) return; if (attr) { return "[" + attr + "]" } }, // // The `block` rule is used by `ruleset` and `mixin.definition`. // It's a wrapper around the `primary` rule, with added `{}`. // block: function () { var content; if ($('{') && (content = $(this.primary)) && $('}')) { return content; } }, // // div, .class, body > p {...} // ruleset: function () { var selectors = [], s, rules, match; save(); while (s = $(this.selector)) { selectors.push(s); $(this.comment); if (! $(',')) { break } $(this.comment); } if (selectors.length > 0 && (rules = $(this.block))) { return new(tree.Ruleset)(selectors, rules); } else { // Backtrack furthest = i; restore(); } }, rule: function () { var name, value, c = input.charAt(i), important, match; save(); if (c === '.' || c === '#' || c === '&') { return } if (name = $(this.variable) || $(this.property)) { if ((name.charAt(0) != '@') && (match = /^([^@+\/'"*`(;{}-]*);/.exec(chunks[j]))) { i += match[0].length - 1; value = new(tree.Anonymous)(match[1]); } else if (name === "font") { value = $(this.font); } else { value = $(this.value); } important = $(this.important); if (value && $(this.end)) { return new(tree.Rule)(name, value, important, memo); } else { furthest = i; restore(); } } }, // // An @import directive // // @import "lib"; // // Depending on our environemnt, importing is done differently: // In the browser, it's an XHR request, in Node, it would be a // file-system operation. The function used for importing is // stored in `import`, which we pass to the Import constructor. // "import": function () { var path, features, index = i; if ($(/^@import\s+/) && (path = $(this.entities.quoted) || $(this.entities.url))) { features = $(this.mediaFeatures); if ($(';')) { return new(tree.Import)(path, imports, features, index); } } }, mediaFeature: function () { var nodes = []; do { if (e = $(this.entities.keyword)) { nodes.push(e); } else if ($('(')) { p = $(this.property); e = $(this.entity); if ($(')')) { if (p && e) { nodes.push(new(tree.Paren)(new(tree.Rule)(p, e, null, i, true))); } else if (e) { nodes.push(new(tree.Paren)(e)); } else { return null; } } else { return null } } } while (e); if (nodes.length > 0) { return new(tree.Expression)(nodes); } }, mediaFeatures: function () { var f, features = []; while (f = $(this.mediaFeature)) { features.push(f); if (! $(',')) { break } } return features.length > 0 ? features : null; }, media: function () { var features; if ($(/^@media/)) { features = $(this.mediaFeatures); if (rules = $(this.block)) { return new(tree.Directive)('@media', rules, features); } } }, // // A CSS Directive // // @charset "utf-8"; // directive: function () { var name, value, rules, types, e, nodes; if (input.charAt(i) !== '@') return; if (value = $(this['import']) || $(this.media)) { return value; } else if (name = $(/^@page|@keyframes/) || $(/^@(?:-webkit-|-moz-|-o-|-ms-)[a-z0-9-]+/)) { types = ($(/^[^{]+/) || '').trim(); if (rules = $(this.block)) { return new(tree.Directive)(name + " " + types, rules); } } else if (name = $(/^@[-a-z]+/)) { if (name === '@font-face') { if (rules = $(this.block)) { return new(tree.Directive)(name, rules); } } else if ((value = $(this.entity)) && $(';')) { return new(tree.Directive)(name, value); } } }, font: function () { var value = [], expression = [], weight, shorthand, font, e; while (e = $(this.shorthand) || $(this.entity)) { expression.push(e); } value.push(new(tree.Expression)(expression)); if ($(',')) { while (e = $(this.expression)) { value.push(e); if (! $(',')) { break } } } return new(tree.Value)(value); }, // // A Value is a comma-delimited list of Expressions // // font-family: Baskerville, Georgia, serif; // // In a Rule, a Value represents everything after the `:`, // and before the `;`. // value: function () { var e, expressions = [], important; while (e = $(this.expression)) { expressions.push(e); if (! $(',')) { break } } if (expressions.length > 0) { return new(tree.Value)(expressions); } }, important: function () { if (input.charAt(i) === '!') { return $(/^! *important/); } }, sub: function () { var e; if ($('(') && (e = $(this.expression)) && $(')')) { return e; } }, multiplication: function () { var m, a, op, operation; if (m = $(this.operand)) { while (!peek(/^\/\*/) && (op = ($('/') || $('*'))) && (a = $(this.operand))) { operation = new(tree.Operation)(op, [operation || m, a]); } return operation || m; } }, addition: function () { var m, a, op, operation; if (m = $(this.multiplication)) { while ((op = $(/^[-+]\s+/) || (input.charAt(i - 1) != ' ' && ($('+') || $('-')))) && (a = $(this.multiplication))) { operation = new(tree.Operation)(op, [operation || m, a]); } return operation || m; } }, conditions: function () { var a, b, index = i, condition; if (a = $(this.condition)) { while ($(',') && (b = $(this.condition))) { condition = new(tree.Condition)('or', condition || a, b, index); } return condition || a; } }, condition: function () { var a, b, c, op, index = i, negate = false; if ($(/^not/)) { negate = true } expect('('); if (a = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) { if (op = $(/^(?:>=|=<|[<=>])/)) { if (b = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) { c = new(tree.Condition)(op, a, b, index, negate); } else { error('expected expression'); } } else { c = new(tree.Condition)('=', a, new(tree.Keyword)('true'), index, negate); } expect(')'); return $(/^and/) ? new(tree.Condition)('and', c, $(this.condition)) : c; } }, // // An operand is anything that can be part of an operation, // such as a Color, or a Variable // operand: function () { var negate, p = input.charAt(i + 1); if (input.charAt(i) === '-' && (p === '@' || p === '(')) { negate = $('-') } var o = $(this.sub) || $(this.entities.dimension) || $(this.entities.color) || $(this.entities.variable) || $(this.entities.call); return negate ? new(tree.Operation)('*', [new(tree.Dimension)(-1), o]) : o; }, // // Expressions either represent mathematical operations, // or white-space delimited Entities. // // 1px solid black // @var * 2 // expression: function () { var e, delim, entities = [], d; while (e = $(this.addition) || $(this.entity)) { entities.push(e); } if (entities.length > 0) { return new(tree.Expression)(entities); } }, property: function () { var name; if (name = $(/^(\*?-?[-a-z_0-9]+)\s*:/)) { return name[1]; } } } }; }; if (less.mode === 'browser' || less.mode === 'rhino') { // // Used by `@import` directives // less.Parser.importer = function (path, paths, callback, env) { if (path.charAt(0) !== '/' && paths.length > 0) { path = paths[0] + path; } // We pass `true` as 3rd argument, to force the reload of the import. // This is so we can get the syntax tree as opposed to just the CSS output, // as we need this to evaluate the current stylesheet. loadStyleSheet({ href: path, title: path, type: env.mime }, callback, true); }; } (function (tree) { tree.functions = { rgb: function (r, g, b) { return this.rgba(r, g, b, 1.0); }, rgba: function (r, g, b, a) { var rgb = [r, g, b].map(function (c) { return number(c) }), a = number(a); return new(tree.Color)(rgb, a); }, hsl: function (h, s, l) { return this.hsla(h, s, l, 1.0); }, hsla: function (h, s, l, a) { h = (number(h) % 360) / 360; s = number(s); l = number(l); a = number(a); var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s; var m1 = l * 2 - m2; return this.rgba(hue(h + 1/3) * 255, hue(h) * 255, hue(h - 1/3) * 255, a); function hue(h) { h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h); if (h * 6 < 1) return m1 + (m2 - m1) * h * 6; else if (h * 2 < 1) return m2; else if (h * 3 < 2) return m1 + (m2 - m1) * (2/3 - h) * 6; else return m1; } }, hue: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().h)); }, saturation: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().s * 100), '%'); }, lightness: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().l * 100), '%'); }, alpha: function (color) { return new(tree.Dimension)(color.toHSL().a); }, saturate: function (color, amount) { var hsl = color.toHSL(); hsl.s += amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, desaturate: function (color, amount) { var hsl = color.toHSL(); hsl.s -= amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, lighten: function (color, amount) { var hsl = color.toHSL(); hsl.l += amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, darken: function (color, amount) { var hsl = color.toHSL(); hsl.l -= amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, fadein: function (color, amount) { var hsl = color.toHSL(); hsl.a += amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, fadeout: function (color, amount) { var hsl = color.toHSL(); hsl.a -= amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, fade: function (color, amount) { var hsl = color.toHSL(); hsl.a = amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, spin: function (color, amount) { var hsl = color.toHSL(); var hue = (hsl.h + amount.value) % 360; hsl.h = hue < 0 ? 360 + hue : hue; return hsla(hsl); }, // // Copyright (c) 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein // http://sass-lang.com // mix: function (color1, color2, weight) { var p = weight.value / 100.0; var w = p * 2 - 1; var a = color1.toHSL().a - color2.toHSL().a; var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0; var w2 = 1 - w1; var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2, color1.rgb[1] * w1 + color2.rgb[1] * w2, color1.rgb[2] * w1 + color2.rgb[2] * w2]; var alpha = color1.alpha * p + color2.alpha * (1 - p); return new(tree.Color)(rgb, alpha); }, greyscale: function (color) { return this.desaturate(color, new(tree.Dimension)(100)); }, e: function (str) { return new(tree.Anonymous)(str instanceof tree.JavaScript ? str.evaluated : str); }, escape: function (str) { return new(tree.Anonymous)(encodeURI(str.value).replace(/=/g, "%3D").replace(/:/g, "%3A").replace(/#/g, "%23").replace(/;/g, "%3B").replace(/\(/g, "%28").replace(/\)/g, "%29")); }, '%': function (quoted /* arg, arg, ...*/) { var args = Array.prototype.slice.call(arguments, 1), str = quoted.value; for (var i = 0; i < args.length; i++) { str = str.replace(/%[sda]/i, function(token) { var value = token.match(/s/i) ? args[i].value : args[i].toCSS(); return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value; }); } str = str.replace(/%%/g, '%'); return new(tree.Quoted)('"' + str + '"', str); }, round: function (n) { return this._math('round', n); }, ceil: function (n) { return this._math('ceil', n); }, floor: function (n) { return this._math('floor', n); }, _math: function (fn, n) { if (n instanceof tree.Dimension) { return new(tree.Dimension)(Math[fn](number(n)), n.unit); } else if (typeof(n) === 'number') { return Math[fn](n); } else { throw { type: "Argument", message: "argument must be a number" }; } }, argb: function (color) { return new(tree.Anonymous)(color.toARGB()); }, percentage: function (n) { return new(tree.Dimension)(n.value * 100, '%'); }, color: function (n) { if (n instanceof tree.Quoted) { return new(tree.Color)(n.value.slice(1)); } else { throw { type: "Argument", message: "argument must be a string" }; } }, iscolor: function (n) { return this._isa(n, tree.Color); }, isnumber: function (n) { return this._isa(n, tree.Dimension); }, isstring: function (n) { return this._isa(n, tree.Quoted); }, iskeyword: function (n) { return this._isa(n, tree.Keyword); }, isurl: function (n) { return this._isa(n, tree.URL); }, ispixel: function (n) { return (n instanceof tree.Dimension) && n.unit === 'px' ? tree.True : tree.False; }, ispercentage: function (n) { return (n instanceof tree.Dimension) && n.unit === '%' ? tree.True : tree.False; }, isem: function (n) { return (n instanceof tree.Dimension) && n.unit === 'em' ? tree.True : tree.False; }, _isa: function (n, Type) { return (n instanceof Type) ? tree.True : tree.False; } }; function hsla(hsla) { return tree.functions.hsla(hsla.h, hsla.s, hsla.l, hsla.a); } function number(n) { if (n instanceof tree.Dimension) { return parseFloat(n.unit == '%' ? n.value / 100 : n.value); } else if (typeof(n) === 'number') { return n; } else { throw { error: "RuntimeError", message: "color functions take numbers as parameters" }; } } function clamp(val) { return Math.min(1, Math.max(0, val)); } })(require('./tree')); (function (tree) { tree.colors = { 'aliceblue':'#f0f8ff', 'antiquewhite':'#faebd7', 'aqua':'#00ffff', 'aquamarine':'#7fffd4', 'azure':'#f0ffff', 'beige':'#f5f5dc', 'bisque':'#ffe4c4', 'black':'#000000', 'blanchedalmond':'#ffebcd', 'blue':'#0000ff', 'blueviolet':'#8a2be2', 'brown':'#a52a2a', 'burlywood':'#deb887', 'cadetblue':'#5f9ea0', 'chartreuse':'#7fff00', 'chocolate':'#d2691e', 'coral':'#ff7f50', 'cornflowerblue':'#6495ed', 'cornsilk':'#fff8dc', 'crimson':'#dc143c', 'cyan':'#00ffff', 'darkblue':'#00008b', 'darkcyan':'#008b8b', 'darkgoldenrod':'#b8860b', 'darkgray':'#a9a9a9', 'darkgrey':'#a9a9a9', 'darkgreen':'#006400', 'darkkhaki':'#bdb76b', 'darkmagenta':'#8b008b', 'darkolivegreen':'#556b2f', 'darkorange':'#ff8c00', 'darkorchid':'#9932cc', 'darkred':'#8b0000', 'darksalmon':'#e9967a', 'darkseagreen':'#8fbc8f', 'darkslateblue':'#483d8b', 'darkslategray':'#2f4f4f', 'darkslategrey':'#2f4f4f', 'darkturquoise':'#00ced1', 'darkviolet':'#9400d3', 'deeppink':'#ff1493', 'deepskyblue':'#00bfff', 'dimgray':'#696969', 'dimgrey':'#696969', 'dodgerblue':'#1e90ff', 'firebrick':'#b22222', 'floralwhite':'#fffaf0', 'forestgreen':'#228b22', 'fuchsia':'#ff00ff', 'gainsboro':'#dcdcdc', 'ghostwhite':'#f8f8ff', 'gold':'#ffd700', 'goldenrod':'#daa520', 'gray':'#808080', 'grey':'#808080', 'green':'#008000', 'greenyellow':'#adff2f', 'honeydew':'#f0fff0', 'hotpink':'#ff69b4', 'indianred':'#cd5c5c', 'indigo':'#4b0082', 'ivory':'#fffff0', 'khaki':'#f0e68c', 'lavender':'#e6e6fa', 'lavenderblush':'#fff0f5', 'lawngreen':'#7cfc00', 'lemonchiffon':'#fffacd', 'lightblue':'#add8e6', 'lightcoral':'#f08080', 'lightcyan':'#e0ffff', 'lightgoldenrodyellow':'#fafad2', 'lightgray':'#d3d3d3', 'lightgrey':'#d3d3d3', 'lightgreen':'#90ee90', 'lightpink':'#ffb6c1', 'lightsalmon':'#ffa07a', 'lightseagreen':'#20b2aa', 'lightskyblue':'#87cefa', 'lightslategray':'#778899', 'lightslategrey':'#778899', 'lightsteelblue':'#b0c4de', 'lightyellow':'#ffffe0', 'lime':'#00ff00', 'limegreen':'#32cd32', 'linen':'#faf0e6', 'magenta':'#ff00ff', 'maroon':'#800000', 'mediumaquamarine':'#66cdaa', 'mediumblue':'#0000cd', 'mediumorchid':'#ba55d3', 'mediumpurple':'#9370d8', 'mediumseagreen':'#3cb371', 'mediumslateblue':'#7b68ee', 'mediumspringgreen':'#00fa9a', 'mediumturquoise':'#48d1cc', 'mediumvioletred':'#c71585', 'midnightblue':'#191970', 'mintcream':'#f5fffa', 'mistyrose':'#ffe4e1', 'moccasin':'#ffe4b5', 'navajowhite':'#ffdead', 'navy':'#000080', 'oldlace':'#fdf5e6', 'olive':'#808000', 'olivedrab':'#6b8e23', 'orange':'#ffa500', 'orangered':'#ff4500', 'orchid':'#da70d6', 'palegoldenrod':'#eee8aa', 'palegreen':'#98fb98', 'paleturquoise':'#afeeee', 'palevioletred':'#d87093', 'papayawhip':'#ffefd5', 'peachpuff':'#ffdab9', 'peru':'#cd853f', 'pink':'#ffc0cb', 'plum':'#dda0dd', 'powderblue':'#b0e0e6', 'purple':'#800080', 'red':'#ff0000', 'rosybrown':'#bc8f8f', 'royalblue':'#4169e1', 'saddlebrown':'#8b4513', 'salmon':'#fa8072', 'sandybrown':'#f4a460', 'seagreen':'#2e8b57', 'seashell':'#fff5ee', 'sienna':'#a0522d', 'silver':'#c0c0c0', 'skyblue':'#87ceeb', 'slateblue':'#6a5acd', 'slategray':'#708090', 'slategrey':'#708090', 'snow':'#fffafa', 'springgreen':'#00ff7f', 'steelblue':'#4682b4', 'tan':'#d2b48c', 'teal':'#008080', 'thistle':'#d8bfd8', 'tomato':'#ff6347', 'turquoise':'#40e0d0', 'violet':'#ee82ee', 'wheat':'#f5deb3', 'white':'#ffffff', 'whitesmoke':'#f5f5f5', 'yellow':'#ffff00', 'yellowgreen':'#9acd32' }; })(require('./tree')); (function (tree) { tree.Alpha = function (val) { this.value = val; }; tree.Alpha.prototype = { toCSS: function () { return "alpha(opacity=" + (this.value.toCSS ? this.value.toCSS() : this.value) + ")"; }, eval: function (env) { if (this.value.eval) { this.value = this.value.eval(env) } return this; } }; })(require('../tree')); (function (tree) { tree.Anonymous = function (string) { this.value = string.value || string; }; tree.Anonymous.prototype = { toCSS: function () { return this.value; }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.Assignment = function (key, val) { this.key = key; this.value = val; }; tree.Assignment.prototype = { toCSS: function () { return this.key + '=' + (this.value.toCSS ? this.value.toCSS() : this.value); }, eval: function (env) { if (this.value.eval) { this.value = this.value.eval(env) } return this; } }; })(require('../tree'));(function (tree) { // // A function call node. // tree.Call = function (name, args, index, filename) { this.name = name; this.args = args; this.index = index; this.filename = filename; }; tree.Call.prototype = { // // When evaluating a function call, // we either find the function in `tree.functions` [1], // in which case we call it, passing the evaluated arguments, // or we simply print it out as it appeared originally [2]. // // The *functions.js* file contains the built-in functions. // // The reason why we evaluate the arguments, is in the case where // we try to pass a variable to a function, like: `saturate(@color)`. // The function should receive the value, not the variable. // eval: function (env) { var args = this.args.map(function (a) { return a.eval(env) }); if (this.name in tree.functions) { // 1. try { return tree.functions[this.name].apply(tree.functions, args); } catch (e) { throw { type: e.type || "Runtime", message: "error evaluating function `" + this.name + "`" + (e.message ? ': ' + e.message : ''), index: this.index, filename: this.filename }; } } else { // 2. return new(tree.Anonymous)(this.name + "(" + args.map(function (a) { return a.toCSS() }).join(', ') + ")"); } }, toCSS: function (env) { return this.eval(env).toCSS(); } }; })(require('../tree')); (function (tree) { // // RGB Colors - #ff0014, #eee // tree.Color = function (rgb, a) { // // The end goal here, is to parse the arguments // into an integer triplet, such as `128, 255, 0` // // This facilitates operations and conversions. // if (Array.isArray(rgb)) { this.rgb = rgb; } else if (rgb.length == 6) { this.rgb = rgb.match(/.{2}/g).map(function (c) { return parseInt(c, 16); }); } else { this.rgb = rgb.split('').map(function (c) { return parseInt(c + c, 16); }); } this.alpha = typeof(a) === 'number' ? a : 1; }; tree.Color.prototype = { eval: function () { return this }, // // If we have some transparency, the only way to represent it // is via `rgba`. Otherwise, we use the hex representation, // which has better compatibility with older browsers. // Values are capped between `0` and `255`, rounded and zero-padded. // toCSS: function () { if (this.alpha < 1.0) { return "rgba(" + this.rgb.map(function (c) { return Math.round(c); }).concat(this.alpha).join(', ') + ")"; } else { return '#' + this.rgb.map(function (i) { i = Math.round(i); i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16); return i.length === 1 ? '0' + i : i; }).join(''); } }, // // Operations have to be done per-channel, if not, // channels will spill onto each other. Once we have // our result, in the form of an integer triplet, // we create a new Color node to hold the result. // operate: function (op, other) { var result = []; if (! (other instanceof tree.Color)) { other = other.toColor(); } for (var c = 0; c < 3; c++) { result[c] = tree.operate(op, this.rgb[c], other.rgb[c]); } return new(tree.Color)(result, this.alpha + other.alpha); }, toHSL: function () { var r = this.rgb[0] / 255, g = this.rgb[1] / 255, b = this.rgb[2] / 255, a = this.alpha; var max = Math.max(r, g, b), min = Math.min(r, g, b); var h, s, l = (max + min) / 2, d = max - min; if (max === min) { h = s = 0; } else { s = l > 0.5 ? d / (2 - max - min) : d / (max + min); switch (max) { case r: h = (g - b) / d + (g < b ? 6 : 0); break; case g: h = (b - r) / d + 2; break; case b: h = (r - g) / d + 4; break; } h /= 6; } return { h: h * 360, s: s, l: l, a: a }; }, toARGB: function () { var argb = [Math.round(this.alpha * 255)].concat(this.rgb); return '#' + argb.map(function (i) { i = Math.round(i); i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16); return i.length === 1 ? '0' + i : i; }).join(''); } }; })(require('../tree')); (function (tree) { tree.Comment = function (value, silent) { this.value = value; this.silent = !!silent; }; tree.Comment.prototype = { toCSS: function (env) { return env.compress ? '' : this.value; }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.Condition = function (op, l, r, i, negate) { this.op = op.trim(); this.lvalue = l; this.rvalue = r; this.index = i; this.negate = negate; }; tree.Condition.prototype.eval = function (env) { var a = this.lvalue.eval(env), b = this.rvalue.eval(env); var i = this.index, result var result = (function (op) { switch (op) { case 'and': return a && b; case 'or': return a || b; default: if (a.compare) { result = a.compare(b); } else if (b.compare) { result = b.compare(a); } else { throw { type: "Type", message: "Unable to perform comparison", index: i }; } switch (result) { case -1: return op === '<' || op === '=<'; case 0: return op === '=' || op === '>=' || op === '=<'; case 1: return op === '>' || op === '>='; } } })(this.op); return this.negate ? !result : result; }; })(require('../tree')); (function (tree) { // // A number with a unit // tree.Dimension = function (value, unit) { this.value = parseFloat(value); this.unit = unit || null; }; tree.Dimension.prototype = { eval: function () { return this }, toColor: function () { return new(tree.Color)([this.value, this.value, this.value]); }, toCSS: function () { var css = this.value + this.unit; return css; }, // In an operation between two Dimensions, // we default to the first Dimension's unit, // so `1px + 2em` will yield `3px`. // In the future, we could implement some unit // conversions such that `100cm + 10mm` would yield // `101cm`. operate: function (op, other) { return new(tree.Dimension) (tree.operate(op, this.value, other.value), this.unit || other.unit); }, // TODO: Perform unit conversion before comparing compare: function (other) { if (other instanceof tree.Dimension) { if (other.value > this.value) { return -1; } else if (other.value < this.value) { return 1; } else { return 0; } } else { return -1; } } }; })(require('../tree')); (function (tree) { tree.Directive = function (name, value, features) { this.name = name; this.features = features && new(tree.Value)(features); if (Array.isArray(value)) { this.ruleset = new(tree.Ruleset)([], value); this.ruleset.allowImports = true; } else { this.value = value; } }; tree.Directive.prototype = { toCSS: function (ctx, env) { var features = this.features ? ' ' + this.features.toCSS(env) : ''; if (this.ruleset) { this.ruleset.root = true; return this.name + features + (env.compress ? '{' : ' {\n ') + this.ruleset.toCSS(ctx, env).trim().replace(/\n/g, '\n ') + (env.compress ? '}': '\n}\n'); } else { return this.name + ' ' + this.value.toCSS() + ';\n'; } }, eval: function (env) { this.features = this.features && this.features.eval(env); env.frames.unshift(this); this.ruleset = this.ruleset && this.ruleset.eval(env); env.frames.shift(); return this; }, variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) }, find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) }, rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) } }; })(require('../tree')); (function (tree) { tree.Element = function (combinator, value, index) { this.combinator = combinator instanceof tree.Combinator ? combinator : new(tree.Combinator)(combinator); if (typeof(value) === 'string') { this.value = value.trim(); } else if (value) { this.value = value; } else { this.value = ""; } this.index = index; }; tree.Element.prototype.eval = function (env) { return new(tree.Element)(this.combinator, this.value.eval ? this.value.eval(env) : this.value, this.index); }; tree.Element.prototype.toCSS = function (env) { return this.combinator.toCSS(env || {}) + (this.value.toCSS ? this.value.toCSS(env) : this.value); }; tree.Combinator = function (value) { if (value === ' ') { this.value = ' '; } else if (value === '& ') { this.value = '& '; } else { this.value = value ? value.trim() : ""; } }; tree.Combinator.prototype.toCSS = function (env) { return { '' : '', ' ' : ' ', '&' : '', '& ' : ' ', ':' : ' :', '::': '::', '+' : env.compress ? '+' : ' + ', '~' : env.compress ? '~' : ' ~ ', '>' : env.compress ? '>' : ' > ' }[this.value]; }; })(require('../tree')); (function (tree) { tree.Expression = function (value) { this.value = value }; tree.Expression.prototype = { eval: function (env) { if (this.value.length > 1) { return new(tree.Expression)(this.value.map(function (e) { return e.eval(env); })); } else if (this.value.length === 1) { return this.value[0].eval(env); } else { return this; } }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS ? e.toCSS(env) : ''; }).join(' '); } }; })(require('../tree')); (function (tree) { // // CSS @import node // // The general strategy here is that we don't want to wait // for the parsing to be completed, before we start importing // the file. That's because in the context of a browser, // most of the time will be spent waiting for the server to respond. // // On creation, we push the import path to our import queue, though // `import,push`, we also pass it a callback, which it'll call once // the file has been fetched, and parsed. // tree.Import = function (path, imports, features, index) { var that = this; this.index = index; this._path = path; this.features = features && new(tree.Value)(features); // The '.less' extension is optional if (path instanceof tree.Quoted) { this.path = /\.(le?|c)ss(\?.*)?$/.test(path.value) ? path.value : path.value + '.less'; } else { this.path = path.value.value || path.value; } this.css = /css(\?.*)?$/.test(this.path); // Only pre-compile .less files if (! this.css) { imports.push(this.path, function (e, root) { if (e) { e.index = index } that.root = root || new(tree.Ruleset)([], []); }); } }; // // The actual import node doesn't return anything, when converted to CSS. // The reason is that it's used at the evaluation stage, so that the rules // it imports can be treated like any other rules. // // In `eval`, we make sure all Import nodes get evaluated, recursively, so // we end up with a flat structure, which can easily be imported in the parent // ruleset. // tree.Import.prototype = { toCSS: function (env) { var features = this.features ? ' ' + this.features.toCSS(env) : ''; if (this.css) { return "@import " + this._path.toCSS() + features + ';\n'; } else { return ""; } }, eval: function (env) { var ruleset, features = this.features && this.features.eval(env); if (this.css) { return this; } else { ruleset = new(tree.Ruleset)([], this.root.rules.slice(0)); for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.Import) { Array.prototype .splice .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env))); } } return this.features ? new(tree.Directive)('@media', ruleset.rules, this.features.value) : ruleset.rules; } } }; })(require('../tree')); (function (tree) { tree.JavaScript = function (string, index, escaped) { this.escaped = escaped; this.expression = string; this.index = index; }; tree.JavaScript.prototype = { eval: function (env) { var result, that = this, context = {}; var expression = this.expression.replace(/@\{([\w-]+)\}/g, function (_, name) { return tree.jsify(new(tree.Variable)('@' + name, that.index).eval(env)); }); try { expression = new(Function)('return (' + expression + ')'); } catch (e) { throw { message: "JavaScript evaluation error: `" + expression + "`" , index: this.index }; } for (var k in env.frames[0].variables()) { context[k.slice(1)] = { value: env.frames[0].variables()[k].value, toJS: function () { return this.value.eval(env).toCSS(); } }; } try { result = expression.call(context); } catch (e) { throw { message: "JavaScript evaluation error: '" + e.name + ': ' + e.message + "'" , index: this.index }; } if (typeof(result) === 'string') { return new(tree.Quoted)('"' + result + '"', result, this.escaped, this.index); } else if (Array.isArray(result)) { return new(tree.Anonymous)(result.join(', ')); } else { return new(tree.Anonymous)(result); } } }; })(require('../tree')); (function (tree) { tree.Keyword = function (value) { this.value = value }; tree.Keyword.prototype = { eval: function () { return this }, toCSS: function () { return this.value }, compare: function (other) { if (other instanceof tree.Keyword) { return other.value === this.value ? 0 : 1; } else { return -1; } } }; tree.True = new(tree.Keyword)('true'); tree.False = new(tree.Keyword)('false'); })(require('../tree')); (function (tree) { tree.mixin = {}; tree.mixin.Call = function (elements, args, index, filename, important) { this.selector = new(tree.Selector)(elements); this.arguments = args; this.index = index; this.filename = filename; this.important = important; }; tree.mixin.Call.prototype = { eval: function (env) { var mixins, args, rules = [], match = false; for (var i = 0; i < env.frames.length; i++) { if ((mixins = env.frames[i].find(this.selector)).length > 0) { args = this.arguments && this.arguments.map(function (a) { return a.eval(env) }); for (var m = 0; m < mixins.length; m++) { if (mixins[m].match(args, env)) { try { Array.prototype.push.apply( rules, mixins[m].eval(env, this.arguments, this.important).rules); match = true; } catch (e) { throw { message: e.message, index: e.index, filename: this.filename, stack: e.stack, call: this.index }; } } } if (match) { return rules; } else { throw { type: 'Runtime', message: 'No matching definition was found for `' + this.selector.toCSS().trim() + '(' + this.arguments.map(function (a) { return a.toCSS(); }).join(', ') + ")`", index: this.index, filename: this.filename }; } } } throw { type: 'Name', message: this.selector.toCSS().trim() + " is undefined", index: this.index, filename: this.filename }; } }; tree.mixin.Definition = function (name, params, rules, condition) { this.name = name; this.selectors = [new(tree.Selector)([new(tree.Element)(null, name)])]; this.params = params; this.condition = condition; this.arity = params.length; this.rules = rules; this._lookups = {}; this.required = params.reduce(function (count, p) { if (!p.name || (p.name && !p.value)) { return count + 1 } else { return count } }, 0); this.parent = tree.Ruleset.prototype; this.frames = []; }; tree.mixin.Definition.prototype = { toCSS: function () { return "" }, variable: function (name) { return this.parent.variable.call(this, name) }, variables: function () { return this.parent.variables.call(this) }, find: function () { return this.parent.find.apply(this, arguments) }, rulesets: function () { return this.parent.rulesets.apply(this) }, evalParams: function (env, args) { var frame = new(tree.Ruleset)(null, []); for (var i = 0, val; i < this.params.length; i++) { if (this.params[i].name) { if (val = (args && args[i]) || this.params[i].value) { frame.rules.unshift(new(tree.Rule)(this.params[i].name, val.eval(env))); } else { throw { type: 'Runtime', message: "wrong number of arguments for " + this.name + ' (' + args.length + ' for ' + this.arity + ')' }; } } } return frame; }, eval: function (env, args, important) { var frame = this.evalParams(env, args), context, _arguments = [], rules; for (var i = 0; i < Math.max(this.params.length, args && args.length); i++) { _arguments.push(args[i] || this.params[i].value); } frame.rules.unshift(new(tree.Rule)('@arguments', new(tree.Expression)(_arguments).eval(env))); rules = important ? this.rules.map(function (r) { return new(tree.Rule)(r.name, r.value, '!important', r.index); }) : this.rules.slice(0); return new(tree.Ruleset)(null, rules).eval({ frames: [this, frame].concat(this.frames, env.frames) }); }, match: function (args, env) { var argsLength = (args && args.length) || 0, len, frame; if (argsLength < this.required) { return false } if ((this.required > 0) && (argsLength > this.params.length)) { return false } if (this.condition && !this.condition.eval({ frames: [this.evalParams(env, args)].concat(env.frames) })) { return false } len = Math.min(argsLength, this.arity); for (var i = 0; i < len; i++) { if (!this.params[i].name) { if (args[i].eval(env).toCSS() != this.params[i].value.eval(env).toCSS()) { return false; } } } return true; } }; })(require('../tree')); (function (tree) { tree.Operation = function (op, operands) { this.op = op.trim(); this.operands = operands; }; tree.Operation.prototype.eval = function (env) { var a = this.operands[0].eval(env), b = this.operands[1].eval(env), temp; if (a instanceof tree.Dimension && b instanceof tree.Color) { if (this.op === '*' || this.op === '+') { temp = b, b = a, a = temp; } else { throw { name: "OperationError", message: "Can't substract or divide a color from a number" }; } } return a.operate(this.op, b); }; tree.operate = function (op, a, b) { switch (op) { case '+': return a + b; case '-': return a - b; case '*': return a * b; case '/': return a / b; } }; })(require('../tree')); (function (tree) { tree.Paren = function (node) { this.value = node; }; tree.Paren.prototype = { toCSS: function (env) { return '(' + this.value.toCSS(env) + ')'; }, eval: function (env) { return new(tree.Paren)(this.value.eval(env)); } }; })(require('../tree')); (function (tree) { tree.Quoted = function (str, content, escaped, i) { this.escaped = escaped; this.value = content || ''; this.quote = str.charAt(0); this.index = i; }; tree.Quoted.prototype = { toCSS: function () { if (this.escaped) { return this.value; } else { return this.quote + this.value + this.quote; } }, eval: function (env) { var that = this; var value = this.value.replace(/`([^`]+)`/g, function (_, exp) { return new(tree.JavaScript)(exp, that.index, true).eval(env).value; }).replace(/@\{([\w-]+)\}/g, function (_, name) { var v = new(tree.Variable)('@' + name, that.index).eval(env); return ('value' in v) ? v.value : v.toCSS(); }); return new(tree.Quoted)(this.quote + value + this.quote, value, this.escaped, this.index); } }; })(require('../tree')); (function (tree) { tree.Rule = function (name, value, important, index, inline) { this.name = name; this.value = (value instanceof tree.Value) ? value : new(tree.Value)([value]); this.important = important ? ' ' + important.trim() : ''; this.index = index; this.inline = inline || false; if (name.charAt(0) === '@') { this.variable = true; } else { this.variable = false } }; tree.Rule.prototype.toCSS = function (env) { if (this.variable) { return "" } else { return this.name + (env.compress ? ':' : ': ') + this.value.toCSS(env) + this.important + (this.inline ? "" : ";"); } }; tree.Rule.prototype.eval = function (context) { return new(tree.Rule)(this.name, this.value.eval(context), this.important, this.index, this.inline); }; tree.Shorthand = function (a, b) { this.a = a; this.b = b; }; tree.Shorthand.prototype = { toCSS: function (env) { return this.a.toCSS(env) + "/" + this.b.toCSS(env); }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.Ruleset = function (selectors, rules) { this.selectors = selectors; this.rules = rules; this._lookups = {}; }; tree.Ruleset.prototype = { eval: function (env) { var selectors = this.selectors && this.selectors.map(function (s) { return s.eval(env) }); var ruleset = new(tree.Ruleset)(selectors, this.rules.slice(0)); ruleset.root = this.root; ruleset.allowImports = this.allowImports; // push the current ruleset to the frames stack env.frames.unshift(ruleset); // Evaluate imports if (ruleset.root || ruleset.allowImports) { for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.Import) { Array.prototype.splice .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env))); } } } // Store the frames around mixin definitions, // so they can be evaluated like closures when the time comes. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Definition) { ruleset.rules[i].frames = env.frames.slice(0); } } // Evaluate mixin calls. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Call) { Array.prototype.splice .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env))); } } // Evaluate everything else for (var i = 0, rule; i < ruleset.rules.length; i++) { rule = ruleset.rules[i]; if (! (rule instanceof tree.mixin.Definition)) { ruleset.rules[i] = rule.eval ? rule.eval(env) : rule; } } // Pop the stack env.frames.shift(); return ruleset; }, match: function (args) { return !args || args.length === 0; }, variables: function () { if (this._variables) { return this._variables } else { return this._variables = this.rules.reduce(function (hash, r) { if (r instanceof tree.Rule && r.variable === true) { hash[r.name] = r; } return hash; }, {}); } }, variable: function (name) { return this.variables()[name]; }, rulesets: function () { if (this._rulesets) { return this._rulesets } else { return this._rulesets = this.rules.filter(function (r) { return (r instanceof tree.Ruleset) || (r instanceof tree.mixin.Definition); }); } }, find: function (selector, self) { self = self || this; var rules = [], rule, match, key = selector.toCSS(); if (key in this._lookups) { return this._lookups[key] } this.rulesets().forEach(function (rule) { if (rule !== self) { for (var j = 0; j < rule.selectors.length; j++) { if (match = selector.match(rule.selectors[j])) { if (selector.elements.length > rule.selectors[j].elements.length) { Array.prototype.push.apply(rules, rule.find( new(tree.Selector)(selector.elements.slice(1)), self)); } else { rules.push(rule); } break; } } } }); return this._lookups[key] = rules; }, // // Entry point for code generation // // `context` holds an array of arrays. // toCSS: function (context, env) { var css = [], // The CSS output rules = [], // node.Rule instances rulesets = [], // node.Ruleset instances paths = [], // Current selectors selector, // The fully rendered selector rule; if (! this.root) { if (context.length === 0) { paths = this.selectors.map(function (s) { return [s] }); } else { this.joinSelectors(paths, context, this.selectors); } } // Compile rules and rulesets for (var i = 0; i < this.rules.length; i++) { rule = this.rules[i]; if (rule.rules || (rule instanceof tree.Directive)) { rulesets.push(rule.toCSS(paths, env)); } else if (rule instanceof tree.Comment) { if (!rule.silent) { if (this.root) { rulesets.push(rule.toCSS(env)); } else { rules.push(rule.toCSS(env)); } } } else { if (rule.toCSS && !rule.variable) { rules.push(rule.toCSS(env)); } else if (rule.value && !rule.variable) { rules.push(rule.value.toString()); } } } rulesets = rulesets.join(''); // If this is the root node, we don't render // a selector, or {}. // Otherwise, only output if this ruleset has rules. if (this.root) { css.push(rules.join(env.compress ? '' : '\n')); } else { if (rules.length > 0) { selector = paths.map(function (p) { return p.map(function (s) { return s.toCSS(env); }).join('').trim(); }).join(env.compress ? ',' : (paths.length > 3 ? ',\n' : ', ')); css.push(selector, (env.compress ? '{' : ' {\n ') + rules.join(env.compress ? '' : '\n ') + (env.compress ? '}' : '\n}\n')); } } css.push(rulesets); return css.join('') + (env.compress ? '\n' : ''); }, joinSelectors: function (paths, context, selectors) { for (var s = 0; s < selectors.length; s++) { this.joinSelector(paths, context, selectors[s]); } }, joinSelector: function (paths, context, selector) { var before = [], after = [], beforeElements = [], afterElements = [], hasParentSelector = false, el; for (var i = 0; i < selector.elements.length; i++) { el = selector.elements[i]; if (el.combinator.value.charAt(0) === '&') { hasParentSelector = true; } if (hasParentSelector) afterElements.push(el); else beforeElements.push(el); } if (! hasParentSelector) { afterElements = beforeElements; beforeElements = []; } if (beforeElements.length > 0) { before.push(new(tree.Selector)(beforeElements)); } if (afterElements.length > 0) { after.push(new(tree.Selector)(afterElements)); } for (var c = 0; c < context.length; c++) { paths.push(before.concat(context[c]).concat(after)); } } }; })(require('../tree')); (function (tree) { tree.Selector = function (elements) { this.elements = elements; if (this.elements[0].combinator.value === "") { this.elements[0].combinator.value = ' '; } }; tree.Selector.prototype.match = function (other) { var len = this.elements.length, olen = other.elements.length, max = Math.min(len, olen); if (len < olen) { return false; } else { for (var i = 0; i < max; i++) { if (this.elements[i].value !== other.elements[i].value) { return false; } } } return true; }; tree.Selector.prototype.eval = function (env) { return new(tree.Selector)(this.elements.map(function (e) { return e.eval(env); })); }; tree.Selector.prototype.toCSS = function (env) { if (this._css) { return this._css } return this._css = this.elements.map(function (e) { if (typeof(e) === 'string') { return ' ' + e.trim(); } else { return e.toCSS(env); } }).join(''); }; })(require('../tree')); (function (tree) { tree.URL = function (val, paths) { if (val.data) { this.attrs = val; } else { // Add the base path if the URL is relative and we are in the browser if (typeof(window) !== 'undefined' && !/^(?:https?:\/\/|file:\/\/|data:|\/)/.test(val.value) && paths.length > 0) { val.value = paths[0] + (val.value.charAt(0) === '/' ? val.value.slice(1) : val.value); } this.value = val; this.paths = paths; } }; tree.URL.prototype = { toCSS: function () { return "url(" + (this.attrs ? 'data:' + this.attrs.mime + this.attrs.charset + this.attrs.base64 + this.attrs.data : this.value.toCSS()) + ")"; }, eval: function (ctx) { return this.attrs ? this : new(tree.URL)(this.value.eval(ctx), this.paths); } }; })(require('../tree')); (function (tree) { tree.Value = function (value) { this.value = value; this.is = 'value'; }; tree.Value.prototype = { eval: function (env) { if (this.value.length === 1) { return this.value[0].eval(env); } else { return new(tree.Value)(this.value.map(function (v) { return v.eval(env); })); } }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS(env); }).join(env.compress ? ',' : ', '); } }; })(require('../tree')); (function (tree) { tree.Variable = function (name, index, file) { this.name = name, this.index = index, this.file = file }; tree.Variable.prototype = { eval: function (env) { var variable, v, name = this.name; if (name.indexOf('@@') == 0) { name = '@' + new(tree.Variable)(name.slice(1)).eval(env).value; } if (variable = tree.find(env.frames, function (frame) { if (v = frame.variable(name)) { return v.value.eval(env); } })) { return variable } else { throw { type: 'Name', message: "variable " + name + " is undefined", filename: this.file, index: this.index }; } } }; })(require('../tree')); (function (tree) { tree.find = function (obj, fun) { for (var i = 0, r; i < obj.length; i++) { if (r = fun.call(obj, obj[i])) { return r } } return null; }; tree.jsify = function (obj) { if (Array.isArray(obj.value) && (obj.value.length > 1)) { return '[' + obj.value.map(function (v) { return v.toCSS(false) }).join(', ') + ']'; } else { return obj.toCSS(false); } }; })(require('./tree')); // // browser.js - client-side engine // var isFileProtocol = (location.protocol === 'file:' || location.protocol === 'chrome:' || location.protocol === 'chrome-extension:' || location.protocol === 'resource:'); less.env = less.env || (location.hostname == '127.0.0.1' || location.hostname == '0.0.0.0' || location.hostname == 'localhost' || location.port.length > 0 || isFileProtocol ? 'development' : 'production'); // Load styles asynchronously (default: false) // // This is set to `false` by default, so that the body // doesn't start loading before the stylesheets are parsed. // Setting this to `true` can result in flickering. // less.async = false; // Interval between watch polls less.poll = less.poll || (isFileProtocol ? 1000 : 1500); // // Watch mode // less.watch = function () { return this.watchMode = true }; less.unwatch = function () { return this.watchMode = false }; if (less.env === 'development') { less.optimization = 0; if (/!watch/.test(location.hash)) { less.watch(); } less.watchTimer = setInterval(function () { if (less.watchMode) { loadStyleSheets(function (e, root, _, sheet, env) { if (root) { createCSS(root.toCSS(), sheet, env.lastModified); } }); } }, less.poll); } else { less.optimization = 3; } var cache; try { cache = (typeof(window.localStorage) === 'undefined') ? null : window.localStorage; } catch (_) { cache = null; } // // Get all tags with the 'rel' attribute set to "stylesheet/less" // var links = document.getElementsByTagName('link'); var typePattern = /^text\/(x-)?less$/; less.sheets = []; for (var i = 0; i < links.length; i++) { if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) && (links[i].type.match(typePattern)))) { less.sheets.push(links[i]); } } less.refresh = function (reload) { var startTime, endTime; startTime = endTime = new(Date); loadStyleSheets(function (e, root, _, sheet, env) { if (env.local) { log("loading " + sheet.href + " from cache."); } else { log("parsed " + sheet.href + " successfully."); createCSS(root.toCSS(), sheet, env.lastModified); } log("css for " + sheet.href + " generated in " + (new(Date) - endTime) + 'ms'); (env.remaining === 0) && log("css generated in " + (new(Date) - startTime) + 'ms'); endTime = new(Date); }, reload); loadStyles(); }; less.refreshStyles = loadStyles; less.refresh(less.env === 'development'); function loadStyles() { var styles = document.getElementsByTagName('style'); for (var i = 0; i < styles.length; i++) { if (styles[i].type.match(typePattern)) { new(less.Parser)().parse(styles[i].innerHTML || '', function (e, tree) { var css = tree.toCSS(); var style = styles[i]; style.type = 'text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.innerHTML = css; } }); } } } function loadStyleSheets(callback, reload) { for (var i = 0; i < less.sheets.length; i++) { loadStyleSheet(less.sheets[i], callback, reload, less.sheets.length - (i + 1)); } } function loadStyleSheet(sheet, callback, reload, remaining) { var url = window.location.href.replace(/[#?].*$/, ''); var href = sheet.href.replace(/\?.*$/, ''); var css = cache && cache.getItem(href); var timestamp = cache && cache.getItem(href + ':timestamp'); var styles = { css: css, timestamp: timestamp }; // Stylesheets in IE don't always return the full path if (! /^(https?|file):/.test(href)) { if (href.charAt(0) == "/") { href = window.location.protocol + "//" + window.location.host + href; } else { href = url.slice(0, url.lastIndexOf('/') + 1) + href; } } var filename = href.match(/([^\/]+)$/)[1]; xhr(sheet.href, sheet.type, function (data, lastModified) { if (!reload && styles && lastModified && (new(Date)(lastModified).valueOf() === new(Date)(styles.timestamp).valueOf())) { // Use local copy createCSS(styles.css, sheet); callback(null, sheet, { local: true, remaining: remaining }); } else { // Use remote copy (re-parse) try { new(less.Parser)({ optimization: less.optimization, paths: [href.replace(/[\w\.-]+$/, '')], mime: sheet.type, filename: filename }).parse(data, function (e, root) { if (e) { return error(e, href) } try { callback(e, root, data, sheet, { local: false, lastModified: lastModified, remaining: remaining }); removeNode(document.getElementById('less-error-message:' + extractId(href))); } catch (e) { error(e, href); } }); } catch (e) { error(e, href); } } }, function (status, url) { throw new(Error)("Couldn't load " + url + " (" + status + ")"); }); } function extractId(href) { return href.replace(/^[a-z]+:\/\/?[^\/]+/, '' ) // Remove protocol & domain .replace(/^\//, '' ) // Remove root / .replace(/\?.*$/, '' ) // Remove query .replace(/\.[^\.\/]+$/, '' ) // Remove file extension .replace(/[^\.\w-]+/g, '-') // Replace illegal characters .replace(/\./g, ':'); // Replace dots with colons(for valid id) } function createCSS(styles, sheet, lastModified) { var css; // Strip the query-string var href = sheet.href ? sheet.href.replace(/\?.*$/, '') : ''; // If there is no title set, use the filename, minus the extension var id = 'less:' + (sheet.title || extractId(href)); // If the stylesheet doesn't exist, create a new node if ((css = document.getElementById(id)) === null) { css = document.createElement('style'); css.type = 'text/css'; css.media = sheet.media || 'screen'; css.id = id; document.getElementsByTagName('head')[0].appendChild(css); } if (css.styleSheet) { // IE try { css.styleSheet.cssText = styles; } catch (e) { throw new(Error)("Couldn't reassign styleSheet.cssText."); } } else { (function (node) { if (css.childNodes.length > 0) { if (css.firstChild.nodeValue !== node.nodeValue) { css.replaceChild(node, css.firstChild); } } else { css.appendChild(node); } })(document.createTextNode(styles)); } // Don't update the local store if the file wasn't modified if (lastModified && cache) { log('saving ' + href + ' to cache.'); cache.setItem(href, styles); cache.setItem(href + ':timestamp', lastModified); } } function xhr(url, type, callback, errback) { var xhr = getXMLHttpRequest(); var async = isFileProtocol ? false : less.async; if (typeof(xhr.overrideMimeType) === 'function') { xhr.overrideMimeType('text/css'); } xhr.open('GET', url, async); xhr.setRequestHeader('Accept', type || 'text/x-less, text/css; q=0.9, */*; q=0.5'); xhr.send(null); if (isFileProtocol) { if (xhr.status === 0 || (xhr.status >= 200 && xhr.status < 300)) { callback(xhr.responseText); } else { errback(xhr.status, url); } } else if (async) { xhr.onreadystatechange = function () { if (xhr.readyState == 4) { handleResponse(xhr, callback, errback); } }; } else { handleResponse(xhr, callback, errback); } function handleResponse(xhr, callback, errback) { if (xhr.status >= 200 && xhr.status < 300) { callback(xhr.responseText, xhr.getResponseHeader("Last-Modified")); } else if (typeof(errback) === 'function') { errback(xhr.status, url); } } } function getXMLHttpRequest() { if (window.XMLHttpRequest) { return new(XMLHttpRequest); } else { try { return new(ActiveXObject)("MSXML2.XMLHTTP.3.0"); } catch (e) { log("browser doesn't support AJAX."); return null; } } } function removeNode(node) { return node && node.parentNode.removeChild(node); } function log(str) { if (less.env == 'development' && typeof(console) !== "undefined") { console.log('less: ' + str) } } function error(e, href) { var id = 'less-error-message:' + extractId(href); var template = '
  • {content}
  • '; var elem = document.createElement('div'), timer, content, error = []; var filename = e.filename || href; elem.id = id; elem.className = "less-error-message"; content = '

    ' + (e.message || 'There is an error in your .less file') + '

    ' + '

    in ' + filename + " "; var errorline = function (e, i, classname) { if (e.extract[i]) { error.push(template.replace(/\{line\}/, parseInt(e.line) + (i - 1)) .replace(/\{class\}/, classname) .replace(/\{content\}/, e.extract[i])); } }; if (e.stack) { content += '
    ' + e.stack.split('\n').slice(1).join('
    '); } else if (e.extract) { errorline(e, 0, ''); errorline(e, 1, 'line'); errorline(e, 2, ''); content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':

    ' + '
      ' + error.join('') + '
    '; } elem.innerHTML = content; // CSS for error messages createCSS([ '.less-error-message ul, .less-error-message li {', 'list-style-type: none;', 'margin-right: 15px;', 'padding: 4px 0;', 'margin: 0;', '}', '.less-error-message label {', 'font-size: 12px;', 'margin-right: 15px;', 'padding: 4px 0;', 'color: #cc7777;', '}', '.less-error-message pre {', 'color: #dd6666;', 'padding: 4px 0;', 'margin: 0;', 'display: inline-block;', '}', '.less-error-message pre.line {', 'color: #ff0000;', '}', '.less-error-message h3 {', 'font-size: 20px;', 'font-weight: bold;', 'padding: 15px 0 5px 0;', 'margin: 0;', '}', '.less-error-message a {', 'color: #10a', '}', '.less-error-message .error {', 'color: red;', 'font-weight: bold;', 'padding-bottom: 2px;', 'border-bottom: 1px dashed red;', '}' ].join('\n'), { title: 'error-message' }); elem.style.cssText = [ "font-family: Arial, sans-serif", "border: 1px solid #e00", "background-color: #eee", "border-radius: 5px", "-webkit-border-radius: 5px", "-moz-border-radius: 5px", "color: #e00", "padding: 15px", "margin-bottom: 15px" ].join(';'); if (less.env == 'development') { timer = setInterval(function () { if (document.body) { if (document.getElementById(id)) { document.body.replaceChild(elem, document.getElementById(id)); } else { document.body.insertBefore(elem, document.body.firstChild); } clearInterval(timer); } }, 10); } } })(window); less.js-1.4.2/dist/less-1.2.1.min.js000066400000000000000000001266071217256642200166100ustar00rootroot00000000000000// // LESS - Leaner CSS v1.2.1 // http://lesscss.org // // Copyright (c) 2009-2011, Alexis Sellier // Licensed under the Apache 2.0 License. // (function(a,b){function c(b){return a.less[b.split("/")[1]]}function m(){var a=document.getElementsByTagName("style");for(var b=0;b0?d.firstChild.nodeValue!==a.nodeValue&&d.replaceChild(a,d.firstChild):d.appendChild(a)})(document.createTextNode(a));c&&h&&(v("saving "+e+" to cache."),h.setItem(e,a),h.setItem(e+":timestamp",c))}function s(a,b,c,e){function i(b,c,d){b.status>=200&&b.status<300?c(b.responseText,b.getResponseHeader("Last-Modified")):typeof d=="function"&&d(b.status,a)}var f=t(),h=g?!1:d.async;typeof f.overrideMimeType=="function"&&f.overrideMimeType("text/css"),f.open("GET",a,h),f.setRequestHeader("Accept",b||"text/x-less, text/css; q=0.9, */*; q=0.5"),f.send(null),g?f.status===0||f.status>=200&&f.status<300?c(f.responseText):e(f.status,a):h?f.onreadystatechange=function(){f.readyState==4&&i(f,c,e)}:i(f,c,e)}function t(){if(a.XMLHttpRequest)return new XMLHttpRequest;try{return new ActiveXObject("MSXML2.XMLHTTP.3.0")}catch(b){return v("browser doesn't support AJAX."),null}}function u(a){return a&&a.parentNode.removeChild(a)}function v(a){d.env=="development"&&typeof console!="undefined"&&console.log("less: "+a)}function w(a,b){var c="less-error-message:"+q(b),e='
  • {content}
  • ',f=document.createElement("div"),g,h,i=[],j=a.filename||b;f.id=c,f.className="less-error-message",h="

    "+(a.message||"There is an error in your .less file")+"

    "+'

    in '+j+" ";var k=function(a,b,c){a.extract[b]&&i.push(e.replace(/\{line\}/,parseInt(a.line)+(b-1)).replace(/\{class\}/,c).replace(/\{content\}/,a.extract[b]))};a.stack?h+="
    "+a.stack.split("\n").slice(1).join("
    "):a.extract&&(k(a,0,""),k(a,1,"line"),k(a,2,""),h+="on line "+a.line+", column "+(a.column+1)+":

    "+"
      "+i.join("")+"
    "),f.innerHTML=h,r([".less-error-message ul, .less-error-message li {","list-style-type: none;","margin-right: 15px;","padding: 4px 0;","margin: 0;","}",".less-error-message label {","font-size: 12px;","margin-right: 15px;","padding: 4px 0;","color: #cc7777;","}",".less-error-message pre {","color: #dd6666;","padding: 4px 0;","margin: 0;","display: inline-block;","}",".less-error-message pre.line {","color: #ff0000;","}",".less-error-message h3 {","font-size: 20px;","font-weight: bold;","padding: 15px 0 5px 0;","margin: 0;","}",".less-error-message a {","color: #10a","}",".less-error-message .error {","color: red;","font-weight: bold;","padding-bottom: 2px;","border-bottom: 1px dashed red;","}"].join("\n"),{title:"error-message"}),f.style.cssText=["font-family: Arial, sans-serif","border: 1px solid #e00","background-color: #eee","border-radius: 5px","-webkit-border-radius: 5px","-moz-border-radius: 5px","color: #e00","padding: 15px","margin-bottom: 15px"].join(";"),d.env=="development"&&(g=setInterval(function(){document.body&&(document.getElementById(c)?document.body.replaceChild(f,document.getElementById(c)):document.body.insertBefore(f,document.body.firstChild),clearInterval(g))},10))}Array.isArray||(Array.isArray=function(a){return Object.prototype.toString.call(a)==="[object Array]"||a instanceof Array}),Array.prototype.forEach||(Array.prototype.forEach=function(a,b){var c=this.length>>>0;for(var d=0;d>>0,c=new Array(b),d=arguments[1];for(var e=0;e>>0,c=0;if(b===0&&arguments.length===1)throw new TypeError;if(arguments.length>=2)var d=arguments[1];else do{if(c in this){d=this[c++];break}if(++c>=b)throw new TypeError}while(!0);for(;c=b)return-1;c<0&&(c+=b);for(;cn&&(m[i]=m[i].slice(h-n),n=h)}function w(a){var b,c,d,e,f,j,k,l;if(a instanceof Function)return a.call(o.parsers);if(typeof a=="string")b=g.charAt(h)===a?a:null,d=1,v();else{v();if(!(b=a.exec(m[i])))return null;d=b[0].length}if(b){l=h+=d,j=h+m[i].length-d;while(h=0&&b.charAt(c)!=="\n";c--)d++;return{line:typeof a=="number"?(b.slice(0,a).match(/\n/g)||"").length:null,column:d}}function C(a,b){var c=A(a,b),d=B(a.index,c),e=d.line,f=d.column,g=c.split("\n");this.type=a.type||"Syntax",this.message=a.message,this.filename=a.filename||b.filename,this.index=a.index,this.line=typeof e=="number"?e+1:null,this.callLine=a.call&&B(a.call,c)+1,this.callExtract=g[B(a.call,c)],this.stack=a.stack,this.column=f,this.extract=[g[e-1],g[e],g[e+1]]}var g,h,i,j,k,l,m,n,o,q=this,r=function(){},s=this.imports={paths:b&&b.paths||[],queue:[],files:{},contents:{},mime:b&&b.mime,error:null,push:function(a,c){var e=this;this.queue.push(a),d.Parser.importer(a,this.paths,function(b,d,f){e.queue.splice(e.queue.indexOf(a),1),e.files[a]=d,e.contents[a]=f,b&&!e.error&&(e.error=b),c(b,d),e.queue.length===0&&r()},b)}};return this.env=b=b||{},this.optimization="optimization"in this.env?this.env.optimization:1,this.env.filename=this.env.filename||null,o={imports:s,parse:function(a,e){var j,k,p,q,s,t,u=[],v,x=null;h=i=n=l=0,m=[],g=a.replace(/\r\n/g,"\n"),m=function(a){var c=0,d=/[^"'`\{\}\/\(\)]+/g,e=/\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g,f=0,h,i=a[0],j,k;for(var l=0,m,n;l0)throw{type:"Syntax",message:"Missing closing `}`",filename:b.filename};return a.map(function(a){return a.join("")})}([[]]);try{j=new f.Ruleset([],w(this.parsers.primary)),j.root=!0}catch(y){return e(new C(y,b))}j.toCSS=function(a){var e,g,h;return function(e,g){var h=[],i;e=e||{},typeof g=="object"&&!Array.isArray(g)&&(g=Object.keys(g).map(function(a){var b=g[a];return b instanceof f.Value||(b instanceof f.Expression||(b=new f.Expression([b])),b=new f.Value([b])),new f.Rule("@"+a,b,!1,0)}),h=[new f.Ruleset(null,g)]);try{var j=a.call(this,{frames:h}).toCSS([],{compress:e.compress||!1})}catch(k){throw new C(k,b)}if(i=o.imports.error)throw i instanceof C?i:new C(i,b);return e.yuicompress&&d.mode==="node"?c("./cssmin").compressor.cssmin(j):e.compress?j.replace(/(\s)+/g,"$1"):j}}(j.eval);if(h=0&&g.charAt(z)!=="\n";z--)A++;x={type:"Parse",message:"Syntax Error on line "+s,index:h,filename:b.filename,line:s,column:A,extract:[t[s-2],t[s-1],t[s]]}}this.imports.queue.length>0?r=function(){e(x,j)}:e(x,j)},parsers:{primary:function(){var a,b=[];while((a=w(this.mixin.definition)||w(this.rule)||w(this.ruleset)||w(this.mixin.call)||w(this.comment)||w(this.directive))||w(/^[\s\n]+/))a&&b.push(a);return b},comment:function(){var a;if(g.charAt(h)!=="/")return;if(g.charAt(h+1)==="/")return new f.Comment(w(/^\/\/.*/),!0);if(a=w(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/))return new f.Comment(a)},entities:{quoted:function(){var a,b=h,c;g.charAt(b)==="~"&&(b++,c=!0);if(g.charAt(b)!=='"'&&g.charAt(b)!=="'")return;c&&w("~");if(a=w(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/))return new f.Quoted(a[0],a[1]||a[2],c)},keyword:function(){var a;if(a=w(/^[_A-Za-z-][_A-Za-z0-9-]*/))return f.colors.hasOwnProperty(a)?new f.Color(f.colors[a].slice(1)):new f.Keyword(a)},call:function(){var a,c,d=h;if(!(a=/^([\w-]+|%|progid:[\w\.]+)\(/.exec(m[i])))return;a=a[1].toLowerCase();if(a==="url")return null;h+=a.length;if(a==="alpha")return w(this.alpha);w("("),c=w(this.entities.arguments);if(!w(")"))return;if(a)return new f.Call(a,c,d,b.filename)},arguments:function(){var a=[],b;while(b=w(this.entities.assignment)||w(this.expression)){a.push(b);if(!w(","))break}return a},literal:function(){return w(this.entities.dimension)||w(this.entities.color)||w(this.entities.quoted)},assignment:function(){var a,b;if((a=w(/^\w+(?=\s?=)/i))&&w("=")&&(b=w(this.entity)))return new f.Assignment(a,b)},url:function(){var a;if(g.charAt(h)!=="u"||!w(/^url\(/))return;return a=w(this.entities.quoted)||w(this.entities.variable)||w(this.entities.dataURI)||w(/^[-\w%@$\/.&=:;#+?~]+/)||"",x(")"),new f.URL(a.value||a.data||a instanceof f.Variable?a:new f.Anonymous(a),s.paths)},dataURI:function(){var a;if(w(/^data:/)){a={},a.mime=w(/^[^\/]+\/[^,;)]+/)||"",a.charset=w(/^;\s*charset=[^,;)]+/)||"",a.base64=w(/^;\s*base64/)||"",a.data=w(/^,\s*[^)]+/);if(a.data)return a}},variable:function(){var a,c=h;if(g.charAt(h)==="@"&&(a=w(/^@@?[\w-]+/)))return new f.Variable(a,c,b.filename)},color:function(){var a;if(g.charAt(h)==="#"&&(a=w(/^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})/)))return new f.Color(a[1])},dimension:function(){var a,b=g.charCodeAt(h);if(b>57||b<45||b===47)return;if(a=w(/^(-?\d*\.?\d+)(px|%|em|rem|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn)?/))return new f.Dimension(a[1],a[2])},javascript:function(){var a,b=h,c;g.charAt(b)==="~"&&(b++,c=!0);if(g.charAt(b)!=="`")return;c&&w("~");if(a=w(/^`([^`]*)`/))return new f.JavaScript(a[1],h,c)}},variable:function(){var a;if(g.charAt(h)==="@"&&(a=w(/^(@[\w-]+)\s*:/)))return a[1]},shorthand:function(){var a,b;if(!z(/^[@\w.%-]+\/[@\w.-]+/))return;if((a=w(this.entity))&&w("/")&&(b=w(this.entity)))return new f.Shorthand(a,b)},mixin:{call:function(){var a=[],c,d,e,i=h,j=g.charAt(h),k=!1;if(j!=="."&&j!=="#")return;while(c=w(/^[#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/))a.push(new f.Element(d,c,h)),d=w(">");w("(")&&(e=w(this.entities.arguments))&&w(")"),w(this.important)&&(k=!0);if(a.length>0&&(w(";")||z("}")))return new f.mixin.Call(a,e,i,b.filename,k)},definition:function(){var a,b=[],c,d,e,i,j;if(g.charAt(h)!=="."&&g.charAt(h)!=="#"||z(/^[^{]*(;|})/))return;t();if(c=w(/^([#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+)\s*\(/)){a=c[1];while(e=w(this.entities.variable)||w(this.entities.literal)||w(this.entities.keyword)){e instanceof f.Variable?w(":")?(i=x(this.expression,"expected expression"),b.push({name:e.name,value:i})):b.push({name:e.name}):b.push({value:e});if(!w(","))break}x(")"),w(/^when/)&&(j=x(this.conditions,"expected condition")),d=w(this.block);if(d)return new f.mixin.Definition(a,b,d,j);u()}}},entity:function(){return w(this.entities.literal)||w(this.entities.variable)||w(this.entities.url)||w(this.entities.call)||w(this.entities.keyword)||w(this.entities.javascript)||w(this.comment)},end:function(){return w(";")||z("}")},alpha:function(){var a;if(!w(/^\(opacity=/i))return;if(a=w(/^\d+/)||w(this.entities.variable))return x(")"),new f.Alpha(a)},element:function(){var a,b,c,d;c=w(this.combinator),a=w(/^(?:\d+\.\d+|\d+)%/)||w(/^(?:[.#]?|:*)(?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/)||w("*")||w(this.attribute)||w(/^\([^)@]+\)/),a||w("(")&&(d=w(this.entities.variable))&&w(")")&&(a=new f.Paren(d));if(a)return new f.Element(c,a,h);if(c.value&&c.value.charAt(0)==="&")return new f.Element(c,null,h)},combinator:function(){var a,b=g.charAt(h);if(b===">"||b==="+"||b==="~"){h++;while(g.charAt(h)===" ")h++;return new f.Combinator(b)}if(b==="&"){a="&",h++,g.charAt(h)===" "&&(a="& ");while(g.charAt(h)===" ")h++;return new f.Combinator(a)}if(b===":"&&g.charAt(h+1)===":"){h+=2;while(g.charAt(h)===" ")h++;return new f.Combinator("::")}return g.charAt(h-1)===" "?new f.Combinator(" "):new f.Combinator(null)},selector:function(){var a,b,c=[],d,e;while(b=w(this.element)){d=g.charAt(h),c.push(b);if(d==="{"||d==="}"||d===";"||d===",")break}if(c.length>0)return new f.Selector(c)},tag:function(){return w(/^[a-zA-Z][a-zA-Z-]*[0-9]?/)||w("*")},attribute:function(){var a="",b,c,d;if(!w("["))return;if(b=w(/^[a-zA-Z-]+/)||w(this.entities.quoted))(d=w(/^[|~*$^]?=/))&&(c=w(this.entities.quoted)||w(/^[\w-]+/))?a=[b,d,c.toCSS?c.toCSS():c].join(""):a=b;if(!w("]"))return;if(a)return"["+a+"]"},block:function(){var a;if(w("{")&&(a=w(this.primary))&&w("}"))return a},ruleset:function(){var a=[],b,c,d;t();while(b=w(this.selector)){a.push(b),w(this.comment);if(!w(","))break;w(this.comment)}if(a.length>0&&(c=w(this.block)))return new f.Ruleset(a,c);l=h,u()},rule:function(){var a,b,c=g.charAt(h),d,e;t();if(c==="."||c==="#"||c==="&")return;if(a=w(this.variable)||w(this.property)){a.charAt(0)!="@"&&(e=/^([^@+\/'"*`(;{}-]*);/.exec(m[i]))?(h+=e[0].length-1,b=new f.Anonymous(e[1])):a==="font"?b=w(this.font):b=w(this.value),d=w(this.important);if(b&&w(this.end))return new f.Rule(a,b,d,k);l=h,u()}},"import":function(){var a,b,c=h;if(w(/^@import\s+/)&&(a=w(this.entities.quoted)||w(this.entities.url))){b=w(this.mediaFeatures);if(w(";"))return new f.Import(a,s,b,c)}},mediaFeature:function(){var a=[];do if(e=w(this.entities.keyword))a.push(e);else if(w("(")){p=w(this.property),e=w(this.entity);if(!w(")"))return null;if(p&&e)a.push(new f.Paren(new f.Rule(p,e,null,h,!0)));else{if(!e)return null;a.push(new f.Paren(e))}}while(e);if(a.length>0)return new f.Expression(a)},mediaFeatures:function(){var a,b=[];while(a=w(this.mediaFeature)){b.push(a);if(!w(","))break}return b.length>0?b:null},media:function(){var a;if(w(/^@media/)){a=w(this.mediaFeatures);if(rules=w(this.block))return new f.Directive("@media",rules,a)}},directive:function(){var a,b,c,d,e,i;if(g.charAt(h)!=="@")return;if(b=w(this["import"])||w(this.media))return b;if(a=w(/^@page|@keyframes/)||w(/^@(?:-webkit-|-moz-|-o-|-ms-)[a-z0-9-]+/)){d=(w(/^[^{]+/)||"").trim();if(c=w(this.block))return new f.Directive(a+" "+d,c)}else if(a=w(/^@[-a-z]+/))if(a==="@font-face"){if(c=w(this.block))return new f.Directive(a,c)}else if((b=w(this.entity))&&w(";"))return new f.Directive(a,b)},font:function(){var a=[],b=[],c,d,e,g;while(g=w(this.shorthand)||w(this.entity))b.push(g);a.push(new f.Expression(b));if(w(","))while(g=w(this.expression)){a.push(g);if(!w(","))break}return new f.Value(a)},value:function(){var a,b=[],c;while(a=w(this.expression)){b.push(a);if(!w(","))break}if(b.length>0)return new f.Value(b)},important:function(){if(g.charAt(h)==="!")return w(/^! *important/)},sub:function(){var a;if(w("(")&&(a=w(this.expression))&&w(")"))return a},multiplication:function(){var a,b,c,d;if(a=w(this.operand)){while(!z(/^\/\*/)&&(c=w("/")||w("*"))&&(b=w(this.operand)))d=new f.Operation(c,[d||a,b]);return d||a}},addition:function(){var a,b,c,d;if(a=w(this.multiplication)){while((c=w(/^[-+]\s+/)||g.charAt(h-1)!=" "&&(w("+")||w("-")))&&(b=w(this.multiplication)))d=new f.Operation(c,[d||a,b]);return d||a}},conditions:function(){var a,b,c=h,d;if(a=w(this.condition)){while(w(",")&&(b=w(this.condition)))d=new f.Condition("or",d||a,b,c);return d||a}},condition:function(){var a,b,c,d,e=h,g=!1;w(/^not/)&&(g=!0),x("(");if(a=w(this.addition)||w(this.entities.keyword)||w(this.entities.quoted))return(d=w(/^(?:>=|=<|[<=>])/))?(b=w(this.addition)||w(this.entities.keyword)||w(this.entities.quoted))?c=new f.Condition(d,a,b,e,g):y("expected expression"):c=new f.Condition("=",a,new f.Keyword("true"),e,g),x(")"),w(/^and/)?new f.Condition("and",c,w(this.condition)):c},operand:function(){var a,b=g.charAt(h+1);g.charAt(h)==="-"&&(b==="@"||b==="(")&&(a=w("-"));var c=w(this.sub)||w(this.entities.dimension)||w(this.entities.color)||w(this.entities.variable)||w(this.entities.call);return a?new f.Operation("*",[new f.Dimension(-1),c]):c},expression:function(){var a,b,c=[],d;while(a=w(this.addition)||w(this.entity))c.push(a);if(c.length>0)return new f.Expression(c)},property:function(){var a;if(a=w(/^(\*?-?[-a-z_0-9]+)\s*:/))return a[1]}}}};if(d.mode==="browser"||d.mode==="rhino")d.Parser.importer=function(a,b,c,d){a.charAt(0)!=="/"&&b.length>0&&(a=b[0]+a),o({href:a,title:a,type:d.mime},c,!0)};(function(a){function b(b){return a.functions.hsla(b.h,b.s,b.l,b.a)}function c(b){if(b instanceof a.Dimension)return parseFloat(b.unit=="%"?b.value/100:b.value);if(typeof b=="number")return b;throw{error:"RuntimeError",message:"color functions take numbers as parameters"}}function d(a){return Math.min(1,Math.max(0,a))}a.functions={rgb:function(a,b,c){return this.rgba(a,b,c,1)},rgba:function(b,d,e,f){var g=[b,d,e].map(function(a){return c(a)}),f=c(f);return new a.Color(g,f)},hsl:function(a,b,c){return this.hsla(a,b,c,1)},hsla:function(a,b,d,e){function h(a){return a=a<0?a+1:a>1?a-1:a,a*6<1?g+(f-g)*a*6:a*2<1?f:a*3<2?g+(f-g)*(2/3-a)*6:g}a=c(a)%360/360,b=c(b),d=c(d),e=c(e);var f=d<=.5?d*(b+1):d+b-d*b,g=d*2-f;return this.rgba(h(a+1/3)*255,h(a)*255,h(a-1/3)*255,e)},hue:function(b){return new a.Dimension(Math.round(b.toHSL().h))},saturation:function(b){return new a.Dimension(Math.round(b.toHSL().s*100),"%")},lightness:function(b){return new a.Dimension(Math.round(b.toHSL().l*100),"%")},alpha:function(b){return new a.Dimension(b.toHSL().a)},saturate:function(a,c){var e=a.toHSL();return e.s+=c.value/100,e.s=d(e.s),b(e)},desaturate:function(a,c){var e=a.toHSL();return e.s-=c.value/100,e.s=d(e.s),b(e)},lighten:function(a,c){var e=a.toHSL();return e.l+=c.value/100,e.l=d(e.l),b(e)},darken:function(a,c){var e=a.toHSL();return e.l-=c.value/100,e.l=d(e.l),b(e)},fadein:function(a,c){var e=a.toHSL();return e.a+=c.value/100,e.a=d(e.a),b(e)},fadeout:function(a,c){var e=a.toHSL();return e.a-=c.value/100,e.a=d(e.a),b(e)},fade:function(a,c){var e=a.toHSL();return e.a=c.value/100,e.a=d(e.a),b(e)},spin:function(a,c){var d=a.toHSL(),e=(d.h+c.value)%360;return d.h=e<0?360+e:e,b(d)},mix:function(b,c,d){var e=d.value/100,f=e*2-1,g=b.toHSL().a-c.toHSL().a,h=((f*g==-1?f:(f+g)/(1+f*g))+1)/2,i=1-h,j=[b.rgb[0]*h+c.rgb[0]*i,b.rgb[1]*h+c.rgb[1]*i,b.rgb[2]*h+c.rgb[2]*i],k=b.alpha*e+c.alpha*(1-e);return new a.Color(j,k)},greyscale:function(b){return this.desaturate(b,new a.Dimension(100))},e:function(b){return new a.Anonymous(b instanceof a.JavaScript?b.evaluated:b)},escape:function(b){return new a.Anonymous(encodeURI(b.value).replace(/=/g,"%3D").replace(/:/g,"%3A").replace(/#/g,"%23").replace(/;/g,"%3B").replace(/\(/g,"%28").replace(/\)/g,"%29"))},"%":function(b){var c=Array.prototype.slice.call(arguments,1),d=b.value;for(var e=0;e255?255:a<0?0:a).toString(16),a.length===1?"0"+a:a}).join("")},operate:function(b,c){var d=[];c instanceof a.Color||(c=c.toColor());for(var e=0;e<3;e++)d[e]=a.operate(b,this.rgb[e],c.rgb[e]);return new a.Color(d,this.alpha+c.alpha)},toHSL:function(){var a=this.rgb[0]/255,b=this.rgb[1]/255,c=this.rgb[2]/255,d=this.alpha,e=Math.max(a,b,c),f=Math.min(a,b,c),g,h,i=(e+f)/2,j=e-f;if(e===f)g=h=0;else{h=i>.5?j/(2-e-f):j/(e+f);switch(e){case a:g=(b-c)/j+(b255?255:a<0?0:a).toString(16),a.length===1?"0"+a:a}).join("")}}}(c("../tree")),function(a){a.Comment=function(a,b){this.value=a,this.silent=!!b},a.Comment.prototype={toCSS:function(a){return a.compress?"":this.value},eval:function(){return this}}}(c("../tree")),function(a){a.Condition=function(a,b,c,d,e){this.op=a.trim(),this.lvalue=b,this.rvalue=c,this.index=d,this.negate=e},a.Condition.prototype.eval=function(a){var b=this.lvalue.eval(a),c=this.rvalue.eval(a),d=this.index,e,e=function(a){switch(a){case"and":return b&&c;case"or":return b||c;default:if(b.compare)e=b.compare(c);else{if(!c.compare)throw{type:"Type",message:"Unable to perform comparison",index:d};e=c.compare(b)}switch(e){case-1:return a==="<"||a==="=<";case 0:return a==="="||a===">="||a==="=<";case 1:return a===">"||a===">="}}}(this.op);return this.negate?!e:e}}(c("../tree")),function(a){a.Dimension=function(a,b){this.value=parseFloat(a),this.unit=b||null},a.Dimension.prototype={eval:function(){return this},toColor:function(){return new a.Color([this.value,this.value,this.value])},toCSS:function(){var a=this.value+this.unit;return a},operate:function(b,c){return new a.Dimension(a.operate(b,this.value,c.value),this.unit||c.unit)},compare:function(b){return b instanceof a.Dimension?b.value>this.value?-1:b.value":a.compress?">":" > "}[this.value]}}(c("../tree")),function(a){a.Expression=function(a){this.value=a},a.Expression.prototype={eval:function(b){return this.value.length>1?new a.Expression(this.value.map(function(a){return a.eval(b)})):this.value.length===1?this.value[0].eval(b):this},toCSS:function(a){return this.value.map(function(b){return b.toCSS?b.toCSS(a):""}).join(" ")}}}(c("../tree")),function(a){a.Import=function(b,c,d,e){var f=this;this.index=e,this._path=b,this.features=d&&new a.Value(d),b instanceof a.Quoted?this.path=/\.(le?|c)ss(\?.*)?$/.test(b.value)?b.value:b.value+".less":this.path=b.value.value||b.value,this.css=/css(\?.*)?$/.test(this.path),this.css||c.push(this.path,function(b,c){b&&(b.index=e),f.root=c||new a.Ruleset([],[])})},a.Import.prototype={toCSS:function(a){var b=this.features?" "+this.features.toCSS(a):"";return this.css?"@import "+this._path.toCSS()+b+";\n":""},eval:function(b){var c,d=this.features&&this.features.eval(b);if(this.css)return this;c=new a.Ruleset([],this.root.rules.slice(0));for(var e=0;e0){c=this.arguments&&this.arguments.map(function(b){return b.eval(a)});for(var g=0;g0&&c>this.params.length)return!1;if(this.condition&&!this.condition.eval({frames:[this.evalParams(b,a)].concat(b.frames)}))return!1;d=Math.min(c,this.arity);for(var f=0;fe.selectors[g].elements.length?Array.prototype.push.apply(d,e.find(new a.Selector(b.elements.slice(1)),c)):d.push(e);break}}),this._lookups[g]=d)},toCSS:function(b,c){var d=[],e=[],f=[],g=[],h,i;this.root||(b.length===0?g=this.selectors.map(function(a){return[a]}):this.joinSelectors(g,b,this.selectors));for(var j=0;j0&&(h=g.map(function(a){return a.map(function(a){return a.toCSS(c)}).join("").trim()}).join(c.compress?",":g.length>3?",\n":", "),d.push(h,(c.compress?"{":" {\n ")+e.join(c.compress?"":"\n ")+(c.compress?"}":"\n}\n"))),d.push(f),d.join("")+(c.compress?"\n":"")},joinSelectors:function(a,b,c){for(var d=0;d0&&e.push(new a.Selector(g)),h.length>0&&f.push(new a.Selector(h));for(var l=0;l0&&(b.value=c[0]+(b.value.charAt(0)==="/"?b.value.slice(1):b.value)),this.value=b,this.paths=c)},b.URL.prototype={toCSS:function(){return"url("+(this.attrs?"data:"+this.attrs.mime+this.attrs.charset+this.attrs.base64+this.attrs.data:this.value.toCSS())+")"},eval:function(a){return this.attrs?this:new b.URL(this.value.eval(a),this.paths)}}}(c("../tree")),function(a){a.Value=function(a){this.value=a,this.is="value"},a.Value.prototype={eval:function(b){return this.value.length===1?this.value[0].eval(b):new a.Value(this.value.map(function(a){return a.eval(b)}))},toCSS:function(a){return this.value.map(function(b){return b.toCSS(a)}).join(a.compress?",":", ")}}}(c("../tree")),function(a){a.Variable=function(a,b,c){this.name=a,this.index=b,this.file=c},a.Variable.prototype={eval:function(b){var c,d,e=this.name;e.indexOf("@@")==0&&(e="@"+(new a.Variable(e.slice(1))).eval(b).value);if(c=a.find(b.frames,function(a){if(d=a.variable(e))return d.value.eval(b)}))return c;throw{type:"Name",message:"variable "+e+" is undefined",filename:this.file,index:this.index}}}}(c("../tree")),function(a){a.find=function(a,b){for(var c=0,d;c1?"["+a.value.map(function(a){return a.toCSS(!1)}).join(", ")+"]":a.toCSS(!1)}}(c("./tree"));var g=location.protocol==="file:"||location.protocol==="chrome:"||location.protocol==="chrome-extension:"||location.protocol==="resource:";d.env=d.env||(location.hostname=="127.0.0.1"||location.hostname=="0.0.0.0"||location.hostname=="localhost"||location.port.length>0||g?"development":"production"),d.async=!1,d.poll=d.poll||(g?1e3:1500),d.watch=function(){return this.watchMode=!0},d.unwatch=function(){return this.watchMode=!1},d.env==="development"?(d.optimization=0,/!watch/.test(location.hash)&&d.watch(),d.watchTimer=setInterval(function(){d.watchMode&&n(function(a,b,c,d,e){b&&r(b.toCSS(),d,e.lastModified)})},d.poll)):d.optimization=3;var h;try{h=typeof a.localStorage=="undefined"?null:a.localStorage}catch(i){h=null}var j=document.getElementsByTagName("link"),k=/^text\/(x-)?less$/;d.sheets=[];for(var l=0;l>> 0; for (var i = 0; i < len; i++) { if (i in this) { block.call(thisObject, this[i], i, this); } } }; } if (!Array.prototype.map) { Array.prototype.map = function(fun /*, thisp*/) { var len = this.length >>> 0; var res = new Array(len); var thisp = arguments[1]; for (var i = 0; i < len; i++) { if (i in this) { res[i] = fun.call(thisp, this[i], i, this); } } return res; }; } if (!Array.prototype.filter) { Array.prototype.filter = function (block /*, thisp */) { var values = []; var thisp = arguments[1]; for (var i = 0; i < this.length; i++) { if (block.call(thisp, this[i])) { values.push(this[i]); } } return values; }; } if (!Array.prototype.reduce) { Array.prototype.reduce = function(fun /*, initial*/) { var len = this.length >>> 0; var i = 0; // no value to return if no initial value and an empty array if (len === 0 && arguments.length === 1) throw new TypeError(); if (arguments.length >= 2) { var rv = arguments[1]; } else { do { if (i in this) { rv = this[i++]; break; } // if array contains no values, no initial value to return if (++i >= len) throw new TypeError(); } while (true); } for (; i < len; i++) { if (i in this) { rv = fun.call(null, rv, this[i], i, this); } } return rv; }; } if (!Array.prototype.indexOf) { Array.prototype.indexOf = function (value /*, fromIndex */ ) { var length = this.length; var i = arguments[1] || 0; if (!length) return -1; if (i >= length) return -1; if (i < 0) i += length; for (; i < length; i++) { if (!Object.prototype.hasOwnProperty.call(this, i)) { continue } if (value === this[i]) return i; } return -1; }; } // // Object // if (!Object.keys) { Object.keys = function (object) { var keys = []; for (var name in object) { if (Object.prototype.hasOwnProperty.call(object, name)) { keys.push(name); } } return keys; }; } // // String // if (!String.prototype.trim) { String.prototype.trim = function () { return String(this).replace(/^\s\s*/, '').replace(/\s\s*$/, ''); }; } var less, tree; if (typeof environment === "object" && ({}).toString.call(environment) === "[object Environment]") { // Rhino // Details on how to detect Rhino: https://github.com/ringo/ringojs/issues/88 if (typeof(window) === 'undefined') { less = {} } else { less = window.less = {} } tree = less.tree = {}; less.mode = 'rhino'; } else if (typeof(window) === 'undefined') { // Node.js less = exports, tree = require('./tree'); less.mode = 'node'; } else { // Browser if (typeof(window.less) === 'undefined') { window.less = {} } less = window.less, tree = window.less.tree = {}; less.mode = 'browser'; } // // less.js - parser // // A relatively straight-forward predictive parser. // There is no tokenization/lexing stage, the input is parsed // in one sweep. // // To make the parser fast enough to run in the browser, several // optimization had to be made: // // - Matching and slicing on a huge input is often cause of slowdowns. // The solution is to chunkify the input into smaller strings. // The chunks are stored in the `chunks` var, // `j` holds the current chunk index, and `current` holds // the index of the current chunk in relation to `input`. // This gives us an almost 4x speed-up. // // - In many cases, we don't need to match individual tokens; // for example, if a value doesn't hold any variables, operations // or dynamic references, the parser can effectively 'skip' it, // treating it as a literal. // An example would be '1px solid #000' - which evaluates to itself, // we don't need to know what the individual components are. // The drawback, of course is that you don't get the benefits of // syntax-checking on the CSS. This gives us a 50% speed-up in the parser, // and a smaller speed-up in the code-gen. // // // Token matching is done with the `$` function, which either takes // a terminal string or regexp, or a non-terminal function to call. // It also takes care of moving all the indices forwards. // // less.Parser = function Parser(env) { var input, // LeSS input string i, // current index in `input` j, // current chunk temp, // temporarily holds a chunk's state, for backtracking memo, // temporarily holds `i`, when backtracking furthest, // furthest index the parser has gone to chunks, // chunkified input current, // index of current chunk, in `input` parser; var that = this; // This function is called after all files // have been imported through `@import`. var finish = function () {}; var imports = this.imports = { paths: env && env.paths || [], // Search paths, when importing queue: [], // Files which haven't been imported yet files: {}, // Holds the imported parse trees contents: {}, // Holds the imported file contents mime: env && env.mime, // MIME type of .less files error: null, // Error in parsing/evaluating an import push: function (path, callback) { var that = this; this.queue.push(path); // // Import a file asynchronously // less.Parser.importer(path, this.paths, function (e, root, contents) { that.queue.splice(that.queue.indexOf(path), 1); // Remove the path from the queue that.files[path] = root; // Store the root that.contents[path] = contents; if (e && !that.error) { that.error = e } callback(e, root); if (that.queue.length === 0) { finish() } // Call `finish` if we're done importing }, env); } }; function save() { temp = chunks[j], memo = i, current = i } function restore() { chunks[j] = temp, i = memo, current = i } function sync() { if (i > current) { chunks[j] = chunks[j].slice(i - current); current = i; } } // // Parse from a token, regexp or string, and move forward if match // function $(tok) { var match, args, length, c, index, endIndex, k, mem; // // Non-terminal // if (tok instanceof Function) { return tok.call(parser.parsers); // // Terminal // // Either match a single character in the input, // or match a regexp in the current chunk (chunk[j]). // } else if (typeof(tok) === 'string') { match = input.charAt(i) === tok ? tok : null; length = 1; sync (); } else { sync (); if (match = tok.exec(chunks[j])) { length = match[0].length; } else { return null; } } // The match is confirmed, add the match length to `i`, // and consume any extra white-space characters (' ' || '\n') // which come after that. The reason for this is that LeSS's // grammar is mostly white-space insensitive. // if (match) { mem = i += length; endIndex = i + chunks[j].length - length; while (i < endIndex) { c = input.charCodeAt(i); if (! (c === 32 || c === 10 || c === 9)) { break } i++; } chunks[j] = chunks[j].slice(length + (i - mem)); current = i; if (chunks[j].length === 0 && j < chunks.length - 1) { j++ } if(typeof(match) === 'string') { return match; } else { return match.length === 1 ? match[0] : match; } } } function expect(arg, msg) { var result = $(arg); if (! result) { error(msg || (typeof(arg) === 'string' ? "expected '" + arg + "' got '" + input.charAt(i) + "'" : "unexpected token")); } else { return result; } } function error(msg, type) { throw { index: i, type: type || 'Syntax', message: msg }; } // Same as $(), but don't change the state of the parser, // just return the match. function peek(tok) { if (typeof(tok) === 'string') { return input.charAt(i) === tok; } else { if (tok.test(chunks[j])) { return true; } else { return false; } } } function basename(pathname) { if (less.mode === 'node') { return require('path').basename(pathname); } else { return pathname.match(/[^\/]+$/)[0]; } } function getInput(e, env) { if (e.filename && env.filename && (e.filename !== env.filename)) { return parser.imports.contents[basename(e.filename)]; } else { return input; } } function getLocation(index, input) { for (var n = index, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } return { line: typeof(index) === 'number' ? (input.slice(0, index).match(/\n/g) || "").length : null, column: column }; } function LessError(e, env) { var input = getInput(e, env), loc = getLocation(e.index, input), line = loc.line, col = loc.column, lines = input.split('\n'); this.type = e.type || 'Syntax'; this.message = e.message; this.filename = e.filename || env.filename; this.index = e.index; this.line = typeof(line) === 'number' ? line + 1 : null; this.callLine = e.call && (getLocation(e.call, input) + 1); this.callExtract = lines[getLocation(e.call, input)]; this.stack = e.stack; this.column = col; this.extract = [ lines[line - 1], lines[line], lines[line + 1] ]; } this.env = env = env || {}; // The optimization level dictates the thoroughness of the parser, // the lower the number, the less nodes it will create in the tree. // This could matter for debugging, or if you want to access // the individual nodes in the tree. this.optimization = ('optimization' in this.env) ? this.env.optimization : 1; this.env.filename = this.env.filename || null; // // The Parser // return parser = { imports: imports, // // Parse an input string into an abstract syntax tree, // call `callback` when done. // parse: function (str, callback) { var root, start, end, zone, line, lines, buff = [], c, error = null; i = j = current = furthest = 0; input = str.replace(/\r\n/g, '\n'); // Split the input into chunks. chunks = (function (chunks) { var j = 0, skip = /[^"'`\{\}\/\(\)\\]+/g, comment = /\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g, string = /"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'|`((?:[^`\\\r\n]|\\.)*)`/g, level = 0, match, chunk = chunks[0], inParam; for (var i = 0, c, cc; i < input.length; i++) { skip.lastIndex = i; if (match = skip.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); } } c = input.charAt(i); comment.lastIndex = string.lastIndex = i; if (match = string.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); c = input.charAt(i); } } if (!inParam && c === '/') { cc = input.charAt(i + 1); if (cc === '/' || cc === '*') { if (match = comment.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); c = input.charAt(i); } } } } switch (c) { case '{': if (! inParam) { level ++; chunk.push(c); break } case '}': if (! inParam) { level --; chunk.push(c); chunks[++j] = chunk = []; break } case '(': if (! inParam) { inParam = true; chunk.push(c); break } case ')': if ( inParam) { inParam = false; chunk.push(c); break } default: chunk.push(c); } } if (level > 0) { error = new(LessError)({ index: i, type: 'Parse', message: "missing closing `}`", filename: env.filename }, env); } return chunks.map(function (c) { return c.join('') });; })([[]]); if (error) { return callback(error); } // Start with the primary rule. // The whole syntax tree is held under a Ruleset node, // with the `root` property set to true, so no `{}` are // output. The callback is called when the input is parsed. try { root = new(tree.Ruleset)([], $(this.parsers.primary)); root.root = true; } catch (e) { return callback(new(LessError)(e, env)); } root.toCSS = (function (evaluate) { var line, lines, column; return function (options, variables) { var frames = [], importError; options = options || {}; // // Allows setting variables with a hash, so: // // `{ color: new(tree.Color)('#f01') }` will become: // // new(tree.Rule)('@color', // new(tree.Value)([ // new(tree.Expression)([ // new(tree.Color)('#f01') // ]) // ]) // ) // if (typeof(variables) === 'object' && !Array.isArray(variables)) { variables = Object.keys(variables).map(function (k) { var value = variables[k]; if (! (value instanceof tree.Value)) { if (! (value instanceof tree.Expression)) { value = new(tree.Expression)([value]); } value = new(tree.Value)([value]); } return new(tree.Rule)('@' + k, value, false, 0); }); frames = [new(tree.Ruleset)(null, variables)]; } try { var css = evaluate.call(this, { frames: frames }) .toCSS([], { compress: options.compress || false }); } catch (e) { throw new(LessError)(e, env); } if ((importError = parser.imports.error)) { // Check if there was an error during importing if (importError instanceof LessError) throw importError; else throw new(LessError)(importError, env); } if (options.yuicompress && less.mode === 'node') { return require('./cssmin').compressor.cssmin(css); } else if (options.compress) { return css.replace(/(\s)+/g, "$1"); } else { return css; } }; })(root.eval); // If `i` is smaller than the `input.length - 1`, // it means the parser wasn't able to parse the whole // string, so we've got a parsing error. // // We try to extract a \n delimited string, // showing the line where the parse error occured. // We split it up into two parts (the part which parsed, // and the part which didn't), so we can color them differently. if (i < input.length - 1) { i = furthest; lines = input.split('\n'); line = (input.slice(0, i).match(/\n/g) || "").length + 1; for (var n = i, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } error = { type: "Parse", message: "Syntax Error on line " + line, index: i, filename: env.filename, line: line, column: column, extract: [ lines[line - 2], lines[line - 1], lines[line] ] }; } if (this.imports.queue.length > 0) { finish = function () { callback(error, root) }; } else { callback(error, root); } }, // // Here in, the parsing rules/functions // // The basic structure of the syntax tree generated is as follows: // // Ruleset -> Rule -> Value -> Expression -> Entity // // Here's some LESS code: // // .class { // color: #fff; // border: 1px solid #000; // width: @w + 4px; // > .child {...} // } // // And here's what the parse tree might look like: // // Ruleset (Selector '.class', [ // Rule ("color", Value ([Expression [Color #fff]])) // Rule ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]])) // Rule ("width", Value ([Expression [Operation "+" [Variable "@w"][Dimension 4px]]])) // Ruleset (Selector [Element '>', '.child'], [...]) // ]) // // In general, most rules will try to parse a token with the `$()` function, and if the return // value is truly, will return a new node, of the relevant type. Sometimes, we need to check // first, before parsing, that's when we use `peek()`. // parsers: { // // The `primary` rule is the *entry* and *exit* point of the parser. // The rules here can appear at any level of the parse tree. // // The recursive nature of the grammar is an interplay between the `block` // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule, // as represented by this simplified grammar: // // primary → (ruleset | rule)+ // ruleset → selector+ block // block → '{' primary '}' // // Only at one point is the primary rule not called from the // block rule: at the root level. // primary: function () { var node, root = []; while ((node = $(this.mixin.definition) || $(this.rule) || $(this.ruleset) || $(this.mixin.call) || $(this.comment) || $(this.directive)) || $(/^[\s\n]+/)) { node && root.push(node); } return root; }, // We create a Comment node for CSS comments `/* */`, // but keep the LeSS comments `//` silent, by just skipping // over them. comment: function () { var comment; if (input.charAt(i) !== '/') return; if (input.charAt(i + 1) === '/') { return new(tree.Comment)($(/^\/\/.*/), true); } else if (comment = $(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/)) { return new(tree.Comment)(comment); } }, // // Entities are tokens which can be found inside an Expression // entities: { // // A string, which supports escaping " and ' // // "milky way" 'he\'s the one!' // quoted: function () { var str, j = i, e; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '"' && input.charAt(j) !== "'") return; e && $('~'); if (str = $(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/)) { return new(tree.Quoted)(str[0], str[1] || str[2], e); } }, // // A catch-all word, such as: // // black border-collapse // keyword: function () { var k; if (k = $(/^[_A-Za-z-][_A-Za-z0-9-]*/)) { if (tree.colors.hasOwnProperty(k)) { // detect named color return new(tree.Color)(tree.colors[k].slice(1)); } else { return new(tree.Keyword)(k); } } }, // // A function call // // rgb(255, 0, 255) // // We also try to catch IE's `alpha()`, but let the `alpha` parser // deal with the details. // // The arguments are parsed with the `entities.arguments` parser. // call: function () { var name, args, index = i; if (! (name = /^([\w-]+|%|progid:[\w\.]+)\(/.exec(chunks[j]))) return; name = name[1].toLowerCase(); if (name === 'url') { return null } else { i += name.length } if (name === 'alpha') { return $(this.alpha) } $('('); // Parse the '(' and consume whitespace. args = $(this.entities.arguments); if (! $(')')) return; if (name) { return new(tree.Call)(name, args, index, env.filename) } }, arguments: function () { var args = [], arg; while (arg = $(this.entities.assignment) || $(this.expression)) { args.push(arg); if (! $(',')) { break } } return args; }, literal: function () { return $(this.entities.dimension) || $(this.entities.color) || $(this.entities.quoted); }, // Assignments are argument entities for calls. // They are present in ie filter properties as shown below. // // filter: progid:DXImageTransform.Microsoft.Alpha( *opacity=50* ) // assignment: function () { var key, value; if ((key = $(/^\w+(?=\s?=)/i)) && $('=') && (value = $(this.entity))) { return new(tree.Assignment)(key, value); } }, // // Parse url() tokens // // We use a specific rule for urls, because they don't really behave like // standard function calls. The difference is that the argument doesn't have // to be enclosed within a string, so it can't be parsed as an Expression. // url: function () { var value; if (input.charAt(i) !== 'u' || !$(/^url\(/)) return; value = $(this.entities.quoted) || $(this.entities.variable) || $(this.entities.dataURI) || $(/^[-\w%@$\/.&=:;#+?~]+/) || ""; expect(')'); return new(tree.URL)((value.value || value.data || value instanceof tree.Variable) ? value : new(tree.Anonymous)(value), imports.paths); }, dataURI: function () { var obj; if ($(/^data:/)) { obj = {}; obj.mime = $(/^[^\/]+\/[^,;)]+/) || ''; obj.charset = $(/^;\s*charset=[^,;)]+/) || ''; obj.base64 = $(/^;\s*base64/) || ''; obj.data = $(/^,\s*[^)]+/); if (obj.data) { return obj } } }, // // A Variable entity, such as `@fink`, in // // width: @fink + 2px // // We use a different parser for variable definitions, // see `parsers.variable`. // variable: function () { var name, index = i; if (input.charAt(i) === '@' && (name = $(/^@@?[\w-]+/))) { return new(tree.Variable)(name, index, env.filename); } }, // // A Hexadecimal color // // #4F3C2F // // `rgb` and `hsl` colors are parsed through the `entities.call` parser. // color: function () { var rgb; if (input.charAt(i) === '#' && (rgb = $(/^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})/))) { return new(tree.Color)(rgb[1]); } }, // // A Dimension, that is, a number and a unit // // 0.5em 95% // dimension: function () { var value, c = input.charCodeAt(i); if ((c > 57 || c < 45) || c === 47) return; if (value = $(/^(-?\d*\.?\d+)(px|%|em|rem|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn)?/)) { return new(tree.Dimension)(value[1], value[2]); } }, // // JavaScript code to be evaluated // // `window.location.href` // javascript: function () { var str, j = i, e; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '`') { return } e && $('~'); if (str = $(/^`([^`]*)`/)) { return new(tree.JavaScript)(str[1], i, e); } } }, // // The variable part of a variable definition. Used in the `rule` parser // // @fink: // variable: function () { var name; if (input.charAt(i) === '@' && (name = $(/^(@[\w-]+)\s*:/))) { return name[1] } }, // // A font size/line-height shorthand // // small/12px // // We need to peek first, or we'll match on keywords and dimensions // shorthand: function () { var a, b; if (! peek(/^[@\w.%-]+\/[@\w.-]+/)) return; if ((a = $(this.entity)) && $('/') && (b = $(this.entity))) { return new(tree.Shorthand)(a, b); } }, // // Mixins // mixin: { // // A Mixin call, with an optional argument list // // #mixins > .square(#fff); // .rounded(4px, black); // .button; // // The `while` loop is there because mixins can be // namespaced, but we only support the child and descendant // selector for now. // call: function () { var elements = [], e, c, args, index = i, s = input.charAt(i), important = false; if (s !== '.' && s !== '#') { return } while (e = $(/^[#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/)) { elements.push(new(tree.Element)(c, e, i)); c = $('>'); } $('(') && (args = $(this.entities.arguments)) && $(')'); if ($(this.important)) { important = true; } if (elements.length > 0 && ($(';') || peek('}'))) { return new(tree.mixin.Call)(elements, args, index, env.filename, important); } }, // // A Mixin definition, with a list of parameters // // .rounded (@radius: 2px, @color) { // ... // } // // Until we have a finer grained state-machine, we have to // do a look-ahead, to make sure we don't have a mixin call. // See the `rule` function for more information. // // We start by matching `.rounded (`, and then proceed on to // the argument list, which has optional default values. // We store the parameters in `params`, with a `value` key, // if there is a value, such as in the case of `@radius`. // // Once we've got our params list, and a closing `)`, we parse // the `{...}` block. // definition: function () { var name, params = [], match, ruleset, param, value, cond; if ((input.charAt(i) !== '.' && input.charAt(i) !== '#') || peek(/^[^{]*(;|})/)) return; save(); if (match = $(/^([#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+)\s*\(/)) { name = match[1]; while (param = $(this.entities.variable) || $(this.entities.literal) || $(this.entities.keyword)) { // Variable if (param instanceof tree.Variable) { if ($(':')) { value = expect(this.expression, 'expected expression'); params.push({ name: param.name, value: value }); } else { params.push({ name: param.name }); } } else { params.push({ value: param }); } if (! $(',')) { break } } expect(')'); if ($(/^when/)) { // Guard cond = expect(this.conditions, 'expected condition'); } ruleset = $(this.block); if (ruleset) { return new(tree.mixin.Definition)(name, params, ruleset, cond); } else { restore(); } } } }, // // Entities are the smallest recognized token, // and can be found inside a rule's value. // entity: function () { return $(this.entities.literal) || $(this.entities.variable) || $(this.entities.url) || $(this.entities.call) || $(this.entities.keyword) || $(this.entities.javascript) || $(this.comment); }, // // A Rule terminator. Note that we use `peek()` to check for '}', // because the `block` rule will be expecting it, but we still need to make sure // it's there, if ';' was ommitted. // end: function () { return $(';') || peek('}'); }, // // IE's alpha function // // alpha(opacity=88) // alpha: function () { var value; if (! $(/^\(opacity=/i)) return; if (value = $(/^\d+/) || $(this.entities.variable)) { expect(')'); return new(tree.Alpha)(value); } }, // // A Selector Element // // div // + h1 // #socks // input[type="text"] // // Elements are the building blocks for Selectors, // they are made out of a `Combinator` (see combinator rule), // and an element name, such as a tag a class, or `*`. // element: function () { var e, t, c, v; c = $(this.combinator); e = $(/^(?:\d+\.\d+|\d+)%/) || $(/^(?:[.#]?|:*)(?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/) || $('*') || $(this.attribute) || $(/^\([^)@]+\)/); if (! e) { $('(') && (v = $(this.entities.variable)) && $(')') && (e = new(tree.Paren)(v)); } if (e) { return new(tree.Element)(c, e, i) } if (c.value && c.value.charAt(0) === '&') { return new(tree.Element)(c, null, i); } }, // // Combinators combine elements together, in a Selector. // // Because our parser isn't white-space sensitive, special care // has to be taken, when parsing the descendant combinator, ` `, // as it's an empty space. We have to check the previous character // in the input, to see if it's a ` ` character. More info on how // we deal with this in *combinator.js*. // combinator: function () { var match, c = input.charAt(i); if (c === '>' || c === '+' || c === '~') { i++; while (input.charAt(i) === ' ') { i++ } return new(tree.Combinator)(c); } else if (c === '&') { match = '&'; i++; if(input.charAt(i) === ' ') { match = '& '; } while (input.charAt(i) === ' ') { i++ } return new(tree.Combinator)(match); } else if (c === ':' && input.charAt(i + 1) === ':') { i += 2; while (input.charAt(i) === ' ') { i++ } return new(tree.Combinator)('::'); } else if (input.charAt(i - 1) === ' ') { return new(tree.Combinator)(" "); } else { return new(tree.Combinator)(null); } }, // // A CSS Selector // // .class > div + h1 // li a:hover // // Selectors are made out of one or more Elements, see above. // selector: function () { var sel, e, elements = [], c, match; while (e = $(this.element)) { c = input.charAt(i); elements.push(e) if (c === '{' || c === '}' || c === ';' || c === ',') { break } } if (elements.length > 0) { return new(tree.Selector)(elements) } }, tag: function () { return $(/^[a-zA-Z][a-zA-Z-]*[0-9]?/) || $('*'); }, attribute: function () { var attr = '', key, val, op; if (! $('[')) return; if (key = $(/^[a-zA-Z-]+/) || $(this.entities.quoted)) { if ((op = $(/^[|~*$^]?=/)) && (val = $(this.entities.quoted) || $(/^[\w-]+/))) { attr = [key, op, val.toCSS ? val.toCSS() : val].join(''); } else { attr = key } } if (! $(']')) return; if (attr) { return "[" + attr + "]" } }, // // The `block` rule is used by `ruleset` and `mixin.definition`. // It's a wrapper around the `primary` rule, with added `{}`. // block: function () { var content; if ($('{') && (content = $(this.primary)) && $('}')) { return content; } }, // // div, .class, body > p {...} // ruleset: function () { var selectors = [], s, rules, match; save(); while (s = $(this.selector)) { selectors.push(s); $(this.comment); if (! $(',')) { break } $(this.comment); } if (selectors.length > 0 && (rules = $(this.block))) { return new(tree.Ruleset)(selectors, rules); } else { // Backtrack furthest = i; restore(); } }, rule: function () { var name, value, c = input.charAt(i), important, match; save(); if (c === '.' || c === '#' || c === '&') { return } if (name = $(this.variable) || $(this.property)) { if ((name.charAt(0) != '@') && (match = /^([^@+\/'"*`(;{}-]*);/.exec(chunks[j]))) { i += match[0].length - 1; value = new(tree.Anonymous)(match[1]); } else if (name === "font") { value = $(this.font); } else { value = $(this.value); } important = $(this.important); if (value && $(this.end)) { return new(tree.Rule)(name, value, important, memo); } else { furthest = i; restore(); } } }, // // An @import directive // // @import "lib"; // // Depending on our environemnt, importing is done differently: // In the browser, it's an XHR request, in Node, it would be a // file-system operation. The function used for importing is // stored in `import`, which we pass to the Import constructor. // "import": function () { var path, features, index = i; if ($(/^@import\s+/) && (path = $(this.entities.quoted) || $(this.entities.url))) { features = $(this.mediaFeatures); if ($(';')) { return new(tree.Import)(path, imports, features, index); } } }, mediaFeature: function () { var nodes = []; do { if (e = $(this.entities.keyword)) { nodes.push(e); } else if ($('(')) { p = $(this.property); e = $(this.entity); if ($(')')) { if (p && e) { nodes.push(new(tree.Paren)(new(tree.Rule)(p, e, null, i, true))); } else if (e) { nodes.push(new(tree.Paren)(e)); } else { return null; } } else { return null } } } while (e); if (nodes.length > 0) { return new(tree.Expression)(nodes); } }, mediaFeatures: function () { var f, features = []; while (f = $(this.mediaFeature)) { features.push(f); if (! $(',')) { break } } return features.length > 0 ? features : null; }, media: function () { var features; if ($(/^@media/)) { features = $(this.mediaFeatures); if (rules = $(this.block)) { return new(tree.Directive)('@media', rules, features); } } }, // // A CSS Directive // // @charset "utf-8"; // directive: function () { var name, value, rules, types, e, nodes; if (input.charAt(i) !== '@') return; if (value = $(this['import']) || $(this.media)) { return value; } else if (name = $(/^@page|@keyframes/) || $(/^@(?:-webkit-|-moz-|-o-|-ms-)[a-z0-9-]+/)) { types = ($(/^[^{]+/) || '').trim(); if (rules = $(this.block)) { return new(tree.Directive)(name + " " + types, rules); } } else if (name = $(/^@[-a-z]+/)) { if (name === '@font-face') { if (rules = $(this.block)) { return new(tree.Directive)(name, rules); } } else if ((value = $(this.entity)) && $(';')) { return new(tree.Directive)(name, value); } } }, font: function () { var value = [], expression = [], weight, shorthand, font, e; while (e = $(this.shorthand) || $(this.entity)) { expression.push(e); } value.push(new(tree.Expression)(expression)); if ($(',')) { while (e = $(this.expression)) { value.push(e); if (! $(',')) { break } } } return new(tree.Value)(value); }, // // A Value is a comma-delimited list of Expressions // // font-family: Baskerville, Georgia, serif; // // In a Rule, a Value represents everything after the `:`, // and before the `;`. // value: function () { var e, expressions = [], important; while (e = $(this.expression)) { expressions.push(e); if (! $(',')) { break } } if (expressions.length > 0) { return new(tree.Value)(expressions); } }, important: function () { if (input.charAt(i) === '!') { return $(/^! *important/); } }, sub: function () { var e; if ($('(') && (e = $(this.expression)) && $(')')) { return e; } }, multiplication: function () { var m, a, op, operation; if (m = $(this.operand)) { while (!peek(/^\/\*/) && (op = ($('/') || $('*'))) && (a = $(this.operand))) { operation = new(tree.Operation)(op, [operation || m, a]); } return operation || m; } }, addition: function () { var m, a, op, operation; if (m = $(this.multiplication)) { while ((op = $(/^[-+]\s+/) || (input.charAt(i - 1) != ' ' && ($('+') || $('-')))) && (a = $(this.multiplication))) { operation = new(tree.Operation)(op, [operation || m, a]); } return operation || m; } }, conditions: function () { var a, b, index = i, condition; if (a = $(this.condition)) { while ($(',') && (b = $(this.condition))) { condition = new(tree.Condition)('or', condition || a, b, index); } return condition || a; } }, condition: function () { var a, b, c, op, index = i, negate = false; if ($(/^not/)) { negate = true } expect('('); if (a = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) { if (op = $(/^(?:>=|=<|[<=>])/)) { if (b = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) { c = new(tree.Condition)(op, a, b, index, negate); } else { error('expected expression'); } } else { c = new(tree.Condition)('=', a, new(tree.Keyword)('true'), index, negate); } expect(')'); return $(/^and/) ? new(tree.Condition)('and', c, $(this.condition)) : c; } }, // // An operand is anything that can be part of an operation, // such as a Color, or a Variable // operand: function () { var negate, p = input.charAt(i + 1); if (input.charAt(i) === '-' && (p === '@' || p === '(')) { negate = $('-') } var o = $(this.sub) || $(this.entities.dimension) || $(this.entities.color) || $(this.entities.variable) || $(this.entities.call); return negate ? new(tree.Operation)('*', [new(tree.Dimension)(-1), o]) : o; }, // // Expressions either represent mathematical operations, // or white-space delimited Entities. // // 1px solid black // @var * 2 // expression: function () { var e, delim, entities = [], d; while (e = $(this.addition) || $(this.entity)) { entities.push(e); } if (entities.length > 0) { return new(tree.Expression)(entities); } }, property: function () { var name; if (name = $(/^(\*?-?[-a-z_0-9]+)\s*:/)) { return name[1]; } } } }; }; if (less.mode === 'browser' || less.mode === 'rhino') { // // Used by `@import` directives // less.Parser.importer = function (path, paths, callback, env) { if (!/^([a-z]+:)?\//.test(path) && paths.length > 0) { path = paths[0] + path; } // We pass `true` as 3rd argument, to force the reload of the import. // This is so we can get the syntax tree as opposed to just the CSS output, // as we need this to evaluate the current stylesheet. loadStyleSheet({ href: path, title: path, type: env.mime }, function (e) { if (e && typeof(env.errback) === "function") { env.errback.call(null, path, paths, callback, env); } else { callback.apply(null, arguments); } }, true); }; } (function (tree) { tree.functions = { rgb: function (r, g, b) { return this.rgba(r, g, b, 1.0); }, rgba: function (r, g, b, a) { var rgb = [r, g, b].map(function (c) { return number(c) }), a = number(a); return new(tree.Color)(rgb, a); }, hsl: function (h, s, l) { return this.hsla(h, s, l, 1.0); }, hsla: function (h, s, l, a) { h = (number(h) % 360) / 360; s = number(s); l = number(l); a = number(a); var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s; var m1 = l * 2 - m2; return this.rgba(hue(h + 1/3) * 255, hue(h) * 255, hue(h - 1/3) * 255, a); function hue(h) { h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h); if (h * 6 < 1) return m1 + (m2 - m1) * h * 6; else if (h * 2 < 1) return m2; else if (h * 3 < 2) return m1 + (m2 - m1) * (2/3 - h) * 6; else return m1; } }, hue: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().h)); }, saturation: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().s * 100), '%'); }, lightness: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().l * 100), '%'); }, alpha: function (color) { return new(tree.Dimension)(color.toHSL().a); }, saturate: function (color, amount) { var hsl = color.toHSL(); hsl.s += amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, desaturate: function (color, amount) { var hsl = color.toHSL(); hsl.s -= amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, lighten: function (color, amount) { var hsl = color.toHSL(); hsl.l += amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, darken: function (color, amount) { var hsl = color.toHSL(); hsl.l -= amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, fadein: function (color, amount) { var hsl = color.toHSL(); hsl.a += amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, fadeout: function (color, amount) { var hsl = color.toHSL(); hsl.a -= amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, fade: function (color, amount) { var hsl = color.toHSL(); hsl.a = amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, spin: function (color, amount) { var hsl = color.toHSL(); var hue = (hsl.h + amount.value) % 360; hsl.h = hue < 0 ? 360 + hue : hue; return hsla(hsl); }, // // Copyright (c) 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein // http://sass-lang.com // mix: function (color1, color2, weight) { var p = weight.value / 100.0; var w = p * 2 - 1; var a = color1.toHSL().a - color2.toHSL().a; var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0; var w2 = 1 - w1; var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2, color1.rgb[1] * w1 + color2.rgb[1] * w2, color1.rgb[2] * w1 + color2.rgb[2] * w2]; var alpha = color1.alpha * p + color2.alpha * (1 - p); return new(tree.Color)(rgb, alpha); }, greyscale: function (color) { return this.desaturate(color, new(tree.Dimension)(100)); }, e: function (str) { return new(tree.Anonymous)(str instanceof tree.JavaScript ? str.evaluated : str); }, escape: function (str) { return new(tree.Anonymous)(encodeURI(str.value).replace(/=/g, "%3D").replace(/:/g, "%3A").replace(/#/g, "%23").replace(/;/g, "%3B").replace(/\(/g, "%28").replace(/\)/g, "%29")); }, '%': function (quoted /* arg, arg, ...*/) { var args = Array.prototype.slice.call(arguments, 1), str = quoted.value; for (var i = 0; i < args.length; i++) { str = str.replace(/%[sda]/i, function(token) { var value = token.match(/s/i) ? args[i].value : args[i].toCSS(); return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value; }); } str = str.replace(/%%/g, '%'); return new(tree.Quoted)('"' + str + '"', str); }, round: function (n) { return this._math('round', n); }, ceil: function (n) { return this._math('ceil', n); }, floor: function (n) { return this._math('floor', n); }, _math: function (fn, n) { if (n instanceof tree.Dimension) { return new(tree.Dimension)(Math[fn](number(n)), n.unit); } else if (typeof(n) === 'number') { return Math[fn](n); } else { throw { type: "Argument", message: "argument must be a number" }; } }, argb: function (color) { return new(tree.Anonymous)(color.toARGB()); }, percentage: function (n) { return new(tree.Dimension)(n.value * 100, '%'); }, color: function (n) { if (n instanceof tree.Quoted) { return new(tree.Color)(n.value.slice(1)); } else { throw { type: "Argument", message: "argument must be a string" }; } }, iscolor: function (n) { return this._isa(n, tree.Color); }, isnumber: function (n) { return this._isa(n, tree.Dimension); }, isstring: function (n) { return this._isa(n, tree.Quoted); }, iskeyword: function (n) { return this._isa(n, tree.Keyword); }, isurl: function (n) { return this._isa(n, tree.URL); }, ispixel: function (n) { return (n instanceof tree.Dimension) && n.unit === 'px' ? tree.True : tree.False; }, ispercentage: function (n) { return (n instanceof tree.Dimension) && n.unit === '%' ? tree.True : tree.False; }, isem: function (n) { return (n instanceof tree.Dimension) && n.unit === 'em' ? tree.True : tree.False; }, _isa: function (n, Type) { return (n instanceof Type) ? tree.True : tree.False; } }; function hsla(hsla) { return tree.functions.hsla(hsla.h, hsla.s, hsla.l, hsla.a); } function number(n) { if (n instanceof tree.Dimension) { return parseFloat(n.unit == '%' ? n.value / 100 : n.value); } else if (typeof(n) === 'number') { return n; } else { throw { error: "RuntimeError", message: "color functions take numbers as parameters" }; } } function clamp(val) { return Math.min(1, Math.max(0, val)); } })(require('./tree')); (function (tree) { tree.colors = { 'aliceblue':'#f0f8ff', 'antiquewhite':'#faebd7', 'aqua':'#00ffff', 'aquamarine':'#7fffd4', 'azure':'#f0ffff', 'beige':'#f5f5dc', 'bisque':'#ffe4c4', 'black':'#000000', 'blanchedalmond':'#ffebcd', 'blue':'#0000ff', 'blueviolet':'#8a2be2', 'brown':'#a52a2a', 'burlywood':'#deb887', 'cadetblue':'#5f9ea0', 'chartreuse':'#7fff00', 'chocolate':'#d2691e', 'coral':'#ff7f50', 'cornflowerblue':'#6495ed', 'cornsilk':'#fff8dc', 'crimson':'#dc143c', 'cyan':'#00ffff', 'darkblue':'#00008b', 'darkcyan':'#008b8b', 'darkgoldenrod':'#b8860b', 'darkgray':'#a9a9a9', 'darkgrey':'#a9a9a9', 'darkgreen':'#006400', 'darkkhaki':'#bdb76b', 'darkmagenta':'#8b008b', 'darkolivegreen':'#556b2f', 'darkorange':'#ff8c00', 'darkorchid':'#9932cc', 'darkred':'#8b0000', 'darksalmon':'#e9967a', 'darkseagreen':'#8fbc8f', 'darkslateblue':'#483d8b', 'darkslategray':'#2f4f4f', 'darkslategrey':'#2f4f4f', 'darkturquoise':'#00ced1', 'darkviolet':'#9400d3', 'deeppink':'#ff1493', 'deepskyblue':'#00bfff', 'dimgray':'#696969', 'dimgrey':'#696969', 'dodgerblue':'#1e90ff', 'firebrick':'#b22222', 'floralwhite':'#fffaf0', 'forestgreen':'#228b22', 'fuchsia':'#ff00ff', 'gainsboro':'#dcdcdc', 'ghostwhite':'#f8f8ff', 'gold':'#ffd700', 'goldenrod':'#daa520', 'gray':'#808080', 'grey':'#808080', 'green':'#008000', 'greenyellow':'#adff2f', 'honeydew':'#f0fff0', 'hotpink':'#ff69b4', 'indianred':'#cd5c5c', 'indigo':'#4b0082', 'ivory':'#fffff0', 'khaki':'#f0e68c', 'lavender':'#e6e6fa', 'lavenderblush':'#fff0f5', 'lawngreen':'#7cfc00', 'lemonchiffon':'#fffacd', 'lightblue':'#add8e6', 'lightcoral':'#f08080', 'lightcyan':'#e0ffff', 'lightgoldenrodyellow':'#fafad2', 'lightgray':'#d3d3d3', 'lightgrey':'#d3d3d3', 'lightgreen':'#90ee90', 'lightpink':'#ffb6c1', 'lightsalmon':'#ffa07a', 'lightseagreen':'#20b2aa', 'lightskyblue':'#87cefa', 'lightslategray':'#778899', 'lightslategrey':'#778899', 'lightsteelblue':'#b0c4de', 'lightyellow':'#ffffe0', 'lime':'#00ff00', 'limegreen':'#32cd32', 'linen':'#faf0e6', 'magenta':'#ff00ff', 'maroon':'#800000', 'mediumaquamarine':'#66cdaa', 'mediumblue':'#0000cd', 'mediumorchid':'#ba55d3', 'mediumpurple':'#9370d8', 'mediumseagreen':'#3cb371', 'mediumslateblue':'#7b68ee', 'mediumspringgreen':'#00fa9a', 'mediumturquoise':'#48d1cc', 'mediumvioletred':'#c71585', 'midnightblue':'#191970', 'mintcream':'#f5fffa', 'mistyrose':'#ffe4e1', 'moccasin':'#ffe4b5', 'navajowhite':'#ffdead', 'navy':'#000080', 'oldlace':'#fdf5e6', 'olive':'#808000', 'olivedrab':'#6b8e23', 'orange':'#ffa500', 'orangered':'#ff4500', 'orchid':'#da70d6', 'palegoldenrod':'#eee8aa', 'palegreen':'#98fb98', 'paleturquoise':'#afeeee', 'palevioletred':'#d87093', 'papayawhip':'#ffefd5', 'peachpuff':'#ffdab9', 'peru':'#cd853f', 'pink':'#ffc0cb', 'plum':'#dda0dd', 'powderblue':'#b0e0e6', 'purple':'#800080', 'red':'#ff0000', 'rosybrown':'#bc8f8f', 'royalblue':'#4169e1', 'saddlebrown':'#8b4513', 'salmon':'#fa8072', 'sandybrown':'#f4a460', 'seagreen':'#2e8b57', 'seashell':'#fff5ee', 'sienna':'#a0522d', 'silver':'#c0c0c0', 'skyblue':'#87ceeb', 'slateblue':'#6a5acd', 'slategray':'#708090', 'slategrey':'#708090', 'snow':'#fffafa', 'springgreen':'#00ff7f', 'steelblue':'#4682b4', 'tan':'#d2b48c', 'teal':'#008080', 'thistle':'#d8bfd8', 'tomato':'#ff6347', 'turquoise':'#40e0d0', 'violet':'#ee82ee', 'wheat':'#f5deb3', 'white':'#ffffff', 'whitesmoke':'#f5f5f5', 'yellow':'#ffff00', 'yellowgreen':'#9acd32' }; })(require('./tree')); (function (tree) { tree.Alpha = function (val) { this.value = val; }; tree.Alpha.prototype = { toCSS: function () { return "alpha(opacity=" + (this.value.toCSS ? this.value.toCSS() : this.value) + ")"; }, eval: function (env) { if (this.value.eval) { this.value = this.value.eval(env) } return this; } }; })(require('../tree')); (function (tree) { tree.Anonymous = function (string) { this.value = string.value || string; }; tree.Anonymous.prototype = { toCSS: function () { return this.value; }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.Assignment = function (key, val) { this.key = key; this.value = val; }; tree.Assignment.prototype = { toCSS: function () { return this.key + '=' + (this.value.toCSS ? this.value.toCSS() : this.value); }, eval: function (env) { if (this.value.eval) { this.value = this.value.eval(env) } return this; } }; })(require('../tree'));(function (tree) { // // A function call node. // tree.Call = function (name, args, index, filename) { this.name = name; this.args = args; this.index = index; this.filename = filename; }; tree.Call.prototype = { // // When evaluating a function call, // we either find the function in `tree.functions` [1], // in which case we call it, passing the evaluated arguments, // or we simply print it out as it appeared originally [2]. // // The *functions.js* file contains the built-in functions. // // The reason why we evaluate the arguments, is in the case where // we try to pass a variable to a function, like: `saturate(@color)`. // The function should receive the value, not the variable. // eval: function (env) { var args = this.args.map(function (a) { return a.eval(env) }); if (this.name in tree.functions) { // 1. try { return tree.functions[this.name].apply(tree.functions, args); } catch (e) { throw { type: e.type || "Runtime", message: "error evaluating function `" + this.name + "`" + (e.message ? ': ' + e.message : ''), index: this.index, filename: this.filename }; } } else { // 2. return new(tree.Anonymous)(this.name + "(" + args.map(function (a) { return a.toCSS() }).join(', ') + ")"); } }, toCSS: function (env) { return this.eval(env).toCSS(); } }; })(require('../tree')); (function (tree) { // // RGB Colors - #ff0014, #eee // tree.Color = function (rgb, a) { // // The end goal here, is to parse the arguments // into an integer triplet, such as `128, 255, 0` // // This facilitates operations and conversions. // if (Array.isArray(rgb)) { this.rgb = rgb; } else if (rgb.length == 6) { this.rgb = rgb.match(/.{2}/g).map(function (c) { return parseInt(c, 16); }); } else { this.rgb = rgb.split('').map(function (c) { return parseInt(c + c, 16); }); } this.alpha = typeof(a) === 'number' ? a : 1; }; tree.Color.prototype = { eval: function () { return this }, // // If we have some transparency, the only way to represent it // is via `rgba`. Otherwise, we use the hex representation, // which has better compatibility with older browsers. // Values are capped between `0` and `255`, rounded and zero-padded. // toCSS: function () { if (this.alpha < 1.0) { return "rgba(" + this.rgb.map(function (c) { return Math.round(c); }).concat(this.alpha).join(', ') + ")"; } else { return '#' + this.rgb.map(function (i) { i = Math.round(i); i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16); return i.length === 1 ? '0' + i : i; }).join(''); } }, // // Operations have to be done per-channel, if not, // channels will spill onto each other. Once we have // our result, in the form of an integer triplet, // we create a new Color node to hold the result. // operate: function (op, other) { var result = []; if (! (other instanceof tree.Color)) { other = other.toColor(); } for (var c = 0; c < 3; c++) { result[c] = tree.operate(op, this.rgb[c], other.rgb[c]); } return new(tree.Color)(result, this.alpha + other.alpha); }, toHSL: function () { var r = this.rgb[0] / 255, g = this.rgb[1] / 255, b = this.rgb[2] / 255, a = this.alpha; var max = Math.max(r, g, b), min = Math.min(r, g, b); var h, s, l = (max + min) / 2, d = max - min; if (max === min) { h = s = 0; } else { s = l > 0.5 ? d / (2 - max - min) : d / (max + min); switch (max) { case r: h = (g - b) / d + (g < b ? 6 : 0); break; case g: h = (b - r) / d + 2; break; case b: h = (r - g) / d + 4; break; } h /= 6; } return { h: h * 360, s: s, l: l, a: a }; }, toARGB: function () { var argb = [Math.round(this.alpha * 255)].concat(this.rgb); return '#' + argb.map(function (i) { i = Math.round(i); i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16); return i.length === 1 ? '0' + i : i; }).join(''); } }; })(require('../tree')); (function (tree) { tree.Comment = function (value, silent) { this.value = value; this.silent = !!silent; }; tree.Comment.prototype = { toCSS: function (env) { return env.compress ? '' : this.value; }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.Condition = function (op, l, r, i, negate) { this.op = op.trim(); this.lvalue = l; this.rvalue = r; this.index = i; this.negate = negate; }; tree.Condition.prototype.eval = function (env) { var a = this.lvalue.eval(env), b = this.rvalue.eval(env); var i = this.index, result; var result = (function (op) { switch (op) { case 'and': return a && b; case 'or': return a || b; default: if (a.compare) { result = a.compare(b); } else if (b.compare) { result = b.compare(a); } else { throw { type: "Type", message: "Unable to perform comparison", index: i }; } switch (result) { case -1: return op === '<' || op === '=<'; case 0: return op === '=' || op === '>=' || op === '=<'; case 1: return op === '>' || op === '>='; } } })(this.op); return this.negate ? !result : result; }; })(require('../tree')); (function (tree) { // // A number with a unit // tree.Dimension = function (value, unit) { this.value = parseFloat(value); this.unit = unit || null; }; tree.Dimension.prototype = { eval: function () { return this }, toColor: function () { return new(tree.Color)([this.value, this.value, this.value]); }, toCSS: function () { var css = this.value + this.unit; return css; }, // In an operation between two Dimensions, // we default to the first Dimension's unit, // so `1px + 2em` will yield `3px`. // In the future, we could implement some unit // conversions such that `100cm + 10mm` would yield // `101cm`. operate: function (op, other) { return new(tree.Dimension) (tree.operate(op, this.value, other.value), this.unit || other.unit); }, // TODO: Perform unit conversion before comparing compare: function (other) { if (other instanceof tree.Dimension) { if (other.value > this.value) { return -1; } else if (other.value < this.value) { return 1; } else { return 0; } } else { return -1; } } }; })(require('../tree')); (function (tree) { tree.Directive = function (name, value, features) { this.name = name; this.features = features && new(tree.Value)(features); if (Array.isArray(value)) { this.ruleset = new(tree.Ruleset)([], value); this.ruleset.allowImports = true; } else { this.value = value; } }; tree.Directive.prototype = { toCSS: function (ctx, env) { var features = this.features ? ' ' + this.features.toCSS(env) : ''; if (this.ruleset) { this.ruleset.root = true; return this.name + features + (env.compress ? '{' : ' {\n ') + this.ruleset.toCSS(ctx, env).trim().replace(/\n/g, '\n ') + (env.compress ? '}': '\n}\n'); } else { return this.name + ' ' + this.value.toCSS() + ';\n'; } }, eval: function (env) { this.features = this.features && this.features.eval(env); env.frames.unshift(this); this.ruleset = this.ruleset && this.ruleset.eval(env); env.frames.shift(); return this; }, variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) }, find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) }, rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) } }; })(require('../tree')); (function (tree) { tree.Element = function (combinator, value, index) { this.combinator = combinator instanceof tree.Combinator ? combinator : new(tree.Combinator)(combinator); if (typeof(value) === 'string') { this.value = value.trim(); } else if (value) { this.value = value; } else { this.value = ""; } this.index = index; }; tree.Element.prototype.eval = function (env) { return new(tree.Element)(this.combinator, this.value.eval ? this.value.eval(env) : this.value, this.index); }; tree.Element.prototype.toCSS = function (env) { return this.combinator.toCSS(env || {}) + (this.value.toCSS ? this.value.toCSS(env) : this.value); }; tree.Combinator = function (value) { if (value === ' ') { this.value = ' '; } else if (value === '& ') { this.value = '& '; } else { this.value = value ? value.trim() : ""; } }; tree.Combinator.prototype.toCSS = function (env) { return { '' : '', ' ' : ' ', '&' : '', '& ' : ' ', ':' : ' :', '::': '::', '+' : env.compress ? '+' : ' + ', '~' : env.compress ? '~' : ' ~ ', '>' : env.compress ? '>' : ' > ' }[this.value]; }; })(require('../tree')); (function (tree) { tree.Expression = function (value) { this.value = value }; tree.Expression.prototype = { eval: function (env) { if (this.value.length > 1) { return new(tree.Expression)(this.value.map(function (e) { return e.eval(env); })); } else if (this.value.length === 1) { return this.value[0].eval(env); } else { return this; } }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS ? e.toCSS(env) : ''; }).join(' '); } }; })(require('../tree')); (function (tree) { // // CSS @import node // // The general strategy here is that we don't want to wait // for the parsing to be completed, before we start importing // the file. That's because in the context of a browser, // most of the time will be spent waiting for the server to respond. // // On creation, we push the import path to our import queue, though // `import,push`, we also pass it a callback, which it'll call once // the file has been fetched, and parsed. // tree.Import = function (path, imports, features, index) { var that = this; this.index = index; this._path = path; this.features = features && new(tree.Value)(features); // The '.less' extension is optional if (path instanceof tree.Quoted) { this.path = /\.(le?|c)ss(\?.*)?$/.test(path.value) ? path.value : path.value + '.less'; } else { this.path = path.value.value || path.value; } this.css = /css(\?.*)?$/.test(this.path); // Only pre-compile .less files if (! this.css) { imports.push(this.path, function (e, root) { if (e) { e.index = index } that.root = root || new(tree.Ruleset)([], []); }); } }; // // The actual import node doesn't return anything, when converted to CSS. // The reason is that it's used at the evaluation stage, so that the rules // it imports can be treated like any other rules. // // In `eval`, we make sure all Import nodes get evaluated, recursively, so // we end up with a flat structure, which can easily be imported in the parent // ruleset. // tree.Import.prototype = { toCSS: function (env) { var features = this.features ? ' ' + this.features.toCSS(env) : ''; if (this.css) { return "@import " + this._path.toCSS() + features + ';\n'; } else { return ""; } }, eval: function (env) { var ruleset, features = this.features && this.features.eval(env); if (this.css) { return this; } else { ruleset = new(tree.Ruleset)([], this.root.rules.slice(0)); for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.Import) { Array.prototype .splice .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env))); } } return this.features ? new(tree.Directive)('@media', ruleset.rules, this.features.value) : ruleset.rules; } } }; })(require('../tree')); (function (tree) { tree.JavaScript = function (string, index, escaped) { this.escaped = escaped; this.expression = string; this.index = index; }; tree.JavaScript.prototype = { eval: function (env) { var result, that = this, context = {}; var expression = this.expression.replace(/@\{([\w-]+)\}/g, function (_, name) { return tree.jsify(new(tree.Variable)('@' + name, that.index).eval(env)); }); try { expression = new(Function)('return (' + expression + ')'); } catch (e) { throw { message: "JavaScript evaluation error: `" + expression + "`" , index: this.index }; } for (var k in env.frames[0].variables()) { context[k.slice(1)] = { value: env.frames[0].variables()[k].value, toJS: function () { return this.value.eval(env).toCSS(); } }; } try { result = expression.call(context); } catch (e) { throw { message: "JavaScript evaluation error: '" + e.name + ': ' + e.message + "'" , index: this.index }; } if (typeof(result) === 'string') { return new(tree.Quoted)('"' + result + '"', result, this.escaped, this.index); } else if (Array.isArray(result)) { return new(tree.Anonymous)(result.join(', ')); } else { return new(tree.Anonymous)(result); } } }; })(require('../tree')); (function (tree) { tree.Keyword = function (value) { this.value = value }; tree.Keyword.prototype = { eval: function () { return this }, toCSS: function () { return this.value }, compare: function (other) { if (other instanceof tree.Keyword) { return other.value === this.value ? 0 : 1; } else { return -1; } } }; tree.True = new(tree.Keyword)('true'); tree.False = new(tree.Keyword)('false'); })(require('../tree')); (function (tree) { tree.mixin = {}; tree.mixin.Call = function (elements, args, index, filename, important) { this.selector = new(tree.Selector)(elements); this.arguments = args; this.index = index; this.filename = filename; this.important = important; }; tree.mixin.Call.prototype = { eval: function (env) { var mixins, args, rules = [], match = false; for (var i = 0; i < env.frames.length; i++) { if ((mixins = env.frames[i].find(this.selector)).length > 0) { args = this.arguments && this.arguments.map(function (a) { return a.eval(env) }); for (var m = 0; m < mixins.length; m++) { if (mixins[m].match(args, env)) { try { Array.prototype.push.apply( rules, mixins[m].eval(env, this.arguments, this.important).rules); match = true; } catch (e) { throw { message: e.message, index: e.index, filename: this.filename, stack: e.stack, call: this.index }; } } } if (match) { return rules; } else { throw { type: 'Runtime', message: 'No matching definition was found for `' + this.selector.toCSS().trim() + '(' + this.arguments.map(function (a) { return a.toCSS(); }).join(', ') + ")`", index: this.index, filename: this.filename }; } } } throw { type: 'Name', message: this.selector.toCSS().trim() + " is undefined", index: this.index, filename: this.filename }; } }; tree.mixin.Definition = function (name, params, rules, condition) { this.name = name; this.selectors = [new(tree.Selector)([new(tree.Element)(null, name)])]; this.params = params; this.condition = condition; this.arity = params.length; this.rules = rules; this._lookups = {}; this.required = params.reduce(function (count, p) { if (!p.name || (p.name && !p.value)) { return count + 1 } else { return count } }, 0); this.parent = tree.Ruleset.prototype; this.frames = []; }; tree.mixin.Definition.prototype = { toCSS: function () { return "" }, variable: function (name) { return this.parent.variable.call(this, name) }, variables: function () { return this.parent.variables.call(this) }, find: function () { return this.parent.find.apply(this, arguments) }, rulesets: function () { return this.parent.rulesets.apply(this) }, evalParams: function (env, args) { var frame = new(tree.Ruleset)(null, []); for (var i = 0, val; i < this.params.length; i++) { if (this.params[i].name) { if (val = (args && args[i]) || this.params[i].value) { frame.rules.unshift(new(tree.Rule)(this.params[i].name, val.eval(env))); } else { throw { type: 'Runtime', message: "wrong number of arguments for " + this.name + ' (' + args.length + ' for ' + this.arity + ')' }; } } } return frame; }, eval: function (env, args, important) { var frame = this.evalParams(env, args), context, _arguments = [], rules; for (var i = 0; i < Math.max(this.params.length, args && args.length); i++) { _arguments.push(args[i] || this.params[i].value); } frame.rules.unshift(new(tree.Rule)('@arguments', new(tree.Expression)(_arguments).eval(env))); rules = important ? this.rules.map(function (r) { return new(tree.Rule)(r.name, r.value, '!important', r.index); }) : this.rules.slice(0); return new(tree.Ruleset)(null, rules).eval({ frames: [this, frame].concat(this.frames, env.frames) }); }, match: function (args, env) { var argsLength = (args && args.length) || 0, len, frame; if (argsLength < this.required) { return false } if ((this.required > 0) && (argsLength > this.params.length)) { return false } if (this.condition && !this.condition.eval({ frames: [this.evalParams(env, args)].concat(env.frames) })) { return false } len = Math.min(argsLength, this.arity); for (var i = 0; i < len; i++) { if (!this.params[i].name) { if (args[i].eval(env).toCSS() != this.params[i].value.eval(env).toCSS()) { return false; } } } return true; } }; })(require('../tree')); (function (tree) { tree.Operation = function (op, operands) { this.op = op.trim(); this.operands = operands; }; tree.Operation.prototype.eval = function (env) { var a = this.operands[0].eval(env), b = this.operands[1].eval(env), temp; if (a instanceof tree.Dimension && b instanceof tree.Color) { if (this.op === '*' || this.op === '+') { temp = b, b = a, a = temp; } else { throw { name: "OperationError", message: "Can't substract or divide a color from a number" }; } } return a.operate(this.op, b); }; tree.operate = function (op, a, b) { switch (op) { case '+': return a + b; case '-': return a - b; case '*': return a * b; case '/': return a / b; } }; })(require('../tree')); (function (tree) { tree.Paren = function (node) { this.value = node; }; tree.Paren.prototype = { toCSS: function (env) { return '(' + this.value.toCSS(env) + ')'; }, eval: function (env) { return new(tree.Paren)(this.value.eval(env)); } }; })(require('../tree')); (function (tree) { tree.Quoted = function (str, content, escaped, i) { this.escaped = escaped; this.value = content || ''; this.quote = str.charAt(0); this.index = i; }; tree.Quoted.prototype = { toCSS: function () { if (this.escaped) { return this.value; } else { return this.quote + this.value + this.quote; } }, eval: function (env) { var that = this; var value = this.value.replace(/`([^`]+)`/g, function (_, exp) { return new(tree.JavaScript)(exp, that.index, true).eval(env).value; }).replace(/@\{([\w-]+)\}/g, function (_, name) { var v = new(tree.Variable)('@' + name, that.index).eval(env); return ('value' in v) ? v.value : v.toCSS(); }); return new(tree.Quoted)(this.quote + value + this.quote, value, this.escaped, this.index); } }; })(require('../tree')); (function (tree) { tree.Rule = function (name, value, important, index, inline) { this.name = name; this.value = (value instanceof tree.Value) ? value : new(tree.Value)([value]); this.important = important ? ' ' + important.trim() : ''; this.index = index; this.inline = inline || false; if (name.charAt(0) === '@') { this.variable = true; } else { this.variable = false } }; tree.Rule.prototype.toCSS = function (env) { if (this.variable) { return "" } else { return this.name + (env.compress ? ':' : ': ') + this.value.toCSS(env) + this.important + (this.inline ? "" : ";"); } }; tree.Rule.prototype.eval = function (context) { return new(tree.Rule)(this.name, this.value.eval(context), this.important, this.index, this.inline); }; tree.Shorthand = function (a, b) { this.a = a; this.b = b; }; tree.Shorthand.prototype = { toCSS: function (env) { return this.a.toCSS(env) + "/" + this.b.toCSS(env); }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.Ruleset = function (selectors, rules) { this.selectors = selectors; this.rules = rules; this._lookups = {}; }; tree.Ruleset.prototype = { eval: function (env) { var selectors = this.selectors && this.selectors.map(function (s) { return s.eval(env) }); var ruleset = new(tree.Ruleset)(selectors, this.rules.slice(0)); ruleset.root = this.root; ruleset.allowImports = this.allowImports; // push the current ruleset to the frames stack env.frames.unshift(ruleset); // Evaluate imports if (ruleset.root || ruleset.allowImports) { for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.Import) { Array.prototype.splice .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env))); } } } // Store the frames around mixin definitions, // so they can be evaluated like closures when the time comes. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Definition) { ruleset.rules[i].frames = env.frames.slice(0); } } // Evaluate mixin calls. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Call) { Array.prototype.splice .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env))); } } // Evaluate everything else for (var i = 0, rule; i < ruleset.rules.length; i++) { rule = ruleset.rules[i]; if (! (rule instanceof tree.mixin.Definition)) { ruleset.rules[i] = rule.eval ? rule.eval(env) : rule; } } // Pop the stack env.frames.shift(); return ruleset; }, match: function (args) { return !args || args.length === 0; }, variables: function () { if (this._variables) { return this._variables } else { return this._variables = this.rules.reduce(function (hash, r) { if (r instanceof tree.Rule && r.variable === true) { hash[r.name] = r; } return hash; }, {}); } }, variable: function (name) { return this.variables()[name]; }, rulesets: function () { if (this._rulesets) { return this._rulesets } else { return this._rulesets = this.rules.filter(function (r) { return (r instanceof tree.Ruleset) || (r instanceof tree.mixin.Definition); }); } }, find: function (selector, self) { self = self || this; var rules = [], rule, match, key = selector.toCSS(); if (key in this._lookups) { return this._lookups[key] } this.rulesets().forEach(function (rule) { if (rule !== self) { for (var j = 0; j < rule.selectors.length; j++) { if (match = selector.match(rule.selectors[j])) { if (selector.elements.length > rule.selectors[j].elements.length) { Array.prototype.push.apply(rules, rule.find( new(tree.Selector)(selector.elements.slice(1)), self)); } else { rules.push(rule); } break; } } } }); return this._lookups[key] = rules; }, // // Entry point for code generation // // `context` holds an array of arrays. // toCSS: function (context, env) { var css = [], // The CSS output rules = [], // node.Rule instances rulesets = [], // node.Ruleset instances paths = [], // Current selectors selector, // The fully rendered selector rule; if (! this.root) { if (context.length === 0) { paths = this.selectors.map(function (s) { return [s] }); } else { this.joinSelectors(paths, context, this.selectors); } } // Compile rules and rulesets for (var i = 0; i < this.rules.length; i++) { rule = this.rules[i]; if (rule.rules || (rule instanceof tree.Directive)) { rulesets.push(rule.toCSS(paths, env)); } else if (rule instanceof tree.Comment) { if (!rule.silent) { if (this.root) { rulesets.push(rule.toCSS(env)); } else { rules.push(rule.toCSS(env)); } } } else { if (rule.toCSS && !rule.variable) { rules.push(rule.toCSS(env)); } else if (rule.value && !rule.variable) { rules.push(rule.value.toString()); } } } rulesets = rulesets.join(''); // If this is the root node, we don't render // a selector, or {}. // Otherwise, only output if this ruleset has rules. if (this.root) { css.push(rules.join(env.compress ? '' : '\n')); } else { if (rules.length > 0) { selector = paths.map(function (p) { return p.map(function (s) { return s.toCSS(env); }).join('').trim(); }).join( env.compress ? ',' : ',\n'); css.push(selector, (env.compress ? '{' : ' {\n ') + rules.join(env.compress ? '' : '\n ') + (env.compress ? '}' : '\n}\n')); } } css.push(rulesets); return css.join('') + (env.compress ? '\n' : ''); }, joinSelectors: function (paths, context, selectors) { for (var s = 0; s < selectors.length; s++) { this.joinSelector(paths, context, selectors[s]); } }, joinSelector: function (paths, context, selector) { var before = [], after = [], beforeElements = [], afterElements = [], hasParentSelector = false, el; for (var i = 0; i < selector.elements.length; i++) { el = selector.elements[i]; if (el.combinator.value.charAt(0) === '&') { hasParentSelector = true; } if (hasParentSelector) afterElements.push(el); else beforeElements.push(el); } if (! hasParentSelector) { afterElements = beforeElements; beforeElements = []; } if (beforeElements.length > 0) { before.push(new(tree.Selector)(beforeElements)); } if (afterElements.length > 0) { after.push(new(tree.Selector)(afterElements)); } for (var c = 0; c < context.length; c++) { paths.push(before.concat(context[c]).concat(after)); } } }; })(require('../tree')); (function (tree) { tree.Selector = function (elements) { this.elements = elements; if (this.elements[0].combinator.value === "") { this.elements[0].combinator.value = ' '; } }; tree.Selector.prototype.match = function (other) { var len = this.elements.length, olen = other.elements.length, max = Math.min(len, olen); if (len < olen) { return false; } else { for (var i = 0; i < max; i++) { if (this.elements[i].value !== other.elements[i].value) { return false; } } } return true; }; tree.Selector.prototype.eval = function (env) { return new(tree.Selector)(this.elements.map(function (e) { return e.eval(env); })); }; tree.Selector.prototype.toCSS = function (env) { if (this._css) { return this._css } return this._css = this.elements.map(function (e) { if (typeof(e) === 'string') { return ' ' + e.trim(); } else { return e.toCSS(env); } }).join(''); }; })(require('../tree')); (function (tree) { tree.URL = function (val, paths) { if (val.data) { this.attrs = val; } else { // Add the base path if the URL is relative and we are in the browser if (typeof(window) !== 'undefined' && !/^(?:https?:\/\/|file:\/\/|data:|\/)/.test(val.value) && paths.length > 0) { val.value = paths[0] + (val.value.charAt(0) === '/' ? val.value.slice(1) : val.value); } this.value = val; this.paths = paths; } }; tree.URL.prototype = { toCSS: function () { return "url(" + (this.attrs ? 'data:' + this.attrs.mime + this.attrs.charset + this.attrs.base64 + this.attrs.data : this.value.toCSS()) + ")"; }, eval: function (ctx) { return this.attrs ? this : new(tree.URL)(this.value.eval(ctx), this.paths); } }; })(require('../tree')); (function (tree) { tree.Value = function (value) { this.value = value; this.is = 'value'; }; tree.Value.prototype = { eval: function (env) { if (this.value.length === 1) { return this.value[0].eval(env); } else { return new(tree.Value)(this.value.map(function (v) { return v.eval(env); })); } }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS(env); }).join(env.compress ? ',' : ', '); } }; })(require('../tree')); (function (tree) { tree.Variable = function (name, index, file) { this.name = name, this.index = index, this.file = file }; tree.Variable.prototype = { eval: function (env) { var variable, v, name = this.name; if (name.indexOf('@@') == 0) { name = '@' + new(tree.Variable)(name.slice(1)).eval(env).value; } if (variable = tree.find(env.frames, function (frame) { if (v = frame.variable(name)) { return v.value.eval(env); } })) { return variable } else { throw { type: 'Name', message: "variable " + name + " is undefined", filename: this.file, index: this.index }; } } }; })(require('../tree')); (function (tree) { tree.find = function (obj, fun) { for (var i = 0, r; i < obj.length; i++) { if (r = fun.call(obj, obj[i])) { return r } } return null; }; tree.jsify = function (obj) { if (Array.isArray(obj.value) && (obj.value.length > 1)) { return '[' + obj.value.map(function (v) { return v.toCSS(false) }).join(', ') + ']'; } else { return obj.toCSS(false); } }; })(require('./tree')); // // browser.js - client-side engine // var isFileProtocol = (location.protocol === 'file:' || location.protocol === 'chrome:' || location.protocol === 'chrome-extension:' || location.protocol === 'resource:'); less.env = less.env || (location.hostname == '127.0.0.1' || location.hostname == '0.0.0.0' || location.hostname == 'localhost' || location.port.length > 0 || isFileProtocol ? 'development' : 'production'); // Load styles asynchronously (default: false) // // This is set to `false` by default, so that the body // doesn't start loading before the stylesheets are parsed. // Setting this to `true` can result in flickering. // less.async = false; // Interval between watch polls less.poll = less.poll || (isFileProtocol ? 1000 : 1500); // // Watch mode // less.watch = function () { return this.watchMode = true }; less.unwatch = function () { return this.watchMode = false }; if (less.env === 'development') { less.optimization = 0; if (/!watch/.test(location.hash)) { less.watch(); } less.watchTimer = setInterval(function () { if (less.watchMode) { loadStyleSheets(function (e, root, _, sheet, env) { if (root) { createCSS(root.toCSS(), sheet, env.lastModified); } }); } }, less.poll); } else { less.optimization = 3; } var cache; try { cache = (typeof(window.localStorage) === 'undefined') ? null : window.localStorage; } catch (_) { cache = null; } // // Get all tags with the 'rel' attribute set to "stylesheet/less" // var links = document.getElementsByTagName('link'); var typePattern = /^text\/(x-)?less$/; less.sheets = []; for (var i = 0; i < links.length; i++) { if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) && (links[i].type.match(typePattern)))) { less.sheets.push(links[i]); } } less.refresh = function (reload) { var startTime, endTime; startTime = endTime = new(Date); loadStyleSheets(function (e, root, _, sheet, env) { if (env.local) { log("loading " + sheet.href + " from cache."); } else { log("parsed " + sheet.href + " successfully."); createCSS(root.toCSS(), sheet, env.lastModified); } log("css for " + sheet.href + " generated in " + (new(Date) - endTime) + 'ms'); (env.remaining === 0) && log("css generated in " + (new(Date) - startTime) + 'ms'); endTime = new(Date); }, reload); loadStyles(); }; less.refreshStyles = loadStyles; less.refresh(less.env === 'development'); function loadStyles() { var styles = document.getElementsByTagName('style'); for (var i = 0; i < styles.length; i++) { if (styles[i].type.match(typePattern)) { new(less.Parser)().parse(styles[i].innerHTML || '', function (e, tree) { var css = tree.toCSS(); var style = styles[i]; style.type = 'text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.innerHTML = css; } }); } } } function loadStyleSheets(callback, reload) { for (var i = 0; i < less.sheets.length; i++) { loadStyleSheet(less.sheets[i], callback, reload, less.sheets.length - (i + 1)); } } function loadStyleSheet(sheet, callback, reload, remaining) { var url = window.location.href.replace(/[#?].*$/, ''); var href = sheet.href.replace(/\?.*$/, ''); var css = cache && cache.getItem(href); var timestamp = cache && cache.getItem(href + ':timestamp'); var styles = { css: css, timestamp: timestamp }; // Stylesheets in IE don't always return the full path if (! /^(https?|file):/.test(href)) { if (href.charAt(0) == "/") { href = window.location.protocol + "//" + window.location.host + href; } else { href = url.slice(0, url.lastIndexOf('/') + 1) + href; } } var filename = href.match(/([^\/]+)$/)[1]; xhr(sheet.href, sheet.type, function (data, lastModified) { if (!reload && styles && lastModified && (new(Date)(lastModified).valueOf() === new(Date)(styles.timestamp).valueOf())) { // Use local copy createCSS(styles.css, sheet); callback(null, null, data, sheet, { local: true, remaining: remaining }); } else { // Use remote copy (re-parse) try { new(less.Parser)({ optimization: less.optimization, paths: [href.replace(/[\w\.-]+$/, '')], mime: sheet.type, filename: filename }).parse(data, function (e, root) { if (e) { return error(e, href) } try { callback(e, root, data, sheet, { local: false, lastModified: lastModified, remaining: remaining }); removeNode(document.getElementById('less-error-message:' + extractId(href))); } catch (e) { error(e, href); } }); } catch (e) { error(e, href); } } }, function (status, url) { throw new(Error)("Couldn't load " + url + " (" + status + ")"); }); } function extractId(href) { return href.replace(/^[a-z]+:\/\/?[^\/]+/, '' ) // Remove protocol & domain .replace(/^\//, '' ) // Remove root / .replace(/\?.*$/, '' ) // Remove query .replace(/\.[^\.\/]+$/, '' ) // Remove file extension .replace(/[^\.\w-]+/g, '-') // Replace illegal characters .replace(/\./g, ':'); // Replace dots with colons(for valid id) } function createCSS(styles, sheet, lastModified) { var css; // Strip the query-string var href = sheet.href ? sheet.href.replace(/\?.*$/, '') : ''; // If there is no title set, use the filename, minus the extension var id = 'less:' + (sheet.title || extractId(href)); // If the stylesheet doesn't exist, create a new node if ((css = document.getElementById(id)) === null) { css = document.createElement('style'); css.type = 'text/css'; css.media = sheet.media || 'screen'; css.id = id; document.getElementsByTagName('head')[0].appendChild(css); } if (css.styleSheet) { // IE try { css.styleSheet.cssText = styles; } catch (e) { throw new(Error)("Couldn't reassign styleSheet.cssText."); } } else { (function (node) { if (css.childNodes.length > 0) { if (css.firstChild.nodeValue !== node.nodeValue) { css.replaceChild(node, css.firstChild); } } else { css.appendChild(node); } })(document.createTextNode(styles)); } // Don't update the local store if the file wasn't modified if (lastModified && cache) { log('saving ' + href + ' to cache.'); cache.setItem(href, styles); cache.setItem(href + ':timestamp', lastModified); } } function xhr(url, type, callback, errback) { var xhr = getXMLHttpRequest(); var async = isFileProtocol ? false : less.async; if (typeof(xhr.overrideMimeType) === 'function') { xhr.overrideMimeType('text/css'); } xhr.open('GET', url, async); xhr.setRequestHeader('Accept', type || 'text/x-less, text/css; q=0.9, */*; q=0.5'); xhr.send(null); if (isFileProtocol) { if (xhr.status === 0 || (xhr.status >= 200 && xhr.status < 300)) { callback(xhr.responseText); } else { errback(xhr.status, url); } } else if (async) { xhr.onreadystatechange = function () { if (xhr.readyState == 4) { handleResponse(xhr, callback, errback); } }; } else { handleResponse(xhr, callback, errback); } function handleResponse(xhr, callback, errback) { if (xhr.status >= 200 && xhr.status < 300) { callback(xhr.responseText, xhr.getResponseHeader("Last-Modified")); } else if (typeof(errback) === 'function') { errback(xhr.status, url); } } } function getXMLHttpRequest() { if (window.XMLHttpRequest) { return new(XMLHttpRequest); } else { try { return new(ActiveXObject)("MSXML2.XMLHTTP.3.0"); } catch (e) { log("browser doesn't support AJAX."); return null; } } } function removeNode(node) { return node && node.parentNode.removeChild(node); } function log(str) { if (less.env == 'development' && typeof(console) !== "undefined") { console.log('less: ' + str) } } function error(e, href) { var id = 'less-error-message:' + extractId(href); var template = '
  • {content}
  • '; var elem = document.createElement('div'), timer, content, error = []; var filename = e.filename || href; elem.id = id; elem.className = "less-error-message"; content = '

    ' + (e.message || 'There is an error in your .less file') + '

    ' + '

    in ' + filename + " "; var errorline = function (e, i, classname) { if (e.extract[i]) { error.push(template.replace(/\{line\}/, parseInt(e.line) + (i - 1)) .replace(/\{class\}/, classname) .replace(/\{content\}/, e.extract[i])); } }; if (e.stack) { content += '
    ' + e.stack.split('\n').slice(1).join('
    '); } else if (e.extract) { errorline(e, 0, ''); errorline(e, 1, 'line'); errorline(e, 2, ''); content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':

    ' + '
      ' + error.join('') + '
    '; } elem.innerHTML = content; // CSS for error messages createCSS([ '.less-error-message ul, .less-error-message li {', 'list-style-type: none;', 'margin-right: 15px;', 'padding: 4px 0;', 'margin: 0;', '}', '.less-error-message label {', 'font-size: 12px;', 'margin-right: 15px;', 'padding: 4px 0;', 'color: #cc7777;', '}', '.less-error-message pre {', 'color: #dd6666;', 'padding: 4px 0;', 'margin: 0;', 'display: inline-block;', '}', '.less-error-message pre.line {', 'color: #ff0000;', '}', '.less-error-message h3 {', 'font-size: 20px;', 'font-weight: bold;', 'padding: 15px 0 5px 0;', 'margin: 0;', '}', '.less-error-message a {', 'color: #10a', '}', '.less-error-message .error {', 'color: red;', 'font-weight: bold;', 'padding-bottom: 2px;', 'border-bottom: 1px dashed red;', '}' ].join('\n'), { title: 'error-message' }); elem.style.cssText = [ "font-family: Arial, sans-serif", "border: 1px solid #e00", "background-color: #eee", "border-radius: 5px", "-webkit-border-radius: 5px", "-moz-border-radius: 5px", "color: #e00", "padding: 15px", "margin-bottom: 15px" ].join(';'); if (less.env == 'development') { timer = setInterval(function () { if (document.body) { if (document.getElementById(id)) { document.body.replaceChild(elem, document.getElementById(id)); } else { document.body.insertBefore(elem, document.body.firstChild); } clearInterval(timer); } }, 10); } } })(window); less.js-1.4.2/dist/less-1.2.2.min.js000066400000000000000000001274271217256642200166120ustar00rootroot00000000000000// // LESS - Leaner CSS v1.2.2 // http://lesscss.org // // Copyright (c) 2009-2011, Alexis Sellier // Licensed under the Apache 2.0 License. // (function(a,b){function c(b){return a.less[b.split("/")[1]]}function m(){var a=document.getElementsByTagName("style");for(var b=0;b0?d.firstChild.nodeValue!==a.nodeValue&&d.replaceChild(a,d.firstChild):d.appendChild(a)})(document.createTextNode(a));c&&h&&(v("saving "+e+" to cache."),h.setItem(e,a),h.setItem(e+":timestamp",c))}function s(a,b,c,e){function i(b,c,d){b.status>=200&&b.status<300?c(b.responseText,b.getResponseHeader("Last-Modified")):typeof d=="function"&&d(b.status,a)}var f=t(),h=g?!1:d.async;typeof f.overrideMimeType=="function"&&f.overrideMimeType("text/css"),f.open("GET",a,h),f.setRequestHeader("Accept",b||"text/x-less, text/css; q=0.9, */*; q=0.5"),f.send(null),g?f.status===0||f.status>=200&&f.status<300?c(f.responseText):e(f.status,a):h?f.onreadystatechange=function(){f.readyState==4&&i(f,c,e)}:i(f,c,e)}function t(){if(a.XMLHttpRequest)return new XMLHttpRequest;try{return new ActiveXObject("MSXML2.XMLHTTP.3.0")}catch(b){return v("browser doesn't support AJAX."),null}}function u(a){return a&&a.parentNode.removeChild(a)}function v(a){d.env=="development"&&typeof console!="undefined"&&console.log("less: "+a)}function w(a,b){var c="less-error-message:"+q(b),e='
  • {content}
  • ',f=document.createElement("div"),g,h,i=[],j=a.filename||b;f.id=c,f.className="less-error-message",h="

    "+(a.message||"There is an error in your .less file")+"

    "+'

    in '+j+" ";var k=function(a,b,c){a.extract[b]&&i.push(e.replace(/\{line\}/,parseInt(a.line)+(b-1)).replace(/\{class\}/,c).replace(/\{content\}/,a.extract[b]))};a.stack?h+="
    "+a.stack.split("\n").slice(1).join("
    "):a.extract&&(k(a,0,""),k(a,1,"line"),k(a,2,""),h+="on line "+a.line+", column "+(a.column+1)+":

    "+"
      "+i.join("")+"
    "),f.innerHTML=h,r([".less-error-message ul, .less-error-message li {","list-style-type: none;","margin-right: 15px;","padding: 4px 0;","margin: 0;","}",".less-error-message label {","font-size: 12px;","margin-right: 15px;","padding: 4px 0;","color: #cc7777;","}",".less-error-message pre {","color: #dd6666;","padding: 4px 0;","margin: 0;","display: inline-block;","}",".less-error-message pre.line {","color: #ff0000;","}",".less-error-message h3 {","font-size: 20px;","font-weight: bold;","padding: 15px 0 5px 0;","margin: 0;","}",".less-error-message a {","color: #10a","}",".less-error-message .error {","color: red;","font-weight: bold;","padding-bottom: 2px;","border-bottom: 1px dashed red;","}"].join("\n"),{title:"error-message"}),f.style.cssText=["font-family: Arial, sans-serif","border: 1px solid #e00","background-color: #eee","border-radius: 5px","-webkit-border-radius: 5px","-moz-border-radius: 5px","color: #e00","padding: 15px","margin-bottom: 15px"].join(";"),d.env=="development"&&(g=setInterval(function(){document.body&&(document.getElementById(c)?document.body.replaceChild(f,document.getElementById(c)):document.body.insertBefore(f,document.body.firstChild),clearInterval(g))},10))}typeof define=="function"&&define.amd&&define("less",[],function(){return d}),Array.isArray||(Array.isArray=function(a){return Object.prototype.toString.call(a)==="[object Array]"||a instanceof Array}),Array.prototype.forEach||(Array.prototype.forEach=function(a,b){var c=this.length>>>0;for(var d=0;d>>0,c=new Array(b),d=arguments[1];for(var e=0;e>>0,c=0;if(b===0&&arguments.length===1)throw new TypeError;if(arguments.length>=2)var d=arguments[1];else do{if(c in this){d=this[c++];break}if(++c>=b)throw new TypeError}while(!0);for(;c=b)return-1;c<0&&(c+=b);for(;cn&&(m[i]=m[i].slice(h-n),n=h)}function w(a){var b,c,d,e,f,j,k,l;if(a instanceof Function)return a.call(o.parsers);if(typeof a=="string")b=g.charAt(h)===a?a:null,d=1,v();else{v();if(!(b=a.exec(m[i])))return null;d=b[0].length}if(b){l=h+=d,j=h+m[i].length-d;while(h=0&&b.charAt(c)!=="\n";c--)d++;return{line:typeof a=="number"?(b.slice(0,a).match(/\n/g)||"").length:null,column:d}}function D(a,b){var c=B(a,b),d=C(a.index,c),e=d.line,f=d.column,g=c.split("\n");this.type=a.type||"Syntax",this.message=a.message,this.filename=a.filename||b.filename,this.index=a.index,this.line=typeof e=="number"?e+1:null,this.callLine=a.call&&C(a.call,c)+1,this.callExtract=g[C(a.call,c)],this.stack=a.stack,this.column=f,this.extract=[g[e-1],g[e],g[e+1]]}var g,h,i,j,k,l,m,n,o,q=this,r=function(){},s=this.imports={paths:b&&b.paths||[],queue:[],files:{},contents:{},mime:b&&b.mime,error:null,push:function(a,c){var e=this;this.queue.push(a),d.Parser.importer(a,this.paths,function(b,d,f){e.queue.splice(e.queue.indexOf(a),1),e.files[a]=d,e.contents[a]=f,b&&!e.error&&(e.error=b),c(b,d),e.queue.length===0&&r()},b)}};return this.env=b=b||{},this.optimization="optimization"in this.env?this.env.optimization:1,this.env.filename=this.env.filename||null,o={imports:s,parse:function(a,e){var j,k,p,q,s,t,u=[],v,x=null;h=i=n=l=0,g=a.replace(/\r\n/g,"\n"),m=function(a){var c=0,d=/[^"'`\{\}\/\(\)\\]+/g,e=/\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g,f=/"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'|`((?:[^`\\\r\n]|\\.)*)`/g,h=0,i,j=a[0],k;for(var l=0,m,n;l0&&(x=new D({index:l,type:"Parse",message:"missing closing `}`",filename:b.filename},b)),a.map(function(a){return a.join("")})}([[]]);if(x)return e(x);try{j=new f.Ruleset([],w(this.parsers.primary)),j.root=!0}catch(y){return e(new D(y,b))}j.toCSS=function(a){var e,g,h;return function(e,g){var h=[],i;e=e||{},typeof g=="object"&&!Array.isArray(g)&&(g=Object.keys(g).map(function(a){var b=g[a];return b instanceof f.Value||(b instanceof f.Expression||(b=new f.Expression([b])),b=new f.Value([b])),new f.Rule("@"+a,b,!1,0)}),h=[new f.Ruleset(null,g)]);try{var j=a.call(this,{frames:h}).toCSS([],{compress:e.compress||!1})}catch(k){throw new D(k,b)}if(i=o.imports.error)throw i instanceof D?i:new D(i,b);return e.yuicompress&&d.mode==="node"?c("./cssmin").compressor.cssmin(j):e.compress?j.replace(/(\s)+/g,"$1"):j}}(j.eval);if(h=0&&g.charAt(z)!=="\n";z--)A++;x={type:"Parse",message:"Syntax Error on line "+s,index:h,filename:b.filename,line:s,column:A,extract:[t[s-2],t[s-1],t[s]]}}this.imports.queue.length>0?r=function(){e(x,j)}:e(x,j)},parsers:{primary:function(){var a,b=[];while((a=w(this.mixin.definition)||w(this.rule)||w(this.ruleset)||w(this.mixin.call)||w(this.comment)||w(this.directive))||w(/^[\s\n]+/))a&&b.push(a);return b},comment:function(){var a;if(g.charAt(h)!=="/")return;if(g.charAt(h+1)==="/")return new f.Comment(w(/^\/\/.*/),!0);if(a=w(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/))return new f.Comment(a)},entities:{quoted:function(){var a,b=h,c;g.charAt(b)==="~"&&(b++,c=!0);if(g.charAt(b)!=='"'&&g.charAt(b)!=="'")return;c&&w("~");if(a=w(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/))return new f.Quoted(a[0],a[1]||a[2],c)},keyword:function(){var a;if(a=w(/^[_A-Za-z-][_A-Za-z0-9-]*/))return f.colors.hasOwnProperty(a)?new f.Color(f.colors[a].slice(1)):new f.Keyword(a)},call:function(){var a,c,d=h;if(!(a=/^([\w-]+|%|progid:[\w\.]+)\(/.exec(m[i])))return;a=a[1].toLowerCase();if(a==="url")return null;h+=a.length;if(a==="alpha")return w(this.alpha);w("("),c=w(this.entities.arguments);if(!w(")"))return;if(a)return new f.Call(a,c,d,b.filename)},arguments:function(){var a=[],b;while(b=w(this.entities.assignment)||w(this.expression)){a.push(b);if(!w(","))break}return a},literal:function(){return w(this.entities.dimension)||w(this.entities.color)||w(this.entities.quoted)},assignment:function(){var a,b;if((a=w(/^\w+(?=\s?=)/i))&&w("=")&&(b=w(this.entity)))return new f.Assignment(a,b)},url:function(){var a;if(g.charAt(h)!=="u"||!w(/^url\(/))return;return a=w(this.entities.quoted)||w(this.entities.variable)||w(this.entities.dataURI)||w(/^[-\w%@$\/.&=:;#+?~]+/)||"",x(")"),new f.URL(a.value||a.data||a instanceof f.Variable?a:new f.Anonymous(a),s.paths)},dataURI:function(){var a;if(w(/^data:/)){a={},a.mime=w(/^[^\/]+\/[^,;)]+/)||"",a.charset=w(/^;\s*charset=[^,;)]+/)||"",a.base64=w(/^;\s*base64/)||"",a.data=w(/^,\s*[^)]+/);if(a.data)return a}},variable:function(){var a,c=h;if(g.charAt(h)==="@"&&(a=w(/^@@?[\w-]+/)))return new f.Variable(a,c,b.filename)},color:function(){var a;if(g.charAt(h)==="#"&&(a=w(/^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})/)))return new f.Color(a[1])},dimension:function(){var a,b=g.charCodeAt(h);if(b>57||b<45||b===47)return;if(a=w(/^(-?\d*\.?\d+)(px|%|em|rem|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn)?/))return new f.Dimension(a[1],a[2])},javascript:function(){var a,b=h,c;g.charAt(b)==="~"&&(b++,c=!0);if(g.charAt(b)!=="`")return;c&&w("~");if(a=w(/^`([^`]*)`/))return new f.JavaScript(a[1],h,c)}},variable:function(){var a;if(g.charAt(h)==="@"&&(a=w(/^(@[\w-]+)\s*:/)))return a[1]},shorthand:function(){var a,b;if(!z(/^[@\w.%-]+\/[@\w.-]+/))return;if((a=w(this.entity))&&w("/")&&(b=w(this.entity)))return new f.Shorthand(a,b)},mixin:{call:function(){var a=[],c,d,e,i=h,j=g.charAt(h),k=!1;if(j!=="."&&j!=="#")return;while(c=w(/^[#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/))a.push(new f.Element(d,c,h)),d=w(">");w("(")&&(e=w(this.entities.arguments))&&w(")"),w(this.important)&&(k=!0);if(a.length>0&&(w(";")||z("}")))return new f.mixin.Call(a,e,i,b.filename,k)},definition:function(){var a,b=[],c,d,e,i,j;if(g.charAt(h)!=="."&&g.charAt(h)!=="#"||z(/^[^{]*(;|})/))return;t();if(c=w(/^([#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+)\s*\(/)){a=c[1];while(e=w(this.entities.variable)||w(this.entities.literal)||w(this.entities.keyword)){e instanceof f.Variable?w(":")?(i=x(this.expression,"expected expression"),b.push({name:e.name,value:i})):b.push({name:e.name}):b.push({value:e});if(!w(","))break}x(")"),w(/^when/)&&(j=x(this.conditions,"expected condition")),d=w(this.block);if(d)return new f.mixin.Definition(a,b,d,j);u()}}},entity:function(){return w(this.entities.literal)||w(this.entities.variable)||w(this.entities.url)||w(this.entities.call)||w(this.entities.keyword)||w(this.entities.javascript)||w(this.comment)},end:function(){return w(";")||z("}")},alpha:function(){var a;if(!w(/^\(opacity=/i))return;if(a=w(/^\d+/)||w(this.entities.variable))return x(")"),new f.Alpha(a)},element:function(){var a,b,c,d;c=w(this.combinator),a=w(/^(?:\d+\.\d+|\d+)%/)||w(/^(?:[.#]?|:*)(?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/)||w("*")||w(this.attribute)||w(/^\([^)@]+\)/),a||w("(")&&(d=w(this.entities.variable))&&w(")")&&(a=new f.Paren(d));if(a)return new f.Element(c,a,h);if(c.value&&c.value.charAt(0)==="&")return new f.Element(c,null,h)},combinator:function(){var a,b=g.charAt(h);if(b===">"||b==="+"||b==="~"){h++;while(g.charAt(h)===" ")h++;return new f.Combinator(b)}if(b==="&"){a="&",h++,g.charAt(h)===" "&&(a="& ");while(g.charAt(h)===" ")h++;return new f.Combinator(a)}if(b===":"&&g.charAt(h+1)===":"){h+=2;while(g.charAt(h)===" ")h++;return new f.Combinator("::")}return g.charAt(h-1)===" "?new f.Combinator(" "):new f.Combinator(null)},selector:function(){var a,b,c=[],d,e;while(b=w(this.element)){d=g.charAt(h),c.push(b);if(d==="{"||d==="}"||d===";"||d===",")break}if(c.length>0)return new f.Selector(c)},tag:function(){return w(/^[a-zA-Z][a-zA-Z-]*[0-9]?/)||w("*")},attribute:function(){var a="",b,c,d;if(!w("["))return;if(b=w(/^[a-zA-Z-]+/)||w(this.entities.quoted))(d=w(/^[|~*$^]?=/))&&(c=w(this.entities.quoted)||w(/^[\w-]+/))?a=[b,d,c.toCSS?c.toCSS():c].join(""):a=b;if(!w("]"))return;if(a)return"["+a+"]"},block:function(){var a;if(w("{")&&(a=w(this.primary))&&w("}"))return a},ruleset:function(){var a=[],b,c,d;t();while(b=w(this.selector)){a.push(b),w(this.comment);if(!w(","))break;w(this.comment)}if(a.length>0&&(c=w(this.block)))return new f.Ruleset(a,c);l=h,u()},rule:function(){var a,b,c=g.charAt(h),d,e;t();if(c==="."||c==="#"||c==="&")return;if(a=w(this.variable)||w(this.property)){a.charAt(0)!="@"&&(e=/^([^@+\/'"*`(;{}-]*);/.exec(m[i]))?(h+=e[0].length-1,b=new f.Anonymous(e[1])):a==="font"?b=w(this.font):b=w(this.value),d=w(this.important);if(b&&w(this.end))return new f.Rule(a,b,d,k);l=h,u()}},"import":function(){var a,b,c=h;if(w(/^@import\s+/)&&(a=w(this.entities.quoted)||w(this.entities.url))){b=w(this.mediaFeatures);if(w(";"))return new f.Import(a,s,b,c)}},mediaFeature:function(){var a=[];do if(e=w(this.entities.keyword))a.push(e);else if(w("(")){p=w(this.property),e=w(this.entity);if(!w(")"))return null;if(p&&e)a.push(new f.Paren(new f.Rule(p,e,null,h,!0)));else{if(!e)return null;a.push(new f.Paren(e))}}while(e);if(a.length>0)return new f.Expression(a)},mediaFeatures:function(){var a,b=[];while(a=w(this.mediaFeature)){b.push(a);if(!w(","))break}return b.length>0?b:null},media:function(){var a;if(w(/^@media/)){a=w(this.mediaFeatures);if(rules=w(this.block))return new f.Directive("@media",rules,a)}},directive:function(){var a,b,c,d,e,i;if(g.charAt(h)!=="@")return;if(b=w(this["import"])||w(this.media))return b;if(a=w(/^@page|@keyframes/)||w(/^@(?:-webkit-|-moz-|-o-|-ms-)[a-z0-9-]+/)){d=(w(/^[^{]+/)||"").trim();if(c=w(this.block))return new f.Directive(a+" "+d,c)}else if(a=w(/^@[-a-z]+/))if(a==="@font-face"){if(c=w(this.block))return new f.Directive(a,c)}else if((b=w(this.entity))&&w(";"))return new f.Directive(a,b)},font:function(){var a=[],b=[],c,d,e,g;while(g=w(this.shorthand)||w(this.entity))b.push(g);a.push(new f.Expression(b));if(w(","))while(g=w(this.expression)){a.push(g);if(!w(","))break}return new f.Value(a)},value:function(){var a,b=[],c;while(a=w(this.expression)){b.push(a);if(!w(","))break}if(b.length>0)return new f.Value(b)},important:function(){if(g.charAt(h)==="!")return w(/^! *important/)},sub:function(){var a;if(w("(")&&(a=w(this.expression))&&w(")"))return a},multiplication:function(){var a,b,c,d;if(a=w(this.operand)){while(!z(/^\/\*/)&&(c=w("/")||w("*"))&&(b=w(this.operand)))d=new f.Operation(c,[d||a,b]);return d||a}},addition:function(){var a,b,c,d;if(a=w(this.multiplication)){while((c=w(/^[-+]\s+/)||g.charAt(h-1)!=" "&&(w("+")||w("-")))&&(b=w(this.multiplication)))d=new f.Operation(c,[d||a,b]);return d||a}},conditions:function(){var a,b,c=h,d;if(a=w(this.condition)){while(w(",")&&(b=w(this.condition)))d=new f.Condition("or",d||a,b,c);return d||a}},condition:function(){var a,b,c,d,e=h,g=!1;w(/^not/)&&(g=!0),x("(");if(a=w(this.addition)||w(this.entities.keyword)||w(this.entities.quoted))return(d=w(/^(?:>=|=<|[<=>])/))?(b=w(this.addition)||w(this.entities.keyword)||w(this.entities.quoted))?c=new f.Condition(d,a,b,e,g):y("expected expression"):c=new f.Condition("=",a,new f.Keyword("true"),e,g),x(")"),w(/^and/)?new f.Condition("and",c,w(this.condition)):c},operand:function(){var a,b=g.charAt(h+1);g.charAt(h)==="-"&&(b==="@"||b==="(")&&(a=w("-"));var c=w(this.sub)||w(this.entities.dimension)||w(this.entities.color)||w(this.entities.variable)||w(this.entities.call);return a?new f.Operation("*",[new f.Dimension(-1),c]):c},expression:function(){var a,b,c=[],d;while(a=w(this.addition)||w(this.entity))c.push(a);if(c.length>0)return new f.Expression(c)},property:function(){var a;if(a=w(/^(\*?-?[-a-z_0-9]+)\s*:/))return a[1]}}}};if(d.mode==="browser"||d.mode==="rhino")d.Parser.importer=function(a,b,c,d){!/^([a-z]+:)?\//.test(a)&&b.length>0&&(a=b[0]+a),o({href:a,title:a,type:d.mime},function(e){e&&typeof d.errback=="function"?d.errback.call(null,a,b,c,d):c.apply(null,arguments)},!0)};(function(a){function b(b){return a.functions.hsla(b.h,b.s,b.l,b.a)}function c(b){if(b instanceof a.Dimension)return parseFloat(b.unit=="%"?b.value/100:b.value);if(typeof b=="number")return b;throw{error:"RuntimeError",message:"color functions take numbers as parameters"}}function d(a){return Math.min(1,Math.max(0,a))}a.functions={rgb:function(a,b,c){return this.rgba(a,b,c,1)},rgba:function(b,d,e,f){var g=[b,d,e].map(function(a){return c(a)}),f=c(f);return new a.Color(g,f)},hsl:function(a,b,c){return this.hsla(a,b,c,1)},hsla:function(a,b,d,e){function h(a){return a=a<0?a+1:a>1?a-1:a,a*6<1?g+(f-g)*a*6:a*2<1?f:a*3<2?g+(f-g)*(2/3-a)*6:g}a=c(a)%360/360,b=c(b),d=c(d),e=c(e);var f=d<=.5?d*(b+1):d+b-d*b,g=d*2-f;return this.rgba(h(a+1/3)*255,h(a)*255,h(a-1/3)*255,e)},hue:function(b){return new a.Dimension(Math.round(b.toHSL().h))},saturation:function(b){return new a.Dimension(Math.round(b.toHSL().s*100),"%")},lightness:function(b){return new a.Dimension(Math.round(b.toHSL().l*100),"%")},alpha:function(b){return new a.Dimension(b.toHSL().a)},saturate:function(a,c){var e=a.toHSL();return e.s+=c.value/100,e.s=d(e.s),b(e)},desaturate:function(a,c){var e=a.toHSL();return e.s-=c.value/100,e.s=d(e.s),b(e)},lighten:function(a,c){var e=a.toHSL();return e.l+=c.value/100,e.l=d(e.l),b(e)},darken:function(a,c){var e=a.toHSL();return e.l-=c.value/100,e.l=d(e.l),b(e)},fadein:function(a,c){var e=a.toHSL();return e.a+=c.value/100,e.a=d(e.a),b(e)},fadeout:function(a,c){var e=a.toHSL();return e.a-=c.value/100,e.a=d(e.a),b(e)},fade:function(a,c){var e=a.toHSL();return e.a=c.value/100,e.a=d(e.a),b(e)},spin:function(a,c){var d=a.toHSL(),e=(d.h+c.value)%360;return d.h=e<0?360+e:e,b(d)},mix:function(b,c,d){var e=d.value/100,f=e*2-1,g=b.toHSL().a-c.toHSL().a,h=((f*g==-1?f:(f+g)/(1+f*g))+1)/2,i=1-h,j=[b.rgb[0]*h+c.rgb[0]*i,b.rgb[1]*h+c.rgb[1]*i,b.rgb[2]*h+c.rgb[2]*i],k=b.alpha*e+c.alpha*(1-e);return new a.Color(j,k)},greyscale:function(b){return this.desaturate(b,new a.Dimension(100))},e:function(b){return new a.Anonymous(b instanceof a.JavaScript?b.evaluated:b)},escape:function(b){return new a.Anonymous(encodeURI(b.value).replace(/=/g,"%3D").replace(/:/g,"%3A").replace(/#/g,"%23").replace(/;/g,"%3B").replace(/\(/g,"%28").replace(/\)/g,"%29"))},"%":function(b){var c=Array.prototype.slice.call(arguments,1),d=b.value;for(var e=0;e255?255:a<0?0:a).toString(16),a.length===1?"0"+a:a}).join("")},operate:function(b,c){var d=[];c instanceof a.Color||(c=c.toColor());for(var e=0;e<3;e++)d[e]=a.operate(b,this.rgb[e],c.rgb[e]);return new a.Color(d,this.alpha+c.alpha)},toHSL:function(){var a=this.rgb[0]/255,b=this.rgb[1]/255,c=this.rgb[2]/255,d=this.alpha,e=Math.max(a,b,c),f=Math.min(a,b,c),g,h,i=(e+f)/2,j=e-f;if(e===f)g=h=0;else{h=i>.5?j/(2-e-f):j/(e+f);switch(e){case a:g=(b-c)/j+(b255?255:a<0?0:a).toString(16),a.length===1?"0"+a:a}).join("")}}}(c("../tree")),function(a){a.Comment=function(a,b){this.value=a,this.silent=!!b},a.Comment.prototype={toCSS:function(a){return a.compress?"":this.value},eval:function(){return this}}}(c("../tree")),function(a){a.Condition=function(a,b,c,d,e){this.op=a.trim(),this.lvalue=b,this.rvalue=c,this.index=d,this.negate=e},a.Condition.prototype.eval=function(a){var b=this.lvalue.eval(a),c=this.rvalue.eval(a),d=this.index,e,e=function(a){switch(a){case"and":return b&&c;case"or":return b||c;default:if(b.compare)e=b.compare(c);else{if(!c.compare)throw{type:"Type",message:"Unable to perform comparison",index:d};e=c.compare(b)}switch(e){case-1:return a==="<"||a==="=<";case 0:return a==="="||a===">="||a==="=<";case 1:return a===">"||a===">="}}}(this.op);return this.negate?!e:e}}(c("../tree")),function(a){a.Dimension=function(a,b){this.value=parseFloat(a),this.unit=b||null},a.Dimension.prototype={eval:function(){return this},toColor:function(){return new a.Color([this.value,this.value,this.value])},toCSS:function(){var a=this.value+this.unit;return a},operate:function(b,c){return new a.Dimension(a.operate(b,this.value,c.value),this.unit||c.unit)},compare:function(b){return b instanceof a.Dimension?b.value>this.value?-1:b.value":a.compress?">":" > "}[this.value]}}(c("../tree")),function(a){a.Expression=function(a){this.value=a},a.Expression.prototype={eval:function(b){return this.value.length>1?new a.Expression(this.value.map(function(a){return a.eval(b)})):this.value.length===1?this.value[0].eval(b):this},toCSS:function(a){return this.value.map(function(b){return b.toCSS?b.toCSS(a):""}).join(" ")}}}(c("../tree")),function(a){a.Import=function(b,c,d,e){var f=this;this.index=e,this._path=b,this.features=d&&new a.Value(d),b instanceof a.Quoted?this.path=/\.(le?|c)ss(\?.*)?$/.test(b.value)?b.value:b.value+".less":this.path=b.value.value||b.value,this.css=/css(\?.*)?$/.test(this.path),this.css||c.push(this.path,function(b,c){b&&(b.index=e),f.root=c||new a.Ruleset([],[])})},a.Import.prototype={toCSS:function(a){var b=this.features?" "+this.features.toCSS(a):"";return this.css?"@import "+this._path.toCSS()+b+";\n":""},eval:function(b){var c,d=this.features&&this.features.eval(b);if(this.css)return this;c=new a.Ruleset([],this.root.rules.slice(0));for(var e=0;e0){c=this.arguments&&this.arguments.map(function(b){return b.eval(a)});for(var g=0;g0&&c>this.params.length)return!1;if(this.condition&&!this.condition.eval({frames:[this.evalParams(b,a)].concat(b.frames)}))return!1;d=Math.min(c,this.arity);for(var f=0;fe.selectors[g].elements.length?Array.prototype.push.apply(d,e.find(new a.Selector(b.elements.slice(1)),c)):d.push(e);break}}),this._lookups[g]=d)},toCSS:function(b,c){var d=[],e=[],f=[],g=[],h,i;this.root||(b.length===0?g=this.selectors.map(function(a){return[a]}):this.joinSelectors(g,b,this.selectors));for(var j=0;j0&&(h=g.map(function(a){return a.map(function(a){return a.toCSS(c)}).join("").trim()}).join(c.compress?",":",\n"),d.push(h,(c.compress?"{":" {\n ")+e.join(c.compress?"":"\n ")+(c.compress?"}":"\n}\n"))),d.push(f),d.join("")+(c.compress?"\n":"")},joinSelectors:function(a,b,c){for(var d=0;d0&&e.push(new a.Selector(g)),h.length>0&&f.push(new a.Selector(h));for(var l=0;l0&&(b.value=c[0]+(b.value.charAt(0)==="/"?b.value.slice(1):b.value)),this.value=b,this.paths=c)},b.URL.prototype={toCSS:function(){return"url("+(this.attrs?"data:"+this.attrs.mime+this.attrs.charset+this.attrs.base64+this.attrs.data:this.value.toCSS())+")"},eval:function(a){return this.attrs?this:new b.URL(this.value.eval(a),this.paths)}}}(c("../tree")),function(a){a.Value=function(a){this.value=a,this.is="value"},a.Value.prototype={eval:function(b){return this.value.length===1?this.value[0].eval(b):new a.Value(this.value.map(function(a){return a.eval(b)}))},toCSS:function(a){return this.value.map(function(b){return b.toCSS(a)}).join(a.compress?",":", ")}}}(c("../tree")),function(a){a.Variable=function(a,b,c){this.name=a,this.index=b,this.file=c},a.Variable.prototype={eval:function(b){var c,d,e=this.name;e.indexOf("@@")==0&&(e="@"+(new a.Variable(e.slice(1))).eval(b).value);if(c=a.find(b.frames,function(a){if(d=a.variable(e))return d.value.eval(b)}))return c;throw{type:"Name",message:"variable "+e+" is undefined",filename:this.file,index:this.index}}}}(c("../tree")),function(a){a.find=function(a,b){for(var c=0,d;c1?"["+a.value.map(function(a){return a.toCSS(!1)}).join(", ")+"]":a.toCSS(!1)}}(c("./tree"));var g=location.protocol==="file:"||location.protocol==="chrome:"||location.protocol==="chrome-extension:"||location.protocol==="resource:";d.env=d.env||(location.hostname=="127.0.0.1"||location.hostname=="0.0.0.0"||location.hostname=="localhost"||location.port.length>0||g?"development":"production"),d.async=!1,d.poll=d.poll||(g?1e3:1500),d.watch=function(){return this.watchMode=!0},d.unwatch=function(){return this.watchMode=!1},d.env==="development"?(d.optimization=0,/!watch/.test(location.hash)&&d.watch(),d.watchTimer=setInterval(function(){d.watchMode&&n(function(a,b,c,d,e){b&&r(b.toCSS(),d,e.lastModified)})},d.poll)):d.optimization=3;var h;try{h=typeof a.localStorage=="undefined"?null:a.localStorage}catch(i){h=null}var j=document.getElementsByTagName("link"),k=/^text\/(x-)?less$/;d.sheets=[];for(var l=0;l>> 0; for (var i = 0; i < len; i++) { if (i in this) { block.call(thisObject, this[i], i, this); } } }; } if (!Array.prototype.map) { Array.prototype.map = function(fun /*, thisp*/) { var len = this.length >>> 0; var res = new Array(len); var thisp = arguments[1]; for (var i = 0; i < len; i++) { if (i in this) { res[i] = fun.call(thisp, this[i], i, this); } } return res; }; } if (!Array.prototype.filter) { Array.prototype.filter = function (block /*, thisp */) { var values = []; var thisp = arguments[1]; for (var i = 0; i < this.length; i++) { if (block.call(thisp, this[i])) { values.push(this[i]); } } return values; }; } if (!Array.prototype.reduce) { Array.prototype.reduce = function(fun /*, initial*/) { var len = this.length >>> 0; var i = 0; // no value to return if no initial value and an empty array if (len === 0 && arguments.length === 1) throw new TypeError(); if (arguments.length >= 2) { var rv = arguments[1]; } else { do { if (i in this) { rv = this[i++]; break; } // if array contains no values, no initial value to return if (++i >= len) throw new TypeError(); } while (true); } for (; i < len; i++) { if (i in this) { rv = fun.call(null, rv, this[i], i, this); } } return rv; }; } if (!Array.prototype.indexOf) { Array.prototype.indexOf = function (value /*, fromIndex */ ) { var length = this.length; var i = arguments[1] || 0; if (!length) return -1; if (i >= length) return -1; if (i < 0) i += length; for (; i < length; i++) { if (!Object.prototype.hasOwnProperty.call(this, i)) { continue } if (value === this[i]) return i; } return -1; }; } // // Object // if (!Object.keys) { Object.keys = function (object) { var keys = []; for (var name in object) { if (Object.prototype.hasOwnProperty.call(object, name)) { keys.push(name); } } return keys; }; } // // String // if (!String.prototype.trim) { String.prototype.trim = function () { return String(this).replace(/^\s\s*/, '').replace(/\s\s*$/, ''); }; } var less, tree; if (typeof environment === "object" && ({}).toString.call(environment) === "[object Environment]") { // Rhino // Details on how to detect Rhino: https://github.com/ringo/ringojs/issues/88 if (typeof(window) === 'undefined') { less = {} } else { less = window.less = {} } tree = less.tree = {}; less.mode = 'rhino'; } else if (typeof(window) === 'undefined') { // Node.js less = exports, tree = require('./tree'); less.mode = 'node'; } else { // Browser if (typeof(window.less) === 'undefined') { window.less = {} } less = window.less, tree = window.less.tree = {}; less.mode = 'browser'; } // // less.js - parser // // A relatively straight-forward predictive parser. // There is no tokenization/lexing stage, the input is parsed // in one sweep. // // To make the parser fast enough to run in the browser, several // optimization had to be made: // // - Matching and slicing on a huge input is often cause of slowdowns. // The solution is to chunkify the input into smaller strings. // The chunks are stored in the `chunks` var, // `j` holds the current chunk index, and `current` holds // the index of the current chunk in relation to `input`. // This gives us an almost 4x speed-up. // // - In many cases, we don't need to match individual tokens; // for example, if a value doesn't hold any variables, operations // or dynamic references, the parser can effectively 'skip' it, // treating it as a literal. // An example would be '1px solid #000' - which evaluates to itself, // we don't need to know what the individual components are. // The drawback, of course is that you don't get the benefits of // syntax-checking on the CSS. This gives us a 50% speed-up in the parser, // and a smaller speed-up in the code-gen. // // // Token matching is done with the `$` function, which either takes // a terminal string or regexp, or a non-terminal function to call. // It also takes care of moving all the indices forwards. // // less.Parser = function Parser(env) { var input, // LeSS input string i, // current index in `input` j, // current chunk temp, // temporarily holds a chunk's state, for backtracking memo, // temporarily holds `i`, when backtracking furthest, // furthest index the parser has gone to chunks, // chunkified input current, // index of current chunk, in `input` parser; var that = this; // This function is called after all files // have been imported through `@import`. var finish = function () {}; var imports = this.imports = { paths: env && env.paths || [], // Search paths, when importing queue: [], // Files which haven't been imported yet files: {}, // Holds the imported parse trees contents: {}, // Holds the imported file contents mime: env && env.mime, // MIME type of .less files error: null, // Error in parsing/evaluating an import push: function (path, callback) { var that = this; this.queue.push(path); // // Import a file asynchronously // less.Parser.importer(path, this.paths, function (e, root, contents) { that.queue.splice(that.queue.indexOf(path), 1); // Remove the path from the queue that.files[path] = root; // Store the root that.contents[path] = contents; if (e && !that.error) { that.error = e } callback(e, root); if (that.queue.length === 0) { finish() } // Call `finish` if we're done importing }, env); } }; function save() { temp = chunks[j], memo = i, current = i } function restore() { chunks[j] = temp, i = memo, current = i } function sync() { if (i > current) { chunks[j] = chunks[j].slice(i - current); current = i; } } // // Parse from a token, regexp or string, and move forward if match // function $(tok) { var match, args, length, c, index, endIndex, k, mem; // // Non-terminal // if (tok instanceof Function) { return tok.call(parser.parsers); // // Terminal // // Either match a single character in the input, // or match a regexp in the current chunk (chunk[j]). // } else if (typeof(tok) === 'string') { match = input.charAt(i) === tok ? tok : null; length = 1; sync (); } else { sync (); if (match = tok.exec(chunks[j])) { length = match[0].length; } else { return null; } } // The match is confirmed, add the match length to `i`, // and consume any extra white-space characters (' ' || '\n') // which come after that. The reason for this is that LeSS's // grammar is mostly white-space insensitive. // if (match) { mem = i += length; endIndex = i + chunks[j].length - length; while (i < endIndex) { c = input.charCodeAt(i); if (! (c === 32 || c === 10 || c === 9)) { break } i++; } chunks[j] = chunks[j].slice(length + (i - mem)); current = i; if (chunks[j].length === 0 && j < chunks.length - 1) { j++ } if(typeof(match) === 'string') { return match; } else { return match.length === 1 ? match[0] : match; } } } function expect(arg, msg) { var result = $(arg); if (! result) { error(msg || (typeof(arg) === 'string' ? "expected '" + arg + "' got '" + input.charAt(i) + "'" : "unexpected token")); } else { return result; } } function error(msg, type) { throw { index: i, type: type || 'Syntax', message: msg }; } // Same as $(), but don't change the state of the parser, // just return the match. function peek(tok) { if (typeof(tok) === 'string') { return input.charAt(i) === tok; } else { if (tok.test(chunks[j])) { return true; } else { return false; } } } function basename(pathname) { if (less.mode === 'node') { return require('path').basename(pathname); } else { return pathname.match(/[^\/]+$/)[0]; } } function getInput(e, env) { if (e.filename && env.filename && (e.filename !== env.filename)) { return parser.imports.contents[basename(e.filename)]; } else { return input; } } function getLocation(index, input) { for (var n = index, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } return { line: typeof(index) === 'number' ? (input.slice(0, index).match(/\n/g) || "").length : null, column: column }; } function LessError(e, env) { var input = getInput(e, env), loc = getLocation(e.index, input), line = loc.line, col = loc.column, lines = input.split('\n'); this.type = e.type || 'Syntax'; this.message = e.message; this.filename = e.filename || env.filename; this.index = e.index; this.line = typeof(line) === 'number' ? line + 1 : null; this.callLine = e.call && (getLocation(e.call, input).line + 1); this.callExtract = lines[getLocation(e.call, input).line]; this.stack = e.stack; this.column = col; this.extract = [ lines[line - 1], lines[line], lines[line + 1] ]; } this.env = env = env || {}; // The optimization level dictates the thoroughness of the parser, // the lower the number, the less nodes it will create in the tree. // This could matter for debugging, or if you want to access // the individual nodes in the tree. this.optimization = ('optimization' in this.env) ? this.env.optimization : 1; this.env.filename = this.env.filename || null; // // The Parser // return parser = { imports: imports, // // Parse an input string into an abstract syntax tree, // call `callback` when done. // parse: function (str, callback) { var root, start, end, zone, line, lines, buff = [], c, error = null; i = j = current = furthest = 0; input = str.replace(/\r\n/g, '\n'); // Split the input into chunks. chunks = (function (chunks) { var j = 0, skip = /[^"'`\{\}\/\(\)\\]+/g, comment = /\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g, string = /"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'|`((?:[^`\\\r\n]|\\.)*)`/g, level = 0, match, chunk = chunks[0], inParam; for (var i = 0, c, cc; i < input.length; i++) { skip.lastIndex = i; if (match = skip.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); } } c = input.charAt(i); comment.lastIndex = string.lastIndex = i; if (match = string.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); c = input.charAt(i); } } if (!inParam && c === '/') { cc = input.charAt(i + 1); if (cc === '/' || cc === '*') { if (match = comment.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); c = input.charAt(i); } } } } switch (c) { case '{': if (! inParam) { level ++; chunk.push(c); break } case '}': if (! inParam) { level --; chunk.push(c); chunks[++j] = chunk = []; break } case '(': if (! inParam) { inParam = true; chunk.push(c); break } case ')': if ( inParam) { inParam = false; chunk.push(c); break } default: chunk.push(c); } } if (level > 0) { error = new(LessError)({ index: i, type: 'Parse', message: "missing closing `}`", filename: env.filename }, env); } return chunks.map(function (c) { return c.join('') });; })([[]]); if (error) { return callback(error); } // Start with the primary rule. // The whole syntax tree is held under a Ruleset node, // with the `root` property set to true, so no `{}` are // output. The callback is called when the input is parsed. try { root = new(tree.Ruleset)([], $(this.parsers.primary)); root.root = true; } catch (e) { return callback(new(LessError)(e, env)); } root.toCSS = (function (evaluate) { var line, lines, column; return function (options, variables) { var frames = [], importError; options = options || {}; // // Allows setting variables with a hash, so: // // `{ color: new(tree.Color)('#f01') }` will become: // // new(tree.Rule)('@color', // new(tree.Value)([ // new(tree.Expression)([ // new(tree.Color)('#f01') // ]) // ]) // ) // if (typeof(variables) === 'object' && !Array.isArray(variables)) { variables = Object.keys(variables).map(function (k) { var value = variables[k]; if (! (value instanceof tree.Value)) { if (! (value instanceof tree.Expression)) { value = new(tree.Expression)([value]); } value = new(tree.Value)([value]); } return new(tree.Rule)('@' + k, value, false, 0); }); frames = [new(tree.Ruleset)(null, variables)]; } try { var css = evaluate.call(this, { frames: frames }) .toCSS([], { compress: options.compress || false }); } catch (e) { throw new(LessError)(e, env); } if ((importError = parser.imports.error)) { // Check if there was an error during importing if (importError instanceof LessError) throw importError; else throw new(LessError)(importError, env); } if (options.yuicompress && less.mode === 'node') { return require('./cssmin').compressor.cssmin(css); } else if (options.compress) { return css.replace(/(\s)+/g, "$1"); } else { return css; } }; })(root.eval); // If `i` is smaller than the `input.length - 1`, // it means the parser wasn't able to parse the whole // string, so we've got a parsing error. // // We try to extract a \n delimited string, // showing the line where the parse error occured. // We split it up into two parts (the part which parsed, // and the part which didn't), so we can color them differently. if (i < input.length - 1) { i = furthest; lines = input.split('\n'); line = (input.slice(0, i).match(/\n/g) || "").length + 1; for (var n = i, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } error = { type: "Parse", message: "Syntax Error on line " + line, index: i, filename: env.filename, line: line, column: column, extract: [ lines[line - 2], lines[line - 1], lines[line] ] }; } if (this.imports.queue.length > 0) { finish = function () { callback(error, root) }; } else { callback(error, root); } }, // // Here in, the parsing rules/functions // // The basic structure of the syntax tree generated is as follows: // // Ruleset -> Rule -> Value -> Expression -> Entity // // Here's some LESS code: // // .class { // color: #fff; // border: 1px solid #000; // width: @w + 4px; // > .child {...} // } // // And here's what the parse tree might look like: // // Ruleset (Selector '.class', [ // Rule ("color", Value ([Expression [Color #fff]])) // Rule ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]])) // Rule ("width", Value ([Expression [Operation "+" [Variable "@w"][Dimension 4px]]])) // Ruleset (Selector [Element '>', '.child'], [...]) // ]) // // In general, most rules will try to parse a token with the `$()` function, and if the return // value is truly, will return a new node, of the relevant type. Sometimes, we need to check // first, before parsing, that's when we use `peek()`. // parsers: { // // The `primary` rule is the *entry* and *exit* point of the parser. // The rules here can appear at any level of the parse tree. // // The recursive nature of the grammar is an interplay between the `block` // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule, // as represented by this simplified grammar: // // primary → (ruleset | rule)+ // ruleset → selector+ block // block → '{' primary '}' // // Only at one point is the primary rule not called from the // block rule: at the root level. // primary: function () { var node, root = []; while ((node = $(this.mixin.definition) || $(this.rule) || $(this.ruleset) || $(this.mixin.call) || $(this.comment) || $(this.directive)) || $(/^[\s\n]+/)) { node && root.push(node); } return root; }, // We create a Comment node for CSS comments `/* */`, // but keep the LeSS comments `//` silent, by just skipping // over them. comment: function () { var comment; if (input.charAt(i) !== '/') return; if (input.charAt(i + 1) === '/') { return new(tree.Comment)($(/^\/\/.*/), true); } else if (comment = $(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/)) { return new(tree.Comment)(comment); } }, // // Entities are tokens which can be found inside an Expression // entities: { // // A string, which supports escaping " and ' // // "milky way" 'he\'s the one!' // quoted: function () { var str, j = i, e; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '"' && input.charAt(j) !== "'") return; e && $('~'); if (str = $(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/)) { return new(tree.Quoted)(str[0], str[1] || str[2], e); } }, // // A catch-all word, such as: // // black border-collapse // keyword: function () { var k; if (k = $(/^[_A-Za-z-][_A-Za-z0-9-]*/)) { if (tree.colors.hasOwnProperty(k)) { // detect named color return new(tree.Color)(tree.colors[k].slice(1)); } else { return new(tree.Keyword)(k); } } }, // // A function call // // rgb(255, 0, 255) // // We also try to catch IE's `alpha()`, but let the `alpha` parser // deal with the details. // // The arguments are parsed with the `entities.arguments` parser. // call: function () { var name, args, index = i; if (! (name = /^([\w-]+|%|progid:[\w\.]+)\(/.exec(chunks[j]))) return; name = name[1].toLowerCase(); if (name === 'url') { return null } else { i += name.length } if (name === 'alpha') { return $(this.alpha) } $('('); // Parse the '(' and consume whitespace. args = $(this.entities.arguments); if (! $(')')) return; if (name) { return new(tree.Call)(name, args, index, env.filename) } }, arguments: function () { var args = [], arg; while (arg = $(this.entities.assignment) || $(this.expression)) { args.push(arg); if (! $(',')) { break } } return args; }, literal: function () { return $(this.entities.dimension) || $(this.entities.color) || $(this.entities.quoted); }, // Assignments are argument entities for calls. // They are present in ie filter properties as shown below. // // filter: progid:DXImageTransform.Microsoft.Alpha( *opacity=50* ) // assignment: function () { var key, value; if ((key = $(/^\w+(?=\s?=)/i)) && $('=') && (value = $(this.entity))) { return new(tree.Assignment)(key, value); } }, // // Parse url() tokens // // We use a specific rule for urls, because they don't really behave like // standard function calls. The difference is that the argument doesn't have // to be enclosed within a string, so it can't be parsed as an Expression. // url: function () { var value; if (input.charAt(i) !== 'u' || !$(/^url\(/)) return; value = $(this.entities.quoted) || $(this.entities.variable) || $(this.entities.dataURI) || $(/^[-\w%@$\/.&=:;#+?~]+/) || ""; expect(')'); return new(tree.URL)((value.value || value.data || value instanceof tree.Variable) ? value : new(tree.Anonymous)(value), imports.paths); }, dataURI: function () { var obj; if ($(/^data:/)) { obj = {}; obj.mime = $(/^[^\/]+\/[^,;)]+/) || ''; obj.charset = $(/^;\s*charset=[^,;)]+/) || ''; obj.base64 = $(/^;\s*base64/) || ''; obj.data = $(/^,\s*[^)]+/); if (obj.data) { return obj } } }, // // A Variable entity, such as `@fink`, in // // width: @fink + 2px // // We use a different parser for variable definitions, // see `parsers.variable`. // variable: function () { var name, index = i; if (input.charAt(i) === '@' && (name = $(/^@@?[\w-]+/))) { return new(tree.Variable)(name, index, env.filename); } }, // // A Hexadecimal color // // #4F3C2F // // `rgb` and `hsl` colors are parsed through the `entities.call` parser. // color: function () { var rgb; if (input.charAt(i) === '#' && (rgb = $(/^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})/))) { return new(tree.Color)(rgb[1]); } }, // // A Dimension, that is, a number and a unit // // 0.5em 95% // dimension: function () { var value, c = input.charCodeAt(i); if ((c > 57 || c < 45) || c === 47) return; if (value = $(/^(-?\d*\.?\d+)(px|%|em|rem|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn)?/)) { return new(tree.Dimension)(value[1], value[2]); } }, // // JavaScript code to be evaluated // // `window.location.href` // javascript: function () { var str, j = i, e; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '`') { return } e && $('~'); if (str = $(/^`([^`]*)`/)) { return new(tree.JavaScript)(str[1], i, e); } } }, // // The variable part of a variable definition. Used in the `rule` parser // // @fink: // variable: function () { var name; if (input.charAt(i) === '@' && (name = $(/^(@[\w-]+)\s*:/))) { return name[1] } }, // // A font size/line-height shorthand // // small/12px // // We need to peek first, or we'll match on keywords and dimensions // shorthand: function () { var a, b; if (! peek(/^[@\w.%-]+\/[@\w.-]+/)) return; if ((a = $(this.entity)) && $('/') && (b = $(this.entity))) { return new(tree.Shorthand)(a, b); } }, // // Mixins // mixin: { // // A Mixin call, with an optional argument list // // #mixins > .square(#fff); // .rounded(4px, black); // .button; // // The `while` loop is there because mixins can be // namespaced, but we only support the child and descendant // selector for now. // call: function () { var elements = [], e, c, args, index = i, s = input.charAt(i), important = false; if (s !== '.' && s !== '#') { return } while (e = $(/^[#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/)) { elements.push(new(tree.Element)(c, e, i)); c = $('>'); } $('(') && (args = $(this.entities.arguments)) && $(')'); if ($(this.important)) { important = true; } if (elements.length > 0 && ($(';') || peek('}'))) { return new(tree.mixin.Call)(elements, args || [], index, env.filename, important); } }, // // A Mixin definition, with a list of parameters // // .rounded (@radius: 2px, @color) { // ... // } // // Until we have a finer grained state-machine, we have to // do a look-ahead, to make sure we don't have a mixin call. // See the `rule` function for more information. // // We start by matching `.rounded (`, and then proceed on to // the argument list, which has optional default values. // We store the parameters in `params`, with a `value` key, // if there is a value, such as in the case of `@radius`. // // Once we've got our params list, and a closing `)`, we parse // the `{...}` block. // definition: function () { var name, params = [], match, ruleset, param, value, cond, variadic = false; if ((input.charAt(i) !== '.' && input.charAt(i) !== '#') || peek(/^[^{]*(;|})/)) return; save(); if (match = $(/^([#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+)\s*\(/)) { name = match[1]; do { if (input.charAt(i) === '.' && $(/^\.{3}/)) { variadic = true; break; } else if (param = $(this.entities.variable) || $(this.entities.literal) || $(this.entities.keyword)) { // Variable if (param instanceof tree.Variable) { if ($(':')) { value = expect(this.expression, 'expected expression'); params.push({ name: param.name, value: value }); } else if ($(/^\.{3}/)) { params.push({ name: param.name, variadic: true }); variadic = true; break; } else { params.push({ name: param.name }); } } else { params.push({ value: param }); } } else { break; } } while ($(',')) expect(')'); if ($(/^when/)) { // Guard cond = expect(this.conditions, 'expected condition'); } ruleset = $(this.block); if (ruleset) { return new(tree.mixin.Definition)(name, params, ruleset, cond, variadic); } else { restore(); } } } }, // // Entities are the smallest recognized token, // and can be found inside a rule's value. // entity: function () { return $(this.entities.literal) || $(this.entities.variable) || $(this.entities.url) || $(this.entities.call) || $(this.entities.keyword) || $(this.entities.javascript) || $(this.comment); }, // // A Rule terminator. Note that we use `peek()` to check for '}', // because the `block` rule will be expecting it, but we still need to make sure // it's there, if ';' was ommitted. // end: function () { return $(';') || peek('}'); }, // // IE's alpha function // // alpha(opacity=88) // alpha: function () { var value; if (! $(/^\(opacity=/i)) return; if (value = $(/^\d+/) || $(this.entities.variable)) { expect(')'); return new(tree.Alpha)(value); } }, // // A Selector Element // // div // + h1 // #socks // input[type="text"] // // Elements are the building blocks for Selectors, // they are made out of a `Combinator` (see combinator rule), // and an element name, such as a tag a class, or `*`. // element: function () { var e, t, c, v; c = $(this.combinator); e = $(/^(?:\d+\.\d+|\d+)%/) || $(/^(?:[.#]?|:*)(?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/) || $('*') || $(this.attribute) || $(/^\([^)@]+\)/); if (! e) { $('(') && (v = $(this.entities.variable)) && $(')') && (e = new(tree.Paren)(v)); } if (e) { return new(tree.Element)(c, e, i) } if (c.value && c.value.charAt(0) === '&') { return new(tree.Element)(c, null, i); } }, // // Combinators combine elements together, in a Selector. // // Because our parser isn't white-space sensitive, special care // has to be taken, when parsing the descendant combinator, ` `, // as it's an empty space. We have to check the previous character // in the input, to see if it's a ` ` character. More info on how // we deal with this in *combinator.js*. // combinator: function () { var match, c = input.charAt(i); if (c === '>' || c === '+' || c === '~') { i++; while (input.charAt(i) === ' ') { i++ } return new(tree.Combinator)(c); } else if (c === '&') { match = '&'; i++; if(input.charAt(i) === ' ') { match = '& '; } while (input.charAt(i) === ' ') { i++ } return new(tree.Combinator)(match); } else if (input.charAt(i - 1) === ' ') { return new(tree.Combinator)(" "); } else { return new(tree.Combinator)(null); } }, // // A CSS Selector // // .class > div + h1 // li a:hover // // Selectors are made out of one or more Elements, see above. // selector: function () { var sel, e, elements = [], c, match; if ($('(')) { sel = $(this.entity); expect(')'); return new(tree.Selector)([new(tree.Element)('', sel, i)]); } while (e = $(this.element)) { c = input.charAt(i); elements.push(e) if (c === '{' || c === '}' || c === ';' || c === ',') { break } } if (elements.length > 0) { return new(tree.Selector)(elements) } }, tag: function () { return $(/^[a-zA-Z][a-zA-Z-]*[0-9]?/) || $('*'); }, attribute: function () { var attr = '', key, val, op; if (! $('[')) return; if (key = $(/^[a-zA-Z-]+/) || $(this.entities.quoted)) { if ((op = $(/^[|~*$^]?=/)) && (val = $(this.entities.quoted) || $(/^[\w-]+/))) { attr = [key, op, val.toCSS ? val.toCSS() : val].join(''); } else { attr = key } } if (! $(']')) return; if (attr) { return "[" + attr + "]" } }, // // The `block` rule is used by `ruleset` and `mixin.definition`. // It's a wrapper around the `primary` rule, with added `{}`. // block: function () { var content; if ($('{') && (content = $(this.primary)) && $('}')) { return content; } }, // // div, .class, body > p {...} // ruleset: function () { var selectors = [], s, rules, match; save(); while (s = $(this.selector)) { selectors.push(s); $(this.comment); if (! $(',')) { break } $(this.comment); } if (selectors.length > 0 && (rules = $(this.block))) { return new(tree.Ruleset)(selectors, rules, env.strictImports); } else { // Backtrack furthest = i; restore(); } }, rule: function () { var name, value, c = input.charAt(i), important, match; save(); if (c === '.' || c === '#' || c === '&') { return } if (name = $(this.variable) || $(this.property)) { if ((name.charAt(0) != '@') && (match = /^([^@+\/'"*`(;{}-]*);/.exec(chunks[j]))) { i += match[0].length - 1; value = new(tree.Anonymous)(match[1]); } else if (name === "font") { value = $(this.font); } else { value = $(this.value); } important = $(this.important); if (value && $(this.end)) { return new(tree.Rule)(name, value, important, memo); } else { furthest = i; restore(); } } }, // // An @import directive // // @import "lib"; // // Depending on our environemnt, importing is done differently: // In the browser, it's an XHR request, in Node, it would be a // file-system operation. The function used for importing is // stored in `import`, which we pass to the Import constructor. // "import": function () { var path, features, index = i; if ($(/^@import\s+/) && (path = $(this.entities.quoted) || $(this.entities.url))) { features = $(this.mediaFeatures); if ($(';')) { return new(tree.Import)(path, imports, features, index); } } }, mediaFeature: function () { var e, p, nodes = []; do { if (e = $(this.entities.keyword)) { nodes.push(e); } else if ($('(')) { p = $(this.property); e = $(this.entity); if ($(')')) { if (p && e) { nodes.push(new(tree.Paren)(new(tree.Rule)(p, e, null, i, true))); } else if (e) { nodes.push(new(tree.Paren)(e)); } else { return null; } } else { return null } } } while (e); if (nodes.length > 0) { return new(tree.Expression)(nodes); } }, mediaFeatures: function () { var e, features = []; do { if (e = $(this.mediaFeature)) { features.push(e); if (! $(',')) { break } } else if (e = $(this.entities.variable)) { features.push(e); if (! $(',')) { break } } } while (e); return features.length > 0 ? features : null; }, media: function () { var features, rules; if ($(/^@media/)) { features = $(this.mediaFeatures); if (rules = $(this.block)) { return new(tree.Media)(rules, features); } } }, // // A CSS Directive // // @charset "utf-8"; // directive: function () { var name, value, rules, types, e, nodes; if (input.charAt(i) !== '@') return; if (value = $(this['import']) || $(this.media)) { return value; } else if (name = $(/^@page|@keyframes/) || $(/^@(?:-webkit-|-moz-|-o-|-ms-)[a-z0-9-]+/)) { types = ($(/^[^{]+/) || '').trim(); if (rules = $(this.block)) { return new(tree.Directive)(name + " " + types, rules); } } else if (name = $(/^@[-a-z]+/)) { if (name === '@font-face') { if (rules = $(this.block)) { return new(tree.Directive)(name, rules); } } else if ((value = $(this.entity)) && $(';')) { return new(tree.Directive)(name, value); } } }, font: function () { var value = [], expression = [], weight, shorthand, font, e; while (e = $(this.shorthand) || $(this.entity)) { expression.push(e); } value.push(new(tree.Expression)(expression)); if ($(',')) { while (e = $(this.expression)) { value.push(e); if (! $(',')) { break } } } return new(tree.Value)(value); }, // // A Value is a comma-delimited list of Expressions // // font-family: Baskerville, Georgia, serif; // // In a Rule, a Value represents everything after the `:`, // and before the `;`. // value: function () { var e, expressions = [], important; while (e = $(this.expression)) { expressions.push(e); if (! $(',')) { break } } if (expressions.length > 0) { return new(tree.Value)(expressions); } }, important: function () { if (input.charAt(i) === '!') { return $(/^! *important/); } }, sub: function () { var e; if ($('(') && (e = $(this.expression)) && $(')')) { return e; } }, multiplication: function () { var m, a, op, operation; if (m = $(this.operand)) { while (!peek(/^\/\*/) && (op = ($('/') || $('*'))) && (a = $(this.operand))) { operation = new(tree.Operation)(op, [operation || m, a]); } return operation || m; } }, addition: function () { var m, a, op, operation; if (m = $(this.multiplication)) { while ((op = $(/^[-+]\s+/) || (input.charAt(i - 1) != ' ' && ($('+') || $('-')))) && (a = $(this.multiplication))) { operation = new(tree.Operation)(op, [operation || m, a]); } return operation || m; } }, conditions: function () { var a, b, index = i, condition; if (a = $(this.condition)) { while ($(',') && (b = $(this.condition))) { condition = new(tree.Condition)('or', condition || a, b, index); } return condition || a; } }, condition: function () { var a, b, c, op, index = i, negate = false; if ($(/^not/)) { negate = true } expect('('); if (a = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) { if (op = $(/^(?:>=|=<|[<=>])/)) { if (b = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) { c = new(tree.Condition)(op, a, b, index, negate); } else { error('expected expression'); } } else { c = new(tree.Condition)('=', a, new(tree.Keyword)('true'), index, negate); } expect(')'); return $(/^and/) ? new(tree.Condition)('and', c, $(this.condition)) : c; } }, // // An operand is anything that can be part of an operation, // such as a Color, or a Variable // operand: function () { var negate, p = input.charAt(i + 1); if (input.charAt(i) === '-' && (p === '@' || p === '(')) { negate = $('-') } var o = $(this.sub) || $(this.entities.dimension) || $(this.entities.color) || $(this.entities.variable) || $(this.entities.call); return negate ? new(tree.Operation)('*', [new(tree.Dimension)(-1), o]) : o; }, // // Expressions either represent mathematical operations, // or white-space delimited Entities. // // 1px solid black // @var * 2 // expression: function () { var e, delim, entities = [], d; while (e = $(this.addition) || $(this.entity)) { entities.push(e); } if (entities.length > 0) { return new(tree.Expression)(entities); } }, property: function () { var name; if (name = $(/^(\*?-?[-a-z_0-9]+)\s*:/)) { return name[1]; } } } }; }; if (less.mode === 'browser' || less.mode === 'rhino') { // // Used by `@import` directives // less.Parser.importer = function (path, paths, callback, env) { if (!/^([a-z]+:)?\//.test(path) && paths.length > 0) { path = paths[0] + path; } // We pass `true` as 3rd argument, to force the reload of the import. // This is so we can get the syntax tree as opposed to just the CSS output, // as we need this to evaluate the current stylesheet. loadStyleSheet({ href: path, title: path, type: env.mime }, function (e) { if (e && typeof(env.errback) === "function") { env.errback.call(null, path, paths, callback, env); } else { callback.apply(null, arguments); } }, true); }; } (function (tree) { tree.functions = { rgb: function (r, g, b) { return this.rgba(r, g, b, 1.0); }, rgba: function (r, g, b, a) { var rgb = [r, g, b].map(function (c) { return number(c) }), a = number(a); return new(tree.Color)(rgb, a); }, hsl: function (h, s, l) { return this.hsla(h, s, l, 1.0); }, hsla: function (h, s, l, a) { h = (number(h) % 360) / 360; s = number(s); l = number(l); a = number(a); var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s; var m1 = l * 2 - m2; return this.rgba(hue(h + 1/3) * 255, hue(h) * 255, hue(h - 1/3) * 255, a); function hue(h) { h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h); if (h * 6 < 1) return m1 + (m2 - m1) * h * 6; else if (h * 2 < 1) return m2; else if (h * 3 < 2) return m1 + (m2 - m1) * (2/3 - h) * 6; else return m1; } }, hue: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().h)); }, saturation: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().s * 100), '%'); }, lightness: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().l * 100), '%'); }, alpha: function (color) { return new(tree.Dimension)(color.toHSL().a); }, saturate: function (color, amount) { var hsl = color.toHSL(); hsl.s += amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, desaturate: function (color, amount) { var hsl = color.toHSL(); hsl.s -= amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, lighten: function (color, amount) { var hsl = color.toHSL(); hsl.l += amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, darken: function (color, amount) { var hsl = color.toHSL(); hsl.l -= amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, fadein: function (color, amount) { var hsl = color.toHSL(); hsl.a += amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, fadeout: function (color, amount) { var hsl = color.toHSL(); hsl.a -= amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, fade: function (color, amount) { var hsl = color.toHSL(); hsl.a = amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, spin: function (color, amount) { var hsl = color.toHSL(); var hue = (hsl.h + amount.value) % 360; hsl.h = hue < 0 ? 360 + hue : hue; return hsla(hsl); }, // // Copyright (c) 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein // http://sass-lang.com // mix: function (color1, color2, weight) { var p = weight.value / 100.0; var w = p * 2 - 1; var a = color1.toHSL().a - color2.toHSL().a; var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0; var w2 = 1 - w1; var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2, color1.rgb[1] * w1 + color2.rgb[1] * w2, color1.rgb[2] * w1 + color2.rgb[2] * w2]; var alpha = color1.alpha * p + color2.alpha * (1 - p); return new(tree.Color)(rgb, alpha); }, greyscale: function (color) { return this.desaturate(color, new(tree.Dimension)(100)); }, e: function (str) { return new(tree.Anonymous)(str instanceof tree.JavaScript ? str.evaluated : str); }, escape: function (str) { return new(tree.Anonymous)(encodeURI(str.value).replace(/=/g, "%3D").replace(/:/g, "%3A").replace(/#/g, "%23").replace(/;/g, "%3B").replace(/\(/g, "%28").replace(/\)/g, "%29")); }, '%': function (quoted /* arg, arg, ...*/) { var args = Array.prototype.slice.call(arguments, 1), str = quoted.value; for (var i = 0; i < args.length; i++) { str = str.replace(/%[sda]/i, function(token) { var value = token.match(/s/i) ? args[i].value : args[i].toCSS(); return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value; }); } str = str.replace(/%%/g, '%'); return new(tree.Quoted)('"' + str + '"', str); }, round: function (n) { return this._math('round', n); }, ceil: function (n) { return this._math('ceil', n); }, floor: function (n) { return this._math('floor', n); }, _math: function (fn, n) { if (n instanceof tree.Dimension) { return new(tree.Dimension)(Math[fn](number(n)), n.unit); } else if (typeof(n) === 'number') { return Math[fn](n); } else { throw { type: "Argument", message: "argument must be a number" }; } }, argb: function (color) { return new(tree.Anonymous)(color.toARGB()); }, percentage: function (n) { return new(tree.Dimension)(n.value * 100, '%'); }, color: function (n) { if (n instanceof tree.Quoted) { return new(tree.Color)(n.value.slice(1)); } else { throw { type: "Argument", message: "argument must be a string" }; } }, iscolor: function (n) { return this._isa(n, tree.Color); }, isnumber: function (n) { return this._isa(n, tree.Dimension); }, isstring: function (n) { return this._isa(n, tree.Quoted); }, iskeyword: function (n) { return this._isa(n, tree.Keyword); }, isurl: function (n) { return this._isa(n, tree.URL); }, ispixel: function (n) { return (n instanceof tree.Dimension) && n.unit === 'px' ? tree.True : tree.False; }, ispercentage: function (n) { return (n instanceof tree.Dimension) && n.unit === '%' ? tree.True : tree.False; }, isem: function (n) { return (n instanceof tree.Dimension) && n.unit === 'em' ? tree.True : tree.False; }, _isa: function (n, Type) { return (n instanceof Type) ? tree.True : tree.False; } }; function hsla(hsla) { return tree.functions.hsla(hsla.h, hsla.s, hsla.l, hsla.a); } function number(n) { if (n instanceof tree.Dimension) { return parseFloat(n.unit == '%' ? n.value / 100 : n.value); } else if (typeof(n) === 'number') { return n; } else { throw { error: "RuntimeError", message: "color functions take numbers as parameters" }; } } function clamp(val) { return Math.min(1, Math.max(0, val)); } })(require('./tree')); (function (tree) { tree.colors = { 'aliceblue':'#f0f8ff', 'antiquewhite':'#faebd7', 'aqua':'#00ffff', 'aquamarine':'#7fffd4', 'azure':'#f0ffff', 'beige':'#f5f5dc', 'bisque':'#ffe4c4', 'black':'#000000', 'blanchedalmond':'#ffebcd', 'blue':'#0000ff', 'blueviolet':'#8a2be2', 'brown':'#a52a2a', 'burlywood':'#deb887', 'cadetblue':'#5f9ea0', 'chartreuse':'#7fff00', 'chocolate':'#d2691e', 'coral':'#ff7f50', 'cornflowerblue':'#6495ed', 'cornsilk':'#fff8dc', 'crimson':'#dc143c', 'cyan':'#00ffff', 'darkblue':'#00008b', 'darkcyan':'#008b8b', 'darkgoldenrod':'#b8860b', 'darkgray':'#a9a9a9', 'darkgrey':'#a9a9a9', 'darkgreen':'#006400', 'darkkhaki':'#bdb76b', 'darkmagenta':'#8b008b', 'darkolivegreen':'#556b2f', 'darkorange':'#ff8c00', 'darkorchid':'#9932cc', 'darkred':'#8b0000', 'darksalmon':'#e9967a', 'darkseagreen':'#8fbc8f', 'darkslateblue':'#483d8b', 'darkslategray':'#2f4f4f', 'darkslategrey':'#2f4f4f', 'darkturquoise':'#00ced1', 'darkviolet':'#9400d3', 'deeppink':'#ff1493', 'deepskyblue':'#00bfff', 'dimgray':'#696969', 'dimgrey':'#696969', 'dodgerblue':'#1e90ff', 'firebrick':'#b22222', 'floralwhite':'#fffaf0', 'forestgreen':'#228b22', 'fuchsia':'#ff00ff', 'gainsboro':'#dcdcdc', 'ghostwhite':'#f8f8ff', 'gold':'#ffd700', 'goldenrod':'#daa520', 'gray':'#808080', 'grey':'#808080', 'green':'#008000', 'greenyellow':'#adff2f', 'honeydew':'#f0fff0', 'hotpink':'#ff69b4', 'indianred':'#cd5c5c', 'indigo':'#4b0082', 'ivory':'#fffff0', 'khaki':'#f0e68c', 'lavender':'#e6e6fa', 'lavenderblush':'#fff0f5', 'lawngreen':'#7cfc00', 'lemonchiffon':'#fffacd', 'lightblue':'#add8e6', 'lightcoral':'#f08080', 'lightcyan':'#e0ffff', 'lightgoldenrodyellow':'#fafad2', 'lightgray':'#d3d3d3', 'lightgrey':'#d3d3d3', 'lightgreen':'#90ee90', 'lightpink':'#ffb6c1', 'lightsalmon':'#ffa07a', 'lightseagreen':'#20b2aa', 'lightskyblue':'#87cefa', 'lightslategray':'#778899', 'lightslategrey':'#778899', 'lightsteelblue':'#b0c4de', 'lightyellow':'#ffffe0', 'lime':'#00ff00', 'limegreen':'#32cd32', 'linen':'#faf0e6', 'magenta':'#ff00ff', 'maroon':'#800000', 'mediumaquamarine':'#66cdaa', 'mediumblue':'#0000cd', 'mediumorchid':'#ba55d3', 'mediumpurple':'#9370d8', 'mediumseagreen':'#3cb371', 'mediumslateblue':'#7b68ee', 'mediumspringgreen':'#00fa9a', 'mediumturquoise':'#48d1cc', 'mediumvioletred':'#c71585', 'midnightblue':'#191970', 'mintcream':'#f5fffa', 'mistyrose':'#ffe4e1', 'moccasin':'#ffe4b5', 'navajowhite':'#ffdead', 'navy':'#000080', 'oldlace':'#fdf5e6', 'olive':'#808000', 'olivedrab':'#6b8e23', 'orange':'#ffa500', 'orangered':'#ff4500', 'orchid':'#da70d6', 'palegoldenrod':'#eee8aa', 'palegreen':'#98fb98', 'paleturquoise':'#afeeee', 'palevioletred':'#d87093', 'papayawhip':'#ffefd5', 'peachpuff':'#ffdab9', 'peru':'#cd853f', 'pink':'#ffc0cb', 'plum':'#dda0dd', 'powderblue':'#b0e0e6', 'purple':'#800080', 'red':'#ff0000', 'rosybrown':'#bc8f8f', 'royalblue':'#4169e1', 'saddlebrown':'#8b4513', 'salmon':'#fa8072', 'sandybrown':'#f4a460', 'seagreen':'#2e8b57', 'seashell':'#fff5ee', 'sienna':'#a0522d', 'silver':'#c0c0c0', 'skyblue':'#87ceeb', 'slateblue':'#6a5acd', 'slategray':'#708090', 'slategrey':'#708090', 'snow':'#fffafa', 'springgreen':'#00ff7f', 'steelblue':'#4682b4', 'tan':'#d2b48c', 'teal':'#008080', 'thistle':'#d8bfd8', 'tomato':'#ff6347', 'turquoise':'#40e0d0', 'violet':'#ee82ee', 'wheat':'#f5deb3', 'white':'#ffffff', 'whitesmoke':'#f5f5f5', 'yellow':'#ffff00', 'yellowgreen':'#9acd32' }; })(require('./tree')); (function (tree) { tree.Alpha = function (val) { this.value = val; }; tree.Alpha.prototype = { toCSS: function () { return "alpha(opacity=" + (this.value.toCSS ? this.value.toCSS() : this.value) + ")"; }, eval: function (env) { if (this.value.eval) { this.value = this.value.eval(env) } return this; } }; })(require('../tree')); (function (tree) { tree.Anonymous = function (string) { this.value = string.value || string; }; tree.Anonymous.prototype = { toCSS: function () { return this.value; }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.Assignment = function (key, val) { this.key = key; this.value = val; }; tree.Assignment.prototype = { toCSS: function () { return this.key + '=' + (this.value.toCSS ? this.value.toCSS() : this.value); }, eval: function (env) { if (this.value.eval) { this.value = this.value.eval(env) } return this; } }; })(require('../tree'));(function (tree) { // // A function call node. // tree.Call = function (name, args, index, filename) { this.name = name; this.args = args; this.index = index; this.filename = filename; }; tree.Call.prototype = { // // When evaluating a function call, // we either find the function in `tree.functions` [1], // in which case we call it, passing the evaluated arguments, // or we simply print it out as it appeared originally [2]. // // The *functions.js* file contains the built-in functions. // // The reason why we evaluate the arguments, is in the case where // we try to pass a variable to a function, like: `saturate(@color)`. // The function should receive the value, not the variable. // eval: function (env) { var args = this.args.map(function (a) { return a.eval(env) }); if (this.name in tree.functions) { // 1. try { return tree.functions[this.name].apply(tree.functions, args); } catch (e) { throw { type: e.type || "Runtime", message: "error evaluating function `" + this.name + "`" + (e.message ? ': ' + e.message : ''), index: this.index, filename: this.filename }; } } else { // 2. return new(tree.Anonymous)(this.name + "(" + args.map(function (a) { return a.toCSS() }).join(', ') + ")"); } }, toCSS: function (env) { return this.eval(env).toCSS(); } }; })(require('../tree')); (function (tree) { // // RGB Colors - #ff0014, #eee // tree.Color = function (rgb, a) { // // The end goal here, is to parse the arguments // into an integer triplet, such as `128, 255, 0` // // This facilitates operations and conversions. // if (Array.isArray(rgb)) { this.rgb = rgb; } else if (rgb.length == 6) { this.rgb = rgb.match(/.{2}/g).map(function (c) { return parseInt(c, 16); }); } else { this.rgb = rgb.split('').map(function (c) { return parseInt(c + c, 16); }); } this.alpha = typeof(a) === 'number' ? a : 1; }; tree.Color.prototype = { eval: function () { return this }, // // If we have some transparency, the only way to represent it // is via `rgba`. Otherwise, we use the hex representation, // which has better compatibility with older browsers. // Values are capped between `0` and `255`, rounded and zero-padded. // toCSS: function () { if (this.alpha < 1.0) { return "rgba(" + this.rgb.map(function (c) { return Math.round(c); }).concat(this.alpha).join(', ') + ")"; } else { return '#' + this.rgb.map(function (i) { i = Math.round(i); i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16); return i.length === 1 ? '0' + i : i; }).join(''); } }, // // Operations have to be done per-channel, if not, // channels will spill onto each other. Once we have // our result, in the form of an integer triplet, // we create a new Color node to hold the result. // operate: function (op, other) { var result = []; if (! (other instanceof tree.Color)) { other = other.toColor(); } for (var c = 0; c < 3; c++) { result[c] = tree.operate(op, this.rgb[c], other.rgb[c]); } return new(tree.Color)(result, this.alpha + other.alpha); }, toHSL: function () { var r = this.rgb[0] / 255, g = this.rgb[1] / 255, b = this.rgb[2] / 255, a = this.alpha; var max = Math.max(r, g, b), min = Math.min(r, g, b); var h, s, l = (max + min) / 2, d = max - min; if (max === min) { h = s = 0; } else { s = l > 0.5 ? d / (2 - max - min) : d / (max + min); switch (max) { case r: h = (g - b) / d + (g < b ? 6 : 0); break; case g: h = (b - r) / d + 2; break; case b: h = (r - g) / d + 4; break; } h /= 6; } return { h: h * 360, s: s, l: l, a: a }; }, toARGB: function () { var argb = [Math.round(this.alpha * 255)].concat(this.rgb); return '#' + argb.map(function (i) { i = Math.round(i); i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16); return i.length === 1 ? '0' + i : i; }).join(''); } }; })(require('../tree')); (function (tree) { tree.Comment = function (value, silent) { this.value = value; this.silent = !!silent; }; tree.Comment.prototype = { toCSS: function (env) { return env.compress ? '' : this.value; }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.Condition = function (op, l, r, i, negate) { this.op = op.trim(); this.lvalue = l; this.rvalue = r; this.index = i; this.negate = negate; }; tree.Condition.prototype.eval = function (env) { var a = this.lvalue.eval(env), b = this.rvalue.eval(env); var i = this.index, result; var result = (function (op) { switch (op) { case 'and': return a && b; case 'or': return a || b; default: if (a.compare) { result = a.compare(b); } else if (b.compare) { result = b.compare(a); } else { throw { type: "Type", message: "Unable to perform comparison", index: i }; } switch (result) { case -1: return op === '<' || op === '=<'; case 0: return op === '=' || op === '>=' || op === '=<'; case 1: return op === '>' || op === '>='; } } })(this.op); return this.negate ? !result : result; }; })(require('../tree')); (function (tree) { // // A number with a unit // tree.Dimension = function (value, unit) { this.value = parseFloat(value); this.unit = unit || null; }; tree.Dimension.prototype = { eval: function () { return this }, toColor: function () { return new(tree.Color)([this.value, this.value, this.value]); }, toCSS: function () { var css = this.value + this.unit; return css; }, // In an operation between two Dimensions, // we default to the first Dimension's unit, // so `1px + 2em` will yield `3px`. // In the future, we could implement some unit // conversions such that `100cm + 10mm` would yield // `101cm`. operate: function (op, other) { return new(tree.Dimension) (tree.operate(op, this.value, other.value), this.unit || other.unit); }, // TODO: Perform unit conversion before comparing compare: function (other) { if (other instanceof tree.Dimension) { if (other.value > this.value) { return -1; } else if (other.value < this.value) { return 1; } else { return 0; } } else { return -1; } } }; })(require('../tree')); (function (tree) { tree.Directive = function (name, value, features) { this.name = name; if (Array.isArray(value)) { this.ruleset = new(tree.Ruleset)([], value); this.ruleset.allowImports = true; } else { this.value = value; } }; tree.Directive.prototype = { toCSS: function (ctx, env) { if (this.ruleset) { this.ruleset.root = true; return this.name + (env.compress ? '{' : ' {\n ') + this.ruleset.toCSS(ctx, env).trim().replace(/\n/g, '\n ') + (env.compress ? '}': '\n}\n'); } else { return this.name + ' ' + this.value.toCSS() + ';\n'; } }, eval: function (env) { env.frames.unshift(this); this.ruleset = this.ruleset && this.ruleset.eval(env); env.frames.shift(); return this; }, variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) }, find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) }, rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) } }; })(require('../tree')); (function (tree) { tree.Element = function (combinator, value, index) { this.combinator = combinator instanceof tree.Combinator ? combinator : new(tree.Combinator)(combinator); if (typeof(value) === 'string') { this.value = value.trim(); } else if (value) { this.value = value; } else { this.value = ""; } this.index = index; }; tree.Element.prototype.eval = function (env) { return new(tree.Element)(this.combinator, this.value.eval ? this.value.eval(env) : this.value, this.index); }; tree.Element.prototype.toCSS = function (env) { return this.combinator.toCSS(env || {}) + (this.value.toCSS ? this.value.toCSS(env) : this.value); }; tree.Combinator = function (value) { if (value === ' ') { this.value = ' '; } else if (value === '& ') { this.value = '& '; } else { this.value = value ? value.trim() : ""; } }; tree.Combinator.prototype.toCSS = function (env) { return { '' : '', ' ' : ' ', '&' : '', '& ' : ' ', ':' : ' :', '+' : env.compress ? '+' : ' + ', '~' : env.compress ? '~' : ' ~ ', '>' : env.compress ? '>' : ' > ' }[this.value]; }; })(require('../tree')); (function (tree) { tree.Expression = function (value) { this.value = value }; tree.Expression.prototype = { eval: function (env) { if (this.value.length > 1) { return new(tree.Expression)(this.value.map(function (e) { return e.eval(env); })); } else if (this.value.length === 1) { return this.value[0].eval(env); } else { return this; } }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS ? e.toCSS(env) : ''; }).join(' '); } }; })(require('../tree')); (function (tree) { // // CSS @import node // // The general strategy here is that we don't want to wait // for the parsing to be completed, before we start importing // the file. That's because in the context of a browser, // most of the time will be spent waiting for the server to respond. // // On creation, we push the import path to our import queue, though // `import,push`, we also pass it a callback, which it'll call once // the file has been fetched, and parsed. // tree.Import = function (path, imports, features, index) { var that = this; this.index = index; this._path = path; this.features = features && new(tree.Value)(features); // The '.less' extension is optional if (path instanceof tree.Quoted) { this.path = /\.(le?|c)ss(\?.*)?$/.test(path.value) ? path.value : path.value + '.less'; } else { this.path = path.value.value || path.value; } this.css = /css(\?.*)?$/.test(this.path); // Only pre-compile .less files if (! this.css) { imports.push(this.path, function (e, root) { if (e) { e.index = index } that.root = root || new(tree.Ruleset)([], []); }); } }; // // The actual import node doesn't return anything, when converted to CSS. // The reason is that it's used at the evaluation stage, so that the rules // it imports can be treated like any other rules. // // In `eval`, we make sure all Import nodes get evaluated, recursively, so // we end up with a flat structure, which can easily be imported in the parent // ruleset. // tree.Import.prototype = { toCSS: function (env) { var features = this.features ? ' ' + this.features.toCSS(env) : ''; if (this.css) { return "@import " + this._path.toCSS() + features + ';\n'; } else { return ""; } }, eval: function (env) { var ruleset, features = this.features && this.features.eval(env); if (this.css) { return this; } else { ruleset = new(tree.Ruleset)([], this.root.rules.slice(0)); for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.Import) { Array.prototype .splice .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env))); } } return this.features ? new(tree.Media)(ruleset.rules, this.features.value) : ruleset.rules; } } }; })(require('../tree')); (function (tree) { tree.JavaScript = function (string, index, escaped) { this.escaped = escaped; this.expression = string; this.index = index; }; tree.JavaScript.prototype = { eval: function (env) { var result, that = this, context = {}; var expression = this.expression.replace(/@\{([\w-]+)\}/g, function (_, name) { return tree.jsify(new(tree.Variable)('@' + name, that.index).eval(env)); }); try { expression = new(Function)('return (' + expression + ')'); } catch (e) { throw { message: "JavaScript evaluation error: `" + expression + "`" , index: this.index }; } for (var k in env.frames[0].variables()) { context[k.slice(1)] = { value: env.frames[0].variables()[k].value, toJS: function () { return this.value.eval(env).toCSS(); } }; } try { result = expression.call(context); } catch (e) { throw { message: "JavaScript evaluation error: '" + e.name + ': ' + e.message + "'" , index: this.index }; } if (typeof(result) === 'string') { return new(tree.Quoted)('"' + result + '"', result, this.escaped, this.index); } else if (Array.isArray(result)) { return new(tree.Anonymous)(result.join(', ')); } else { return new(tree.Anonymous)(result); } } }; })(require('../tree')); (function (tree) { tree.Keyword = function (value) { this.value = value }; tree.Keyword.prototype = { eval: function () { return this }, toCSS: function () { return this.value }, compare: function (other) { if (other instanceof tree.Keyword) { return other.value === this.value ? 0 : 1; } else { return -1; } } }; tree.True = new(tree.Keyword)('true'); tree.False = new(tree.Keyword)('false'); })(require('../tree')); (function (tree) { tree.Media = function (value, features) { var el = new(tree.Element)('&', null, 0), selectors = [new(tree.Selector)([el])]; this.features = new(tree.Value)(features); this.ruleset = new(tree.Ruleset)(selectors, value); this.ruleset.allowImports = true; }; tree.Media.prototype = { toCSS: function (ctx, env) { var features = this.features.toCSS(env); this.ruleset.root = (ctx.length === 0 || ctx[0].multiMedia); return '@media ' + features + (env.compress ? '{' : ' {\n ') + this.ruleset.toCSS(ctx, env).trim().replace(/\n/g, '\n ') + (env.compress ? '}': '\n}\n'); }, eval: function (env) { if (!env.mediaBlocks) { env.mediaBlocks = []; env.mediaPath = []; } var blockIndex = env.mediaBlocks.length; env.mediaPath.push(this); env.mediaBlocks.push(this); var media = new(tree.Media)([], []); media.features = this.features.eval(env); env.frames.unshift(this.ruleset); media.ruleset = this.ruleset.eval(env); env.frames.shift(); env.mediaBlocks[blockIndex] = media; env.mediaPath.pop(); return env.mediaPath.length === 0 ? media.evalTop(env) : media.evalNested(env) }, variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) }, find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) }, rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) }, evalTop: function (env) { var result = this; // Render all dependent Media blocks. if (env.mediaBlocks.length > 1) { var el = new(tree.Element)('&', null, 0); var selectors = [new(tree.Selector)([el])]; result = new(tree.Ruleset)(selectors, env.mediaBlocks); result.multiMedia = true; } delete env.mediaBlocks; delete env.mediaPath; return result; }, evalNested: function (env) { var i, value, path = env.mediaPath.concat([this]); // Extract the media-query conditions separated with `,` (OR). for (i = 0; i < path.length; i++) { value = path[i].features instanceof tree.Value ? path[i].features.value : path[i].features; path[i] = Array.isArray(value) ? value : [value]; } // Trace all permutations to generate the resulting media-query. // // (a, b and c) with nested (d, e) -> // a and d // a and e // b and c and d // b and c and e this.features = new(tree.Value)(this.permute(path).map(function (path) { path = path.map(function (fragment) { return fragment.toCSS ? fragment : new(tree.Anonymous)(fragment); }); for(i = path.length - 1; i > 0; i--) { path.splice(i, 0, new(tree.Anonymous)("and")); } return new(tree.Expression)(path); })); // Fake a tree-node that doesn't output anything. return new(tree.Ruleset)([], []); }, permute: function (arr) { if (arr.length === 0) { return []; } else if (arr.length === 1) { return arr[0]; } else { var result = []; var rest = this.permute(arr.slice(1)); for (var i = 0; i < rest.length; i++) { for (var j = 0; j < arr[0].length; j++) { result.push([arr[0][j]].concat(rest[i])); } } return result; } } }; })(require('../tree')); (function (tree) { tree.mixin = {}; tree.mixin.Call = function (elements, args, index, filename, important) { this.selector = new(tree.Selector)(elements); this.arguments = args; this.index = index; this.filename = filename; this.important = important; }; tree.mixin.Call.prototype = { eval: function (env) { var mixins, args, rules = [], match = false; for (var i = 0; i < env.frames.length; i++) { if ((mixins = env.frames[i].find(this.selector)).length > 0) { args = this.arguments && this.arguments.map(function (a) { return a.eval(env) }); for (var m = 0; m < mixins.length; m++) { if (mixins[m].match(args, env)) { try { Array.prototype.push.apply( rules, mixins[m].eval(env, this.arguments, this.important).rules); match = true; } catch (e) { throw { message: e.message, index: this.index, filename: this.filename, stack: e.stack }; } } } if (match) { return rules; } else { throw { type: 'Runtime', message: 'No matching definition was found for `' + this.selector.toCSS().trim() + '(' + this.arguments.map(function (a) { return a.toCSS(); }).join(', ') + ")`", index: this.index, filename: this.filename }; } } } throw { type: 'Name', message: this.selector.toCSS().trim() + " is undefined", index: this.index, filename: this.filename }; } }; tree.mixin.Definition = function (name, params, rules, condition, variadic) { this.name = name; this.selectors = [new(tree.Selector)([new(tree.Element)(null, name)])]; this.params = params; this.condition = condition; this.variadic = variadic; this.arity = params.length; this.rules = rules; this._lookups = {}; this.required = params.reduce(function (count, p) { if (!p.name || (p.name && !p.value)) { return count + 1 } else { return count } }, 0); this.parent = tree.Ruleset.prototype; this.frames = []; }; tree.mixin.Definition.prototype = { toCSS: function () { return "" }, variable: function (name) { return this.parent.variable.call(this, name) }, variables: function () { return this.parent.variables.call(this) }, find: function () { return this.parent.find.apply(this, arguments) }, rulesets: function () { return this.parent.rulesets.apply(this) }, evalParams: function (env, args) { var frame = new(tree.Ruleset)(null, []), varargs; for (var i = 0, val, name; i < this.params.length; i++) { if (name = this.params[i].name) { if (this.params[i].variadic && args) { varargs = []; for (var j = i; j < args.length; j++) { varargs.push(args[j].eval(env)); } frame.rules.unshift(new(tree.Rule)(name, new(tree.Expression)(varargs).eval(env))); } else if (val = (args && args[i]) || this.params[i].value) { frame.rules.unshift(new(tree.Rule)(name, val.eval(env))); } else { throw { type: 'Runtime', message: "wrong number of arguments for " + this.name + ' (' + args.length + ' for ' + this.arity + ')' }; } } } return frame; }, eval: function (env, args, important) { var frame = this.evalParams(env, args), context, _arguments = [], rules, start; for (var i = 0; i < Math.max(this.params.length, args && args.length); i++) { _arguments.push(args[i] || this.params[i].value); } frame.rules.unshift(new(tree.Rule)('@arguments', new(tree.Expression)(_arguments).eval(env))); rules = important ? this.rules.map(function (r) { return new(tree.Rule)(r.name, r.value, '!important', r.index); }) : this.rules.slice(0); return new(tree.Ruleset)(null, rules).eval({ frames: [this, frame].concat(this.frames, env.frames) }); }, match: function (args, env) { var argsLength = (args && args.length) || 0, len, frame; if (! this.variadic) { if (argsLength < this.required) { return false } if (argsLength > this.params.length) { return false } if ((this.required > 0) && (argsLength > this.params.length)) { return false } } if (this.condition && !this.condition.eval({ frames: [this.evalParams(env, args)].concat(env.frames) })) { return false } len = Math.min(argsLength, this.arity); for (var i = 0; i < len; i++) { if (!this.params[i].name) { if (args[i].eval(env).toCSS() != this.params[i].value.eval(env).toCSS()) { return false; } } } return true; } }; })(require('../tree')); (function (tree) { tree.Operation = function (op, operands) { this.op = op.trim(); this.operands = operands; }; tree.Operation.prototype.eval = function (env) { var a = this.operands[0].eval(env), b = this.operands[1].eval(env), temp; if (a instanceof tree.Dimension && b instanceof tree.Color) { if (this.op === '*' || this.op === '+') { temp = b, b = a, a = temp; } else { throw { name: "OperationError", message: "Can't substract or divide a color from a number" }; } } return a.operate(this.op, b); }; tree.operate = function (op, a, b) { switch (op) { case '+': return a + b; case '-': return a - b; case '*': return a * b; case '/': return a / b; } }; })(require('../tree')); (function (tree) { tree.Paren = function (node) { this.value = node; }; tree.Paren.prototype = { toCSS: function (env) { return '(' + this.value.toCSS(env) + ')'; }, eval: function (env) { return new(tree.Paren)(this.value.eval(env)); } }; })(require('../tree')); (function (tree) { tree.Quoted = function (str, content, escaped, i) { this.escaped = escaped; this.value = content || ''; this.quote = str.charAt(0); this.index = i; }; tree.Quoted.prototype = { toCSS: function () { if (this.escaped) { return this.value; } else { return this.quote + this.value + this.quote; } }, eval: function (env) { var that = this; var value = this.value.replace(/`([^`]+)`/g, function (_, exp) { return new(tree.JavaScript)(exp, that.index, true).eval(env).value; }).replace(/@\{([\w-]+)\}/g, function (_, name) { var v = new(tree.Variable)('@' + name, that.index).eval(env); return ('value' in v) ? v.value : v.toCSS(); }); return new(tree.Quoted)(this.quote + value + this.quote, value, this.escaped, this.index); } }; })(require('../tree')); (function (tree) { tree.Rule = function (name, value, important, index, inline) { this.name = name; this.value = (value instanceof tree.Value) ? value : new(tree.Value)([value]); this.important = important ? ' ' + important.trim() : ''; this.index = index; this.inline = inline || false; if (name.charAt(0) === '@') { this.variable = true; } else { this.variable = false } }; tree.Rule.prototype.toCSS = function (env) { if (this.variable) { return "" } else { return this.name + (env.compress ? ':' : ': ') + this.value.toCSS(env) + this.important + (this.inline ? "" : ";"); } }; tree.Rule.prototype.eval = function (context) { return new(tree.Rule)(this.name, this.value.eval(context), this.important, this.index, this.inline); }; tree.Shorthand = function (a, b) { this.a = a; this.b = b; }; tree.Shorthand.prototype = { toCSS: function (env) { return this.a.toCSS(env) + "/" + this.b.toCSS(env); }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.Ruleset = function (selectors, rules, strictImports) { this.selectors = selectors; this.rules = rules; this._lookups = {}; this.strictImports = strictImports; }; tree.Ruleset.prototype = { eval: function (env) { var selectors = this.selectors && this.selectors.map(function (s) { return s.eval(env) }); var ruleset = new(tree.Ruleset)(selectors, this.rules.slice(0), this.strictImports); ruleset.root = this.root; ruleset.allowImports = this.allowImports; // push the current ruleset to the frames stack env.frames.unshift(ruleset); // Evaluate imports if (ruleset.root || ruleset.allowImports || !ruleset.strictImports) { for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.Import) { Array.prototype.splice .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env))); } } } // Store the frames around mixin definitions, // so they can be evaluated like closures when the time comes. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Definition) { ruleset.rules[i].frames = env.frames.slice(0); } } // Evaluate mixin calls. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Call) { Array.prototype.splice .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env))); } } // Evaluate everything else for (var i = 0, rule; i < ruleset.rules.length; i++) { rule = ruleset.rules[i]; if (! (rule instanceof tree.mixin.Definition)) { ruleset.rules[i] = rule.eval ? rule.eval(env) : rule; } } // Pop the stack env.frames.shift(); return ruleset; }, match: function (args) { return !args || args.length === 0; }, variables: function () { if (this._variables) { return this._variables } else { return this._variables = this.rules.reduce(function (hash, r) { if (r instanceof tree.Rule && r.variable === true) { hash[r.name] = r; } return hash; }, {}); } }, variable: function (name) { return this.variables()[name]; }, rulesets: function () { if (this._rulesets) { return this._rulesets } else { return this._rulesets = this.rules.filter(function (r) { return (r instanceof tree.Ruleset) || (r instanceof tree.mixin.Definition); }); } }, find: function (selector, self) { self = self || this; var rules = [], rule, match, key = selector.toCSS(); if (key in this._lookups) { return this._lookups[key] } this.rulesets().forEach(function (rule) { if (rule !== self) { for (var j = 0; j < rule.selectors.length; j++) { if (match = selector.match(rule.selectors[j])) { if (selector.elements.length > rule.selectors[j].elements.length) { Array.prototype.push.apply(rules, rule.find( new(tree.Selector)(selector.elements.slice(1)), self)); } else { rules.push(rule); } break; } } } }); return this._lookups[key] = rules; }, // // Entry point for code generation // // `context` holds an array of arrays. // toCSS: function (context, env) { var css = [], // The CSS output rules = [], // node.Rule instances rulesets = [], // node.Ruleset instances paths = [], // Current selectors selector, // The fully rendered selector rule; if (! this.root) { if (context.length === 0) { paths = this.selectors.map(function (s) { return [s] }); } else { this.joinSelectors(paths, context, this.selectors); } } // Compile rules and rulesets for (var i = 0; i < this.rules.length; i++) { rule = this.rules[i]; if (rule.rules || (rule instanceof tree.Directive) || (rule instanceof tree.Media)) { rulesets.push(rule.toCSS(paths, env)); } else if (rule instanceof tree.Comment) { if (!rule.silent) { if (this.root) { rulesets.push(rule.toCSS(env)); } else { rules.push(rule.toCSS(env)); } } } else { if (rule.toCSS && !rule.variable) { rules.push(rule.toCSS(env)); } else if (rule.value && !rule.variable) { rules.push(rule.value.toString()); } } } rulesets = rulesets.join(''); // If this is the root node, we don't render // a selector, or {}. // Otherwise, only output if this ruleset has rules. if (this.root) { css.push(rules.join(env.compress ? '' : '\n')); } else { if (rules.length > 0) { selector = paths.map(function (p) { return p.map(function (s) { return s.toCSS(env); }).join('').trim(); }).join( env.compress ? ',' : ',\n'); css.push(selector, (env.compress ? '{' : ' {\n ') + rules.join(env.compress ? '' : '\n ') + (env.compress ? '}' : '\n}\n')); } } css.push(rulesets); return css.join('') + (env.compress ? '\n' : ''); }, joinSelectors: function (paths, context, selectors) { for (var s = 0; s < selectors.length; s++) { this.joinSelector(paths, context, selectors[s]); } }, joinSelector: function (paths, context, selector) { var before = [], after = [], beforeElements = [], afterElements = [], hasParentSelector = false, el; for (var i = 0; i < selector.elements.length; i++) { el = selector.elements[i]; if (el.combinator.value.charAt(0) === '&') { hasParentSelector = true; } if (hasParentSelector) afterElements.push(el); else beforeElements.push(el); } if (! hasParentSelector) { afterElements = beforeElements; beforeElements = []; } if (beforeElements.length > 0) { before.push(new(tree.Selector)(beforeElements)); } if (afterElements.length > 0) { after.push(new(tree.Selector)(afterElements)); } for (var c = 0; c < context.length; c++) { paths.push(before.concat(context[c]).concat(after)); } } }; })(require('../tree')); (function (tree) { tree.Selector = function (elements) { this.elements = elements; if (this.elements[0].combinator.value === "") { this.elements[0].combinator.value = ' '; } }; tree.Selector.prototype.match = function (other) { var len = this.elements.length, olen = other.elements.length, max = Math.min(len, olen); if (len < olen) { return false; } else { for (var i = 0; i < max; i++) { if (this.elements[i].value !== other.elements[i].value) { return false; } } } return true; }; tree.Selector.prototype.eval = function (env) { return new(tree.Selector)(this.elements.map(function (e) { return e.eval(env); })); }; tree.Selector.prototype.toCSS = function (env) { if (this._css) { return this._css } return this._css = this.elements.map(function (e) { if (typeof(e) === 'string') { return ' ' + e.trim(); } else { return e.toCSS(env); } }).join(''); }; })(require('../tree')); (function (tree) { tree.URL = function (val, paths) { if (val.data) { this.attrs = val; } else { // Add the base path if the URL is relative and we are in the browser if (typeof(window) !== 'undefined' && !/^(?:https?:\/\/|file:\/\/|data:|\/)/.test(val.value) && paths.length > 0) { val.value = paths[0] + (val.value.charAt(0) === '/' ? val.value.slice(1) : val.value); } this.value = val; this.paths = paths; } }; tree.URL.prototype = { toCSS: function () { return "url(" + (this.attrs ? 'data:' + this.attrs.mime + this.attrs.charset + this.attrs.base64 + this.attrs.data : this.value.toCSS()) + ")"; }, eval: function (ctx) { return this.attrs ? this : new(tree.URL)(this.value.eval(ctx), this.paths); } }; })(require('../tree')); (function (tree) { tree.Value = function (value) { this.value = value; this.is = 'value'; }; tree.Value.prototype = { eval: function (env) { if (this.value.length === 1) { return this.value[0].eval(env); } else { return new(tree.Value)(this.value.map(function (v) { return v.eval(env); })); } }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS(env); }).join(env.compress ? ',' : ', '); } }; })(require('../tree')); (function (tree) { tree.Variable = function (name, index, file) { this.name = name, this.index = index, this.file = file }; tree.Variable.prototype = { eval: function (env) { var variable, v, name = this.name; if (name.indexOf('@@') == 0) { name = '@' + new(tree.Variable)(name.slice(1)).eval(env).value; } if (variable = tree.find(env.frames, function (frame) { if (v = frame.variable(name)) { return v.value.eval(env); } })) { return variable } else { throw { type: 'Name', message: "variable " + name + " is undefined", filename: this.file, index: this.index }; } } }; })(require('../tree')); (function (tree) { tree.find = function (obj, fun) { for (var i = 0, r; i < obj.length; i++) { if (r = fun.call(obj, obj[i])) { return r } } return null; }; tree.jsify = function (obj) { if (Array.isArray(obj.value) && (obj.value.length > 1)) { return '[' + obj.value.map(function (v) { return v.toCSS(false) }).join(', ') + ']'; } else { return obj.toCSS(false); } }; })(require('./tree')); // // browser.js - client-side engine // var isFileProtocol = (location.protocol === 'file:' || location.protocol === 'chrome:' || location.protocol === 'chrome-extension:' || location.protocol === 'resource:'); less.env = less.env || (location.hostname == '127.0.0.1' || location.hostname == '0.0.0.0' || location.hostname == 'localhost' || location.port.length > 0 || isFileProtocol ? 'development' : 'production'); // Load styles asynchronously (default: false) // // This is set to `false` by default, so that the body // doesn't start loading before the stylesheets are parsed. // Setting this to `true` can result in flickering. // less.async = false; // Interval between watch polls less.poll = less.poll || (isFileProtocol ? 1000 : 1500); // // Watch mode // less.watch = function () { return this.watchMode = true }; less.unwatch = function () { return this.watchMode = false }; if (less.env === 'development') { less.optimization = 0; if (/!watch/.test(location.hash)) { less.watch(); } less.watchTimer = setInterval(function () { if (less.watchMode) { loadStyleSheets(function (e, root, _, sheet, env) { if (root) { createCSS(root.toCSS(), sheet, env.lastModified); } }); } }, less.poll); } else { less.optimization = 3; } var cache; try { cache = (typeof(window.localStorage) === 'undefined') ? null : window.localStorage; } catch (_) { cache = null; } // // Get all tags with the 'rel' attribute set to "stylesheet/less" // var links = document.getElementsByTagName('link'); var typePattern = /^text\/(x-)?less$/; less.sheets = []; for (var i = 0; i < links.length; i++) { if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) && (links[i].type.match(typePattern)))) { less.sheets.push(links[i]); } } less.refresh = function (reload) { var startTime, endTime; startTime = endTime = new(Date); loadStyleSheets(function (e, root, _, sheet, env) { if (env.local) { log("loading " + sheet.href + " from cache."); } else { log("parsed " + sheet.href + " successfully."); createCSS(root.toCSS(), sheet, env.lastModified); } log("css for " + sheet.href + " generated in " + (new(Date) - endTime) + 'ms'); (env.remaining === 0) && log("css generated in " + (new(Date) - startTime) + 'ms'); endTime = new(Date); }, reload); loadStyles(); }; less.refreshStyles = loadStyles; less.refresh(less.env === 'development'); function loadStyles() { var styles = document.getElementsByTagName('style'); for (var i = 0; i < styles.length; i++) { if (styles[i].type.match(typePattern)) { new(less.Parser)().parse(styles[i].innerHTML || '', function (e, tree) { var css = tree.toCSS(); var style = styles[i]; style.type = 'text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.innerHTML = css; } }); } } } function loadStyleSheets(callback, reload) { for (var i = 0; i < less.sheets.length; i++) { loadStyleSheet(less.sheets[i], callback, reload, less.sheets.length - (i + 1)); } } function loadStyleSheet(sheet, callback, reload, remaining) { var url = window.location.href.replace(/[#?].*$/, ''); var href = sheet.href.replace(/\?.*$/, ''); var css = cache && cache.getItem(href); var timestamp = cache && cache.getItem(href + ':timestamp'); var styles = { css: css, timestamp: timestamp }; // Stylesheets in IE don't always return the full path if (! /^(https?|file):/.test(href)) { if (href.charAt(0) == "/") { href = window.location.protocol + "//" + window.location.host + href; } else { href = url.slice(0, url.lastIndexOf('/') + 1) + href; } } var filename = href.match(/([^\/]+)$/)[1]; xhr(sheet.href, sheet.type, function (data, lastModified) { if (!reload && styles && lastModified && (new(Date)(lastModified).valueOf() === new(Date)(styles.timestamp).valueOf())) { // Use local copy createCSS(styles.css, sheet); callback(null, null, data, sheet, { local: true, remaining: remaining }); } else { // Use remote copy (re-parse) try { new(less.Parser)({ optimization: less.optimization, paths: [href.replace(/[\w\.-]+$/, '')], mime: sheet.type, filename: filename }).parse(data, function (e, root) { if (e) { return error(e, href) } try { callback(e, root, data, sheet, { local: false, lastModified: lastModified, remaining: remaining }); removeNode(document.getElementById('less-error-message:' + extractId(href))); } catch (e) { error(e, href); } }); } catch (e) { error(e, href); } } }, function (status, url) { throw new(Error)("Couldn't load " + url + " (" + status + ")"); }); } function extractId(href) { return href.replace(/^[a-z]+:\/\/?[^\/]+/, '' ) // Remove protocol & domain .replace(/^\//, '' ) // Remove root / .replace(/\?.*$/, '' ) // Remove query .replace(/\.[^\.\/]+$/, '' ) // Remove file extension .replace(/[^\.\w-]+/g, '-') // Replace illegal characters .replace(/\./g, ':'); // Replace dots with colons(for valid id) } function createCSS(styles, sheet, lastModified) { var css; // Strip the query-string var href = sheet.href ? sheet.href.replace(/\?.*$/, '') : ''; // If there is no title set, use the filename, minus the extension var id = 'less:' + (sheet.title || extractId(href)); // If the stylesheet doesn't exist, create a new node if ((css = document.getElementById(id)) === null) { css = document.createElement('style'); css.type = 'text/css'; css.media = sheet.media || 'screen'; css.id = id; document.getElementsByTagName('head')[0].appendChild(css); } if (css.styleSheet) { // IE try { css.styleSheet.cssText = styles; } catch (e) { throw new(Error)("Couldn't reassign styleSheet.cssText."); } } else { (function (node) { if (css.childNodes.length > 0) { if (css.firstChild.nodeValue !== node.nodeValue) { css.replaceChild(node, css.firstChild); } } else { css.appendChild(node); } })(document.createTextNode(styles)); } // Don't update the local store if the file wasn't modified if (lastModified && cache) { log('saving ' + href + ' to cache.'); cache.setItem(href, styles); cache.setItem(href + ':timestamp', lastModified); } } function xhr(url, type, callback, errback) { var xhr = getXMLHttpRequest(); var async = isFileProtocol ? false : less.async; if (typeof(xhr.overrideMimeType) === 'function') { xhr.overrideMimeType('text/css'); } xhr.open('GET', url, async); xhr.setRequestHeader('Accept', type || 'text/x-less, text/css; q=0.9, */*; q=0.5'); xhr.send(null); if (isFileProtocol) { if (xhr.status === 0 || (xhr.status >= 200 && xhr.status < 300)) { callback(xhr.responseText); } else { errback(xhr.status, url); } } else if (async) { xhr.onreadystatechange = function () { if (xhr.readyState == 4) { handleResponse(xhr, callback, errback); } }; } else { handleResponse(xhr, callback, errback); } function handleResponse(xhr, callback, errback) { if (xhr.status >= 200 && xhr.status < 300) { callback(xhr.responseText, xhr.getResponseHeader("Last-Modified")); } else if (typeof(errback) === 'function') { errback(xhr.status, url); } } } function getXMLHttpRequest() { if (window.XMLHttpRequest) { return new(XMLHttpRequest); } else { try { return new(ActiveXObject)("MSXML2.XMLHTTP.3.0"); } catch (e) { log("browser doesn't support AJAX."); return null; } } } function removeNode(node) { return node && node.parentNode.removeChild(node); } function log(str) { if (less.env == 'development' && typeof(console) !== "undefined") { console.log('less: ' + str) } } function error(e, href) { var id = 'less-error-message:' + extractId(href); var template = '
  • {content}
  • '; var elem = document.createElement('div'), timer, content, error = []; var filename = e.filename || href; elem.id = id; elem.className = "less-error-message"; content = '

    ' + (e.message || 'There is an error in your .less file') + '

    ' + '

    in ' + filename + " "; var errorline = function (e, i, classname) { if (e.extract[i]) { error.push(template.replace(/\{line\}/, parseInt(e.line) + (i - 1)) .replace(/\{class\}/, classname) .replace(/\{content\}/, e.extract[i])); } }; if (e.stack) { content += '
    ' + e.stack.split('\n').slice(1).join('
    '); } else if (e.extract) { errorline(e, 0, ''); errorline(e, 1, 'line'); errorline(e, 2, ''); content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':

    ' + '
      ' + error.join('') + '
    '; } elem.innerHTML = content; // CSS for error messages createCSS([ '.less-error-message ul, .less-error-message li {', 'list-style-type: none;', 'margin-right: 15px;', 'padding: 4px 0;', 'margin: 0;', '}', '.less-error-message label {', 'font-size: 12px;', 'margin-right: 15px;', 'padding: 4px 0;', 'color: #cc7777;', '}', '.less-error-message pre {', 'color: #dd6666;', 'padding: 4px 0;', 'margin: 0;', 'display: inline-block;', '}', '.less-error-message pre.line {', 'color: #ff0000;', '}', '.less-error-message h3 {', 'font-size: 20px;', 'font-weight: bold;', 'padding: 15px 0 5px 0;', 'margin: 0;', '}', '.less-error-message a {', 'color: #10a', '}', '.less-error-message .error {', 'color: red;', 'font-weight: bold;', 'padding-bottom: 2px;', 'border-bottom: 1px dashed red;', '}' ].join('\n'), { title: 'error-message' }); elem.style.cssText = [ "font-family: Arial, sans-serif", "border: 1px solid #e00", "background-color: #eee", "border-radius: 5px", "-webkit-border-radius: 5px", "-moz-border-radius: 5px", "color: #e00", "padding: 15px", "margin-bottom: 15px" ].join(';'); if (less.env == 'development') { timer = setInterval(function () { if (document.body) { if (document.getElementById(id)) { document.body.replaceChild(elem, document.getElementById(id)); } else { document.body.insertBefore(elem, document.body.firstChild); } clearInterval(timer); } }, 10); } } })(window); less.js-1.4.2/dist/less-1.3.0.min.js000066400000000000000000001337161217256642200166070ustar00rootroot00000000000000// // LESS - Leaner CSS v1.3.0 // http://lesscss.org // // Copyright (c) 2009-2011, Alexis Sellier // Licensed under the Apache 2.0 License. // (function(a,b){function c(b){return a.less[b.split("/")[1]]}function l(){var a=document.getElementsByTagName("style");for(var b=0;b0?d.firstChild.nodeValue!==a.nodeValue&&d.replaceChild(a,d.firstChild):d.appendChild(a)})(document.createTextNode(a));c&&g&&(t("saving "+e+" to cache."),g.setItem(e,a),g.setItem(e+":timestamp",c))}function q(a,b,c,e){function i(b,c,d){b.status>=200&&b.status<300?c(b.responseText,b.getResponseHeader("Last-Modified")):typeof d=="function"&&d(b.status,a)}var g=r(),h=f?!1:d.async;typeof g.overrideMimeType=="function"&&g.overrideMimeType("text/css"),g.open("GET",a,h),g.setRequestHeader("Accept",b||"text/x-less, text/css; q=0.9, */*; q=0.5"),g.send(null),f?g.status===0||g.status>=200&&g.status<300?c(g.responseText):e(g.status,a):h?g.onreadystatechange=function(){g.readyState==4&&i(g,c,e)}:i(g,c,e)}function r(){if(a.XMLHttpRequest)return new XMLHttpRequest;try{return new ActiveXObject("MSXML2.XMLHTTP.3.0")}catch(b){return t("browser doesn't support AJAX."),null}}function s(a){return a&&a.parentNode.removeChild(a)}function t(a){d.env=="development"&&typeof console!="undefined"&&console.log("less: "+a)}function u(a,b){var c="less-error-message:"+o(b),e='
  • {content}
  • ',f=document.createElement("div"),g,h,i=[],j=a.filename||b;f.id=c,f.className="less-error-message",h="

    "+(a.message||"There is an error in your .less file")+"

    "+'

    in '+j+" ";var k=function(a,b,c){a.extract[b]&&i.push(e.replace(/\{line\}/,parseInt(a.line)+(b-1)).replace(/\{class\}/,c).replace(/\{content\}/,a.extract[b]))};a.stack?h+="
    "+a.stack.split("\n").slice(1).join("
    "):a.extract&&(k(a,0,""),k(a,1,"line"),k(a,2,""),h+="on line "+a.line+", column "+(a.column+1)+":

    "+"
      "+i.join("")+"
    "),f.innerHTML=h,p([".less-error-message ul, .less-error-message li {","list-style-type: none;","margin-right: 15px;","padding: 4px 0;","margin: 0;","}",".less-error-message label {","font-size: 12px;","margin-right: 15px;","padding: 4px 0;","color: #cc7777;","}",".less-error-message pre {","color: #dd6666;","padding: 4px 0;","margin: 0;","display: inline-block;","}",".less-error-message pre.line {","color: #ff0000;","}",".less-error-message h3 {","font-size: 20px;","font-weight: bold;","padding: 15px 0 5px 0;","margin: 0;","}",".less-error-message a {","color: #10a","}",".less-error-message .error {","color: red;","font-weight: bold;","padding-bottom: 2px;","border-bottom: 1px dashed red;","}"].join("\n"),{title:"error-message"}),f.style.cssText=["font-family: Arial, sans-serif","border: 1px solid #e00","background-color: #eee","border-radius: 5px","-webkit-border-radius: 5px","-moz-border-radius: 5px","color: #e00","padding: 15px","margin-bottom: 15px"].join(";"),d.env=="development"&&(g=setInterval(function(){document.body&&(document.getElementById(c)?document.body.replaceChild(f,document.getElementById(c)):document.body.insertBefore(f,document.body.firstChild),clearInterval(g))},10))}typeof define=="function"&&define.amd&&define("less",[],function(){return d}),Array.isArray||(Array.isArray=function(a){return Object.prototype.toString.call(a)==="[object Array]"||a instanceof Array}),Array.prototype.forEach||(Array.prototype.forEach=function(a,b){var c=this.length>>>0;for(var d=0;d>>0,c=new Array(b),d=arguments[1];for(var e=0;e>>0,c=0;if(b===0&&arguments.length===1)throw new TypeError;if(arguments.length>=2)var d=arguments[1];else do{if(c in this){d=this[c++];break}if(++c>=b)throw new TypeError}while(!0);for(;c=b)return-1;c<0&&(c+=b);for(;cl&&(k[g]=k[g].slice(f-l),l=f)}function t(a){var c,d,e,h,i,j,n,o;if(a instanceof Function)return a.call(m.parsers);if(typeof a=="string")c=b.charAt(f)===a?a:null,e=1,s();else{s();if(c=a.exec(k[g]))e=c[0].length;else return null}if(c){o=f+=e,j=f+k[g].length-e;while(f=0&&b.charAt(c)!=="\n";c--)d++;return{line:typeof a=="number"?(b.slice(0,a).match(/\n/g)||"").length:null,column:d}}function A(a,b){var c=y(a,b),d=z(a.index,c),e=d.line,f=d.column,g=c.split("\n");this.type=a.type||"Syntax",this.message=a.message,this.filename=a.filename||b.filename,this.index=a.index,this.line=typeof e=="number"?e+1:null,this.callLine=a.call&&z(a.call,c).line+1,this.callExtract=g[z(a.call,c).line],this.stack=a.stack,this.column=f,this.extract=[g[e-1],g[e],g[e+1]]}var b,f,g,h,i,j,k,l,m,n=this,o=function(){},p=this.imports={paths:a&&a.paths||[],queue:[],files:{},contents:{},mime:a&&a.mime,error:null,push:function(b,c){var e=this;this.queue.push(b),d.Parser.importer(b,this.paths,function(a,d,f){e.queue.splice(e.queue.indexOf(b),1),e.files[b]=d,e.contents[b]=f,a&&!e.error&&(e.error=a),c(a,d),e.queue.length===0&&o()},a)}};return this.env=a=a||{},this.optimization="optimization"in this.env?this.env.optimization:1,this.env.filename=this.env.filename||null,m={imports:p,parse:function(h,i){var n,p,q,r,s,u,v=[],w,x=null;f=g=l=j=0,b=h.replace(/\r\n/g,"\n"),k=function(c){var d=0,e=/[^"'`\{\}\/\(\)\\]+/g,f=/\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g,g=/"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'|`((?:[^`\\\r\n]|\\.)*)`/g,h=0,i,j=c[0],k;for(var l=0,m,n;l0&&(x=new A({index:l,type:"Parse",message:"missing closing `}`",filename:a.filename},a)),c.map(function(a){return a.join("")})}([[]]);if(x)return i(x);try{n=new e.Ruleset([],t(this.parsers.primary)),n.root=!0}catch(y){return i(new A(y,a))}n.toCSS=function(b){var f,g,h;return function(f,g){var h=[],i;f=f||{},typeof g=="object"&&!Array.isArray(g)&&(g=Object.keys(g).map(function(a){var b=g[a];return b instanceof e.Value||(b instanceof e.Expression||(b=new e.Expression([b])),b=new e.Value([b])),new e.Rule("@"+a,b,!1,0)}),h=[new e.Ruleset(null,g)]);try{var j=b.call(this,{frames:h}).toCSS([],{compress:f.compress||!1})}catch(k){throw new A(k,a)}if(i=m.imports.error)throw i instanceof A?i:new A(i,a);return f.yuicompress&&d.mode==="node"?c("./cssmin").compressor.cssmin(j):f.compress?j.replace(/(\s)+/g,"$1"):j}}(n.eval);if(f=0&&b.charAt(z)!=="\n";z--)B++;x={type:"Parse",message:"Syntax Error on line "+s,index:f,filename:a.filename,line:s,column:B,extract:[u[s-2],u[s-1],u[s]]}}this.imports.queue.length>0?o=function(){i(x,n)}:i(x,n)},parsers:{primary:function(){var a,b=[];while((a=t(this.mixin.definition)||t(this.rule)||t(this.ruleset)||t(this.mixin.call)||t(this.comment)||t(this.directive))||t(/^[\s\n]+/))a&&b.push(a);return b},comment:function(){var a;if(b.charAt(f)!=="/")return;if(b.charAt(f+1)==="/")return new e.Comment(t(/^\/\/.*/),!0);if(a=t(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/))return new e.Comment(a)},entities:{quoted:function(){var a,c=f,d;b.charAt(c)==="~"&&(c++,d=!0);if(b.charAt(c)!=='"'&&b.charAt(c)!=="'")return;d&&t("~");if(a=t(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/))return new e.Quoted(a[0],a[1]||a[2],d)},keyword:function(){var a;if(a=t(/^[_A-Za-z-][_A-Za-z0-9-]*/))return e.colors.hasOwnProperty(a)?new e.Color(e.colors[a].slice(1)):new e.Keyword(a)},call:function(){var b,c,d=f;if(!(b=/^([\w-]+|%|progid:[\w\.]+)\(/.exec(k[g])))return;b=b[1].toLowerCase();if(b==="url")return null;f+=b.length;if(b==="alpha")return t(this.alpha);t("("),c=t(this.entities.arguments);if(!t(")"))return;if(b)return new e.Call(b,c,d,a.filename)},arguments:function(){var a=[],b;while(b=t(this.entities.assignment)||t(this.expression)){a.push(b);if(!t(","))break}return a},literal:function(){return t(this.entities.dimension)||t(this.entities.color)||t(this.entities.quoted)},assignment:function(){var a,b;if((a=t(/^\w+(?=\s?=)/i))&&t("=")&&(b=t(this.entity)))return new e.Assignment(a,b)},url:function(){var a;if(b.charAt(f)!=="u"||!t(/^url\(/))return;return a=t(this.entities.quoted)||t(this.entities.variable)||t(this.entities.dataURI)||t(/^[-\w%@$\/.&=:;#+?~]+/)||"",u(")"),new e.URL(a.value||a.data||a instanceof e.Variable?a:new e.Anonymous(a),p.paths)},dataURI:function(){var a;if(t(/^data:/)){a={},a.mime=t(/^[^\/]+\/[^,;)]+/)||"",a.charset=t(/^;\s*charset=[^,;)]+/)||"",a.base64=t(/^;\s*base64/)||"",a.data=t(/^,\s*[^)]+/);if(a.data)return a}},variable:function(){var c,d=f;if(b.charAt(f)==="@"&&(c=t(/^@@?[\w-]+/)))return new e.Variable(c,d,a.filename)},color:function(){var a;if(b.charAt(f)==="#"&&(a=t(/^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})/)))return new e.Color(a[1])},dimension:function(){var a,c=b.charCodeAt(f);if(c>57||c<45||c===47)return;if(a=t(/^(-?\d*\.?\d+)(px|%|em|rem|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn)?/))return new e.Dimension(a[1],a[2])},javascript:function(){var a,c=f,d;b.charAt(c)==="~"&&(c++,d=!0);if(b.charAt(c)!=="`")return;d&&t("~");if(a=t(/^`([^`]*)`/))return new e.JavaScript(a[1],f,d)}},variable:function(){var a;if(b.charAt(f)==="@"&&(a=t(/^(@[\w-]+)\s*:/)))return a[1]},shorthand:function(){var a,b;if(!w(/^[@\w.%-]+\/[@\w.-]+/))return;if((a=t(this.entity))&&t("/")&&(b=t(this.entity)))return new e.Shorthand(a,b)},mixin:{call:function(){var c=[],d,g,h,i=f,j=b.charAt(f),k=!1;if(j!=="."&&j!=="#")return;while(d=t(/^[#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/))c.push(new e.Element(g,d,f)),g=t(">");t("(")&&(h=t(this.entities.arguments))&&t(")"),t(this.important)&&(k=!0);if(c.length>0&&(t(";")||w("}")))return new e.mixin.Call(c,h||[],i,a.filename,k)},definition:function(){var a,c=[],d,g,h,i,j,k=!1;if(b.charAt(f)!=="."&&b.charAt(f)!=="#"||w(/^[^{]*(;|})/))return;q();if(d=t(/^([#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+)\s*\(/)){a=d[1];do{if(b.charAt(f)==="."&&t(/^\.{3}/)){k=!0;break}if(!(h=t(this.entities.variable)||t(this.entities.literal)||t(this.entities.keyword)))break;if(h instanceof e.Variable)if(t(":"))i=u(this.expression,"expected expression"),c.push({name:h.name,value:i});else{if(t(/^\.{3}/)){c.push({name:h.name,variadic:!0}),k=!0;break}c.push({name:h.name})}else c.push({value:h})}while(t(","));u(")"),t(/^when/)&&(j=u(this.conditions,"expected condition")),g=t(this.block);if(g)return new e.mixin.Definition(a,c,g,j,k);r()}}},entity:function(){return t(this.entities.literal)||t(this.entities.variable)||t(this.entities.url)||t(this.entities.call)||t(this.entities.keyword)||t(this.entities.javascript)||t(this.comment)},end:function(){return t(";")||w("}")},alpha:function(){var a;if(!t(/^\(opacity=/i))return;if(a=t(/^\d+/)||t(this.entities.variable))return u(")"),new e.Alpha(a)},element:function(){var a,b,c,d;c=t(this.combinator),a=t(/^(?:\d+\.\d+|\d+)%/)||t(/^(?:[.#]?|:*)(?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/)||t("*")||t(this.attribute)||t(/^\([^)@]+\)/),a||t("(")&&(d=t(this.entities.variable))&&t(")")&&(a=new e.Paren(d));if(a)return new e.Element(c,a,f);if(c.value&&c.value.charAt(0)==="&")return new e.Element(c,null,f)},combinator:function(){var a,c=b.charAt(f);if(c===">"||c==="+"||c==="~"){f++;while(b.charAt(f)===" ")f++;return new e.Combinator(c)}if(c==="&"){a="&",f++,b.charAt(f)===" "&&(a="& ");while(b.charAt(f)===" ")f++;return new e.Combinator(a)}return b.charAt(f-1)===" "?new e.Combinator(" "):new e.Combinator(null)},selector:function(){var a,c,d=[],g,h;if(t("("))return a=t(this.entity),u(")"),new e.Selector([new e.Element("",a,f)]);while(c=t(this.element)){g=b.charAt(f),d.push(c);if(g==="{"||g==="}"||g===";"||g===",")break}if(d.length>0)return new e.Selector(d)},tag:function(){return t(/^[a-zA-Z][a-zA-Z-]*[0-9]?/)||t("*")},attribute:function(){var a="",b,c,d;if(!t("["))return;if(b=t(/^[a-zA-Z-]+/)||t(this.entities.quoted))(d=t(/^[|~*$^]?=/))&&(c=t(this.entities.quoted)||t(/^[\w-]+/))?a=[b,d,c.toCSS?c.toCSS():c].join(""):a=b;if(!t("]"))return;if(a)return"["+a+"]"},block:function(){var a;if(t("{")&&(a=t(this.primary))&&t("}"))return a},ruleset:function(){var b=[],c,d,g;q();while(c=t(this.selector)){b.push(c),t(this.comment);if(!t(","))break;t(this.comment)}if(b.length>0&&(d=t(this.block)))return new e.Ruleset(b,d,a.strictImports);j=f,r()},rule:function(){var a,c,d=b.charAt(f),h,l;q();if(d==="."||d==="#"||d==="&")return;if(a=t(this.variable)||t(this.property)){a.charAt(0)!="@"&&(l=/^([^@+\/'"*`(;{}-]*);/.exec(k[g]))?(f+=l[0].length-1,c=new e.Anonymous(l[1])):a==="font"?c=t(this.font):c=t(this.value),h=t(this.important);if(c&&t(this.end))return new e.Rule(a,c,h,i);j=f,r()}},"import":function(){var a,b,c=f;if(t(/^@import\s+/)&&(a=t(this.entities.quoted)||t(this.entities.url))){b=t(this.mediaFeatures);if(t(";"))return new e.Import(a,p,b,c)}},mediaFeature:function(){var a,b,c=[];do if(a=t(this.entities.keyword))c.push(a);else if(t("(")){b=t(this.property),a=t(this.entity);if(!t(")"))return null;if(b&&a)c.push(new e.Paren(new e.Rule(b,a,null,f,!0)));else if(a)c.push(new e.Paren(a));else return null}while(a);if(c.length>0)return new e.Expression(c)},mediaFeatures:function(){var a,b=[];do if(a=t(this.mediaFeature)){b.push(a);if(!t(","))break}else if(a=t(this.entities.variable)){b.push(a);if(!t(","))break}while(a);return b.length>0?b:null},media:function(){var a,b;if(t(/^@media/)){a=t(this.mediaFeatures);if(b=t(this.block))return new e.Media(b,a)}},directive:function(){var a,c,d,g,h,i;if(b.charAt(f)!=="@")return;if(c=t(this["import"])||t(this.media))return c;if(a=t(/^@page|@keyframes/)||t(/^@(?:-webkit-|-moz-|-o-|-ms-)[a-z0-9-]+/)){g=(t(/^[^{]+/)||"").trim();if(d=t(this.block))return new e.Directive(a+" "+g,d)}else if(a=t(/^@[-a-z]+/))if(a==="@font-face"){if(d=t(this.block))return new e.Directive(a,d)}else if((c=t(this.entity))&&t(";"))return new e.Directive(a,c)},font:function(){var a=[],b=[],c,d,f,g;while(g=t(this.shorthand)||t(this.entity))b.push(g);a.push(new e.Expression(b));if(t(","))while(g=t(this.expression)){a.push(g);if(!t(","))break}return new e.Value(a)},value:function(){var a,b=[],c;while(a=t(this.expression)){b.push(a);if(!t(","))break}if(b.length>0)return new e.Value(b)},important:function(){if(b.charAt(f)==="!")return t(/^! *important/)},sub:function(){var a;if(t("(")&&(a=t(this.expression))&&t(")"))return a},multiplication:function(){var a,b,c,d;if(a=t(this.operand)){while(!w(/^\/\*/)&&(c=t("/")||t("*"))&&(b=t(this.operand)))d=new e.Operation(c,[d||a,b]);return d||a}},addition:function(){var a,c,d,g;if(a=t(this.multiplication)){while((d=t(/^[-+]\s+/)||b.charAt(f-1)!=" "&&(t("+")||t("-")))&&(c=t(this.multiplication)))g=new e.Operation(d,[g||a,c]);return g||a}},conditions:function(){var a,b,c=f,d;if(a=t(this.condition)){while(t(",")&&(b=t(this.condition)))d=new e.Condition("or",d||a,b,c);return d||a}},condition:function(){var a,b,c,d,g=f,h=!1;t(/^not/)&&(h=!0),u("(");if(a=t(this.addition)||t(this.entities.keyword)||t(this.entities.quoted))return(d=t(/^(?:>=|=<|[<=>])/))?(b=t(this.addition)||t(this.entities.keyword)||t(this.entities.quoted))?c=new e.Condition(d,a,b,g,h):v("expected expression"):c=new e.Condition("=",a,new e.Keyword("true"),g,h),u(")"),t(/^and/)?new e.Condition("and",c,t(this.condition)):c},operand:function(){var a,c=b.charAt(f+1);b.charAt(f)==="-"&&(c==="@"||c==="(")&&(a=t("-"));var d=t(this.sub)||t(this.entities.dimension)||t(this.entities.color)||t(this.entities.variable)||t(this.entities.call);return a?new e.Operation("*",[new e.Dimension(-1),d]):d},expression:function(){var a,b,c=[],d;while(a=t(this.addition)||t(this.entity))c.push(a);if(c.length>0)return new e.Expression(c)},property:function(){var a;if(a=t(/^(\*?-?[-a-z_0-9]+)\s*:/))return a[1]}}}};if(d.mode==="browser"||d.mode==="rhino")d.Parser.importer=function(a,b,c,d){!/^([a-z]+:)?\//.test(a)&&b.length>0&&(a=b[0]+a),n({href:a,title:a,type:d.mime},function(e){e&&typeof d.errback=="function"?d.errback.call(null,a,b,c,d):c.apply(null,arguments)},!0)};(function(a){function b(b){return a.functions.hsla(b.h,b.s,b.l,b.a)}function c(b){if(b instanceof a.Dimension)return parseFloat(b.unit=="%"?b.value/100:b.value);if(typeof b=="number")return b;throw{error:"RuntimeError",message:"color functions take numbers as parameters"}}function d(a){return Math.min(1,Math.max(0,a))}a.functions={rgb:function(a,b,c){return this.rgba(a,b,c,1)},rgba:function(b,d,e,f){var g=[b,d,e].map(function(a){return c(a)}),f=c(f);return new a.Color(g,f)},hsl:function(a,b,c){return this.hsla(a,b,c,1)},hsla:function(a,b,d,e){function h(a){return a=a<0?a+1:a>1?a-1:a,a*6<1?g+(f-g)*a*6:a*2<1?f:a*3<2?g+(f-g)*(2/3-a)*6:g}a=c(a)%360/360,b=c(b),d=c(d),e=c(e);var f=d<=.5?d*(b+1):d+b-d*b,g=d*2-f;return this.rgba(h(a+1/3)*255,h(a)*255,h(a-1/3)*255,e)},hue:function(b){return new a.Dimension(Math.round(b.toHSL().h))},saturation:function(b){return new a.Dimension(Math.round(b.toHSL().s*100),"%")},lightness:function(b){return new a.Dimension(Math.round(b.toHSL().l*100),"%")},alpha:function(b){return new a.Dimension(b.toHSL().a)},saturate:function(a,c){var e=a.toHSL();return e.s+=c.value/100,e.s=d(e.s),b(e)},desaturate:function(a,c){var e=a.toHSL();return e.s-=c.value/100,e.s=d(e.s),b(e)},lighten:function(a,c){var e=a.toHSL();return e.l+=c.value/100,e.l=d(e.l),b(e)},darken:function(a,c){var e=a.toHSL();return e.l-=c.value/100,e.l=d(e.l),b(e)},fadein:function(a,c){var e=a.toHSL();return e.a+=c.value/100,e.a=d(e.a),b(e)},fadeout:function(a,c){var e=a.toHSL();return e.a-=c.value/100,e.a=d(e.a),b(e)},fade:function(a,c){var e=a.toHSL();return e.a=c.value/100,e.a=d(e.a),b(e)},spin:function(a,c){var d=a.toHSL(),e=(d.h+c.value)%360;return d.h=e<0?360+e:e,b(d)},mix:function(b,c,d){var e=d.value/100,f=e*2-1,g=b.toHSL().a-c.toHSL().a,h=((f*g==-1?f:(f+g)/(1+f*g))+1)/2,i=1-h,j=[b.rgb[0]*h+c.rgb[0]*i,b.rgb[1]*h+c.rgb[1]*i,b.rgb[2]*h+c.rgb[2]*i],k=b.alpha*e+c.alpha*(1-e);return new a.Color(j,k)},greyscale:function(b){return this.desaturate(b,new a.Dimension(100))},e:function(b){return new a.Anonymous(b instanceof a.JavaScript?b.evaluated:b)},escape:function(b){return new a.Anonymous(encodeURI(b.value).replace(/=/g,"%3D").replace(/:/g,"%3A").replace(/#/g,"%23").replace(/;/g,"%3B").replace(/\(/g,"%28").replace(/\)/g,"%29"))},"%":function(b){var c=Array.prototype.slice.call(arguments,1),d=b.value;for(var e=0;e255?255:a<0?0:a).toString(16),a.length===1?"0"+a:a}).join("")},operate:function(b,c){var d=[];c instanceof a.Color||(c=c.toColor());for(var e=0;e<3;e++)d[e]=a.operate(b,this.rgb[e],c.rgb[e]);return new a.Color(d,this.alpha+c.alpha)},toHSL:function(){var a=this.rgb[0]/255,b=this.rgb[1]/255,c=this.rgb[2]/255,d=this.alpha,e=Math.max(a,b,c),f=Math.min(a,b,c),g,h,i=(e+f)/2,j=e-f;if(e===f)g=h=0;else{h=i>.5?j/(2-e-f):j/(e+f);switch(e){case a:g=(b-c)/j+(b255?255:a<0?0:a).toString(16),a.length===1?"0"+a:a}).join("")}}}(c("../tree")),function(a){a.Comment=function(a,b){this.value=a,this.silent=!!b},a.Comment.prototype={toCSS:function(a){return a.compress?"":this.value},eval:function(){return this}}}(c("../tree")),function(a){a.Condition=function(a,b,c,d,e){this.op=a.trim(),this.lvalue=b,this.rvalue=c,this.index=d,this.negate=e},a.Condition.prototype.eval=function(a){var b=this.lvalue.eval(a),c=this.rvalue.eval(a),d=this.index,e,e=function(a){switch(a){case"and":return b&&c;case"or":return b||c;default:if(b.compare)e=b.compare(c);else if(c.compare)e=c.compare(b);else throw{type:"Type",message:"Unable to perform comparison",index:d};switch(e){case-1:return a==="<"||a==="=<";case 0:return a==="="||a===">="||a==="=<";case 1:return a===">"||a===">="}}}(this.op);return this.negate?!e:e}}(c("../tree")),function(a){a.Dimension=function(a,b){this.value=parseFloat(a),this.unit=b||null},a.Dimension.prototype={eval:function(){return this},toColor:function(){return new a.Color([this.value,this.value,this.value])},toCSS:function(){var a=this.value+this.unit;return a},operate:function(b,c){return new a.Dimension(a.operate(b,this.value,c.value),this.unit||c.unit)},compare:function(b){return b instanceof a.Dimension?b.value>this.value?-1:b.value":a.compress?">":" > "}[this.value]}}(c("../tree")),function(a){a.Expression=function(a){this.value=a},a.Expression.prototype={eval:function(b){return this.value.length>1?new a.Expression(this.value.map(function(a){return a.eval(b)})):this.value.length===1?this.value[0].eval(b):this},toCSS:function(a){return this.value.map(function(b){return b.toCSS?b.toCSS(a):""}).join(" ")}}}(c("../tree")),function(a){a.Import=function(b,c,d,e){var f=this;this.index=e,this._path=b,this.features=d&&new a.Value(d),b instanceof a.Quoted?this.path=/\.(le?|c)ss(\?.*)?$/.test(b.value)?b.value:b.value+".less":this.path=b.value.value||b.value,this.css=/css(\?.*)?$/.test(this.path),this.css||c.push(this.path,function(b,c){b&&(b.index=e),f.root=c||new a.Ruleset([],[])})},a.Import.prototype={toCSS:function(a){var b=this.features?" "+this.features.toCSS(a):"";return this.css?"@import "+this._path.toCSS()+b+";\n":""},eval:function(b){var c,d=this.features&&this.features.eval(b);if(this.css)return this;c=new a.Ruleset([],this.root.rules.slice(0));for(var e=0;e1){var d=new a.Element("&",null,0),e=[new a.Selector([d])];c=new a.Ruleset(e,b.mediaBlocks),c.multiMedia=!0}return delete b.mediaBlocks,delete b.mediaPath,c},evalNested:function(b){var c,d,e=b.mediaPath.concat([this]);for(c=0;c0;c--)b.splice(c,0,new a.Anonymous("and"));return new a.Expression(b)})),new a.Ruleset([],[])},permute:function(a){if(a.length===0)return[];if(a.length===1)return a[0];var b=[],c=this.permute(a.slice(1));for(var d=0;d0){c=this.arguments&&this.arguments.map(function(b){return b.eval(a)});for(var g=0;gthis.params.length)return!1;if(this.required>0&&c>this.params.length)return!1}if(this.condition&&!this.condition.eval({frames:[this.evalParams(b,a)].concat(b.frames)}))return!1;d=Math.min(c,this.arity);for(var f=0;fe.selectors[g].elements.length?Array.prototype.push.apply(d,e.find(new a.Selector(b.elements.slice(1)),c)):d.push(e);break}}),this._lookups[g]=d)},toCSS:function(b,c){var d=[],e=[],f=[],g=[],h,i;this.root||(b.length===0?g=this.selectors.map(function(a){return[a]}):this.joinSelectors(g,b,this.selectors));for(var j=0;j0&&(h=g.map(function(a){return a.map(function(a){return a.toCSS(c)}).join("").trim()}).join(c.compress?",":",\n"),d.push(h,(c.compress?"{":" {\n ")+e.join(c.compress?"":"\n ")+(c.compress?"}":"\n}\n"))),d.push(f),d.join("")+(c.compress?"\n":"")},joinSelectors:function(a,b,c){for(var d=0;d0&&e.push(new a.Selector(g)),h.length>0&&f.push(new a.Selector(h));for(var l=0;l0&&(b.value=c[0]+(b.value.charAt(0)==="/"?b.value.slice(1):b.value)),this.value=b,this.paths=c)},b.URL.prototype={toCSS:function(){return"url("+(this.attrs?"data:"+this.attrs.mime+this.attrs.charset+this.attrs.base64+this.attrs.data:this.value.toCSS())+")"},eval:function(a){return this.attrs?this:new b.URL(this.value.eval(a),this.paths)}}}(c("../tree")),function(a){a.Value=function(a){this.value=a,this.is="value"},a.Value.prototype={eval:function(b){return this.value.length===1?this.value[0].eval(b):new a.Value(this.value.map(function(a){return a.eval(b)}))},toCSS:function(a){return this.value.map(function(b){return b.toCSS(a)}).join(a.compress?",":", ")}}}(c("../tree")),function(a){a.Variable=function(a,b,c){this.name=a,this.index=b,this.file=c},a.Variable.prototype={eval:function(b){var c,d,e=this.name;e.indexOf("@@")==0&&(e="@"+(new a.Variable(e.slice(1))).eval(b).value);if(c=a.find(b.frames,function(a){if(d=a.variable(e))return d.value.eval(b)}))return c;throw{type:"Name",message:"variable "+e+" is undefined",filename:this.file,index:this.index}}}}(c("../tree")),function(a){a.find=function(a,b){for(var c=0,d;c1?"["+a.value.map(function(a){return a.toCSS(!1)}).join(", ")+"]":a.toCSS(!1)}}(c("./tree"));var f=location.protocol==="file:"||location.protocol==="chrome:"||location.protocol==="chrome-extension:"||location.protocol==="resource:";d.env=d.env||(location.hostname=="127.0.0.1"||location.hostname=="0.0.0.0"||location.hostname=="localhost"||location.port.length>0||f?"development":"production"),d.async=!1,d.poll=d.poll||(f?1e3:1500),d.watch=function(){return this.watchMode=!0},d.unwatch=function(){return this.watchMode=!1},d.env==="development"?(d.optimization=0,/!watch/.test(location.hash)&&d.watch(),d.watchTimer=setInterval(function(){d.watchMode&&m(function(a,b,c,d,e){b&&p(b.toCSS(),d,e.lastModified)})},d.poll)):d.optimization=3;var g;try{g=typeof a.localStorage=="undefined"?null:a.localStorage}catch(h){g=null}var i=document.getElementsByTagName("link"),j=/^text\/(x-)?less$/;d.sheets=[];for(var k=0;k>> 0; for (var i = 0; i < len; i++) { if (i in this) { block.call(thisObject, this[i], i, this); } } }; } if (!Array.prototype.map) { Array.prototype.map = function(fun /*, thisp*/) { var len = this.length >>> 0; var res = new Array(len); var thisp = arguments[1]; for (var i = 0; i < len; i++) { if (i in this) { res[i] = fun.call(thisp, this[i], i, this); } } return res; }; } if (!Array.prototype.filter) { Array.prototype.filter = function (block /*, thisp */) { var values = []; var thisp = arguments[1]; for (var i = 0; i < this.length; i++) { if (block.call(thisp, this[i])) { values.push(this[i]); } } return values; }; } if (!Array.prototype.reduce) { Array.prototype.reduce = function(fun /*, initial*/) { var len = this.length >>> 0; var i = 0; // no value to return if no initial value and an empty array if (len === 0 && arguments.length === 1) throw new TypeError(); if (arguments.length >= 2) { var rv = arguments[1]; } else { do { if (i in this) { rv = this[i++]; break; } // if array contains no values, no initial value to return if (++i >= len) throw new TypeError(); } while (true); } for (; i < len; i++) { if (i in this) { rv = fun.call(null, rv, this[i], i, this); } } return rv; }; } if (!Array.prototype.indexOf) { Array.prototype.indexOf = function (value /*, fromIndex */ ) { var length = this.length; var i = arguments[1] || 0; if (!length) return -1; if (i >= length) return -1; if (i < 0) i += length; for (; i < length; i++) { if (!Object.prototype.hasOwnProperty.call(this, i)) { continue } if (value === this[i]) return i; } return -1; }; } // // Object // if (!Object.keys) { Object.keys = function (object) { var keys = []; for (var name in object) { if (Object.prototype.hasOwnProperty.call(object, name)) { keys.push(name); } } return keys; }; } // // String // if (!String.prototype.trim) { String.prototype.trim = function () { return String(this).replace(/^\s\s*/, '').replace(/\s\s*$/, ''); }; } var less, tree; if (typeof environment === "object" && ({}).toString.call(environment) === "[object Environment]") { // Rhino // Details on how to detect Rhino: https://github.com/ringo/ringojs/issues/88 if (typeof(window) === 'undefined') { less = {} } else { less = window.less = {} } tree = less.tree = {}; less.mode = 'rhino'; } else if (typeof(window) === 'undefined') { // Node.js less = exports, tree = require('./tree'); less.mode = 'node'; } else { // Browser if (typeof(window.less) === 'undefined') { window.less = {} } less = window.less, tree = window.less.tree = {}; less.mode = 'browser'; } // // less.js - parser // // A relatively straight-forward predictive parser. // There is no tokenization/lexing stage, the input is parsed // in one sweep. // // To make the parser fast enough to run in the browser, several // optimization had to be made: // // - Matching and slicing on a huge input is often cause of slowdowns. // The solution is to chunkify the input into smaller strings. // The chunks are stored in the `chunks` var, // `j` holds the current chunk index, and `current` holds // the index of the current chunk in relation to `input`. // This gives us an almost 4x speed-up. // // - In many cases, we don't need to match individual tokens; // for example, if a value doesn't hold any variables, operations // or dynamic references, the parser can effectively 'skip' it, // treating it as a literal. // An example would be '1px solid #000' - which evaluates to itself, // we don't need to know what the individual components are. // The drawback, of course is that you don't get the benefits of // syntax-checking on the CSS. This gives us a 50% speed-up in the parser, // and a smaller speed-up in the code-gen. // // // Token matching is done with the `$` function, which either takes // a terminal string or regexp, or a non-terminal function to call. // It also takes care of moving all the indices forwards. // // less.Parser = function Parser(env) { var input, // LeSS input string i, // current index in `input` j, // current chunk temp, // temporarily holds a chunk's state, for backtracking memo, // temporarily holds `i`, when backtracking furthest, // furthest index the parser has gone to chunks, // chunkified input current, // index of current chunk, in `input` parser; var that = this; // Top parser on an import tree must be sure there is one "env" // which will then be passed arround by reference. var env = env || { }; if (!env.contents) { env.contents={}; } // env.contents must be passed arround with top env // This function is called after all files // have been imported through `@import`. var finish = function () {}; var imports = this.imports = { paths: env && env.paths || [], // Search paths, when importing queue: [], // Files which haven't been imported yet files: {}, // Holds the imported parse trees contents: env.contents, // Holds the imported file contents mime: env && env.mime, // MIME type of .less files error: null, // Error in parsing/evaluating an import push: function (path, callback) { var that = this; this.queue.push(path); // // Import a file asynchronously // less.Parser.importer(path, this.paths, function (e, root) { that.queue.splice(that.queue.indexOf(path), 1); // Remove the path from the queue var imported = path in that.files; that.files[path] = root; // Store the root if (e && !that.error) { that.error = e } callback(e, root, imported); if (that.queue.length === 0) { finish(e) } // Call `finish` if we're done importing }, env); } }; function save() { temp = chunks[j], memo = i, current = i } function restore() { chunks[j] = temp, i = memo, current = i } function sync() { if (i > current) { chunks[j] = chunks[j].slice(i - current); current = i; } } function isWhitespace(c) { // Could change to \s? var code = c.charCodeAt(0); return code === 32 || code === 10 || code === 9; } // // Parse from a token, regexp or string, and move forward if match // function $(tok) { var match, args, length, index, k; // // Non-terminal // if (tok instanceof Function) { return tok.call(parser.parsers); // // Terminal // // Either match a single character in the input, // or match a regexp in the current chunk (chunk[j]). // } else if (typeof(tok) === 'string') { match = input.charAt(i) === tok ? tok : null; length = 1; sync (); } else { sync (); if (match = tok.exec(chunks[j])) { length = match[0].length; } else { return null; } } // The match is confirmed, add the match length to `i`, // and consume any extra white-space characters (' ' || '\n') // which come after that. The reason for this is that LeSS's // grammar is mostly white-space insensitive. // if (match) { skipWhitespace(length); if(typeof(match) === 'string') { return match; } else { return match.length === 1 ? match[0] : match; } } } function skipWhitespace(length) { var oldi = i, oldj = j, endIndex = i + chunks[j].length, mem = i += length; while (i < endIndex) { if (! isWhitespace(input.charAt(i))) { break } i++; } chunks[j] = chunks[j].slice(length + (i - mem)); current = i; if (chunks[j].length === 0 && j < chunks.length - 1) { j++ } return oldi !== i || oldj !== j; } function expect(arg, msg) { var result = $(arg); if (! result) { error(msg || (typeof(arg) === 'string' ? "expected '" + arg + "' got '" + input.charAt(i) + "'" : "unexpected token")); } else { return result; } } function error(msg, type) { throw { index: i, type: type || 'Syntax', message: msg }; } // Same as $(), but don't change the state of the parser, // just return the match. function peek(tok) { if (typeof(tok) === 'string') { return input.charAt(i) === tok; } else { if (tok.test(chunks[j])) { return true; } else { return false; } } } function getInput(e, env) { if (e.filename && env.filename && (e.filename !== env.filename)) { return parser.imports.contents[e.filename]; } else { return input; } } function getLocation(index, input) { for (var n = index, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } return { line: typeof(index) === 'number' ? (input.slice(0, index).match(/\n/g) || "").length : null, column: column }; } function getFileName(e) { if(less.mode === 'browser' || less.mode === 'rhino') return e.filename; else return require('path').resolve(e.filename); } function getDebugInfo(index, inputStream, e) { return { lineNumber: getLocation(index, inputStream).line + 1, fileName: getFileName(e) }; } function LessError(e, env) { var input = getInput(e, env), loc = getLocation(e.index, input), line = loc.line, col = loc.column, lines = input.split('\n'); this.type = e.type || 'Syntax'; this.message = e.message; this.filename = e.filename || env.filename; this.index = e.index; this.line = typeof(line) === 'number' ? line + 1 : null; this.callLine = e.call && (getLocation(e.call, input).line + 1); this.callExtract = lines[getLocation(e.call, input).line]; this.stack = e.stack; this.column = col; this.extract = [ lines[line - 1], lines[line], lines[line + 1] ]; } this.env = env = env || {}; // The optimization level dictates the thoroughness of the parser, // the lower the number, the less nodes it will create in the tree. // This could matter for debugging, or if you want to access // the individual nodes in the tree. this.optimization = ('optimization' in this.env) ? this.env.optimization : 1; this.env.filename = this.env.filename || null; // // The Parser // return parser = { imports: imports, // // Parse an input string into an abstract syntax tree, // call `callback` when done. // parse: function (str, callback) { var root, start, end, zone, line, lines, buff = [], c, error = null; i = j = current = furthest = 0; input = str.replace(/\r\n/g, '\n'); // Remove potential UTF Byte Order Mark input = input.replace(/^\uFEFF/, ''); // Split the input into chunks. chunks = (function (chunks) { var j = 0, skip = /(?:@\{[\w-]+\}|[^"'`\{\}\/\(\)\\])+/g, comment = /\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g, string = /"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'|`((?:[^`]|\\.)*)`/g, level = 0, match, chunk = chunks[0], inParam; for (var i = 0, c, cc; i < input.length; i++) { skip.lastIndex = i; if (match = skip.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); } } c = input.charAt(i); comment.lastIndex = string.lastIndex = i; if (match = string.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); c = input.charAt(i); } } if (!inParam && c === '/') { cc = input.charAt(i + 1); if (cc === '/' || cc === '*') { if (match = comment.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); c = input.charAt(i); } } } } switch (c) { case '{': if (! inParam) { level ++; chunk.push(c); break } case '}': if (! inParam) { level --; chunk.push(c); chunks[++j] = chunk = []; break } case '(': if (! inParam) { inParam = true; chunk.push(c); break } case ')': if ( inParam) { inParam = false; chunk.push(c); break } default: chunk.push(c); } } if (level > 0) { error = new(LessError)({ index: i, type: 'Parse', message: "missing closing `}`", filename: env.filename }, env); } return chunks.map(function (c) { return c.join('') });; })([[]]); if (error) { return callback(error); } // Start with the primary rule. // The whole syntax tree is held under a Ruleset node, // with the `root` property set to true, so no `{}` are // output. The callback is called when the input is parsed. try { root = new(tree.Ruleset)([], $(this.parsers.primary)); root.root = true; } catch (e) { return callback(new(LessError)(e, env)); } root.toCSS = (function (evaluate) { var line, lines, column; return function (options, variables) { var frames = [], importError; options = options || {}; // // Allows setting variables with a hash, so: // // `{ color: new(tree.Color)('#f01') }` will become: // // new(tree.Rule)('@color', // new(tree.Value)([ // new(tree.Expression)([ // new(tree.Color)('#f01') // ]) // ]) // ) // if (typeof(variables) === 'object' && !Array.isArray(variables)) { variables = Object.keys(variables).map(function (k) { var value = variables[k]; if (! (value instanceof tree.Value)) { if (! (value instanceof tree.Expression)) { value = new(tree.Expression)([value]); } value = new(tree.Value)([value]); } return new(tree.Rule)('@' + k, value, false, 0); }); frames = [new(tree.Ruleset)(null, variables)]; } try { var css = evaluate.call(this, { frames: frames }) .toCSS([], { compress: options.compress || false, dumpLineNumbers: env.dumpLineNumbers }); } catch (e) { throw new(LessError)(e, env); } if ((importError = parser.imports.error)) { // Check if there was an error during importing if (importError instanceof LessError) throw importError; else throw new(LessError)(importError, env); } if (options.yuicompress && less.mode === 'node') { return require('./cssmin').compressor.cssmin(css); } else if (options.compress) { return css.replace(/(\s)+/g, "$1"); } else { return css; } }; })(root.eval); // If `i` is smaller than the `input.length - 1`, // it means the parser wasn't able to parse the whole // string, so we've got a parsing error. // // We try to extract a \n delimited string, // showing the line where the parse error occured. // We split it up into two parts (the part which parsed, // and the part which didn't), so we can color them differently. if (i < input.length - 1) { i = furthest; lines = input.split('\n'); line = (input.slice(0, i).match(/\n/g) || "").length + 1; for (var n = i, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } error = { type: "Parse", message: "Syntax Error on line " + line, index: i, filename: env.filename, line: line, column: column, extract: [ lines[line - 2], lines[line - 1], lines[line] ] }; } if (this.imports.queue.length > 0) { finish = function (e) { if (e) callback(e); else callback(null, root); }; } else { callback(error, root); } }, // // Here in, the parsing rules/functions // // The basic structure of the syntax tree generated is as follows: // // Ruleset -> Rule -> Value -> Expression -> Entity // // Here's some LESS code: // // .class { // color: #fff; // border: 1px solid #000; // width: @w + 4px; // > .child {...} // } // // And here's what the parse tree might look like: // // Ruleset (Selector '.class', [ // Rule ("color", Value ([Expression [Color #fff]])) // Rule ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]])) // Rule ("width", Value ([Expression [Operation "+" [Variable "@w"][Dimension 4px]]])) // Ruleset (Selector [Element '>', '.child'], [...]) // ]) // // In general, most rules will try to parse a token with the `$()` function, and if the return // value is truly, will return a new node, of the relevant type. Sometimes, we need to check // first, before parsing, that's when we use `peek()`. // parsers: { // // The `primary` rule is the *entry* and *exit* point of the parser. // The rules here can appear at any level of the parse tree. // // The recursive nature of the grammar is an interplay between the `block` // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule, // as represented by this simplified grammar: // // primary → (ruleset | rule)+ // ruleset → selector+ block // block → '{' primary '}' // // Only at one point is the primary rule not called from the // block rule: at the root level. // primary: function () { var node, root = []; while ((node = $(this.mixin.definition) || $(this.rule) || $(this.ruleset) || $(this.mixin.call) || $(this.comment) || $(this.directive)) || $(/^[\s\n]+/)) { node && root.push(node); } return root; }, // We create a Comment node for CSS comments `/* */`, // but keep the LeSS comments `//` silent, by just skipping // over them. comment: function () { var comment; if (input.charAt(i) !== '/') return; if (input.charAt(i + 1) === '/') { return new(tree.Comment)($(/^\/\/.*/), true); } else if (comment = $(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/)) { return new(tree.Comment)(comment); } }, // // Entities are tokens which can be found inside an Expression // entities: { // // A string, which supports escaping " and ' // // "milky way" 'he\'s the one!' // quoted: function () { var str, j = i, e; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '"' && input.charAt(j) !== "'") return; e && $('~'); if (str = $(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/)) { return new(tree.Quoted)(str[0], str[1] || str[2], e); } }, // // A catch-all word, such as: // // black border-collapse // keyword: function () { var k; if (k = $(/^[_A-Za-z-][_A-Za-z0-9-]*/)) { if (tree.colors.hasOwnProperty(k)) { // detect named color return new(tree.Color)(tree.colors[k].slice(1)); } else { return new(tree.Keyword)(k); } } }, // // A function call // // rgb(255, 0, 255) // // We also try to catch IE's `alpha()`, but let the `alpha` parser // deal with the details. // // The arguments are parsed with the `entities.arguments` parser. // call: function () { var name, nameLC, args, alpha_ret, index = i; if (! (name = /^([\w-]+|%|progid:[\w\.]+)\(/.exec(chunks[j]))) return; name = name[1]; nameLC = name.toLowerCase(); if (nameLC === 'url') { return null } else { i += name.length } if (nameLC === 'alpha') { alpha_ret = $(this.alpha); if(typeof alpha_ret !== 'undefined') { return alpha_ret; } } $('('); // Parse the '(' and consume whitespace. args = $(this.entities.arguments); if (! $(')')) return; if (name) { return new(tree.Call)(name, args, index, env.filename) } }, arguments: function () { var args = [], arg; while (arg = $(this.entities.assignment) || $(this.expression)) { args.push(arg); if (! $(',')) { break } } return args; }, literal: function () { return $(this.entities.ratio) || $(this.entities.dimension) || $(this.entities.color) || $(this.entities.quoted); }, // Assignments are argument entities for calls. // They are present in ie filter properties as shown below. // // filter: progid:DXImageTransform.Microsoft.Alpha( *opacity=50* ) // assignment: function () { var key, value; if ((key = $(/^\w+(?=\s?=)/i)) && $('=') && (value = $(this.entity))) { return new(tree.Assignment)(key, value); } }, // // Parse url() tokens // // We use a specific rule for urls, because they don't really behave like // standard function calls. The difference is that the argument doesn't have // to be enclosed within a string, so it can't be parsed as an Expression. // url: function () { var value; if (input.charAt(i) !== 'u' || !$(/^url\(/)) return; value = $(this.entities.quoted) || $(this.entities.variable) || $(/^(?:(?:\\[\(\)'"])|[^\(\)'"])+/) || ""; expect(')'); return new(tree.URL)((value.value != null || value instanceof tree.Variable) ? value : new(tree.Anonymous)(value), imports.paths); }, // // A Variable entity, such as `@fink`, in // // width: @fink + 2px // // We use a different parser for variable definitions, // see `parsers.variable`. // variable: function () { var name, index = i; if (input.charAt(i) === '@' && (name = $(/^@@?[\w-]+/))) { return new(tree.Variable)(name, index, env.filename); } }, // A variable entity useing the protective {} e.g. @{var} variableCurly: function () { var name, curly, index = i; if (input.charAt(i) === '@' && (curly = $(/^@\{([\w-]+)\}/))) { return new(tree.Variable)("@" + curly[1], index, env.filename); } }, // // A Hexadecimal color // // #4F3C2F // // `rgb` and `hsl` colors are parsed through the `entities.call` parser. // color: function () { var rgb; if (input.charAt(i) === '#' && (rgb = $(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/))) { return new(tree.Color)(rgb[1]); } }, // // A Dimension, that is, a number and a unit // // 0.5em 95% // dimension: function () { var value, c = input.charCodeAt(i); if ((c > 57 || c < 45) || c === 47) return; if (value = $(/^(-?\d*\.?\d+)(px|%|em|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn|dpi|dpcm|dppx|rem|vw|vh|vmin|vm|ch)?/)) { return new(tree.Dimension)(value[1], value[2]); } }, // // A Ratio // // 16/9 // ratio: function () { var value, c = input.charCodeAt(i); if (c > 57 || c < 48) return; if (value = $(/^(\d+\/\d+)/)) { return new(tree.Ratio)(value[1]); } }, // // JavaScript code to be evaluated // // `window.location.href` // javascript: function () { var str, j = i, e; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '`') { return } e && $('~'); if (str = $(/^`([^`]*)`/)) { return new(tree.JavaScript)(str[1], i, e); } } }, // // The variable part of a variable definition. Used in the `rule` parser // // @fink: // variable: function () { var name; if (input.charAt(i) === '@' && (name = $(/^(@[\w-]+)\s*:/))) { return name[1] } }, // // A font size/line-height shorthand // // small/12px // // We need to peek first, or we'll match on keywords and dimensions // shorthand: function () { var a, b; if (! peek(/^[@\w.%-]+\/[@\w.-]+/)) return; save(); if ((a = $(this.entity)) && $('/') && (b = $(this.entity))) { return new(tree.Shorthand)(a, b); } restore(); }, // // Mixins // mixin: { // // A Mixin call, with an optional argument list // // #mixins > .square(#fff); // .rounded(4px, black); // .button; // // The `while` loop is there because mixins can be // namespaced, but we only support the child and descendant // selector for now. // call: function () { var elements = [], e, c, args = [], arg, index = i, s = input.charAt(i), name, value, important = false; if (s !== '.' && s !== '#') { return } save(); // stop us absorbing part of an invalid selector while (e = $(/^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/)) { elements.push(new(tree.Element)(c, e, i)); c = $('>'); } if ($('(')) { while (arg = $(this.expression)) { value = arg; name = null; // Variable if (arg.value.length == 1) { var val = arg.value[0]; if (val instanceof tree.Variable) { if ($(':')) { if (value = $(this.expression)) { name = val.name; } else { throw new(Error)("Expected value"); } } } } args.push({ name: name, value: value }); if (! $(',')) { break } } if (! $(')')) throw new(Error)("Expected )"); } if ($(this.important)) { important = true; } if (elements.length > 0 && ($(';') || peek('}'))) { return new(tree.mixin.Call)(elements, args, index, env.filename, important); } restore(); }, // // A Mixin definition, with a list of parameters // // .rounded (@radius: 2px, @color) { // ... // } // // Until we have a finer grained state-machine, we have to // do a look-ahead, to make sure we don't have a mixin call. // See the `rule` function for more information. // // We start by matching `.rounded (`, and then proceed on to // the argument list, which has optional default values. // We store the parameters in `params`, with a `value` key, // if there is a value, such as in the case of `@radius`. // // Once we've got our params list, and a closing `)`, we parse // the `{...}` block. // definition: function () { var name, params = [], match, ruleset, param, value, cond, variadic = false; if ((input.charAt(i) !== '.' && input.charAt(i) !== '#') || peek(/^[^{]*(;|})/)) return; save(); if (match = $(/^([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/)) { name = match[1]; do { if (input.charAt(i) === '.' && $(/^\.{3}/)) { variadic = true; break; } else if (param = $(this.entities.variable) || $(this.entities.literal) || $(this.entities.keyword)) { // Variable if (param instanceof tree.Variable) { if ($(':')) { value = expect(this.expression, 'expected expression'); params.push({ name: param.name, value: value }); } else if ($(/^\.{3}/)) { params.push({ name: param.name, variadic: true }); variadic = true; break; } else { params.push({ name: param.name }); } } else { params.push({ value: param }); } } else { break; } } while ($(',')) // .mixincall("@{a}"); // looks a bit like a mixin definition.. so we have to be nice and restore if (!$(')')) { furthest = i; restore(); } if ($(/^when/)) { // Guard cond = expect(this.conditions, 'expected condition'); } ruleset = $(this.block); if (ruleset) { return new(tree.mixin.Definition)(name, params, ruleset, cond, variadic); } else { restore(); } } } }, // // Entities are the smallest recognized token, // and can be found inside a rule's value. // entity: function () { return $(this.entities.literal) || $(this.entities.variable) || $(this.entities.url) || $(this.entities.call) || $(this.entities.keyword) || $(this.entities.javascript) || $(this.comment); }, // // A Rule terminator. Note that we use `peek()` to check for '}', // because the `block` rule will be expecting it, but we still need to make sure // it's there, if ';' was ommitted. // end: function () { return $(';') || peek('}'); }, // // IE's alpha function // // alpha(opacity=88) // alpha: function () { var value; if (! $(/^\(opacity=/i)) return; if (value = $(/^\d+/) || $(this.entities.variable)) { expect(')'); return new(tree.Alpha)(value); } }, // // A Selector Element // // div // + h1 // #socks // input[type="text"] // // Elements are the building blocks for Selectors, // they are made out of a `Combinator` (see combinator rule), // and an element name, such as a tag a class, or `*`. // element: function () { var e, t, c, v; c = $(this.combinator); e = $(/^(?:\d+\.\d+|\d+)%/) || $(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/) || $('*') || $('&') || $(this.attribute) || $(/^\([^)@]+\)/) || $(/^[\.#](?=@)/) || $(this.entities.variableCurly); if (! e) { if ($('(') && (v = ($(this.entities.variableCurly) || $(this.entities.variable))) && $(')')) { e = new(tree.Paren)(v); } } if (e) { return new(tree.Element)(c, e, i) } }, // // Combinators combine elements together, in a Selector. // // Because our parser isn't white-space sensitive, special care // has to be taken, when parsing the descendant combinator, ` `, // as it's an empty space. We have to check the previous character // in the input, to see if it's a ` ` character. More info on how // we deal with this in *combinator.js*. // combinator: function () { var match, c = input.charAt(i); if (c === '>' || c === '+' || c === '~') { i++; while (input.charAt(i).match(/\s/)) { i++ } return new(tree.Combinator)(c); } else if (input.charAt(i - 1).match(/\s/)) { return new(tree.Combinator)(" "); } else { return new(tree.Combinator)(null); } }, // // A CSS Selector // // .class > div + h1 // li a:hover // // Selectors are made out of one or more Elements, see above. // selector: function () { var sel, e, elements = [], c, match; // depreciated, will be removed soon if ($('(')) { sel = $(this.entity); expect(')'); return new(tree.Selector)([new(tree.Element)('', sel, i)]); } while (e = $(this.element)) { c = input.charAt(i); elements.push(e) if (c === '{' || c === '}' || c === ';' || c === ',') { break } } if (elements.length > 0) { return new(tree.Selector)(elements) } }, tag: function () { return $(/^[A-Za-z][A-Za-z-]*[0-9]?/) || $('*'); }, attribute: function () { var attr = '', key, val, op; if (! $('[')) return; if (key = $(/^(?:[_A-Za-z0-9-]|\\.)+/) || $(this.entities.quoted)) { if ((op = $(/^[|~*$^]?=/)) && (val = $(this.entities.quoted) || $(/^[\w-]+/))) { attr = [key, op, val.toCSS ? val.toCSS() : val].join(''); } else { attr = key } } if (! $(']')) return; if (attr) { return "[" + attr + "]" } }, // // The `block` rule is used by `ruleset` and `mixin.definition`. // It's a wrapper around the `primary` rule, with added `{}`. // block: function () { var content; if ($('{') && (content = $(this.primary)) && $('}')) { return content; } }, // // div, .class, body > p {...} // ruleset: function () { var selectors = [], s, rules, match, debugInfo; save(); if (env.dumpLineNumbers) debugInfo = getDebugInfo(i, input, env); while (s = $(this.selector)) { selectors.push(s); $(this.comment); if (! $(',')) { break } $(this.comment); } if (selectors.length > 0 && (rules = $(this.block))) { var ruleset = new(tree.Ruleset)(selectors, rules, env.strictImports); if (env.dumpLineNumbers) ruleset.debugInfo = debugInfo; return ruleset; } else { // Backtrack furthest = i; restore(); } }, rule: function () { var name, value, c = input.charAt(i), important, match; save(); if (c === '.' || c === '#' || c === '&') { return } if (name = $(this.variable) || $(this.property)) { if ((name.charAt(0) != '@') && (match = /^([^@+\/'"*`(;{}-]*);/.exec(chunks[j]))) { i += match[0].length - 1; value = new(tree.Anonymous)(match[1]); } else if (name === "font") { value = $(this.font); } else { value = $(this.value); } important = $(this.important); if (value && $(this.end)) { return new(tree.Rule)(name, value, important, memo); } else { furthest = i; restore(); } } }, // // An @import directive // // @import "lib"; // // Depending on our environemnt, importing is done differently: // In the browser, it's an XHR request, in Node, it would be a // file-system operation. The function used for importing is // stored in `import`, which we pass to the Import constructor. // "import": function () { var path, features, index = i; save(); var dir = $(/^@import(?:-(once))?\s+/); if (dir && (path = $(this.entities.quoted) || $(this.entities.url))) { features = $(this.mediaFeatures); if ($(';')) { return new(tree.Import)(path, imports, features, (dir[1] === 'once'), index); } } restore(); }, mediaFeature: function () { var e, p, nodes = []; do { if (e = $(this.entities.keyword)) { nodes.push(e); } else if ($('(')) { p = $(this.property); e = $(this.entity); if ($(')')) { if (p && e) { nodes.push(new(tree.Paren)(new(tree.Rule)(p, e, null, i, true))); } else if (e) { nodes.push(new(tree.Paren)(e)); } else { return null; } } else { return null } } } while (e); if (nodes.length > 0) { return new(tree.Expression)(nodes); } }, mediaFeatures: function () { var e, features = []; do { if (e = $(this.mediaFeature)) { features.push(e); if (! $(',')) { break } } else if (e = $(this.entities.variable)) { features.push(e); if (! $(',')) { break } } } while (e); return features.length > 0 ? features : null; }, media: function () { var features, rules, media, debugInfo; if (env.dumpLineNumbers) debugInfo = getDebugInfo(i, input, env); if ($(/^@media/)) { features = $(this.mediaFeatures); if (rules = $(this.block)) { media = new(tree.Media)(rules, features); if(env.dumpLineNumbers) media.debugInfo = debugInfo; return media; } } }, // // A CSS Directive // // @charset "utf-8"; // directive: function () { var name, value, rules, identifier, e, nodes, nonVendorSpecificName, hasBlock, hasIdentifier; if (input.charAt(i) !== '@') return; if (value = $(this['import']) || $(this.media)) { return value; } save(); name = $(/^@[a-z-]+/); nonVendorSpecificName = name; if (name.charAt(1) == '-' && name.indexOf('-', 2) > 0) { nonVendorSpecificName = "@" + name.slice(name.indexOf('-', 2) + 1); } switch(nonVendorSpecificName) { case "@font-face": hasBlock = true; break; case "@viewport": case "@top-left": case "@top-left-corner": case "@top-center": case "@top-right": case "@top-right-corner": case "@bottom-left": case "@bottom-left-corner": case "@bottom-center": case "@bottom-right": case "@bottom-right-corner": case "@left-top": case "@left-middle": case "@left-bottom": case "@right-top": case "@right-middle": case "@right-bottom": hasBlock = true; break; case "@page": case "@document": case "@supports": case "@keyframes": hasBlock = true; hasIdentifier = true; break; } if (hasIdentifier) { name += " " + ($(/^[^{]+/) || '').trim(); } if (hasBlock) { if (rules = $(this.block)) { return new(tree.Directive)(name, rules); } } else { if ((value = $(this.entity)) && $(';')) { return new(tree.Directive)(name, value); } } restore(); }, font: function () { var value = [], expression = [], weight, shorthand, font, e; while (e = $(this.shorthand) || $(this.entity)) { expression.push(e); } value.push(new(tree.Expression)(expression)); if ($(',')) { while (e = $(this.expression)) { value.push(e); if (! $(',')) { break } } } return new(tree.Value)(value); }, // // A Value is a comma-delimited list of Expressions // // font-family: Baskerville, Georgia, serif; // // In a Rule, a Value represents everything after the `:`, // and before the `;`. // value: function () { var e, expressions = [], important; while (e = $(this.expression)) { expressions.push(e); if (! $(',')) { break } } if (expressions.length > 0) { return new(tree.Value)(expressions); } }, important: function () { if (input.charAt(i) === '!') { return $(/^! *important/); } }, sub: function () { var e; if ($('(') && (e = $(this.expression)) && $(')')) { return e; } }, multiplication: function () { var m, a, op, operation; if (m = $(this.operand)) { while (!peek(/^\/\*/) && (op = ($('/') || $('*'))) && (a = $(this.operand))) { operation = new(tree.Operation)(op, [operation || m, a]); } return operation || m; } }, addition: function () { var m, a, op, operation; if (m = $(this.multiplication)) { while ((op = $(/^[-+]\s+/) || (!isWhitespace(input.charAt(i - 1)) && ($('+') || $('-')))) && (a = $(this.multiplication))) { operation = new(tree.Operation)(op, [operation || m, a]); } return operation || m; } }, conditions: function () { var a, b, index = i, condition; if (a = $(this.condition)) { while ($(',') && (b = $(this.condition))) { condition = new(tree.Condition)('or', condition || a, b, index); } return condition || a; } }, condition: function () { var a, b, c, op, index = i, negate = false; if ($(/^not/)) { negate = true } expect('('); if (a = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) { if (op = $(/^(?:>=|=<|[<=>])/)) { if (b = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) { c = new(tree.Condition)(op, a, b, index, negate); } else { error('expected expression'); } } else { c = new(tree.Condition)('=', a, new(tree.Keyword)('true'), index, negate); } expect(')'); return $(/^and/) ? new(tree.Condition)('and', c, $(this.condition)) : c; } }, // // An operand is anything that can be part of an operation, // such as a Color, or a Variable // operand: function () { var negate, p = input.charAt(i + 1); if (input.charAt(i) === '-' && (p === '@' || p === '(')) { negate = $('-') } var o = $(this.sub) || $(this.entities.dimension) || $(this.entities.color) || $(this.entities.variable) || $(this.entities.call); return negate ? new(tree.Operation)('*', [new(tree.Dimension)(-1), o]) : o; }, // // Expressions either represent mathematical operations, // or white-space delimited Entities. // // 1px solid black // @var * 2 // expression: function () { var e, delim, entities = [], d; while (e = $(this.addition) || $(this.entity)) { entities.push(e); } if (entities.length > 0) { return new(tree.Expression)(entities); } }, property: function () { var name; if (name = $(/^(\*?-?[_a-z0-9-]+)\s*:/)) { return name[1]; } } } }; }; if (less.mode === 'browser' || less.mode === 'rhino') { // // Used by `@import` directives // less.Parser.importer = function (path, paths, callback, env) { if (!/^([a-z-]+:)?\//.test(path) && paths.length > 0) { path = paths[0] + path; } // We pass `true` as 3rd argument, to force the reload of the import. // This is so we can get the syntax tree as opposed to just the CSS output, // as we need this to evaluate the current stylesheet. // __ Now using the hack of passing a ref to top parser's content cache in the 1st arg. __ loadStyleSheet({ href: path, title: path, type: env.mime, contents: env.contents }, function (e) { if (e && typeof(env.errback) === "function") { env.errback.call(null, path, paths, callback, env); } else { callback.apply(null, arguments); } }, true); }; } (function (tree) { tree.functions = { rgb: function (r, g, b) { return this.rgba(r, g, b, 1.0); }, rgba: function (r, g, b, a) { var rgb = [r, g, b].map(function (c) { return number(c) }), a = number(a); return new(tree.Color)(rgb, a); }, hsl: function (h, s, l) { return this.hsla(h, s, l, 1.0); }, hsla: function (h, s, l, a) { h = (number(h) % 360) / 360; s = number(s); l = number(l); a = number(a); var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s; var m1 = l * 2 - m2; return this.rgba(hue(h + 1/3) * 255, hue(h) * 255, hue(h - 1/3) * 255, a); function hue(h) { h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h); if (h * 6 < 1) return m1 + (m2 - m1) * h * 6; else if (h * 2 < 1) return m2; else if (h * 3 < 2) return m1 + (m2 - m1) * (2/3 - h) * 6; else return m1; } }, hue: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().h)); }, saturation: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().s * 100), '%'); }, lightness: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().l * 100), '%'); }, red: function (color) { return new(tree.Dimension)(color.rgb[0]); }, green: function (color) { return new(tree.Dimension)(color.rgb[1]); }, blue: function (color) { return new(tree.Dimension)(color.rgb[2]); }, alpha: function (color) { return new(tree.Dimension)(color.toHSL().a); }, luma: function (color) { return new(tree.Dimension)(Math.round((0.2126 * (color.rgb[0]/255) + 0.7152 * (color.rgb[1]/255) + 0.0722 * (color.rgb[2]/255)) * color.alpha * 100), '%'); }, saturate: function (color, amount) { var hsl = color.toHSL(); hsl.s += amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, desaturate: function (color, amount) { var hsl = color.toHSL(); hsl.s -= amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, lighten: function (color, amount) { var hsl = color.toHSL(); hsl.l += amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, darken: function (color, amount) { var hsl = color.toHSL(); hsl.l -= amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, fadein: function (color, amount) { var hsl = color.toHSL(); hsl.a += amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, fadeout: function (color, amount) { var hsl = color.toHSL(); hsl.a -= amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, fade: function (color, amount) { var hsl = color.toHSL(); hsl.a = amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, spin: function (color, amount) { var hsl = color.toHSL(); var hue = (hsl.h + amount.value) % 360; hsl.h = hue < 0 ? 360 + hue : hue; return hsla(hsl); }, // // Copyright (c) 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein // http://sass-lang.com // mix: function (color1, color2, weight) { if (!weight) { weight = new(tree.Dimension)(50); } var p = weight.value / 100.0; var w = p * 2 - 1; var a = color1.toHSL().a - color2.toHSL().a; var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0; var w2 = 1 - w1; var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2, color1.rgb[1] * w1 + color2.rgb[1] * w2, color1.rgb[2] * w1 + color2.rgb[2] * w2]; var alpha = color1.alpha * p + color2.alpha * (1 - p); return new(tree.Color)(rgb, alpha); }, greyscale: function (color) { return this.desaturate(color, new(tree.Dimension)(100)); }, contrast: function (color, dark, light, threshold) { if (typeof light === 'undefined') { light = this.rgba(255, 255, 255, 1.0); } if (typeof dark === 'undefined') { dark = this.rgba(0, 0, 0, 1.0); } if (typeof threshold === 'undefined') { threshold = 0.43; } else { threshold = threshold.value; } if (((0.2126 * (color.rgb[0]/255) + 0.7152 * (color.rgb[1]/255) + 0.0722 * (color.rgb[2]/255)) * color.alpha) < threshold) { return light; } else { return dark; } }, e: function (str) { return new(tree.Anonymous)(str instanceof tree.JavaScript ? str.evaluated : str); }, escape: function (str) { return new(tree.Anonymous)(encodeURI(str.value).replace(/=/g, "%3D").replace(/:/g, "%3A").replace(/#/g, "%23").replace(/;/g, "%3B").replace(/\(/g, "%28").replace(/\)/g, "%29")); }, '%': function (quoted /* arg, arg, ...*/) { var args = Array.prototype.slice.call(arguments, 1), str = quoted.value; for (var i = 0; i < args.length; i++) { str = str.replace(/%[sda]/i, function(token) { var value = token.match(/s/i) ? args[i].value : args[i].toCSS(); return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value; }); } str = str.replace(/%%/g, '%'); return new(tree.Quoted)('"' + str + '"', str); }, round: function (n, f) { var fraction = typeof(f) === "undefined" ? 0 : f.value; if (n instanceof tree.Dimension) { return new(tree.Dimension)(number(n).toFixed(fraction), n.unit); } else if (typeof(n) === 'number') { return n.toFixed(fraction); } else { throw { type: "Argument", message: "argument must be a number" }; } }, ceil: function (n) { return this._math('ceil', n); }, floor: function (n) { return this._math('floor', n); }, _math: function (fn, n) { if (n instanceof tree.Dimension) { return new(tree.Dimension)(Math[fn](number(n)), n.unit); } else if (typeof(n) === 'number') { return Math[fn](n); } else { throw { type: "Argument", message: "argument must be a number" }; } }, argb: function (color) { return new(tree.Anonymous)(color.toARGB()); }, percentage: function (n) { return new(tree.Dimension)(n.value * 100, '%'); }, color: function (n) { if (n instanceof tree.Quoted) { return new(tree.Color)(n.value.slice(1)); } else { throw { type: "Argument", message: "argument must be a string" }; } }, iscolor: function (n) { return this._isa(n, tree.Color); }, isnumber: function (n) { return this._isa(n, tree.Dimension); }, isstring: function (n) { return this._isa(n, tree.Quoted); }, iskeyword: function (n) { return this._isa(n, tree.Keyword); }, isurl: function (n) { return this._isa(n, tree.URL); }, ispixel: function (n) { return (n instanceof tree.Dimension) && n.unit === 'px' ? tree.True : tree.False; }, ispercentage: function (n) { return (n instanceof tree.Dimension) && n.unit === '%' ? tree.True : tree.False; }, isem: function (n) { return (n instanceof tree.Dimension) && n.unit === 'em' ? tree.True : tree.False; }, _isa: function (n, Type) { return (n instanceof Type) ? tree.True : tree.False; }, /* Blending modes */ multiply: function(color1, color2) { var r = color1.rgb[0] * color2.rgb[0] / 255; var g = color1.rgb[1] * color2.rgb[1] / 255; var b = color1.rgb[2] * color2.rgb[2] / 255; return this.rgb(r, g, b); }, screen: function(color1, color2) { var r = 255 - (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255; var g = 255 - (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255; var b = 255 - (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255; return this.rgb(r, g, b); }, overlay: function(color1, color2) { var r = color1.rgb[0] < 128 ? 2 * color1.rgb[0] * color2.rgb[0] / 255 : 255 - 2 * (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255; var g = color1.rgb[1] < 128 ? 2 * color1.rgb[1] * color2.rgb[1] / 255 : 255 - 2 * (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255; var b = color1.rgb[2] < 128 ? 2 * color1.rgb[2] * color2.rgb[2] / 255 : 255 - 2 * (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255; return this.rgb(r, g, b); }, softlight: function(color1, color2) { var t = color2.rgb[0] * color1.rgb[0] / 255; var r = t + color1.rgb[0] * (255 - (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255 - t) / 255; t = color2.rgb[1] * color1.rgb[1] / 255; var g = t + color1.rgb[1] * (255 - (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255 - t) / 255; t = color2.rgb[2] * color1.rgb[2] / 255; var b = t + color1.rgb[2] * (255 - (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255 - t) / 255; return this.rgb(r, g, b); }, hardlight: function(color1, color2) { var r = color2.rgb[0] < 128 ? 2 * color2.rgb[0] * color1.rgb[0] / 255 : 255 - 2 * (255 - color2.rgb[0]) * (255 - color1.rgb[0]) / 255; var g = color2.rgb[1] < 128 ? 2 * color2.rgb[1] * color1.rgb[1] / 255 : 255 - 2 * (255 - color2.rgb[1]) * (255 - color1.rgb[1]) / 255; var b = color2.rgb[2] < 128 ? 2 * color2.rgb[2] * color1.rgb[2] / 255 : 255 - 2 * (255 - color2.rgb[2]) * (255 - color1.rgb[2]) / 255; return this.rgb(r, g, b); }, difference: function(color1, color2) { var r = Math.abs(color1.rgb[0] - color2.rgb[0]); var g = Math.abs(color1.rgb[1] - color2.rgb[1]); var b = Math.abs(color1.rgb[2] - color2.rgb[2]); return this.rgb(r, g, b); }, exclusion: function(color1, color2) { var r = color1.rgb[0] + color2.rgb[0] * (255 - color1.rgb[0] - color1.rgb[0]) / 255; var g = color1.rgb[1] + color2.rgb[1] * (255 - color1.rgb[1] - color1.rgb[1]) / 255; var b = color1.rgb[2] + color2.rgb[2] * (255 - color1.rgb[2] - color1.rgb[2]) / 255; return this.rgb(r, g, b); }, average: function(color1, color2) { var r = (color1.rgb[0] + color2.rgb[0]) / 2; var g = (color1.rgb[1] + color2.rgb[1]) / 2; var b = (color1.rgb[2] + color2.rgb[2]) / 2; return this.rgb(r, g, b); }, negation: function(color1, color2) { var r = 255 - Math.abs(255 - color2.rgb[0] - color1.rgb[0]); var g = 255 - Math.abs(255 - color2.rgb[1] - color1.rgb[1]); var b = 255 - Math.abs(255 - color2.rgb[2] - color1.rgb[2]); return this.rgb(r, g, b); }, tint: function(color, amount) { return this.mix(this.rgb(255,255,255), color, amount); }, shade: function(color, amount) { return this.mix(this.rgb(0, 0, 0), color, amount); } }; function hsla(hsla) { return tree.functions.hsla(hsla.h, hsla.s, hsla.l, hsla.a); } function number(n) { if (n instanceof tree.Dimension) { return parseFloat(n.unit == '%' ? n.value / 100 : n.value); } else if (typeof(n) === 'number') { return n; } else { throw { error: "RuntimeError", message: "color functions take numbers as parameters" }; } } function clamp(val) { return Math.min(1, Math.max(0, val)); } })(require('./tree')); (function (tree) { tree.colors = { 'aliceblue':'#f0f8ff', 'antiquewhite':'#faebd7', 'aqua':'#00ffff', 'aquamarine':'#7fffd4', 'azure':'#f0ffff', 'beige':'#f5f5dc', 'bisque':'#ffe4c4', 'black':'#000000', 'blanchedalmond':'#ffebcd', 'blue':'#0000ff', 'blueviolet':'#8a2be2', 'brown':'#a52a2a', 'burlywood':'#deb887', 'cadetblue':'#5f9ea0', 'chartreuse':'#7fff00', 'chocolate':'#d2691e', 'coral':'#ff7f50', 'cornflowerblue':'#6495ed', 'cornsilk':'#fff8dc', 'crimson':'#dc143c', 'cyan':'#00ffff', 'darkblue':'#00008b', 'darkcyan':'#008b8b', 'darkgoldenrod':'#b8860b', 'darkgray':'#a9a9a9', 'darkgrey':'#a9a9a9', 'darkgreen':'#006400', 'darkkhaki':'#bdb76b', 'darkmagenta':'#8b008b', 'darkolivegreen':'#556b2f', 'darkorange':'#ff8c00', 'darkorchid':'#9932cc', 'darkred':'#8b0000', 'darksalmon':'#e9967a', 'darkseagreen':'#8fbc8f', 'darkslateblue':'#483d8b', 'darkslategray':'#2f4f4f', 'darkslategrey':'#2f4f4f', 'darkturquoise':'#00ced1', 'darkviolet':'#9400d3', 'deeppink':'#ff1493', 'deepskyblue':'#00bfff', 'dimgray':'#696969', 'dimgrey':'#696969', 'dodgerblue':'#1e90ff', 'firebrick':'#b22222', 'floralwhite':'#fffaf0', 'forestgreen':'#228b22', 'fuchsia':'#ff00ff', 'gainsboro':'#dcdcdc', 'ghostwhite':'#f8f8ff', 'gold':'#ffd700', 'goldenrod':'#daa520', 'gray':'#808080', 'grey':'#808080', 'green':'#008000', 'greenyellow':'#adff2f', 'honeydew':'#f0fff0', 'hotpink':'#ff69b4', 'indianred':'#cd5c5c', 'indigo':'#4b0082', 'ivory':'#fffff0', 'khaki':'#f0e68c', 'lavender':'#e6e6fa', 'lavenderblush':'#fff0f5', 'lawngreen':'#7cfc00', 'lemonchiffon':'#fffacd', 'lightblue':'#add8e6', 'lightcoral':'#f08080', 'lightcyan':'#e0ffff', 'lightgoldenrodyellow':'#fafad2', 'lightgray':'#d3d3d3', 'lightgrey':'#d3d3d3', 'lightgreen':'#90ee90', 'lightpink':'#ffb6c1', 'lightsalmon':'#ffa07a', 'lightseagreen':'#20b2aa', 'lightskyblue':'#87cefa', 'lightslategray':'#778899', 'lightslategrey':'#778899', 'lightsteelblue':'#b0c4de', 'lightyellow':'#ffffe0', 'lime':'#00ff00', 'limegreen':'#32cd32', 'linen':'#faf0e6', 'magenta':'#ff00ff', 'maroon':'#800000', 'mediumaquamarine':'#66cdaa', 'mediumblue':'#0000cd', 'mediumorchid':'#ba55d3', 'mediumpurple':'#9370d8', 'mediumseagreen':'#3cb371', 'mediumslateblue':'#7b68ee', 'mediumspringgreen':'#00fa9a', 'mediumturquoise':'#48d1cc', 'mediumvioletred':'#c71585', 'midnightblue':'#191970', 'mintcream':'#f5fffa', 'mistyrose':'#ffe4e1', 'moccasin':'#ffe4b5', 'navajowhite':'#ffdead', 'navy':'#000080', 'oldlace':'#fdf5e6', 'olive':'#808000', 'olivedrab':'#6b8e23', 'orange':'#ffa500', 'orangered':'#ff4500', 'orchid':'#da70d6', 'palegoldenrod':'#eee8aa', 'palegreen':'#98fb98', 'paleturquoise':'#afeeee', 'palevioletred':'#d87093', 'papayawhip':'#ffefd5', 'peachpuff':'#ffdab9', 'peru':'#cd853f', 'pink':'#ffc0cb', 'plum':'#dda0dd', 'powderblue':'#b0e0e6', 'purple':'#800080', 'red':'#ff0000', 'rosybrown':'#bc8f8f', 'royalblue':'#4169e1', 'saddlebrown':'#8b4513', 'salmon':'#fa8072', 'sandybrown':'#f4a460', 'seagreen':'#2e8b57', 'seashell':'#fff5ee', 'sienna':'#a0522d', 'silver':'#c0c0c0', 'skyblue':'#87ceeb', 'slateblue':'#6a5acd', 'slategray':'#708090', 'slategrey':'#708090', 'snow':'#fffafa', 'springgreen':'#00ff7f', 'steelblue':'#4682b4', 'tan':'#d2b48c', 'teal':'#008080', 'thistle':'#d8bfd8', 'tomato':'#ff6347', // 'transparent':'rgba(0,0,0,0)', 'turquoise':'#40e0d0', 'violet':'#ee82ee', 'wheat':'#f5deb3', 'white':'#ffffff', 'whitesmoke':'#f5f5f5', 'yellow':'#ffff00', 'yellowgreen':'#9acd32' }; })(require('./tree')); (function (tree) { tree.Alpha = function (val) { this.value = val; }; tree.Alpha.prototype = { toCSS: function () { return "alpha(opacity=" + (this.value.toCSS ? this.value.toCSS() : this.value) + ")"; }, eval: function (env) { if (this.value.eval) { this.value = this.value.eval(env) } return this; } }; })(require('../tree')); (function (tree) { tree.Anonymous = function (string) { this.value = string.value || string; }; tree.Anonymous.prototype = { toCSS: function () { return this.value; }, eval: function () { return this }, compare: function (x) { if (!x.toCSS) { return -1; } var left = this.toCSS(), right = x.toCSS(); if (left === right) { return 0; } return left < right ? -1 : 1; } }; })(require('../tree')); (function (tree) { tree.Assignment = function (key, val) { this.key = key; this.value = val; }; tree.Assignment.prototype = { toCSS: function () { return this.key + '=' + (this.value.toCSS ? this.value.toCSS() : this.value); }, eval: function (env) { if (this.value.eval) { return new(tree.Assignment)(this.key, this.value.eval(env)); } return this; } }; })(require('../tree'));(function (tree) { // // A function call node. // tree.Call = function (name, args, index, filename) { this.name = name; this.args = args; this.index = index; this.filename = filename; }; tree.Call.prototype = { // // When evaluating a function call, // we either find the function in `tree.functions` [1], // in which case we call it, passing the evaluated arguments, // or we simply print it out as it appeared originally [2]. // // The *functions.js* file contains the built-in functions. // // The reason why we evaluate the arguments, is in the case where // we try to pass a variable to a function, like: `saturate(@color)`. // The function should receive the value, not the variable. // eval: function (env) { var args = this.args.map(function (a) { return a.eval(env) }); if (this.name in tree.functions) { // 1. try { return tree.functions[this.name].apply(tree.functions, args); } catch (e) { throw { type: e.type || "Runtime", message: "error evaluating function `" + this.name + "`" + (e.message ? ': ' + e.message : ''), index: this.index, filename: this.filename }; } } else { // 2. return new(tree.Anonymous)(this.name + "(" + args.map(function (a) { return a.toCSS(env) }).join(', ') + ")"); } }, toCSS: function (env) { return this.eval(env).toCSS(); } }; })(require('../tree')); (function (tree) { // // RGB Colors - #ff0014, #eee // tree.Color = function (rgb, a) { // // The end goal here, is to parse the arguments // into an integer triplet, such as `128, 255, 0` // // This facilitates operations and conversions. // if (Array.isArray(rgb)) { this.rgb = rgb; } else if (rgb.length == 6) { this.rgb = rgb.match(/.{2}/g).map(function (c) { return parseInt(c, 16); }); } else { this.rgb = rgb.split('').map(function (c) { return parseInt(c + c, 16); }); } this.alpha = typeof(a) === 'number' ? a : 1; }; tree.Color.prototype = { eval: function () { return this }, // // If we have some transparency, the only way to represent it // is via `rgba`. Otherwise, we use the hex representation, // which has better compatibility with older browsers. // Values are capped between `0` and `255`, rounded and zero-padded. // toCSS: function () { if (this.alpha < 1.0) { return "rgba(" + this.rgb.map(function (c) { return Math.round(c); }).concat(this.alpha).join(', ') + ")"; } else { return '#' + this.rgb.map(function (i) { i = Math.round(i); i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16); return i.length === 1 ? '0' + i : i; }).join(''); } }, // // Operations have to be done per-channel, if not, // channels will spill onto each other. Once we have // our result, in the form of an integer triplet, // we create a new Color node to hold the result. // operate: function (op, other) { var result = []; if (! (other instanceof tree.Color)) { other = other.toColor(); } for (var c = 0; c < 3; c++) { result[c] = tree.operate(op, this.rgb[c], other.rgb[c]); } return new(tree.Color)(result, this.alpha + other.alpha); }, toHSL: function () { var r = this.rgb[0] / 255, g = this.rgb[1] / 255, b = this.rgb[2] / 255, a = this.alpha; var max = Math.max(r, g, b), min = Math.min(r, g, b); var h, s, l = (max + min) / 2, d = max - min; if (max === min) { h = s = 0; } else { s = l > 0.5 ? d / (2 - max - min) : d / (max + min); switch (max) { case r: h = (g - b) / d + (g < b ? 6 : 0); break; case g: h = (b - r) / d + 2; break; case b: h = (r - g) / d + 4; break; } h /= 6; } return { h: h * 360, s: s, l: l, a: a }; }, toARGB: function () { var argb = [Math.round(this.alpha * 255)].concat(this.rgb); return '#' + argb.map(function (i) { i = Math.round(i); i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16); return i.length === 1 ? '0' + i : i; }).join(''); }, compare: function (x) { if (!x.rgb) { return -1; } return (x.rgb[0] === this.rgb[0] && x.rgb[1] === this.rgb[1] && x.rgb[2] === this.rgb[2] && x.alpha === this.alpha) ? 0 : -1; } }; })(require('../tree')); (function (tree) { tree.Comment = function (value, silent) { this.value = value; this.silent = !!silent; }; tree.Comment.prototype = { toCSS: function (env) { return env.compress ? '' : this.value; }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.Condition = function (op, l, r, i, negate) { this.op = op.trim(); this.lvalue = l; this.rvalue = r; this.index = i; this.negate = negate; }; tree.Condition.prototype.eval = function (env) { var a = this.lvalue.eval(env), b = this.rvalue.eval(env); var i = this.index, result; var result = (function (op) { switch (op) { case 'and': return a && b; case 'or': return a || b; default: if (a.compare) { result = a.compare(b); } else if (b.compare) { result = b.compare(a); } else { throw { type: "Type", message: "Unable to perform comparison", index: i }; } switch (result) { case -1: return op === '<' || op === '=<'; case 0: return op === '=' || op === '>=' || op === '=<'; case 1: return op === '>' || op === '>='; } } })(this.op); return this.negate ? !result : result; }; })(require('../tree')); (function (tree) { // // A number with a unit // tree.Dimension = function (value, unit) { this.value = parseFloat(value); this.unit = unit || null; }; tree.Dimension.prototype = { eval: function () { return this }, toColor: function () { return new(tree.Color)([this.value, this.value, this.value]); }, toCSS: function () { var css = this.value + this.unit; return css; }, // In an operation between two Dimensions, // we default to the first Dimension's unit, // so `1px + 2em` will yield `3px`. // In the future, we could implement some unit // conversions such that `100cm + 10mm` would yield // `101cm`. operate: function (op, other) { return new(tree.Dimension) (tree.operate(op, this.value, other.value), this.unit || other.unit); }, // TODO: Perform unit conversion before comparing compare: function (other) { if (other instanceof tree.Dimension) { if (other.value > this.value) { return -1; } else if (other.value < this.value) { return 1; } else { return 0; } } else { return -1; } } }; })(require('../tree')); (function (tree) { tree.Directive = function (name, value) { this.name = name; if (Array.isArray(value)) { this.ruleset = new(tree.Ruleset)([], value); this.ruleset.allowImports = true; } else { this.value = value; } }; tree.Directive.prototype = { toCSS: function (ctx, env) { if (this.ruleset) { this.ruleset.root = true; return this.name + (env.compress ? '{' : ' {\n ') + this.ruleset.toCSS(ctx, env).trim().replace(/\n/g, '\n ') + (env.compress ? '}': '\n}\n'); } else { return this.name + ' ' + this.value.toCSS() + ';\n'; } }, eval: function (env) { var evaldDirective = this; if (this.ruleset) { env.frames.unshift(this); evaldDirective = new(tree.Directive)(this.name); evaldDirective.ruleset = this.ruleset.eval(env); env.frames.shift(); } return evaldDirective; }, variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) }, find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) }, rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) } }; })(require('../tree')); (function (tree) { tree.Element = function (combinator, value, index) { this.combinator = combinator instanceof tree.Combinator ? combinator : new(tree.Combinator)(combinator); if (typeof(value) === 'string') { this.value = value.trim(); } else if (value) { this.value = value; } else { this.value = ""; } this.index = index; }; tree.Element.prototype.eval = function (env) { return new(tree.Element)(this.combinator, this.value.eval ? this.value.eval(env) : this.value, this.index); }; tree.Element.prototype.toCSS = function (env) { var value = (this.value.toCSS ? this.value.toCSS(env) : this.value); if (value == '' && this.combinator.value.charAt(0) == '&') { return ''; } else { return this.combinator.toCSS(env || {}) + value; } }; tree.Combinator = function (value) { if (value === ' ') { this.value = ' '; } else { this.value = value ? value.trim() : ""; } }; tree.Combinator.prototype.toCSS = function (env) { return { '' : '', ' ' : ' ', ':' : ' :', '+' : env.compress ? '+' : ' + ', '~' : env.compress ? '~' : ' ~ ', '>' : env.compress ? '>' : ' > ' }[this.value]; }; })(require('../tree')); (function (tree) { tree.Expression = function (value) { this.value = value }; tree.Expression.prototype = { eval: function (env) { if (this.value.length > 1) { return new(tree.Expression)(this.value.map(function (e) { return e.eval(env); })); } else if (this.value.length === 1) { return this.value[0].eval(env); } else { return this; } }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS ? e.toCSS(env) : ''; }).join(' '); } }; })(require('../tree')); (function (tree) { // // CSS @import node // // The general strategy here is that we don't want to wait // for the parsing to be completed, before we start importing // the file. That's because in the context of a browser, // most of the time will be spent waiting for the server to respond. // // On creation, we push the import path to our import queue, though // `import,push`, we also pass it a callback, which it'll call once // the file has been fetched, and parsed. // tree.Import = function (path, imports, features, once, index) { var that = this; this.once = once; this.index = index; this._path = path; this.features = features && new(tree.Value)(features); // The '.less' extension is optional if (path instanceof tree.Quoted) { this.path = /\.(le?|c)ss(\?.*)?$/.test(path.value) ? path.value : path.value + '.less'; } else { this.path = path.value.value || path.value; } this.css = /css(\?.*)?$/.test(this.path); // Only pre-compile .less files if (! this.css) { imports.push(this.path, function (e, root, imported) { if (e) { e.index = index } if (imported && that.once) that.skip = imported; that.root = root || new(tree.Ruleset)([], []); }); } }; // // The actual import node doesn't return anything, when converted to CSS. // The reason is that it's used at the evaluation stage, so that the rules // it imports can be treated like any other rules. // // In `eval`, we make sure all Import nodes get evaluated, recursively, so // we end up with a flat structure, which can easily be imported in the parent // ruleset. // tree.Import.prototype = { toCSS: function (env) { var features = this.features ? ' ' + this.features.toCSS(env) : ''; if (this.css) { return "@import " + this._path.toCSS() + features + ';\n'; } else { return ""; } }, eval: function (env) { var ruleset, features = this.features && this.features.eval(env); if (this.skip) return []; if (this.css) { return this; } else { ruleset = new(tree.Ruleset)([], this.root.rules.slice(0)); for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.Import) { Array.prototype .splice .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env))); } } return this.features ? new(tree.Media)(ruleset.rules, this.features.value) : ruleset.rules; } } }; })(require('../tree')); (function (tree) { tree.JavaScript = function (string, index, escaped) { this.escaped = escaped; this.expression = string; this.index = index; }; tree.JavaScript.prototype = { eval: function (env) { var result, that = this, context = {}; var expression = this.expression.replace(/@\{([\w-]+)\}/g, function (_, name) { return tree.jsify(new(tree.Variable)('@' + name, that.index).eval(env)); }); try { expression = new(Function)('return (' + expression + ')'); } catch (e) { throw { message: "JavaScript evaluation error: `" + expression + "`" , index: this.index }; } for (var k in env.frames[0].variables()) { context[k.slice(1)] = { value: env.frames[0].variables()[k].value, toJS: function () { return this.value.eval(env).toCSS(); } }; } try { result = expression.call(context); } catch (e) { throw { message: "JavaScript evaluation error: '" + e.name + ': ' + e.message + "'" , index: this.index }; } if (typeof(result) === 'string') { return new(tree.Quoted)('"' + result + '"', result, this.escaped, this.index); } else if (Array.isArray(result)) { return new(tree.Anonymous)(result.join(', ')); } else { return new(tree.Anonymous)(result); } } }; })(require('../tree')); (function (tree) { tree.Keyword = function (value) { this.value = value }; tree.Keyword.prototype = { eval: function () { return this }, toCSS: function () { return this.value }, compare: function (other) { if (other instanceof tree.Keyword) { return other.value === this.value ? 0 : 1; } else { return -1; } } }; tree.True = new(tree.Keyword)('true'); tree.False = new(tree.Keyword)('false'); })(require('../tree')); (function (tree) { tree.Media = function (value, features) { var selectors = this.emptySelectors(); this.features = new(tree.Value)(features); this.ruleset = new(tree.Ruleset)(selectors, value); this.ruleset.allowImports = true; }; tree.Media.prototype = { toCSS: function (ctx, env) { var features = this.features.toCSS(env); this.ruleset.root = (ctx.length === 0 || ctx[0].multiMedia); return '@media ' + features + (env.compress ? '{' : ' {\n ') + this.ruleset.toCSS(ctx, env).trim().replace(/\n/g, '\n ') + (env.compress ? '}': '\n}\n'); }, eval: function (env) { if (!env.mediaBlocks) { env.mediaBlocks = []; env.mediaPath = []; } var blockIndex = env.mediaBlocks.length; env.mediaPath.push(this); env.mediaBlocks.push(this); var media = new(tree.Media)([], []); if(this.debugInfo) { this.ruleset.debugInfo = this.debugInfo; media.debugInfo = this.debugInfo; } media.features = this.features.eval(env); env.frames.unshift(this.ruleset); media.ruleset = this.ruleset.eval(env); env.frames.shift(); env.mediaBlocks[blockIndex] = media; env.mediaPath.pop(); return env.mediaPath.length === 0 ? media.evalTop(env) : media.evalNested(env) }, variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) }, find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) }, rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) }, emptySelectors: function() { var el = new(tree.Element)('', '&', 0); return [new(tree.Selector)([el])]; }, evalTop: function (env) { var result = this; // Render all dependent Media blocks. if (env.mediaBlocks.length > 1) { var selectors = this.emptySelectors(); result = new(tree.Ruleset)(selectors, env.mediaBlocks); result.multiMedia = true; } delete env.mediaBlocks; delete env.mediaPath; return result; }, evalNested: function (env) { var i, value, path = env.mediaPath.concat([this]); // Extract the media-query conditions separated with `,` (OR). for (i = 0; i < path.length; i++) { value = path[i].features instanceof tree.Value ? path[i].features.value : path[i].features; path[i] = Array.isArray(value) ? value : [value]; } // Trace all permutations to generate the resulting media-query. // // (a, b and c) with nested (d, e) -> // a and d // a and e // b and c and d // b and c and e this.features = new(tree.Value)(this.permute(path).map(function (path) { path = path.map(function (fragment) { return fragment.toCSS ? fragment : new(tree.Anonymous)(fragment); }); for(i = path.length - 1; i > 0; i--) { path.splice(i, 0, new(tree.Anonymous)("and")); } return new(tree.Expression)(path); })); // Fake a tree-node that doesn't output anything. return new(tree.Ruleset)([], []); }, permute: function (arr) { if (arr.length === 0) { return []; } else if (arr.length === 1) { return arr[0]; } else { var result = []; var rest = this.permute(arr.slice(1)); for (var i = 0; i < rest.length; i++) { for (var j = 0; j < arr[0].length; j++) { result.push([arr[0][j]].concat(rest[i])); } } return result; } }, bubbleSelectors: function (selectors) { this.ruleset = new(tree.Ruleset)(selectors.slice(0), [this.ruleset]); } }; })(require('../tree')); (function (tree) { tree.mixin = {}; tree.mixin.Call = function (elements, args, index, filename, important) { this.selector = new(tree.Selector)(elements); this.arguments = args; this.index = index; this.filename = filename; this.important = important; }; tree.mixin.Call.prototype = { eval: function (env) { var mixins, args, rules = [], match = false; for (var i = 0; i < env.frames.length; i++) { if ((mixins = env.frames[i].find(this.selector)).length > 0) { args = this.arguments && this.arguments.map(function (a) { return { name: a.name, value: a.value.eval(env) }; }); for (var m = 0; m < mixins.length; m++) { if (mixins[m].match(args, env)) { try { Array.prototype.push.apply( rules, mixins[m].eval(env, this.arguments, this.important).rules); match = true; } catch (e) { throw { message: e.message, index: this.index, filename: this.filename, stack: e.stack }; } } } if (match) { return rules; } else { throw { type: 'Runtime', message: 'No matching definition was found for `' + this.selector.toCSS().trim() + '(' + this.arguments.map(function (a) { return a.toCSS(); }).join(', ') + ")`", index: this.index, filename: this.filename }; } } } throw { type: 'Name', message: this.selector.toCSS().trim() + " is undefined", index: this.index, filename: this.filename }; } }; tree.mixin.Definition = function (name, params, rules, condition, variadic) { this.name = name; this.selectors = [new(tree.Selector)([new(tree.Element)(null, name)])]; this.params = params; this.condition = condition; this.variadic = variadic; this.arity = params.length; this.rules = rules; this._lookups = {}; this.required = params.reduce(function (count, p) { if (!p.name || (p.name && !p.value)) { return count + 1 } else { return count } }, 0); this.parent = tree.Ruleset.prototype; this.frames = []; }; tree.mixin.Definition.prototype = { toCSS: function () { return "" }, variable: function (name) { return this.parent.variable.call(this, name) }, variables: function () { return this.parent.variables.call(this) }, find: function () { return this.parent.find.apply(this, arguments) }, rulesets: function () { return this.parent.rulesets.apply(this) }, evalParams: function (env, args) { var frame = new(tree.Ruleset)(null, []), varargs, arg; for (var i = 0, val, name; i < this.params.length; i++) { arg = args && args[i] if (arg && arg.name) { frame.rules.unshift(new(tree.Rule)(arg.name, arg.value.eval(env))); args.splice(i, 1); i--; continue; } if (name = this.params[i].name) { if (this.params[i].variadic && args) { varargs = []; for (var j = i; j < args.length; j++) { varargs.push(args[j].value.eval(env)); } frame.rules.unshift(new(tree.Rule)(name, new(tree.Expression)(varargs).eval(env))); } else if (val = (arg && arg.value) || this.params[i].value) { frame.rules.unshift(new(tree.Rule)(name, val.eval(env))); } else { throw { type: 'Runtime', message: "wrong number of arguments for " + this.name + ' (' + args.length + ' for ' + this.arity + ')' }; } } } return frame; }, eval: function (env, args, important) { var frame = this.evalParams(env, args), context, _arguments = [], rules, start; for (var i = 0; i < Math.max(this.params.length, args && args.length); i++) { _arguments.push((args[i] && args[i].value) || this.params[i].value); } frame.rules.unshift(new(tree.Rule)('@arguments', new(tree.Expression)(_arguments).eval(env))); rules = important ? this.rules.map(function (r) { return new(tree.Rule)(r.name, r.value, '!important', r.index); }) : this.rules.slice(0); return new(tree.Ruleset)(null, rules).eval({ frames: [this, frame].concat(this.frames, env.frames) }); }, match: function (args, env) { var argsLength = (args && args.length) || 0, len, frame; if (! this.variadic) { if (argsLength < this.required) { return false } if (argsLength > this.params.length) { return false } if ((this.required > 0) && (argsLength > this.params.length)) { return false } } if (this.condition && !this.condition.eval({ frames: [this.evalParams(env, args)].concat(env.frames) })) { return false } len = Math.min(argsLength, this.arity); for (var i = 0; i < len; i++) { if (!this.params[i].name) { if (args[i].value.eval(env).toCSS() != this.params[i].value.eval(env).toCSS()) { return false; } } } return true; } }; })(require('../tree')); (function (tree) { tree.Operation = function (op, operands) { this.op = op.trim(); this.operands = operands; }; tree.Operation.prototype.eval = function (env) { var a = this.operands[0].eval(env), b = this.operands[1].eval(env), temp; if (a instanceof tree.Dimension && b instanceof tree.Color) { if (this.op === '*' || this.op === '+') { temp = b, b = a, a = temp; } else { throw { name: "OperationError", message: "Can't substract or divide a color from a number" }; } } return a.operate(this.op, b); }; tree.operate = function (op, a, b) { switch (op) { case '+': return a + b; case '-': return a - b; case '*': return a * b; case '/': return a / b; } }; })(require('../tree')); (function (tree) { tree.Paren = function (node) { this.value = node; }; tree.Paren.prototype = { toCSS: function (env) { return '(' + this.value.toCSS(env) + ')'; }, eval: function (env) { return new(tree.Paren)(this.value.eval(env)); } }; })(require('../tree')); (function (tree) { tree.Quoted = function (str, content, escaped, i) { this.escaped = escaped; this.value = content || ''; this.quote = str.charAt(0); this.index = i; }; tree.Quoted.prototype = { toCSS: function () { if (this.escaped) { return this.value; } else { return this.quote + this.value + this.quote; } }, eval: function (env) { var that = this; var value = this.value.replace(/`([^`]+)`/g, function (_, exp) { return new(tree.JavaScript)(exp, that.index, true).eval(env).value; }).replace(/@\{([\w-]+)\}/g, function (_, name) { var v = new(tree.Variable)('@' + name, that.index).eval(env); return ('value' in v) ? v.value : v.toCSS(); }); return new(tree.Quoted)(this.quote + value + this.quote, value, this.escaped, this.index); }, compare: function (x) { if (!x.toCSS) { return -1; } var left = this.toCSS(), right = x.toCSS(); if (left === right) { return 0; } return left < right ? -1 : 1; } }; })(require('../tree')); (function (tree) { tree.Ratio = function (value) { this.value = value; }; tree.Ratio.prototype = { toCSS: function (env) { return this.value; }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.Rule = function (name, value, important, index, inline) { this.name = name; this.value = (value instanceof tree.Value) ? value : new(tree.Value)([value]); this.important = important ? ' ' + important.trim() : ''; this.index = index; this.inline = inline || false; if (name.charAt(0) === '@') { this.variable = true; } else { this.variable = false } }; tree.Rule.prototype.toCSS = function (env) { if (this.variable) { return "" } else { return this.name + (env.compress ? ':' : ': ') + this.value.toCSS(env) + this.important + (this.inline ? "" : ";"); } }; tree.Rule.prototype.eval = function (context) { return new(tree.Rule)(this.name, this.value.eval(context), this.important, this.index, this.inline); }; tree.Shorthand = function (a, b) { this.a = a; this.b = b; }; tree.Shorthand.prototype = { toCSS: function (env) { return this.a.toCSS(env) + "/" + this.b.toCSS(env); }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.Ruleset = function (selectors, rules, strictImports) { this.selectors = selectors; this.rules = rules; this._lookups = {}; this.strictImports = strictImports; }; tree.Ruleset.prototype = { eval: function (env) { var selectors = this.selectors && this.selectors.map(function (s) { return s.eval(env) }); var ruleset = new(tree.Ruleset)(selectors, this.rules.slice(0), this.strictImports); var rules = []; ruleset.root = this.root; ruleset.allowImports = this.allowImports; if(this.debugInfo) { ruleset.debugInfo = this.debugInfo; } // push the current ruleset to the frames stack env.frames.unshift(ruleset); // Evaluate imports if (ruleset.root || ruleset.allowImports || !ruleset.strictImports) { for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.Import) { rules = rules.concat(ruleset.rules[i].eval(env)); } else { rules.push(ruleset.rules[i]); } } ruleset.rules = rules; rules = []; } // Store the frames around mixin definitions, // so they can be evaluated like closures when the time comes. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Definition) { ruleset.rules[i].frames = env.frames.slice(0); } } var mediaBlockCount = (env.mediaBlocks && env.mediaBlocks.length) || 0; // Evaluate mixin calls. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Call) { rules = rules.concat(ruleset.rules[i].eval(env)); } else { rules.push(ruleset.rules[i]); } } ruleset.rules = rules; // Evaluate everything else for (var i = 0, rule; i < ruleset.rules.length; i++) { rule = ruleset.rules[i]; if (! (rule instanceof tree.mixin.Definition)) { ruleset.rules[i] = rule.eval ? rule.eval(env) : rule; } } // Pop the stack env.frames.shift(); if (env.mediaBlocks) { for(var i = mediaBlockCount; i < env.mediaBlocks.length; i++) { env.mediaBlocks[i].bubbleSelectors(selectors); } } return ruleset; }, match: function (args) { return !args || args.length === 0; }, variables: function () { if (this._variables) { return this._variables } else { return this._variables = this.rules.reduce(function (hash, r) { if (r instanceof tree.Rule && r.variable === true) { hash[r.name] = r; } return hash; }, {}); } }, variable: function (name) { return this.variables()[name]; }, rulesets: function () { if (this._rulesets) { return this._rulesets } else { return this._rulesets = this.rules.filter(function (r) { return (r instanceof tree.Ruleset) || (r instanceof tree.mixin.Definition); }); } }, find: function (selector, self) { self = self || this; var rules = [], rule, match, key = selector.toCSS(); if (key in this._lookups) { return this._lookups[key] } this.rulesets().forEach(function (rule) { if (rule !== self) { for (var j = 0; j < rule.selectors.length; j++) { if (match = selector.match(rule.selectors[j])) { if (selector.elements.length > rule.selectors[j].elements.length) { Array.prototype.push.apply(rules, rule.find( new(tree.Selector)(selector.elements.slice(1)), self)); } else { rules.push(rule); } break; } } } }); return this._lookups[key] = rules; }, // // Entry point for code generation // // `context` holds an array of arrays. // toCSS: function (context, env) { var css = [], // The CSS output rules = [], // node.Rule instances _rules = [], // rulesets = [], // node.Ruleset instances paths = [], // Current selectors selector, // The fully rendered selector debugInfo, // Line number debugging rule; if (! this.root) { this.joinSelectors(paths, context, this.selectors); } // Compile rules and rulesets for (var i = 0; i < this.rules.length; i++) { rule = this.rules[i]; if (rule.rules || (rule instanceof tree.Directive) || (rule instanceof tree.Media)) { rulesets.push(rule.toCSS(paths, env)); } else if (rule instanceof tree.Comment) { if (!rule.silent) { if (this.root) { rulesets.push(rule.toCSS(env)); } else { rules.push(rule.toCSS(env)); } } } else { if (rule.toCSS && !rule.variable) { rules.push(rule.toCSS(env)); } else if (rule.value && !rule.variable) { rules.push(rule.value.toString()); } } } rulesets = rulesets.join(''); // If this is the root node, we don't render // a selector, or {}. // Otherwise, only output if this ruleset has rules. if (this.root) { css.push(rules.join(env.compress ? '' : '\n')); } else { if (rules.length > 0) { debugInfo = tree.debugInfo(env, this); selector = paths.map(function (p) { return p.map(function (s) { return s.toCSS(env); }).join('').trim(); }).join(env.compress ? ',' : ',\n'); // Remove duplicates for (var i = rules.length - 1; i >= 0; i--) { if (_rules.indexOf(rules[i]) === -1) { _rules.unshift(rules[i]); } } rules = _rules; css.push(debugInfo + selector + (env.compress ? '{' : ' {\n ') + rules.join(env.compress ? '' : '\n ') + (env.compress ? '}' : '\n}\n')); } } css.push(rulesets); return css.join('') + (env.compress ? '\n' : ''); }, joinSelectors: function (paths, context, selectors) { for (var s = 0; s < selectors.length; s++) { this.joinSelector(paths, context, selectors[s]); } }, joinSelector: function (paths, context, selector) { var i, j, k, hasParentSelector, newSelectors, el, sel, parentSel, newSelectorPath, afterParentJoin, newJoinedSelector, newJoinedSelectorEmpty, lastSelector, currentElements, selectorsMultiplied; for (i = 0; i < selector.elements.length; i++) { el = selector.elements[i]; if (el.value === '&') { hasParentSelector = true; } } if (!hasParentSelector) { if (context.length > 0) { for(i = 0; i < context.length; i++) { paths.push(context[i].concat(selector)); } } else { paths.push([selector]); } return; } // The paths are [[Selector]] // The first list is a list of comma seperated selectors // The inner list is a list of inheritance seperated selectors // e.g. // .a, .b { // .c { // } // } // == [[.a] [.c]] [[.b] [.c]] // // the elements from the current selector so far currentElements = []; // the current list of new selectors to add to the path. // We will build it up. We initiate it with one empty selector as we "multiply" the new selectors // by the parents newSelectors = [[]]; for (i = 0; i < selector.elements.length; i++) { el = selector.elements[i]; // non parent reference elements just get added if (el.value !== "&") { currentElements.push(el); } else { // the new list of selectors to add selectorsMultiplied = []; // merge the current list of non parent selector elements // on to the current list of selectors to add if (currentElements.length > 0) { this.mergeElementsOnToSelectors(currentElements, newSelectors); } // loop through our current selectors for(j = 0; j < newSelectors.length; j++) { sel = newSelectors[j]; // if we don't have any parent paths, the & might be in a mixin so that it can be used // whether there are parents or not if (context.length == 0) { // the combinator used on el should now be applied to the next element instead so that // it is not lost if (sel.length > 0) { sel[0].elements = sel[0].elements.slice(0); sel[0].elements.push(new(tree.Element)(el.combinator, '', 0)); //new Element(el.Combinator, "")); } selectorsMultiplied.push(sel); } else { // and the parent selectors for(k = 0; k < context.length; k++) { parentSel = context[k]; // We need to put the current selectors // then join the last selector's elements on to the parents selectors // our new selector path newSelectorPath = []; // selectors from the parent after the join afterParentJoin = []; newJoinedSelectorEmpty = true; //construct the joined selector - if & is the first thing this will be empty, // if not newJoinedSelector will be the last set of elements in the selector if (sel.length > 0) { newSelectorPath = sel.slice(0); lastSelector = newSelectorPath.pop(); newJoinedSelector = new(tree.Selector)(lastSelector.elements.slice(0)); newJoinedSelectorEmpty = false; } else { newJoinedSelector = new(tree.Selector)([]); } //put together the parent selectors after the join if (parentSel.length > 1) { afterParentJoin = afterParentJoin.concat(parentSel.slice(1)); } if (parentSel.length > 0) { newJoinedSelectorEmpty = false; // join the elements so far with the first part of the parent newJoinedSelector.elements.push(new(tree.Element)(el.combinator, parentSel[0].elements[0].value, 0)); newJoinedSelector.elements = newJoinedSelector.elements.concat(parentSel[0].elements.slice(1)); } if (!newJoinedSelectorEmpty) { // now add the joined selector newSelectorPath.push(newJoinedSelector); } // and the rest of the parent newSelectorPath = newSelectorPath.concat(afterParentJoin); // add that to our new set of selectors selectorsMultiplied.push(newSelectorPath); } } } // our new selectors has been multiplied, so reset the state newSelectors = selectorsMultiplied; currentElements = []; } } // if we have any elements left over (e.g. .a& .b == .b) // add them on to all the current selectors if (currentElements.length > 0) { this.mergeElementsOnToSelectors(currentElements, newSelectors); } for(i = 0; i < newSelectors.length; i++) { paths.push(newSelectors[i]); } }, mergeElementsOnToSelectors: function(elements, selectors) { var i, sel; if (selectors.length == 0) { selectors.push([ new(tree.Selector)(elements) ]); return; } for(i = 0; i < selectors.length; i++) { sel = selectors[i]; // if the previous thing in sel is a parent this needs to join on to it if (sel.length > 0) { sel[sel.length - 1] = new(tree.Selector)(sel[sel.length - 1].elements.concat(elements)); } else { sel.push(new(tree.Selector)(elements)); } } } }; })(require('../tree')); (function (tree) { tree.Selector = function (elements) { this.elements = elements; }; tree.Selector.prototype.match = function (other) { var len = this.elements.length, olen = other.elements.length, max = Math.min(len, olen); if (len < olen) { return false; } else { for (var i = 0; i < max; i++) { if (this.elements[i].value !== other.elements[i].value) { return false; } } } return true; }; tree.Selector.prototype.eval = function (env) { return new(tree.Selector)(this.elements.map(function (e) { return e.eval(env); })); }; tree.Selector.prototype.toCSS = function (env) { if (this._css) { return this._css } if (this.elements[0].combinator.value === "") { this._css = ' '; } else { this._css = ''; } this._css += this.elements.map(function (e) { if (typeof(e) === 'string') { return ' ' + e.trim(); } else { return e.toCSS(env); } }).join(''); return this._css; }; })(require('../tree')); (function (tree) { tree.URL = function (val, paths) { this.value = val; this.paths = paths; }; tree.URL.prototype = { toCSS: function () { return "url(" + this.value.toCSS() + ")"; }, eval: function (ctx) { var val = this.value.eval(ctx); // Add the base path if the URL is relative and we are in the browser if (typeof window !== 'undefined' && typeof val.value === "string" && !/^(?:[a-z-]+:|\/)/.test(val.value) && this.paths.length > 0) { val.value = this.paths[0] + (val.value.charAt(0) === '/' ? val.value.slice(1) : val.value); } return new(tree.URL)(val, this.paths); } }; })(require('../tree')); (function (tree) { tree.Value = function (value) { this.value = value; this.is = 'value'; }; tree.Value.prototype = { eval: function (env) { if (this.value.length === 1) { return this.value[0].eval(env); } else { return new(tree.Value)(this.value.map(function (v) { return v.eval(env); })); } }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS(env); }).join(env.compress ? ',' : ', '); } }; })(require('../tree')); (function (tree) { tree.Variable = function (name, index, file) { this.name = name, this.index = index, this.file = file }; tree.Variable.prototype = { eval: function (env) { var variable, v, name = this.name; if (name.indexOf('@@') == 0) { name = '@' + new(tree.Variable)(name.slice(1)).eval(env).value; } if (variable = tree.find(env.frames, function (frame) { if (v = frame.variable(name)) { return v.value.eval(env); } })) { return variable } else { throw { type: 'Name', message: "variable " + name + " is undefined", filename: this.file, index: this.index }; } } }; })(require('../tree')); (function (tree) { tree.debugInfo = function(env, ctx) { var result=""; if (env.dumpLineNumbers && !env.compress) { switch(env.dumpLineNumbers) { case 'comments': result = tree.debugInfo.asComment(ctx); break; case 'mediaquery': result = tree.debugInfo.asMediaQuery(ctx); break; case 'all': result = tree.debugInfo.asComment(ctx)+tree.debugInfo.asMediaQuery(ctx); break; } } return result; }; tree.debugInfo.asComment = function(ctx) { return '/* line ' + ctx.debugInfo.lineNumber + ', ' + ctx.debugInfo.fileName + ' */\n'; }; tree.debugInfo.asMediaQuery = function(ctx) { return '@media -sass-debug-info{filename{font-family:"' + ctx.debugInfo.fileName + '";}line{font-family:"' + ctx.debugInfo.lineNumber + '";}}\n'; }; tree.find = function (obj, fun) { for (var i = 0, r; i < obj.length; i++) { if (r = fun.call(obj, obj[i])) { return r } } return null; }; tree.jsify = function (obj) { if (Array.isArray(obj.value) && (obj.value.length > 1)) { return '[' + obj.value.map(function (v) { return v.toCSS(false) }).join(', ') + ']'; } else { return obj.toCSS(false); } }; })(require('./tree')); // // browser.js - client-side engine // var isFileProtocol = /^(file|chrome(-extension)?|resource|qrc|app):/.test(location.protocol); less.env = less.env || (location.hostname == '127.0.0.1' || location.hostname == '0.0.0.0' || location.hostname == 'localhost' || location.port.length > 0 || isFileProtocol ? 'development' : 'production'); // Load styles asynchronously (default: false) // // This is set to `false` by default, so that the body // doesn't start loading before the stylesheets are parsed. // Setting this to `true` can result in flickering. // less.async = less.async || false; less.fileAsync = less.fileAsync || false; // Interval between watch polls less.poll = less.poll || (isFileProtocol ? 1000 : 1500); // // Watch mode // less.watch = function () { return this.watchMode = true }; less.unwatch = function () { return this.watchMode = false }; if (less.env === 'development') { less.optimization = 0; if (/!watch/.test(location.hash)) { less.watch(); } var dumpLineNumbers = /!dumpLineNumbers:(comments|mediaquery|all)/.exec(location.hash); if (dumpLineNumbers) { less.dumpLineNumbers = dumpLineNumbers[1]; } less.watchTimer = setInterval(function () { if (less.watchMode) { loadStyleSheets(function (e, root, _, sheet, env) { if (root) { createCSS(root.toCSS(), sheet, env.lastModified); } }); } }, less.poll); } else { less.optimization = 3; } var cache; try { cache = (typeof(window.localStorage) === 'undefined') ? null : window.localStorage; } catch (_) { cache = null; } // // Get all tags with the 'rel' attribute set to "stylesheet/less" // var links = document.getElementsByTagName('link'); var typePattern = /^text\/(x-)?less$/; less.sheets = []; for (var i = 0; i < links.length; i++) { if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) && (links[i].type.match(typePattern)))) { less.sheets.push(links[i]); } } less.refresh = function (reload) { var startTime, endTime; startTime = endTime = new(Date); loadStyleSheets(function (e, root, _, sheet, env) { if (env.local) { log("loading " + sheet.href + " from cache."); } else { log("parsed " + sheet.href + " successfully."); createCSS(root.toCSS(), sheet, env.lastModified); } log("css for " + sheet.href + " generated in " + (new(Date) - endTime) + 'ms'); (env.remaining === 0) && log("css generated in " + (new(Date) - startTime) + 'ms'); endTime = new(Date); }, reload); loadStyles(); }; less.refreshStyles = loadStyles; less.refresh(less.env === 'development'); function loadStyles() { var styles = document.getElementsByTagName('style'); for (var i = 0; i < styles.length; i++) { if (styles[i].type.match(typePattern)) { new(less.Parser)({ filename: document.location.href.replace(/#.*$/, ''), dumpLineNumbers: less.dumpLineNumbers }).parse(styles[i].innerHTML || '', function (e, tree) { var css = tree.toCSS(); var style = styles[i]; style.type = 'text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.innerHTML = css; } }); } } } function loadStyleSheets(callback, reload) { for (var i = 0; i < less.sheets.length; i++) { loadStyleSheet(less.sheets[i], callback, reload, less.sheets.length - (i + 1)); } } function loadStyleSheet(sheet, callback, reload, remaining) { var contents = sheet.contents || {}; // Passing a ref to top importing parser content cache trough 'sheet' arg. var url = window.location.href.replace(/[#?].*$/, ''); var href = sheet.href.replace(/\?.*$/, ''); var css = cache && cache.getItem(href); var timestamp = cache && cache.getItem(href + ':timestamp'); var styles = { css: css, timestamp: timestamp }; // Stylesheets in IE don't always return the full path if (! /^[a-z-]+:/.test(href)) { if (href.charAt(0) == "/") { href = window.location.protocol + "//" + window.location.host + href; } else { href = url.slice(0, url.lastIndexOf('/') + 1) + href; } } xhr(sheet.href, sheet.type, function (data, lastModified) { if (!reload && styles && lastModified && (new(Date)(lastModified).valueOf() === new(Date)(styles.timestamp).valueOf())) { // Use local copy createCSS(styles.css, sheet); callback(null, null, data, sheet, { local: true, remaining: remaining }); } else { // Use remote copy (re-parse) try { contents[href] = data; // Updating top importing parser content cache new(less.Parser)({ optimization: less.optimization, paths: [href.replace(/[\w\.-]+$/, '')], mime: sheet.type, filename: href, 'contents': contents, // Passing top importing parser content cache ref down. dumpLineNumbers: less.dumpLineNumbers }).parse(data, function (e, root) { if (e) { return error(e, href) } try { callback(e, root, data, sheet, { local: false, lastModified: lastModified, remaining: remaining }); removeNode(document.getElementById('less-error-message:' + extractId(href))); } catch (e) { error(e, href); } }); } catch (e) { error(e, href); } } }, function (status, url) { throw new(Error)("Couldn't load " + url + " (" + status + ")"); }); } function extractId(href) { return href.replace(/^[a-z]+:\/\/?[^\/]+/, '' ) // Remove protocol & domain .replace(/^\//, '' ) // Remove root / .replace(/\?.*$/, '' ) // Remove query .replace(/\.[^\.\/]+$/, '' ) // Remove file extension .replace(/[^\.\w-]+/g, '-') // Replace illegal characters .replace(/\./g, ':'); // Replace dots with colons(for valid id) } function createCSS(styles, sheet, lastModified) { var css; // Strip the query-string var href = sheet.href ? sheet.href.replace(/\?.*$/, '') : ''; // If there is no title set, use the filename, minus the extension var id = 'less:' + (sheet.title || extractId(href)); // If the stylesheet doesn't exist, create a new node if ((css = document.getElementById(id)) === null) { css = document.createElement('style'); css.type = 'text/css'; if( sheet.media ){ css.media = sheet.media; } css.id = id; var nextEl = sheet && sheet.nextSibling || null; document.getElementsByTagName('head')[0].insertBefore(css, nextEl); } if (css.styleSheet) { // IE try { css.styleSheet.cssText = styles; } catch (e) { throw new(Error)("Couldn't reassign styleSheet.cssText."); } } else { (function (node) { if (css.childNodes.length > 0) { if (css.firstChild.nodeValue !== node.nodeValue) { css.replaceChild(node, css.firstChild); } } else { css.appendChild(node); } })(document.createTextNode(styles)); } // Don't update the local store if the file wasn't modified if (lastModified && cache) { log('saving ' + href + ' to cache.'); try { cache.setItem(href, styles); cache.setItem(href + ':timestamp', lastModified); } catch(e) { //TODO - could do with adding more robust error handling log('failed to save'); } } } function xhr(url, type, callback, errback) { var xhr = getXMLHttpRequest(); var async = isFileProtocol ? less.fileAsync : less.async; if (typeof(xhr.overrideMimeType) === 'function') { xhr.overrideMimeType('text/css'); } xhr.open('GET', url, async); xhr.setRequestHeader('Accept', type || 'text/x-less, text/css; q=0.9, */*; q=0.5'); xhr.send(null); if (isFileProtocol && !less.fileAsync) { if (xhr.status === 0 || (xhr.status >= 200 && xhr.status < 300)) { callback(xhr.responseText); } else { errback(xhr.status, url); } } else if (async) { xhr.onreadystatechange = function () { if (xhr.readyState == 4) { handleResponse(xhr, callback, errback); } }; } else { handleResponse(xhr, callback, errback); } function handleResponse(xhr, callback, errback) { if (xhr.status >= 200 && xhr.status < 300) { callback(xhr.responseText, xhr.getResponseHeader("Last-Modified")); } else if (typeof(errback) === 'function') { errback(xhr.status, url); } } } function getXMLHttpRequest() { if (window.XMLHttpRequest) { return new(XMLHttpRequest); } else { try { return new(ActiveXObject)("MSXML2.XMLHTTP.3.0"); } catch (e) { log("browser doesn't support AJAX."); return null; } } } function removeNode(node) { return node && node.parentNode.removeChild(node); } function log(str) { if (less.env == 'development' && typeof(console) !== "undefined") { console.log('less: ' + str) } } function error(e, href) { var id = 'less-error-message:' + extractId(href); var template = '
  • {content}
  • '; var elem = document.createElement('div'), timer, content, error = []; var filename = e.filename || href; var filenameNoPath = filename.match(/([^\/]+)$/)[1]; elem.id = id; elem.className = "less-error-message"; content = '

    ' + (e.message || 'There is an error in your .less file') + '

    ' + '

    in ' + filenameNoPath + " "; var errorline = function (e, i, classname) { if (e.extract[i]) { error.push(template.replace(/\{line\}/, parseInt(e.line) + (i - 1)) .replace(/\{class\}/, classname) .replace(/\{content\}/, e.extract[i])); } }; if (e.stack) { content += '
    ' + e.stack.split('\n').slice(1).join('
    '); } else if (e.extract) { errorline(e, 0, ''); errorline(e, 1, 'line'); errorline(e, 2, ''); content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':

    ' + '
      ' + error.join('') + '
    '; } elem.innerHTML = content; // CSS for error messages createCSS([ '.less-error-message ul, .less-error-message li {', 'list-style-type: none;', 'margin-right: 15px;', 'padding: 4px 0;', 'margin: 0;', '}', '.less-error-message label {', 'font-size: 12px;', 'margin-right: 15px;', 'padding: 4px 0;', 'color: #cc7777;', '}', '.less-error-message pre {', 'color: #dd6666;', 'padding: 4px 0;', 'margin: 0;', 'display: inline-block;', '}', '.less-error-message pre.line {', 'color: #ff0000;', '}', '.less-error-message h3 {', 'font-size: 20px;', 'font-weight: bold;', 'padding: 15px 0 5px 0;', 'margin: 0;', '}', '.less-error-message a {', 'color: #10a', '}', '.less-error-message .error {', 'color: red;', 'font-weight: bold;', 'padding-bottom: 2px;', 'border-bottom: 1px dashed red;', '}' ].join('\n'), { title: 'error-message' }); elem.style.cssText = [ "font-family: Arial, sans-serif", "border: 1px solid #e00", "background-color: #eee", "border-radius: 5px", "-webkit-border-radius: 5px", "-moz-border-radius: 5px", "color: #e00", "padding: 15px", "margin-bottom: 15px" ].join(';'); if (less.env == 'development') { timer = setInterval(function () { if (document.body) { if (document.getElementById(id)) { document.body.replaceChild(elem, document.getElementById(id)); } else { document.body.insertBefore(elem, document.body.firstChild); } clearInterval(timer); } }, 10); } } // amd.js // // Define Less as an AMD module. if (typeof define === "function" && define.amd) { define("less", [], function () { return less; } ); } })(window); less.js-1.4.2/dist/less-1.3.1.min.js000066400000000000000000001510611217256642200166010ustar00rootroot00000000000000// // LESS - Leaner CSS v1.3.1 // http://lesscss.org // // Copyright (c) 2009-2011, Alexis Sellier // Licensed under the Apache 2.0 License. // (function(e,t){function n(t){return e.less[t.split("/")[1]]}function h(){var e=document.getElementsByTagName("style");for(var t=0;t0?r.firstChild.nodeValue!==e.nodeValue&&r.replaceChild(e,r.firstChild):r.appendChild(e)})(document.createTextNode(e));if(n&&u){w("saving "+i+" to cache.");try{u.setItem(i,e),u.setItem(i+":timestamp",n)}catch(a){w("failed to save")}}}function g(e,t,n,i){function a(t,n,r){t.status>=200&&t.status<300?n(t.responseText,t.getResponseHeader("Last-Modified")):typeof r=="function"&&r(t.status,e)}var o=y(),u=s?r.fileAsync:r.async;typeof o.overrideMimeType=="function"&&o.overrideMimeType("text/css"),o.open("GET",e,u),o.setRequestHeader("Accept",t||"text/x-less, text/css; q=0.9, */*; q=0.5"),o.send(null),s&&!r.fileAsync?o.status===0||o.status>=200&&o.status<300?n(o.responseText):i(o.status,e):u?o.onreadystatechange=function(){o.readyState==4&&a(o,n,i)}:a(o,n,i)}function y(){if(e.XMLHttpRequest)return new XMLHttpRequest;try{return new ActiveXObject("MSXML2.XMLHTTP.3.0")}catch(t){return w("browser doesn't support AJAX."),null}}function b(e){return e&&e.parentNode.removeChild(e)}function w(e){r.env=="development"&&typeof console!="undefined"&&console.log("less: "+e)}function E(e,t){var n="less-error-message:"+v(t),i='
  • {content}
  • ',s=document.createElement("div"),o,u,a=[],f=e.filename||t,l=f.match(/([^\/]+)$/)[1];s.id=n,s.className="less-error-message",u="

    "+(e.message||"There is an error in your .less file")+"

    "+'

    in '+l+" ";var c=function(e,t,n){e.extract[t]&&a.push(i.replace(/\{line\}/,parseInt(e.line)+(t-1)).replace(/\{class\}/,n).replace(/\{content\}/,e.extract[t]))};e.stack?u+="
    "+e.stack.split("\n").slice(1).join("
    "):e.extract&&(c(e,0,""),c(e,1,"line"),c(e,2,""),u+="on line "+e.line+", column "+(e.column+1)+":

    "+"
      "+a.join("")+"
    "),s.innerHTML=u,m([".less-error-message ul, .less-error-message li {","list-style-type: none;","margin-right: 15px;","padding: 4px 0;","margin: 0;","}",".less-error-message label {","font-size: 12px;","margin-right: 15px;","padding: 4px 0;","color: #cc7777;","}",".less-error-message pre {","color: #dd6666;","padding: 4px 0;","margin: 0;","display: inline-block;","}",".less-error-message pre.line {","color: #ff0000;","}",".less-error-message h3 {","font-size: 20px;","font-weight: bold;","padding: 15px 0 5px 0;","margin: 0;","}",".less-error-message a {","color: #10a","}",".less-error-message .error {","color: red;","font-weight: bold;","padding-bottom: 2px;","border-bottom: 1px dashed red;","}"].join("\n"),{title:"error-message"}),s.style.cssText=["font-family: Arial, sans-serif","border: 1px solid #e00","background-color: #eee","border-radius: 5px","-webkit-border-radius: 5px","-moz-border-radius: 5px","color: #e00","padding: 15px","margin-bottom: 15px"].join(";"),r.env=="development"&&(o=setInterval(function(){document.body&&(document.getElementById(n)?document.body.replaceChild(s,document.getElementById(n)):document.body.insertBefore(s,document.body.firstChild),clearInterval(o))},10))}Array.isArray||(Array.isArray=function(e){return Object.prototype.toString.call(e)==="[object Array]"||e instanceof Array}),Array.prototype.forEach||(Array.prototype.forEach=function(e,t){var n=this.length>>>0;for(var r=0;r>>0,n=new Array(t),r=arguments[1];for(var i=0;i>>0,n=0;if(t===0&&arguments.length===1)throw new TypeError;if(arguments.length>=2)var r=arguments[1];else do{if(n in this){r=this[n++];break}if(++n>=t)throw new TypeError}while(!0);for(;n=t)return-1;n<0&&(n+=t);for(;nh&&(c[u]=c[u].slice(o-h),h=o)}function w(e){var t=e.charCodeAt(0);return t===32||t===10||t===9}function E(e){var t,n,r,i,a;if(e instanceof Function)return e.call(p.parsers);if(typeof e=="string")t=s.charAt(o)===e?e:null,r=1,b();else{b();if(!(t=e.exec(c[u])))return null;r=t[0].length}if(t)return S(r),typeof t=="string"?t:t.length===1?t[0]:t}function S(e){var t=o,n=u,r=o+c[u].length,i=o+=e;while(o=0&&t.charAt(n)!=="\n";n--)r++;return{line:typeof e=="number"?(t.slice(0,e).match(/\n/g)||"").length:null,column:r}}function L(e){return r.mode==="browser"||r.mode==="rhino"?e.filename:n("path").resolve(e.filename)}function A(e,t,n){return{lineNumber:k(e,t).line+1,fileName:L(n)}}function O(e,t){var n=C(e,t),r=k(e.index,n),i=r.line,s=r.column,o=n.split("\n");this.type=e.type||"Syntax",this.message=e.message,this.filename=e.filename||t.filename,this.index=e.index,this.line=typeof i=="number"?i+1:null,this.callLine=e.call&&k(e.call,n).line+1,this.callExtract=o[k(e.call,n).line],this.stack=e.stack,this.column=s,this.extract=[o[i-1],o[i],o[i+1]]}var s,o,u,a,f,l,c,h,p,d=this,t=t||{};t.contents||(t.contents={});var v=function(){},m=this.imports={paths:t&&t.paths||[],queue:[],files:{},contents:t.contents,mime:t&&t.mime,error:null,push:function(e,n){var i=this;this.queue.push(e),r.Parser.importer(e,this.paths,function(t,r){i.queue.splice(i.queue.indexOf(e),1);var s=e in i.files;i.files[e]=r,t&&!i.error&&(i.error=t),n(t,r,s),i.queue.length===0&&v(t)},t)}};return this.env=t=t||{},this.optimization="optimization"in this.env?this.env.optimization:1,this.env.filename=this.env.filename||null,p={imports:m,parse:function(e,a){var f,d,m,g,y,b,w=[],S,x=null;o=u=h=l=0,s=e.replace(/\r\n/g,"\n"),s=s.replace(/^\uFEFF/,""),c=function(e){var n=0,r=/(?:@\{[\w-]+\}|[^"'`\{\}\/\(\)\\])+/g,i=/\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g,o=/"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'|`((?:[^`]|\\.)*)`/g,u=0,a,f=e[0],l;for(var c=0,h,p;c0&&(x=new O({index:c,type:"Parse",message:"missing closing `}`",filename:t.filename},t)),e.map(function(e){return e.join("")})}([[]]);if(x)return a(x);try{f=new i.Ruleset([],E(this.parsers.primary)),f.root=!0}catch(T){return a(new O(T,t))}f.toCSS=function(e){var s,o,u;return function(s,o){var u=[],a;s=s||{},typeof o=="object"&&!Array.isArray(o)&&(o=Object.keys(o).map(function(e){var t=o[e];return t instanceof i.Value||(t instanceof i.Expression||(t=new i.Expression([t])),t=new i.Value([t])),new i.Rule("@"+e,t,!1,0)}),u=[new i.Ruleset(null,o)]);try{var f=e.call(this,{frames:u}).toCSS([],{compress:s.compress||!1,dumpLineNumbers:t.dumpLineNumbers})}catch(l){throw new O(l,t)}if(a=p.imports.error)throw a instanceof O?a:new O(a,t);return s.yuicompress&&r.mode==="node"?n("./cssmin").compressor.cssmin(f):s.compress?f.replace(/(\s)+/g,"$1"):f}}(f.eval);if(o=0&&s.charAt(N)!=="\n";N--)C++;x={type:"Parse",message:"Syntax Error on line "+y,index:o,filename:t.filename,line:y,column:C,extract:[b[y-2],b[y-1],b[y]]}}this.imports.queue.length>0?v=function(e){e?a(e):a(null,f)}:a(x,f)},parsers:{primary:function(){var e,t=[];while((e=E(this.mixin.definition)||E(this.rule)||E(this.ruleset)||E(this.mixin.call)||E(this.comment)||E(this.directive))||E(/^[\s\n]+/))e&&t.push(e);return t},comment:function(){var e;if(s.charAt(o)!=="/")return;if(s.charAt(o+1)==="/")return new i.Comment(E(/^\/\/.*/),!0);if(e=E(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/))return new i.Comment(e)},entities:{quoted:function(){var e,t=o,n;s.charAt(t)==="~"&&(t++,n=!0);if(s.charAt(t)!=='"'&&s.charAt(t)!=="'")return;n&&E("~");if(e=E(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/))return new i.Quoted(e[0],e[1]||e[2],n)},keyword:function(){var e;if(e=E(/^[_A-Za-z-][_A-Za-z0-9-]*/))return i.colors.hasOwnProperty(e)?new i.Color(i.colors[e].slice(1)):new i.Keyword(e)},call:function(){var e,n,r,s,a=o;if(!(e=/^([\w-]+|%|progid:[\w\.]+)\(/.exec(c[u])))return;e=e[1],n=e.toLowerCase();if(n==="url")return null;o+=e.length;if(n==="alpha"){s=E(this.alpha);if(typeof s!="undefined")return s}E("("),r=E(this.entities.arguments);if(!E(")"))return;if(e)return new i.Call(e,r,a,t.filename)},arguments:function(){var e=[],t;while(t=E(this.entities.assignment)||E(this.expression)){e.push(t);if(!E(","))break}return e},literal:function(){return E(this.entities.ratio)||E(this.entities.dimension)||E(this.entities.color)||E(this.entities.quoted)},assignment:function(){var e,t;if((e=E(/^\w+(?=\s?=)/i))&&E("=")&&(t=E(this.entity)))return new i.Assignment(e,t)},url:function(){var e;if(s.charAt(o)!=="u"||!E(/^url\(/))return;return e=E(this.entities.quoted)||E(this.entities.variable)||E(/^(?:(?:\\[\(\)'"])|[^\(\)'"])+/)||"",x(")"),new i.URL(e.value!=null||e instanceof i.Variable?e:new i.Anonymous(e),m.paths)},variable:function(){var e,n=o;if(s.charAt(o)==="@"&&(e=E(/^@@?[\w-]+/)))return new i.Variable(e,n,t.filename)},variableCurly:function(){var e,n,r=o;if(s.charAt(o)==="@"&&(n=E(/^@\{([\w-]+)\}/)))return new i.Variable("@"+n[1],r,t.filename)},color:function(){var e;if(s.charAt(o)==="#"&&(e=E(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/)))return new i.Color(e[1])},dimension:function(){var e,t=s.charCodeAt(o);if(t>57||t<45||t===47)return;if(e=E(/^(-?\d*\.?\d+)(px|%|em|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn|dpi|dpcm|dppx|rem|vw|vh|vmin|vm|ch)?/))return new i.Dimension(e[1],e[2])},ratio:function(){var e,t=s.charCodeAt(o);if(t>57||t<48)return;if(e=E(/^(\d+\/\d+)/))return new i.Ratio(e[1])},javascript:function(){var e,t=o,n;s.charAt(t)==="~"&&(t++,n=!0);if(s.charAt(t)!=="`")return;n&&E("~");if(e=E(/^`([^`]*)`/))return new i.JavaScript(e[1],o,n)}},variable:function(){var e;if(s.charAt(o)==="@"&&(e=E(/^(@[\w-]+)\s*:/)))return e[1]},shorthand:function(){var e,t;if(!N(/^[@\w.%-]+\/[@\w.-]+/))return;g();if((e=E(this.entity))&&E("/")&&(t=E(this.entity)))return new i.Shorthand(e,t);y()},mixin:{call:function(){var e=[],n,r,u=[],a,f=o,l=s.charAt(o),c,h,p=!1;if(l!=="."&&l!=="#")return;g();while(n=E(/^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/))e.push(new i.Element(r,n,o)),r=E(">");if(E("(")){while(a=E(this.expression)){h=a,c=null;if(a.value.length==1){var d=a.value[0];if(d instanceof i.Variable&&E(":")){if(!(h=E(this.expression)))throw new Error("Expected value");c=d.name}}u.push({name:c,value:h});if(!E(","))break}if(!E(")"))throw new Error("Expected )")}E(this.important)&&(p=!0);if(e.length>0&&(E(";")||N("}")))return new i.mixin.Call(e,u,f,t.filename,p);y()},definition:function(){var e,t=[],n,r,u,a,f,c=!1;if(s.charAt(o)!=="."&&s.charAt(o)!=="#"||N(/^[^{]*(;|})/))return;g();if(n=E(/^([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/)){e=n[1];do{if(s.charAt(o)==="."&&E(/^\.{3}/)){c=!0;break}if(!(u=E(this.entities.variable)||E(this.entities.literal)||E(this.entities.keyword)))break;if(u instanceof i.Variable)if(E(":"))a=x(this.expression,"expected expression"),t.push({name:u.name,value:a});else{if(E(/^\.{3}/)){t.push({name:u.name,variadic:!0}),c=!0;break}t.push({name:u.name})}else t.push({value:u})}while(E(","));E(")")||(l=o,y()),E(/^when/)&&(f=x(this.conditions,"expected condition")),r=E(this.block);if(r)return new i.mixin.Definition(e,t,r,f,c);y()}}},entity:function(){return E(this.entities.literal)||E(this.entities.variable)||E(this.entities.url)||E(this.entities.call)||E(this.entities.keyword)||E(this.entities.javascript)||E(this.comment)},end:function(){return E(";")||N("}")},alpha:function(){var e;if(!E(/^\(opacity=/i))return;if(e=E(/^\d+/)||E(this.entities.variable))return x(")"),new i.Alpha(e)},element:function(){var e,t,n,r;n=E(this.combinator),e=E(/^(?:\d+\.\d+|\d+)%/)||E(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/)||E("*")||E("&")||E(this.attribute)||E(/^\([^)@]+\)/)||E(/^[\.#](?=@)/)||E(this.entities.variableCurly),e||E("(")&&(r=E(this.entities.variableCurly)||E(this.entities.variable))&&E(")")&&(e=new i.Paren(r));if(e)return new i.Element(n,e,o)},combinator:function(){var e,t=s.charAt(o);if(t===">"||t==="+"||t==="~"){o++;while(s.charAt(o).match(/\s/))o++;return new i.Combinator(t)}return s.charAt(o-1).match(/\s/)?new i.Combinator(" "):new i.Combinator(null)},selector:function(){var e,t,n=[],r,u;if(E("("))return e=E(this.entity),x(")"),new i.Selector([new i.Element("",e,o)]);while(t=E(this.element)){r=s.charAt(o),n.push(t);if(r==="{"||r==="}"||r===";"||r===",")break}if(n.length>0)return new i.Selector(n)},tag:function(){return E(/^[A-Za-z][A-Za-z-]*[0-9]?/)||E("*")},attribute:function(){var e="",t,n,r;if(!E("["))return;if(t=E(/^(?:[_A-Za-z0-9-]|\\.)+/)||E(this.entities.quoted))(r=E(/^[|~*$^]?=/))&&(n=E(this.entities.quoted)||E(/^[\w-]+/))?e=[t,r,n.toCSS?n.toCSS():n].join(""):e=t;if(!E("]"))return;if(e)return"["+e+"]"},block:function(){var e;if(E("{")&&(e=E(this.primary))&&E("}"))return e},ruleset:function(){var e=[],n,r,u,a;g(),t.dumpLineNumbers&&(a=A(o,s,t));while(n=E(this.selector)){e.push(n),E(this.comment);if(!E(","))break;E(this.comment)}if(e.length>0&&(r=E(this.block))){var f=new i.Ruleset(e,r,t.strictImports);return t.dumpLineNumbers&&(f.debugInfo=a),f}l=o,y()},rule:function(){var e,t,n=s.charAt(o),r,a;g();if(n==="."||n==="#"||n==="&")return;if(e=E(this.variable)||E(this.property)){e.charAt(0)!="@"&&(a=/^([^@+\/'"*`(;{}-]*);/.exec(c[u]))?(o+=a[0].length-1,t=new i.Anonymous(a[1])):e==="font"?t=E(this.font):t=E(this.value),r=E(this.important);if(t&&E(this.end))return new i.Rule(e,t,r,f);l=o,y()}},"import":function(){var e,t,n=o;g();var r=E(/^@import(?:-(once))?\s+/);if(r&&(e=E(this.entities.quoted)||E(this.entities.url))){t=E(this.mediaFeatures);if(E(";"))return new i.Import(e,m,t,r[1]==="once",n)}y()},mediaFeature:function(){var e,t,n=[];do if(e=E(this.entities.keyword))n.push(e);else if(E("(")){t=E(this.property),e=E(this.entity);if(!E(")"))return null;if(t&&e)n.push(new i.Paren(new i.Rule(t,e,null,o,!0)));else{if(!e)return null;n.push(new i.Paren(e))}}while(e);if(n.length>0)return new i.Expression(n)},mediaFeatures:function(){var e,t=[];do if(e=E(this.mediaFeature)){t.push(e);if(!E(","))break}else if(e=E(this.entities.variable)){t.push(e);if(!E(","))break}while(e);return t.length>0?t:null},media:function(){var e,n,r,u;t.dumpLineNumbers&&(u=A(o,s,t));if(E(/^@media/)){e=E(this.mediaFeatures);if(n=E(this.block))return r=new i.Media(n,e),t.dumpLineNumbers&&(r.debugInfo=u),r}},directive:function(){var e,t,n,r,u,a,f,l,c;if(s.charAt(o)!=="@")return;if(t=E(this["import"])||E(this.media))return t;g(),e=E(/^@[a-z-]+/),f=e,e.charAt(1)=="-"&&e.indexOf("-",2)>0&&(f="@"+e.slice(e.indexOf("-",2)+1));switch(f){case"@font-face":l=!0;break;case"@viewport":case"@top-left":case"@top-left-corner":case"@top-center":case"@top-right":case"@top-right-corner":case"@bottom-left":case"@bottom-left-corner":case"@bottom-center":case"@bottom-right":case"@bottom-right-corner":case"@left-top":case"@left-middle":case"@left-bottom":case"@right-top":case"@right-middle":case"@right-bottom":l=!0;break;case"@page":case"@document":case"@supports":case"@keyframes":l=!0,c=!0}c&&(e+=" "+(E(/^[^{]+/)||"").trim());if(l){if(n=E(this.block))return new i.Directive(e,n)}else if((t=E(this.entity))&&E(";"))return new i.Directive(e,t);y()},font:function(){var e=[],t=[],n,r,s,o;while(o=E(this.shorthand)||E(this.entity))t.push(o);e.push(new i.Expression(t));if(E(","))while(o=E(this.expression)){e.push(o);if(!E(","))break}return new i.Value(e)},value:function(){var e,t=[],n;while(e=E(this.expression)){t.push(e);if(!E(","))break}if(t.length>0)return new i.Value(t)},important:function(){if(s.charAt(o)==="!")return E(/^! *important/)},sub:function(){var e;if(E("(")&&(e=E(this.expression))&&E(")"))return e},multiplication:function(){var e,t,n,r;if(e=E(this.operand)){while(!N(/^\/\*/)&&(n=E("/")||E("*"))&&(t=E(this.operand)))r=new i.Operation(n,[r||e,t]);return r||e}},addition:function(){var e,t,n,r;if(e=E(this.multiplication)){while((n=E(/^[-+]\s+/)||!w(s.charAt(o-1))&&(E("+")||E("-")))&&(t=E(this.multiplication)))r=new i.Operation(n,[r||e,t]);return r||e}},conditions:function(){var e,t,n=o,r;if(e=E(this.condition)){while(E(",")&&(t=E(this.condition)))r=new i.Condition("or",r||e,t,n);return r||e}},condition:function(){var e,t,n,r,s=o,u=!1;E(/^not/)&&(u=!0),x("(");if(e=E(this.addition)||E(this.entities.keyword)||E(this.entities.quoted))return(r=E(/^(?:>=|=<|[<=>])/))?(t=E(this.addition)||E(this.entities.keyword)||E(this.entities.quoted))?n=new i.Condition(r,e,t,s,u):T("expected expression"):n=new i.Condition("=",e,new i.Keyword("true"),s,u),x(")"),E(/^and/)?new i.Condition("and",n,E(this.condition)):n},operand:function(){var e,t=s.charAt(o+1);s.charAt(o)==="-"&&(t==="@"||t==="(")&&(e=E("-"));var n=E(this.sub)||E(this.entities.dimension)||E(this.entities.color)||E(this.entities.variable)||E(this.entities.call);return e?new i.Operation("*",[new i.Dimension(-1),n]):n},expression:function(){var e,t,n=[],r;while(e=E(this.addition)||E(this.entity))n.push(e);if(n.length>0)return new i.Expression(n)},property:function(){var e;if(e=E(/^(\*?-?[_a-z0-9-]+)\s*:/))return e[1]}}}};if(r.mode==="browser"||r.mode==="rhino")r.Parser.importer=function(e,t,n,r){!/^([a-z-]+:)?\//.test(e)&&t.length>0&&(e=t[0]+e),d({href:e,title:e,type:r.mime,contents:r.contents},function(i){i&&typeof r.errback=="function"?r.errback.call(null,e,t,n,r):n.apply(null,arguments)},!0)};(function(e){function t(t){return e.functions.hsla(t.h,t.s,t.l,t.a)}function n(t){if(t instanceof e.Dimension)return parseFloat(t.unit=="%"?t.value/100:t.value);if(typeof t=="number")return t;throw{error:"RuntimeError",message:"color functions take numbers as parameters"}}function r(e){return Math.min(1,Math.max(0,e))}e.functions={rgb:function(e,t,n){return this.rgba(e,t,n,1)},rgba:function(t,r,i,s){var o=[t,r,i].map(function(e){return n(e)}),s=n(s);return new e.Color(o,s)},hsl:function(e,t,n){return this.hsla(e,t,n,1)},hsla:function(e,t,r,i){function u(e){return e=e<0?e+1:e>1?e-1:e,e*6<1?o+(s-o)*e*6:e*2<1?s:e*3<2?o+(s-o)*(2/3-e)*6:o}e=n(e)%360/360,t=n(t),r=n(r),i=n(i);var s=r<=.5?r*(t+1):r+t-r*t,o=r*2-s;return this.rgba(u(e+1/3)*255,u(e)*255,u(e-1/3)*255,i)},hue:function(t){return new e.Dimension(Math.round(t.toHSL().h))},saturation:function(t){return new e.Dimension(Math.round(t.toHSL().s*100),"%")},lightness:function(t){return new e.Dimension(Math.round(t.toHSL().l*100),"%")},red:function(t){return new e.Dimension(t.rgb[0])},green:function(t){return new e.Dimension(t.rgb[1])},blue:function(t){return new e.Dimension(t.rgb[2])},alpha:function(t){return new e.Dimension(t.toHSL().a)},luma:function(t){return new e.Dimension(Math.round((.2126*(t.rgb[0]/255)+.7152*(t.rgb[1]/255)+.0722*(t.rgb[2]/255))*t.alpha*100),"%")},saturate:function(e,n){var i=e.toHSL();return i.s+=n.value/100,i.s=r(i.s),t(i)},desaturate:function(e,n){var i=e.toHSL();return i.s-=n.value/100,i.s=r(i.s),t(i)},lighten:function(e,n){var i=e.toHSL();return i.l+=n.value/100,i.l=r(i.l),t(i)},darken:function(e,n){var i=e.toHSL();return i.l-=n.value/100,i.l=r(i.l),t(i)},fadein:function(e,n){var i=e.toHSL();return i.a+=n.value/100,i.a=r(i.a),t(i)},fadeout:function(e,n){var i=e.toHSL();return i.a-=n.value/100,i.a=r(i.a),t(i)},fade:function(e,n){var i=e.toHSL();return i.a=n.value/100,i.a=r(i.a),t(i)},spin:function(e,n){var r=e.toHSL(),i=(r.h+n.value)%360;return r.h=i<0?360+i:i,t(r)},mix:function(t,n,r){r||(r=new e.Dimension(50));var i=r.value/100,s=i*2-1,o=t.toHSL().a-n.toHSL().a,u=((s*o==-1?s:(s+o)/(1+s*o))+1)/2,a=1-u,f=[t.rgb[0]*u+n.rgb[0]*a,t.rgb[1]*u+n.rgb[1]*a,t.rgb[2]*u+n.rgb[2]*a],l=t.alpha*i+n.alpha*(1-i);return new e.Color(f,l)},greyscale:function(t){return this.desaturate(t,new e.Dimension(100))},contrast:function(e,t,n,r){return typeof n=="undefined"&&(n=this.rgba(255,255,255,1)),typeof t=="undefined"&&(t=this.rgba(0,0,0,1)),typeof r=="undefined"?r=.43:r=r.value,(.2126*(e.rgb[0]/255)+.7152*(e.rgb[1]/255)+.0722*(e.rgb[2]/255))*e.alpha255?255:e<0?0:e).toString(16),e.length===1?"0"+e:e}).join("")},operate:function(t,n){var r=[];n instanceof e.Color||(n=n.toColor());for(var i=0;i<3;i++)r[i]=e.operate(t,this.rgb[i],n.rgb[i]);return new e.Color(r,this.alpha+n.alpha)},toHSL:function(){var e=this.rgb[0]/255,t=this.rgb[1]/255,n=this.rgb[2]/255,r=this.alpha,i=Math.max(e,t,n),s=Math.min(e,t, n),o,u,a=(i+s)/2,f=i-s;if(i===s)o=u=0;else{u=a>.5?f/(2-i-s):f/(i+s);switch(i){case e:o=(t-n)/f+(t255?255:e<0?0:e).toString(16),e.length===1?"0"+e:e}).join("")},compare:function(e){return e.rgb?e.rgb[0]===this.rgb[0]&&e.rgb[1]===this.rgb[1]&&e.rgb[2]===this.rgb[2]&&e.alpha===this.alpha?0:-1:-1}}}(n("../tree")),function(e){e.Comment=function(e,t){this.value=e,this.silent=!!t},e.Comment.prototype={toCSS:function(e){return e.compress?"":this.value},eval:function(){return this}}}(n("../tree")),function(e){e.Condition=function(e,t,n,r,i){this.op=e.trim(),this.lvalue=t,this.rvalue=n,this.index=r,this.negate=i},e.Condition.prototype.eval=function(e){var t=this.lvalue.eval(e),n=this.rvalue.eval(e),r=this.index,i,i=function(e){switch(e){case"and":return t&&n;case"or":return t||n;default:if(t.compare)i=t.compare(n);else{if(!n.compare)throw{type:"Type",message:"Unable to perform comparison",index:r};i=n.compare(t)}switch(i){case-1:return e==="<"||e==="=<";case 0:return e==="="||e===">="||e==="=<";case 1:return e===">"||e===">="}}}(this.op);return this.negate?!i:i}}(n("../tree")),function(e){e.Dimension=function(e,t){this.value=parseFloat(e),this.unit=t||null},e.Dimension.prototype={eval:function(){return this},toColor:function(){return new e.Color([this.value,this.value,this.value])},toCSS:function(){var e=this.value+this.unit;return e},operate:function(t,n){return new e.Dimension(e.operate(t,this.value,n.value),this.unit||n.unit)},compare:function(t){return t instanceof e.Dimension?t.value>this.value?-1:t.value":e.compress?">":" > "}[this.value]}}(n("../tree")),function(e){e.Expression=function(e){this.value=e},e.Expression.prototype={eval:function(t){return this.value.length>1?new e.Expression(this.value.map(function(e){return e.eval(t)})):this.value.length===1?this.value[0].eval(t):this},toCSS:function(e){return this.value.map(function(t){return t.toCSS?t.toCSS(e):""}).join(" ")}}}(n("../tree")),function(e){e.Import=function(t,n,r,i,s){var o=this;this.once=i,this.index=s,this._path=t,this.features=r&&new e.Value(r),t instanceof e.Quoted?this.path=/\.(le?|c)ss(\?.*)?$/.test(t.value)?t.value:t.value+".less":this.path=t.value.value||t.value,this.css=/css(\?.*)?$/.test(this.path),this.css||n.push(this.path,function(t,n,r){t&&(t.index=s),r&&o.once&&(o.skip=r),o.root=n||new e.Ruleset([],[])})},e.Import.prototype={toCSS:function(e){var t=this.features?" "+this.features.toCSS(e):"";return this.css?"@import "+this._path.toCSS()+t+";\n":""},eval:function(t){var n,r=this.features&&this.features.eval(t);if(this.skip)return[];if(this.css)return this;n=new e.Ruleset([],this.root.rules.slice(0));for(var i=0;i1){var r=this.emptySelectors();n=new e.Ruleset(r,t.mediaBlocks),n.multiMedia=!0}return delete t.mediaBlocks,delete t.mediaPath,n},evalNested:function(t){var n,r,i=t.mediaPath.concat([this]);for(n=0;n0;n--)t.splice(n,0,new e.Anonymous("and"));return new e.Expression(t)})),new e.Ruleset([],[])},permute:function(e){if(e.length===0)return[];if(e.length===1)return e[0];var t=[],n=this.permute(e.slice(1));for(var r=0;r0){n=this.arguments&&this.arguments.map(function(t){return{name:t.name,value:t.value.eval(e)}});for(var o=0;othis.params.length)return!1;if(this.required>0&&n>this.params.length)return!1}if(this.condition&&!this.condition.eval({frames:[this.evalParams(t,e)].concat(t.frames)}))return!1;r=Math.min(n,this.arity);for(var s=0;si.selectors[o].elements.length?Array.prototype.push.apply(r,i.find(new e.Selector(t.elements.slice(1)),n)):r.push(i);break}}),this._lookups[o]=r)},toCSS:function(t,n){var r=[],i=[],s=[],o=[],u=[],a,f,l;this.root||this.joinSelectors(u,t,this.selectors);for(var c=0;c0){f=e.debugInfo(n,this),a=u.map(function(e){return e.map(function(e){return e.toCSS(n)}).join("").trim()}).join(n.compress?",":",\n");for(var c=i.length-1;c>=0;c--)s.indexOf(i[c])===-1&&s.unshift(i[c]);i=s,r.push(f+a+(n.compress?"{":" {\n ")+i.join(n.compress?"":"\n ")+(n.compress?"}":"\n}\n"))}return r.push(o),r.join("")+(n.compress?"\n":"")},joinSelectors:function(e,t,n){for(var r=0;r0)for(i=0;i0&&this.mergeElementsOnToSelectors(g,a);for(s=0;s0&&(l[0].elements=l[0].elements.slice(0),l[0].elements.push(new e.Element(f.combinator,"",0))),y.push(l);else for(o=0;o0?(h=l.slice(0),m=h.pop(),d=new e.Selector(m.elements.slice(0)),v=!1):d=new e.Selector([]),c.length>1&&(p=p.concat(c.slice(1))),c.length>0&&(v=!1,d.elements.push(new e.Element(f.combinator,c[0].elements[0].value,0)),d.elements=d.elements.concat(c[0].elements.slice(1))),v||h.push(d),h=h.concat(p),y.push(h)}a=y,g=[]}}g.length>0&&this.mergeElementsOnToSelectors(g,a);for(i=0;i0?i[i.length-1]=new e.Selector(i[i.length-1].elements.concat(t)):i.push(new e.Selector(t))}}}(n("../tree")),function(e){e.Selector=function(e){this.elements=e},e.Selector.prototype.match=function(e){var t=this.elements.length,n=e.elements.length,r=Math.min(t,n);if(t0&&(r.value=this.paths[0]+(r.value.charAt(0)==="/"?r.value.slice(1):r.value)),new t.URL(r,this.paths)}}}(n("../tree")),function(e){e.Value=function(e){this.value=e,this.is="value"},e.Value.prototype={eval:function(t){return this.value.length===1?this.value[0].eval(t):new e.Value(this.value.map(function(e){return e.eval(t)}))},toCSS:function(e){return this.value.map(function(t){return t.toCSS(e)}).join(e.compress?",":", ")}}}(n("../tree")),function(e){e.Variable=function(e,t,n){this.name=e,this.index=t,this.file=n},e.Variable.prototype={eval:function(t){var n,r,i=this.name;i.indexOf("@@")==0&&(i="@"+(new e.Variable(i.slice(1))).eval(t).value);if(n=e.find(t.frames,function(e){if(r=e.variable(i))return r.value.eval(t)}))return n;throw{type:"Name",message:"variable "+i+" is undefined",filename:this.file,index:this.index}}}}(n("../tree")),function(e){e.debugInfo=function(t,n){var r="";if(t.dumpLineNumbers&&!t.compress)switch(t.dumpLineNumbers){case"comments":r=e.debugInfo.asComment(n);break;case"mediaquery":r=e.debugInfo.asMediaQuery(n);break;case"all":r=e.debugInfo.asComment(n)+e.debugInfo.asMediaQuery(n)}return r},e.debugInfo.asComment=function(e){return"/* line "+e.debugInfo.lineNumber+", "+e.debugInfo.fileName+" */\n"},e.debugInfo.asMediaQuery=function(e){return'@media -sass-debug-info{filename{font-family:"'+e.debugInfo.fileName+'";}line{font-family:"'+e.debugInfo.lineNumber+'";}}\n'},e.find=function(e,t){for(var n=0,r;n1?"["+e.value.map(function(e){return e.toCSS(!1)}).join(", ")+"]":e.toCSS(!1)}}(n("./tree"));var s=/^(file|chrome(-extension)?|resource|qrc|app):/.test(location.protocol);r.env=r.env||(location.hostname=="127.0.0.1"||location.hostname=="0.0.0.0"||location.hostname=="localhost"||location.port.length>0||s?"development":"production"),r.async=r.async||!1,r.fileAsync=r.fileAsync||!1,r.poll=r.poll||(s?1e3:1500),r.watch=function(){return this.watchMode=!0},r.unwatch=function(){return this.watchMode=!1};if(r.env==="development"){r.optimization=0,/!watch/.test(location.hash)&&r.watch();var o=/!dumpLineNumbers:(comments|mediaquery|all)/.exec(location.hash);o&&(r.dumpLineNumbers=o[1]),r.watchTimer=setInterval(function(){r.watchMode&&p(function(e,t,n,r,i){t&&m(t.toCSS(),r,i.lastModified)})},r.poll)}else r.optimization=3;var u;try{u=typeof e.localStorage=="undefined"?null:e.localStorage}catch(a){u=null}var f=document.getElementsByTagName("link"),l=/^text\/(x-)?less$/;r.sheets=[];for(var c=0;c>> 0; for (var i = 0; i < len; i++) { if (i in this) { block.call(thisObject, this[i], i, this); } } }; } if (!Array.prototype.map) { Array.prototype.map = function(fun /*, thisp*/) { var len = this.length >>> 0; var res = new Array(len); var thisp = arguments[1]; for (var i = 0; i < len; i++) { if (i in this) { res[i] = fun.call(thisp, this[i], i, this); } } return res; }; } if (!Array.prototype.filter) { Array.prototype.filter = function (block /*, thisp */) { var values = []; var thisp = arguments[1]; for (var i = 0; i < this.length; i++) { if (block.call(thisp, this[i])) { values.push(this[i]); } } return values; }; } if (!Array.prototype.reduce) { Array.prototype.reduce = function(fun /*, initial*/) { var len = this.length >>> 0; var i = 0; // no value to return if no initial value and an empty array if (len === 0 && arguments.length === 1) throw new TypeError(); if (arguments.length >= 2) { var rv = arguments[1]; } else { do { if (i in this) { rv = this[i++]; break; } // if array contains no values, no initial value to return if (++i >= len) throw new TypeError(); } while (true); } for (; i < len; i++) { if (i in this) { rv = fun.call(null, rv, this[i], i, this); } } return rv; }; } if (!Array.prototype.indexOf) { Array.prototype.indexOf = function (value /*, fromIndex */ ) { var length = this.length; var i = arguments[1] || 0; if (!length) return -1; if (i >= length) return -1; if (i < 0) i += length; for (; i < length; i++) { if (!Object.prototype.hasOwnProperty.call(this, i)) { continue } if (value === this[i]) return i; } return -1; }; } // // Object // if (!Object.keys) { Object.keys = function (object) { var keys = []; for (var name in object) { if (Object.prototype.hasOwnProperty.call(object, name)) { keys.push(name); } } return keys; }; } // // String // if (!String.prototype.trim) { String.prototype.trim = function () { return String(this).replace(/^\s\s*/, '').replace(/\s\s*$/, ''); }; } var less, tree, charset; if (typeof environment === "object" && ({}).toString.call(environment) === "[object Environment]") { // Rhino // Details on how to detect Rhino: https://github.com/ringo/ringojs/issues/88 if (typeof(window) === 'undefined') { less = {} } else { less = window.less = {} } tree = less.tree = {}; less.mode = 'rhino'; } else if (typeof(window) === 'undefined') { // Node.js less = exports, tree = require('./tree'); less.mode = 'node'; } else { // Browser if (typeof(window.less) === 'undefined') { window.less = {} } less = window.less, tree = window.less.tree = {}; less.mode = 'browser'; } // // less.js - parser // // A relatively straight-forward predictive parser. // There is no tokenization/lexing stage, the input is parsed // in one sweep. // // To make the parser fast enough to run in the browser, several // optimization had to be made: // // - Matching and slicing on a huge input is often cause of slowdowns. // The solution is to chunkify the input into smaller strings. // The chunks are stored in the `chunks` var, // `j` holds the current chunk index, and `current` holds // the index of the current chunk in relation to `input`. // This gives us an almost 4x speed-up. // // - In many cases, we don't need to match individual tokens; // for example, if a value doesn't hold any variables, operations // or dynamic references, the parser can effectively 'skip' it, // treating it as a literal. // An example would be '1px solid #000' - which evaluates to itself, // we don't need to know what the individual components are. // The drawback, of course is that you don't get the benefits of // syntax-checking on the CSS. This gives us a 50% speed-up in the parser, // and a smaller speed-up in the code-gen. // // // Token matching is done with the `$` function, which either takes // a terminal string or regexp, or a non-terminal function to call. // It also takes care of moving all the indices forwards. // // less.Parser = function Parser(env) { var input, // LeSS input string i, // current index in `input` j, // current chunk temp, // temporarily holds a chunk's state, for backtracking memo, // temporarily holds `i`, when backtracking furthest, // furthest index the parser has gone to chunks, // chunkified input current, // index of current chunk, in `input` parser; var that = this; // Top parser on an import tree must be sure there is one "env" // which will then be passed arround by reference. var env = env || { }; // env.contents and files must be passed arround with top env if (!env.contents) { env.contents = {}; } env.rootpath = env.rootpath || ''; // env.rootpath must be initialized to '' if not provided if (!env.files) { env.files = {}; } // This function is called after all files // have been imported through `@import`. var finish = function () {}; var imports = this.imports = { paths: env.paths || [], // Search paths, when importing queue: [], // Files which haven't been imported yet files: env.files, // Holds the imported parse trees contents: env.contents, // Holds the imported file contents mime: env.mime, // MIME type of .less files error: null, // Error in parsing/evaluating an import push: function (path, callback) { var that = this; this.queue.push(path); // // Import a file asynchronously // less.Parser.importer(path, this.paths, function (e, root, fullPath) { that.queue.splice(that.queue.indexOf(path), 1); // Remove the path from the queue var imported = fullPath in that.files; that.files[fullPath] = root; // Store the root if (e && !that.error) { that.error = e } callback(e, root, imported); if (that.queue.length === 0) { finish(that.error) } // Call `finish` if we're done importing }, env); } }; function save() { temp = chunks[j], memo = i, current = i } function restore() { chunks[j] = temp, i = memo, current = i } function sync() { if (i > current) { chunks[j] = chunks[j].slice(i - current); current = i; } } function isWhitespace(c) { // Could change to \s? var code = c.charCodeAt(0); return code === 32 || code === 10 || code === 9; } // // Parse from a token, regexp or string, and move forward if match // function $(tok) { var match, args, length, index, k; // // Non-terminal // if (tok instanceof Function) { return tok.call(parser.parsers); // // Terminal // // Either match a single character in the input, // or match a regexp in the current chunk (chunk[j]). // } else if (typeof(tok) === 'string') { match = input.charAt(i) === tok ? tok : null; length = 1; sync (); } else { sync (); if (match = tok.exec(chunks[j])) { length = match[0].length; } else { return null; } } // The match is confirmed, add the match length to `i`, // and consume any extra white-space characters (' ' || '\n') // which come after that. The reason for this is that LeSS's // grammar is mostly white-space insensitive. // if (match) { skipWhitespace(length); if(typeof(match) === 'string') { return match; } else { return match.length === 1 ? match[0] : match; } } } function skipWhitespace(length) { var oldi = i, oldj = j, endIndex = i + chunks[j].length, mem = i += length; while (i < endIndex) { if (! isWhitespace(input.charAt(i))) { break } i++; } chunks[j] = chunks[j].slice(length + (i - mem)); current = i; if (chunks[j].length === 0 && j < chunks.length - 1) { j++ } return oldi !== i || oldj !== j; } function expect(arg, msg) { var result = $(arg); if (! result) { error(msg || (typeof(arg) === 'string' ? "expected '" + arg + "' got '" + input.charAt(i) + "'" : "unexpected token")); } else { return result; } } function error(msg, type) { var e = new Error(msg); e.index = i; e.type = type || 'Syntax'; throw e; } // Same as $(), but don't change the state of the parser, // just return the match. function peek(tok) { if (typeof(tok) === 'string') { return input.charAt(i) === tok; } else { if (tok.test(chunks[j])) { return true; } else { return false; } } } function getInput(e, env) { if (e.filename && env.filename && (e.filename !== env.filename)) { return parser.imports.contents[e.filename]; } else { return input; } } function getLocation(index, input) { for (var n = index, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } return { line: typeof(index) === 'number' ? (input.slice(0, index).match(/\n/g) || "").length : null, column: column }; } function getFileName(e) { if(less.mode === 'browser' || less.mode === 'rhino') return e.filename; else return require('path').resolve(e.filename); } function getDebugInfo(index, inputStream, e) { return { lineNumber: getLocation(index, inputStream).line + 1, fileName: getFileName(e) }; } function LessError(e, env) { var input = getInput(e, env), loc = getLocation(e.index, input), line = loc.line, col = loc.column, lines = input.split('\n'); this.type = e.type || 'Syntax'; this.message = e.message; this.filename = e.filename || env.filename; this.index = e.index; this.line = typeof(line) === 'number' ? line + 1 : null; this.callLine = e.call && (getLocation(e.call, input).line + 1); this.callExtract = lines[getLocation(e.call, input).line]; this.stack = e.stack; this.column = col; this.extract = [ lines[line - 1], lines[line], lines[line + 1] ]; } this.env = env = env || {}; // The optimization level dictates the thoroughness of the parser, // the lower the number, the less nodes it will create in the tree. // This could matter for debugging, or if you want to access // the individual nodes in the tree. this.optimization = ('optimization' in this.env) ? this.env.optimization : 1; this.env.filename = this.env.filename || null; // // The Parser // return parser = { imports: imports, // // Parse an input string into an abstract syntax tree, // call `callback` when done. // parse: function (str, callback) { var root, start, end, zone, line, lines, buff = [], c, error = null; i = j = current = furthest = 0; input = str.replace(/\r\n/g, '\n'); // Remove potential UTF Byte Order Mark input = input.replace(/^\uFEFF/, ''); // Split the input into chunks. chunks = (function (chunks) { var j = 0, skip = /(?:@\{[\w-]+\}|[^"'`\{\}\/\(\)\\])+/g, comment = /\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g, string = /"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'|`((?:[^`]|\\.)*)`/g, level = 0, match, chunk = chunks[0], inParam; for (var i = 0, c, cc; i < input.length;) { skip.lastIndex = i; if (match = skip.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); } } c = input.charAt(i); comment.lastIndex = string.lastIndex = i; if (match = string.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); continue; } } if (!inParam && c === '/') { cc = input.charAt(i + 1); if (cc === '/' || cc === '*') { if (match = comment.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); continue; } } } } switch (c) { case '{': if (! inParam) { level ++; chunk.push(c); break } case '}': if (! inParam) { level --; chunk.push(c); chunks[++j] = chunk = []; break } case '(': if (! inParam) { inParam = true; chunk.push(c); break } case ')': if ( inParam) { inParam = false; chunk.push(c); break } default: chunk.push(c); } i++; } if (level != 0) { error = new(LessError)({ index: i-1, type: 'Parse', message: (level > 0) ? "missing closing `}`" : "missing opening `{`", filename: env.filename }, env); } return chunks.map(function (c) { return c.join('') });; })([[]]); if (error) { return callback(error, env); } // Start with the primary rule. // The whole syntax tree is held under a Ruleset node, // with the `root` property set to true, so no `{}` are // output. The callback is called when the input is parsed. try { root = new(tree.Ruleset)([], $(this.parsers.primary)); root.root = true; } catch (e) { return callback(new(LessError)(e, env)); } root.toCSS = (function (evaluate) { var line, lines, column; return function (options, variables) { var frames = [], importError; options = options || {}; // // Allows setting variables with a hash, so: // // `{ color: new(tree.Color)('#f01') }` will become: // // new(tree.Rule)('@color', // new(tree.Value)([ // new(tree.Expression)([ // new(tree.Color)('#f01') // ]) // ]) // ) // if (typeof(variables) === 'object' && !Array.isArray(variables)) { variables = Object.keys(variables).map(function (k) { var value = variables[k]; if (! (value instanceof tree.Value)) { if (! (value instanceof tree.Expression)) { value = new(tree.Expression)([value]); } value = new(tree.Value)([value]); } return new(tree.Rule)('@' + k, value, false, 0); }); frames = [new(tree.Ruleset)(null, variables)]; } try { var css = evaluate.call(this, { frames: frames }) .toCSS([], { compress: options.compress || false, dumpLineNumbers: env.dumpLineNumbers }); } catch (e) { throw new(LessError)(e, env); } if ((importError = parser.imports.error)) { // Check if there was an error during importing if (importError instanceof LessError) throw importError; else throw new(LessError)(importError, env); } if (options.yuicompress && less.mode === 'node') { return require('ycssmin').cssmin(css); } else if (options.compress) { return css.replace(/(\s)+/g, "$1"); } else { return css; } }; })(root.eval); // If `i` is smaller than the `input.length - 1`, // it means the parser wasn't able to parse the whole // string, so we've got a parsing error. // // We try to extract a \n delimited string, // showing the line where the parse error occured. // We split it up into two parts (the part which parsed, // and the part which didn't), so we can color them differently. if (i < input.length - 1) { i = furthest; lines = input.split('\n'); line = (input.slice(0, i).match(/\n/g) || "").length + 1; for (var n = i, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } error = { type: "Parse", message: "Syntax Error on line " + line, index: i, filename: env.filename, line: line, column: column, extract: [ lines[line - 2], lines[line - 1], lines[line] ] }; } if (this.imports.queue.length > 0) { finish = function (e) { e = error || e; if (e) callback(e); else callback(null, root); }; } else { callback(error, root); } }, // // Here in, the parsing rules/functions // // The basic structure of the syntax tree generated is as follows: // // Ruleset -> Rule -> Value -> Expression -> Entity // // Here's some LESS code: // // .class { // color: #fff; // border: 1px solid #000; // width: @w + 4px; // > .child {...} // } // // And here's what the parse tree might look like: // // Ruleset (Selector '.class', [ // Rule ("color", Value ([Expression [Color #fff]])) // Rule ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]])) // Rule ("width", Value ([Expression [Operation "+" [Variable "@w"][Dimension 4px]]])) // Ruleset (Selector [Element '>', '.child'], [...]) // ]) // // In general, most rules will try to parse a token with the `$()` function, and if the return // value is truly, will return a new node, of the relevant type. Sometimes, we need to check // first, before parsing, that's when we use `peek()`. // parsers: { // // The `primary` rule is the *entry* and *exit* point of the parser. // The rules here can appear at any level of the parse tree. // // The recursive nature of the grammar is an interplay between the `block` // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule, // as represented by this simplified grammar: // // primary → (ruleset | rule)+ // ruleset → selector+ block // block → '{' primary '}' // // Only at one point is the primary rule not called from the // block rule: at the root level. // primary: function () { var node, root = []; while ((node = $(this.mixin.definition) || $(this.rule) || $(this.ruleset) || $(this.mixin.call) || $(this.comment) || $(this.directive)) || $(/^[\s\n]+/) || $(/^;+/)) { node && root.push(node); } return root; }, // We create a Comment node for CSS comments `/* */`, // but keep the LeSS comments `//` silent, by just skipping // over them. comment: function () { var comment; if (input.charAt(i) !== '/') return; if (input.charAt(i + 1) === '/') { return new(tree.Comment)($(/^\/\/.*/), true); } else if (comment = $(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/)) { return new(tree.Comment)(comment); } }, // // Entities are tokens which can be found inside an Expression // entities: { // // A string, which supports escaping " and ' // // "milky way" 'he\'s the one!' // quoted: function () { var str, j = i, e; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '"' && input.charAt(j) !== "'") return; e && $('~'); if (str = $(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/)) { return new(tree.Quoted)(str[0], str[1] || str[2], e); } }, // // A catch-all word, such as: // // black border-collapse // keyword: function () { var k; if (k = $(/^[_A-Za-z-][_A-Za-z0-9-]*/)) { if (tree.colors.hasOwnProperty(k)) { // detect named color return new(tree.Color)(tree.colors[k].slice(1)); } else { return new(tree.Keyword)(k); } } }, // // A function call // // rgb(255, 0, 255) // // We also try to catch IE's `alpha()`, but let the `alpha` parser // deal with the details. // // The arguments are parsed with the `entities.arguments` parser. // call: function () { var name, nameLC, args, alpha_ret, index = i; if (! (name = /^([\w-]+|%|progid:[\w\.]+)\(/.exec(chunks[j]))) return; name = name[1]; nameLC = name.toLowerCase(); if (nameLC === 'url') { return null } else { i += name.length } if (nameLC === 'alpha') { alpha_ret = $(this.alpha); if(typeof alpha_ret !== 'undefined') { return alpha_ret; } } $('('); // Parse the '(' and consume whitespace. args = $(this.entities.arguments); if (! $(')')) return; if (name) { return new(tree.Call)(name, args, index, env.filename) } }, arguments: function () { var args = [], arg; while (arg = $(this.entities.assignment) || $(this.expression)) { args.push(arg); if (! $(',')) { break } } return args; }, literal: function () { return $(this.entities.ratio) || $(this.entities.dimension) || $(this.entities.color) || $(this.entities.quoted) || $(this.entities.unicodeDescriptor); }, // Assignments are argument entities for calls. // They are present in ie filter properties as shown below. // // filter: progid:DXImageTransform.Microsoft.Alpha( *opacity=50* ) // assignment: function () { var key, value; if ((key = $(/^\w+(?=\s?=)/i)) && $('=') && (value = $(this.entity))) { return new(tree.Assignment)(key, value); } }, // // Parse url() tokens // // We use a specific rule for urls, because they don't really behave like // standard function calls. The difference is that the argument doesn't have // to be enclosed within a string, so it can't be parsed as an Expression. // url: function () { var value; if (input.charAt(i) !== 'u' || !$(/^url\(/)) return; value = $(this.entities.quoted) || $(this.entities.variable) || $(/^(?:(?:\\[\(\)'"])|[^\(\)'"])+/) || ""; expect(')'); return new(tree.URL)((value.value != null || value instanceof tree.Variable) ? value : new(tree.Anonymous)(value), env.rootpath); }, // // A Variable entity, such as `@fink`, in // // width: @fink + 2px // // We use a different parser for variable definitions, // see `parsers.variable`. // variable: function () { var name, index = i; if (input.charAt(i) === '@' && (name = $(/^@@?[\w-]+/))) { return new(tree.Variable)(name, index, env.filename); } }, // A variable entity useing the protective {} e.g. @{var} variableCurly: function () { var name, curly, index = i; if (input.charAt(i) === '@' && (curly = $(/^@\{([\w-]+)\}/))) { return new(tree.Variable)("@" + curly[1], index, env.filename); } }, // // A Hexadecimal color // // #4F3C2F // // `rgb` and `hsl` colors are parsed through the `entities.call` parser. // color: function () { var rgb; if (input.charAt(i) === '#' && (rgb = $(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/))) { return new(tree.Color)(rgb[1]); } }, // // A Dimension, that is, a number and a unit // // 0.5em 95% // dimension: function () { var value, c = input.charCodeAt(i); //Is the first char of the dimension 0-9, '.', '+' or '-' if ((c > 57 || c < 43) || c === 47 || c == 44) return; if (value = $(/^([+-]?\d*\.?\d+)(px|%|em|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn|dpi|dpcm|dppx|rem|vw|vh|vmin|vm|ch)?/)) { return new(tree.Dimension)(value[1], value[2]); } }, // // A Ratio // // 16/9 // ratio: function () { var value, c = input.charCodeAt(i); if (c > 57 || c < 48) return; if (value = $(/^(\d+\/\d+)/)) { return new(tree.Ratio)(value[1]); } }, // // A unicode descriptor, as is used in unicode-range // // U+0?? or U+00A1-00A9 // unicodeDescriptor: function () { var ud; if (ud = $(/^U\+[0-9a-fA-F?]+(\-[0-9a-fA-F?]+)?/)) { return new(tree.UnicodeDescriptor)(ud[0]); } }, // // JavaScript code to be evaluated // // `window.location.href` // javascript: function () { var str, j = i, e; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '`') { return } e && $('~'); if (str = $(/^`([^`]*)`/)) { return new(tree.JavaScript)(str[1], i, e); } } }, // // The variable part of a variable definition. Used in the `rule` parser // // @fink: // variable: function () { var name; if (input.charAt(i) === '@' && (name = $(/^(@[\w-]+)\s*:/))) { return name[1] } }, // // A font size/line-height shorthand // // small/12px // // We need to peek first, or we'll match on keywords and dimensions // shorthand: function () { var a, b; if (! peek(/^[@\w.%-]+\/[@\w.-]+/)) return; save(); if ((a = $(this.entity)) && $('/') && (b = $(this.entity))) { return new(tree.Shorthand)(a, b); } restore(); }, // // Mixins // mixin: { // // A Mixin call, with an optional argument list // // #mixins > .square(#fff); // .rounded(4px, black); // .button; // // The `while` loop is there because mixins can be // namespaced, but we only support the child and descendant // selector for now. // call: function () { var elements = [], e, c, argsSemiColon = [], argsComma = [], args, delim, arg, nameLoop, expressions, isSemiColonSeperated, expressionContainsNamed, index = i, s = input.charAt(i), name, value, important = false; if (s !== '.' && s !== '#') { return } save(); // stop us absorbing part of an invalid selector while (e = $(/^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/)) { elements.push(new(tree.Element)(c, e, i)); c = $('>'); } if ($('(')) { expressions = []; while (arg = $(this.expression)) { nameLoop = null; value = arg; // Variable if (arg.value.length == 1) { var val = arg.value[0]; if (val instanceof tree.Variable) { if ($(':')) { if (expressions.length > 0) { if (isSemiColonSeperated) { error("Cannot mix ; and , as delimiter types"); } expressionContainsNamed = true; } value = expect(this.expression); nameLoop = (name = val.name); } } } expressions.push(value); argsComma.push({ name: nameLoop, value: value }); if ($(',')) { continue; } if ($(';') || isSemiColonSeperated) { if (expressionContainsNamed) { error("Cannot mix ; and , as delimiter types"); } isSemiColonSeperated = true; if (expressions.length > 1) { value = new(tree.Value)(expressions); } argsSemiColon.push({ name: name, value: value }); name = null; expressions = []; expressionContainsNamed = false; } } expect(')'); } args = isSemiColonSeperated ? argsSemiColon : argsComma; if ($(this.important)) { important = true; } if (elements.length > 0 && ($(';') || peek('}'))) { return new(tree.mixin.Call)(elements, args, index, env.filename, important); } restore(); }, // // A Mixin definition, with a list of parameters // // .rounded (@radius: 2px, @color) { // ... // } // // Until we have a finer grained state-machine, we have to // do a look-ahead, to make sure we don't have a mixin call. // See the `rule` function for more information. // // We start by matching `.rounded (`, and then proceed on to // the argument list, which has optional default values. // We store the parameters in `params`, with a `value` key, // if there is a value, such as in the case of `@radius`. // // Once we've got our params list, and a closing `)`, we parse // the `{...}` block. // definition: function () { var name, params = [], match, ruleset, param, value, cond, variadic = false; if ((input.charAt(i) !== '.' && input.charAt(i) !== '#') || peek(/^[^{]*\}/)) return; save(); if (match = $(/^([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/)) { name = match[1]; do { $(this.comment); if (input.charAt(i) === '.' && $(/^\.{3}/)) { variadic = true; params.push({ variadic: true }); break; } else if (param = $(this.entities.variable) || $(this.entities.literal) || $(this.entities.keyword)) { // Variable if (param instanceof tree.Variable) { if ($(':')) { value = expect(this.expression, 'expected expression'); params.push({ name: param.name, value: value }); } else if ($(/^\.{3}/)) { params.push({ name: param.name, variadic: true }); variadic = true; break; } else { params.push({ name: param.name }); } } else { params.push({ value: param }); } } else { break; } } while ($(',') || $(';')) // .mixincall("@{a}"); // looks a bit like a mixin definition.. so we have to be nice and restore if (!$(')')) { furthest = i; restore(); } $(this.comment); if ($(/^when/)) { // Guard cond = expect(this.conditions, 'expected condition'); } ruleset = $(this.block); if (ruleset) { return new(tree.mixin.Definition)(name, params, ruleset, cond, variadic); } else { restore(); } } } }, // // Entities are the smallest recognized token, // and can be found inside a rule's value. // entity: function () { return $(this.entities.literal) || $(this.entities.variable) || $(this.entities.url) || $(this.entities.call) || $(this.entities.keyword) ||$(this.entities.javascript) || $(this.comment); }, // // A Rule terminator. Note that we use `peek()` to check for '}', // because the `block` rule will be expecting it, but we still need to make sure // it's there, if ';' was ommitted. // end: function () { return $(';') || peek('}'); }, // // IE's alpha function // // alpha(opacity=88) // alpha: function () { var value; if (! $(/^\(opacity=/i)) return; if (value = $(/^\d+/) || $(this.entities.variable)) { expect(')'); return new(tree.Alpha)(value); } }, // // A Selector Element // // div // + h1 // #socks // input[type="text"] // // Elements are the building blocks for Selectors, // they are made out of a `Combinator` (see combinator rule), // and an element name, such as a tag a class, or `*`. // element: function () { var e, t, c, v; c = $(this.combinator); e = $(/^(?:\d+\.\d+|\d+)%/) || $(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/) || $('*') || $('&') || $(this.attribute) || $(/^\([^()@]+\)/) || $(/^[\.#](?=@)/) || $(this.entities.variableCurly); if (! e) { if ($('(')) { if ((v = ($(this.entities.variableCurly) || $(this.entities.variable) || $(this.selector))) && $(')')) { e = new(tree.Paren)(v); } } } if (e) { return new(tree.Element)(c, e, i) } }, // // Combinators combine elements together, in a Selector. // // Because our parser isn't white-space sensitive, special care // has to be taken, when parsing the descendant combinator, ` `, // as it's an empty space. We have to check the previous character // in the input, to see if it's a ` ` character. More info on how // we deal with this in *combinator.js*. // combinator: function () { var match, c = input.charAt(i); if (c === '>' || c === '+' || c === '~' || c === '|') { i++; while (input.charAt(i).match(/\s/)) { i++ } return new(tree.Combinator)(c); } else if (input.charAt(i - 1).match(/\s/)) { return new(tree.Combinator)(" "); } else { return new(tree.Combinator)(null); } }, // // A CSS Selector // // .class > div + h1 // li a:hover // // Selectors are made out of one or more Elements, see above. // selector: function () { var sel, e, elements = [], c, match; // depreciated, will be removed soon if ($('(')) { sel = $(this.entity); expect(')'); return new(tree.Selector)([new(tree.Element)('', sel, i)]); } while (e = $(this.element)) { c = input.charAt(i); elements.push(e) if (c === '{' || c === '}' || c === ';' || c === ',' || c === ')') { break } } if (elements.length > 0) { return new(tree.Selector)(elements) } }, attribute: function () { var attr = '', key, val, op; if (! $('[')) return; if (key = $(/^(?:[_A-Za-z0-9-]|\\.)+/) || $(this.entities.quoted)) { if ((op = $(/^[|~*$^]?=/)) && (val = $(this.entities.quoted) || $(/^[\w-]+/))) { attr = [key, op, val.toCSS ? val.toCSS() : val].join(''); } else { attr = key } } if (! $(']')) return; if (attr) { return "[" + attr + "]" } }, // // The `block` rule is used by `ruleset` and `mixin.definition`. // It's a wrapper around the `primary` rule, with added `{}`. // block: function () { var content; if ($('{') && (content = $(this.primary)) && $('}')) { return content; } }, // // div, .class, body > p {...} // ruleset: function () { var selectors = [], s, rules, match, debugInfo; save(); if (env.dumpLineNumbers) debugInfo = getDebugInfo(i, input, env); while (s = $(this.selector)) { selectors.push(s); $(this.comment); if (! $(',')) { break } $(this.comment); } if (selectors.length > 0 && (rules = $(this.block))) { var ruleset = new(tree.Ruleset)(selectors, rules, env.strictImports); if (env.dumpLineNumbers) ruleset.debugInfo = debugInfo; return ruleset; } else { // Backtrack furthest = i; restore(); } }, rule: function () { var name, value, c = input.charAt(i), important, match; save(); if (c === '.' || c === '#' || c === '&') { return } if (name = $(this.variable) || $(this.property)) { if ((name.charAt(0) != '@') && (match = /^([^@+\/'"*`(;{}-]*);/.exec(chunks[j]))) { i += match[0].length - 1; value = new(tree.Anonymous)(match[1]); } else if (name === "font") { value = $(this.font); } else { value = $(this.value); } important = $(this.important); if (value && $(this.end)) { return new(tree.Rule)(name, value, important, memo); } else { furthest = i; restore(); } } }, // // An @import directive // // @import "lib"; // // Depending on our environemnt, importing is done differently: // In the browser, it's an XHR request, in Node, it would be a // file-system operation. The function used for importing is // stored in `import`, which we pass to the Import constructor. // "import": function () { var path, features, index = i; save(); var dir = $(/^@import(?:-(once))?\s+/); if (dir && (path = $(this.entities.quoted) || $(this.entities.url))) { features = $(this.mediaFeatures); if ($(';')) { return new(tree.Import)(path, imports, features, (dir[1] === 'once'), index, env.rootpath); } } restore(); }, mediaFeature: function () { var e, p, nodes = []; do { if (e = $(this.entities.keyword)) { nodes.push(e); } else if ($('(')) { p = $(this.property); e = $(this.entity); if ($(')')) { if (p && e) { nodes.push(new(tree.Paren)(new(tree.Rule)(p, e, null, i, true))); } else if (e) { nodes.push(new(tree.Paren)(e)); } else { return null; } } else { return null } } } while (e); if (nodes.length > 0) { return new(tree.Expression)(nodes); } }, mediaFeatures: function () { var e, features = []; do { if (e = $(this.mediaFeature)) { features.push(e); if (! $(',')) { break } } else if (e = $(this.entities.variable)) { features.push(e); if (! $(',')) { break } } } while (e); return features.length > 0 ? features : null; }, media: function () { var features, rules, media, debugInfo; if (env.dumpLineNumbers) debugInfo = getDebugInfo(i, input, env); if ($(/^@media/)) { features = $(this.mediaFeatures); if (rules = $(this.block)) { media = new(tree.Media)(rules, features); if(env.dumpLineNumbers) media.debugInfo = debugInfo; return media; } } }, // // A CSS Directive // // @charset "utf-8"; // directive: function () { var name, value, rules, identifier, e, nodes, nonVendorSpecificName, hasBlock, hasIdentifier, hasExpression; if (input.charAt(i) !== '@') return; if (value = $(this['import']) || $(this.media)) { return value; } save(); name = $(/^@[a-z-]+/); if (!name) return; nonVendorSpecificName = name; if (name.charAt(1) == '-' && name.indexOf('-', 2) > 0) { nonVendorSpecificName = "@" + name.slice(name.indexOf('-', 2) + 1); } switch(nonVendorSpecificName) { case "@font-face": hasBlock = true; break; case "@viewport": case "@top-left": case "@top-left-corner": case "@top-center": case "@top-right": case "@top-right-corner": case "@bottom-left": case "@bottom-left-corner": case "@bottom-center": case "@bottom-right": case "@bottom-right-corner": case "@left-top": case "@left-middle": case "@left-bottom": case "@right-top": case "@right-middle": case "@right-bottom": hasBlock = true; break; case "@page": case "@document": case "@supports": case "@keyframes": hasBlock = true; hasIdentifier = true; break; case "@namespace": hasExpression = true; break; } if (hasIdentifier) { name += " " + ($(/^[^{]+/) || '').trim(); } if (hasBlock) { if (rules = $(this.block)) { return new(tree.Directive)(name, rules); } } else { if ((value = hasExpression ? $(this.expression) : $(this.entity)) && $(';')) { var directive = new(tree.Directive)(name, value); if (env.dumpLineNumbers) { directive.debugInfo = getDebugInfo(i, input, env); } return directive; } } restore(); }, font: function () { var value = [], expression = [], weight, shorthand, font, e; while (e = $(this.shorthand) || $(this.entity)) { expression.push(e); } value.push(new(tree.Expression)(expression)); if ($(',')) { while (e = $(this.expression)) { value.push(e); if (! $(',')) { break } } } return new(tree.Value)(value); }, // // A Value is a comma-delimited list of Expressions // // font-family: Baskerville, Georgia, serif; // // In a Rule, a Value represents everything after the `:`, // and before the `;`. // value: function () { var e, expressions = [], important; while (e = $(this.expression)) { expressions.push(e); if (! $(',')) { break } } if (expressions.length > 0) { return new(tree.Value)(expressions); } }, important: function () { if (input.charAt(i) === '!') { return $(/^! *important/); } }, sub: function () { var e; if ($('(') && (e = $(this.expression)) && $(')')) { return e; } }, multiplication: function () { var m, a, op, operation; if (m = $(this.operand)) { while (!peek(/^\/[*\/]/) && (op = ($('/') || $('*'))) && (a = $(this.operand))) { operation = new(tree.Operation)(op, [operation || m, a]); } return operation || m; } }, addition: function () { var m, a, op, operation; if (m = $(this.multiplication)) { while ((op = $(/^[-+]\s+/) || (!isWhitespace(input.charAt(i - 1)) && ($('+') || $('-')))) && (a = $(this.multiplication))) { operation = new(tree.Operation)(op, [operation || m, a]); } return operation || m; } }, conditions: function () { var a, b, index = i, condition; if (a = $(this.condition)) { while ($(',') && (b = $(this.condition))) { condition = new(tree.Condition)('or', condition || a, b, index); } return condition || a; } }, condition: function () { var a, b, c, op, index = i, negate = false; if ($(/^not/)) { negate = true } expect('('); if (a = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) { if (op = $(/^(?:>=|=<|[<=>])/)) { if (b = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) { c = new(tree.Condition)(op, a, b, index, negate); } else { error('expected expression'); } } else { c = new(tree.Condition)('=', a, new(tree.Keyword)('true'), index, negate); } expect(')'); return $(/^and/) ? new(tree.Condition)('and', c, $(this.condition)) : c; } }, // // An operand is anything that can be part of an operation, // such as a Color, or a Variable // operand: function () { var negate, p = input.charAt(i + 1); if (input.charAt(i) === '-' && (p === '@' || p === '(')) { negate = $('-') } var o = $(this.sub) || $(this.entities.dimension) || $(this.entities.color) || $(this.entities.variable) || $(this.entities.call); return negate ? new(tree.Operation)('*', [new(tree.Dimension)(-1), o]) : o; }, // // Expressions either represent mathematical operations, // or white-space delimited Entities. // // 1px solid black // @var * 2 // expression: function () { var e, delim, entities = [], d; while (e = $(this.addition) || $(this.entity)) { entities.push(e); } if (entities.length > 0) { return new(tree.Expression)(entities); } }, property: function () { var name; if (name = $(/^(\*?-?[_a-z0-9-]+)\s*:/)) { return name[1]; } } } }; }; if (less.mode === 'browser' || less.mode === 'rhino') { // // Used by `@import` directives // less.Parser.importer = function (path, paths, callback, env) { if (!/^([a-z-]+:)?\//.test(path) && paths.length > 0) { path = paths[0] + path; } // We pass `true` as 3rd argument, to force the reload of the import. // This is so we can get the syntax tree as opposed to just the CSS output, // as we need this to evaluate the current stylesheet. loadStyleSheet({ href: path, title: path, type: env.mime, contents: env.contents, files: env.files, rootpath: env.rootpath, entryPath: env.entryPath, relativeUrls: env.relativeUrls }, function (e, root, data, sheet, _, path) { if (e && typeof(env.errback) === "function") { env.errback.call(null, path, paths, callback, env); } else { callback.call(null, e, root, path); } }, true); }; } (function (tree) { tree.functions = { rgb: function (r, g, b) { return this.rgba(r, g, b, 1.0); }, rgba: function (r, g, b, a) { var rgb = [r, g, b].map(function (c) { return scaled(c, 256); }); a = number(a); return new(tree.Color)(rgb, a); }, hsl: function (h, s, l) { return this.hsla(h, s, l, 1.0); }, hsla: function (h, s, l, a) { h = (number(h) % 360) / 360; s = number(s); l = number(l); a = number(a); var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s; var m1 = l * 2 - m2; return this.rgba(hue(h + 1/3) * 255, hue(h) * 255, hue(h - 1/3) * 255, a); function hue(h) { h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h); if (h * 6 < 1) return m1 + (m2 - m1) * h * 6; else if (h * 2 < 1) return m2; else if (h * 3 < 2) return m1 + (m2 - m1) * (2/3 - h) * 6; else return m1; } }, hsv: function(h, s, v) { return this.hsva(h, s, v, 1.0); }, hsva: function(h, s, v, a) { h = ((number(h) % 360) / 360) * 360; s = number(s); v = number(v); a = number(a); var i, f; i = Math.floor((h / 60) % 6); f = (h / 60) - i; var vs = [v, v * (1 - s), v * (1 - f * s), v * (1 - (1 - f) * s)]; var perm = [[0, 3, 1], [2, 0, 1], [1, 0, 3], [1, 2, 0], [3, 1, 0], [0, 1, 2]]; return this.rgba(vs[perm[i][0]] * 255, vs[perm[i][1]] * 255, vs[perm[i][2]] * 255, a); }, hue: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().h)); }, saturation: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().s * 100), '%'); }, lightness: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().l * 100), '%'); }, red: function (color) { return new(tree.Dimension)(color.rgb[0]); }, green: function (color) { return new(tree.Dimension)(color.rgb[1]); }, blue: function (color) { return new(tree.Dimension)(color.rgb[2]); }, alpha: function (color) { return new(tree.Dimension)(color.toHSL().a); }, luma: function (color) { return new(tree.Dimension)(Math.round((0.2126 * (color.rgb[0]/255) + 0.7152 * (color.rgb[1]/255) + 0.0722 * (color.rgb[2]/255)) * color.alpha * 100), '%'); }, saturate: function (color, amount) { var hsl = color.toHSL(); hsl.s += amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, desaturate: function (color, amount) { var hsl = color.toHSL(); hsl.s -= amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, lighten: function (color, amount) { var hsl = color.toHSL(); hsl.l += amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, darken: function (color, amount) { var hsl = color.toHSL(); hsl.l -= amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, fadein: function (color, amount) { var hsl = color.toHSL(); hsl.a += amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, fadeout: function (color, amount) { var hsl = color.toHSL(); hsl.a -= amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, fade: function (color, amount) { var hsl = color.toHSL(); hsl.a = amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, spin: function (color, amount) { var hsl = color.toHSL(); var hue = (hsl.h + amount.value) % 360; hsl.h = hue < 0 ? 360 + hue : hue; return hsla(hsl); }, // // Copyright (c) 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein // http://sass-lang.com // mix: function (color1, color2, weight) { if (!weight) { weight = new(tree.Dimension)(50); } var p = weight.value / 100.0; var w = p * 2 - 1; var a = color1.toHSL().a - color2.toHSL().a; var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0; var w2 = 1 - w1; var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2, color1.rgb[1] * w1 + color2.rgb[1] * w2, color1.rgb[2] * w1 + color2.rgb[2] * w2]; var alpha = color1.alpha * p + color2.alpha * (1 - p); return new(tree.Color)(rgb, alpha); }, greyscale: function (color) { return this.desaturate(color, new(tree.Dimension)(100)); }, contrast: function (color, dark, light, threshold) { if (typeof light === 'undefined') { light = this.rgba(255, 255, 255, 1.0); } if (typeof dark === 'undefined') { dark = this.rgba(0, 0, 0, 1.0); } if (typeof threshold === 'undefined') { threshold = 0.43; } else { threshold = threshold.value; } if (((0.2126 * (color.rgb[0]/255) + 0.7152 * (color.rgb[1]/255) + 0.0722 * (color.rgb[2]/255)) * color.alpha) < threshold) { return light; } else { return dark; } }, e: function (str) { return new(tree.Anonymous)(str instanceof tree.JavaScript ? str.evaluated : str); }, escape: function (str) { return new(tree.Anonymous)(encodeURI(str.value).replace(/=/g, "%3D").replace(/:/g, "%3A").replace(/#/g, "%23").replace(/;/g, "%3B").replace(/\(/g, "%28").replace(/\)/g, "%29")); }, '%': function (quoted /* arg, arg, ...*/) { var args = Array.prototype.slice.call(arguments, 1), str = quoted.value; for (var i = 0; i < args.length; i++) { str = str.replace(/%[sda]/i, function(token) { var value = token.match(/s/i) ? args[i].value : args[i].toCSS(); return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value; }); } str = str.replace(/%%/g, '%'); return new(tree.Quoted)('"' + str + '"', str); }, unit: function (val, unit) { return new(tree.Dimension)(val.value, unit ? unit.toCSS() : ""); }, round: function (n, f) { var fraction = typeof(f) === "undefined" ? 0 : f.value; return this._math(function(num) { return num.toFixed(fraction); }, n); }, ceil: function (n) { return this._math(Math.ceil, n); }, floor: function (n) { return this._math(Math.floor, n); }, _math: function (fn, n) { if (n instanceof tree.Dimension) { return new(tree.Dimension)(fn(parseFloat(n.value)), n.unit); } else if (typeof(n) === 'number') { return fn(n); } else { throw { type: "Argument", message: "argument must be a number" }; } }, argb: function (color) { return new(tree.Anonymous)(color.toARGB()); }, percentage: function (n) { return new(tree.Dimension)(n.value * 100, '%'); }, color: function (n) { if (n instanceof tree.Quoted) { return new(tree.Color)(n.value.slice(1)); } else { throw { type: "Argument", message: "argument must be a string" }; } }, iscolor: function (n) { return this._isa(n, tree.Color); }, isnumber: function (n) { return this._isa(n, tree.Dimension); }, isstring: function (n) { return this._isa(n, tree.Quoted); }, iskeyword: function (n) { return this._isa(n, tree.Keyword); }, isurl: function (n) { return this._isa(n, tree.URL); }, ispixel: function (n) { return (n instanceof tree.Dimension) && n.unit === 'px' ? tree.True : tree.False; }, ispercentage: function (n) { return (n instanceof tree.Dimension) && n.unit === '%' ? tree.True : tree.False; }, isem: function (n) { return (n instanceof tree.Dimension) && n.unit === 'em' ? tree.True : tree.False; }, _isa: function (n, Type) { return (n instanceof Type) ? tree.True : tree.False; }, /* Blending modes */ multiply: function(color1, color2) { var r = color1.rgb[0] * color2.rgb[0] / 255; var g = color1.rgb[1] * color2.rgb[1] / 255; var b = color1.rgb[2] * color2.rgb[2] / 255; return this.rgb(r, g, b); }, screen: function(color1, color2) { var r = 255 - (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255; var g = 255 - (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255; var b = 255 - (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255; return this.rgb(r, g, b); }, overlay: function(color1, color2) { var r = color1.rgb[0] < 128 ? 2 * color1.rgb[0] * color2.rgb[0] / 255 : 255 - 2 * (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255; var g = color1.rgb[1] < 128 ? 2 * color1.rgb[1] * color2.rgb[1] / 255 : 255 - 2 * (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255; var b = color1.rgb[2] < 128 ? 2 * color1.rgb[2] * color2.rgb[2] / 255 : 255 - 2 * (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255; return this.rgb(r, g, b); }, softlight: function(color1, color2) { var t = color2.rgb[0] * color1.rgb[0] / 255; var r = t + color1.rgb[0] * (255 - (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255 - t) / 255; t = color2.rgb[1] * color1.rgb[1] / 255; var g = t + color1.rgb[1] * (255 - (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255 - t) / 255; t = color2.rgb[2] * color1.rgb[2] / 255; var b = t + color1.rgb[2] * (255 - (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255 - t) / 255; return this.rgb(r, g, b); }, hardlight: function(color1, color2) { var r = color2.rgb[0] < 128 ? 2 * color2.rgb[0] * color1.rgb[0] / 255 : 255 - 2 * (255 - color2.rgb[0]) * (255 - color1.rgb[0]) / 255; var g = color2.rgb[1] < 128 ? 2 * color2.rgb[1] * color1.rgb[1] / 255 : 255 - 2 * (255 - color2.rgb[1]) * (255 - color1.rgb[1]) / 255; var b = color2.rgb[2] < 128 ? 2 * color2.rgb[2] * color1.rgb[2] / 255 : 255 - 2 * (255 - color2.rgb[2]) * (255 - color1.rgb[2]) / 255; return this.rgb(r, g, b); }, difference: function(color1, color2) { var r = Math.abs(color1.rgb[0] - color2.rgb[0]); var g = Math.abs(color1.rgb[1] - color2.rgb[1]); var b = Math.abs(color1.rgb[2] - color2.rgb[2]); return this.rgb(r, g, b); }, exclusion: function(color1, color2) { var r = color1.rgb[0] + color2.rgb[0] * (255 - color1.rgb[0] - color1.rgb[0]) / 255; var g = color1.rgb[1] + color2.rgb[1] * (255 - color1.rgb[1] - color1.rgb[1]) / 255; var b = color1.rgb[2] + color2.rgb[2] * (255 - color1.rgb[2] - color1.rgb[2]) / 255; return this.rgb(r, g, b); }, average: function(color1, color2) { var r = (color1.rgb[0] + color2.rgb[0]) / 2; var g = (color1.rgb[1] + color2.rgb[1]) / 2; var b = (color1.rgb[2] + color2.rgb[2]) / 2; return this.rgb(r, g, b); }, negation: function(color1, color2) { var r = 255 - Math.abs(255 - color2.rgb[0] - color1.rgb[0]); var g = 255 - Math.abs(255 - color2.rgb[1] - color1.rgb[1]); var b = 255 - Math.abs(255 - color2.rgb[2] - color1.rgb[2]); return this.rgb(r, g, b); }, tint: function(color, amount) { return this.mix(this.rgb(255,255,255), color, amount); }, shade: function(color, amount) { return this.mix(this.rgb(0, 0, 0), color, amount); } }; function hsla(color) { return tree.functions.hsla(color.h, color.s, color.l, color.a); } function scaled(n, size) { if (n instanceof tree.Dimension && n.unit == '%') { return parseFloat(n.value * size / 100); } else { return number(n); } } function number(n) { if (n instanceof tree.Dimension) { return parseFloat(n.unit == '%' ? n.value / 100 : n.value); } else if (typeof(n) === 'number') { return n; } else { throw { error: "RuntimeError", message: "color functions take numbers as parameters" }; } } function clamp(val) { return Math.min(1, Math.max(0, val)); } })(require('./tree')); (function (tree) { tree.colors = { 'aliceblue':'#f0f8ff', 'antiquewhite':'#faebd7', 'aqua':'#00ffff', 'aquamarine':'#7fffd4', 'azure':'#f0ffff', 'beige':'#f5f5dc', 'bisque':'#ffe4c4', 'black':'#000000', 'blanchedalmond':'#ffebcd', 'blue':'#0000ff', 'blueviolet':'#8a2be2', 'brown':'#a52a2a', 'burlywood':'#deb887', 'cadetblue':'#5f9ea0', 'chartreuse':'#7fff00', 'chocolate':'#d2691e', 'coral':'#ff7f50', 'cornflowerblue':'#6495ed', 'cornsilk':'#fff8dc', 'crimson':'#dc143c', 'cyan':'#00ffff', 'darkblue':'#00008b', 'darkcyan':'#008b8b', 'darkgoldenrod':'#b8860b', 'darkgray':'#a9a9a9', 'darkgrey':'#a9a9a9', 'darkgreen':'#006400', 'darkkhaki':'#bdb76b', 'darkmagenta':'#8b008b', 'darkolivegreen':'#556b2f', 'darkorange':'#ff8c00', 'darkorchid':'#9932cc', 'darkred':'#8b0000', 'darksalmon':'#e9967a', 'darkseagreen':'#8fbc8f', 'darkslateblue':'#483d8b', 'darkslategray':'#2f4f4f', 'darkslategrey':'#2f4f4f', 'darkturquoise':'#00ced1', 'darkviolet':'#9400d3', 'deeppink':'#ff1493', 'deepskyblue':'#00bfff', 'dimgray':'#696969', 'dimgrey':'#696969', 'dodgerblue':'#1e90ff', 'firebrick':'#b22222', 'floralwhite':'#fffaf0', 'forestgreen':'#228b22', 'fuchsia':'#ff00ff', 'gainsboro':'#dcdcdc', 'ghostwhite':'#f8f8ff', 'gold':'#ffd700', 'goldenrod':'#daa520', 'gray':'#808080', 'grey':'#808080', 'green':'#008000', 'greenyellow':'#adff2f', 'honeydew':'#f0fff0', 'hotpink':'#ff69b4', 'indianred':'#cd5c5c', 'indigo':'#4b0082', 'ivory':'#fffff0', 'khaki':'#f0e68c', 'lavender':'#e6e6fa', 'lavenderblush':'#fff0f5', 'lawngreen':'#7cfc00', 'lemonchiffon':'#fffacd', 'lightblue':'#add8e6', 'lightcoral':'#f08080', 'lightcyan':'#e0ffff', 'lightgoldenrodyellow':'#fafad2', 'lightgray':'#d3d3d3', 'lightgrey':'#d3d3d3', 'lightgreen':'#90ee90', 'lightpink':'#ffb6c1', 'lightsalmon':'#ffa07a', 'lightseagreen':'#20b2aa', 'lightskyblue':'#87cefa', 'lightslategray':'#778899', 'lightslategrey':'#778899', 'lightsteelblue':'#b0c4de', 'lightyellow':'#ffffe0', 'lime':'#00ff00', 'limegreen':'#32cd32', 'linen':'#faf0e6', 'magenta':'#ff00ff', 'maroon':'#800000', 'mediumaquamarine':'#66cdaa', 'mediumblue':'#0000cd', 'mediumorchid':'#ba55d3', 'mediumpurple':'#9370d8', 'mediumseagreen':'#3cb371', 'mediumslateblue':'#7b68ee', 'mediumspringgreen':'#00fa9a', 'mediumturquoise':'#48d1cc', 'mediumvioletred':'#c71585', 'midnightblue':'#191970', 'mintcream':'#f5fffa', 'mistyrose':'#ffe4e1', 'moccasin':'#ffe4b5', 'navajowhite':'#ffdead', 'navy':'#000080', 'oldlace':'#fdf5e6', 'olive':'#808000', 'olivedrab':'#6b8e23', 'orange':'#ffa500', 'orangered':'#ff4500', 'orchid':'#da70d6', 'palegoldenrod':'#eee8aa', 'palegreen':'#98fb98', 'paleturquoise':'#afeeee', 'palevioletred':'#d87093', 'papayawhip':'#ffefd5', 'peachpuff':'#ffdab9', 'peru':'#cd853f', 'pink':'#ffc0cb', 'plum':'#dda0dd', 'powderblue':'#b0e0e6', 'purple':'#800080', 'red':'#ff0000', 'rosybrown':'#bc8f8f', 'royalblue':'#4169e1', 'saddlebrown':'#8b4513', 'salmon':'#fa8072', 'sandybrown':'#f4a460', 'seagreen':'#2e8b57', 'seashell':'#fff5ee', 'sienna':'#a0522d', 'silver':'#c0c0c0', 'skyblue':'#87ceeb', 'slateblue':'#6a5acd', 'slategray':'#708090', 'slategrey':'#708090', 'snow':'#fffafa', 'springgreen':'#00ff7f', 'steelblue':'#4682b4', 'tan':'#d2b48c', 'teal':'#008080', 'thistle':'#d8bfd8', 'tomato':'#ff6347', // 'transparent':'rgba(0,0,0,0)', 'turquoise':'#40e0d0', 'violet':'#ee82ee', 'wheat':'#f5deb3', 'white':'#ffffff', 'whitesmoke':'#f5f5f5', 'yellow':'#ffff00', 'yellowgreen':'#9acd32' }; })(require('./tree')); (function (tree) { tree.Alpha = function (val) { this.value = val; }; tree.Alpha.prototype = { toCSS: function () { return "alpha(opacity=" + (this.value.toCSS ? this.value.toCSS() : this.value) + ")"; }, eval: function (env) { if (this.value.eval) { this.value = this.value.eval(env) } return this; } }; })(require('../tree')); (function (tree) { tree.Anonymous = function (string) { this.value = string.value || string; }; tree.Anonymous.prototype = { toCSS: function () { return this.value; }, eval: function () { return this }, compare: function (x) { if (!x.toCSS) { return -1; } var left = this.toCSS(), right = x.toCSS(); if (left === right) { return 0; } return left < right ? -1 : 1; } }; })(require('../tree')); (function (tree) { tree.Assignment = function (key, val) { this.key = key; this.value = val; }; tree.Assignment.prototype = { toCSS: function () { return this.key + '=' + (this.value.toCSS ? this.value.toCSS() : this.value); }, eval: function (env) { if (this.value.eval) { return new(tree.Assignment)(this.key, this.value.eval(env)); } return this; } }; })(require('../tree'));(function (tree) { // // A function call node. // tree.Call = function (name, args, index, filename) { this.name = name; this.args = args; this.index = index; this.filename = filename; }; tree.Call.prototype = { // // When evaluating a function call, // we either find the function in `tree.functions` [1], // in which case we call it, passing the evaluated arguments, // or we simply print it out as it appeared originally [2]. // // The *functions.js* file contains the built-in functions. // // The reason why we evaluate the arguments, is in the case where // we try to pass a variable to a function, like: `saturate(@color)`. // The function should receive the value, not the variable. // eval: function (env) { var args = this.args.map(function (a) { return a.eval(env) }); if (this.name in tree.functions) { // 1. try { return tree.functions[this.name].apply(tree.functions, args); } catch (e) { throw { type: e.type || "Runtime", message: "error evaluating function `" + this.name + "`" + (e.message ? ': ' + e.message : ''), index: this.index, filename: this.filename }; } } else { // 2. return new(tree.Anonymous)(this.name + "(" + args.map(function (a) { return a.toCSS(env) }).join(', ') + ")"); } }, toCSS: function (env) { return this.eval(env).toCSS(); } }; })(require('../tree')); (function (tree) { // // RGB Colors - #ff0014, #eee // tree.Color = function (rgb, a) { // // The end goal here, is to parse the arguments // into an integer triplet, such as `128, 255, 0` // // This facilitates operations and conversions. // if (Array.isArray(rgb)) { this.rgb = rgb; } else if (rgb.length == 6) { this.rgb = rgb.match(/.{2}/g).map(function (c) { return parseInt(c, 16); }); } else { this.rgb = rgb.split('').map(function (c) { return parseInt(c + c, 16); }); } this.alpha = typeof(a) === 'number' ? a : 1; }; tree.Color.prototype = { eval: function () { return this }, // // If we have some transparency, the only way to represent it // is via `rgba`. Otherwise, we use the hex representation, // which has better compatibility with older browsers. // Values are capped between `0` and `255`, rounded and zero-padded. // toCSS: function () { if (this.alpha < 1.0) { return "rgba(" + this.rgb.map(function (c) { return Math.round(c); }).concat(this.alpha).join(', ') + ")"; } else { return '#' + this.rgb.map(function (i) { i = Math.round(i); i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16); return i.length === 1 ? '0' + i : i; }).join(''); } }, // // Operations have to be done per-channel, if not, // channels will spill onto each other. Once we have // our result, in the form of an integer triplet, // we create a new Color node to hold the result. // operate: function (op, other) { var result = []; if (! (other instanceof tree.Color)) { other = other.toColor(); } for (var c = 0; c < 3; c++) { result[c] = tree.operate(op, this.rgb[c], other.rgb[c]); } return new(tree.Color)(result, this.alpha + other.alpha); }, toHSL: function () { var r = this.rgb[0] / 255, g = this.rgb[1] / 255, b = this.rgb[2] / 255, a = this.alpha; var max = Math.max(r, g, b), min = Math.min(r, g, b); var h, s, l = (max + min) / 2, d = max - min; if (max === min) { h = s = 0; } else { s = l > 0.5 ? d / (2 - max - min) : d / (max + min); switch (max) { case r: h = (g - b) / d + (g < b ? 6 : 0); break; case g: h = (b - r) / d + 2; break; case b: h = (r - g) / d + 4; break; } h /= 6; } return { h: h * 360, s: s, l: l, a: a }; }, toARGB: function () { var argb = [Math.round(this.alpha * 255)].concat(this.rgb); return '#' + argb.map(function (i) { i = Math.round(i); i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16); return i.length === 1 ? '0' + i : i; }).join(''); }, compare: function (x) { if (!x.rgb) { return -1; } return (x.rgb[0] === this.rgb[0] && x.rgb[1] === this.rgb[1] && x.rgb[2] === this.rgb[2] && x.alpha === this.alpha) ? 0 : -1; } }; })(require('../tree')); (function (tree) { tree.Comment = function (value, silent) { this.value = value; this.silent = !!silent; }; tree.Comment.prototype = { toCSS: function (env) { return env.compress ? '' : this.value; }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.Condition = function (op, l, r, i, negate) { this.op = op.trim(); this.lvalue = l; this.rvalue = r; this.index = i; this.negate = negate; }; tree.Condition.prototype.eval = function (env) { var a = this.lvalue.eval(env), b = this.rvalue.eval(env); var i = this.index, result; var result = (function (op) { switch (op) { case 'and': return a && b; case 'or': return a || b; default: if (a.compare) { result = a.compare(b); } else if (b.compare) { result = b.compare(a); } else { throw { type: "Type", message: "Unable to perform comparison", index: i }; } switch (result) { case -1: return op === '<' || op === '=<'; case 0: return op === '=' || op === '>=' || op === '=<'; case 1: return op === '>' || op === '>='; } } })(this.op); return this.negate ? !result : result; }; })(require('../tree')); (function (tree) { // // A number with a unit // tree.Dimension = function (value, unit) { this.value = parseFloat(value); this.unit = unit || null; }; tree.Dimension.prototype = { eval: function () { return this }, toColor: function () { return new(tree.Color)([this.value, this.value, this.value]); }, toCSS: function () { var css = this.value + this.unit; return css; }, // In an operation between two Dimensions, // we default to the first Dimension's unit, // so `1px + 2em` will yield `3px`. // In the future, we could implement some unit // conversions such that `100cm + 10mm` would yield // `101cm`. operate: function (op, other) { return new(tree.Dimension) (tree.operate(op, this.value, other.value), this.unit || other.unit); }, compare: function (other) { if (other instanceof tree.Dimension) { if (other.value > this.value) { return -1; } else if (other.value < this.value) { return 1; } else { if (other.unit && this.unit !== other.unit) { return -1; } return 0; } } else { return -1; } } }; })(require('../tree')); (function (tree) { tree.Directive = function (name, value) { this.name = name; if (Array.isArray(value)) { this.ruleset = new(tree.Ruleset)([], value); this.ruleset.allowImports = true; } else { this.value = value; } }; tree.Directive.prototype = { toCSS: function (ctx, env) { if (this.ruleset) { this.ruleset.root = true; return this.name + (env.compress ? '{' : ' {\n ') + this.ruleset.toCSS(ctx, env).trim().replace(/\n/g, '\n ') + (env.compress ? '}': '\n}\n'); } else { return this.name + ' ' + this.value.toCSS() + ';\n'; } }, eval: function (env) { var evaldDirective = this; if (this.ruleset) { env.frames.unshift(this); evaldDirective = new(tree.Directive)(this.name); evaldDirective.ruleset = this.ruleset.eval(env); env.frames.shift(); } return evaldDirective; }, variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) }, find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) }, rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) } }; })(require('../tree')); (function (tree) { tree.Element = function (combinator, value, index) { this.combinator = combinator instanceof tree.Combinator ? combinator : new(tree.Combinator)(combinator); if (typeof(value) === 'string') { this.value = value.trim(); } else if (value) { this.value = value; } else { this.value = ""; } this.index = index; }; tree.Element.prototype.eval = function (env) { return new(tree.Element)(this.combinator, this.value.eval ? this.value.eval(env) : this.value, this.index); }; tree.Element.prototype.toCSS = function (env) { var value = (this.value.toCSS ? this.value.toCSS(env) : this.value); if (value == '' && this.combinator.value.charAt(0) == '&') { return ''; } else { return this.combinator.toCSS(env || {}) + value; } }; tree.Combinator = function (value) { if (value === ' ') { this.value = ' '; } else { this.value = value ? value.trim() : ""; } }; tree.Combinator.prototype.toCSS = function (env) { return { '' : '', ' ' : ' ', ':' : ' :', '+' : env.compress ? '+' : ' + ', '~' : env.compress ? '~' : ' ~ ', '>' : env.compress ? '>' : ' > ', '|' : env.compress ? '|' : ' | ' }[this.value]; }; })(require('../tree')); (function (tree) { tree.Expression = function (value) { this.value = value }; tree.Expression.prototype = { eval: function (env) { if (this.value.length > 1) { return new(tree.Expression)(this.value.map(function (e) { return e.eval(env); })); } else if (this.value.length === 1) { return this.value[0].eval(env); } else { return this; } }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS ? e.toCSS(env) : ''; }).join(' '); } }; })(require('../tree')); (function (tree) { // // CSS @import node // // The general strategy here is that we don't want to wait // for the parsing to be completed, before we start importing // the file. That's because in the context of a browser, // most of the time will be spent waiting for the server to respond. // // On creation, we push the import path to our import queue, though // `import,push`, we also pass it a callback, which it'll call once // the file has been fetched, and parsed. // tree.Import = function (path, imports, features, once, index, rootpath) { var that = this; this.once = once; this.index = index; this._path = path; this.features = features && new(tree.Value)(features); this.rootpath = rootpath; // The '.less' extension is optional if (path instanceof tree.Quoted) { this.path = /(\.[a-z]*$)|([\?;].*)$/.test(path.value) ? path.value : path.value + '.less'; } else { this.path = path.value.value || path.value; } this.css = /css([\?;].*)?$/.test(this.path); // Only pre-compile .less files if (! this.css) { imports.push(this.path, function (e, root, imported) { if (e) { e.index = index } if (imported && that.once) that.skip = imported; that.root = root || new(tree.Ruleset)([], []); }); } }; // // The actual import node doesn't return anything, when converted to CSS. // The reason is that it's used at the evaluation stage, so that the rules // it imports can be treated like any other rules. // // In `eval`, we make sure all Import nodes get evaluated, recursively, so // we end up with a flat structure, which can easily be imported in the parent // ruleset. // tree.Import.prototype = { toCSS: function (env) { var features = this.features ? ' ' + this.features.toCSS(env) : ''; if (this.css) { // Add the base path if the import is relative if (typeof this._path.value === "string" && !/^(?:[a-z-]+:|\/)/.test(this._path.value)) { this._path.value = this.rootpath + this._path.value; } return "@import " + this._path.toCSS() + features + ';\n'; } else { return ""; } }, eval: function (env) { var ruleset, features = this.features && this.features.eval(env); if (this.skip) return []; if (this.css) { return this; } else { ruleset = new(tree.Ruleset)([], this.root.rules.slice(0)); ruleset.evalImports(env); return this.features ? new(tree.Media)(ruleset.rules, this.features.value) : ruleset.rules; } } }; })(require('../tree')); (function (tree) { tree.JavaScript = function (string, index, escaped) { this.escaped = escaped; this.expression = string; this.index = index; }; tree.JavaScript.prototype = { eval: function (env) { var result, that = this, context = {}; var expression = this.expression.replace(/@\{([\w-]+)\}/g, function (_, name) { return tree.jsify(new(tree.Variable)('@' + name, that.index).eval(env)); }); try { expression = new(Function)('return (' + expression + ')'); } catch (e) { throw { message: "JavaScript evaluation error: `" + expression + "`" , index: this.index }; } for (var k in env.frames[0].variables()) { context[k.slice(1)] = { value: env.frames[0].variables()[k].value, toJS: function () { return this.value.eval(env).toCSS(); } }; } try { result = expression.call(context); } catch (e) { throw { message: "JavaScript evaluation error: '" + e.name + ': ' + e.message + "'" , index: this.index }; } if (typeof(result) === 'string') { return new(tree.Quoted)('"' + result + '"', result, this.escaped, this.index); } else if (Array.isArray(result)) { return new(tree.Anonymous)(result.join(', ')); } else { return new(tree.Anonymous)(result); } } }; })(require('../tree')); (function (tree) { tree.Keyword = function (value) { this.value = value }; tree.Keyword.prototype = { eval: function () { return this }, toCSS: function () { return this.value }, compare: function (other) { if (other instanceof tree.Keyword) { return other.value === this.value ? 0 : 1; } else { return -1; } } }; tree.True = new(tree.Keyword)('true'); tree.False = new(tree.Keyword)('false'); })(require('../tree')); (function (tree) { tree.Media = function (value, features) { var selectors = this.emptySelectors(); this.features = new(tree.Value)(features); this.ruleset = new(tree.Ruleset)(selectors, value); this.ruleset.allowImports = true; }; tree.Media.prototype = { toCSS: function (ctx, env) { var features = this.features.toCSS(env); this.ruleset.root = (ctx.length === 0 || ctx[0].multiMedia); return '@media ' + features + (env.compress ? '{' : ' {\n ') + this.ruleset.toCSS(ctx, env).trim().replace(/\n/g, '\n ') + (env.compress ? '}': '\n}\n'); }, eval: function (env) { if (!env.mediaBlocks) { env.mediaBlocks = []; env.mediaPath = []; } var media = new(tree.Media)([], []); if(this.debugInfo) { this.ruleset.debugInfo = this.debugInfo; media.debugInfo = this.debugInfo; } media.features = this.features.eval(env); env.mediaPath.push(media); env.mediaBlocks.push(media); env.frames.unshift(this.ruleset); media.ruleset = this.ruleset.eval(env); env.frames.shift(); env.mediaPath.pop(); return env.mediaPath.length === 0 ? media.evalTop(env) : media.evalNested(env) }, variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) }, find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) }, rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) }, emptySelectors: function() { var el = new(tree.Element)('', '&', 0); return [new(tree.Selector)([el])]; }, evalTop: function (env) { var result = this; // Render all dependent Media blocks. if (env.mediaBlocks.length > 1) { var selectors = this.emptySelectors(); result = new(tree.Ruleset)(selectors, env.mediaBlocks); result.multiMedia = true; } delete env.mediaBlocks; delete env.mediaPath; return result; }, evalNested: function (env) { var i, value, path = env.mediaPath.concat([this]); // Extract the media-query conditions separated with `,` (OR). for (i = 0; i < path.length; i++) { value = path[i].features instanceof tree.Value ? path[i].features.value : path[i].features; path[i] = Array.isArray(value) ? value : [value]; } // Trace all permutations to generate the resulting media-query. // // (a, b and c) with nested (d, e) -> // a and d // a and e // b and c and d // b and c and e this.features = new(tree.Value)(this.permute(path).map(function (path) { path = path.map(function (fragment) { return fragment.toCSS ? fragment : new(tree.Anonymous)(fragment); }); for(i = path.length - 1; i > 0; i--) { path.splice(i, 0, new(tree.Anonymous)("and")); } return new(tree.Expression)(path); })); // Fake a tree-node that doesn't output anything. return new(tree.Ruleset)([], []); }, permute: function (arr) { if (arr.length === 0) { return []; } else if (arr.length === 1) { return arr[0]; } else { var result = []; var rest = this.permute(arr.slice(1)); for (var i = 0; i < rest.length; i++) { for (var j = 0; j < arr[0].length; j++) { result.push([arr[0][j]].concat(rest[i])); } } return result; } }, bubbleSelectors: function (selectors) { this.ruleset = new(tree.Ruleset)(selectors.slice(0), [this.ruleset]); } }; })(require('../tree')); (function (tree) { tree.mixin = {}; tree.mixin.Call = function (elements, args, index, filename, important) { this.selector = new(tree.Selector)(elements); this.arguments = args; this.index = index; this.filename = filename; this.important = important; }; tree.mixin.Call.prototype = { eval: function (env) { var mixins, mixin, args, rules = [], match = false, i, m, f, isRecursive, isOneFound; args = this.arguments && this.arguments.map(function (a) { return { name: a.name, value: a.value.eval(env) }; }); for (i = 0; i < env.frames.length; i++) { if ((mixins = env.frames[i].find(this.selector)).length > 0) { isOneFound = true; for (m = 0; m < mixins.length; m++) { mixin = mixins[m]; isRecursive = false; for(f = 0; f < env.frames.length; f++) { if ((!(mixin instanceof tree.mixin.Definition)) && mixin === (env.frames[f].originalRuleset || env.frames[f])) { isRecursive = true; break; } } if (isRecursive) { continue; } if (mixin.matchArgs(args, env)) { if (!mixin.matchCondition || mixin.matchCondition(args, env)) { try { Array.prototype.push.apply( rules, mixin.eval(env, args, this.important).rules); } catch (e) { throw { message: e.message, index: this.index, filename: this.filename, stack: e.stack }; } } match = true; } } if (match) { return rules; } } } if (isOneFound) { throw { type: 'Runtime', message: 'No matching definition was found for `' + this.selector.toCSS().trim() + '(' + (args ? args.map(function (a) { var argValue = ""; if (a.name) { argValue += a.name + ":"; } if (a.value.toCSS) { argValue += a.value.toCSS(); } else { argValue += "???"; } return argValue; }).join(', ') : "") + ")`", index: this.index, filename: this.filename }; } else { throw { type: 'Name', message: this.selector.toCSS().trim() + " is undefined", index: this.index, filename: this.filename }; } } }; tree.mixin.Definition = function (name, params, rules, condition, variadic) { this.name = name; this.selectors = [new(tree.Selector)([new(tree.Element)(null, name)])]; this.params = params; this.condition = condition; this.variadic = variadic; this.arity = params.length; this.rules = rules; this._lookups = {}; this.required = params.reduce(function (count, p) { if (!p.name || (p.name && !p.value)) { return count + 1 } else { return count } }, 0); this.parent = tree.Ruleset.prototype; this.frames = []; }; tree.mixin.Definition.prototype = { toCSS: function () { return "" }, variable: function (name) { return this.parent.variable.call(this, name) }, variables: function () { return this.parent.variables.call(this) }, find: function () { return this.parent.find.apply(this, arguments) }, rulesets: function () { return this.parent.rulesets.apply(this) }, evalParams: function (env, mixinEnv, args, evaldArguments) { var frame = new(tree.Ruleset)(null, []), varargs, arg, params = this.params.slice(0), i, j, val, name, isNamedFound, argIndex; if (args) { args = args.slice(0); for(i = 0; i < args.length; i++) { arg = args[i]; if (name = (arg && arg.name)) { isNamedFound = false; for(j = 0; j < params.length; j++) { if (!evaldArguments[j] && name === params[j].name) { evaldArguments[j] = arg.value.eval(env); frame.rules.unshift(new(tree.Rule)(name, arg.value.eval(env))); isNamedFound = true; break; } } if (isNamedFound) { args.splice(i, 1); i--; continue; } else { throw { type: 'Runtime', message: "Named argument for " + this.name + ' ' + args[i].name + ' not found' }; } } } } argIndex = 0; for (i = 0; i < params.length; i++) { if (evaldArguments[i]) continue; arg = args && args[argIndex]; if (name = params[i].name) { if (params[i].variadic && args) { varargs = []; for (j = argIndex; j < args.length; j++) { varargs.push(args[j].value.eval(env)); } frame.rules.unshift(new(tree.Rule)(name, new(tree.Expression)(varargs).eval(env))); } else { val = arg && arg.value; if (val) { val = val.eval(env); } else if (params[i].value) { val = params[i].value.eval(mixinEnv); } else { throw { type: 'Runtime', message: "wrong number of arguments for " + this.name + ' (' + args.length + ' for ' + this.arity + ')' }; } frame.rules.unshift(new(tree.Rule)(name, val)); evaldArguments[i] = val; } } if (params[i].variadic && args) { for (j = argIndex; j < args.length; j++) { evaldArguments[j] = args[j].value.eval(env); } } argIndex++; } return frame; }, eval: function (env, args, important) { var _arguments = [], mixinFrames = this.frames.concat(env.frames), frame = this.evalParams(env, {frames: mixinFrames}, args, _arguments), context, rules, start, ruleset; frame.rules.unshift(new(tree.Rule)('@arguments', new(tree.Expression)(_arguments).eval(env))); rules = important ? this.parent.makeImportant.apply(this).rules : this.rules.slice(0); ruleset = new(tree.Ruleset)(null, rules).eval({ frames: [this, frame].concat(mixinFrames) }); ruleset.originalRuleset = this; return ruleset; }, matchCondition: function (args, env) { if (this.condition && !this.condition.eval({ frames: [this.evalParams(env, {frames: this.frames.concat(env.frames)}, args, [])].concat(env.frames) })) { return false } return true; }, matchArgs: function (args, env) { var argsLength = (args && args.length) || 0, len, frame; if (! this.variadic) { if (argsLength < this.required) { return false } if (argsLength > this.params.length) { return false } if ((this.required > 0) && (argsLength > this.params.length)) { return false } } len = Math.min(argsLength, this.arity); for (var i = 0; i < len; i++) { if (!this.params[i].name && !this.params[i].variadic) { if (args[i].value.eval(env).toCSS() != this.params[i].value.eval(env).toCSS()) { return false; } } } return true; } }; })(require('../tree')); (function (tree) { tree.Operation = function (op, operands) { this.op = op.trim(); this.operands = operands; }; tree.Operation.prototype.eval = function (env) { var a = this.operands[0].eval(env), b = this.operands[1].eval(env), temp; if (a instanceof tree.Dimension && b instanceof tree.Color) { if (this.op === '*' || this.op === '+') { temp = b, b = a, a = temp; } else { throw { name: "OperationError", message: "Can't substract or divide a color from a number" }; } } if (!a.operate) { throw { name: "OperationError", message: "Operation on an invalid type" }; } return a.operate(this.op, b); }; tree.operate = function (op, a, b) { switch (op) { case '+': return a + b; case '-': return a - b; case '*': return a * b; case '/': return a / b; } }; })(require('../tree')); (function (tree) { tree.Paren = function (node) { this.value = node; }; tree.Paren.prototype = { toCSS: function (env) { return '(' + this.value.toCSS(env) + ')'; }, eval: function (env) { return new(tree.Paren)(this.value.eval(env)); } }; })(require('../tree')); (function (tree) { tree.Quoted = function (str, content, escaped, i) { this.escaped = escaped; this.value = content || ''; this.quote = str.charAt(0); this.index = i; }; tree.Quoted.prototype = { toCSS: function () { if (this.escaped) { return this.value; } else { return this.quote + this.value + this.quote; } }, eval: function (env) { var that = this; var value = this.value.replace(/`([^`]+)`/g, function (_, exp) { return new(tree.JavaScript)(exp, that.index, true).eval(env).value; }).replace(/@\{([\w-]+)\}/g, function (_, name) { var v = new(tree.Variable)('@' + name, that.index).eval(env); return (v instanceof tree.Quoted) ? v.value : v.toCSS(); }); return new(tree.Quoted)(this.quote + value + this.quote, value, this.escaped, this.index); }, compare: function (x) { if (!x.toCSS) { return -1; } var left = this.toCSS(), right = x.toCSS(); if (left === right) { return 0; } return left < right ? -1 : 1; } }; })(require('../tree')); (function (tree) { tree.Ratio = function (value) { this.value = value; }; tree.Ratio.prototype = { toCSS: function (env) { return this.value; }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.Rule = function (name, value, important, index, inline) { this.name = name; this.value = (value instanceof tree.Value) ? value : new(tree.Value)([value]); this.important = important ? ' ' + important.trim() : ''; this.index = index; this.inline = inline || false; if (name.charAt(0) === '@') { this.variable = true; } else { this.variable = false } }; tree.Rule.prototype.toCSS = function (env) { if (this.variable) { return "" } else { return this.name + (env.compress ? ':' : ': ') + this.value.toCSS(env) + this.important + (this.inline ? "" : ";"); } }; tree.Rule.prototype.eval = function (context) { return new(tree.Rule)(this.name, this.value.eval(context), this.important, this.index, this.inline); }; tree.Rule.prototype.makeImportant = function () { return new(tree.Rule)(this.name, this.value, "!important", this.index, this.inline); }; tree.Shorthand = function (a, b) { this.a = a; this.b = b; }; tree.Shorthand.prototype = { toCSS: function (env) { return this.a.toCSS(env) + "/" + this.b.toCSS(env); }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.Ruleset = function (selectors, rules, strictImports) { this.selectors = selectors; this.rules = rules; this._lookups = {}; this.strictImports = strictImports; }; tree.Ruleset.prototype = { eval: function (env) { var selectors = this.selectors && this.selectors.map(function (s) { return s.eval(env) }); var ruleset = new(tree.Ruleset)(selectors, this.rules.slice(0), this.strictImports); var rules; ruleset.originalRuleset = this; ruleset.root = this.root; ruleset.allowImports = this.allowImports; if(this.debugInfo) { ruleset.debugInfo = this.debugInfo; } // push the current ruleset to the frames stack env.frames.unshift(ruleset); // Evaluate imports if (ruleset.root || ruleset.allowImports || !ruleset.strictImports) { ruleset.evalImports(env); } // Store the frames around mixin definitions, // so they can be evaluated like closures when the time comes. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Definition) { ruleset.rules[i].frames = env.frames.slice(0); } } var mediaBlockCount = (env.mediaBlocks && env.mediaBlocks.length) || 0; // Evaluate mixin calls. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Call) { rules = ruleset.rules[i].eval(env); ruleset.rules.splice.apply(ruleset.rules, [i, 1].concat(rules)); i += rules.length-1; ruleset.resetCache(); } } // Evaluate everything else for (var i = 0, rule; i < ruleset.rules.length; i++) { rule = ruleset.rules[i]; if (! (rule instanceof tree.mixin.Definition)) { ruleset.rules[i] = rule.eval ? rule.eval(env) : rule; } } // Pop the stack env.frames.shift(); if (env.mediaBlocks) { for(var i = mediaBlockCount; i < env.mediaBlocks.length; i++) { env.mediaBlocks[i].bubbleSelectors(selectors); } } return ruleset; }, evalImports: function(env) { var i, rules; for (i = 0; i < this.rules.length; i++) { if (this.rules[i] instanceof tree.Import) { rules = this.rules[i].eval(env); if (typeof rules.length === "number") { this.rules.splice.apply(this.rules, [i, 1].concat(rules)); i+= rules.length-1; } else { this.rules.splice(i, 1, rules); } this.resetCache(); } } }, makeImportant: function() { return new tree.Ruleset(this.selectors, this.rules.map(function (r) { if (r.makeImportant) { return r.makeImportant(); } else { return r; } }), this.strictImports); }, matchArgs: function (args) { return !args || args.length === 0; }, resetCache: function () { this._rulesets = null; this._variables = null; this._lookups = {}; }, variables: function () { if (this._variables) { return this._variables } else { return this._variables = this.rules.reduce(function (hash, r) { if (r instanceof tree.Rule && r.variable === true) { hash[r.name] = r; } return hash; }, {}); } }, variable: function (name) { return this.variables()[name]; }, rulesets: function () { if (this._rulesets) { return this._rulesets } else { return this._rulesets = this.rules.filter(function (r) { return (r instanceof tree.Ruleset) || (r instanceof tree.mixin.Definition); }); } }, find: function (selector, self) { self = self || this; var rules = [], rule, match, key = selector.toCSS(); if (key in this._lookups) { return this._lookups[key] } this.rulesets().forEach(function (rule) { if (rule !== self) { for (var j = 0; j < rule.selectors.length; j++) { if (match = selector.match(rule.selectors[j])) { if (selector.elements.length > rule.selectors[j].elements.length) { Array.prototype.push.apply(rules, rule.find( new(tree.Selector)(selector.elements.slice(1)), self)); } else { rules.push(rule); } break; } } } }); return this._lookups[key] = rules; }, // // Entry point for code generation // // `context` holds an array of arrays. // toCSS: function (context, env) { var css = [], // The CSS output rules = [], // node.Rule instances _rules = [], // rulesets = [], // node.Ruleset instances paths = [], // Current selectors selector, // The fully rendered selector debugInfo, // Line number debugging rule; if (! this.root) { this.joinSelectors(paths, context, this.selectors); } // Compile rules and rulesets for (var i = 0; i < this.rules.length; i++) { rule = this.rules[i]; if (rule.rules || (rule instanceof tree.Media)) { rulesets.push(rule.toCSS(paths, env)); } else if (rule instanceof tree.Directive) { var cssValue = rule.toCSS(paths, env); // Output only the first @charset definition as such - convert the others // to comments in case debug is enabled if (rule.name === "@charset") { // Only output the debug info together with subsequent @charset definitions // a comment (or @media statement) before the actual @charset directive would // be considered illegal css as it has to be on the first line if (env.charset) { if (rule.debugInfo) { rulesets.push(tree.debugInfo(env, rule)); rulesets.push(new tree.Comment("/* "+cssValue.replace(/\n/g, "")+" */\n").toCSS(env)); } continue; } env.charset = true; } rulesets.push(cssValue); } else if (rule instanceof tree.Comment) { if (!rule.silent) { if (this.root) { rulesets.push(rule.toCSS(env)); } else { rules.push(rule.toCSS(env)); } } } else { if (rule.toCSS && !rule.variable) { rules.push(rule.toCSS(env)); } else if (rule.value && !rule.variable) { rules.push(rule.value.toString()); } } } rulesets = rulesets.join(''); // If this is the root node, we don't render // a selector, or {}. // Otherwise, only output if this ruleset has rules. if (this.root) { css.push(rules.join(env.compress ? '' : '\n')); } else { if (rules.length > 0) { debugInfo = tree.debugInfo(env, this); selector = paths.map(function (p) { return p.map(function (s) { return s.toCSS(env); }).join('').trim(); }).join(env.compress ? ',' : ',\n'); // Remove duplicates for (var i = rules.length - 1; i >= 0; i--) { if (_rules.indexOf(rules[i]) === -1) { _rules.unshift(rules[i]); } } rules = _rules; css.push(debugInfo + selector + (env.compress ? '{' : ' {\n ') + rules.join(env.compress ? '' : '\n ') + (env.compress ? '}' : '\n}\n')); } } css.push(rulesets); return css.join('') + (env.compress ? '\n' : ''); }, joinSelectors: function (paths, context, selectors) { for (var s = 0; s < selectors.length; s++) { this.joinSelector(paths, context, selectors[s]); } }, joinSelector: function (paths, context, selector) { var i, j, k, hasParentSelector, newSelectors, el, sel, parentSel, newSelectorPath, afterParentJoin, newJoinedSelector, newJoinedSelectorEmpty, lastSelector, currentElements, selectorsMultiplied; for (i = 0; i < selector.elements.length; i++) { el = selector.elements[i]; if (el.value === '&') { hasParentSelector = true; } } if (!hasParentSelector) { if (context.length > 0) { for(i = 0; i < context.length; i++) { paths.push(context[i].concat(selector)); } } else { paths.push([selector]); } return; } // The paths are [[Selector]] // The first list is a list of comma seperated selectors // The inner list is a list of inheritance seperated selectors // e.g. // .a, .b { // .c { // } // } // == [[.a] [.c]] [[.b] [.c]] // // the elements from the current selector so far currentElements = []; // the current list of new selectors to add to the path. // We will build it up. We initiate it with one empty selector as we "multiply" the new selectors // by the parents newSelectors = [[]]; for (i = 0; i < selector.elements.length; i++) { el = selector.elements[i]; // non parent reference elements just get added if (el.value !== "&") { currentElements.push(el); } else { // the new list of selectors to add selectorsMultiplied = []; // merge the current list of non parent selector elements // on to the current list of selectors to add if (currentElements.length > 0) { this.mergeElementsOnToSelectors(currentElements, newSelectors); } // loop through our current selectors for(j = 0; j < newSelectors.length; j++) { sel = newSelectors[j]; // if we don't have any parent paths, the & might be in a mixin so that it can be used // whether there are parents or not if (context.length == 0) { // the combinator used on el should now be applied to the next element instead so that // it is not lost if (sel.length > 0) { sel[0].elements = sel[0].elements.slice(0); sel[0].elements.push(new(tree.Element)(el.combinator, '', 0)); //new Element(el.Combinator, "")); } selectorsMultiplied.push(sel); } else { // and the parent selectors for(k = 0; k < context.length; k++) { parentSel = context[k]; // We need to put the current selectors // then join the last selector's elements on to the parents selectors // our new selector path newSelectorPath = []; // selectors from the parent after the join afterParentJoin = []; newJoinedSelectorEmpty = true; //construct the joined selector - if & is the first thing this will be empty, // if not newJoinedSelector will be the last set of elements in the selector if (sel.length > 0) { newSelectorPath = sel.slice(0); lastSelector = newSelectorPath.pop(); newJoinedSelector = new(tree.Selector)(lastSelector.elements.slice(0)); newJoinedSelectorEmpty = false; } else { newJoinedSelector = new(tree.Selector)([]); } //put together the parent selectors after the join if (parentSel.length > 1) { afterParentJoin = afterParentJoin.concat(parentSel.slice(1)); } if (parentSel.length > 0) { newJoinedSelectorEmpty = false; // join the elements so far with the first part of the parent newJoinedSelector.elements.push(new(tree.Element)(el.combinator, parentSel[0].elements[0].value, 0)); newJoinedSelector.elements = newJoinedSelector.elements.concat(parentSel[0].elements.slice(1)); } if (!newJoinedSelectorEmpty) { // now add the joined selector newSelectorPath.push(newJoinedSelector); } // and the rest of the parent newSelectorPath = newSelectorPath.concat(afterParentJoin); // add that to our new set of selectors selectorsMultiplied.push(newSelectorPath); } } } // our new selectors has been multiplied, so reset the state newSelectors = selectorsMultiplied; currentElements = []; } } // if we have any elements left over (e.g. .a& .b == .b) // add them on to all the current selectors if (currentElements.length > 0) { this.mergeElementsOnToSelectors(currentElements, newSelectors); } for(i = 0; i < newSelectors.length; i++) { paths.push(newSelectors[i]); } }, mergeElementsOnToSelectors: function(elements, selectors) { var i, sel; if (selectors.length == 0) { selectors.push([ new(tree.Selector)(elements) ]); return; } for(i = 0; i < selectors.length; i++) { sel = selectors[i]; // if the previous thing in sel is a parent this needs to join on to it if (sel.length > 0) { sel[sel.length - 1] = new(tree.Selector)(sel[sel.length - 1].elements.concat(elements)); } else { sel.push(new(tree.Selector)(elements)); } } } }; })(require('../tree')); (function (tree) { tree.Selector = function (elements) { this.elements = elements; }; tree.Selector.prototype.match = function (other) { var elements = this.elements, len = elements.length, oelements, olen, max, i; oelements = other.elements.slice( (other.elements.length && other.elements[0].value === "&") ? 1 : 0); olen = oelements.length; max = Math.min(len, olen) if (olen === 0 || len < olen) { return false; } else { for (i = 0; i < max; i++) { if (elements[i].value !== oelements[i].value) { return false; } } } return true; }; tree.Selector.prototype.eval = function (env) { return new(tree.Selector)(this.elements.map(function (e) { return e.eval(env); })); }; tree.Selector.prototype.toCSS = function (env) { if (this._css) { return this._css } if (this.elements[0].combinator.value === "") { this._css = ' '; } else { this._css = ''; } this._css += this.elements.map(function (e) { if (typeof(e) === 'string') { return ' ' + e.trim(); } else { return e.toCSS(env); } }).join(''); return this._css; }; })(require('../tree')); (function (tree) { tree.UnicodeDescriptor = function (value) { this.value = value; }; tree.UnicodeDescriptor.prototype = { toCSS: function (env) { return this.value; }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.URL = function (val, rootpath) { this.value = val; this.rootpath = rootpath; }; tree.URL.prototype = { toCSS: function () { return "url(" + this.value.toCSS() + ")"; }, eval: function (ctx) { var val = this.value.eval(ctx), rootpath; // Add the base path if the URL is relative if (typeof val.value === "string" && !/^(?:[a-z-]+:|\/)/.test(val.value)) { rootpath = this.rootpath; if (!val.quote) { rootpath = rootpath.replace(/[\(\)'"\s]/g, function(match) { return "\\"+match; }); } val.value = rootpath + val.value; } return new(tree.URL)(val, this.rootpath); } }; })(require('../tree')); (function (tree) { tree.Value = function (value) { this.value = value; this.is = 'value'; }; tree.Value.prototype = { eval: function (env) { if (this.value.length === 1) { return this.value[0].eval(env); } else { return new(tree.Value)(this.value.map(function (v) { return v.eval(env); })); } }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS(env); }).join(env.compress ? ',' : ', '); } }; })(require('../tree')); (function (tree) { tree.Variable = function (name, index, file) { this.name = name, this.index = index, this.file = file }; tree.Variable.prototype = { eval: function (env) { var variable, v, name = this.name; if (name.indexOf('@@') == 0) { name = '@' + new(tree.Variable)(name.slice(1)).eval(env).value; } if (this.evaluating) { throw { type: 'Name', message: "Recursive variable definition for " + name, filename: this.file, index: this.index }; } this.evaluating = true; if (variable = tree.find(env.frames, function (frame) { if (v = frame.variable(name)) { return v.value.eval(env); } })) { this.evaluating = false; return variable; } else { throw { type: 'Name', message: "variable " + name + " is undefined", filename: this.file, index: this.index }; } } }; })(require('../tree')); (function (tree) { tree.debugInfo = function(env, ctx) { var result=""; if (env.dumpLineNumbers && !env.compress) { switch(env.dumpLineNumbers) { case 'comments': result = tree.debugInfo.asComment(ctx); break; case 'mediaquery': result = tree.debugInfo.asMediaQuery(ctx); break; case 'all': result = tree.debugInfo.asComment(ctx)+tree.debugInfo.asMediaQuery(ctx); break; } } return result; }; tree.debugInfo.asComment = function(ctx) { return '/* line ' + ctx.debugInfo.lineNumber + ', ' + ctx.debugInfo.fileName + ' */\n'; }; tree.debugInfo.asMediaQuery = function(ctx) { return '@media -sass-debug-info{filename{font-family:' + ('file://' + ctx.debugInfo.fileName).replace(/[\/:.]/g, '\\$&') + '}line{font-family:\\00003' + ctx.debugInfo.lineNumber + '}}\n'; }; tree.find = function (obj, fun) { for (var i = 0, r; i < obj.length; i++) { if (r = fun.call(obj, obj[i])) { return r } } return null; }; tree.jsify = function (obj) { if (Array.isArray(obj.value) && (obj.value.length > 1)) { return '[' + obj.value.map(function (v) { return v.toCSS(false) }).join(', ') + ']'; } else { return obj.toCSS(false); } }; })(require('./tree')); // // browser.js - client-side engine // var isFileProtocol = /^(file|chrome(-extension)?|resource|qrc|app):/.test(location.protocol); less.env = less.env || (location.hostname == '127.0.0.1' || location.hostname == '0.0.0.0' || location.hostname == 'localhost' || location.port.length > 0 || isFileProtocol ? 'development' : 'production'); // Load styles asynchronously (default: false) // // This is set to `false` by default, so that the body // doesn't start loading before the stylesheets are parsed. // Setting this to `true` can result in flickering. // less.async = less.async || false; less.fileAsync = less.fileAsync || false; // Interval between watch polls less.poll = less.poll || (isFileProtocol ? 1000 : 1500); //Setup user functions if (less.functions) { for(var func in less.functions) { less.tree.functions[func] = less.functions[func]; } } var dumpLineNumbers = /!dumpLineNumbers:(comments|mediaquery|all)/.exec(location.hash); if (dumpLineNumbers) { less.dumpLineNumbers = dumpLineNumbers[1]; } // // Watch mode // less.watch = function () { if (!less.watchMode ){ less.env = 'development'; initRunningMode(); } return this.watchMode = true }; less.unwatch = function () {clearInterval(less.watchTimer); return this.watchMode = false; }; function initRunningMode(){ if (less.env === 'development') { less.optimization = 0; less.watchTimer = setInterval(function () { if (less.watchMode) { loadStyleSheets(function (e, root, _, sheet, env) { if (root) { createCSS(root.toCSS(), sheet, env.lastModified); } }); } }, less.poll); } else { less.optimization = 3; } } if (/!watch/.test(location.hash)) { less.watch(); } var cache = null; if (less.env != 'development') { try { cache = (typeof(window.localStorage) === 'undefined') ? null : window.localStorage; } catch (_) {} } // // Get all tags with the 'rel' attribute set to "stylesheet/less" // var links = document.getElementsByTagName('link'); var typePattern = /^text\/(x-)?less$/; less.sheets = []; for (var i = 0; i < links.length; i++) { if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) && (links[i].type.match(typePattern)))) { less.sheets.push(links[i]); } } // // With this function, it's possible to alter variables and re-render // CSS without reloading less-files // var session_cache = ''; less.modifyVars = function(record) { var str = session_cache; for (name in record) { str += ((name.slice(0,1) === '@')? '' : '@') + name +': '+ ((record[name].slice(-1) === ';')? record[name] : record[name] +';'); } new(less.Parser)().parse(str, function (e, root) { createCSS(root.toCSS(), less.sheets[less.sheets.length - 1]); }); }; less.refresh = function (reload) { var startTime, endTime; startTime = endTime = new(Date); loadStyleSheets(function (e, root, _, sheet, env) { if (env.local) { log("loading " + sheet.href + " from cache."); } else { log("parsed " + sheet.href + " successfully."); createCSS(root.toCSS(), sheet, env.lastModified); } log("css for " + sheet.href + " generated in " + (new(Date) - endTime) + 'ms'); (env.remaining === 0) && log("css generated in " + (new(Date) - startTime) + 'ms'); endTime = new(Date); }, reload); loadStyles(); }; less.refreshStyles = loadStyles; less.refresh(less.env === 'development'); function loadStyles() { var styles = document.getElementsByTagName('style'); for (var i = 0; i < styles.length; i++) { if (styles[i].type.match(typePattern)) { new(less.Parser)({ filename: document.location.href.replace(/#.*$/, ''), dumpLineNumbers: less.dumpLineNumbers }).parse(styles[i].innerHTML || '', function (e, tree) { var css = tree.toCSS(); var style = styles[i]; style.type = 'text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.innerHTML = css; } }); } } } function loadStyleSheets(callback, reload) { for (var i = 0; i < less.sheets.length; i++) { loadStyleSheet(less.sheets[i], callback, reload, less.sheets.length - (i + 1)); } } function pathDiff(url, baseUrl) { // diff between two paths to create a relative path var urlParts = extractUrlParts(url), baseUrlParts = extractUrlParts(baseUrl), i, max, urlDirectories, baseUrlDirectories, diff = ""; if (urlParts.hostPart !== baseUrlParts.hostPart) { return ""; } max = Math.max(baseUrlParts.directories.length, urlParts.directories.length); for(i = 0; i < max; i++) { if (baseUrlParts.directories[i] !== urlParts.directories[i]) { break; } } baseUrlDirectories = baseUrlParts.directories.slice(i); urlDirectories = urlParts.directories.slice(i); for(i = 0; i < baseUrlDirectories.length-1; i++) { diff += "../"; } for(i = 0; i < urlDirectories.length-1; i++) { diff += urlDirectories[i] + "/"; } return diff; } function extractUrlParts(url, baseUrl) { // urlParts[1] = protocol&hostname || / // urlParts[2] = / if path relative to host base // urlParts[3] = directories // urlParts[4] = filename // urlParts[5] = parameters var urlPartsRegex = /^((?:[a-z-]+:)?\/\/(?:[^\/\?#]+\/)|([\/\\]))?((?:[^\/\\\?#]+[\/\\])*)([^\/\\\?#]*)([#\?].*)?$/, urlParts = url.match(urlPartsRegex), returner = {}, directories = [], i, baseUrlParts; if (!urlParts) { throw new Error("Could not parse sheet href - '"+url+"'"); } // Stylesheets in IE don't always return the full path if (!urlParts[1] || urlParts[2]) { baseUrlParts = baseUrl.match(urlPartsRegex); if (!baseUrlParts) { throw new Error("Could not parse page url - '"+baseUrl+"'"); } urlParts[1] = baseUrlParts[1]; if (!urlParts[2]) { urlParts[3] = baseUrlParts[3] + urlParts[3]; } } if (urlParts[3]) { directories = urlParts[3].replace("\\", "/").split("/"); for(i = 0; i < directories.length; i++) { if (directories[i] === ".." && i > 0) { directories.splice(i-1, 2); i -= 2; } } } returner.hostPart = urlParts[1]; returner.directories = directories; returner.path = urlParts[1] + directories.join("/"); returner.fileUrl = returner.path + (urlParts[4] || ""); returner.url = returner.fileUrl + (urlParts[5] || ""); return returner; } function loadStyleSheet(sheet, callback, reload, remaining) { // sheet may be set to the stylesheet for the initial load or a collection of properties including // some env variables for imports var contents = sheet.contents || {}; var files = sheet.files || {}; var hrefParts = extractUrlParts(sheet.href, window.location.href); var href = hrefParts.url; var css = cache && cache.getItem(href); var timestamp = cache && cache.getItem(href + ':timestamp'); var styles = { css: css, timestamp: timestamp }; var rootpath; if (less.relativeUrls) { if (less.rootpath) { if (sheet.entryPath) { rootpath = extractUrlParts(less.rootpath + pathDiff(hrefParts.path, sheet.entryPath)).path; } else { rootpath = less.rootpath; } } else { rootpath = hrefParts.path; } } else { if (less.rootpath) { rootpath = less.rootpath; } else { if (sheet.entryPath) { rootpath = sheet.entryPath; } else { rootpath = hrefParts.path; } } } xhr(href, sheet.type, function (data, lastModified) { // Store data this session session_cache += data.replace(/@import .+?;/ig, ''); if (!reload && styles && lastModified && (new(Date)(lastModified).valueOf() === new(Date)(styles.timestamp).valueOf())) { // Use local copy createCSS(styles.css, sheet); callback(null, null, data, sheet, { local: true, remaining: remaining }, href); } else { // Use remote copy (re-parse) try { contents[href] = data; // Updating top importing parser content cache new(less.Parser)({ optimization: less.optimization, paths: [hrefParts.path], entryPath: sheet.entryPath || hrefParts.path, mime: sheet.type, filename: href, rootpath: rootpath, relativeUrls: sheet.relativeUrls, contents: contents, // Passing top importing parser content cache ref down. files: files, dumpLineNumbers: less.dumpLineNumbers }).parse(data, function (e, root) { if (e) { return error(e, href) } try { callback(e, root, data, sheet, { local: false, lastModified: lastModified, remaining: remaining }, href); removeNode(document.getElementById('less-error-message:' + extractId(href))); } catch (e) { error(e, href); } }); } catch (e) { error(e, href); } } }, function (status, url) { throw new(Error)("Couldn't load " + url + " (" + status + ")"); }); } function extractId(href) { return href.replace(/^[a-z]+:\/\/?[^\/]+/, '' ) // Remove protocol & domain .replace(/^\//, '' ) // Remove root / .replace(/\.[a-zA-Z]+$/, '' ) // Remove simple extension .replace(/[^\.\w-]+/g, '-') // Replace illegal characters .replace(/\./g, ':'); // Replace dots with colons(for valid id) } function createCSS(styles, sheet, lastModified) { var css; // Strip the query-string var href = sheet.href || ''; // If there is no title set, use the filename, minus the extension var id = 'less:' + (sheet.title || extractId(href)); // If the stylesheet doesn't exist, create a new node if ((css = document.getElementById(id)) === null) { css = document.createElement('style'); css.type = 'text/css'; if( sheet.media ){ css.media = sheet.media; } css.id = id; var nextEl = sheet && sheet.nextSibling || null; (nextEl || document.getElementsByTagName('head')[0]).parentNode.insertBefore(css, nextEl); } if (css.styleSheet) { // IE try { css.styleSheet.cssText = styles; } catch (e) { throw new(Error)("Couldn't reassign styleSheet.cssText."); } } else { (function (node) { if (css.childNodes.length > 0) { if (css.firstChild.nodeValue !== node.nodeValue) { css.replaceChild(node, css.firstChild); } } else { css.appendChild(node); } })(document.createTextNode(styles)); } // Don't update the local store if the file wasn't modified if (lastModified && cache) { log('saving ' + href + ' to cache.'); try { cache.setItem(href, styles); cache.setItem(href + ':timestamp', lastModified); } catch(e) { //TODO - could do with adding more robust error handling log('failed to save'); } } } function xhr(url, type, callback, errback) { var xhr = getXMLHttpRequest(); var async = isFileProtocol ? less.fileAsync : less.async; if (typeof(xhr.overrideMimeType) === 'function') { xhr.overrideMimeType('text/css'); } xhr.open('GET', url, async); xhr.setRequestHeader('Accept', type || 'text/x-less, text/css; q=0.9, */*; q=0.5'); xhr.send(null); if (isFileProtocol && !less.fileAsync) { if (xhr.status === 0 || (xhr.status >= 200 && xhr.status < 300)) { callback(xhr.responseText); } else { errback(xhr.status, url); } } else if (async) { xhr.onreadystatechange = function () { if (xhr.readyState == 4) { handleResponse(xhr, callback, errback); } }; } else { handleResponse(xhr, callback, errback); } function handleResponse(xhr, callback, errback) { if (xhr.status >= 200 && xhr.status < 300) { callback(xhr.responseText, xhr.getResponseHeader("Last-Modified")); } else if (typeof(errback) === 'function') { errback(xhr.status, url); } } } function getXMLHttpRequest() { if (window.XMLHttpRequest) { return new(XMLHttpRequest); } else { try { return new(ActiveXObject)("MSXML2.XMLHTTP.3.0"); } catch (e) { log("browser doesn't support AJAX."); return null; } } } function removeNode(node) { return node && node.parentNode.removeChild(node); } function log(str) { if (less.env == 'development' && typeof(console) !== "undefined") { console.log('less: ' + str) } } function error(e, href) { var id = 'less-error-message:' + extractId(href); var template = '
  • {content}
  • '; var elem = document.createElement('div'), timer, content, error = []; var filename = e.filename || href; var filenameNoPath = filename.match(/([^\/]+(\?.*)?)$/)[1]; elem.id = id; elem.className = "less-error-message"; content = '

    ' + (e.message || 'There is an error in your .less file') + '

    ' + '

    in ' + filenameNoPath + " "; var errorline = function (e, i, classname) { if (e.extract[i]) { error.push(template.replace(/\{line\}/, parseInt(e.line) + (i - 1)) .replace(/\{class\}/, classname) .replace(/\{content\}/, e.extract[i])); } }; if (e.stack) { content += '
    ' + e.stack.split('\n').slice(1).join('
    '); } else if (e.extract) { errorline(e, 0, ''); errorline(e, 1, 'line'); errorline(e, 2, ''); content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':

    ' + '
      ' + error.join('') + '
    '; } elem.innerHTML = content; // CSS for error messages createCSS([ '.less-error-message ul, .less-error-message li {', 'list-style-type: none;', 'margin-right: 15px;', 'padding: 4px 0;', 'margin: 0;', '}', '.less-error-message label {', 'font-size: 12px;', 'margin-right: 15px;', 'padding: 4px 0;', 'color: #cc7777;', '}', '.less-error-message pre {', 'color: #dd6666;', 'padding: 4px 0;', 'margin: 0;', 'display: inline-block;', '}', '.less-error-message pre.line {', 'color: #ff0000;', '}', '.less-error-message h3 {', 'font-size: 20px;', 'font-weight: bold;', 'padding: 15px 0 5px 0;', 'margin: 0;', '}', '.less-error-message a {', 'color: #10a', '}', '.less-error-message .error {', 'color: red;', 'font-weight: bold;', 'padding-bottom: 2px;', 'border-bottom: 1px dashed red;', '}' ].join('\n'), { title: 'error-message' }); elem.style.cssText = [ "font-family: Arial, sans-serif", "border: 1px solid #e00", "background-color: #eee", "border-radius: 5px", "-webkit-border-radius: 5px", "-moz-border-radius: 5px", "color: #e00", "padding: 15px", "margin-bottom: 15px" ].join(';'); if (less.env == 'development') { timer = setInterval(function () { if (document.body) { if (document.getElementById(id)) { document.body.replaceChild(elem, document.getElementById(id)); } else { document.body.insertBefore(elem, document.body.firstChild); } clearInterval(timer); } }, 10); } } // amd.js // // Define Less as an AMD module. if (typeof define === "function" && define.amd) { define("less", [], function () { return less; } ); } })(window); less.js-1.4.2/dist/less-1.3.2.min.js000066400000000000000000001614521217256642200166070ustar00rootroot00000000000000// // LESS - Leaner CSS v1.3.2 // http://lesscss.org // // Copyright (c) 2009-2011, Alexis Sellier // Licensed under the Apache 2.0 License. // (function(e,t){function n(t){return e.less[t.split("/")[1]]}function f(){r.env==="development"?(r.optimization=0,r.watchTimer=setInterval(function(){r.watchMode&&g(function(e,t,n,r,i){t&&S(t.toCSS(),r,i.lastModified)})},r.poll)):r.optimization=3}function m(){var e=document.getElementsByTagName("style");for(var t=0;t0&&(s.splice(o-1,2),o-=2)}return i.hostPart=r[1],i.directories=s,i.path=r[1]+s.join("/"),i.fileUrl=i.path+(r[4]||""),i.url=i.fileUrl+(r[5]||""),i}function w(t,n,i,s){var o=t.contents||{},u=t.files||{},a=b(t.href,e.location.href),f=a.url,c=l&&l.getItem(f),h=l&&l.getItem(f+":timestamp"),p={css:c,timestamp:h},d;r.relativeUrls?r.rootpath?t.entryPath?d=b(r.rootpath+y(a.path,t.entryPath)).path:d=r.rootpath:d=a.path:r.rootpath?d=r.rootpath:t.entryPath?d=t.entryPath:d=a.path,x(f,t.type,function(e,l){v+=e.replace(/@import .+?;/ig,"");if(!i&&p&&l&&(new Date(l)).valueOf()===(new Date(p.timestamp)).valueOf())S(p.css,t),n(null,null,e,t,{local:!0,remaining:s},f);else try{o[f]=e,(new r.Parser({optimization:r.optimization,paths:[a.path],entryPath:t.entryPath||a.path,mime:t.type,filename:f,rootpath:d,relativeUrls:t.relativeUrls,contents:o,files:u,dumpLineNumbers:r.dumpLineNumbers})).parse(e,function(r,i){if(r)return k(r,f);try{n(r,i,e,t,{local:!1,lastModified:l,remaining:s},f),N(document.getElementById("less-error-message:"+E(f)))}catch(r){k(r,f)}})}catch(c){k(c,f)}},function(e,t){throw new Error("Couldn't load "+t+" ("+e+")")})}function E(e){return e.replace(/^[a-z]+:\/\/?[^\/]+/,"").replace(/^\//,"").replace(/\.[a-zA-Z]+$/,"").replace(/[^\.\w-]+/g,"-").replace(/\./g,":")}function S(e,t,n){var r,i=t.href||"",s="less:"+(t.title||E(i));if((r=document.getElementById(s))===null){r=document.createElement("style"),r.type="text/css",t.media&&(r.media=t.media),r.id=s;var o=t&&t.nextSibling||null;(o||document.getElementsByTagName("head")[0]).parentNode.insertBefore(r,o)}if(r.styleSheet)try{r.styleSheet.cssText=e}catch(u){throw new Error("Couldn't reassign styleSheet.cssText.")}else(function(e){r.childNodes.length>0?r.firstChild.nodeValue!==e.nodeValue&&r.replaceChild(e,r.firstChild):r.appendChild(e)})(document.createTextNode(e));if(n&&l){C("saving "+i+" to cache.");try{l.setItem(i,e),l.setItem(i+":timestamp",n)}catch(u){C("failed to save")}}}function x(e,t,n,i){function a(t,n,r){t.status>=200&&t.status<300?n(t.responseText,t.getResponseHeader("Last-Modified")):typeof r=="function"&&r(t.status,e)}var s=T(),u=o?r.fileAsync:r.async;typeof s.overrideMimeType=="function"&&s.overrideMimeType("text/css"),s.open("GET",e,u),s.setRequestHeader("Accept",t||"text/x-less, text/css; q=0.9, */*; q=0.5"),s.send(null),o&&!r.fileAsync?s.status===0||s.status>=200&&s.status<300?n(s.responseText):i(s.status,e):u?s.onreadystatechange=function(){s.readyState==4&&a(s,n,i)}:a(s,n,i)}function T(){if(e.XMLHttpRequest)return new XMLHttpRequest;try{return new ActiveXObject("MSXML2.XMLHTTP.3.0")}catch(t){return C("browser doesn't support AJAX."),null}}function N(e){return e&&e.parentNode.removeChild(e)}function C(e){r.env=="development"&&typeof console!="undefined"&&console.log("less: "+e)}function k(e,t){var n="less-error-message:"+E(t),i='
  • {content}
  • ',s=document.createElement("div"),o,u,a=[],f=e.filename||t,l=f.match(/([^\/]+(\?.*)?)$/)[1];s.id=n,s.className="less-error-message",u="

    "+(e.message||"There is an error in your .less file")+"

    "+'

    in '+l+" ";var c=function(e,t,n){e.extract[t]&&a.push(i.replace(/\{line\}/,parseInt(e.line)+(t-1)).replace(/\{class\}/,n).replace(/\{content\}/,e.extract[t]))};e.stack?u+="
    "+e.stack.split("\n").slice(1).join("
    "):e.extract&&(c(e,0,""),c(e,1,"line"),c(e,2,""),u+="on line "+e.line+", column "+(e.column+1)+":

    "+"
      "+a.join("")+"
    "),s.innerHTML=u,S([".less-error-message ul, .less-error-message li {","list-style-type: none;","margin-right: 15px;","padding: 4px 0;","margin: 0;","}",".less-error-message label {","font-size: 12px;","margin-right: 15px;","padding: 4px 0;","color: #cc7777;","}",".less-error-message pre {","color: #dd6666;","padding: 4px 0;","margin: 0;","display: inline-block;","}",".less-error-message pre.line {","color: #ff0000;","}",".less-error-message h3 {","font-size: 20px;","font-weight: bold;","padding: 15px 0 5px 0;","margin: 0;","}",".less-error-message a {","color: #10a","}",".less-error-message .error {","color: red;","font-weight: bold;","padding-bottom: 2px;","border-bottom: 1px dashed red;","}"].join("\n"),{title:"error-message"}),s.style.cssText=["font-family: Arial, sans-serif","border: 1px solid #e00","background-color: #eee","border-radius: 5px","-webkit-border-radius: 5px","-moz-border-radius: 5px","color: #e00","padding: 15px","margin-bottom: 15px"].join(";"),r.env=="development"&&(o=setInterval(function(){document.body&&(document.getElementById(n)?document.body.replaceChild(s,document.getElementById(n)):document.body.insertBefore(s,document.body.firstChild),clearInterval(o))},10))}Array.isArray||(Array.isArray=function(e){return Object.prototype.toString.call(e)==="[object Array]"||e instanceof Array}),Array.prototype.forEach||(Array.prototype.forEach=function(e,t){var n=this.length>>>0;for(var r=0;r>>0,n=new Array(t),r=arguments[1];for(var i=0;i>>0,n=0;if(t===0&&arguments.length===1)throw new TypeError;if(arguments.length>=2)var r=arguments[1];else do{if(n in this){r=this[n++];break}if(++n>=t)throw new TypeError}while(!0);for(;n=t)return-1;n<0&&(n+=t);for(;nh&&(c[u]=c[u].slice(o-h),h=o)}function w(e){var t=e.charCodeAt(0);return t===32||t===10||t===9}function E(e){var t,n,r,i,a;if(e instanceof Function)return e.call(p.parsers);if(typeof e=="string")t=s.charAt(o)===e?e:null,r=1,b();else{b();if(!(t=e.exec(c[u])))return null;r=t[0].length}if(t)return S(r),typeof t=="string"?t:t.length===1?t[0]:t}function S(e){var t=o,n=u,r=o+c[u].length,i=o+=e;while(o=0&&t.charAt(n)!=="\n";n--)r++;return{line:typeof e=="number"?(t.slice(0,e).match(/\n/g)||"").length:null,column:r}}function L(e){return r.mode==="browser"||r.mode==="rhino"?e.filename:n("path").resolve(e.filename)}function A(e,t,n){return{lineNumber:k(e,t).line+1,fileName:L(n)}}function O(e,t){var n=C(e,t),r=k(e.index,n),i=r.line,s=r.column,o=n.split("\n");this.type=e.type||"Syntax",this.message=e.message,this.filename=e.filename||t.filename,this.index=e.index,this.line=typeof i=="number"?i+1:null,this.callLine=e.call&&k(e.call,n).line+1,this.callExtract=o[k(e.call,n).line],this.stack=e.stack,this.column=s,this.extract=[o[i-1],o[i],o[i+1]]}var s,o,u,a,f,l,c,h,p,d=this,t=t||{};t.contents||(t.contents={}),t.rootpath=t.rootpath||"",t.files||(t.files={});var v=function(){},m=this.imports={paths:t.paths||[],queue:[],files:t.files,contents:t.contents,mime:t.mime,error:null,push:function(e,n){var i=this;this.queue.push(e),r.Parser.importer(e,this.paths,function(t,r,s){i.queue.splice(i.queue.indexOf(e),1);var o=s in i.files;i.files[s]=r,t&&!i.error&&(i.error=t),n(t,r,o),i.queue.length===0&&v(i.error)},t)}};return this.env=t=t||{},this.optimization="optimization"in this.env?this.env.optimization:1,this.env.filename=this.env.filename||null,p={imports:m,parse:function(e,a){var f,d,m,g,y,b,w=[],S,x=null;o=u=h=l=0,s=e.replace(/\r\n/g,"\n"),s=s.replace(/^\uFEFF/,""),c=function(e){var n=0,r=/(?:@\{[\w-]+\}|[^"'`\{\}\/\(\)\\])+/g,i=/\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g,o=/"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'|`((?:[^`]|\\.)*)`/g,u=0,a,f=e[0],l;for(var c=0,h,p;c0?"missing closing `}`":"missing opening `{`",filename:t.filename},t)),e.map(function(e){return e.join("")})}([[]]);if(x)return a(x,t);try{f=new i.Ruleset([],E(this.parsers.primary)),f.root=!0}catch(T){return a(new O(T,t))}f.toCSS=function(e){var s,o,u;return function(s,o){var u=[],a;s=s||{},typeof o=="object"&&!Array.isArray(o)&&(o=Object.keys(o).map(function(e){var t=o[e];return t instanceof i.Value||(t instanceof i.Expression||(t=new i.Expression([t])),t=new i.Value([t])),new i.Rule("@"+e,t,!1,0)}),u=[new i.Ruleset(null,o)]);try{var f=e.call(this,{frames:u}).toCSS([],{compress:s.compress||!1,dumpLineNumbers:t.dumpLineNumbers})}catch(l){throw new O(l,t)}if(a=p.imports.error)throw a instanceof O?a:new O(a,t);return s.yuicompress&&r.mode==="node"?n("ycssmin").cssmin(f):s.compress?f.replace(/(\s)+/g,"$1"):f}}(f.eval);if(o=0&&s.charAt(N)!=="\n";N--)C++;x={type:"Parse",message:"Syntax Error on line "+y,index:o,filename:t.filename,line:y,column:C,extract:[b[y-2],b[y-1],b[y]]}}this.imports.queue.length>0?v=function(e){e=x||e,e?a(e):a(null,f)}:a(x,f)},parsers:{primary:function(){var e,t=[];while((e=E(this.mixin.definition)||E(this.rule)||E(this.ruleset)||E(this.mixin.call)||E(this.comment)||E(this.directive))||E(/^[\s\n]+/)||E(/^;+/))e&&t.push(e);return t},comment:function(){var e;if(s.charAt(o)!=="/")return;if(s.charAt(o+1)==="/")return new i.Comment(E(/^\/\/.*/),!0);if(e=E(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/))return new i.Comment(e)},entities:{quoted:function(){var e,t=o,n;s.charAt(t)==="~"&&(t++,n=!0);if(s.charAt(t)!=='"'&&s.charAt(t)!=="'")return;n&&E("~");if(e=E(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/))return new i.Quoted(e[0],e[1]||e[2],n)},keyword:function(){var e;if(e=E(/^[_A-Za-z-][_A-Za-z0-9-]*/))return i.colors.hasOwnProperty(e)?new i.Color(i.colors[e].slice(1)):new i.Keyword(e)},call:function(){var e,n,r,s,a=o;if(!(e=/^([\w-]+|%|progid:[\w\.]+)\(/.exec(c[u])))return;e=e[1],n=e.toLowerCase();if(n==="url")return null;o+=e.length;if(n==="alpha"){s=E(this.alpha);if(typeof s!="undefined")return s}E("("),r=E(this.entities.arguments);if(!E(")"))return;if(e)return new i.Call(e,r,a,t.filename)},arguments:function(){var e=[],t;while(t=E(this.entities.assignment)||E(this.expression)){e.push(t);if(!E(","))break}return e},literal:function(){return E(this.entities.ratio)||E(this.entities.dimension)||E(this.entities.color)||E(this.entities.quoted)||E(this.entities.unicodeDescriptor)},assignment:function(){var e,t;if((e=E(/^\w+(?=\s?=)/i))&&E("=")&&(t=E(this.entity)))return new i.Assignment(e,t)},url:function(){var e;if(s.charAt(o)!=="u"||!E(/^url\(/))return;return e=E(this.entities.quoted)||E(this.entities.variable)||E(/^(?:(?:\\[\(\)'"])|[^\(\)'"])+/)||"",x(")"),new i.URL(e.value!=null||e instanceof i.Variable?e:new i.Anonymous(e),t.rootpath)},variable:function(){var e,n=o;if(s.charAt(o)==="@"&&(e=E(/^@@?[\w-]+/)))return new i.Variable(e,n,t.filename)},variableCurly:function(){var e,n,r=o;if(s.charAt(o)==="@"&&(n=E(/^@\{([\w-]+)\}/)))return new i.Variable("@"+n[1],r,t.filename)},color:function(){var e;if(s.charAt(o)==="#"&&(e=E(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/)))return new i.Color(e[1])},dimension:function(){var e,t=s.charCodeAt(o);if(t>57||t<43||t===47||t==44)return;if(e=E(/^([+-]?\d*\.?\d+)(px|%|em|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn|dpi|dpcm|dppx|rem|vw|vh|vmin|vm|ch)?/))return new i.Dimension(e[1],e[2])},ratio:function(){var e,t=s.charCodeAt(o);if(t>57||t<48)return;if(e=E(/^(\d+\/\d+)/))return new i.Ratio(e[1])},unicodeDescriptor:function(){var e;if(e=E(/^U\+[0-9a-fA-F?]+(\-[0-9a-fA-F?]+)?/))return new i.UnicodeDescriptor(e[0])},javascript:function(){var e,t=o,n;s.charAt(t)==="~"&&(t++,n=!0);if(s.charAt(t)!=="`")return;n&&E("~");if(e=E(/^`([^`]*)`/))return new i.JavaScript(e[1],o,n)}},variable:function(){var e;if(s.charAt(o)==="@"&&(e=E(/^(@[\w-]+)\s*:/)))return e[1]},shorthand:function(){var e,t;if(!N(/^[@\w.%-]+\/[@\w.-]+/))return;g();if((e=E(this.entity))&&E("/")&&(t=E(this.entity)))return new i.Shorthand(e,t);y()},mixin:{call:function(){var e=[],n,r,u=[],a=[],f,l,c,h,p,d,v,m=o,b=s.charAt(o),w,S,C=!1;if(b!=="."&&b!=="#")return;g();while(n=E(/^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/))e.push(new i.Element(r,n,o)),r=E(">");if(E("(")){p=[];while(c=E(this.expression)){h=null,S=c;if(c.value.length==1){var k=c.value[0];k instanceof i.Variable&&E(":")&&(p.length>0&&(d&&T("Cannot mix ; and , as delimiter types"),v=!0),S=x(this.expression),h=w=k.name)}p.push(S),a.push({name:h,value:S});if(E(","))continue;if(E(";")||d)v&&T("Cannot mix ; and , as delimiter types"),d=!0,p.length>1&&(S=new i.Value(p)),u.push({name:w,value:S}),w=null,p=[],v=!1}x(")")}f=d?u:a,E(this.important)&&(C=!0);if(e.length>0&&(E(";")||N("}")))return new i.mixin.Call(e,f,m,t.filename,C);y()},definition:function(){var e,t=[],n,r,u,a,f,c=!1;if(s.charAt(o)!=="."&&s.charAt(o)!=="#"||N(/^[^{]*\}/))return;g();if(n=E(/^([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/)){e=n[1];do{E(this.comment);if(s.charAt(o)==="."&&E(/^\.{3}/)){c=!0,t.push({variadic:!0});break}if(!(u=E(this.entities.variable)||E(this.entities.literal)||E(this.entities.keyword)))break;if(u instanceof i.Variable)if(E(":"))a=x(this.expression,"expected expression"),t.push({name:u.name,value:a});else{if(E(/^\.{3}/)){t.push({name:u.name,variadic:!0}),c=!0;break}t.push({name:u.name})}else t.push({value:u})}while(E(",")||E(";"));E(")")||(l=o,y()),E(this.comment),E(/^when/)&&(f=x(this.conditions,"expected condition")),r=E(this.block);if(r)return new i.mixin.Definition(e,t,r,f,c);y()}}},entity:function(){return E(this.entities.literal)||E(this.entities.variable)||E(this.entities.url)||E(this.entities.call)||E(this.entities.keyword)||E(this.entities.javascript)||E(this.comment)},end:function(){return E(";")||N("}")},alpha:function(){var e;if(!E(/^\(opacity=/i))return;if(e=E(/^\d+/)||E(this.entities.variable))return x(")"),new i.Alpha(e)},element:function(){var e,t,n,r;n=E(this.combinator),e=E(/^(?:\d+\.\d+|\d+)%/)||E(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/)||E("*")||E("&")||E(this.attribute)||E(/^\([^()@]+\)/)||E(/^[\.#](?=@)/)||E(this.entities.variableCurly),e||E("(")&&(r=E(this.entities.variableCurly)||E(this.entities.variable)||E(this.selector))&&E(")")&&(e=new i.Paren(r));if(e)return new i.Element(n,e,o)},combinator:function(){var e,t=s.charAt(o);if(t===">"||t==="+"||t==="~"||t==="|"){o++;while(s.charAt(o).match(/\s/))o++;return new i.Combinator(t)}return s.charAt(o-1).match(/\s/)?new i.Combinator(" "):new i.Combinator(null)},selector:function(){var e,t,n=[],r,u;if(E("("))return e=E(this.entity),x(")"),new i.Selector([new i.Element("",e,o)]);while(t=E(this.element)){r=s.charAt(o),n.push(t);if(r==="{"||r==="}"||r===";"||r===","||r===")")break}if(n.length>0)return new i.Selector(n)},attribute:function(){var e="",t,n,r;if(!E("["))return;if(t=E(/^(?:[_A-Za-z0-9-]|\\.)+/)||E(this.entities.quoted))(r=E(/^[|~*$^]?=/))&&(n=E(this.entities.quoted)||E(/^[\w-]+/))?e=[t,r,n.toCSS?n.toCSS():n].join(""):e=t;if(!E("]"))return;if(e)return"["+e+"]"},block:function(){var e;if(E("{")&&(e=E(this.primary))&&E("}"))return e},ruleset:function(){var e=[],n,r,u,a;g(),t.dumpLineNumbers&&(a=A(o,s,t));while(n=E(this.selector)){e.push(n),E(this.comment);if(!E(","))break;E(this.comment)}if(e.length>0&&(r=E(this.block))){var f=new i.Ruleset(e,r,t.strictImports);return t.dumpLineNumbers&&(f.debugInfo=a),f}l=o,y()},rule:function(){var e,t,n=s.charAt(o),r,a;g();if(n==="."||n==="#"||n==="&")return;if(e=E(this.variable)||E(this.property)){e.charAt(0)!="@"&&(a=/^([^@+\/'"*`(;{}-]*);/.exec(c[u]))?(o+=a[0].length-1,t=new i.Anonymous(a[1])):e==="font"?t=E(this.font):t=E(this.value),r=E(this.important);if(t&&E(this.end))return new i.Rule(e,t,r,f);l=o,y()}},"import":function(){var e,n,r=o;g();var s=E(/^@import(?:-(once))?\s+/);if(s&&(e=E(this.entities.quoted)||E(this.entities.url))){n=E(this.mediaFeatures);if(E(";"))return new i.Import(e,m,n,s[1]==="once",r,t.rootpath)}y()},mediaFeature:function(){var e,t,n=[];do if(e=E(this.entities.keyword))n.push(e);else if(E("(")){t=E(this.property),e=E(this.entity);if(!E(")"))return null;if(t&&e)n.push(new i.Paren(new i.Rule(t,e,null,o,!0)));else{if(!e)return null;n.push(new i.Paren(e))}}while(e);if(n.length>0)return new i.Expression(n)},mediaFeatures:function(){var e,t=[];do if(e=E(this.mediaFeature)){t.push(e);if(!E(","))break}else if(e=E(this.entities.variable)){t.push(e);if(!E(","))break}while(e);return t.length>0?t:null},media:function(){var e,n,r,u;t.dumpLineNumbers&&(u=A(o,s,t));if(E(/^@media/)){e=E(this.mediaFeatures);if(n=E(this.block))return r=new i.Media(n,e),t.dumpLineNumbers&&(r.debugInfo=u),r}},directive:function(){var e,n,r,u,a,f,l,c,h,p;if(s.charAt(o)!=="@")return;if(n=E(this["import"])||E(this.media))return n;g(),e=E(/^@[a-z-]+/);if(!e)return;l=e,e.charAt(1)=="-"&&e.indexOf("-",2)>0&&(l="@"+e.slice(e.indexOf("-",2)+1));switch(l){case"@font-face":c=!0;break;case"@viewport":case"@top-left":case"@top-left-corner":case"@top-center":case"@top-right":case"@top-right-corner":case"@bottom-left":case"@bottom-left-corner":case"@bottom-center":case"@bottom-right":case"@bottom-right-corner":case"@left-top":case"@left-middle":case"@left-bottom":case"@right-top":case"@right-middle":case"@right-bottom":c=!0;break;case"@page":case"@document":case"@supports":case"@keyframes":c=!0,h=!0;break;case"@namespace":p=!0}h&&(e+=" "+(E(/^[^{]+/)||"").trim());if(c){if(r=E(this.block))return new i.Directive(e,r)}else if((n=p?E(this.expression):E(this.entity))&&E(";")){var d=new i.Directive(e,n);return t.dumpLineNumbers&&(d.debugInfo=A(o,s,t)),d}y()},font:function(){var e=[],t=[],n,r,s,o;while(o=E(this.shorthand)||E(this.entity))t.push(o);e.push(new i.Expression(t));if(E(","))while(o=E(this.expression)){e.push(o);if(!E(","))break}return new i.Value(e)},value:function(){var e,t=[],n;while(e=E(this.expression)){t.push(e);if(!E(","))break}if(t.length>0)return new i.Value(t)},important:function(){if(s.charAt(o)==="!")return E(/^! *important/)},sub:function(){var e;if(E("(")&&(e=E(this.expression))&&E(")"))return e},multiplication:function(){var e,t,n,r;if(e=E(this.operand)){while(!N(/^\/[*\/]/)&&(n=E("/")||E("*"))&&(t=E(this.operand)))r=new i.Operation(n,[r||e,t]);return r||e}},addition:function(){var e,t,n,r;if(e=E(this.multiplication)){while((n=E(/^[-+]\s+/)||!w(s.charAt(o-1))&&(E("+")||E("-")))&&(t=E(this.multiplication)))r=new i.Operation(n,[r||e,t]);return r||e}},conditions:function(){var e,t,n=o,r;if(e=E(this.condition)){while(E(",")&&(t=E(this.condition)))r=new i.Condition("or",r||e,t,n);return r||e}},condition:function(){var e,t,n,r,s=o,u=!1;E(/^not/)&&(u=!0),x("(");if(e=E(this.addition)||E(this.entities.keyword)||E(this.entities.quoted))return(r=E(/^(?:>=|=<|[<=>])/))?(t=E(this.addition)||E(this.entities.keyword)||E(this.entities.quoted))?n=new i.Condition(r,e,t,s,u):T("expected expression"):n=new i.Condition("=",e,new i.Keyword("true"),s,u),x(")"),E(/^and/)?new i.Condition("and",n,E(this.condition)):n},operand:function(){var e,t=s.charAt(o+1);s.charAt(o)==="-"&&(t==="@"||t==="(")&&(e=E("-"));var n=E(this.sub)||E(this.entities.dimension)||E(this.entities.color)||E(this.entities.variable)||E(this.entities.call);return e?new i.Operation("*",[new i.Dimension(-1),n]):n},expression:function(){var e,t,n=[],r;while(e=E(this.addition)||E(this.entity))n.push(e);if(n.length>0)return new i.Expression(n)},property:function(){var e;if(e=E(/^(\*?-?[_a-z0-9-]+)\s*:/))return e[1]}}}};if(r.mode==="browser"||r.mode==="rhino")r.Parser.importer=function(e,t,n,r){!/^([a-z-]+:)?\//.test(e)&&t.length>0&&(e=t[0]+e),w({href:e,title:e,type:r.mime,contents:r.contents,files:r.files,rootpath:r.rootpath,entryPath:r.entryPath,relativeUrls:r.relativeUrls},function(e,i,s,o,u,a){e&&typeof r.errback=="function"?r.errback.call(null,a,t,n,r):n.call(null,e,i,a)},!0)};(function(e){function t(t){return e.functions.hsla(t.h,t.s,t.l,t.a)}function n(t,n){return t instanceof e.Dimension&&t.unit=="%"?parseFloat(t.value*n/100):r(t)}function r(t){if(t instanceof e.Dimension)return parseFloat(t.unit=="%"?t.value/100:t.value);if(typeof t=="number")return t;throw{error:"RuntimeError",message:"color functions take numbers as parameters"}}function i(e){return Math.min(1,Math.max(0,e))}e.functions={rgb:function(e,t,n){return this.rgba(e,t,n,1)},rgba:function(t,i,s,o){var u=[t,i,s].map(function(e){return n(e,256)});return o=r(o),new e.Color(u,o)},hsl:function(e,t,n){return this.hsla(e,t,n,1)},hsla:function(e,t,n,i){function u(e){return e=e<0?e+1:e>1?e-1:e,e*6<1?o+(s-o)*e*6:e*2<1?s:e*3<2?o+(s-o)*(2/3-e)*6:o}e=r(e)%360/360,t=r(t),n=r(n),i=r(i);var s=n<=.5?n*(t+1):n+t-n*t,o=n*2-s;return this.rgba(u(e+1/3)*255,u(e)*255,u(e-1/3)*255,i)},hsv:function(e,t,n){return this.hsva(e,t,n,1)},hsva:function(e,t,n,i){e=r(e)%360/360*360,t=r(t),n=r(n),i=r(i);var s,o;s=Math.floor(e/60%6),o=e/60-s;var u=[n,n*(1-t),n*(1-o*t),n*(1-(1-o)*t)],a=[[0,3,1],[2,0,1],[1,0,3],[1,2,0],[3,1,0],[0,1,2]];return this.rgba(u[a[s][0]]*255,u[a[s][1]]*255,u[a[s][2]]*255,i)},hue:function(t){return new e.Dimension(Math.round(t.toHSL().h))},saturation:function(t){return new e.Dimension(Math.round(t.toHSL().s*100),"%")},lightness:function(t){return new e.Dimension(Math.round(t.toHSL().l*100),"%")},red:function(t){return new e.Dimension(t.rgb[0])},green:function(t){return new e.Dimension(t.rgb[1])},blue:function(t){return new e.Dimension(t.rgb[2])},alpha:function(t){return new e.Dimension(t.toHSL().a)},luma:function(t){return new e.Dimension(Math.round((.2126*(t.rgb[0]/255)+.7152*(t.rgb[1]/255)+.0722*(t.rgb[2]/255))*t.alpha*100),"%")},saturate:function(e,n){var r=e.toHSL();return r.s+=n.value/100,r.s=i(r.s),t(r)},desaturate:function(e,n){var r=e.toHSL();return r.s-=n.value/100,r.s=i(r.s),t(r)},lighten:function(e,n){var r=e.toHSL();return r.l+=n.value/100,r.l=i(r.l),t(r)},darken:function(e,n){var r=e.toHSL();return r.l-=n.value/100,r.l=i(r.l),t(r)},fadein:function(e,n){var r=e.toHSL();return r.a+=n.value/100,r.a=i(r.a),t(r)},fadeout:function(e,n){var r=e.toHSL();return r.a-=n.value/100,r.a=i(r.a),t(r)},fade:function(e,n){var r=e.toHSL();return r.a=n.value/100,r.a=i(r.a),t(r)},spin:function(e,n){var r=e.toHSL(),i=(r.h+n.value)%360;return r.h=i<0?360+i:i,t(r)},mix:function(t,n,r){r||(r=new e.Dimension(50));var i=r.value/100,s=i*2-1,o=t.toHSL().a-n.toHSL().a,u=((s*o==-1?s:(s+o)/(1+s*o))+1)/2,a=1-u,f=[t.rgb[0]*u+n.rgb[0]*a,t.rgb[1]*u+n.rgb[1]*a,t.rgb[2]*u+n.rgb[2]*a],l=t.alpha*i+n.alpha*(1-i);return new e.Color(f,l)},greyscale:function(t){return this.desaturate(t,new e.Dimension(100))},contrast:function(e,t,n,r){return typeof n=="undefined"&&(n=this.rgba(255,255,255,1)),typeof t=="undefined"&&(t=this.rgba(0,0,0,1)),typeof r=="undefined"?r=.43:r=r.value,(.2126*(e.rgb[0]/255)+.7152*(e.rgb[1]/255)+.0722*(e.rgb[2]/255))*e.alpha255?255:e<0?0:e).toString(16),e.length===1?"0"+e:e}).join("")},operate:function(t,n){var r=[];n instanceof e.Color||(n=n.toColor());for(var i=0;i<3;i++)r[i]=e.operate(t,this.rgb[i],n.rgb[i]);return new e.Color(r,this.alpha+n.alpha)},toHSL:function(){var e=this.rgb[0]/255,t=this.rgb[1]/255,n=this.rgb[2]/255,r=this.alpha,i=Math.max(e,t,n),s=Math.min(e,t,n),o,u,a=(i+s)/2,f=i-s;if(i===s)o=u=0;else{u=a>.5?f/(2-i-s):f/(i+s);switch(i){case e:o=(t-n)/f+(t255?255:e<0?0:e).toString(16),e.length===1?"0"+e:e}).join("")},compare:function(e){return e.rgb?e.rgb[0]===this.rgb[0]&&e.rgb[1]===this.rgb[1]&&e.rgb[2]===this.rgb[2]&&e.alpha===this.alpha?0:-1:-1}}}(n("../tree")),function(e){e.Comment=function(e,t){this.value=e,this.silent=!!t},e.Comment.prototype={toCSS:function(e){return e.compress?"":this.value},eval:function(){return this}}}(n("../tree")),function(e){e.Condition=function(e,t,n,r,i){this.op=e.trim(),this.lvalue=t,this.rvalue=n,this.index=r,this.negate=i},e.Condition.prototype.eval=function(e){var t=this.lvalue.eval(e),n=this.rvalue.eval(e),r=this.index,i,i=function(e){switch(e){case"and":return t&&n;case"or":return t||n;default:if(t.compare)i=t.compare(n);else{if(!n.compare)throw{type:"Type",message:"Unable to perform comparison",index:r};i=n.compare(t)}switch(i){case-1:return e==="<"||e==="=<";case 0:return e==="="||e===">="||e==="=<";case 1:return e===">"||e===">="}}}(this.op);return this.negate?!i:i}}(n("../tree")),function(e){e.Dimension=function(e,t){this.value=parseFloat(e),this.unit=t||null},e.Dimension.prototype={eval:function(){return this},toColor:function(){return new e.Color([this.value,this.value,this.value])},toCSS:function(){var e=this.value+this.unit;return e},operate:function(t,n){return new e.Dimension(e.operate(t,this.value,n.value),this.unit||n.unit)},compare:function(t){return t instanceof e.Dimension?t.value>this.value?-1:t.value":e.compress?">":" > ","|":e.compress?"|":" | "}[this.value]}}(n("../tree")),function(e){e.Expression=function(e){this.value=e},e.Expression.prototype={eval:function(t){return this.value.length>1?new e.Expression(this.value.map(function(e){return e.eval(t)})):this.value.length===1?this.value[0].eval(t):this},toCSS:function(e){return this.value.map(function(t){return t.toCSS?t.toCSS(e):""}).join(" ")}}}(n("../tree")),function(e){e.Import=function(t,n,r,i,s,o){var u=this;this.once=i,this.index=s,this._path=t,this.features=r&&new e.Value(r),this.rootpath=o,t instanceof e.Quoted?this.path=/(\.[a-z]*$)|([\?;].*)$/.test(t.value)?t.value:t.value+".less":this.path=t.value.value||t.value,this.css=/css([\?;].*)?$/.test(this.path),this.css||n.push(this.path,function(t,n,r){t&&(t.index=s),r&&u.once&&(u.skip=r),u.root=n||new e.Ruleset([],[])})},e.Import.prototype={toCSS:function(e){var t=this.features?" "+this.features.toCSS(e):"";return this.css?(typeof this._path.value=="string"&&!/^(?:[a-z-]+:|\/)/.test(this._path.value)&&(this._path.value=this.rootpath+this._path.value),"@import "+this._path.toCSS()+t+";\n"):""},eval:function(t){var n,r=this.features&&this.features.eval(t);return this.skip?[]:this.css?this:(n=new e.Ruleset([],this.root.rules.slice(0)),n.evalImports(t),this.features?new e.Media(n.rules,this.features.value):n.rules)}}}(n("../tree")),function(e){e.JavaScript=function(e,t,n){this.escaped=n,this.expression=e,this.index=t},e.JavaScript.prototype={eval:function(t){var n,r=this,i={},s=this.expression.replace(/@\{([\w-]+)\}/g,function(n,i){return e.jsify((new e.Variable("@"+i,r.index)).eval(t))});try{s=new Function("return ("+s+")")}catch(o){throw{message:"JavaScript evaluation error: `"+s+"`",index:this.index}}for(var u in t.frames[0].variables())i[u.slice(1)]={value:t.frames[0].variables()[u].value,toJS:function(){return this.value.eval(t).toCSS()}};try{n=s.call(i)}catch(o){throw{message:"JavaScript evaluation error: '"+o.name+": "+o.message+"'",index:this.index}}return typeof n=="string"?new e.Quoted('"'+n+'"',n,this.escaped,this.index):Array.isArray(n)?new e.Anonymous(n.join(", ")):new e.Anonymous(n)}}}(n("../tree")),function(e){e.Keyword=function(e){this.value=e},e.Keyword.prototype={eval:function(){return this},toCSS:function(){return this.value},compare:function(t){return t instanceof e.Keyword?t.value===this.value?0:1:-1}},e.True=new e.Keyword("true"),e.False=new e.Keyword("false")}(n("../tree")),function(e){e.Media=function(t,n){var r=this.emptySelectors();this.features=new e.Value(n),this.ruleset=new e.Ruleset(r,t),this.ruleset.allowImports=!0},e.Media.prototype={toCSS:function(e,t){var n=this.features.toCSS(t);return this.ruleset.root=e.length===0||e[0].multiMedia,"@media "+n+(t.compress?"{":" {\n ")+this.ruleset.toCSS(e,t).trim().replace(/\n/g,"\n ")+(t.compress?"}":"\n}\n")},eval:function(t){t.mediaBlocks||(t.mediaBlocks=[],t.mediaPath=[]);var n=new e.Media([],[]);return this.debugInfo&&(this.ruleset.debugInfo=this.debugInfo,n.debugInfo=this.debugInfo),n.features=this.features.eval(t),t.mediaPath.push(n),t.mediaBlocks.push(n),t.frames.unshift(this.ruleset),n.ruleset=this.ruleset.eval(t),t.frames.shift(),t.mediaPath.pop(),t.mediaPath.length===0?n.evalTop(t):n.evalNested(t)},variable:function(t){return e.Ruleset.prototype.variable.call(this.ruleset,t)},find:function(){return e.Ruleset.prototype.find.apply(this.ruleset,arguments)},rulesets:function(){return e.Ruleset.prototype.rulesets.apply(this.ruleset)},emptySelectors:function(){var t=new e.Element("","&",0);return[new e.Selector([t])]},evalTop:function(t){var n=this;if(t.mediaBlocks.length>1){var r=this.emptySelectors();n=new e.Ruleset(r,t.mediaBlocks),n.multiMedia=!0}return delete t.mediaBlocks,delete t.mediaPath,n},evalNested:function(t){var n,r,i=t.mediaPath.concat([this]);for(n=0;n0;n--)t.splice(n,0,new e.Anonymous("and"));return new e.Expression(t)})),new e.Ruleset([],[])},permute:function(e){if(e.length===0)return[];if(e.length===1)return e[0];var t=[],n=this.permute(e.slice(1));for(var r=0;r0){c=!0;for(a=0;athis.params.length)return!1;if(this.required>0&&n>this.params.length)return!1}r=Math.min(n,this.arity);for(var s=0;si.selectors[o].elements.length?Array.prototype.push.apply(r,i.find(new e.Selector(t.elements.slice(1)),n)):r.push(i);break}}),this._lookups[o]=r)},toCSS:function(t,n){var r=[],i=[],s=[],o=[],u=[],a,f,l;this.root||this.joinSelectors(u,t,this.selectors);for(var c=0;c0){f=e.debugInfo(n,this),a=u.map(function(e){return e.map(function(e){return e.toCSS(n)}).join("").trim()}).join(n.compress?",":",\n");for(var c=i.length-1;c>=0;c--)s.indexOf(i[c])===-1&&s.unshift(i[c]);i=s,r.push(f+a+(n.compress?"{":" {\n ")+i.join(n.compress?"":"\n ")+(n.compress?"}":"\n}\n"))}return r.push(o),r.join("")+(n.compress?"\n":"")},joinSelectors:function(e,t,n){for(var r=0;r0)for(i=0;i0&&this.mergeElementsOnToSelectors(g,a);for(s=0;s0&&(l[0].elements=l[0].elements.slice(0),l[0].elements.push(new e.Element(f.combinator,"",0))),y.push(l);else for(o=0;o0?(h=l.slice(0),m=h.pop(),d=new e.Selector(m.elements.slice(0)),v=!1):d=new e.Selector([]),c.length>1&&(p=p.concat(c.slice(1))),c.length>0&&(v=!1,d.elements.push(new e.Element(f.combinator,c[0].elements[0].value,0)),d.elements=d.elements.concat(c[0].elements.slice(1))),v||h.push(d),h=h.concat(p),y.push(h)}a=y,g=[]}}g.length>0&&this.mergeElementsOnToSelectors(g,a);for(i=0;i0?i[i.length-1]=new e.Selector(i[i.length-1].elements.concat(t)):i.push(new e.Selector(t))}}}(n("../tree")),function(e){e.Selector=function(e){this.elements=e},e.Selector.prototype.match=function(e){var t=this.elements,n=t.length,r,i,s,o;r=e.elements.slice(e.elements.length&&e.elements[0].value==="&"?1:0),i=r.length,s=Math.min(n,i);if(i===0||n1?"["+e.value.map(function(e){return e.toCSS(!1)}).join(", ")+"]":e.toCSS(!1)}}(n("./tree"));var o=/^(file|chrome(-extension)?|resource|qrc|app):/.test(location.protocol);r.env=r.env||(location.hostname=="127.0.0.1"||location.hostname=="0.0.0.0"||location.hostname=="localhost"||location.port.length>0||o?"development":"production"),r.async=r.async||!1,r.fileAsync=r.fileAsync||!1,r.poll=r.poll||(o?1e3:1500);if(r.functions)for(var u in r.functions)r.tree.functions[u]=r.functions[u];var a=/!dumpLineNumbers:(comments|mediaquery|all)/.exec(location.hash);a&&(r.dumpLineNumbers=a[1]),r.watch=function(){return r.watchMode||(r.env="development",f()),this.watchMode=!0},r.unwatch=function(){return clearInterval(r.watchTimer),this.watchMode=!1},/!watch/.test(location.hash)&&r.watch();var l=null;if(r.env!="development")try{l=typeof e.localStorage=="undefined"?null:e.localStorage}catch(c){}var h=document.getElementsByTagName("link"),p=/^text\/(x-)?less$/;r.sheets=[];for(var d=0;d>> 0; for (var i = 0; i < len; i++) { if (i in this) { block.call(thisObject, this[i], i, this); } } }; } if (!Array.prototype.map) { Array.prototype.map = function(fun /*, thisp*/) { var len = this.length >>> 0; var res = new Array(len); var thisp = arguments[1]; for (var i = 0; i < len; i++) { if (i in this) { res[i] = fun.call(thisp, this[i], i, this); } } return res; }; } if (!Array.prototype.filter) { Array.prototype.filter = function (block /*, thisp */) { var values = []; var thisp = arguments[1]; for (var i = 0; i < this.length; i++) { if (block.call(thisp, this[i])) { values.push(this[i]); } } return values; }; } if (!Array.prototype.reduce) { Array.prototype.reduce = function(fun /*, initial*/) { var len = this.length >>> 0; var i = 0; // no value to return if no initial value and an empty array if (len === 0 && arguments.length === 1) throw new TypeError(); if (arguments.length >= 2) { var rv = arguments[1]; } else { do { if (i in this) { rv = this[i++]; break; } // if array contains no values, no initial value to return if (++i >= len) throw new TypeError(); } while (true); } for (; i < len; i++) { if (i in this) { rv = fun.call(null, rv, this[i], i, this); } } return rv; }; } if (!Array.prototype.indexOf) { Array.prototype.indexOf = function (value /*, fromIndex */ ) { var length = this.length; var i = arguments[1] || 0; if (!length) return -1; if (i >= length) return -1; if (i < 0) i += length; for (; i < length; i++) { if (!Object.prototype.hasOwnProperty.call(this, i)) { continue } if (value === this[i]) return i; } return -1; }; } // // Object // if (!Object.keys) { Object.keys = function (object) { var keys = []; for (var name in object) { if (Object.prototype.hasOwnProperty.call(object, name)) { keys.push(name); } } return keys; }; } // // String // if (!String.prototype.trim) { String.prototype.trim = function () { return String(this).replace(/^\s\s*/, '').replace(/\s\s*$/, ''); }; } var less, tree, charset; if (typeof environment === "object" && ({}).toString.call(environment) === "[object Environment]") { // Rhino // Details on how to detect Rhino: https://github.com/ringo/ringojs/issues/88 if (typeof(window) === 'undefined') { less = {} } else { less = window.less = {} } tree = less.tree = {}; less.mode = 'rhino'; } else if (typeof(window) === 'undefined') { // Node.js less = exports, tree = require('./tree'); less.mode = 'node'; } else { // Browser if (typeof(window.less) === 'undefined') { window.less = {} } less = window.less, tree = window.less.tree = {}; less.mode = 'browser'; } // // less.js - parser // // A relatively straight-forward predictive parser. // There is no tokenization/lexing stage, the input is parsed // in one sweep. // // To make the parser fast enough to run in the browser, several // optimization had to be made: // // - Matching and slicing on a huge input is often cause of slowdowns. // The solution is to chunkify the input into smaller strings. // The chunks are stored in the `chunks` var, // `j` holds the current chunk index, and `current` holds // the index of the current chunk in relation to `input`. // This gives us an almost 4x speed-up. // // - In many cases, we don't need to match individual tokens; // for example, if a value doesn't hold any variables, operations // or dynamic references, the parser can effectively 'skip' it, // treating it as a literal. // An example would be '1px solid #000' - which evaluates to itself, // we don't need to know what the individual components are. // The drawback, of course is that you don't get the benefits of // syntax-checking on the CSS. This gives us a 50% speed-up in the parser, // and a smaller speed-up in the code-gen. // // // Token matching is done with the `$` function, which either takes // a terminal string or regexp, or a non-terminal function to call. // It also takes care of moving all the indices forwards. // // less.Parser = function Parser(env) { var input, // LeSS input string i, // current index in `input` j, // current chunk temp, // temporarily holds a chunk's state, for backtracking memo, // temporarily holds `i`, when backtracking furthest, // furthest index the parser has gone to chunks, // chunkified input current, // index of current chunk, in `input` parser; var that = this; // Top parser on an import tree must be sure there is one "env" // which will then be passed arround by reference. var env = env || { }; // env.contents and files must be passed arround with top env if (!env.contents) { env.contents = {}; } env.rootpath = env.rootpath || ''; // env.rootpath must be initialized to '' if not provided if (!env.files) { env.files = {}; } // This function is called after all files // have been imported through `@import`. var finish = function () {}; var imports = this.imports = { paths: env.paths || [], // Search paths, when importing queue: [], // Files which haven't been imported yet files: env.files, // Holds the imported parse trees contents: env.contents, // Holds the imported file contents mime: env.mime, // MIME type of .less files error: null, // Error in parsing/evaluating an import push: function (path, callback) { var that = this; this.queue.push(path); // // Import a file asynchronously // less.Parser.importer(path, this.paths, function (e, root, fullPath) { that.queue.splice(that.queue.indexOf(path), 1); // Remove the path from the queue var imported = fullPath in that.files; that.files[fullPath] = root; // Store the root if (e && !that.error) { that.error = e } callback(e, root, imported); if (that.queue.length === 0) { finish(that.error) } // Call `finish` if we're done importing }, env); } }; function save() { temp = chunks[j], memo = i, current = i } function restore() { chunks[j] = temp, i = memo, current = i } function sync() { if (i > current) { chunks[j] = chunks[j].slice(i - current); current = i; } } function isWhitespace(c) { // Could change to \s? var code = c.charCodeAt(0); return code === 32 || code === 10 || code === 9; } // // Parse from a token, regexp or string, and move forward if match // function $(tok) { var match, args, length, index, k; // // Non-terminal // if (tok instanceof Function) { return tok.call(parser.parsers); // // Terminal // // Either match a single character in the input, // or match a regexp in the current chunk (chunk[j]). // } else if (typeof(tok) === 'string') { match = input.charAt(i) === tok ? tok : null; length = 1; sync (); } else { sync (); if (match = tok.exec(chunks[j])) { length = match[0].length; } else { return null; } } // The match is confirmed, add the match length to `i`, // and consume any extra white-space characters (' ' || '\n') // which come after that. The reason for this is that LeSS's // grammar is mostly white-space insensitive. // if (match) { skipWhitespace(length); if(typeof(match) === 'string') { return match; } else { return match.length === 1 ? match[0] : match; } } } function skipWhitespace(length) { var oldi = i, oldj = j, endIndex = i + chunks[j].length, mem = i += length; while (i < endIndex) { if (! isWhitespace(input.charAt(i))) { break } i++; } chunks[j] = chunks[j].slice(length + (i - mem)); current = i; if (chunks[j].length === 0 && j < chunks.length - 1) { j++ } return oldi !== i || oldj !== j; } function expect(arg, msg) { var result = $(arg); if (! result) { error(msg || (typeof(arg) === 'string' ? "expected '" + arg + "' got '" + input.charAt(i) + "'" : "unexpected token")); } else { return result; } } function error(msg, type) { var e = new Error(msg); e.index = i; e.type = type || 'Syntax'; throw e; } // Same as $(), but don't change the state of the parser, // just return the match. function peek(tok) { if (typeof(tok) === 'string') { return input.charAt(i) === tok; } else { if (tok.test(chunks[j])) { return true; } else { return false; } } } function getInput(e, env) { if (e.filename && env.filename && (e.filename !== env.filename)) { return parser.imports.contents[e.filename]; } else { return input; } } function getLocation(index, input) { for (var n = index, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } return { line: typeof(index) === 'number' ? (input.slice(0, index).match(/\n/g) || "").length : null, column: column }; } function getFileName(e) { if(less.mode === 'browser' || less.mode === 'rhino') return e.filename; else return require('path').resolve(e.filename); } function getDebugInfo(index, inputStream, e) { return { lineNumber: getLocation(index, inputStream).line + 1, fileName: getFileName(e) }; } function LessError(e, env) { var input = getInput(e, env), loc = getLocation(e.index, input), line = loc.line, col = loc.column, lines = input.split('\n'); this.type = e.type || 'Syntax'; this.message = e.message; this.filename = e.filename || env.filename; this.index = e.index; this.line = typeof(line) === 'number' ? line + 1 : null; this.callLine = e.call && (getLocation(e.call, input).line + 1); this.callExtract = lines[getLocation(e.call, input).line]; this.stack = e.stack; this.column = col; this.extract = [ lines[line - 1], lines[line], lines[line + 1] ]; } this.env = env = env || {}; // The optimization level dictates the thoroughness of the parser, // the lower the number, the less nodes it will create in the tree. // This could matter for debugging, or if you want to access // the individual nodes in the tree. this.optimization = ('optimization' in this.env) ? this.env.optimization : 1; this.env.filename = this.env.filename || null; // // The Parser // return parser = { imports: imports, // // Parse an input string into an abstract syntax tree, // call `callback` when done. // parse: function (str, callback) { var root, start, end, zone, line, lines, buff = [], c, error = null; i = j = current = furthest = 0; input = str.replace(/\r\n/g, '\n'); // Remove potential UTF Byte Order Mark input = input.replace(/^\uFEFF/, ''); // Split the input into chunks. chunks = (function (chunks) { var j = 0, skip = /(?:@\{[\w-]+\}|[^"'`\{\}\/\(\)\\])+/g, comment = /\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g, string = /"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'|`((?:[^`]|\\.)*)`/g, level = 0, match, chunk = chunks[0], inParam; for (var i = 0, c, cc; i < input.length;) { skip.lastIndex = i; if (match = skip.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); } } c = input.charAt(i); comment.lastIndex = string.lastIndex = i; if (match = string.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); continue; } } if (!inParam && c === '/') { cc = input.charAt(i + 1); if (cc === '/' || cc === '*') { if (match = comment.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); continue; } } } } switch (c) { case '{': if (! inParam) { level ++; chunk.push(c); break } case '}': if (! inParam) { level --; chunk.push(c); chunks[++j] = chunk = []; break } case '(': if (! inParam) { inParam = true; chunk.push(c); break } case ')': if ( inParam) { inParam = false; chunk.push(c); break } default: chunk.push(c); } i++; } if (level != 0) { error = new(LessError)({ index: i-1, type: 'Parse', message: (level > 0) ? "missing closing `}`" : "missing opening `{`", filename: env.filename }, env); } return chunks.map(function (c) { return c.join('') });; })([[]]); if (error) { return callback(error, env); } // Start with the primary rule. // The whole syntax tree is held under a Ruleset node, // with the `root` property set to true, so no `{}` are // output. The callback is called when the input is parsed. try { root = new(tree.Ruleset)([], $(this.parsers.primary)); root.root = true; } catch (e) { return callback(new(LessError)(e, env)); } root.toCSS = (function (evaluate) { var line, lines, column; return function (options, variables) { var frames = [], importError; options = options || {}; // // Allows setting variables with a hash, so: // // `{ color: new(tree.Color)('#f01') }` will become: // // new(tree.Rule)('@color', // new(tree.Value)([ // new(tree.Expression)([ // new(tree.Color)('#f01') // ]) // ]) // ) // if (typeof(variables) === 'object' && !Array.isArray(variables)) { variables = Object.keys(variables).map(function (k) { var value = variables[k]; if (! (value instanceof tree.Value)) { if (! (value instanceof tree.Expression)) { value = new(tree.Expression)([value]); } value = new(tree.Value)([value]); } return new(tree.Rule)('@' + k, value, false, 0); }); frames = [new(tree.Ruleset)(null, variables)]; } try { var css = evaluate.call(this, { frames: frames }) .toCSS([], { compress: options.compress || false, dumpLineNumbers: env.dumpLineNumbers }); } catch (e) { throw new(LessError)(e, env); } if ((importError = parser.imports.error)) { // Check if there was an error during importing if (importError instanceof LessError) throw importError; else throw new(LessError)(importError, env); } if (options.yuicompress && less.mode === 'node') { return require('ycssmin').cssmin(css); } else if (options.compress) { return css.replace(/(\s)+/g, "$1"); } else { return css; } }; })(root.eval); // If `i` is smaller than the `input.length - 1`, // it means the parser wasn't able to parse the whole // string, so we've got a parsing error. // // We try to extract a \n delimited string, // showing the line where the parse error occured. // We split it up into two parts (the part which parsed, // and the part which didn't), so we can color them differently. if (i < input.length - 1) { i = furthest; lines = input.split('\n'); line = (input.slice(0, i).match(/\n/g) || "").length + 1; for (var n = i, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } error = { type: "Parse", message: "Syntax Error on line " + line, index: i, filename: env.filename, line: line, column: column, extract: [ lines[line - 2], lines[line - 1], lines[line] ] }; } if (this.imports.queue.length > 0) { finish = function (e) { e = error || e; if (e) callback(e); else callback(null, root); }; } else { callback(error, root); } }, // // Here in, the parsing rules/functions // // The basic structure of the syntax tree generated is as follows: // // Ruleset -> Rule -> Value -> Expression -> Entity // // Here's some LESS code: // // .class { // color: #fff; // border: 1px solid #000; // width: @w + 4px; // > .child {...} // } // // And here's what the parse tree might look like: // // Ruleset (Selector '.class', [ // Rule ("color", Value ([Expression [Color #fff]])) // Rule ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]])) // Rule ("width", Value ([Expression [Operation "+" [Variable "@w"][Dimension 4px]]])) // Ruleset (Selector [Element '>', '.child'], [...]) // ]) // // In general, most rules will try to parse a token with the `$()` function, and if the return // value is truly, will return a new node, of the relevant type. Sometimes, we need to check // first, before parsing, that's when we use `peek()`. // parsers: { // // The `primary` rule is the *entry* and *exit* point of the parser. // The rules here can appear at any level of the parse tree. // // The recursive nature of the grammar is an interplay between the `block` // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule, // as represented by this simplified grammar: // // primary → (ruleset | rule)+ // ruleset → selector+ block // block → '{' primary '}' // // Only at one point is the primary rule not called from the // block rule: at the root level. // primary: function () { var node, root = []; while ((node = $(this.mixin.definition) || $(this.rule) || $(this.ruleset) || $(this.mixin.call) || $(this.comment) || $(this.directive)) || $(/^[\s\n]+/) || $(/^;+/)) { node && root.push(node); } return root; }, // We create a Comment node for CSS comments `/* */`, // but keep the LeSS comments `//` silent, by just skipping // over them. comment: function () { var comment; if (input.charAt(i) !== '/') return; if (input.charAt(i + 1) === '/') { return new(tree.Comment)($(/^\/\/.*/), true); } else if (comment = $(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/)) { return new(tree.Comment)(comment); } }, // // Entities are tokens which can be found inside an Expression // entities: { // // A string, which supports escaping " and ' // // "milky way" 'he\'s the one!' // quoted: function () { var str, j = i, e; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '"' && input.charAt(j) !== "'") return; e && $('~'); if (str = $(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/)) { return new(tree.Quoted)(str[0], str[1] || str[2], e); } }, // // A catch-all word, such as: // // black border-collapse // keyword: function () { var k; if (k = $(/^[_A-Za-z-][_A-Za-z0-9-]*/)) { if (tree.colors.hasOwnProperty(k)) { // detect named color return new(tree.Color)(tree.colors[k].slice(1)); } else { return new(tree.Keyword)(k); } } }, // // A function call // // rgb(255, 0, 255) // // We also try to catch IE's `alpha()`, but let the `alpha` parser // deal with the details. // // The arguments are parsed with the `entities.arguments` parser. // call: function () { var name, nameLC, args, alpha_ret, index = i; if (! (name = /^([\w-]+|%|progid:[\w\.]+)\(/.exec(chunks[j]))) return; name = name[1]; nameLC = name.toLowerCase(); if (nameLC === 'url') { return null } else { i += name.length } if (nameLC === 'alpha') { alpha_ret = $(this.alpha); if(typeof alpha_ret !== 'undefined') { return alpha_ret; } } $('('); // Parse the '(' and consume whitespace. args = $(this.entities.arguments); if (! $(')')) return; if (name) { return new(tree.Call)(name, args, index, env.filename) } }, arguments: function () { var args = [], arg; while (arg = $(this.entities.assignment) || $(this.expression)) { args.push(arg); if (! $(',')) { break } } return args; }, literal: function () { return $(this.entities.ratio) || $(this.entities.dimension) || $(this.entities.color) || $(this.entities.quoted) || $(this.entities.unicodeDescriptor); }, // Assignments are argument entities for calls. // They are present in ie filter properties as shown below. // // filter: progid:DXImageTransform.Microsoft.Alpha( *opacity=50* ) // assignment: function () { var key, value; if ((key = $(/^\w+(?=\s?=)/i)) && $('=') && (value = $(this.entity))) { return new(tree.Assignment)(key, value); } }, // // Parse url() tokens // // We use a specific rule for urls, because they don't really behave like // standard function calls. The difference is that the argument doesn't have // to be enclosed within a string, so it can't be parsed as an Expression. // url: function () { var value; if (input.charAt(i) !== 'u' || !$(/^url\(/)) return; value = $(this.entities.quoted) || $(this.entities.variable) || $(/^(?:(?:\\[\(\)'"])|[^\(\)'"])+/) || ""; expect(')'); return new(tree.URL)((value.value != null || value instanceof tree.Variable) ? value : new(tree.Anonymous)(value), env.rootpath); }, // // A Variable entity, such as `@fink`, in // // width: @fink + 2px // // We use a different parser for variable definitions, // see `parsers.variable`. // variable: function () { var name, index = i; if (input.charAt(i) === '@' && (name = $(/^@@?[\w-]+/))) { return new(tree.Variable)(name, index, env.filename); } }, // A variable entity useing the protective {} e.g. @{var} variableCurly: function () { var name, curly, index = i; if (input.charAt(i) === '@' && (curly = $(/^@\{([\w-]+)\}/))) { return new(tree.Variable)("@" + curly[1], index, env.filename); } }, // // A Hexadecimal color // // #4F3C2F // // `rgb` and `hsl` colors are parsed through the `entities.call` parser. // color: function () { var rgb; if (input.charAt(i) === '#' && (rgb = $(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/))) { return new(tree.Color)(rgb[1]); } }, // // A Dimension, that is, a number and a unit // // 0.5em 95% // dimension: function () { var value, c = input.charCodeAt(i); //Is the first char of the dimension 0-9, '.', '+' or '-' if ((c > 57 || c < 43) || c === 47 || c == 44) return; if (value = $(/^([+-]?\d*\.?\d+)(px|%|em|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn|dpi|dpcm|dppx|rem|vw|vh|vmin|vm|ch)?/)) { return new(tree.Dimension)(value[1], value[2]); } }, // // A Ratio // // 16/9 // ratio: function () { var value, c = input.charCodeAt(i); if (c > 57 || c < 48) return; if (value = $(/^(\d+\/\d+)/)) { return new(tree.Ratio)(value[1]); } }, // // A unicode descriptor, as is used in unicode-range // // U+0?? or U+00A1-00A9 // unicodeDescriptor: function () { var ud; if (ud = $(/^U\+[0-9a-fA-F?]+(\-[0-9a-fA-F?]+)?/)) { return new(tree.UnicodeDescriptor)(ud[0]); } }, // // JavaScript code to be evaluated // // `window.location.href` // javascript: function () { var str, j = i, e; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '`') { return } e && $('~'); if (str = $(/^`([^`]*)`/)) { return new(tree.JavaScript)(str[1], i, e); } } }, // // The variable part of a variable definition. Used in the `rule` parser // // @fink: // variable: function () { var name; if (input.charAt(i) === '@' && (name = $(/^(@[\w-]+)\s*:/))) { return name[1] } }, // // A font size/line-height shorthand // // small/12px // // We need to peek first, or we'll match on keywords and dimensions // shorthand: function () { var a, b; if (! peek(/^[@\w.%-]+\/[@\w.-]+/)) return; save(); if ((a = $(this.entity)) && $('/') && (b = $(this.entity))) { return new(tree.Shorthand)(a, b); } restore(); }, // // Mixins // mixin: { // // A Mixin call, with an optional argument list // // #mixins > .square(#fff); // .rounded(4px, black); // .button; // // The `while` loop is there because mixins can be // namespaced, but we only support the child and descendant // selector for now. // call: function () { var elements = [], e, c, argsSemiColon = [], argsComma = [], args, delim, arg, nameLoop, expressions, isSemiColonSeperated, expressionContainsNamed, index = i, s = input.charAt(i), name, value, important = false; if (s !== '.' && s !== '#') { return } save(); // stop us absorbing part of an invalid selector while (e = $(/^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/)) { elements.push(new(tree.Element)(c, e, i)); c = $('>'); } if ($('(')) { expressions = []; while (arg = $(this.expression)) { nameLoop = null; value = arg; // Variable if (arg.value.length == 1) { var val = arg.value[0]; if (val instanceof tree.Variable) { if ($(':')) { if (expressions.length > 0) { if (isSemiColonSeperated) { error("Cannot mix ; and , as delimiter types"); } expressionContainsNamed = true; } value = expect(this.expression); nameLoop = (name = val.name); } } } expressions.push(value); argsComma.push({ name: nameLoop, value: value }); if ($(',')) { continue; } if ($(';') || isSemiColonSeperated) { if (expressionContainsNamed) { error("Cannot mix ; and , as delimiter types"); } isSemiColonSeperated = true; if (expressions.length > 1) { value = new(tree.Value)(expressions); } argsSemiColon.push({ name: name, value: value }); name = null; expressions = []; expressionContainsNamed = false; } } expect(')'); } args = isSemiColonSeperated ? argsSemiColon : argsComma; if ($(this.important)) { important = true; } if (elements.length > 0 && ($(';') || peek('}'))) { return new(tree.mixin.Call)(elements, args, index, env.filename, important); } restore(); }, // // A Mixin definition, with a list of parameters // // .rounded (@radius: 2px, @color) { // ... // } // // Until we have a finer grained state-machine, we have to // do a look-ahead, to make sure we don't have a mixin call. // See the `rule` function for more information. // // We start by matching `.rounded (`, and then proceed on to // the argument list, which has optional default values. // We store the parameters in `params`, with a `value` key, // if there is a value, such as in the case of `@radius`. // // Once we've got our params list, and a closing `)`, we parse // the `{...}` block. // definition: function () { var name, params = [], match, ruleset, param, value, cond, variadic = false; if ((input.charAt(i) !== '.' && input.charAt(i) !== '#') || peek(/^[^{]*\}/)) return; save(); if (match = $(/^([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/)) { name = match[1]; do { $(this.comment); if (input.charAt(i) === '.' && $(/^\.{3}/)) { variadic = true; params.push({ variadic: true }); break; } else if (param = $(this.entities.variable) || $(this.entities.literal) || $(this.entities.keyword)) { // Variable if (param instanceof tree.Variable) { if ($(':')) { value = expect(this.expression, 'expected expression'); params.push({ name: param.name, value: value }); } else if ($(/^\.{3}/)) { params.push({ name: param.name, variadic: true }); variadic = true; break; } else { params.push({ name: param.name }); } } else { params.push({ value: param }); } } else { break; } } while ($(',') || $(';')) // .mixincall("@{a}"); // looks a bit like a mixin definition.. so we have to be nice and restore if (!$(')')) { furthest = i; restore(); } $(this.comment); if ($(/^when/)) { // Guard cond = expect(this.conditions, 'expected condition'); } ruleset = $(this.block); if (ruleset) { return new(tree.mixin.Definition)(name, params, ruleset, cond, variadic); } else { restore(); } } } }, // // Entities are the smallest recognized token, // and can be found inside a rule's value. // entity: function () { return $(this.entities.literal) || $(this.entities.variable) || $(this.entities.url) || $(this.entities.call) || $(this.entities.keyword) ||$(this.entities.javascript) || $(this.comment); }, // // A Rule terminator. Note that we use `peek()` to check for '}', // because the `block` rule will be expecting it, but we still need to make sure // it's there, if ';' was ommitted. // end: function () { return $(';') || peek('}'); }, // // IE's alpha function // // alpha(opacity=88) // alpha: function () { var value; if (! $(/^\(opacity=/i)) return; if (value = $(/^\d+/) || $(this.entities.variable)) { expect(')'); return new(tree.Alpha)(value); } }, // // A Selector Element // // div // + h1 // #socks // input[type="text"] // // Elements are the building blocks for Selectors, // they are made out of a `Combinator` (see combinator rule), // and an element name, such as a tag a class, or `*`. // element: function () { var e, t, c, v; c = $(this.combinator); e = $(/^(?:\d+\.\d+|\d+)%/) || $(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/) || $('*') || $('&') || $(this.attribute) || $(/^\([^()@]+\)/) || $(/^[\.#](?=@)/) || $(this.entities.variableCurly); if (! e) { if ($('(')) { if ((v = ($(this.entities.variableCurly) || $(this.entities.variable) || $(this.selector))) && $(')')) { e = new(tree.Paren)(v); } } } if (e) { return new(tree.Element)(c, e, i) } }, // // Combinators combine elements together, in a Selector. // // Because our parser isn't white-space sensitive, special care // has to be taken, when parsing the descendant combinator, ` `, // as it's an empty space. We have to check the previous character // in the input, to see if it's a ` ` character. More info on how // we deal with this in *combinator.js*. // combinator: function () { var match, c = input.charAt(i); if (c === '>' || c === '+' || c === '~' || c === '|') { i++; while (input.charAt(i).match(/\s/)) { i++ } return new(tree.Combinator)(c); } else if (input.charAt(i - 1).match(/\s/)) { return new(tree.Combinator)(" "); } else { return new(tree.Combinator)(null); } }, // // A CSS Selector // // .class > div + h1 // li a:hover // // Selectors are made out of one or more Elements, see above. // selector: function () { var sel, e, elements = [], c, match; // depreciated, will be removed soon if ($('(')) { sel = $(this.entity); if (!$(')')) { return null; } return new(tree.Selector)([new(tree.Element)('', sel, i)]); } while (e = $(this.element)) { c = input.charAt(i); elements.push(e) if (c === '{' || c === '}' || c === ';' || c === ',' || c === ')') { break } } if (elements.length > 0) { return new(tree.Selector)(elements) } }, attribute: function () { var attr = '', key, val, op; if (! $('[')) return; if (key = $(/^(?:[_A-Za-z0-9-]|\\.)+/) || $(this.entities.quoted)) { if ((op = $(/^[|~*$^]?=/)) && (val = $(this.entities.quoted) || $(/^[\w-]+/))) { attr = [key, op, val.toCSS ? val.toCSS() : val].join(''); } else { attr = key } } if (! $(']')) return; if (attr) { return "[" + attr + "]" } }, // // The `block` rule is used by `ruleset` and `mixin.definition`. // It's a wrapper around the `primary` rule, with added `{}`. // block: function () { var content; if ($('{') && (content = $(this.primary)) && $('}')) { return content; } }, // // div, .class, body > p {...} // ruleset: function () { var selectors = [], s, rules, match, debugInfo; save(); if (env.dumpLineNumbers) debugInfo = getDebugInfo(i, input, env); while (s = $(this.selector)) { selectors.push(s); $(this.comment); if (! $(',')) { break } $(this.comment); } if (selectors.length > 0 && (rules = $(this.block))) { var ruleset = new(tree.Ruleset)(selectors, rules, env.strictImports); if (env.dumpLineNumbers) ruleset.debugInfo = debugInfo; return ruleset; } else { // Backtrack furthest = i; restore(); } }, rule: function () { var name, value, c = input.charAt(i), important, match; save(); if (c === '.' || c === '#' || c === '&') { return } if (name = $(this.variable) || $(this.property)) { if ((name.charAt(0) != '@') && (match = /^([^@+\/'"*`(;{}-]*);/.exec(chunks[j]))) { i += match[0].length - 1; value = new(tree.Anonymous)(match[1]); } else if (name === "font") { value = $(this.font); } else { value = $(this.value); } important = $(this.important); if (value && $(this.end)) { return new(tree.Rule)(name, value, important, memo); } else { furthest = i; restore(); } } }, // // An @import directive // // @import "lib"; // // Depending on our environemnt, importing is done differently: // In the browser, it's an XHR request, in Node, it would be a // file-system operation. The function used for importing is // stored in `import`, which we pass to the Import constructor. // "import": function () { var path, features, index = i; save(); var dir = $(/^@import(?:-(once))?\s+/); if (dir && (path = $(this.entities.quoted) || $(this.entities.url))) { features = $(this.mediaFeatures); if ($(';')) { return new(tree.Import)(path, imports, features, (dir[1] === 'once'), index, env.rootpath); } } restore(); }, mediaFeature: function () { var e, p, nodes = []; do { if (e = $(this.entities.keyword)) { nodes.push(e); } else if ($('(')) { p = $(this.property); e = $(this.entity); if ($(')')) { if (p && e) { nodes.push(new(tree.Paren)(new(tree.Rule)(p, e, null, i, true))); } else if (e) { nodes.push(new(tree.Paren)(e)); } else { return null; } } else { return null } } } while (e); if (nodes.length > 0) { return new(tree.Expression)(nodes); } }, mediaFeatures: function () { var e, features = []; do { if (e = $(this.mediaFeature)) { features.push(e); if (! $(',')) { break } } else if (e = $(this.entities.variable)) { features.push(e); if (! $(',')) { break } } } while (e); return features.length > 0 ? features : null; }, media: function () { var features, rules, media, debugInfo; if (env.dumpLineNumbers) debugInfo = getDebugInfo(i, input, env); if ($(/^@media/)) { features = $(this.mediaFeatures); if (rules = $(this.block)) { media = new(tree.Media)(rules, features); if(env.dumpLineNumbers) media.debugInfo = debugInfo; return media; } } }, // // A CSS Directive // // @charset "utf-8"; // directive: function () { var name, value, rules, identifier, e, nodes, nonVendorSpecificName, hasBlock, hasIdentifier, hasExpression; if (input.charAt(i) !== '@') return; if (value = $(this['import']) || $(this.media)) { return value; } save(); name = $(/^@[a-z-]+/); if (!name) return; nonVendorSpecificName = name; if (name.charAt(1) == '-' && name.indexOf('-', 2) > 0) { nonVendorSpecificName = "@" + name.slice(name.indexOf('-', 2) + 1); } switch(nonVendorSpecificName) { case "@font-face": hasBlock = true; break; case "@viewport": case "@top-left": case "@top-left-corner": case "@top-center": case "@top-right": case "@top-right-corner": case "@bottom-left": case "@bottom-left-corner": case "@bottom-center": case "@bottom-right": case "@bottom-right-corner": case "@left-top": case "@left-middle": case "@left-bottom": case "@right-top": case "@right-middle": case "@right-bottom": hasBlock = true; break; case "@page": case "@document": case "@supports": case "@keyframes": hasBlock = true; hasIdentifier = true; break; case "@namespace": hasExpression = true; break; } if (hasIdentifier) { name += " " + ($(/^[^{]+/) || '').trim(); } if (hasBlock) { if (rules = $(this.block)) { return new(tree.Directive)(name, rules); } } else { if ((value = hasExpression ? $(this.expression) : $(this.entity)) && $(';')) { var directive = new(tree.Directive)(name, value); if (env.dumpLineNumbers) { directive.debugInfo = getDebugInfo(i, input, env); } return directive; } } restore(); }, font: function () { var value = [], expression = [], weight, shorthand, font, e; while (e = $(this.shorthand) || $(this.entity)) { expression.push(e); } value.push(new(tree.Expression)(expression)); if ($(',')) { while (e = $(this.expression)) { value.push(e); if (! $(',')) { break } } } return new(tree.Value)(value); }, // // A Value is a comma-delimited list of Expressions // // font-family: Baskerville, Georgia, serif; // // In a Rule, a Value represents everything after the `:`, // and before the `;`. // value: function () { var e, expressions = [], important; while (e = $(this.expression)) { expressions.push(e); if (! $(',')) { break } } if (expressions.length > 0) { return new(tree.Value)(expressions); } }, important: function () { if (input.charAt(i) === '!') { return $(/^! *important/); } }, sub: function () { var e; if ($('(') && (e = $(this.expression)) && $(')')) { return e; } }, multiplication: function () { var m, a, op, operation; if (m = $(this.operand)) { while (!peek(/^\/[*\/]/) && (op = ($('/') || $('*'))) && (a = $(this.operand))) { operation = new(tree.Operation)(op, [operation || m, a]); } return operation || m; } }, addition: function () { var m, a, op, operation; if (m = $(this.multiplication)) { while ((op = $(/^[-+]\s+/) || (!isWhitespace(input.charAt(i - 1)) && ($('+') || $('-')))) && (a = $(this.multiplication))) { operation = new(tree.Operation)(op, [operation || m, a]); } return operation || m; } }, conditions: function () { var a, b, index = i, condition; if (a = $(this.condition)) { while ($(',') && (b = $(this.condition))) { condition = new(tree.Condition)('or', condition || a, b, index); } return condition || a; } }, condition: function () { var a, b, c, op, index = i, negate = false; if ($(/^not/)) { negate = true } expect('('); if (a = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) { if (op = $(/^(?:>=|=<|[<=>])/)) { if (b = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) { c = new(tree.Condition)(op, a, b, index, negate); } else { error('expected expression'); } } else { c = new(tree.Condition)('=', a, new(tree.Keyword)('true'), index, negate); } expect(')'); return $(/^and/) ? new(tree.Condition)('and', c, $(this.condition)) : c; } }, // // An operand is anything that can be part of an operation, // such as a Color, or a Variable // operand: function () { var negate, p = input.charAt(i + 1); if (input.charAt(i) === '-' && (p === '@' || p === '(')) { negate = $('-') } var o = $(this.sub) || $(this.entities.dimension) || $(this.entities.color) || $(this.entities.variable) || $(this.entities.call); return negate ? new(tree.Operation)('*', [new(tree.Dimension)(-1), o]) : o; }, // // Expressions either represent mathematical operations, // or white-space delimited Entities. // // 1px solid black // @var * 2 // expression: function () { var e, delim, entities = [], d; while (e = $(this.addition) || $(this.entity)) { entities.push(e); } if (entities.length > 0) { return new(tree.Expression)(entities); } }, property: function () { var name; if (name = $(/^(\*?-?[_a-z0-9-]+)\s*:/)) { return name[1]; } } } }; }; if (less.mode === 'browser' || less.mode === 'rhino') { // // Used by `@import` directives // less.Parser.importer = function (path, paths, callback, env) { if (!/^([a-z-]+:)?\//.test(path) && paths.length > 0) { path = paths[0] + path; } // We pass `true` as 3rd argument, to force the reload of the import. // This is so we can get the syntax tree as opposed to just the CSS output, // as we need this to evaluate the current stylesheet. loadStyleSheet({ href: path, title: path, type: env.mime, contents: env.contents, files: env.files, rootpath: env.rootpath, entryPath: env.entryPath, relativeUrls: env.relativeUrls }, function (e, root, data, sheet, _, path) { if (e && typeof(env.errback) === "function") { env.errback.call(null, path, paths, callback, env); } else { callback.call(null, e, root, path); } }, true); }; } (function (tree) { tree.functions = { rgb: function (r, g, b) { return this.rgba(r, g, b, 1.0); }, rgba: function (r, g, b, a) { var rgb = [r, g, b].map(function (c) { return scaled(c, 256); }); a = number(a); return new(tree.Color)(rgb, a); }, hsl: function (h, s, l) { return this.hsla(h, s, l, 1.0); }, hsla: function (h, s, l, a) { h = (number(h) % 360) / 360; s = number(s); l = number(l); a = number(a); var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s; var m1 = l * 2 - m2; return this.rgba(hue(h + 1/3) * 255, hue(h) * 255, hue(h - 1/3) * 255, a); function hue(h) { h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h); if (h * 6 < 1) return m1 + (m2 - m1) * h * 6; else if (h * 2 < 1) return m2; else if (h * 3 < 2) return m1 + (m2 - m1) * (2/3 - h) * 6; else return m1; } }, hsv: function(h, s, v) { return this.hsva(h, s, v, 1.0); }, hsva: function(h, s, v, a) { h = ((number(h) % 360) / 360) * 360; s = number(s); v = number(v); a = number(a); var i, f; i = Math.floor((h / 60) % 6); f = (h / 60) - i; var vs = [v, v * (1 - s), v * (1 - f * s), v * (1 - (1 - f) * s)]; var perm = [[0, 3, 1], [2, 0, 1], [1, 0, 3], [1, 2, 0], [3, 1, 0], [0, 1, 2]]; return this.rgba(vs[perm[i][0]] * 255, vs[perm[i][1]] * 255, vs[perm[i][2]] * 255, a); }, hue: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().h)); }, saturation: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().s * 100), '%'); }, lightness: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().l * 100), '%'); }, red: function (color) { return new(tree.Dimension)(color.rgb[0]); }, green: function (color) { return new(tree.Dimension)(color.rgb[1]); }, blue: function (color) { return new(tree.Dimension)(color.rgb[2]); }, alpha: function (color) { return new(tree.Dimension)(color.toHSL().a); }, luma: function (color) { return new(tree.Dimension)(Math.round((0.2126 * (color.rgb[0]/255) + 0.7152 * (color.rgb[1]/255) + 0.0722 * (color.rgb[2]/255)) * color.alpha * 100), '%'); }, saturate: function (color, amount) { var hsl = color.toHSL(); hsl.s += amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, desaturate: function (color, amount) { var hsl = color.toHSL(); hsl.s -= amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, lighten: function (color, amount) { var hsl = color.toHSL(); hsl.l += amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, darken: function (color, amount) { var hsl = color.toHSL(); hsl.l -= amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, fadein: function (color, amount) { var hsl = color.toHSL(); hsl.a += amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, fadeout: function (color, amount) { var hsl = color.toHSL(); hsl.a -= amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, fade: function (color, amount) { var hsl = color.toHSL(); hsl.a = amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, spin: function (color, amount) { var hsl = color.toHSL(); var hue = (hsl.h + amount.value) % 360; hsl.h = hue < 0 ? 360 + hue : hue; return hsla(hsl); }, // // Copyright (c) 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein // http://sass-lang.com // mix: function (color1, color2, weight) { if (!weight) { weight = new(tree.Dimension)(50); } var p = weight.value / 100.0; var w = p * 2 - 1; var a = color1.toHSL().a - color2.toHSL().a; var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0; var w2 = 1 - w1; var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2, color1.rgb[1] * w1 + color2.rgb[1] * w2, color1.rgb[2] * w1 + color2.rgb[2] * w2]; var alpha = color1.alpha * p + color2.alpha * (1 - p); return new(tree.Color)(rgb, alpha); }, greyscale: function (color) { return this.desaturate(color, new(tree.Dimension)(100)); }, contrast: function (color, dark, light, threshold) { // filter: contrast(3.2); // should be kept as is, so check for color if (!color.rgb) { return null; } if (typeof light === 'undefined') { light = this.rgba(255, 255, 255, 1.0); } if (typeof dark === 'undefined') { dark = this.rgba(0, 0, 0, 1.0); } if (typeof threshold === 'undefined') { threshold = 0.43; } else { threshold = threshold.value; } if (((0.2126 * (color.rgb[0]/255) + 0.7152 * (color.rgb[1]/255) + 0.0722 * (color.rgb[2]/255)) * color.alpha) < threshold) { return light; } else { return dark; } }, e: function (str) { return new(tree.Anonymous)(str instanceof tree.JavaScript ? str.evaluated : str); }, escape: function (str) { return new(tree.Anonymous)(encodeURI(str.value).replace(/=/g, "%3D").replace(/:/g, "%3A").replace(/#/g, "%23").replace(/;/g, "%3B").replace(/\(/g, "%28").replace(/\)/g, "%29")); }, '%': function (quoted /* arg, arg, ...*/) { var args = Array.prototype.slice.call(arguments, 1), str = quoted.value; for (var i = 0; i < args.length; i++) { str = str.replace(/%[sda]/i, function(token) { var value = token.match(/s/i) ? args[i].value : args[i].toCSS(); return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value; }); } str = str.replace(/%%/g, '%'); return new(tree.Quoted)('"' + str + '"', str); }, unit: function (val, unit) { return new(tree.Dimension)(val.value, unit ? unit.toCSS() : ""); }, round: function (n, f) { var fraction = typeof(f) === "undefined" ? 0 : f.value; return this._math(function(num) { return num.toFixed(fraction); }, n); }, ceil: function (n) { return this._math(Math.ceil, n); }, floor: function (n) { return this._math(Math.floor, n); }, _math: function (fn, n) { if (n instanceof tree.Dimension) { return new(tree.Dimension)(fn(parseFloat(n.value)), n.unit); } else if (typeof(n) === 'number') { return fn(n); } else { throw { type: "Argument", message: "argument must be a number" }; } }, argb: function (color) { return new(tree.Anonymous)(color.toARGB()); }, percentage: function (n) { return new(tree.Dimension)(n.value * 100, '%'); }, color: function (n) { if (n instanceof tree.Quoted) { return new(tree.Color)(n.value.slice(1)); } else { throw { type: "Argument", message: "argument must be a string" }; } }, iscolor: function (n) { return this._isa(n, tree.Color); }, isnumber: function (n) { return this._isa(n, tree.Dimension); }, isstring: function (n) { return this._isa(n, tree.Quoted); }, iskeyword: function (n) { return this._isa(n, tree.Keyword); }, isurl: function (n) { return this._isa(n, tree.URL); }, ispixel: function (n) { return (n instanceof tree.Dimension) && n.unit === 'px' ? tree.True : tree.False; }, ispercentage: function (n) { return (n instanceof tree.Dimension) && n.unit === '%' ? tree.True : tree.False; }, isem: function (n) { return (n instanceof tree.Dimension) && n.unit === 'em' ? tree.True : tree.False; }, _isa: function (n, Type) { return (n instanceof Type) ? tree.True : tree.False; }, /* Blending modes */ multiply: function(color1, color2) { var r = color1.rgb[0] * color2.rgb[0] / 255; var g = color1.rgb[1] * color2.rgb[1] / 255; var b = color1.rgb[2] * color2.rgb[2] / 255; return this.rgb(r, g, b); }, screen: function(color1, color2) { var r = 255 - (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255; var g = 255 - (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255; var b = 255 - (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255; return this.rgb(r, g, b); }, overlay: function(color1, color2) { var r = color1.rgb[0] < 128 ? 2 * color1.rgb[0] * color2.rgb[0] / 255 : 255 - 2 * (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255; var g = color1.rgb[1] < 128 ? 2 * color1.rgb[1] * color2.rgb[1] / 255 : 255 - 2 * (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255; var b = color1.rgb[2] < 128 ? 2 * color1.rgb[2] * color2.rgb[2] / 255 : 255 - 2 * (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255; return this.rgb(r, g, b); }, softlight: function(color1, color2) { var t = color2.rgb[0] * color1.rgb[0] / 255; var r = t + color1.rgb[0] * (255 - (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255 - t) / 255; t = color2.rgb[1] * color1.rgb[1] / 255; var g = t + color1.rgb[1] * (255 - (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255 - t) / 255; t = color2.rgb[2] * color1.rgb[2] / 255; var b = t + color1.rgb[2] * (255 - (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255 - t) / 255; return this.rgb(r, g, b); }, hardlight: function(color1, color2) { var r = color2.rgb[0] < 128 ? 2 * color2.rgb[0] * color1.rgb[0] / 255 : 255 - 2 * (255 - color2.rgb[0]) * (255 - color1.rgb[0]) / 255; var g = color2.rgb[1] < 128 ? 2 * color2.rgb[1] * color1.rgb[1] / 255 : 255 - 2 * (255 - color2.rgb[1]) * (255 - color1.rgb[1]) / 255; var b = color2.rgb[2] < 128 ? 2 * color2.rgb[2] * color1.rgb[2] / 255 : 255 - 2 * (255 - color2.rgb[2]) * (255 - color1.rgb[2]) / 255; return this.rgb(r, g, b); }, difference: function(color1, color2) { var r = Math.abs(color1.rgb[0] - color2.rgb[0]); var g = Math.abs(color1.rgb[1] - color2.rgb[1]); var b = Math.abs(color1.rgb[2] - color2.rgb[2]); return this.rgb(r, g, b); }, exclusion: function(color1, color2) { var r = color1.rgb[0] + color2.rgb[0] * (255 - color1.rgb[0] - color1.rgb[0]) / 255; var g = color1.rgb[1] + color2.rgb[1] * (255 - color1.rgb[1] - color1.rgb[1]) / 255; var b = color1.rgb[2] + color2.rgb[2] * (255 - color1.rgb[2] - color1.rgb[2]) / 255; return this.rgb(r, g, b); }, average: function(color1, color2) { var r = (color1.rgb[0] + color2.rgb[0]) / 2; var g = (color1.rgb[1] + color2.rgb[1]) / 2; var b = (color1.rgb[2] + color2.rgb[2]) / 2; return this.rgb(r, g, b); }, negation: function(color1, color2) { var r = 255 - Math.abs(255 - color2.rgb[0] - color1.rgb[0]); var g = 255 - Math.abs(255 - color2.rgb[1] - color1.rgb[1]); var b = 255 - Math.abs(255 - color2.rgb[2] - color1.rgb[2]); return this.rgb(r, g, b); }, tint: function(color, amount) { return this.mix(this.rgb(255,255,255), color, amount); }, shade: function(color, amount) { return this.mix(this.rgb(0, 0, 0), color, amount); } }; function hsla(color) { return tree.functions.hsla(color.h, color.s, color.l, color.a); } function scaled(n, size) { if (n instanceof tree.Dimension && n.unit == '%') { return parseFloat(n.value * size / 100); } else { return number(n); } } function number(n) { if (n instanceof tree.Dimension) { return parseFloat(n.unit == '%' ? n.value / 100 : n.value); } else if (typeof(n) === 'number') { return n; } else { throw { error: "RuntimeError", message: "color functions take numbers as parameters" }; } } function clamp(val) { return Math.min(1, Math.max(0, val)); } })(require('./tree')); (function (tree) { tree.colors = { 'aliceblue':'#f0f8ff', 'antiquewhite':'#faebd7', 'aqua':'#00ffff', 'aquamarine':'#7fffd4', 'azure':'#f0ffff', 'beige':'#f5f5dc', 'bisque':'#ffe4c4', 'black':'#000000', 'blanchedalmond':'#ffebcd', 'blue':'#0000ff', 'blueviolet':'#8a2be2', 'brown':'#a52a2a', 'burlywood':'#deb887', 'cadetblue':'#5f9ea0', 'chartreuse':'#7fff00', 'chocolate':'#d2691e', 'coral':'#ff7f50', 'cornflowerblue':'#6495ed', 'cornsilk':'#fff8dc', 'crimson':'#dc143c', 'cyan':'#00ffff', 'darkblue':'#00008b', 'darkcyan':'#008b8b', 'darkgoldenrod':'#b8860b', 'darkgray':'#a9a9a9', 'darkgrey':'#a9a9a9', 'darkgreen':'#006400', 'darkkhaki':'#bdb76b', 'darkmagenta':'#8b008b', 'darkolivegreen':'#556b2f', 'darkorange':'#ff8c00', 'darkorchid':'#9932cc', 'darkred':'#8b0000', 'darksalmon':'#e9967a', 'darkseagreen':'#8fbc8f', 'darkslateblue':'#483d8b', 'darkslategray':'#2f4f4f', 'darkslategrey':'#2f4f4f', 'darkturquoise':'#00ced1', 'darkviolet':'#9400d3', 'deeppink':'#ff1493', 'deepskyblue':'#00bfff', 'dimgray':'#696969', 'dimgrey':'#696969', 'dodgerblue':'#1e90ff', 'firebrick':'#b22222', 'floralwhite':'#fffaf0', 'forestgreen':'#228b22', 'fuchsia':'#ff00ff', 'gainsboro':'#dcdcdc', 'ghostwhite':'#f8f8ff', 'gold':'#ffd700', 'goldenrod':'#daa520', 'gray':'#808080', 'grey':'#808080', 'green':'#008000', 'greenyellow':'#adff2f', 'honeydew':'#f0fff0', 'hotpink':'#ff69b4', 'indianred':'#cd5c5c', 'indigo':'#4b0082', 'ivory':'#fffff0', 'khaki':'#f0e68c', 'lavender':'#e6e6fa', 'lavenderblush':'#fff0f5', 'lawngreen':'#7cfc00', 'lemonchiffon':'#fffacd', 'lightblue':'#add8e6', 'lightcoral':'#f08080', 'lightcyan':'#e0ffff', 'lightgoldenrodyellow':'#fafad2', 'lightgray':'#d3d3d3', 'lightgrey':'#d3d3d3', 'lightgreen':'#90ee90', 'lightpink':'#ffb6c1', 'lightsalmon':'#ffa07a', 'lightseagreen':'#20b2aa', 'lightskyblue':'#87cefa', 'lightslategray':'#778899', 'lightslategrey':'#778899', 'lightsteelblue':'#b0c4de', 'lightyellow':'#ffffe0', 'lime':'#00ff00', 'limegreen':'#32cd32', 'linen':'#faf0e6', 'magenta':'#ff00ff', 'maroon':'#800000', 'mediumaquamarine':'#66cdaa', 'mediumblue':'#0000cd', 'mediumorchid':'#ba55d3', 'mediumpurple':'#9370d8', 'mediumseagreen':'#3cb371', 'mediumslateblue':'#7b68ee', 'mediumspringgreen':'#00fa9a', 'mediumturquoise':'#48d1cc', 'mediumvioletred':'#c71585', 'midnightblue':'#191970', 'mintcream':'#f5fffa', 'mistyrose':'#ffe4e1', 'moccasin':'#ffe4b5', 'navajowhite':'#ffdead', 'navy':'#000080', 'oldlace':'#fdf5e6', 'olive':'#808000', 'olivedrab':'#6b8e23', 'orange':'#ffa500', 'orangered':'#ff4500', 'orchid':'#da70d6', 'palegoldenrod':'#eee8aa', 'palegreen':'#98fb98', 'paleturquoise':'#afeeee', 'palevioletred':'#d87093', 'papayawhip':'#ffefd5', 'peachpuff':'#ffdab9', 'peru':'#cd853f', 'pink':'#ffc0cb', 'plum':'#dda0dd', 'powderblue':'#b0e0e6', 'purple':'#800080', 'red':'#ff0000', 'rosybrown':'#bc8f8f', 'royalblue':'#4169e1', 'saddlebrown':'#8b4513', 'salmon':'#fa8072', 'sandybrown':'#f4a460', 'seagreen':'#2e8b57', 'seashell':'#fff5ee', 'sienna':'#a0522d', 'silver':'#c0c0c0', 'skyblue':'#87ceeb', 'slateblue':'#6a5acd', 'slategray':'#708090', 'slategrey':'#708090', 'snow':'#fffafa', 'springgreen':'#00ff7f', 'steelblue':'#4682b4', 'tan':'#d2b48c', 'teal':'#008080', 'thistle':'#d8bfd8', 'tomato':'#ff6347', // 'transparent':'rgba(0,0,0,0)', 'turquoise':'#40e0d0', 'violet':'#ee82ee', 'wheat':'#f5deb3', 'white':'#ffffff', 'whitesmoke':'#f5f5f5', 'yellow':'#ffff00', 'yellowgreen':'#9acd32' }; })(require('./tree')); (function (tree) { tree.Alpha = function (val) { this.value = val; }; tree.Alpha.prototype = { toCSS: function () { return "alpha(opacity=" + (this.value.toCSS ? this.value.toCSS() : this.value) + ")"; }, eval: function (env) { if (this.value.eval) { this.value = this.value.eval(env) } return this; } }; })(require('../tree')); (function (tree) { tree.Anonymous = function (string) { this.value = string.value || string; }; tree.Anonymous.prototype = { toCSS: function () { return this.value; }, eval: function () { return this }, compare: function (x) { if (!x.toCSS) { return -1; } var left = this.toCSS(), right = x.toCSS(); if (left === right) { return 0; } return left < right ? -1 : 1; } }; })(require('../tree')); (function (tree) { tree.Assignment = function (key, val) { this.key = key; this.value = val; }; tree.Assignment.prototype = { toCSS: function () { return this.key + '=' + (this.value.toCSS ? this.value.toCSS() : this.value); }, eval: function (env) { if (this.value.eval) { return new(tree.Assignment)(this.key, this.value.eval(env)); } return this; } }; })(require('../tree'));(function (tree) { // // A function call node. // tree.Call = function (name, args, index, filename) { this.name = name; this.args = args; this.index = index; this.filename = filename; }; tree.Call.prototype = { // // When evaluating a function call, // we either find the function in `tree.functions` [1], // in which case we call it, passing the evaluated arguments, // if this returns null or we cannot find the function, we // simply print it out as it appeared originally [2]. // // The *functions.js* file contains the built-in functions. // // The reason why we evaluate the arguments, is in the case where // we try to pass a variable to a function, like: `saturate(@color)`. // The function should receive the value, not the variable. // eval: function (env) { var args = this.args.map(function (a) { return a.eval(env) }), result; if (this.name in tree.functions) { // 1. try { result = tree.functions[this.name].apply(tree.functions, args); if (result != null) { return result; } } catch (e) { throw { type: e.type || "Runtime", message: "error evaluating function `" + this.name + "`" + (e.message ? ': ' + e.message : ''), index: this.index, filename: this.filename }; } } // 2. return new(tree.Anonymous)(this.name + "(" + args.map(function (a) { return a.toCSS(env) }).join(', ') + ")"); }, toCSS: function (env) { return this.eval(env).toCSS(); } }; })(require('../tree')); (function (tree) { // // RGB Colors - #ff0014, #eee // tree.Color = function (rgb, a) { // // The end goal here, is to parse the arguments // into an integer triplet, such as `128, 255, 0` // // This facilitates operations and conversions. // if (Array.isArray(rgb)) { this.rgb = rgb; } else if (rgb.length == 6) { this.rgb = rgb.match(/.{2}/g).map(function (c) { return parseInt(c, 16); }); } else { this.rgb = rgb.split('').map(function (c) { return parseInt(c + c, 16); }); } this.alpha = typeof(a) === 'number' ? a : 1; }; tree.Color.prototype = { eval: function () { return this }, // // If we have some transparency, the only way to represent it // is via `rgba`. Otherwise, we use the hex representation, // which has better compatibility with older browsers. // Values are capped between `0` and `255`, rounded and zero-padded. // toCSS: function () { if (this.alpha < 1.0) { return "rgba(" + this.rgb.map(function (c) { return Math.round(c); }).concat(this.alpha).join(', ') + ")"; } else { return '#' + this.rgb.map(function (i) { i = Math.round(i); i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16); return i.length === 1 ? '0' + i : i; }).join(''); } }, // // Operations have to be done per-channel, if not, // channels will spill onto each other. Once we have // our result, in the form of an integer triplet, // we create a new Color node to hold the result. // operate: function (op, other) { var result = []; if (! (other instanceof tree.Color)) { other = other.toColor(); } for (var c = 0; c < 3; c++) { result[c] = tree.operate(op, this.rgb[c], other.rgb[c]); } return new(tree.Color)(result, this.alpha + other.alpha); }, toHSL: function () { var r = this.rgb[0] / 255, g = this.rgb[1] / 255, b = this.rgb[2] / 255, a = this.alpha; var max = Math.max(r, g, b), min = Math.min(r, g, b); var h, s, l = (max + min) / 2, d = max - min; if (max === min) { h = s = 0; } else { s = l > 0.5 ? d / (2 - max - min) : d / (max + min); switch (max) { case r: h = (g - b) / d + (g < b ? 6 : 0); break; case g: h = (b - r) / d + 2; break; case b: h = (r - g) / d + 4; break; } h /= 6; } return { h: h * 360, s: s, l: l, a: a }; }, toARGB: function () { var argb = [Math.round(this.alpha * 255)].concat(this.rgb); return '#' + argb.map(function (i) { i = Math.round(i); i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16); return i.length === 1 ? '0' + i : i; }).join(''); }, compare: function (x) { if (!x.rgb) { return -1; } return (x.rgb[0] === this.rgb[0] && x.rgb[1] === this.rgb[1] && x.rgb[2] === this.rgb[2] && x.alpha === this.alpha) ? 0 : -1; } }; })(require('../tree')); (function (tree) { tree.Comment = function (value, silent) { this.value = value; this.silent = !!silent; }; tree.Comment.prototype = { toCSS: function (env) { return env.compress ? '' : this.value; }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.Condition = function (op, l, r, i, negate) { this.op = op.trim(); this.lvalue = l; this.rvalue = r; this.index = i; this.negate = negate; }; tree.Condition.prototype.eval = function (env) { var a = this.lvalue.eval(env), b = this.rvalue.eval(env); var i = this.index, result; var result = (function (op) { switch (op) { case 'and': return a && b; case 'or': return a || b; default: if (a.compare) { result = a.compare(b); } else if (b.compare) { result = b.compare(a); } else { throw { type: "Type", message: "Unable to perform comparison", index: i }; } switch (result) { case -1: return op === '<' || op === '=<'; case 0: return op === '=' || op === '>=' || op === '=<'; case 1: return op === '>' || op === '>='; } } })(this.op); return this.negate ? !result : result; }; })(require('../tree')); (function (tree) { // // A number with a unit // tree.Dimension = function (value, unit) { this.value = parseFloat(value); this.unit = unit || null; }; tree.Dimension.prototype = { eval: function () { return this }, toColor: function () { return new(tree.Color)([this.value, this.value, this.value]); }, toCSS: function () { var css = this.value + this.unit; return css; }, // In an operation between two Dimensions, // we default to the first Dimension's unit, // so `1px + 2em` will yield `3px`. // In the future, we could implement some unit // conversions such that `100cm + 10mm` would yield // `101cm`. operate: function (op, other) { return new(tree.Dimension) (tree.operate(op, this.value, other.value), this.unit || other.unit); }, compare: function (other) { if (other instanceof tree.Dimension) { if (other.value > this.value) { return -1; } else if (other.value < this.value) { return 1; } else { if (other.unit && this.unit !== other.unit) { return -1; } return 0; } } else { return -1; } } }; })(require('../tree')); (function (tree) { tree.Directive = function (name, value) { this.name = name; if (Array.isArray(value)) { this.ruleset = new(tree.Ruleset)([], value); this.ruleset.allowImports = true; } else { this.value = value; } }; tree.Directive.prototype = { toCSS: function (ctx, env) { if (this.ruleset) { this.ruleset.root = true; return this.name + (env.compress ? '{' : ' {\n ') + this.ruleset.toCSS(ctx, env).trim().replace(/\n/g, '\n ') + (env.compress ? '}': '\n}\n'); } else { return this.name + ' ' + this.value.toCSS() + ';\n'; } }, eval: function (env) { var evaldDirective = this; if (this.ruleset) { env.frames.unshift(this); evaldDirective = new(tree.Directive)(this.name); evaldDirective.ruleset = this.ruleset.eval(env); env.frames.shift(); } return evaldDirective; }, variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) }, find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) }, rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) } }; })(require('../tree')); (function (tree) { tree.Element = function (combinator, value, index) { this.combinator = combinator instanceof tree.Combinator ? combinator : new(tree.Combinator)(combinator); if (typeof(value) === 'string') { this.value = value.trim(); } else if (value) { this.value = value; } else { this.value = ""; } this.index = index; }; tree.Element.prototype.eval = function (env) { return new(tree.Element)(this.combinator, this.value.eval ? this.value.eval(env) : this.value, this.index); }; tree.Element.prototype.toCSS = function (env) { var value = (this.value.toCSS ? this.value.toCSS(env) : this.value); if (value == '' && this.combinator.value.charAt(0) == '&') { return ''; } else { return this.combinator.toCSS(env || {}) + value; } }; tree.Combinator = function (value) { if (value === ' ') { this.value = ' '; } else { this.value = value ? value.trim() : ""; } }; tree.Combinator.prototype.toCSS = function (env) { return { '' : '', ' ' : ' ', ':' : ' :', '+' : env.compress ? '+' : ' + ', '~' : env.compress ? '~' : ' ~ ', '>' : env.compress ? '>' : ' > ', '|' : env.compress ? '|' : ' | ' }[this.value]; }; })(require('../tree')); (function (tree) { tree.Expression = function (value) { this.value = value }; tree.Expression.prototype = { eval: function (env) { if (this.value.length > 1) { return new(tree.Expression)(this.value.map(function (e) { return e.eval(env); })); } else if (this.value.length === 1) { return this.value[0].eval(env); } else { return this; } }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS ? e.toCSS(env) : ''; }).join(' '); } }; })(require('../tree')); (function (tree) { // // CSS @import node // // The general strategy here is that we don't want to wait // for the parsing to be completed, before we start importing // the file. That's because in the context of a browser, // most of the time will be spent waiting for the server to respond. // // On creation, we push the import path to our import queue, though // `import,push`, we also pass it a callback, which it'll call once // the file has been fetched, and parsed. // tree.Import = function (path, imports, features, once, index, rootpath) { var that = this; this.once = once; this.index = index; this._path = path; this.features = features && new(tree.Value)(features); this.rootpath = rootpath; // The '.less' extension is optional if (path instanceof tree.Quoted) { this.path = /(\.[a-z]*$)|([\?;].*)$/.test(path.value) ? path.value : path.value + '.less'; } else { this.path = path.value.value || path.value; } this.css = /css([\?;].*)?$/.test(this.path); // Only pre-compile .less files if (! this.css) { imports.push(this.path, function (e, root, imported) { if (e) { e.index = index } if (imported && that.once) that.skip = imported; that.root = root || new(tree.Ruleset)([], []); }); } }; // // The actual import node doesn't return anything, when converted to CSS. // The reason is that it's used at the evaluation stage, so that the rules // it imports can be treated like any other rules. // // In `eval`, we make sure all Import nodes get evaluated, recursively, so // we end up with a flat structure, which can easily be imported in the parent // ruleset. // tree.Import.prototype = { toCSS: function (env) { var features = this.features ? ' ' + this.features.toCSS(env) : ''; if (this.css) { // Add the base path if the import is relative if (typeof this._path.value === "string" && !/^(?:[a-z-]+:|\/)/.test(this._path.value)) { this._path.value = this.rootpath + this._path.value; } return "@import " + this._path.toCSS() + features + ';\n'; } else { return ""; } }, eval: function (env) { var ruleset, features = this.features && this.features.eval(env); if (this.skip) return []; if (this.css) { return this; } else { ruleset = new(tree.Ruleset)([], this.root.rules.slice(0)); ruleset.evalImports(env); return this.features ? new(tree.Media)(ruleset.rules, this.features.value) : ruleset.rules; } } }; })(require('../tree')); (function (tree) { tree.JavaScript = function (string, index, escaped) { this.escaped = escaped; this.expression = string; this.index = index; }; tree.JavaScript.prototype = { eval: function (env) { var result, that = this, context = {}; var expression = this.expression.replace(/@\{([\w-]+)\}/g, function (_, name) { return tree.jsify(new(tree.Variable)('@' + name, that.index).eval(env)); }); try { expression = new(Function)('return (' + expression + ')'); } catch (e) { throw { message: "JavaScript evaluation error: `" + expression + "`" , index: this.index }; } for (var k in env.frames[0].variables()) { context[k.slice(1)] = { value: env.frames[0].variables()[k].value, toJS: function () { return this.value.eval(env).toCSS(); } }; } try { result = expression.call(context); } catch (e) { throw { message: "JavaScript evaluation error: '" + e.name + ': ' + e.message + "'" , index: this.index }; } if (typeof(result) === 'string') { return new(tree.Quoted)('"' + result + '"', result, this.escaped, this.index); } else if (Array.isArray(result)) { return new(tree.Anonymous)(result.join(', ')); } else { return new(tree.Anonymous)(result); } } }; })(require('../tree')); (function (tree) { tree.Keyword = function (value) { this.value = value }; tree.Keyword.prototype = { eval: function () { return this }, toCSS: function () { return this.value }, compare: function (other) { if (other instanceof tree.Keyword) { return other.value === this.value ? 0 : 1; } else { return -1; } } }; tree.True = new(tree.Keyword)('true'); tree.False = new(tree.Keyword)('false'); })(require('../tree')); (function (tree) { tree.Media = function (value, features) { var selectors = this.emptySelectors(); this.features = new(tree.Value)(features); this.ruleset = new(tree.Ruleset)(selectors, value); this.ruleset.allowImports = true; }; tree.Media.prototype = { toCSS: function (ctx, env) { var features = this.features.toCSS(env); this.ruleset.root = (ctx.length === 0 || ctx[0].multiMedia); return '@media ' + features + (env.compress ? '{' : ' {\n ') + this.ruleset.toCSS(ctx, env).trim().replace(/\n/g, '\n ') + (env.compress ? '}': '\n}\n'); }, eval: function (env) { if (!env.mediaBlocks) { env.mediaBlocks = []; env.mediaPath = []; } var media = new(tree.Media)([], []); if(this.debugInfo) { this.ruleset.debugInfo = this.debugInfo; media.debugInfo = this.debugInfo; } media.features = this.features.eval(env); env.mediaPath.push(media); env.mediaBlocks.push(media); env.frames.unshift(this.ruleset); media.ruleset = this.ruleset.eval(env); env.frames.shift(); env.mediaPath.pop(); return env.mediaPath.length === 0 ? media.evalTop(env) : media.evalNested(env) }, variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) }, find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) }, rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) }, emptySelectors: function() { var el = new(tree.Element)('', '&', 0); return [new(tree.Selector)([el])]; }, evalTop: function (env) { var result = this; // Render all dependent Media blocks. if (env.mediaBlocks.length > 1) { var selectors = this.emptySelectors(); result = new(tree.Ruleset)(selectors, env.mediaBlocks); result.multiMedia = true; } delete env.mediaBlocks; delete env.mediaPath; return result; }, evalNested: function (env) { var i, value, path = env.mediaPath.concat([this]); // Extract the media-query conditions separated with `,` (OR). for (i = 0; i < path.length; i++) { value = path[i].features instanceof tree.Value ? path[i].features.value : path[i].features; path[i] = Array.isArray(value) ? value : [value]; } // Trace all permutations to generate the resulting media-query. // // (a, b and c) with nested (d, e) -> // a and d // a and e // b and c and d // b and c and e this.features = new(tree.Value)(this.permute(path).map(function (path) { path = path.map(function (fragment) { return fragment.toCSS ? fragment : new(tree.Anonymous)(fragment); }); for(i = path.length - 1; i > 0; i--) { path.splice(i, 0, new(tree.Anonymous)("and")); } return new(tree.Expression)(path); })); // Fake a tree-node that doesn't output anything. return new(tree.Ruleset)([], []); }, permute: function (arr) { if (arr.length === 0) { return []; } else if (arr.length === 1) { return arr[0]; } else { var result = []; var rest = this.permute(arr.slice(1)); for (var i = 0; i < rest.length; i++) { for (var j = 0; j < arr[0].length; j++) { result.push([arr[0][j]].concat(rest[i])); } } return result; } }, bubbleSelectors: function (selectors) { this.ruleset = new(tree.Ruleset)(selectors.slice(0), [this.ruleset]); } }; })(require('../tree')); (function (tree) { tree.mixin = {}; tree.mixin.Call = function (elements, args, index, filename, important) { this.selector = new(tree.Selector)(elements); this.arguments = args; this.index = index; this.filename = filename; this.important = important; }; tree.mixin.Call.prototype = { eval: function (env) { var mixins, mixin, args, rules = [], match = false, i, m, f, isRecursive, isOneFound; args = this.arguments && this.arguments.map(function (a) { return { name: a.name, value: a.value.eval(env) }; }); for (i = 0; i < env.frames.length; i++) { if ((mixins = env.frames[i].find(this.selector)).length > 0) { isOneFound = true; for (m = 0; m < mixins.length; m++) { mixin = mixins[m]; isRecursive = false; for(f = 0; f < env.frames.length; f++) { if ((!(mixin instanceof tree.mixin.Definition)) && mixin === (env.frames[f].originalRuleset || env.frames[f])) { isRecursive = true; break; } } if (isRecursive) { continue; } if (mixin.matchArgs(args, env)) { if (!mixin.matchCondition || mixin.matchCondition(args, env)) { try { Array.prototype.push.apply( rules, mixin.eval(env, args, this.important).rules); } catch (e) { throw { message: e.message, index: this.index, filename: this.filename, stack: e.stack }; } } match = true; } } if (match) { return rules; } } } if (isOneFound) { throw { type: 'Runtime', message: 'No matching definition was found for `' + this.selector.toCSS().trim() + '(' + (args ? args.map(function (a) { var argValue = ""; if (a.name) { argValue += a.name + ":"; } if (a.value.toCSS) { argValue += a.value.toCSS(); } else { argValue += "???"; } return argValue; }).join(', ') : "") + ")`", index: this.index, filename: this.filename }; } else { throw { type: 'Name', message: this.selector.toCSS().trim() + " is undefined", index: this.index, filename: this.filename }; } } }; tree.mixin.Definition = function (name, params, rules, condition, variadic) { this.name = name; this.selectors = [new(tree.Selector)([new(tree.Element)(null, name)])]; this.params = params; this.condition = condition; this.variadic = variadic; this.arity = params.length; this.rules = rules; this._lookups = {}; this.required = params.reduce(function (count, p) { if (!p.name || (p.name && !p.value)) { return count + 1 } else { return count } }, 0); this.parent = tree.Ruleset.prototype; this.frames = []; }; tree.mixin.Definition.prototype = { toCSS: function () { return "" }, variable: function (name) { return this.parent.variable.call(this, name) }, variables: function () { return this.parent.variables.call(this) }, find: function () { return this.parent.find.apply(this, arguments) }, rulesets: function () { return this.parent.rulesets.apply(this) }, evalParams: function (env, mixinEnv, args, evaldArguments) { var frame = new(tree.Ruleset)(null, []), varargs, arg, params = this.params.slice(0), i, j, val, name, isNamedFound, argIndex; if (args) { args = args.slice(0); for(i = 0; i < args.length; i++) { arg = args[i]; if (name = (arg && arg.name)) { isNamedFound = false; for(j = 0; j < params.length; j++) { if (!evaldArguments[j] && name === params[j].name) { evaldArguments[j] = arg.value.eval(env); frame.rules.unshift(new(tree.Rule)(name, arg.value.eval(env))); isNamedFound = true; break; } } if (isNamedFound) { args.splice(i, 1); i--; continue; } else { throw { type: 'Runtime', message: "Named argument for " + this.name + ' ' + args[i].name + ' not found' }; } } } } argIndex = 0; for (i = 0; i < params.length; i++) { if (evaldArguments[i]) continue; arg = args && args[argIndex]; if (name = params[i].name) { if (params[i].variadic && args) { varargs = []; for (j = argIndex; j < args.length; j++) { varargs.push(args[j].value.eval(env)); } frame.rules.unshift(new(tree.Rule)(name, new(tree.Expression)(varargs).eval(env))); } else { val = arg && arg.value; if (val) { val = val.eval(env); } else if (params[i].value) { val = params[i].value.eval(mixinEnv); } else { throw { type: 'Runtime', message: "wrong number of arguments for " + this.name + ' (' + args.length + ' for ' + this.arity + ')' }; } frame.rules.unshift(new(tree.Rule)(name, val)); evaldArguments[i] = val; } } if (params[i].variadic && args) { for (j = argIndex; j < args.length; j++) { evaldArguments[j] = args[j].value.eval(env); } } argIndex++; } return frame; }, eval: function (env, args, important) { var _arguments = [], mixinFrames = this.frames.concat(env.frames), frame = this.evalParams(env, {frames: mixinFrames}, args, _arguments), context, rules, start, ruleset; frame.rules.unshift(new(tree.Rule)('@arguments', new(tree.Expression)(_arguments).eval(env))); rules = important ? this.parent.makeImportant.apply(this).rules : this.rules.slice(0); ruleset = new(tree.Ruleset)(null, rules).eval({ frames: [this, frame].concat(mixinFrames) }); ruleset.originalRuleset = this; return ruleset; }, matchCondition: function (args, env) { if (this.condition && !this.condition.eval({ frames: [this.evalParams(env, {frames: this.frames.concat(env.frames)}, args, [])].concat(env.frames) })) { return false } return true; }, matchArgs: function (args, env) { var argsLength = (args && args.length) || 0, len, frame; if (! this.variadic) { if (argsLength < this.required) { return false } if (argsLength > this.params.length) { return false } if ((this.required > 0) && (argsLength > this.params.length)) { return false } } len = Math.min(argsLength, this.arity); for (var i = 0; i < len; i++) { if (!this.params[i].name && !this.params[i].variadic) { if (args[i].value.eval(env).toCSS() != this.params[i].value.eval(env).toCSS()) { return false; } } } return true; } }; })(require('../tree')); (function (tree) { tree.Operation = function (op, operands) { this.op = op.trim(); this.operands = operands; }; tree.Operation.prototype.eval = function (env) { var a = this.operands[0].eval(env), b = this.operands[1].eval(env), temp; if (a instanceof tree.Dimension && b instanceof tree.Color) { if (this.op === '*' || this.op === '+') { temp = b, b = a, a = temp; } else { throw { name: "OperationError", message: "Can't substract or divide a color from a number" }; } } if (!a.operate) { throw { name: "OperationError", message: "Operation on an invalid type" }; } return a.operate(this.op, b); }; tree.operate = function (op, a, b) { switch (op) { case '+': return a + b; case '-': return a - b; case '*': return a * b; case '/': return a / b; } }; })(require('../tree')); (function (tree) { tree.Paren = function (node) { this.value = node; }; tree.Paren.prototype = { toCSS: function (env) { return '(' + this.value.toCSS(env) + ')'; }, eval: function (env) { return new(tree.Paren)(this.value.eval(env)); } }; })(require('../tree')); (function (tree) { tree.Quoted = function (str, content, escaped, i) { this.escaped = escaped; this.value = content || ''; this.quote = str.charAt(0); this.index = i; }; tree.Quoted.prototype = { toCSS: function () { if (this.escaped) { return this.value; } else { return this.quote + this.value + this.quote; } }, eval: function (env) { var that = this; var value = this.value.replace(/`([^`]+)`/g, function (_, exp) { return new(tree.JavaScript)(exp, that.index, true).eval(env).value; }).replace(/@\{([\w-]+)\}/g, function (_, name) { var v = new(tree.Variable)('@' + name, that.index).eval(env); return (v instanceof tree.Quoted) ? v.value : v.toCSS(); }); return new(tree.Quoted)(this.quote + value + this.quote, value, this.escaped, this.index); }, compare: function (x) { if (!x.toCSS) { return -1; } var left = this.toCSS(), right = x.toCSS(); if (left === right) { return 0; } return left < right ? -1 : 1; } }; })(require('../tree')); (function (tree) { tree.Ratio = function (value) { this.value = value; }; tree.Ratio.prototype = { toCSS: function (env) { return this.value; }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.Rule = function (name, value, important, index, inline) { this.name = name; this.value = (value instanceof tree.Value) ? value : new(tree.Value)([value]); this.important = important ? ' ' + important.trim() : ''; this.index = index; this.inline = inline || false; if (name.charAt(0) === '@') { this.variable = true; } else { this.variable = false } }; tree.Rule.prototype.toCSS = function (env) { if (this.variable) { return "" } else { return this.name + (env.compress ? ':' : ': ') + this.value.toCSS(env) + this.important + (this.inline ? "" : ";"); } }; tree.Rule.prototype.eval = function (context) { return new(tree.Rule)(this.name, this.value.eval(context), this.important, this.index, this.inline); }; tree.Rule.prototype.makeImportant = function () { return new(tree.Rule)(this.name, this.value, "!important", this.index, this.inline); }; tree.Shorthand = function (a, b) { this.a = a; this.b = b; }; tree.Shorthand.prototype = { toCSS: function (env) { return this.a.toCSS(env) + "/" + this.b.toCSS(env); }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.Ruleset = function (selectors, rules, strictImports) { this.selectors = selectors; this.rules = rules; this._lookups = {}; this.strictImports = strictImports; }; tree.Ruleset.prototype = { eval: function (env) { var selectors = this.selectors && this.selectors.map(function (s) { return s.eval(env) }); var ruleset = new(tree.Ruleset)(selectors, this.rules.slice(0), this.strictImports); var rules; ruleset.originalRuleset = this; ruleset.root = this.root; ruleset.allowImports = this.allowImports; if(this.debugInfo) { ruleset.debugInfo = this.debugInfo; } // push the current ruleset to the frames stack env.frames.unshift(ruleset); // Evaluate imports if (ruleset.root || ruleset.allowImports || !ruleset.strictImports) { ruleset.evalImports(env); } // Store the frames around mixin definitions, // so they can be evaluated like closures when the time comes. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Definition) { ruleset.rules[i].frames = env.frames.slice(0); } } var mediaBlockCount = (env.mediaBlocks && env.mediaBlocks.length) || 0; // Evaluate mixin calls. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Call) { rules = ruleset.rules[i].eval(env); ruleset.rules.splice.apply(ruleset.rules, [i, 1].concat(rules)); i += rules.length-1; ruleset.resetCache(); } } // Evaluate everything else for (var i = 0, rule; i < ruleset.rules.length; i++) { rule = ruleset.rules[i]; if (! (rule instanceof tree.mixin.Definition)) { ruleset.rules[i] = rule.eval ? rule.eval(env) : rule; } } // Pop the stack env.frames.shift(); if (env.mediaBlocks) { for(var i = mediaBlockCount; i < env.mediaBlocks.length; i++) { env.mediaBlocks[i].bubbleSelectors(selectors); } } return ruleset; }, evalImports: function(env) { var i, rules; for (i = 0; i < this.rules.length; i++) { if (this.rules[i] instanceof tree.Import) { rules = this.rules[i].eval(env); if (typeof rules.length === "number") { this.rules.splice.apply(this.rules, [i, 1].concat(rules)); i+= rules.length-1; } else { this.rules.splice(i, 1, rules); } this.resetCache(); } } }, makeImportant: function() { return new tree.Ruleset(this.selectors, this.rules.map(function (r) { if (r.makeImportant) { return r.makeImportant(); } else { return r; } }), this.strictImports); }, matchArgs: function (args) { return !args || args.length === 0; }, resetCache: function () { this._rulesets = null; this._variables = null; this._lookups = {}; }, variables: function () { if (this._variables) { return this._variables } else { return this._variables = this.rules.reduce(function (hash, r) { if (r instanceof tree.Rule && r.variable === true) { hash[r.name] = r; } return hash; }, {}); } }, variable: function (name) { return this.variables()[name]; }, rulesets: function () { if (this._rulesets) { return this._rulesets } else { return this._rulesets = this.rules.filter(function (r) { return (r instanceof tree.Ruleset) || (r instanceof tree.mixin.Definition); }); } }, find: function (selector, self) { self = self || this; var rules = [], rule, match, key = selector.toCSS(); if (key in this._lookups) { return this._lookups[key] } this.rulesets().forEach(function (rule) { if (rule !== self) { for (var j = 0; j < rule.selectors.length; j++) { if (match = selector.match(rule.selectors[j])) { if (selector.elements.length > rule.selectors[j].elements.length) { Array.prototype.push.apply(rules, rule.find( new(tree.Selector)(selector.elements.slice(1)), self)); } else { rules.push(rule); } break; } } } }); return this._lookups[key] = rules; }, // // Entry point for code generation // // `context` holds an array of arrays. // toCSS: function (context, env) { var css = [], // The CSS output rules = [], // node.Rule instances _rules = [], // rulesets = [], // node.Ruleset instances paths = [], // Current selectors selector, // The fully rendered selector debugInfo, // Line number debugging rule; if (! this.root) { this.joinSelectors(paths, context, this.selectors); } // Compile rules and rulesets for (var i = 0; i < this.rules.length; i++) { rule = this.rules[i]; if (rule.rules || (rule instanceof tree.Media)) { rulesets.push(rule.toCSS(paths, env)); } else if (rule instanceof tree.Directive) { var cssValue = rule.toCSS(paths, env); // Output only the first @charset definition as such - convert the others // to comments in case debug is enabled if (rule.name === "@charset") { // Only output the debug info together with subsequent @charset definitions // a comment (or @media statement) before the actual @charset directive would // be considered illegal css as it has to be on the first line if (env.charset) { if (rule.debugInfo) { rulesets.push(tree.debugInfo(env, rule)); rulesets.push(new tree.Comment("/* "+cssValue.replace(/\n/g, "")+" */\n").toCSS(env)); } continue; } env.charset = true; } rulesets.push(cssValue); } else if (rule instanceof tree.Comment) { if (!rule.silent) { if (this.root) { rulesets.push(rule.toCSS(env)); } else { rules.push(rule.toCSS(env)); } } } else { if (rule.toCSS && !rule.variable) { rules.push(rule.toCSS(env)); } else if (rule.value && !rule.variable) { rules.push(rule.value.toString()); } } } rulesets = rulesets.join(''); // If this is the root node, we don't render // a selector, or {}. // Otherwise, only output if this ruleset has rules. if (this.root) { css.push(rules.join(env.compress ? '' : '\n')); } else { if (rules.length > 0) { debugInfo = tree.debugInfo(env, this); selector = paths.map(function (p) { return p.map(function (s) { return s.toCSS(env); }).join('').trim(); }).join(env.compress ? ',' : ',\n'); // Remove duplicates for (var i = rules.length - 1; i >= 0; i--) { if (_rules.indexOf(rules[i]) === -1) { _rules.unshift(rules[i]); } } rules = _rules; css.push(debugInfo + selector + (env.compress ? '{' : ' {\n ') + rules.join(env.compress ? '' : '\n ') + (env.compress ? '}' : '\n}\n')); } } css.push(rulesets); return css.join('') + (env.compress ? '\n' : ''); }, joinSelectors: function (paths, context, selectors) { for (var s = 0; s < selectors.length; s++) { this.joinSelector(paths, context, selectors[s]); } }, joinSelector: function (paths, context, selector) { var i, j, k, hasParentSelector, newSelectors, el, sel, parentSel, newSelectorPath, afterParentJoin, newJoinedSelector, newJoinedSelectorEmpty, lastSelector, currentElements, selectorsMultiplied; for (i = 0; i < selector.elements.length; i++) { el = selector.elements[i]; if (el.value === '&') { hasParentSelector = true; } } if (!hasParentSelector) { if (context.length > 0) { for(i = 0; i < context.length; i++) { paths.push(context[i].concat(selector)); } } else { paths.push([selector]); } return; } // The paths are [[Selector]] // The first list is a list of comma seperated selectors // The inner list is a list of inheritance seperated selectors // e.g. // .a, .b { // .c { // } // } // == [[.a] [.c]] [[.b] [.c]] // // the elements from the current selector so far currentElements = []; // the current list of new selectors to add to the path. // We will build it up. We initiate it with one empty selector as we "multiply" the new selectors // by the parents newSelectors = [[]]; for (i = 0; i < selector.elements.length; i++) { el = selector.elements[i]; // non parent reference elements just get added if (el.value !== "&") { currentElements.push(el); } else { // the new list of selectors to add selectorsMultiplied = []; // merge the current list of non parent selector elements // on to the current list of selectors to add if (currentElements.length > 0) { this.mergeElementsOnToSelectors(currentElements, newSelectors); } // loop through our current selectors for(j = 0; j < newSelectors.length; j++) { sel = newSelectors[j]; // if we don't have any parent paths, the & might be in a mixin so that it can be used // whether there are parents or not if (context.length == 0) { // the combinator used on el should now be applied to the next element instead so that // it is not lost if (sel.length > 0) { sel[0].elements = sel[0].elements.slice(0); sel[0].elements.push(new(tree.Element)(el.combinator, '', 0)); //new Element(el.Combinator, "")); } selectorsMultiplied.push(sel); } else { // and the parent selectors for(k = 0; k < context.length; k++) { parentSel = context[k]; // We need to put the current selectors // then join the last selector's elements on to the parents selectors // our new selector path newSelectorPath = []; // selectors from the parent after the join afterParentJoin = []; newJoinedSelectorEmpty = true; //construct the joined selector - if & is the first thing this will be empty, // if not newJoinedSelector will be the last set of elements in the selector if (sel.length > 0) { newSelectorPath = sel.slice(0); lastSelector = newSelectorPath.pop(); newJoinedSelector = new(tree.Selector)(lastSelector.elements.slice(0)); newJoinedSelectorEmpty = false; } else { newJoinedSelector = new(tree.Selector)([]); } //put together the parent selectors after the join if (parentSel.length > 1) { afterParentJoin = afterParentJoin.concat(parentSel.slice(1)); } if (parentSel.length > 0) { newJoinedSelectorEmpty = false; // join the elements so far with the first part of the parent newJoinedSelector.elements.push(new(tree.Element)(el.combinator, parentSel[0].elements[0].value, 0)); newJoinedSelector.elements = newJoinedSelector.elements.concat(parentSel[0].elements.slice(1)); } if (!newJoinedSelectorEmpty) { // now add the joined selector newSelectorPath.push(newJoinedSelector); } // and the rest of the parent newSelectorPath = newSelectorPath.concat(afterParentJoin); // add that to our new set of selectors selectorsMultiplied.push(newSelectorPath); } } } // our new selectors has been multiplied, so reset the state newSelectors = selectorsMultiplied; currentElements = []; } } // if we have any elements left over (e.g. .a& .b == .b) // add them on to all the current selectors if (currentElements.length > 0) { this.mergeElementsOnToSelectors(currentElements, newSelectors); } for(i = 0; i < newSelectors.length; i++) { paths.push(newSelectors[i]); } }, mergeElementsOnToSelectors: function(elements, selectors) { var i, sel; if (selectors.length == 0) { selectors.push([ new(tree.Selector)(elements) ]); return; } for(i = 0; i < selectors.length; i++) { sel = selectors[i]; // if the previous thing in sel is a parent this needs to join on to it if (sel.length > 0) { sel[sel.length - 1] = new(tree.Selector)(sel[sel.length - 1].elements.concat(elements)); } else { sel.push(new(tree.Selector)(elements)); } } } }; })(require('../tree')); (function (tree) { tree.Selector = function (elements) { this.elements = elements; }; tree.Selector.prototype.match = function (other) { var elements = this.elements, len = elements.length, oelements, olen, max, i; oelements = other.elements.slice( (other.elements.length && other.elements[0].value === "&") ? 1 : 0); olen = oelements.length; max = Math.min(len, olen) if (olen === 0 || len < olen) { return false; } else { for (i = 0; i < max; i++) { if (elements[i].value !== oelements[i].value) { return false; } } } return true; }; tree.Selector.prototype.eval = function (env) { return new(tree.Selector)(this.elements.map(function (e) { return e.eval(env); })); }; tree.Selector.prototype.toCSS = function (env) { if (this._css) { return this._css } if (this.elements[0].combinator.value === "") { this._css = ' '; } else { this._css = ''; } this._css += this.elements.map(function (e) { if (typeof(e) === 'string') { return ' ' + e.trim(); } else { return e.toCSS(env); } }).join(''); return this._css; }; })(require('../tree')); (function (tree) { tree.UnicodeDescriptor = function (value) { this.value = value; }; tree.UnicodeDescriptor.prototype = { toCSS: function (env) { return this.value; }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.URL = function (val, rootpath) { this.value = val; this.rootpath = rootpath; }; tree.URL.prototype = { toCSS: function () { return "url(" + this.value.toCSS() + ")"; }, eval: function (ctx) { var val = this.value.eval(ctx), rootpath; // Add the base path if the URL is relative if (typeof val.value === "string" && !/^(?:[a-z-]+:|\/)/.test(val.value)) { rootpath = this.rootpath; if (!val.quote) { rootpath = rootpath.replace(/[\(\)'"\s]/g, function(match) { return "\\"+match; }); } val.value = rootpath + val.value; } return new(tree.URL)(val, this.rootpath); } }; })(require('../tree')); (function (tree) { tree.Value = function (value) { this.value = value; this.is = 'value'; }; tree.Value.prototype = { eval: function (env) { if (this.value.length === 1) { return this.value[0].eval(env); } else { return new(tree.Value)(this.value.map(function (v) { return v.eval(env); })); } }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS(env); }).join(env.compress ? ',' : ', '); } }; })(require('../tree')); (function (tree) { tree.Variable = function (name, index, file) { this.name = name, this.index = index, this.file = file }; tree.Variable.prototype = { eval: function (env) { var variable, v, name = this.name; if (name.indexOf('@@') == 0) { name = '@' + new(tree.Variable)(name.slice(1)).eval(env).value; } if (this.evaluating) { throw { type: 'Name', message: "Recursive variable definition for " + name, filename: this.file, index: this.index }; } this.evaluating = true; if (variable = tree.find(env.frames, function (frame) { if (v = frame.variable(name)) { return v.value.eval(env); } })) { this.evaluating = false; return variable; } else { throw { type: 'Name', message: "variable " + name + " is undefined", filename: this.file, index: this.index }; } } }; })(require('../tree')); (function (tree) { tree.debugInfo = function(env, ctx) { var result=""; if (env.dumpLineNumbers && !env.compress) { switch(env.dumpLineNumbers) { case 'comments': result = tree.debugInfo.asComment(ctx); break; case 'mediaquery': result = tree.debugInfo.asMediaQuery(ctx); break; case 'all': result = tree.debugInfo.asComment(ctx)+tree.debugInfo.asMediaQuery(ctx); break; } } return result; }; tree.debugInfo.asComment = function(ctx) { return '/* line ' + ctx.debugInfo.lineNumber + ', ' + ctx.debugInfo.fileName + ' */\n'; }; tree.debugInfo.asMediaQuery = function(ctx) { return '@media -sass-debug-info{filename{font-family:' + ('file://' + ctx.debugInfo.fileName).replace(/[\/:.]/g, '\\$&') + '}line{font-family:\\00003' + ctx.debugInfo.lineNumber + '}}\n'; }; tree.find = function (obj, fun) { for (var i = 0, r; i < obj.length; i++) { if (r = fun.call(obj, obj[i])) { return r } } return null; }; tree.jsify = function (obj) { if (Array.isArray(obj.value) && (obj.value.length > 1)) { return '[' + obj.value.map(function (v) { return v.toCSS(false) }).join(', ') + ']'; } else { return obj.toCSS(false); } }; })(require('./tree')); // // browser.js - client-side engine // var isFileProtocol = /^(file|chrome(-extension)?|resource|qrc|app):/.test(location.protocol); less.env = less.env || (location.hostname == '127.0.0.1' || location.hostname == '0.0.0.0' || location.hostname == 'localhost' || location.port.length > 0 || isFileProtocol ? 'development' : 'production'); // Load styles asynchronously (default: false) // // This is set to `false` by default, so that the body // doesn't start loading before the stylesheets are parsed. // Setting this to `true` can result in flickering. // less.async = less.async || false; less.fileAsync = less.fileAsync || false; // Interval between watch polls less.poll = less.poll || (isFileProtocol ? 1000 : 1500); //Setup user functions if (less.functions) { for(var func in less.functions) { less.tree.functions[func] = less.functions[func]; } } var dumpLineNumbers = /!dumpLineNumbers:(comments|mediaquery|all)/.exec(location.hash); if (dumpLineNumbers) { less.dumpLineNumbers = dumpLineNumbers[1]; } // // Watch mode // less.watch = function () { if (!less.watchMode ){ less.env = 'development'; initRunningMode(); } return this.watchMode = true }; less.unwatch = function () {clearInterval(less.watchTimer); return this.watchMode = false; }; function initRunningMode(){ if (less.env === 'development') { less.optimization = 0; less.watchTimer = setInterval(function () { if (less.watchMode) { loadStyleSheets(function (e, root, _, sheet, env) { if (root) { createCSS(root.toCSS(), sheet, env.lastModified); } }); } }, less.poll); } else { less.optimization = 3; } } if (/!watch/.test(location.hash)) { less.watch(); } var cache = null; if (less.env != 'development') { try { cache = (typeof(window.localStorage) === 'undefined') ? null : window.localStorage; } catch (_) {} } // // Get all tags with the 'rel' attribute set to "stylesheet/less" // var links = document.getElementsByTagName('link'); var typePattern = /^text\/(x-)?less$/; less.sheets = []; for (var i = 0; i < links.length; i++) { if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) && (links[i].type.match(typePattern)))) { less.sheets.push(links[i]); } } // // With this function, it's possible to alter variables and re-render // CSS without reloading less-files // var session_cache = ''; less.modifyVars = function(record) { var str = session_cache; for (name in record) { str += ((name.slice(0,1) === '@')? '' : '@') + name +': '+ ((record[name].slice(-1) === ';')? record[name] : record[name] +';'); } new(less.Parser)().parse(str, function (e, root) { createCSS(root.toCSS(), less.sheets[less.sheets.length - 1]); }); }; less.refresh = function (reload) { var startTime, endTime; startTime = endTime = new(Date); loadStyleSheets(function (e, root, _, sheet, env) { if (env.local) { log("loading " + sheet.href + " from cache."); } else { log("parsed " + sheet.href + " successfully."); createCSS(root.toCSS(), sheet, env.lastModified); } log("css for " + sheet.href + " generated in " + (new(Date) - endTime) + 'ms'); (env.remaining === 0) && log("css generated in " + (new(Date) - startTime) + 'ms'); endTime = new(Date); }, reload); loadStyles(); }; less.refreshStyles = loadStyles; less.refresh(less.env === 'development'); function loadStyles() { var styles = document.getElementsByTagName('style'); for (var i = 0; i < styles.length; i++) { if (styles[i].type.match(typePattern)) { new(less.Parser)({ filename: document.location.href.replace(/#.*$/, ''), dumpLineNumbers: less.dumpLineNumbers }).parse(styles[i].innerHTML || '', function (e, tree) { var css = tree.toCSS(); var style = styles[i]; style.type = 'text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.innerHTML = css; } }); } } } function loadStyleSheets(callback, reload) { for (var i = 0; i < less.sheets.length; i++) { loadStyleSheet(less.sheets[i], callback, reload, less.sheets.length - (i + 1)); } } function pathDiff(url, baseUrl) { // diff between two paths to create a relative path var urlParts = extractUrlParts(url), baseUrlParts = extractUrlParts(baseUrl), i, max, urlDirectories, baseUrlDirectories, diff = ""; if (urlParts.hostPart !== baseUrlParts.hostPart) { return ""; } max = Math.max(baseUrlParts.directories.length, urlParts.directories.length); for(i = 0; i < max; i++) { if (baseUrlParts.directories[i] !== urlParts.directories[i]) { break; } } baseUrlDirectories = baseUrlParts.directories.slice(i); urlDirectories = urlParts.directories.slice(i); for(i = 0; i < baseUrlDirectories.length-1; i++) { diff += "../"; } for(i = 0; i < urlDirectories.length-1; i++) { diff += urlDirectories[i] + "/"; } return diff; } function extractUrlParts(url, baseUrl) { // urlParts[1] = protocol&hostname || / // urlParts[2] = / if path relative to host base // urlParts[3] = directories // urlParts[4] = filename // urlParts[5] = parameters var urlPartsRegex = /^((?:[a-z-]+:)?\/\/(?:[^\/\?#]*\/)|([\/\\]))?((?:[^\/\\\?#]*[\/\\])*)([^\/\\\?#]*)([#\?].*)?$/, urlParts = url.match(urlPartsRegex), returner = {}, directories = [], i, baseUrlParts; if (!urlParts) { throw new Error("Could not parse sheet href - '"+url+"'"); } // Stylesheets in IE don't always return the full path if (!urlParts[1] || urlParts[2]) { baseUrlParts = baseUrl.match(urlPartsRegex); if (!baseUrlParts) { throw new Error("Could not parse page url - '"+baseUrl+"'"); } urlParts[1] = baseUrlParts[1]; if (!urlParts[2]) { urlParts[3] = baseUrlParts[3] + urlParts[3]; } } if (urlParts[3]) { directories = urlParts[3].replace("\\", "/").split("/"); for(i = 0; i < directories.length; i++) { if (directories[i] === ".." && i > 0) { directories.splice(i-1, 2); i -= 2; } } } returner.hostPart = urlParts[1]; returner.directories = directories; returner.path = urlParts[1] + directories.join("/"); returner.fileUrl = returner.path + (urlParts[4] || ""); returner.url = returner.fileUrl + (urlParts[5] || ""); return returner; } function loadStyleSheet(sheet, callback, reload, remaining) { // sheet may be set to the stylesheet for the initial load or a collection of properties including // some env variables for imports var contents = sheet.contents || {}; var files = sheet.files || {}; var hrefParts = extractUrlParts(sheet.href, window.location.href); var href = hrefParts.url; var css = cache && cache.getItem(href); var timestamp = cache && cache.getItem(href + ':timestamp'); var styles = { css: css, timestamp: timestamp }; var rootpath; if (less.relativeUrls) { if (less.rootpath) { if (sheet.entryPath) { rootpath = extractUrlParts(less.rootpath + pathDiff(hrefParts.path, sheet.entryPath)).path; } else { rootpath = less.rootpath; } } else { rootpath = hrefParts.path; } } else { if (less.rootpath) { rootpath = less.rootpath; } else { if (sheet.entryPath) { rootpath = sheet.entryPath; } else { rootpath = hrefParts.path; } } } xhr(href, sheet.type, function (data, lastModified) { // Store data this session session_cache += data.replace(/@import .+?;/ig, ''); if (!reload && styles && lastModified && (new(Date)(lastModified).valueOf() === new(Date)(styles.timestamp).valueOf())) { // Use local copy createCSS(styles.css, sheet); callback(null, null, data, sheet, { local: true, remaining: remaining }, href); } else { // Use remote copy (re-parse) try { contents[href] = data; // Updating top importing parser content cache new(less.Parser)({ optimization: less.optimization, paths: [hrefParts.path], entryPath: sheet.entryPath || hrefParts.path, mime: sheet.type, filename: href, rootpath: rootpath, relativeUrls: sheet.relativeUrls, contents: contents, // Passing top importing parser content cache ref down. files: files, dumpLineNumbers: less.dumpLineNumbers }).parse(data, function (e, root) { if (e) { return error(e, href) } try { callback(e, root, data, sheet, { local: false, lastModified: lastModified, remaining: remaining }, href); removeNode(document.getElementById('less-error-message:' + extractId(href))); } catch (e) { error(e, href); } }); } catch (e) { error(e, href); } } }, function (status, url) { throw new(Error)("Couldn't load " + url + " (" + status + ")"); }); } function extractId(href) { return href.replace(/^[a-z]+:\/\/?[^\/]+/, '' ) // Remove protocol & domain .replace(/^\//, '' ) // Remove root / .replace(/\.[a-zA-Z]+$/, '' ) // Remove simple extension .replace(/[^\.\w-]+/g, '-') // Replace illegal characters .replace(/\./g, ':'); // Replace dots with colons(for valid id) } function createCSS(styles, sheet, lastModified) { var css; // Strip the query-string var href = sheet.href || ''; // If there is no title set, use the filename, minus the extension var id = 'less:' + (sheet.title || extractId(href)); // If the stylesheet doesn't exist, create a new node if ((css = document.getElementById(id)) === null) { css = document.createElement('style'); css.type = 'text/css'; if( sheet.media ){ css.media = sheet.media; } css.id = id; var nextEl = sheet && sheet.nextSibling || null; (nextEl || document.getElementsByTagName('head')[0]).parentNode.insertBefore(css, nextEl); } if (css.styleSheet) { // IE try { css.styleSheet.cssText = styles; } catch (e) { throw new(Error)("Couldn't reassign styleSheet.cssText."); } } else { (function (node) { if (css.childNodes.length > 0) { if (css.firstChild.nodeValue !== node.nodeValue) { css.replaceChild(node, css.firstChild); } } else { css.appendChild(node); } })(document.createTextNode(styles)); } // Don't update the local store if the file wasn't modified if (lastModified && cache) { log('saving ' + href + ' to cache.'); try { cache.setItem(href, styles); cache.setItem(href + ':timestamp', lastModified); } catch(e) { //TODO - could do with adding more robust error handling log('failed to save'); } } } function xhr(url, type, callback, errback) { var xhr = getXMLHttpRequest(); var async = isFileProtocol ? less.fileAsync : less.async; if (typeof(xhr.overrideMimeType) === 'function') { xhr.overrideMimeType('text/css'); } xhr.open('GET', url, async); xhr.setRequestHeader('Accept', type || 'text/x-less, text/css; q=0.9, */*; q=0.5'); xhr.send(null); if (isFileProtocol && !less.fileAsync) { if (xhr.status === 0 || (xhr.status >= 200 && xhr.status < 300)) { callback(xhr.responseText); } else { errback(xhr.status, url); } } else if (async) { xhr.onreadystatechange = function () { if (xhr.readyState == 4) { handleResponse(xhr, callback, errback); } }; } else { handleResponse(xhr, callback, errback); } function handleResponse(xhr, callback, errback) { if (xhr.status >= 200 && xhr.status < 300) { callback(xhr.responseText, xhr.getResponseHeader("Last-Modified")); } else if (typeof(errback) === 'function') { errback(xhr.status, url); } } } function getXMLHttpRequest() { if (window.XMLHttpRequest) { return new(XMLHttpRequest); } else { try { return new(ActiveXObject)("MSXML2.XMLHTTP.3.0"); } catch (e) { log("browser doesn't support AJAX."); return null; } } } function removeNode(node) { return node && node.parentNode.removeChild(node); } function log(str) { if (less.env == 'development' && typeof(console) !== "undefined") { console.log('less: ' + str) } } function error(e, href) { var id = 'less-error-message:' + extractId(href); var template = '
  • {content}
  • '; var elem = document.createElement('div'), timer, content, error = []; var filename = e.filename || href; var filenameNoPath = filename.match(/([^\/]+(\?.*)?)$/)[1]; elem.id = id; elem.className = "less-error-message"; content = '

    ' + (e.message || 'There is an error in your .less file') + '

    ' + '

    in ' + filenameNoPath + " "; var errorline = function (e, i, classname) { if (e.extract[i]) { error.push(template.replace(/\{line\}/, parseInt(e.line) + (i - 1)) .replace(/\{class\}/, classname) .replace(/\{content\}/, e.extract[i])); } }; if (e.stack) { content += '
    ' + e.stack.split('\n').slice(1).join('
    '); } else if (e.extract) { errorline(e, 0, ''); errorline(e, 1, 'line'); errorline(e, 2, ''); content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':

    ' + '
      ' + error.join('') + '
    '; } elem.innerHTML = content; // CSS for error messages createCSS([ '.less-error-message ul, .less-error-message li {', 'list-style-type: none;', 'margin-right: 15px;', 'padding: 4px 0;', 'margin: 0;', '}', '.less-error-message label {', 'font-size: 12px;', 'margin-right: 15px;', 'padding: 4px 0;', 'color: #cc7777;', '}', '.less-error-message pre {', 'color: #dd6666;', 'padding: 4px 0;', 'margin: 0;', 'display: inline-block;', '}', '.less-error-message pre.line {', 'color: #ff0000;', '}', '.less-error-message h3 {', 'font-size: 20px;', 'font-weight: bold;', 'padding: 15px 0 5px 0;', 'margin: 0;', '}', '.less-error-message a {', 'color: #10a', '}', '.less-error-message .error {', 'color: red;', 'font-weight: bold;', 'padding-bottom: 2px;', 'border-bottom: 1px dashed red;', '}' ].join('\n'), { title: 'error-message' }); elem.style.cssText = [ "font-family: Arial, sans-serif", "border: 1px solid #e00", "background-color: #eee", "border-radius: 5px", "-webkit-border-radius: 5px", "-moz-border-radius: 5px", "color: #e00", "padding: 15px", "margin-bottom: 15px" ].join(';'); if (less.env == 'development') { timer = setInterval(function () { if (document.body) { if (document.getElementById(id)) { document.body.replaceChild(elem, document.getElementById(id)); } else { document.body.insertBefore(elem, document.body.firstChild); } clearInterval(timer); } }, 10); } } // amd.js // // Define Less as an AMD module. if (typeof define === "function" && define.amd) { define("less", [], function () { return less; } ); } })(window); less.js-1.4.2/dist/less-1.3.3.min.js000066400000000000000000001615111217256642200166040ustar00rootroot00000000000000// // LESS - Leaner CSS v1.3.3 // http://lesscss.org // // Copyright (c) 2009-2013, Alexis Sellier // Licensed under the Apache 2.0 License. // (function(e,t){function n(t){return e.less[t.split("/")[1]]}function f(){r.env==="development"?(r.optimization=0,r.watchTimer=setInterval(function(){r.watchMode&&g(function(e,t,n,r,i){t&&S(t.toCSS(),r,i.lastModified)})},r.poll)):r.optimization=3}function m(){var e=document.getElementsByTagName("style");for(var t=0;t0&&(s.splice(o-1,2),o-=2)}return i.hostPart=r[1],i.directories=s,i.path=r[1]+s.join("/"),i.fileUrl=i.path+(r[4]||""),i.url=i.fileUrl+(r[5]||""),i}function w(t,n,i,s){var o=t.contents||{},u=t.files||{},a=b(t.href,e.location.href),f=a.url,c=l&&l.getItem(f),h=l&&l.getItem(f+":timestamp"),p={css:c,timestamp:h},d;r.relativeUrls?r.rootpath?t.entryPath?d=b(r.rootpath+y(a.path,t.entryPath)).path:d=r.rootpath:d=a.path:r.rootpath?d=r.rootpath:t.entryPath?d=t.entryPath:d=a.path,x(f,t.type,function(e,l){v+=e.replace(/@import .+?;/ig,"");if(!i&&p&&l&&(new Date(l)).valueOf()===(new Date(p.timestamp)).valueOf())S(p.css,t),n(null,null,e,t,{local:!0,remaining:s},f);else try{o[f]=e,(new r.Parser({optimization:r.optimization,paths:[a.path],entryPath:t.entryPath||a.path,mime:t.type,filename:f,rootpath:d,relativeUrls:t.relativeUrls,contents:o,files:u,dumpLineNumbers:r.dumpLineNumbers})).parse(e,function(r,i){if(r)return k(r,f);try{n(r,i,e,t,{local:!1,lastModified:l,remaining:s},f),N(document.getElementById("less-error-message:"+E(f)))}catch(r){k(r,f)}})}catch(c){k(c,f)}},function(e,t){throw new Error("Couldn't load "+t+" ("+e+")")})}function E(e){return e.replace(/^[a-z]+:\/\/?[^\/]+/,"").replace(/^\//,"").replace(/\.[a-zA-Z]+$/,"").replace(/[^\.\w-]+/g,"-").replace(/\./g,":")}function S(e,t,n){var r,i=t.href||"",s="less:"+(t.title||E(i));if((r=document.getElementById(s))===null){r=document.createElement("style"),r.type="text/css",t.media&&(r.media=t.media),r.id=s;var o=t&&t.nextSibling||null;(o||document.getElementsByTagName("head")[0]).parentNode.insertBefore(r,o)}if(r.styleSheet)try{r.styleSheet.cssText=e}catch(u){throw new Error("Couldn't reassign styleSheet.cssText.")}else(function(e){r.childNodes.length>0?r.firstChild.nodeValue!==e.nodeValue&&r.replaceChild(e,r.firstChild):r.appendChild(e)})(document.createTextNode(e));if(n&&l){C("saving "+i+" to cache.");try{l.setItem(i,e),l.setItem(i+":timestamp",n)}catch(u){C("failed to save")}}}function x(e,t,n,i){function a(t,n,r){t.status>=200&&t.status<300?n(t.responseText,t.getResponseHeader("Last-Modified")):typeof r=="function"&&r(t.status,e)}var s=T(),u=o?r.fileAsync:r.async;typeof s.overrideMimeType=="function"&&s.overrideMimeType("text/css"),s.open("GET",e,u),s.setRequestHeader("Accept",t||"text/x-less, text/css; q=0.9, */*; q=0.5"),s.send(null),o&&!r.fileAsync?s.status===0||s.status>=200&&s.status<300?n(s.responseText):i(s.status,e):u?s.onreadystatechange=function(){s.readyState==4&&a(s,n,i)}:a(s,n,i)}function T(){if(e.XMLHttpRequest)return new XMLHttpRequest;try{return new ActiveXObject("MSXML2.XMLHTTP.3.0")}catch(t){return C("browser doesn't support AJAX."),null}}function N(e){return e&&e.parentNode.removeChild(e)}function C(e){r.env=="development"&&typeof console!="undefined"&&console.log("less: "+e)}function k(e,t){var n="less-error-message:"+E(t),i='
  • {content}
  • ',s=document.createElement("div"),o,u,a=[],f=e.filename||t,l=f.match(/([^\/]+(\?.*)?)$/)[1];s.id=n,s.className="less-error-message",u="

    "+(e.message||"There is an error in your .less file")+"

    "+'

    in '+l+" ";var c=function(e,t,n){e.extract[t]&&a.push(i.replace(/\{line\}/,parseInt(e.line)+(t-1)).replace(/\{class\}/,n).replace(/\{content\}/,e.extract[t]))};e.stack?u+="
    "+e.stack.split("\n").slice(1).join("
    "):e.extract&&(c(e,0,""),c(e,1,"line"),c(e,2,""),u+="on line "+e.line+", column "+(e.column+1)+":

    "+"
      "+a.join("")+"
    "),s.innerHTML=u,S([".less-error-message ul, .less-error-message li {","list-style-type: none;","margin-right: 15px;","padding: 4px 0;","margin: 0;","}",".less-error-message label {","font-size: 12px;","margin-right: 15px;","padding: 4px 0;","color: #cc7777;","}",".less-error-message pre {","color: #dd6666;","padding: 4px 0;","margin: 0;","display: inline-block;","}",".less-error-message pre.line {","color: #ff0000;","}",".less-error-message h3 {","font-size: 20px;","font-weight: bold;","padding: 15px 0 5px 0;","margin: 0;","}",".less-error-message a {","color: #10a","}",".less-error-message .error {","color: red;","font-weight: bold;","padding-bottom: 2px;","border-bottom: 1px dashed red;","}"].join("\n"),{title:"error-message"}),s.style.cssText=["font-family: Arial, sans-serif","border: 1px solid #e00","background-color: #eee","border-radius: 5px","-webkit-border-radius: 5px","-moz-border-radius: 5px","color: #e00","padding: 15px","margin-bottom: 15px"].join(";"),r.env=="development"&&(o=setInterval(function(){document.body&&(document.getElementById(n)?document.body.replaceChild(s,document.getElementById(n)):document.body.insertBefore(s,document.body.firstChild),clearInterval(o))},10))}Array.isArray||(Array.isArray=function(e){return Object.prototype.toString.call(e)==="[object Array]"||e instanceof Array}),Array.prototype.forEach||(Array.prototype.forEach=function(e,t){var n=this.length>>>0;for(var r=0;r>>0,n=new Array(t),r=arguments[1];for(var i=0;i>>0,n=0;if(t===0&&arguments.length===1)throw new TypeError;if(arguments.length>=2)var r=arguments[1];else do{if(n in this){r=this[n++];break}if(++n>=t)throw new TypeError}while(!0);for(;n=t)return-1;n<0&&(n+=t);for(;nh&&(c[u]=c[u].slice(o-h),h=o)}function w(e){var t=e.charCodeAt(0);return t===32||t===10||t===9}function E(e){var t,n,r,i,a;if(e instanceof Function)return e.call(p.parsers);if(typeof e=="string")t=s.charAt(o)===e?e:null,r=1,b();else{b();if(!(t=e.exec(c[u])))return null;r=t[0].length}if(t)return S(r),typeof t=="string"?t:t.length===1?t[0]:t}function S(e){var t=o,n=u,r=o+c[u].length,i=o+=e;while(o=0&&t.charAt(n)!=="\n";n--)r++;return{line:typeof e=="number"?(t.slice(0,e).match(/\n/g)||"").length:null,column:r}}function L(e){return r.mode==="browser"||r.mode==="rhino"?e.filename:n("path").resolve(e.filename)}function A(e,t,n){return{lineNumber:k(e,t).line+1,fileName:L(n)}}function O(e,t){var n=C(e,t),r=k(e.index,n),i=r.line,s=r.column,o=n.split("\n");this.type=e.type||"Syntax",this.message=e.message,this.filename=e.filename||t.filename,this.index=e.index,this.line=typeof i=="number"?i+1:null,this.callLine=e.call&&k(e.call,n).line+1,this.callExtract=o[k(e.call,n).line],this.stack=e.stack,this.column=s,this.extract=[o[i-1],o[i],o[i+1]]}var s,o,u,a,f,l,c,h,p,d=this,t=t||{};t.contents||(t.contents={}),t.rootpath=t.rootpath||"",t.files||(t.files={});var v=function(){},m=this.imports={paths:t.paths||[],queue:[],files:t.files,contents:t.contents,mime:t.mime,error:null,push:function(e,n){var i=this;this.queue.push(e),r.Parser.importer(e,this.paths,function(t,r,s){i.queue.splice(i.queue.indexOf(e),1);var o=s in i.files;i.files[s]=r,t&&!i.error&&(i.error=t),n(t,r,o),i.queue.length===0&&v(i.error)},t)}};return this.env=t=t||{},this.optimization="optimization"in this.env?this.env.optimization:1,this.env.filename=this.env.filename||null,p={imports:m,parse:function(e,a){var f,d,m,g,y,b,w=[],S,x=null;o=u=h=l=0,s=e.replace(/\r\n/g,"\n"),s=s.replace(/^\uFEFF/,""),c=function(e){var n=0,r=/(?:@\{[\w-]+\}|[^"'`\{\}\/\(\)\\])+/g,i=/\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g,o=/"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'|`((?:[^`]|\\.)*)`/g,u=0,a,f=e[0],l;for(var c=0,h,p;c0?"missing closing `}`":"missing opening `{`",filename:t.filename},t)),e.map(function(e){return e.join("")})}([[]]);if(x)return a(x,t);try{f=new i.Ruleset([],E(this.parsers.primary)),f.root=!0}catch(T){return a(new O(T,t))}f.toCSS=function(e){var s,o,u;return function(s,o){var u=[],a;s=s||{},typeof o=="object"&&!Array.isArray(o)&&(o=Object.keys(o).map(function(e){var t=o[e];return t instanceof i.Value||(t instanceof i.Expression||(t=new i.Expression([t])),t=new i.Value([t])),new i.Rule("@"+e,t,!1,0)}),u=[new i.Ruleset(null,o)]);try{var f=e.call(this,{frames:u}).toCSS([],{compress:s.compress||!1,dumpLineNumbers:t.dumpLineNumbers})}catch(l){throw new O(l,t)}if(a=p.imports.error)throw a instanceof O?a:new O(a,t);return s.yuicompress&&r.mode==="node"?n("ycssmin").cssmin(f):s.compress?f.replace(/(\s)+/g,"$1"):f}}(f.eval);if(o=0&&s.charAt(N)!=="\n";N--)C++;x={type:"Parse",message:"Syntax Error on line "+y,index:o,filename:t.filename,line:y,column:C,extract:[b[y-2],b[y-1],b[y]]}}this.imports.queue.length>0?v=function(e){e=x||e,e?a(e):a(null,f)}:a(x,f)},parsers:{primary:function(){var e,t=[];while((e=E(this.mixin.definition)||E(this.rule)||E(this.ruleset)||E(this.mixin.call)||E(this.comment)||E(this.directive))||E(/^[\s\n]+/)||E(/^;+/))e&&t.push(e);return t},comment:function(){var e;if(s.charAt(o)!=="/")return;if(s.charAt(o+1)==="/")return new i.Comment(E(/^\/\/.*/),!0);if(e=E(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/))return new i.Comment(e)},entities:{quoted:function(){var e,t=o,n;s.charAt(t)==="~"&&(t++,n=!0);if(s.charAt(t)!=='"'&&s.charAt(t)!=="'")return;n&&E("~");if(e=E(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/))return new i.Quoted(e[0],e[1]||e[2],n)},keyword:function(){var e;if(e=E(/^[_A-Za-z-][_A-Za-z0-9-]*/))return i.colors.hasOwnProperty(e)?new i.Color(i.colors[e].slice(1)):new i.Keyword(e)},call:function(){var e,n,r,s,a=o;if(!(e=/^([\w-]+|%|progid:[\w\.]+)\(/.exec(c[u])))return;e=e[1],n=e.toLowerCase();if(n==="url")return null;o+=e.length;if(n==="alpha"){s=E(this.alpha);if(typeof s!="undefined")return s}E("("),r=E(this.entities.arguments);if(!E(")"))return;if(e)return new i.Call(e,r,a,t.filename)},arguments:function(){var e=[],t;while(t=E(this.entities.assignment)||E(this.expression)){e.push(t);if(!E(","))break}return e},literal:function(){return E(this.entities.ratio)||E(this.entities.dimension)||E(this.entities.color)||E(this.entities.quoted)||E(this.entities.unicodeDescriptor)},assignment:function(){var e,t;if((e=E(/^\w+(?=\s?=)/i))&&E("=")&&(t=E(this.entity)))return new i.Assignment(e,t)},url:function(){var e;if(s.charAt(o)!=="u"||!E(/^url\(/))return;return e=E(this.entities.quoted)||E(this.entities.variable)||E(/^(?:(?:\\[\(\)'"])|[^\(\)'"])+/)||"",x(")"),new i.URL(e.value!=null||e instanceof i.Variable?e:new i.Anonymous(e),t.rootpath)},variable:function(){var e,n=o;if(s.charAt(o)==="@"&&(e=E(/^@@?[\w-]+/)))return new i.Variable(e,n,t.filename)},variableCurly:function(){var e,n,r=o;if(s.charAt(o)==="@"&&(n=E(/^@\{([\w-]+)\}/)))return new i.Variable("@"+n[1],r,t.filename)},color:function(){var e;if(s.charAt(o)==="#"&&(e=E(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/)))return new i.Color(e[1])},dimension:function(){var e,t=s.charCodeAt(o);if(t>57||t<43||t===47||t==44)return;if(e=E(/^([+-]?\d*\.?\d+)(px|%|em|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn|dpi|dpcm|dppx|rem|vw|vh|vmin|vm|ch)?/))return new i.Dimension(e[1],e[2])},ratio:function(){var e,t=s.charCodeAt(o);if(t>57||t<48)return;if(e=E(/^(\d+\/\d+)/))return new i.Ratio(e[1])},unicodeDescriptor:function(){var e;if(e=E(/^U\+[0-9a-fA-F?]+(\-[0-9a-fA-F?]+)?/))return new i.UnicodeDescriptor(e[0])},javascript:function(){var e,t=o,n;s.charAt(t)==="~"&&(t++,n=!0);if(s.charAt(t)!=="`")return;n&&E("~");if(e=E(/^`([^`]*)`/))return new i.JavaScript(e[1],o,n)}},variable:function(){var e;if(s.charAt(o)==="@"&&(e=E(/^(@[\w-]+)\s*:/)))return e[1]},shorthand:function(){var e,t;if(!N(/^[@\w.%-]+\/[@\w.-]+/))return;g();if((e=E(this.entity))&&E("/")&&(t=E(this.entity)))return new i.Shorthand(e,t);y()},mixin:{call:function(){var e=[],n,r,u=[],a=[],f,l,c,h,p,d,v,m=o,b=s.charAt(o),w,S,C=!1;if(b!=="."&&b!=="#")return;g();while(n=E(/^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/))e.push(new i.Element(r,n,o)),r=E(">");if(E("(")){p=[];while(c=E(this.expression)){h=null,S=c;if(c.value.length==1){var k=c.value[0];k instanceof i.Variable&&E(":")&&(p.length>0&&(d&&T("Cannot mix ; and , as delimiter types"),v=!0),S=x(this.expression),h=w=k.name)}p.push(S),a.push({name:h,value:S});if(E(","))continue;if(E(";")||d)v&&T("Cannot mix ; and , as delimiter types"),d=!0,p.length>1&&(S=new i.Value(p)),u.push({name:w,value:S}),w=null,p=[],v=!1}x(")")}f=d?u:a,E(this.important)&&(C=!0);if(e.length>0&&(E(";")||N("}")))return new i.mixin.Call(e,f,m,t.filename,C);y()},definition:function(){var e,t=[],n,r,u,a,f,c=!1;if(s.charAt(o)!=="."&&s.charAt(o)!=="#"||N(/^[^{]*\}/))return;g();if(n=E(/^([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/)){e=n[1];do{E(this.comment);if(s.charAt(o)==="."&&E(/^\.{3}/)){c=!0,t.push({variadic:!0});break}if(!(u=E(this.entities.variable)||E(this.entities.literal)||E(this.entities.keyword)))break;if(u instanceof i.Variable)if(E(":"))a=x(this.expression,"expected expression"),t.push({name:u.name,value:a});else{if(E(/^\.{3}/)){t.push({name:u.name,variadic:!0}),c=!0;break}t.push({name:u.name})}else t.push({value:u})}while(E(",")||E(";"));E(")")||(l=o,y()),E(this.comment),E(/^when/)&&(f=x(this.conditions,"expected condition")),r=E(this.block);if(r)return new i.mixin.Definition(e,t,r,f,c);y()}}},entity:function(){return E(this.entities.literal)||E(this.entities.variable)||E(this.entities.url)||E(this.entities.call)||E(this.entities.keyword)||E(this.entities.javascript)||E(this.comment)},end:function(){return E(";")||N("}")},alpha:function(){var e;if(!E(/^\(opacity=/i))return;if(e=E(/^\d+/)||E(this.entities.variable))return x(")"),new i.Alpha(e)},element:function(){var e,t,n,r;n=E(this.combinator),e=E(/^(?:\d+\.\d+|\d+)%/)||E(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/)||E("*")||E("&")||E(this.attribute)||E(/^\([^()@]+\)/)||E(/^[\.#](?=@)/)||E(this.entities.variableCurly),e||E("(")&&(r=E(this.entities.variableCurly)||E(this.entities.variable)||E(this.selector))&&E(")")&&(e=new i.Paren(r));if(e)return new i.Element(n,e,o)},combinator:function(){var e,t=s.charAt(o);if(t===">"||t==="+"||t==="~"||t==="|"){o++;while(s.charAt(o).match(/\s/))o++;return new i.Combinator(t)}return s.charAt(o-1).match(/\s/)?new i.Combinator(" "):new i.Combinator(null)},selector:function(){var e,t,n=[],r,u;if(E("("))return e=E(this.entity),E(")")?new i.Selector([new i.Element("",e,o)]):null;while(t=E(this.element)){r=s.charAt(o),n.push(t);if(r==="{"||r==="}"||r===";"||r===","||r===")")break}if(n.length>0)return new i.Selector(n)},attribute:function(){var e="",t,n,r;if(!E("["))return;if(t=E(/^(?:[_A-Za-z0-9-]|\\.)+/)||E(this.entities.quoted))(r=E(/^[|~*$^]?=/))&&(n=E(this.entities.quoted)||E(/^[\w-]+/))?e=[t,r,n.toCSS?n.toCSS():n].join(""):e=t;if(!E("]"))return;if(e)return"["+e+"]"},block:function(){var e;if(E("{")&&(e=E(this.primary))&&E("}"))return e},ruleset:function(){var e=[],n,r,u,a;g(),t.dumpLineNumbers&&(a=A(o,s,t));while(n=E(this.selector)){e.push(n),E(this.comment);if(!E(","))break;E(this.comment)}if(e.length>0&&(r=E(this.block))){var f=new i.Ruleset(e,r,t.strictImports);return t.dumpLineNumbers&&(f.debugInfo=a),f}l=o,y()},rule:function(){var e,t,n=s.charAt(o),r,a;g();if(n==="."||n==="#"||n==="&")return;if(e=E(this.variable)||E(this.property)){e.charAt(0)!="@"&&(a=/^([^@+\/'"*`(;{}-]*);/.exec(c[u]))?(o+=a[0].length-1,t=new i.Anonymous(a[1])):e==="font"?t=E(this.font):t=E(this.value),r=E(this.important);if(t&&E(this.end))return new i.Rule(e,t,r,f);l=o,y()}},"import":function(){var e,n,r=o;g();var s=E(/^@import(?:-(once))?\s+/);if(s&&(e=E(this.entities.quoted)||E(this.entities.url))){n=E(this.mediaFeatures);if(E(";"))return new i.Import(e,m,n,s[1]==="once",r,t.rootpath)}y()},mediaFeature:function(){var e,t,n=[];do if(e=E(this.entities.keyword))n.push(e);else if(E("(")){t=E(this.property),e=E(this.entity);if(!E(")"))return null;if(t&&e)n.push(new i.Paren(new i.Rule(t,e,null,o,!0)));else{if(!e)return null;n.push(new i.Paren(e))}}while(e);if(n.length>0)return new i.Expression(n)},mediaFeatures:function(){var e,t=[];do if(e=E(this.mediaFeature)){t.push(e);if(!E(","))break}else if(e=E(this.entities.variable)){t.push(e);if(!E(","))break}while(e);return t.length>0?t:null},media:function(){var e,n,r,u;t.dumpLineNumbers&&(u=A(o,s,t));if(E(/^@media/)){e=E(this.mediaFeatures);if(n=E(this.block))return r=new i.Media(n,e),t.dumpLineNumbers&&(r.debugInfo=u),r}},directive:function(){var e,n,r,u,a,f,l,c,h,p;if(s.charAt(o)!=="@")return;if(n=E(this["import"])||E(this.media))return n;g(),e=E(/^@[a-z-]+/);if(!e)return;l=e,e.charAt(1)=="-"&&e.indexOf("-",2)>0&&(l="@"+e.slice(e.indexOf("-",2)+1));switch(l){case"@font-face":c=!0;break;case"@viewport":case"@top-left":case"@top-left-corner":case"@top-center":case"@top-right":case"@top-right-corner":case"@bottom-left":case"@bottom-left-corner":case"@bottom-center":case"@bottom-right":case"@bottom-right-corner":case"@left-top":case"@left-middle":case"@left-bottom":case"@right-top":case"@right-middle":case"@right-bottom":c=!0;break;case"@page":case"@document":case"@supports":case"@keyframes":c=!0,h=!0;break;case"@namespace":p=!0}h&&(e+=" "+(E(/^[^{]+/)||"").trim());if(c){if(r=E(this.block))return new i.Directive(e,r)}else if((n=p?E(this.expression):E(this.entity))&&E(";")){var d=new i.Directive(e,n);return t.dumpLineNumbers&&(d.debugInfo=A(o,s,t)),d}y()},font:function(){var e=[],t=[],n,r,s,o;while(o=E(this.shorthand)||E(this.entity))t.push(o);e.push(new i.Expression(t));if(E(","))while(o=E(this.expression)){e.push(o);if(!E(","))break}return new i.Value(e)},value:function(){var e,t=[],n;while(e=E(this.expression)){t.push(e);if(!E(","))break}if(t.length>0)return new i.Value(t)},important:function(){if(s.charAt(o)==="!")return E(/^! *important/)},sub:function(){var e;if(E("(")&&(e=E(this.expression))&&E(")"))return e},multiplication:function(){var e,t,n,r;if(e=E(this.operand)){while(!N(/^\/[*\/]/)&&(n=E("/")||E("*"))&&(t=E(this.operand)))r=new i.Operation(n,[r||e,t]);return r||e}},addition:function(){var e,t,n,r;if(e=E(this.multiplication)){while((n=E(/^[-+]\s+/)||!w(s.charAt(o-1))&&(E("+")||E("-")))&&(t=E(this.multiplication)))r=new i.Operation(n,[r||e,t]);return r||e}},conditions:function(){var e,t,n=o,r;if(e=E(this.condition)){while(E(",")&&(t=E(this.condition)))r=new i.Condition("or",r||e,t,n);return r||e}},condition:function(){var e,t,n,r,s=o,u=!1;E(/^not/)&&(u=!0),x("(");if(e=E(this.addition)||E(this.entities.keyword)||E(this.entities.quoted))return(r=E(/^(?:>=|=<|[<=>])/))?(t=E(this.addition)||E(this.entities.keyword)||E(this.entities.quoted))?n=new i.Condition(r,e,t,s,u):T("expected expression"):n=new i.Condition("=",e,new i.Keyword("true"),s,u),x(")"),E(/^and/)?new i.Condition("and",n,E(this.condition)):n},operand:function(){var e,t=s.charAt(o+1);s.charAt(o)==="-"&&(t==="@"||t==="(")&&(e=E("-"));var n=E(this.sub)||E(this.entities.dimension)||E(this.entities.color)||E(this.entities.variable)||E(this.entities.call);return e?new i.Operation("*",[new i.Dimension(-1),n]):n},expression:function(){var e,t,n=[],r;while(e=E(this.addition)||E(this.entity))n.push(e);if(n.length>0)return new i.Expression(n)},property:function(){var e;if(e=E(/^(\*?-?[_a-z0-9-]+)\s*:/))return e[1]}}}};if(r.mode==="browser"||r.mode==="rhino")r.Parser.importer=function(e,t,n,r){!/^([a-z-]+:)?\//.test(e)&&t.length>0&&(e=t[0]+e),w({href:e,title:e,type:r.mime,contents:r.contents,files:r.files,rootpath:r.rootpath,entryPath:r.entryPath,relativeUrls:r.relativeUrls},function(e,i,s,o,u,a){e&&typeof r.errback=="function"?r.errback.call(null,a,t,n,r):n.call(null,e,i,a)},!0)};(function(e){function t(t){return e.functions.hsla(t.h,t.s,t.l,t.a)}function n(t,n){return t instanceof e.Dimension&&t.unit=="%"?parseFloat(t.value*n/100):r(t)}function r(t){if(t instanceof e.Dimension)return parseFloat(t.unit=="%"?t.value/100:t.value);if(typeof t=="number")return t;throw{error:"RuntimeError",message:"color functions take numbers as parameters"}}function i(e){return Math.min(1,Math.max(0,e))}e.functions={rgb:function(e,t,n){return this.rgba(e,t,n,1)},rgba:function(t,i,s,o){var u=[t,i,s].map(function(e){return n(e,256)});return o=r(o),new e.Color(u,o)},hsl:function(e,t,n){return this.hsla(e,t,n,1)},hsla:function(e,t,n,i){function u(e){return e=e<0?e+1:e>1?e-1:e,e*6<1?o+(s-o)*e*6:e*2<1?s:e*3<2?o+(s-o)*(2/3-e)*6:o}e=r(e)%360/360,t=r(t),n=r(n),i=r(i);var s=n<=.5?n*(t+1):n+t-n*t,o=n*2-s;return this.rgba(u(e+1/3)*255,u(e)*255,u(e-1/3)*255,i)},hsv:function(e,t,n){return this.hsva(e,t,n,1)},hsva:function(e,t,n,i){e=r(e)%360/360*360,t=r(t),n=r(n),i=r(i);var s,o;s=Math.floor(e/60%6),o=e/60-s;var u=[n,n*(1-t),n*(1-o*t),n*(1-(1-o)*t)],a=[[0,3,1],[2,0,1],[1,0,3],[1,2,0],[3,1,0],[0,1,2]];return this.rgba(u[a[s][0]]*255,u[a[s][1]]*255,u[a[s][2]]*255,i)},hue:function(t){return new e.Dimension(Math.round(t.toHSL().h))},saturation:function(t){return new e.Dimension(Math.round(t.toHSL().s*100),"%")},lightness:function(t){return new e.Dimension(Math.round(t.toHSL().l*100),"%")},red:function(t){return new e.Dimension(t.rgb[0])},green:function(t){return new e.Dimension(t.rgb[1])},blue:function(t){return new e.Dimension(t.rgb[2])},alpha:function(t){return new e.Dimension(t.toHSL().a)},luma:function(t){return new e.Dimension(Math.round((.2126*(t.rgb[0]/255)+.7152*(t.rgb[1]/255)+.0722*(t.rgb[2]/255))*t.alpha*100),"%")},saturate:function(e,n){var r=e.toHSL();return r.s+=n.value/100,r.s=i(r.s),t(r)},desaturate:function(e,n){var r=e.toHSL();return r.s-=n.value/100,r.s=i(r.s),t(r)},lighten:function(e,n){var r=e.toHSL();return r.l+=n.value/100,r.l=i(r.l),t(r)},darken:function(e,n){var r=e.toHSL();return r.l-=n.value/100,r.l=i(r.l),t(r)},fadein:function(e,n){var r=e.toHSL();return r.a+=n.value/100,r.a=i(r.a),t(r)},fadeout:function(e,n){var r=e.toHSL();return r.a-=n.value/100,r.a=i(r.a),t(r)},fade:function(e,n){var r=e.toHSL();return r.a=n.value/100,r.a=i(r.a),t(r)},spin:function(e,n){var r=e.toHSL(),i=(r.h+n.value)%360;return r.h=i<0?360+i:i,t(r)},mix:function(t,n,r){r||(r=new e.Dimension(50));var i=r.value/100,s=i*2-1,o=t.toHSL().a-n.toHSL().a,u=((s*o==-1?s:(s+o)/(1+s*o))+1)/2,a=1-u,f=[t.rgb[0]*u+n.rgb[0]*a,t.rgb[1]*u+n.rgb[1]*a,t.rgb[2]*u+n.rgb[2]*a],l=t.alpha*i+n.alpha*(1-i);return new e.Color(f,l)},greyscale:function(t){return this.desaturate(t,new e.Dimension(100))},contrast:function(e,t,n,r){return e.rgb?(typeof n=="undefined"&&(n=this.rgba(255,255,255,1)),typeof t=="undefined"&&(t=this.rgba(0,0,0,1)),typeof r=="undefined"?r=.43:r=r.value,(.2126*(e.rgb[0]/255)+.7152*(e.rgb[1]/255)+.0722*(e.rgb[2]/255))*e.alpha255?255:e<0?0:e).toString(16),e.length===1?"0"+e:e}).join("")},operate:function(t,n){var r=[];n instanceof e.Color||(n=n.toColor());for(var i=0;i<3;i++)r[i]=e.operate(t,this.rgb[i],n.rgb[i]);return new e.Color(r,this.alpha+n.alpha)},toHSL:function(){var e=this.rgb[0]/255,t=this.rgb[1]/255,n=this.rgb[2]/255,r=this.alpha,i=Math.max(e,t,n),s=Math.min(e,t,n),o,u,a=(i+s)/2,f=i-s;if(i===s)o=u=0;else{u=a>.5?f/(2-i-s):f/(i+s);switch(i){case e:o=(t-n)/f+(t255?255:e<0?0:e).toString(16),e.length===1?"0"+e:e}).join("")},compare:function(e){return e.rgb?e.rgb[0]===this.rgb[0]&&e.rgb[1]===this.rgb[1]&&e.rgb[2]===this.rgb[2]&&e.alpha===this.alpha?0:-1:-1}}}(n("../tree")),function(e){e.Comment=function(e,t){this.value=e,this.silent=!!t},e.Comment.prototype={toCSS:function(e){return e.compress?"":this.value},eval:function(){return this}}}(n("../tree")),function(e){e.Condition=function(e,t,n,r,i){this.op=e.trim(),this.lvalue=t,this.rvalue=n,this.index=r,this.negate=i},e.Condition.prototype.eval=function(e){var t=this.lvalue.eval(e),n=this.rvalue.eval(e),r=this.index,i,i=function(e){switch(e){case"and":return t&&n;case"or":return t||n;default:if(t.compare)i=t.compare(n);else{if(!n.compare)throw{type:"Type",message:"Unable to perform comparison",index:r};i=n.compare(t)}switch(i){case-1:return e==="<"||e==="=<";case 0:return e==="="||e===">="||e==="=<";case 1:return e===">"||e===">="}}}(this.op);return this.negate?!i:i}}(n("../tree")),function(e){e.Dimension=function(e,t){this.value=parseFloat(e),this.unit=t||null},e.Dimension.prototype={eval:function(){return this},toColor:function(){return new e.Color([this.value,this.value,this.value])},toCSS:function(){var e=this.value+this.unit;return e},operate:function(t,n){return new e.Dimension(e.operate(t,this.value,n.value),this.unit||n.unit)},compare:function(t){return t instanceof e.Dimension?t.value>this.value?-1:t.value":e.compress?">":" > ","|":e.compress?"|":" | "}[this.value]}}(n("../tree")),function(e){e.Expression=function(e){this.value=e},e.Expression.prototype={eval:function(t){return this.value.length>1?new e.Expression(this.value.map(function(e){return e.eval(t)})):this.value.length===1?this.value[0].eval(t):this},toCSS:function(e){return this.value.map(function(t){return t.toCSS?t.toCSS(e):""}).join(" ")}}}(n("../tree")),function(e){e.Import=function(t,n,r,i,s,o){var u=this;this.once=i,this.index=s,this._path=t,this.features=r&&new e.Value(r),this.rootpath=o,t instanceof e.Quoted?this.path=/(\.[a-z]*$)|([\?;].*)$/.test(t.value)?t.value:t.value+".less":this.path=t.value.value||t.value,this.css=/css([\?;].*)?$/.test(this.path),this.css||n.push(this.path,function(t,n,r){t&&(t.index=s),r&&u.once&&(u.skip=r),u.root=n||new e.Ruleset([],[])})},e.Import.prototype={toCSS:function(e){var t=this.features?" "+this.features.toCSS(e):"";return this.css?(typeof this._path.value=="string"&&!/^(?:[a-z-]+:|\/)/.test(this._path.value)&&(this._path.value=this.rootpath+this._path.value),"@import "+this._path.toCSS()+t+";\n"):""},eval:function(t){var n,r=this.features&&this.features.eval(t);return this.skip?[]:this.css?this:(n=new e.Ruleset([],this.root.rules.slice(0)),n.evalImports(t),this.features?new e.Media(n.rules,this.features.value):n.rules)}}}(n("../tree")),function(e){e.JavaScript=function(e,t,n){this.escaped=n,this.expression=e,this.index=t},e.JavaScript.prototype={eval:function(t){var n,r=this,i={},s=this.expression.replace(/@\{([\w-]+)\}/g,function(n,i){return e.jsify((new e.Variable("@"+i,r.index)).eval(t))});try{s=new Function("return ("+s+")")}catch(o){throw{message:"JavaScript evaluation error: `"+s+"`",index:this.index}}for(var u in t.frames[0].variables())i[u.slice(1)]={value:t.frames[0].variables()[u].value,toJS:function(){return this.value.eval(t).toCSS()}};try{n=s.call(i)}catch(o){throw{message:"JavaScript evaluation error: '"+o.name+": "+o.message+"'",index:this.index}}return typeof n=="string"?new e.Quoted('"'+n+'"',n,this.escaped,this.index):Array.isArray(n)?new e.Anonymous(n.join(", ")):new e.Anonymous(n)}}}(n("../tree")),function(e){e.Keyword=function(e){this.value=e},e.Keyword.prototype={eval:function(){return this},toCSS:function(){return this.value},compare:function(t){return t instanceof e.Keyword?t.value===this.value?0:1:-1}},e.True=new e.Keyword("true"),e.False=new e.Keyword("false")}(n("../tree")),function(e){e.Media=function(t,n){var r=this.emptySelectors();this.features=new e.Value(n),this.ruleset=new e.Ruleset(r,t),this.ruleset.allowImports=!0},e.Media.prototype={toCSS:function(e,t){var n=this.features.toCSS(t);return this.ruleset.root=e.length===0||e[0].multiMedia,"@media "+n+(t.compress?"{":" {\n ")+this.ruleset.toCSS(e,t).trim().replace(/\n/g,"\n ")+(t.compress?"}":"\n}\n")},eval:function(t){t.mediaBlocks||(t.mediaBlocks=[],t.mediaPath=[]);var n=new e.Media([],[]);return this.debugInfo&&(this.ruleset.debugInfo=this.debugInfo,n.debugInfo=this.debugInfo),n.features=this.features.eval(t),t.mediaPath.push(n),t.mediaBlocks.push(n),t.frames.unshift(this.ruleset),n.ruleset=this.ruleset.eval(t),t.frames.shift(),t.mediaPath.pop(),t.mediaPath.length===0?n.evalTop(t):n.evalNested(t)},variable:function(t){return e.Ruleset.prototype.variable.call(this.ruleset,t)},find:function(){return e.Ruleset.prototype.find.apply(this.ruleset,arguments)},rulesets:function(){return e.Ruleset.prototype.rulesets.apply(this.ruleset)},emptySelectors:function(){var t=new e.Element("","&",0);return[new e.Selector([t])]},evalTop:function(t){var n=this;if(t.mediaBlocks.length>1){var r=this.emptySelectors();n=new e.Ruleset(r,t.mediaBlocks),n.multiMedia=!0}return delete t.mediaBlocks,delete t.mediaPath,n},evalNested:function(t){var n,r,i=t.mediaPath.concat([this]);for(n=0;n0;n--)t.splice(n,0,new e.Anonymous("and"));return new e.Expression(t)})),new e.Ruleset([],[])},permute:function(e){if(e.length===0)return[];if(e.length===1)return e[0];var t=[],n=this.permute(e.slice(1));for(var r=0;r0){c=!0;for(a=0;athis.params.length)return!1;if(this.required>0&&n>this.params.length)return!1}r=Math.min(n,this.arity);for(var s=0;si.selectors[o].elements.length?Array.prototype.push.apply(r,i.find(new e.Selector(t.elements.slice(1)),n)):r.push(i);break}}),this._lookups[o]=r)},toCSS:function(t,n){var r=[],i=[],s=[],o=[],u=[],a,f,l;this.root||this.joinSelectors(u,t,this.selectors);for(var c=0;c0){f=e.debugInfo(n,this),a=u.map(function(e){return e.map(function(e){return e.toCSS(n)}).join("").trim()}).join(n.compress?",":",\n");for(var c=i.length-1;c>=0;c--)s.indexOf(i[c])===-1&&s.unshift(i[c]);i=s,r.push(f+a+(n.compress?"{":" {\n ")+i.join(n.compress?"":"\n ")+(n.compress?"}":"\n}\n"))}return r.push(o),r.join("")+(n.compress?"\n":"")},joinSelectors:function(e,t,n){for(var r=0;r0)for(i=0;i0&&this.mergeElementsOnToSelectors(g,a);for(s=0;s0&&(l[0].elements=l[0].elements.slice(0),l[0].elements.push(new e.Element(f.combinator,"",0))),y.push(l);else for(o=0;o0?(h=l.slice(0),m=h.pop(),d=new e.Selector(m.elements.slice(0)),v=!1):d=new e.Selector([]),c.length>1&&(p=p.concat(c.slice(1))),c.length>0&&(v=!1,d.elements.push(new e.Element(f.combinator,c[0].elements[0].value,0)),d.elements=d.elements.concat(c[0].elements.slice(1))),v||h.push(d),h=h.concat(p),y.push(h)}a=y,g=[]}}g.length>0&&this.mergeElementsOnToSelectors(g,a);for(i=0;i0?i[i.length-1]=new e.Selector(i[i.length-1].elements.concat(t)):i.push(new e.Selector(t))}}}(n("../tree")),function(e){e.Selector=function(e){this.elements=e},e.Selector.prototype.match=function(e){var t=this.elements,n=t.length,r,i,s,o;r=e.elements.slice(e.elements.length&&e.elements[0].value==="&"?1:0),i=r.length,s=Math.min(n,i);if(i===0||n1?"["+e.value.map(function(e){return e.toCSS(!1)}).join(", ")+"]":e.toCSS(!1)}}(n("./tree"));var o=/^(file|chrome(-extension)?|resource|qrc|app):/.test(location.protocol);r.env=r.env||(location.hostname=="127.0.0.1"||location.hostname=="0.0.0.0"||location.hostname=="localhost"||location.port.length>0||o?"development":"production"),r.async=r.async||!1,r.fileAsync=r.fileAsync||!1,r.poll=r.poll||(o?1e3:1500);if(r.functions)for(var u in r.functions)r.tree.functions[u]=r.functions[u];var a=/!dumpLineNumbers:(comments|mediaquery|all)/.exec(location.hash);a&&(r.dumpLineNumbers=a[1]),r.watch=function(){return r.watchMode||(r.env="development",f()),this.watchMode=!0},r.unwatch=function(){return clearInterval(r.watchTimer),this.watchMode=!1},/!watch/.test(location.hash)&&r.watch();var l=null;if(r.env!="development")try{l=typeof e.localStorage=="undefined"?null:e.localStorage}catch(c){}var h=document.getElementsByTagName("link"),p=/^text\/(x-)?less$/;r.sheets=[];for(var d=0;d current) { chunks[j] = chunks[j].slice(i - current); current = i; } } function isWhitespace(c) { // Could change to \s? var code = c.charCodeAt(0); return code === 32 || code === 10 || code === 9; } // // Parse from a token, regexp or string, and move forward if match // function $(tok) { var match, args, length, index, k; // // Non-terminal // if (tok instanceof Function) { return tok.call(parser.parsers); // // Terminal // // Either match a single character in the input, // or match a regexp in the current chunk (chunk[j]). // } else if (typeof(tok) === 'string') { match = input.charAt(i) === tok ? tok : null; length = 1; sync (); } else { sync (); if (match = tok.exec(chunks[j])) { length = match[0].length; } else { return null; } } // The match is confirmed, add the match length to `i`, // and consume any extra white-space characters (' ' || '\n') // which come after that. The reason for this is that LeSS's // grammar is mostly white-space insensitive. // if (match) { skipWhitespace(length); if(typeof(match) === 'string') { return match; } else { return match.length === 1 ? match[0] : match; } } } function skipWhitespace(length) { var oldi = i, oldj = j, endIndex = i + chunks[j].length, mem = i += length; while (i < endIndex) { if (! isWhitespace(input.charAt(i))) { break } i++; } chunks[j] = chunks[j].slice(length + (i - mem)); current = i; if (chunks[j].length === 0 && j < chunks.length - 1) { j++ } return oldi !== i || oldj !== j; } function expect(arg, msg) { var result = $(arg); if (! result) { error(msg || (typeof(arg) === 'string' ? "expected '" + arg + "' got '" + input.charAt(i) + "'" : "unexpected token")); } else { return result; } } function error(msg, type) { var e = new Error(msg); e.index = i; e.type = type || 'Syntax'; throw e; } // Same as $(), but don't change the state of the parser, // just return the match. function peek(tok) { if (typeof(tok) === 'string') { return input.charAt(i) === tok; } else { if (tok.test(chunks[j])) { return true; } else { return false; } } } function getInput(e, env) { if (e.filename && env.currentFileInfo.filename && (e.filename !== env.currentFileInfo.filename)) { return parser.imports.contents[e.filename]; } else { return input; } } function getLocation(index, input) { for (var n = index, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } return { line: typeof(index) === 'number' ? (input.slice(0, index).match(/\n/g) || "").length : null, column: column }; } function getDebugInfo(index, inputStream, env) { var filename = env.currentFileInfo.filename; if(less.mode !== 'browser' && less.mode !== 'rhino') { filename = require('path').resolve(filename); } return { lineNumber: getLocation(index, inputStream).line + 1, fileName: filename }; } function LessError(e, env) { var input = getInput(e, env), loc = getLocation(e.index, input), line = loc.line, col = loc.column, lines = input.split('\n'); this.type = e.type || 'Syntax'; this.message = e.message; this.filename = e.filename || env.currentFileInfo.filename; this.index = e.index; this.line = typeof(line) === 'number' ? line + 1 : null; this.callLine = e.call && (getLocation(e.call, input).line + 1); this.callExtract = lines[getLocation(e.call, input).line]; this.stack = e.stack; this.column = col; this.extract = [ lines[line - 1], lines[line], lines[line + 1] ]; } LessError.prototype = new Error(); LessError.prototype.constructor = LessError; this.env = env = env || {}; // The optimization level dictates the thoroughness of the parser, // the lower the number, the less nodes it will create in the tree. // This could matter for debugging, or if you want to access // the individual nodes in the tree. this.optimization = ('optimization' in this.env) ? this.env.optimization : 1; // // The Parser // return parser = { imports: imports, // // Parse an input string into an abstract syntax tree, // call `callback` when done. // parse: function (str, callback) { var root, start, end, zone, line, lines, buff = [], c, error = null; i = j = current = furthest = 0; input = str.replace(/\r\n/g, '\n'); // Remove potential UTF Byte Order Mark input = input.replace(/^\uFEFF/, ''); // Split the input into chunks. chunks = (function (chunks) { var j = 0, skip = /(?:@\{[\w-]+\}|[^"'`\{\}\/\(\)\\])+/g, comment = /\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g, string = /"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'|`((?:[^`]|\\.)*)`/g, level = 0, match, chunk = chunks[0], inParam; for (var i = 0, c, cc; i < input.length;) { skip.lastIndex = i; if (match = skip.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); } } c = input.charAt(i); comment.lastIndex = string.lastIndex = i; if (match = string.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); continue; } } if (!inParam && c === '/') { cc = input.charAt(i + 1); if (cc === '/' || cc === '*') { if (match = comment.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); continue; } } } } switch (c) { case '{': if (! inParam) { level ++; chunk.push(c); break } case '}': if (! inParam) { level --; chunk.push(c); chunks[++j] = chunk = []; break } case '(': if (! inParam) { inParam = true; chunk.push(c); break } case ')': if ( inParam) { inParam = false; chunk.push(c); break } default: chunk.push(c); } i++; } if (level != 0) { error = new(LessError)({ index: i-1, type: 'Parse', message: (level > 0) ? "missing closing `}`" : "missing opening `{`", filename: env.currentFileInfo.filename }, env); } return chunks.map(function (c) { return c.join('') });; })([[]]); if (error) { return callback(new(LessError)(error, env)); } // Start with the primary rule. // The whole syntax tree is held under a Ruleset node, // with the `root` property set to true, so no `{}` are // output. The callback is called when the input is parsed. try { root = new(tree.Ruleset)([], $(this.parsers.primary)); root.root = true; root.firstRoot = true; } catch (e) { return callback(new(LessError)(e, env)); } root.toCSS = (function (evaluate) { var line, lines, column; return function (options, variables) { options = options || {}; var importError, evalEnv = new tree.evalEnv(options); // // Allows setting variables with a hash, so: // // `{ color: new(tree.Color)('#f01') }` will become: // // new(tree.Rule)('@color', // new(tree.Value)([ // new(tree.Expression)([ // new(tree.Color)('#f01') // ]) // ]) // ) // if (typeof(variables) === 'object' && !Array.isArray(variables)) { variables = Object.keys(variables).map(function (k) { var value = variables[k]; if (! (value instanceof tree.Value)) { if (! (value instanceof tree.Expression)) { value = new(tree.Expression)([value]); } value = new(tree.Value)([value]); } return new(tree.Rule)('@' + k, value, false, 0); }); evalEnv.frames = [new(tree.Ruleset)(null, variables)]; } try { var evaldRoot = evaluate.call(this, evalEnv); new(tree.joinSelectorVisitor)() .run(evaldRoot); new(tree.processExtendsVisitor)() .run(evaldRoot); var css = evaldRoot.toCSS({ compress: Boolean(options.compress), dumpLineNumbers: env.dumpLineNumbers, strictUnits: Boolean(options.strictUnits)}); } catch (e) { throw new(LessError)(e, env); } if (options.yuicompress && less.mode === 'node') { return require('ycssmin').cssmin(css, options.maxLineLen); } else if (options.compress) { return css.replace(/(\s)+/g, "$1"); } else { return css; } }; })(root.eval); // If `i` is smaller than the `input.length - 1`, // it means the parser wasn't able to parse the whole // string, so we've got a parsing error. // // We try to extract a \n delimited string, // showing the line where the parse error occured. // We split it up into two parts (the part which parsed, // and the part which didn't), so we can color them differently. if (i < input.length - 1) { i = furthest; lines = input.split('\n'); line = (input.slice(0, i).match(/\n/g) || "").length + 1; for (var n = i, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } error = { type: "Parse", message: "Unrecognised input", index: i, filename: env.currentFileInfo.filename, line: line, column: column, extract: [ lines[line - 2], lines[line - 1], lines[line] ] }; } var finish = function (e) { e = error || e || parser.imports.error; if (e) { if (!(e instanceof LessError)) { e = new(LessError)(e, env); } callback(e); } else { callback(null, root); } }; if (env.processImports !== false) { new tree.importVisitor(this.imports, finish) .run(root); } else { finish(); } }, // // Here in, the parsing rules/functions // // The basic structure of the syntax tree generated is as follows: // // Ruleset -> Rule -> Value -> Expression -> Entity // // Here's some LESS code: // // .class { // color: #fff; // border: 1px solid #000; // width: @w + 4px; // > .child {...} // } // // And here's what the parse tree might look like: // // Ruleset (Selector '.class', [ // Rule ("color", Value ([Expression [Color #fff]])) // Rule ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]])) // Rule ("width", Value ([Expression [Operation "+" [Variable "@w"][Dimension 4px]]])) // Ruleset (Selector [Element '>', '.child'], [...]) // ]) // // In general, most rules will try to parse a token with the `$()` function, and if the return // value is truly, will return a new node, of the relevant type. Sometimes, we need to check // first, before parsing, that's when we use `peek()`. // parsers: { // // The `primary` rule is the *entry* and *exit* point of the parser. // The rules here can appear at any level of the parse tree. // // The recursive nature of the grammar is an interplay between the `block` // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule, // as represented by this simplified grammar: // // primary → (ruleset | rule)+ // ruleset → selector+ block // block → '{' primary '}' // // Only at one point is the primary rule not called from the // block rule: at the root level. // primary: function () { var node, root = []; while ((node = $(this.extendRule) || $(this.mixin.definition) || $(this.rule) || $(this.ruleset) || $(this.mixin.call) || $(this.comment) || $(this.directive)) || $(/^[\s\n]+/) || $(/^;+/)) { node && root.push(node); } return root; }, // We create a Comment node for CSS comments `/* */`, // but keep the LeSS comments `//` silent, by just skipping // over them. comment: function () { var comment; if (input.charAt(i) !== '/') return; if (input.charAt(i + 1) === '/') { return new(tree.Comment)($(/^\/\/.*/), true); } else if (comment = $(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/)) { return new(tree.Comment)(comment); } }, // // Entities are tokens which can be found inside an Expression // entities: { // // A string, which supports escaping " and ' // // "milky way" 'he\'s the one!' // quoted: function () { var str, j = i, e, index = i; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '"' && input.charAt(j) !== "'") return; e && $('~'); if (str = $(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/)) { return new(tree.Quoted)(str[0], str[1] || str[2], e, index, env.currentFileInfo); } }, // // A catch-all word, such as: // // black border-collapse // keyword: function () { var k; if (k = $(/^[_A-Za-z-][_A-Za-z0-9-]*/)) { if (tree.colors.hasOwnProperty(k)) { // detect named color return new(tree.Color)(tree.colors[k].slice(1)); } else { return new(tree.Keyword)(k); } } }, // // A function call // // rgb(255, 0, 255) // // We also try to catch IE's `alpha()`, but let the `alpha` parser // deal with the details. // // The arguments are parsed with the `entities.arguments` parser. // call: function () { var name, nameLC, args, alpha_ret, index = i; if (! (name = /^([\w-]+|%|progid:[\w\.]+)\(/.exec(chunks[j]))) return; name = name[1]; nameLC = name.toLowerCase(); if (nameLC === 'url') { return null } else { i += name.length } if (nameLC === 'alpha') { alpha_ret = $(this.alpha); if(typeof alpha_ret !== 'undefined') { return alpha_ret; } } $('('); // Parse the '(' and consume whitespace. args = $(this.entities.arguments); if (! $(')')) { return; } if (name) { return new(tree.Call)(name, args, index, env.currentFileInfo); } }, arguments: function () { var args = [], arg; while (arg = $(this.entities.assignment) || $(this.expression)) { args.push(arg); if (! $(',')) { break } } return args; }, literal: function () { return $(this.entities.dimension) || $(this.entities.color) || $(this.entities.quoted) || $(this.entities.unicodeDescriptor); }, // Assignments are argument entities for calls. // They are present in ie filter properties as shown below. // // filter: progid:DXImageTransform.Microsoft.Alpha( *opacity=50* ) // assignment: function () { var key, value; if ((key = $(/^\w+(?=\s?=)/i)) && $('=') && (value = $(this.entity))) { return new(tree.Assignment)(key, value); } }, // // Parse url() tokens // // We use a specific rule for urls, because they don't really behave like // standard function calls. The difference is that the argument doesn't have // to be enclosed within a string, so it can't be parsed as an Expression. // url: function () { var value; if (input.charAt(i) !== 'u' || !$(/^url\(/)) return; value = $(this.entities.quoted) || $(this.entities.variable) || $(/^(?:(?:\\[\(\)'"])|[^\(\)'"])+/) || ""; expect(')'); return new(tree.URL)((value.value != null || value instanceof tree.Variable) ? value : new(tree.Anonymous)(value), env.currentFileInfo); }, // // A Variable entity, such as `@fink`, in // // width: @fink + 2px // // We use a different parser for variable definitions, // see `parsers.variable`. // variable: function () { var name, index = i; if (input.charAt(i) === '@' && (name = $(/^@@?[\w-]+/))) { return new(tree.Variable)(name, index, env.currentFileInfo); } }, // A variable entity useing the protective {} e.g. @{var} variableCurly: function () { var name, curly, index = i; if (input.charAt(i) === '@' && (curly = $(/^@\{([\w-]+)\}/))) { return new(tree.Variable)("@" + curly[1], index, env.currentFileInfo); } }, // // A Hexadecimal color // // #4F3C2F // // `rgb` and `hsl` colors are parsed through the `entities.call` parser. // color: function () { var rgb; if (input.charAt(i) === '#' && (rgb = $(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/))) { return new(tree.Color)(rgb[1]); } }, // // A Dimension, that is, a number and a unit // // 0.5em 95% // dimension: function () { var value, c = input.charCodeAt(i); //Is the first char of the dimension 0-9, '.', '+' or '-' if ((c > 57 || c < 43) || c === 47 || c == 44) return; if (value = $(/^([+-]?\d*\.?\d+)(%|[a-z]+)?/)) { return new(tree.Dimension)(value[1], value[2]); } }, // // A unicode descriptor, as is used in unicode-range // // U+0?? or U+00A1-00A9 // unicodeDescriptor: function () { var ud; if (ud = $(/^U\+[0-9a-fA-F?]+(\-[0-9a-fA-F?]+)?/)) { return new(tree.UnicodeDescriptor)(ud[0]); } }, // // JavaScript code to be evaluated // // `window.location.href` // javascript: function () { var str, j = i, e; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '`') { return } e && $('~'); if (str = $(/^`([^`]*)`/)) { return new(tree.JavaScript)(str[1], i, e); } } }, // // The variable part of a variable definition. Used in the `rule` parser // // @fink: // variable: function () { var name; if (input.charAt(i) === '@' && (name = $(/^(@[\w-]+)\s*:/))) { return name[1] } }, // // extend syntax - used to extend selectors // extend: function(isRule) { var elements, e, index = i, option, extendList = []; if (!$(isRule ? /^&:extend\(/ : /^:extend\(/)) { return; } do { option = null; elements = []; while (true) { option = $(/^(all)(?=\s*(\)|,))/); if (option) { break; } e = $(this.element); if (!e) { break; } elements.push(e); } option = option && option[1]; extendList.push(new(tree.Extend)(new(tree.Selector)(elements), option, index)); } while($(",")) expect(/^\)/); if (isRule) { expect(/^;/); } return extendList; }, // // extendRule - used in a rule to extend all the parent selectors // extendRule: function() { return this.extend(true); }, // // Mixins // mixin: { // // A Mixin call, with an optional argument list // // #mixins > .square(#fff); // .rounded(4px, black); // .button; // // The `while` loop is there because mixins can be // namespaced, but we only support the child and descendant // selector for now. // call: function () { var elements = [], e, c, args, delim, arg, index = i, s = input.charAt(i), important = false; if (s !== '.' && s !== '#') { return } save(); // stop us absorbing part of an invalid selector while (e = $(/^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/)) { elements.push(new(tree.Element)(c, e, i)); c = $('>'); } if ($('(')) { args = this.mixin.args.call(this, true).args; expect(')'); } args = args || []; if ($(this.important)) { important = true; } if (elements.length > 0 && ($(';') || peek('}'))) { return new(tree.mixin.Call)(elements, args, index, env.currentFileInfo, important); } restore(); }, args: function (isCall) { var expressions = [], argsSemiColon = [], isSemiColonSeperated, argsComma = [], expressionContainsNamed, name, nameLoop, value, arg, returner = {args:null, variadic: false}; while (true) { if (isCall) { arg = $(this.expression); } else { $(this.comment); if (input.charAt(i) === '.' && $(/^\.{3}/)) { returner.variadic = true; if ($(";") && !isSemiColonSeperated) { isSemiColonSeperated = true; } (isSemiColonSeperated ? argsSemiColon : argsComma) .push({ variadic: true }); break; } arg = $(this.entities.variable) || $(this.entities.literal) || $(this.entities.keyword); } if (!arg) { break; } nameLoop = null; if (arg.throwAwayComments) { arg.throwAwayComments(); } value = arg; var val = null; if (isCall) { // Variable if (arg.value.length == 1) { var val = arg.value[0]; } } else { val = arg; } if (val && val instanceof tree.Variable) { if ($(':')) { if (expressions.length > 0) { if (isSemiColonSeperated) { error("Cannot mix ; and , as delimiter types"); } expressionContainsNamed = true; } value = expect(this.expression); nameLoop = (name = val.name); } else if (!isCall && $(/^\.{3}/)) { returner.variadic = true; if ($(";") && !isSemiColonSeperated) { isSemiColonSeperated = true; } (isSemiColonSeperated ? argsSemiColon : argsComma) .push({ name: arg.name, variadic: true }); break; } else if (!isCall) { name = nameLoop = val.name; value = null; } } if (value) { expressions.push(value); } argsComma.push({ name:nameLoop, value:value }); if ($(',')) { continue; } if ($(';') || isSemiColonSeperated) { if (expressionContainsNamed) { error("Cannot mix ; and , as delimiter types"); } isSemiColonSeperated = true; if (expressions.length > 1) { value = new (tree.Value)(expressions); } argsSemiColon.push({ name:name, value:value }); name = null; expressions = []; expressionContainsNamed = false; } } returner.args = isSemiColonSeperated ? argsSemiColon : argsComma; return returner; }, // // A Mixin definition, with a list of parameters // // .rounded (@radius: 2px, @color) { // ... // } // // Until we have a finer grained state-machine, we have to // do a look-ahead, to make sure we don't have a mixin call. // See the `rule` function for more information. // // We start by matching `.rounded (`, and then proceed on to // the argument list, which has optional default values. // We store the parameters in `params`, with a `value` key, // if there is a value, such as in the case of `@radius`. // // Once we've got our params list, and a closing `)`, we parse // the `{...}` block. // definition: function () { var name, params = [], match, ruleset, param, value, cond, variadic = false; if ((input.charAt(i) !== '.' && input.charAt(i) !== '#') || peek(/^[^{]*\}/)) return; save(); if (match = $(/^([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/)) { name = match[1]; var argInfo = this.mixin.args.call(this, false); params = argInfo.args; variadic = argInfo.variadic; // .mixincall("@{a}"); // looks a bit like a mixin definition.. so we have to be nice and restore if (!$(')')) { furthest = i; restore(); } $(this.comment); if ($(/^when/)) { // Guard cond = expect(this.conditions, 'expected condition'); } ruleset = $(this.block); if (ruleset) { return new(tree.mixin.Definition)(name, params, ruleset, cond, variadic); } else { restore(); } } } }, // // Entities are the smallest recognized token, // and can be found inside a rule's value. // entity: function () { return $(this.entities.literal) || $(this.entities.variable) || $(this.entities.url) || $(this.entities.call) || $(this.entities.keyword) ||$(this.entities.javascript) || $(this.comment); }, // // A Rule terminator. Note that we use `peek()` to check for '}', // because the `block` rule will be expecting it, but we still need to make sure // it's there, if ';' was ommitted. // end: function () { return $(';') || peek('}'); }, // // IE's alpha function // // alpha(opacity=88) // alpha: function () { var value; if (! $(/^\(opacity=/i)) return; if (value = $(/^\d+/) || $(this.entities.variable)) { expect(')'); return new(tree.Alpha)(value); } }, // // A Selector Element // // div // + h1 // #socks // input[type="text"] // // Elements are the building blocks for Selectors, // they are made out of a `Combinator` (see combinator rule), // and an element name, such as a tag a class, or `*`. // element: function () { var e, t, c, v; c = $(this.combinator); e = $(/^(?:\d+\.\d+|\d+)%/) || $(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/) || $('*') || $('&') || $(this.attribute) || $(/^\([^()@]+\)/) || $(/^[\.#](?=@)/) || $(this.entities.variableCurly); if (! e) { if ($('(')) { if ((v = ($(this.selector))) && $(')')) { e = new(tree.Paren)(v); } } } if (e) { return new(tree.Element)(c, e, i) } }, // // Combinators combine elements together, in a Selector. // // Because our parser isn't white-space sensitive, special care // has to be taken, when parsing the descendant combinator, ` `, // as it's an empty space. We have to check the previous character // in the input, to see if it's a ` ` character. More info on how // we deal with this in *combinator.js*. // combinator: function () { var match, c = input.charAt(i); if (c === '>' || c === '+' || c === '~' || c === '|') { i++; while (input.charAt(i).match(/\s/)) { i++ } return new(tree.Combinator)(c); } else if (input.charAt(i - 1).match(/\s/)) { return new(tree.Combinator)(" "); } else { return new(tree.Combinator)(null); } }, // // A CSS Selector // // .class > div + h1 // li a:hover // // Selectors are made out of one or more Elements, see above. // selector: function () { var sel, e, elements = [], c, match, extend, extendList = []; while ((extend = $(this.extend)) || (e = $(this.element))) { if (extend) { extendList.push.apply(extendList, extend); } else { if (extendList.length) { error("Extend can only be used at the end of selector"); } c = input.charAt(i); elements.push(e) e = null; } if (c === '{' || c === '}' || c === ';' || c === ',' || c === ')') { break } } if (elements.length > 0) { return new(tree.Selector)(elements, extendList); } if (extendList.length) { error("Extend must be used to extend a selector, it cannot be used on its own"); } }, attribute: function () { var attr = '', key, val, op; if (! $('[')) return; if (!(key = $(this.entities.variableCurly))) { key = expect(/^(?:[_A-Za-z0-9-\*]*\|)?(?:[_A-Za-z0-9-]|\\.)+/); } if ((op = $(/^[|~*$^]?=/))) { val = $(this.entities.quoted) || $(/^[\w-]+/) || $(this.entities.variableCurly); } expect(']'); return new(tree.Attribute)(key, op, val); }, // // The `block` rule is used by `ruleset` and `mixin.definition`. // It's a wrapper around the `primary` rule, with added `{}`. // block: function () { var content; if ($('{') && (content = $(this.primary)) && $('}')) { return content; } }, // // div, .class, body > p {...} // ruleset: function () { var selectors = [], s, rules, match, debugInfo; save(); if (env.dumpLineNumbers) debugInfo = getDebugInfo(i, input, env); while (s = $(this.selector)) { selectors.push(s); $(this.comment); if (! $(',')) { break } $(this.comment); } if (selectors.length > 0 && (rules = $(this.block))) { var ruleset = new(tree.Ruleset)(selectors, rules, env.strictImports); if (env.dumpLineNumbers) ruleset.debugInfo = debugInfo; return ruleset; } else { // Backtrack furthest = i; restore(); } }, rule: function (tryAnonymous) { var name, value, c = input.charAt(i), important, match; save(); if (c === '.' || c === '#' || c === '&') { return } if (name = $(this.variable) || $(this.property)) { // prefer to try to parse first if its a variable or we are compressing // but always fallback on the other one value = !tryAnonymous && (env.compress || (name.charAt(0) === '@')) ? ($(this.value) || $(this.anonymousValue)) : ($(this.anonymousValue) || $(this.value)); important = $(this.important); if (value && $(this.end)) { return new(tree.Rule)(name, value, important, memo, env.currentFileInfo); } else { furthest = i; restore(); if (value && !tryAnonymous) { return this.rule(true); } } } }, anonymousValue: function () { if (match = /^([^@+\/'"*`(;{}-]*);/.exec(chunks[j])) { i += match[0].length - 1; return new(tree.Anonymous)(match[1]); } }, // // An @import directive // // @import "lib"; // // Depending on our environemnt, importing is done differently: // In the browser, it's an XHR request, in Node, it would be a // file-system operation. The function used for importing is // stored in `import`, which we pass to the Import constructor. // "import": function () { var path, features, index = i; save(); var dir = $(/^@import?\s+/); var options = (dir ? $(this.importOptions) : null) || {}; if (dir && (path = $(this.entities.quoted) || $(this.entities.url))) { features = $(this.mediaFeatures); if ($(';')) { features = features && new(tree.Value)(features); return new(tree.Import)(path, features, options, index, env.currentFileInfo); } } restore(); }, importOptions: function() { var o, options = {}, optionName, value; // list of options, surrounded by parens if (! $('(')) { return null; } do { if (o = $(this.importOption)) { optionName = o; value = true; switch(optionName) { case "css": optionName = "less"; value = false; break; case "once": optionName = "multiple"; value = false; break; } options[optionName] = value; if (! $(',')) { break } } } while (o); expect(')'); return options; }, importOption: function() { var opt = $(/^(less|css|multiple|once)/); if (opt) { return opt[1]; } }, mediaFeature: function () { var e, p, nodes = []; do { if (e = $(this.entities.keyword)) { nodes.push(e); } else if ($('(')) { p = $(this.property); e = $(this.value); if ($(')')) { if (p && e) { nodes.push(new(tree.Paren)(new(tree.Rule)(p, e, null, i, env.currentFileInfo, true))); } else if (e) { nodes.push(new(tree.Paren)(e)); } else { return null; } } else { return null } } } while (e); if (nodes.length > 0) { return new(tree.Expression)(nodes); } }, mediaFeatures: function () { var e, features = []; do { if (e = $(this.mediaFeature)) { features.push(e); if (! $(',')) { break } } else if (e = $(this.entities.variable)) { features.push(e); if (! $(',')) { break } } } while (e); return features.length > 0 ? features : null; }, media: function () { var features, rules, media, debugInfo; if (env.dumpLineNumbers) debugInfo = getDebugInfo(i, input, env); if ($(/^@media/)) { features = $(this.mediaFeatures); if (rules = $(this.block)) { media = new(tree.Media)(rules, features); if(env.dumpLineNumbers) media.debugInfo = debugInfo; return media; } } }, // // A CSS Directive // // @charset "utf-8"; // directive: function () { var name, value, rules, identifier, e, nodes, nonVendorSpecificName, hasBlock, hasIdentifier, hasExpression; if (input.charAt(i) !== '@') return; if (value = $(this['import']) || $(this.media)) { return value; } save(); name = $(/^@[a-z-]+/); if (!name) return; nonVendorSpecificName = name; if (name.charAt(1) == '-' && name.indexOf('-', 2) > 0) { nonVendorSpecificName = "@" + name.slice(name.indexOf('-', 2) + 1); } switch(nonVendorSpecificName) { case "@font-face": hasBlock = true; break; case "@viewport": case "@top-left": case "@top-left-corner": case "@top-center": case "@top-right": case "@top-right-corner": case "@bottom-left": case "@bottom-left-corner": case "@bottom-center": case "@bottom-right": case "@bottom-right-corner": case "@left-top": case "@left-middle": case "@left-bottom": case "@right-top": case "@right-middle": case "@right-bottom": hasBlock = true; break; case "@page": case "@document": case "@supports": case "@keyframes": hasBlock = true; hasIdentifier = true; break; case "@namespace": hasExpression = true; break; } if (hasIdentifier) { name += " " + ($(/^[^{]+/) || '').trim(); } if (hasBlock) { if (rules = $(this.block)) { return new(tree.Directive)(name, rules); } } else { if ((value = hasExpression ? $(this.expression) : $(this.entity)) && $(';')) { var directive = new(tree.Directive)(name, value); if (env.dumpLineNumbers) { directive.debugInfo = getDebugInfo(i, input, env); } return directive; } } restore(); }, // // A Value is a comma-delimited list of Expressions // // font-family: Baskerville, Georgia, serif; // // In a Rule, a Value represents everything after the `:`, // and before the `;`. // value: function () { var e, expressions = [], important; while (e = $(this.expression)) { expressions.push(e); if (! $(',')) { break } } if (expressions.length > 0) { return new(tree.Value)(expressions); } }, important: function () { if (input.charAt(i) === '!') { return $(/^! *important/); } }, sub: function () { var a, e; if ($('(')) { if (a = $(this.addition)) { e = new(tree.Expression)([a]); expect(')'); e.parens = true; return e; } } }, multiplication: function () { var m, a, op, operation, isSpaced, expression = []; if (m = $(this.operand)) { isSpaced = isWhitespace(input.charAt(i - 1)); while (!peek(/^\/[*\/]/) && (op = ($('/') || $('*')))) { if (a = $(this.operand)) { m.parensInOp = true; a.parensInOp = true; operation = new(tree.Operation)(op, [operation || m, a], isSpaced); isSpaced = isWhitespace(input.charAt(i - 1)); } else { break; } } return operation || m; } }, addition: function () { var m, a, op, operation, isSpaced; if (m = $(this.multiplication)) { isSpaced = isWhitespace(input.charAt(i - 1)); while ((op = $(/^[-+]\s+/) || (!isSpaced && ($('+') || $('-')))) && (a = $(this.multiplication))) { m.parensInOp = true; a.parensInOp = true; operation = new(tree.Operation)(op, [operation || m, a], isSpaced); isSpaced = isWhitespace(input.charAt(i - 1)); } return operation || m; } }, conditions: function () { var a, b, index = i, condition; if (a = $(this.condition)) { while ($(',') && (b = $(this.condition))) { condition = new(tree.Condition)('or', condition || a, b, index); } return condition || a; } }, condition: function () { var a, b, c, op, index = i, negate = false; if ($(/^not/)) { negate = true } expect('('); if (a = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) { if (op = $(/^(?:>=|=<|[<=>])/)) { if (b = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) { c = new(tree.Condition)(op, a, b, index, negate); } else { error('expected expression'); } } else { c = new(tree.Condition)('=', a, new(tree.Keyword)('true'), index, negate); } expect(')'); return $(/^and/) ? new(tree.Condition)('and', c, $(this.condition)) : c; } }, // // An operand is anything that can be part of an operation, // such as a Color, or a Variable // operand: function () { var negate, p = input.charAt(i + 1); if (input.charAt(i) === '-' && (p === '@' || p === '(')) { negate = $('-') } var o = $(this.sub) || $(this.entities.dimension) || $(this.entities.color) || $(this.entities.variable) || $(this.entities.call); if (negate) { o.parensInOp = true; o = new(tree.Negative)(o); } return o; }, // // Expressions either represent mathematical operations, // or white-space delimited Entities. // // 1px solid black // @var * 2 // expression: function () { var e, delim, entities = [], d; while (e = $(this.addition) || $(this.entity)) { entities.push(e); // operations do not allow keyword "/" dimension (e.g. small/20px) so we support that here if (!peek(/^\/[\/*]/) && (delim = $('/'))) { entities.push(new(tree.Anonymous)(delim)); } } if (entities.length > 0) { return new(tree.Expression)(entities); } }, property: function () { var name; if (name = $(/^(\*?-?[_a-z0-9-]+)\s*:/)) { return name[1]; } } } }; }; if (less.mode === 'browser' || less.mode === 'rhino') { // // Used by `@import` directives // less.Parser.importer = function (path, currentFileInfo, callback, env) { if (!/^([a-z-]+:)?\//.test(path) && currentFileInfo.currentDirectory) { path = currentFileInfo.currentDirectory + path; } var sheetEnv = env.toSheet(path); sheetEnv.processImports = false; sheetEnv.currentFileInfo = currentFileInfo; // We pass `true` as 3rd argument, to force the reload of the import. // This is so we can get the syntax tree as opposed to just the CSS output, // as we need this to evaluate the current stylesheet. loadStyleSheet(sheetEnv, function (e, root, data, sheet, _, path) { callback.call(null, e, root, path); }, true); }; } (function (tree) { tree.functions = { rgb: function (r, g, b) { return this.rgba(r, g, b, 1.0); }, rgba: function (r, g, b, a) { var rgb = [r, g, b].map(function (c) { return scaled(c, 256); }); a = number(a); return new(tree.Color)(rgb, a); }, hsl: function (h, s, l) { return this.hsla(h, s, l, 1.0); }, hsla: function (h, s, l, a) { h = (number(h) % 360) / 360; s = clamp(number(s)); l = clamp(number(l)); a = clamp(number(a)); var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s; var m1 = l * 2 - m2; return this.rgba(hue(h + 1/3) * 255, hue(h) * 255, hue(h - 1/3) * 255, a); function hue(h) { h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h); if (h * 6 < 1) return m1 + (m2 - m1) * h * 6; else if (h * 2 < 1) return m2; else if (h * 3 < 2) return m1 + (m2 - m1) * (2/3 - h) * 6; else return m1; } }, hsv: function(h, s, v) { return this.hsva(h, s, v, 1.0); }, hsva: function(h, s, v, a) { h = ((number(h) % 360) / 360) * 360; s = number(s); v = number(v); a = number(a); var i, f; i = Math.floor((h / 60) % 6); f = (h / 60) - i; var vs = [v, v * (1 - s), v * (1 - f * s), v * (1 - (1 - f) * s)]; var perm = [[0, 3, 1], [2, 0, 1], [1, 0, 3], [1, 2, 0], [3, 1, 0], [0, 1, 2]]; return this.rgba(vs[perm[i][0]] * 255, vs[perm[i][1]] * 255, vs[perm[i][2]] * 255, a); }, hue: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().h)); }, saturation: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().s * 100), '%'); }, lightness: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().l * 100), '%'); }, hsvhue: function(color) { return new(tree.Dimension)(Math.round(color.toHSV().h)); }, hsvsaturation: function (color) { return new(tree.Dimension)(Math.round(color.toHSV().s * 100), '%'); }, hsvvalue: function (color) { return new(tree.Dimension)(Math.round(color.toHSV().v * 100), '%'); }, red: function (color) { return new(tree.Dimension)(color.rgb[0]); }, green: function (color) { return new(tree.Dimension)(color.rgb[1]); }, blue: function (color) { return new(tree.Dimension)(color.rgb[2]); }, alpha: function (color) { return new(tree.Dimension)(color.toHSL().a); }, luma: function (color) { return new(tree.Dimension)(Math.round(color.luma() * color.alpha * 100), '%'); }, saturate: function (color, amount) { var hsl = color.toHSL(); hsl.s += amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, desaturate: function (color, amount) { var hsl = color.toHSL(); hsl.s -= amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, lighten: function (color, amount) { var hsl = color.toHSL(); hsl.l += amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, darken: function (color, amount) { var hsl = color.toHSL(); hsl.l -= amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, fadein: function (color, amount) { var hsl = color.toHSL(); hsl.a += amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, fadeout: function (color, amount) { var hsl = color.toHSL(); hsl.a -= amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, fade: function (color, amount) { var hsl = color.toHSL(); hsl.a = amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, spin: function (color, amount) { var hsl = color.toHSL(); var hue = (hsl.h + amount.value) % 360; hsl.h = hue < 0 ? 360 + hue : hue; return hsla(hsl); }, // // Copyright (c) 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein // http://sass-lang.com // mix: function (color1, color2, weight) { if (!weight) { weight = new(tree.Dimension)(50); } var p = weight.value / 100.0; var w = p * 2 - 1; var a = color1.toHSL().a - color2.toHSL().a; var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0; var w2 = 1 - w1; var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2, color1.rgb[1] * w1 + color2.rgb[1] * w2, color1.rgb[2] * w1 + color2.rgb[2] * w2]; var alpha = color1.alpha * p + color2.alpha * (1 - p); return new(tree.Color)(rgb, alpha); }, greyscale: function (color) { return this.desaturate(color, new(tree.Dimension)(100)); }, contrast: function (color, dark, light, threshold) { // filter: contrast(3.2); // should be kept as is, so check for color if (!color.rgb) { return null; } if (typeof light === 'undefined') { light = this.rgba(255, 255, 255, 1.0); } if (typeof dark === 'undefined') { dark = this.rgba(0, 0, 0, 1.0); } //Figure out which is actually light and dark! if (dark.luma() > light.luma()) { var t = light; light = dark; dark = t; } if (typeof threshold === 'undefined') { threshold = 0.43; } else { threshold = number(threshold); } if ((color.luma() * color.alpha) < threshold) { return light; } else { return dark; } }, e: function (str) { return new(tree.Anonymous)(str instanceof tree.JavaScript ? str.evaluated : str); }, escape: function (str) { return new(tree.Anonymous)(encodeURI(str.value).replace(/=/g, "%3D").replace(/:/g, "%3A").replace(/#/g, "%23").replace(/;/g, "%3B").replace(/\(/g, "%28").replace(/\)/g, "%29")); }, '%': function (quoted /* arg, arg, ...*/) { var args = Array.prototype.slice.call(arguments, 1), str = quoted.value; for (var i = 0; i < args.length; i++) { str = str.replace(/%[sda]/i, function(token) { var value = token.match(/s/i) ? args[i].value : args[i].toCSS(); return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value; }); } str = str.replace(/%%/g, '%'); return new(tree.Quoted)('"' + str + '"', str); }, unit: function (val, unit) { return new(tree.Dimension)(val.value, unit ? unit.toCSS() : ""); }, convert: function (val, unit) { return val.convertTo(unit.value); }, round: function (n, f) { var fraction = typeof(f) === "undefined" ? 0 : f.value; return this._math(function(num) { return num.toFixed(fraction); }, null, n); }, pi: function () { return new(tree.Dimension)(Math.PI); }, mod: function(a, b) { return new(tree.Dimension)(a.value % b.value, a.unit); }, pow: function(x, y) { if (typeof x === "number" && typeof y === "number") { x = new(tree.Dimension)(x); y = new(tree.Dimension)(y); } else if (!(x instanceof tree.Dimension) || !(y instanceof tree.Dimension)) { throw { type: "Argument", message: "arguments must be numbers" }; } return new(tree.Dimension)(Math.pow(x.value, y.value), x.unit); }, _math: function (fn, unit, n) { if (n instanceof tree.Dimension) { return new(tree.Dimension)(fn(parseFloat(n.value)), unit == null ? n.unit : unit); } else if (typeof(n) === 'number') { return fn(n); } else { throw { type: "Argument", message: "argument must be a number" }; } }, argb: function (color) { return new(tree.Anonymous)(color.toARGB()); }, percentage: function (n) { return new(tree.Dimension)(n.value * 100, '%'); }, color: function (n) { if (n instanceof tree.Quoted) { return new(tree.Color)(n.value.slice(1)); } else { throw { type: "Argument", message: "argument must be a string" }; } }, iscolor: function (n) { return this._isa(n, tree.Color); }, isnumber: function (n) { return this._isa(n, tree.Dimension); }, isstring: function (n) { return this._isa(n, tree.Quoted); }, iskeyword: function (n) { return this._isa(n, tree.Keyword); }, isurl: function (n) { return this._isa(n, tree.URL); }, ispixel: function (n) { return this.isunit(n, 'px'); }, ispercentage: function (n) { return this.isunit(n, '%'); }, isem: function (n) { return this.isunit(n, 'em'); }, isunit: function (n, unit) { return (n instanceof tree.Dimension) && n.unit.is(unit.value || unit) ? tree.True : tree.False; }, _isa: function (n, Type) { return (n instanceof Type) ? tree.True : tree.False; }, /* Blending modes */ multiply: function(color1, color2) { var r = color1.rgb[0] * color2.rgb[0] / 255; var g = color1.rgb[1] * color2.rgb[1] / 255; var b = color1.rgb[2] * color2.rgb[2] / 255; return this.rgb(r, g, b); }, screen: function(color1, color2) { var r = 255 - (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255; var g = 255 - (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255; var b = 255 - (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255; return this.rgb(r, g, b); }, overlay: function(color1, color2) { var r = color1.rgb[0] < 128 ? 2 * color1.rgb[0] * color2.rgb[0] / 255 : 255 - 2 * (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255; var g = color1.rgb[1] < 128 ? 2 * color1.rgb[1] * color2.rgb[1] / 255 : 255 - 2 * (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255; var b = color1.rgb[2] < 128 ? 2 * color1.rgb[2] * color2.rgb[2] / 255 : 255 - 2 * (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255; return this.rgb(r, g, b); }, softlight: function(color1, color2) { var t = color2.rgb[0] * color1.rgb[0] / 255; var r = t + color1.rgb[0] * (255 - (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255 - t) / 255; t = color2.rgb[1] * color1.rgb[1] / 255; var g = t + color1.rgb[1] * (255 - (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255 - t) / 255; t = color2.rgb[2] * color1.rgb[2] / 255; var b = t + color1.rgb[2] * (255 - (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255 - t) / 255; return this.rgb(r, g, b); }, hardlight: function(color1, color2) { var r = color2.rgb[0] < 128 ? 2 * color2.rgb[0] * color1.rgb[0] / 255 : 255 - 2 * (255 - color2.rgb[0]) * (255 - color1.rgb[0]) / 255; var g = color2.rgb[1] < 128 ? 2 * color2.rgb[1] * color1.rgb[1] / 255 : 255 - 2 * (255 - color2.rgb[1]) * (255 - color1.rgb[1]) / 255; var b = color2.rgb[2] < 128 ? 2 * color2.rgb[2] * color1.rgb[2] / 255 : 255 - 2 * (255 - color2.rgb[2]) * (255 - color1.rgb[2]) / 255; return this.rgb(r, g, b); }, difference: function(color1, color2) { var r = Math.abs(color1.rgb[0] - color2.rgb[0]); var g = Math.abs(color1.rgb[1] - color2.rgb[1]); var b = Math.abs(color1.rgb[2] - color2.rgb[2]); return this.rgb(r, g, b); }, exclusion: function(color1, color2) { var r = color1.rgb[0] + color2.rgb[0] * (255 - color1.rgb[0] - color1.rgb[0]) / 255; var g = color1.rgb[1] + color2.rgb[1] * (255 - color1.rgb[1] - color1.rgb[1]) / 255; var b = color1.rgb[2] + color2.rgb[2] * (255 - color1.rgb[2] - color1.rgb[2]) / 255; return this.rgb(r, g, b); }, average: function(color1, color2) { var r = (color1.rgb[0] + color2.rgb[0]) / 2; var g = (color1.rgb[1] + color2.rgb[1]) / 2; var b = (color1.rgb[2] + color2.rgb[2]) / 2; return this.rgb(r, g, b); }, negation: function(color1, color2) { var r = 255 - Math.abs(255 - color2.rgb[0] - color1.rgb[0]); var g = 255 - Math.abs(255 - color2.rgb[1] - color1.rgb[1]); var b = 255 - Math.abs(255 - color2.rgb[2] - color1.rgb[2]); return this.rgb(r, g, b); }, tint: function(color, amount) { return this.mix(this.rgb(255,255,255), color, amount); }, shade: function(color, amount) { return this.mix(this.rgb(0, 0, 0), color, amount); }, extract: function(values, index) { index = index.value - 1; // (1-based index) return values.value[index]; }, "data-uri": function(mimetypeNode, filePathNode) { if (typeof window !== 'undefined') { return new tree.URL(filePathNode || mimetypeNode, this.currentFileInfo).eval(this.env); } var mimetype = mimetypeNode.value; var filePath = (filePathNode && filePathNode.value); var fs = require("fs"), path = require("path"), useBase64 = false; if (arguments.length < 2) { filePath = mimetype; } if (this.env.isPathRelative(filePath)) { if (this.currentFileInfo.relativeUrls) { filePath = path.join(this.currentFileInfo.currentDirectory, filePath); } else { filePath = path.join(this.currentFileInfo.entryPath, filePath); } } // detect the mimetype if not given if (arguments.length < 2) { var mime; try { mime = require('mime'); } catch (ex) { mime = tree._mime; } mimetype = mime.lookup(filePath); // use base 64 unless it's an ASCII or UTF-8 format var charset = mime.charsets.lookup(mimetype); useBase64 = ['US-ASCII', 'UTF-8'].indexOf(charset) < 0; if (useBase64) mimetype += ';base64'; } else { useBase64 = /;base64$/.test(mimetype) } var buf = fs.readFileSync(filePath); // IE8 cannot handle a data-uri larger than 32KB. If this is exceeded // and the --ieCompat flag is enabled, return a normal url() instead. var DATA_URI_MAX_KB = 32, fileSizeInKB = parseInt((buf.length / 1024), 10); if (fileSizeInKB >= DATA_URI_MAX_KB) { if (this.env.ieCompat !== false) { if (!this.env.silent) { console.warn("Skipped data-uri embedding of %s because its size (%dKB) exceeds IE8-safe %dKB!", filePath, fileSizeInKB, DATA_URI_MAX_KB); } return new tree.URL(filePathNode || mimetypeNode, this.currentFileInfo).eval(this.env); } else if (!this.env.silent) { // if explicitly disabled (via --no-ie-compat on CLI, or env.ieCompat === false), merely warn console.warn("WARNING: Embedding %s (%dKB) exceeds IE8's data-uri size limit of %dKB!", filePath, fileSizeInKB, DATA_URI_MAX_KB); } } buf = useBase64 ? buf.toString('base64') : encodeURIComponent(buf); var uri = "'data:" + mimetype + ',' + buf + "'"; return new(tree.URL)(new(tree.Anonymous)(uri)); } }; // these static methods are used as a fallback when the optional 'mime' dependency is missing tree._mime = { // this map is intentionally incomplete // if you want more, install 'mime' dep _types: { '.htm' : 'text/html', '.html': 'text/html', '.gif' : 'image/gif', '.jpg' : 'image/jpeg', '.jpeg': 'image/jpeg', '.png' : 'image/png' }, lookup: function (filepath) { var ext = require('path').extname(filepath), type = tree._mime._types[ext]; if (type === undefined) { throw new Error('Optional dependency "mime" is required for ' + ext); } return type; }, charsets: { lookup: function (type) { // assumes all text types are UTF-8 return type && (/^text\//).test(type) ? 'UTF-8' : ''; } } }; var mathFunctions = [{name:"ceil"}, {name:"floor"}, {name: "sqrt"}, {name:"abs"}, {name:"tan", unit: ""}, {name:"sin", unit: ""}, {name:"cos", unit: ""}, {name:"atan", unit: "rad"}, {name:"asin", unit: "rad"}, {name:"acos", unit: "rad"}], createMathFunction = function(name, unit) { return function(n) { if (unit != null) { n = n.unify(); } return this._math(Math[name], unit, n); }; }; for(var i = 0; i < mathFunctions.length; i++) { tree.functions[mathFunctions[i].name] = createMathFunction(mathFunctions[i].name, mathFunctions[i].unit); } function hsla(color) { return tree.functions.hsla(color.h, color.s, color.l, color.a); } function scaled(n, size) { if (n instanceof tree.Dimension && n.unit.is('%')) { return parseFloat(n.value * size / 100); } else { return number(n); } } function number(n) { if (n instanceof tree.Dimension) { return parseFloat(n.unit.is('%') ? n.value / 100 : n.value); } else if (typeof(n) === 'number') { return n; } else { throw { error: "RuntimeError", message: "color functions take numbers as parameters" }; } } function clamp(val) { return Math.min(1, Math.max(0, val)); } tree.functionCall = function(env, currentFileInfo) { this.env = env; this.currentFileInfo = currentFileInfo; }; tree.functionCall.prototype = tree.functions; })(require('./tree')); (function (tree) { tree.colors = { 'aliceblue':'#f0f8ff', 'antiquewhite':'#faebd7', 'aqua':'#00ffff', 'aquamarine':'#7fffd4', 'azure':'#f0ffff', 'beige':'#f5f5dc', 'bisque':'#ffe4c4', 'black':'#000000', 'blanchedalmond':'#ffebcd', 'blue':'#0000ff', 'blueviolet':'#8a2be2', 'brown':'#a52a2a', 'burlywood':'#deb887', 'cadetblue':'#5f9ea0', 'chartreuse':'#7fff00', 'chocolate':'#d2691e', 'coral':'#ff7f50', 'cornflowerblue':'#6495ed', 'cornsilk':'#fff8dc', 'crimson':'#dc143c', 'cyan':'#00ffff', 'darkblue':'#00008b', 'darkcyan':'#008b8b', 'darkgoldenrod':'#b8860b', 'darkgray':'#a9a9a9', 'darkgrey':'#a9a9a9', 'darkgreen':'#006400', 'darkkhaki':'#bdb76b', 'darkmagenta':'#8b008b', 'darkolivegreen':'#556b2f', 'darkorange':'#ff8c00', 'darkorchid':'#9932cc', 'darkred':'#8b0000', 'darksalmon':'#e9967a', 'darkseagreen':'#8fbc8f', 'darkslateblue':'#483d8b', 'darkslategray':'#2f4f4f', 'darkslategrey':'#2f4f4f', 'darkturquoise':'#00ced1', 'darkviolet':'#9400d3', 'deeppink':'#ff1493', 'deepskyblue':'#00bfff', 'dimgray':'#696969', 'dimgrey':'#696969', 'dodgerblue':'#1e90ff', 'firebrick':'#b22222', 'floralwhite':'#fffaf0', 'forestgreen':'#228b22', 'fuchsia':'#ff00ff', 'gainsboro':'#dcdcdc', 'ghostwhite':'#f8f8ff', 'gold':'#ffd700', 'goldenrod':'#daa520', 'gray':'#808080', 'grey':'#808080', 'green':'#008000', 'greenyellow':'#adff2f', 'honeydew':'#f0fff0', 'hotpink':'#ff69b4', 'indianred':'#cd5c5c', 'indigo':'#4b0082', 'ivory':'#fffff0', 'khaki':'#f0e68c', 'lavender':'#e6e6fa', 'lavenderblush':'#fff0f5', 'lawngreen':'#7cfc00', 'lemonchiffon':'#fffacd', 'lightblue':'#add8e6', 'lightcoral':'#f08080', 'lightcyan':'#e0ffff', 'lightgoldenrodyellow':'#fafad2', 'lightgray':'#d3d3d3', 'lightgrey':'#d3d3d3', 'lightgreen':'#90ee90', 'lightpink':'#ffb6c1', 'lightsalmon':'#ffa07a', 'lightseagreen':'#20b2aa', 'lightskyblue':'#87cefa', 'lightslategray':'#778899', 'lightslategrey':'#778899', 'lightsteelblue':'#b0c4de', 'lightyellow':'#ffffe0', 'lime':'#00ff00', 'limegreen':'#32cd32', 'linen':'#faf0e6', 'magenta':'#ff00ff', 'maroon':'#800000', 'mediumaquamarine':'#66cdaa', 'mediumblue':'#0000cd', 'mediumorchid':'#ba55d3', 'mediumpurple':'#9370d8', 'mediumseagreen':'#3cb371', 'mediumslateblue':'#7b68ee', 'mediumspringgreen':'#00fa9a', 'mediumturquoise':'#48d1cc', 'mediumvioletred':'#c71585', 'midnightblue':'#191970', 'mintcream':'#f5fffa', 'mistyrose':'#ffe4e1', 'moccasin':'#ffe4b5', 'navajowhite':'#ffdead', 'navy':'#000080', 'oldlace':'#fdf5e6', 'olive':'#808000', 'olivedrab':'#6b8e23', 'orange':'#ffa500', 'orangered':'#ff4500', 'orchid':'#da70d6', 'palegoldenrod':'#eee8aa', 'palegreen':'#98fb98', 'paleturquoise':'#afeeee', 'palevioletred':'#d87093', 'papayawhip':'#ffefd5', 'peachpuff':'#ffdab9', 'peru':'#cd853f', 'pink':'#ffc0cb', 'plum':'#dda0dd', 'powderblue':'#b0e0e6', 'purple':'#800080', 'red':'#ff0000', 'rosybrown':'#bc8f8f', 'royalblue':'#4169e1', 'saddlebrown':'#8b4513', 'salmon':'#fa8072', 'sandybrown':'#f4a460', 'seagreen':'#2e8b57', 'seashell':'#fff5ee', 'sienna':'#a0522d', 'silver':'#c0c0c0', 'skyblue':'#87ceeb', 'slateblue':'#6a5acd', 'slategray':'#708090', 'slategrey':'#708090', 'snow':'#fffafa', 'springgreen':'#00ff7f', 'steelblue':'#4682b4', 'tan':'#d2b48c', 'teal':'#008080', 'thistle':'#d8bfd8', 'tomato':'#ff6347', // 'transparent':'rgba(0,0,0,0)', 'turquoise':'#40e0d0', 'violet':'#ee82ee', 'wheat':'#f5deb3', 'white':'#ffffff', 'whitesmoke':'#f5f5f5', 'yellow':'#ffff00', 'yellowgreen':'#9acd32' }; })(require('./tree')); (function (tree) { tree.Alpha = function (val) { this.value = val; }; tree.Alpha.prototype = { type: "Alpha", accept: function (visitor) { this.value = visitor.visit(this.value); }, eval: function (env) { if (this.value.eval) { this.value = this.value.eval(env) } return this; }, toCSS: function () { return "alpha(opacity=" + (this.value.toCSS ? this.value.toCSS() : this.value) + ")"; } }; })(require('../tree')); (function (tree) { tree.Anonymous = function (string) { this.value = string.value || string; }; tree.Anonymous.prototype = { type: "Anonymous", toCSS: function () { return this.value; }, eval: function () { return this }, compare: function (x) { if (!x.toCSS) { return -1; } var left = this.toCSS(), right = x.toCSS(); if (left === right) { return 0; } return left < right ? -1 : 1; } }; })(require('../tree')); (function (tree) { tree.Assignment = function (key, val) { this.key = key; this.value = val; }; tree.Assignment.prototype = { type: "Assignment", accept: function (visitor) { this.value = visitor.visit(this.value); }, toCSS: function () { return this.key + '=' + (this.value.toCSS ? this.value.toCSS() : this.value); }, eval: function (env) { if (this.value.eval) { return new(tree.Assignment)(this.key, this.value.eval(env)); } return this; } }; })(require('../tree'));(function (tree) { // // A function call node. // tree.Call = function (name, args, index, currentFileInfo) { this.name = name; this.args = args; this.index = index; this.currentFileInfo = currentFileInfo; }; tree.Call.prototype = { type: "Call", accept: function (visitor) { this.args = visitor.visit(this.args); }, // // When evaluating a function call, // we either find the function in `tree.functions` [1], // in which case we call it, passing the evaluated arguments, // if this returns null or we cannot find the function, we // simply print it out as it appeared originally [2]. // // The *functions.js* file contains the built-in functions. // // The reason why we evaluate the arguments, is in the case where // we try to pass a variable to a function, like: `saturate(@color)`. // The function should receive the value, not the variable. // eval: function (env) { var args = this.args.map(function (a) { return a.eval(env); }), nameLC = this.name.toLowerCase(), result, func; if (nameLC in tree.functions) { // 1. try { func = new tree.functionCall(env, this.currentFileInfo); result = func[nameLC].apply(func, args); if (result != null) { return result; } } catch (e) { throw { type: e.type || "Runtime", message: "error evaluating function `" + this.name + "`" + (e.message ? ': ' + e.message : ''), index: this.index, filename: this.currentFileInfo.filename }; } } // 2. return new(tree.Anonymous)(this.name + "(" + args.map(function (a) { return a.toCSS(env); }).join(', ') + ")"); }, toCSS: function (env) { return this.eval(env).toCSS(); } }; })(require('../tree')); (function (tree) { // // RGB Colors - #ff0014, #eee // tree.Color = function (rgb, a) { // // The end goal here, is to parse the arguments // into an integer triplet, such as `128, 255, 0` // // This facilitates operations and conversions. // if (Array.isArray(rgb)) { this.rgb = rgb; } else if (rgb.length == 6) { this.rgb = rgb.match(/.{2}/g).map(function (c) { return parseInt(c, 16); }); } else { this.rgb = rgb.split('').map(function (c) { return parseInt(c + c, 16); }); } this.alpha = typeof(a) === 'number' ? a : 1; }; tree.Color.prototype = { type: "Color", eval: function () { return this }, luma: function () { return (0.2126 * this.rgb[0] / 255) + (0.7152 * this.rgb[1] / 255) + (0.0722 * this.rgb[2] / 255); }, // // If we have some transparency, the only way to represent it // is via `rgba`. Otherwise, we use the hex representation, // which has better compatibility with older browsers. // Values are capped between `0` and `255`, rounded and zero-padded. // toCSS: function (env, doNotCompress) { var compress = env && env.compress && !doNotCompress; if (this.alpha < 1.0) { return "rgba(" + this.rgb.map(function (c) { return Math.round(c); }).concat(this.alpha).join(',' + (compress ? '' : ' ')) + ")"; } else { var color = this.rgb.map(function (i) { i = Math.round(i); i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16); return i.length === 1 ? '0' + i : i; }).join(''); if (compress) { color = color.split(''); // Convert color to short format if (color[0] == color[1] && color[2] == color[3] && color[4] == color[5]) { color = color[0] + color[2] + color[4]; } else { color = color.join(''); } } return '#' + color; } }, // // Operations have to be done per-channel, if not, // channels will spill onto each other. Once we have // our result, in the form of an integer triplet, // we create a new Color node to hold the result. // operate: function (env, op, other) { var result = []; if (! (other instanceof tree.Color)) { other = other.toColor(); } for (var c = 0; c < 3; c++) { result[c] = tree.operate(env, op, this.rgb[c], other.rgb[c]); } return new(tree.Color)(result, this.alpha + other.alpha); }, toHSL: function () { var r = this.rgb[0] / 255, g = this.rgb[1] / 255, b = this.rgb[2] / 255, a = this.alpha; var max = Math.max(r, g, b), min = Math.min(r, g, b); var h, s, l = (max + min) / 2, d = max - min; if (max === min) { h = s = 0; } else { s = l > 0.5 ? d / (2 - max - min) : d / (max + min); switch (max) { case r: h = (g - b) / d + (g < b ? 6 : 0); break; case g: h = (b - r) / d + 2; break; case b: h = (r - g) / d + 4; break; } h /= 6; } return { h: h * 360, s: s, l: l, a: a }; }, //Adapted from http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript toHSV: function () { var r = this.rgb[0] / 255, g = this.rgb[1] / 255, b = this.rgb[2] / 255, a = this.alpha; var max = Math.max(r, g, b), min = Math.min(r, g, b); var h, s, v = max; var d = max - min; if (max === 0) { s = 0; } else { s = d / max; } if (max === min) { h = 0; } else { switch(max){ case r: h = (g - b) / d + (g < b ? 6 : 0); break; case g: h = (b - r) / d + 2; break; case b: h = (r - g) / d + 4; break; } h /= 6; } return { h: h * 360, s: s, v: v, a: a }; }, toARGB: function () { var argb = [Math.round(this.alpha * 255)].concat(this.rgb); return '#' + argb.map(function (i) { i = Math.round(i); i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16); return i.length === 1 ? '0' + i : i; }).join(''); }, compare: function (x) { if (!x.rgb) { return -1; } return (x.rgb[0] === this.rgb[0] && x.rgb[1] === this.rgb[1] && x.rgb[2] === this.rgb[2] && x.alpha === this.alpha) ? 0 : -1; } }; })(require('../tree')); (function (tree) { tree.Comment = function (value, silent) { this.value = value; this.silent = !!silent; }; tree.Comment.prototype = { type: "Comment", toCSS: function (env) { return env.compress ? '' : this.value; }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.Condition = function (op, l, r, i, negate) { this.op = op.trim(); this.lvalue = l; this.rvalue = r; this.index = i; this.negate = negate; }; tree.Condition.prototype = { type: "Condition", accept: function (visitor) { this.lvalue = visitor.visit(this.lvalue); this.rvalue = visitor.visit(this.rvalue); }, eval: function (env) { var a = this.lvalue.eval(env), b = this.rvalue.eval(env); var i = this.index, result; var result = (function (op) { switch (op) { case 'and': return a && b; case 'or': return a || b; default: if (a.compare) { result = a.compare(b); } else if (b.compare) { result = b.compare(a); } else { throw { type: "Type", message: "Unable to perform comparison", index: i }; } switch (result) { case -1: return op === '<' || op === '=<'; case 0: return op === '=' || op === '>=' || op === '=<'; case 1: return op === '>' || op === '>='; } } })(this.op); return this.negate ? !result : result; } }; })(require('../tree')); (function (tree) { // // A number with a unit // tree.Dimension = function (value, unit) { this.value = parseFloat(value); this.unit = (unit && unit instanceof tree.Unit) ? unit : new(tree.Unit)(unit ? [unit] : undefined); }; tree.Dimension.prototype = { type: "Dimension", accept: function (visitor) { this.unit = visitor.visit(this.unit); }, eval: function (env) { return this; }, toColor: function () { return new(tree.Color)([this.value, this.value, this.value]); }, toCSS: function (env) { if ((env && env.strictUnits) && !this.unit.isSingular()) { throw new Error("Multiple units in dimension. Correct the units or use the unit function. Bad unit: "+this.unit.toString()); } var value = this.value, strValue = String(value); if (value !== 0 && value < 0.000001 && value > -0.000001) { // would be output 1e-6 etc. strValue = value.toFixed(20).replace(/0+$/, ""); } if (env && env.compress) { // Zero values doesn't need a unit if (value === 0 && !this.unit.isAngle()) { return strValue; } // Float values doesn't need a leading zero if (value > 0 && value < 1) { strValue = (strValue).substr(1); } } return strValue + this.unit.toCSS(env); }, // In an operation between two Dimensions, // we default to the first Dimension's unit, // so `1px + 2` will yield `3px`. operate: function (env, op, other) { var value = tree.operate(env, op, this.value, other.value), unit = this.unit.clone(); if (op === '+' || op === '-') { if (unit.numerator.length === 0 && unit.denominator.length === 0) { unit.numerator = other.unit.numerator.slice(0); unit.denominator = other.unit.denominator.slice(0); } else if (other.unit.numerator.length == 0 && unit.denominator.length == 0) { // do nothing } else { other = other.convertTo(this.unit.usedUnits()); if(env.strictUnits && other.unit.toString() !== unit.toString()) { throw new Error("Incompatible units. Change the units or use the unit function. Bad units: '" + unit.toString() + "' and '" + other.unit.toString() + "'."); } value = tree.operate(env, op, this.value, other.value); } } else if (op === '*') { unit.numerator = unit.numerator.concat(other.unit.numerator).sort(); unit.denominator = unit.denominator.concat(other.unit.denominator).sort(); unit.cancel(); } else if (op === '/') { unit.numerator = unit.numerator.concat(other.unit.denominator).sort(); unit.denominator = unit.denominator.concat(other.unit.numerator).sort(); unit.cancel(); } return new(tree.Dimension)(value, unit); }, compare: function (other) { if (other instanceof tree.Dimension) { var a = this.unify(), b = other.unify(), aValue = a.value, bValue = b.value; if (bValue > aValue) { return -1; } else if (bValue < aValue) { return 1; } else { if (!b.unit.isEmpty() && a.unit.compare(b.unit) !== 0) { return -1; } return 0; } } else { return -1; } }, unify: function () { return this.convertTo({ length: 'm', duration: 's', angle: 'rad' }); }, convertTo: function (conversions) { var value = this.value, unit = this.unit.clone(), i, groupName, group, conversion, targetUnit, derivedConversions = {}; if (typeof conversions === 'string') { for(i in tree.UnitConversions) { if (tree.UnitConversions[i].hasOwnProperty(conversions)) { derivedConversions = {}; derivedConversions[i] = conversions; } } conversions = derivedConversions; } for (groupName in conversions) { if (conversions.hasOwnProperty(groupName)) { targetUnit = conversions[groupName]; group = tree.UnitConversions[groupName]; unit.map(function (atomicUnit, denominator) { if (group.hasOwnProperty(atomicUnit)) { if (denominator) { value = value / (group[atomicUnit] / group[targetUnit]); } else { value = value * (group[atomicUnit] / group[targetUnit]); } return targetUnit; } return atomicUnit; }); } } unit.cancel(); return new(tree.Dimension)(value, unit); } }; // http://www.w3.org/TR/css3-values/#absolute-lengths tree.UnitConversions = { length: { 'm': 1, 'cm': 0.01, 'mm': 0.001, 'in': 0.0254, 'pt': 0.0254 / 72, 'pc': 0.0254 / 72 * 12 }, duration: { 's': 1, 'ms': 0.001 }, angle: { 'rad': 1/(2*Math.PI), 'deg': 1/360, 'grad': 1/400, 'turn': 1 } }; tree.Unit = function (numerator, denominator, backupUnit) { this.numerator = numerator ? numerator.slice(0).sort() : []; this.denominator = denominator ? denominator.slice(0).sort() : []; this.backupUnit = backupUnit; }; tree.Unit.prototype = { type: "Unit", clone: function () { return new tree.Unit(this.numerator.slice(0), this.denominator.slice(0), this.backupUnit); }, toCSS: function (env) { if (this.numerator.length >= 1) { return this.numerator[0]; } if (this.denominator.length >= 1) { return this.denominator[0]; } if ((!env || !env.strictUnits) && this.backupUnit) { return this.backupUnit; } return ""; }, toString: function () { var i, returnStr = this.numerator.join("*"); for (i = 0; i < this.denominator.length; i++) { returnStr += "/" + this.denominator[i]; } return returnStr; }, compare: function (other) { return this.is(other.toString()) ? 0 : -1; }, is: function (unitString) { return this.toString() === unitString; }, isAngle: function () { return tree.UnitConversions.angle.hasOwnProperty(this.toCSS()); }, isEmpty: function () { return this.numerator.length == 0 && this.denominator.length == 0; }, isSingular: function() { return this.numerator.length <= 1 && this.denominator.length == 0; }, map: function(callback) { var i; for (i = 0; i < this.numerator.length; i++) { this.numerator[i] = callback(this.numerator[i], false); } for (i = 0; i < this.denominator.length; i++) { this.denominator[i] = callback(this.denominator[i], true); } }, usedUnits: function() { var group, groupName, result = {}; for (groupName in tree.UnitConversions) { if (tree.UnitConversions.hasOwnProperty(groupName)) { group = tree.UnitConversions[groupName]; this.map(function (atomicUnit) { if (group.hasOwnProperty(atomicUnit) && !result[groupName]) { result[groupName] = atomicUnit; } return atomicUnit; }); } } return result; }, cancel: function () { var counter = {}, atomicUnit, i, backup; for (i = 0; i < this.numerator.length; i++) { atomicUnit = this.numerator[i]; if (!backup) { backup = atomicUnit; } counter[atomicUnit] = (counter[atomicUnit] || 0) + 1; } for (i = 0; i < this.denominator.length; i++) { atomicUnit = this.denominator[i]; if (!backup) { backup = atomicUnit; } counter[atomicUnit] = (counter[atomicUnit] || 0) - 1; } this.numerator = []; this.denominator = []; for (atomicUnit in counter) { if (counter.hasOwnProperty(atomicUnit)) { var count = counter[atomicUnit]; if (count > 0) { for (i = 0; i < count; i++) { this.numerator.push(atomicUnit); } } else if (count < 0) { for (i = 0; i < -count; i++) { this.denominator.push(atomicUnit); } } } } if (this.numerator.length === 0 && this.denominator.length === 0 && backup) { this.backupUnit = backup; } this.numerator.sort(); this.denominator.sort(); } }; })(require('../tree')); (function (tree) { tree.Directive = function (name, value) { this.name = name; if (Array.isArray(value)) { this.ruleset = new(tree.Ruleset)([], value); this.ruleset.allowImports = true; } else { this.value = value; } }; tree.Directive.prototype = { type: "Directive", accept: function (visitor) { this.ruleset = visitor.visit(this.ruleset); this.value = visitor.visit(this.value); }, toCSS: function (env) { if (this.ruleset) { this.ruleset.root = true; return this.name + (env.compress ? '{' : ' {\n ') + this.ruleset.toCSS(env).trim().replace(/\n/g, '\n ') + (env.compress ? '}': '\n}\n'); } else { return this.name + ' ' + this.value.toCSS() + ';\n'; } }, eval: function (env) { var evaldDirective = this; if (this.ruleset) { env.frames.unshift(this); evaldDirective = new(tree.Directive)(this.name); evaldDirective.ruleset = this.ruleset.eval(env); env.frames.shift(); } return evaldDirective; }, variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) }, find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) }, rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) } }; })(require('../tree')); (function (tree) { tree.Element = function (combinator, value, index) { this.combinator = combinator instanceof tree.Combinator ? combinator : new(tree.Combinator)(combinator); if (typeof(value) === 'string') { this.value = value.trim(); } else if (value) { this.value = value; } else { this.value = ""; } this.index = index; }; tree.Element.prototype = { type: "Element", accept: function (visitor) { this.combinator = visitor.visit(this.combinator); this.value = visitor.visit(this.value); }, eval: function (env) { return new(tree.Element)(this.combinator, this.value.eval ? this.value.eval(env) : this.value, this.index); }, toCSS: function (env) { var value = (this.value.toCSS ? this.value.toCSS(env) : this.value); if (value == '' && this.combinator.value.charAt(0) == '&') { return ''; } else { return this.combinator.toCSS(env || {}) + value; } } }; tree.Attribute = function (key, op, value) { this.key = key; this.op = op; this.value = value; }; tree.Attribute.prototype = { type: "Attribute", accept: function (visitor) { this.value = visitor.visit(this.value); }, eval: function (env) { return new(tree.Attribute)(this.key.eval ? this.key.eval(env) : this.key, this.op, (this.value && this.value.eval) ? this.value.eval(env) : this.value); }, toCSS: function (env) { var value = this.key.toCSS ? this.key.toCSS(env) : this.key; if (this.op) { value += this.op; value += (this.value.toCSS ? this.value.toCSS(env) : this.value); } return '[' + value + ']'; } }; tree.Combinator = function (value) { if (value === ' ') { this.value = ' '; } else { this.value = value ? value.trim() : ""; } }; tree.Combinator.prototype = { type: "Combinator", toCSS: function (env) { return { '' : '', ' ' : ' ', ':' : ' :', '+' : env.compress ? '+' : ' + ', '~' : env.compress ? '~' : ' ~ ', '>' : env.compress ? '>' : ' > ', '|' : env.compress ? '|' : ' | ' }[this.value]; } }; })(require('../tree')); (function (tree) { tree.Expression = function (value) { this.value = value; }; tree.Expression.prototype = { type: "Expression", accept: function (visitor) { this.value = visitor.visit(this.value); }, eval: function (env) { var returnValue, inParenthesis = this.parens && !this.parensInOp, doubleParen = false; if (inParenthesis) { env.inParenthesis(); } if (this.value.length > 1) { returnValue = new(tree.Expression)(this.value.map(function (e) { return e.eval(env); })); } else if (this.value.length === 1) { if (this.value[0].parens && !this.value[0].parensInOp) { doubleParen = true; } returnValue = this.value[0].eval(env); } else { returnValue = this; } if (inParenthesis) { env.outOfParenthesis(); } if (this.parens && this.parensInOp && !(env.isMathOn()) && !doubleParen) { returnValue = new(tree.Paren)(returnValue); } return returnValue; }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS ? e.toCSS(env) : ''; }).join(' '); }, throwAwayComments: function () { this.value = this.value.filter(function(v) { return !(v instanceof tree.Comment); }); } }; })(require('../tree')); (function (tree) { tree.Extend = function Extend(selector, option, index) { this.selector = selector; this.option = option; this.index = index; switch(option) { case "all": this.allowBefore = true; this.allowAfter = true; break; default: this.allowBefore = false; this.allowAfter = false; break; } }; tree.Extend.prototype = { type: "Extend", accept: function (visitor) { this.selector = visitor.visit(this.selector); }, eval: function (env) { return new(tree.Extend)(this.selector.eval(env), this.option, this.index); }, clone: function (env) { return new(tree.Extend)(this.selector, this.option, this.index); }, findSelfSelectors: function (selectors) { var selfElements = []; for(i = 0; i < selectors.length; i++) { selfElements = selfElements.concat(selectors[i].elements); } this.selfSelectors = [{ elements: selfElements }]; } }; })(require('../tree')); (function (tree) { // // CSS @import node // // The general strategy here is that we don't want to wait // for the parsing to be completed, before we start importing // the file. That's because in the context of a browser, // most of the time will be spent waiting for the server to respond. // // On creation, we push the import path to our import queue, though // `import,push`, we also pass it a callback, which it'll call once // the file has been fetched, and parsed. // tree.Import = function (path, features, options, index, currentFileInfo) { var that = this; this.options = options; this.index = index; this.path = path; this.features = features; this.currentFileInfo = currentFileInfo; if (this.options.less !== undefined) { this.css = !this.options.less; } else { var pathValue = this.getPath(); if (pathValue && /css([\?;].*)?$/.test(pathValue)) { this.css = true; } } }; // // The actual import node doesn't return anything, when converted to CSS. // The reason is that it's used at the evaluation stage, so that the rules // it imports can be treated like any other rules. // // In `eval`, we make sure all Import nodes get evaluated, recursively, so // we end up with a flat structure, which can easily be imported in the parent // ruleset. // tree.Import.prototype = { type: "Import", accept: function (visitor) { this.features = visitor.visit(this.features); this.path = visitor.visit(this.path); this.root = visitor.visit(this.root); }, toCSS: function (env) { var features = this.features ? ' ' + this.features.toCSS(env) : ''; if (this.css) { return "@import " + this.path.toCSS() + features + ';\n'; } else { return ""; } }, getPath: function () { if (this.path instanceof tree.Quoted) { var path = this.path.value; return (this.css !== undefined || /(\.[a-z]*$)|([\?;].*)$/.test(path)) ? path : path + '.less'; } else if (this.path instanceof tree.URL) { return this.path.value.value; } return null; }, evalForImport: function (env) { return new(tree.Import)(this.path.eval(env), this.features, this.options, this.index, this.currentFileInfo); }, evalPath: function (env) { var path = this.path.eval(env); var rootpath = this.currentFileInfo && this.currentFileInfo.rootpath; if (rootpath && !(path instanceof tree.URL)) { var pathValue = path.value; // Add the base path if the import is relative if (pathValue && env.isPathRelative(pathValue)) { path.value = rootpath + pathValue; } } return path; }, eval: function (env) { var ruleset, features = this.features && this.features.eval(env); if (this.skip) { return []; } if (this.css) { var newImport = new(tree.Import)(this.evalPath(env), features, this.options, this.index); if (!newImport.css && this.error) { throw this.error; } return newImport; } else { ruleset = new(tree.Ruleset)([], this.root.rules.slice(0)); ruleset.evalImports(env); return this.features ? new(tree.Media)(ruleset.rules, this.features.value) : ruleset.rules; } } }; })(require('../tree')); (function (tree) { tree.JavaScript = function (string, index, escaped) { this.escaped = escaped; this.expression = string; this.index = index; }; tree.JavaScript.prototype = { type: "JavaScript", eval: function (env) { var result, that = this, context = {}; var expression = this.expression.replace(/@\{([\w-]+)\}/g, function (_, name) { return tree.jsify(new(tree.Variable)('@' + name, that.index).eval(env)); }); try { expression = new(Function)('return (' + expression + ')'); } catch (e) { throw { message: "JavaScript evaluation error: `" + expression + "`" , index: this.index }; } for (var k in env.frames[0].variables()) { context[k.slice(1)] = { value: env.frames[0].variables()[k].value, toJS: function () { return this.value.eval(env).toCSS(); } }; } try { result = expression.call(context); } catch (e) { throw { message: "JavaScript evaluation error: '" + e.name + ': ' + e.message + "'" , index: this.index }; } if (typeof(result) === 'string') { return new(tree.Quoted)('"' + result + '"', result, this.escaped, this.index); } else if (Array.isArray(result)) { return new(tree.Anonymous)(result.join(', ')); } else { return new(tree.Anonymous)(result); } } }; })(require('../tree')); (function (tree) { tree.Keyword = function (value) { this.value = value }; tree.Keyword.prototype = { type: "Keyword", eval: function () { return this; }, toCSS: function () { return this.value; }, compare: function (other) { if (other instanceof tree.Keyword) { return other.value === this.value ? 0 : 1; } else { return -1; } } }; tree.True = new(tree.Keyword)('true'); tree.False = new(tree.Keyword)('false'); })(require('../tree')); (function (tree) { tree.Media = function (value, features) { var selectors = this.emptySelectors(); this.features = new(tree.Value)(features); this.ruleset = new(tree.Ruleset)(selectors, value); this.ruleset.allowImports = true; }; tree.Media.prototype = { type: "Media", accept: function (visitor) { this.features = visitor.visit(this.features); this.ruleset = visitor.visit(this.ruleset); }, toCSS: function (env) { var features = this.features.toCSS(env); return '@media ' + features + (env.compress ? '{' : ' {\n ') + this.ruleset.toCSS(env).trim().replace(/\n/g, '\n ') + (env.compress ? '}': '\n}\n'); }, eval: function (env) { if (!env.mediaBlocks) { env.mediaBlocks = []; env.mediaPath = []; } var media = new(tree.Media)([], []); if(this.debugInfo) { this.ruleset.debugInfo = this.debugInfo; media.debugInfo = this.debugInfo; } var strictMathBypass = false; if (!env.strictMath) { strictMathBypass = true; env.strictMath = true; } try { media.features = this.features.eval(env); } finally { if (strictMathBypass) { env.strictMath = false; } } env.mediaPath.push(media); env.mediaBlocks.push(media); env.frames.unshift(this.ruleset); media.ruleset = this.ruleset.eval(env); env.frames.shift(); env.mediaPath.pop(); return env.mediaPath.length === 0 ? media.evalTop(env) : media.evalNested(env) }, variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) }, find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) }, rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) }, emptySelectors: function() { var el = new(tree.Element)('', '&', 0); return [new(tree.Selector)([el])]; }, evalTop: function (env) { var result = this; // Render all dependent Media blocks. if (env.mediaBlocks.length > 1) { var selectors = this.emptySelectors(); result = new(tree.Ruleset)(selectors, env.mediaBlocks); result.multiMedia = true; } delete env.mediaBlocks; delete env.mediaPath; return result; }, evalNested: function (env) { var i, value, path = env.mediaPath.concat([this]); // Extract the media-query conditions separated with `,` (OR). for (i = 0; i < path.length; i++) { value = path[i].features instanceof tree.Value ? path[i].features.value : path[i].features; path[i] = Array.isArray(value) ? value : [value]; } // Trace all permutations to generate the resulting media-query. // // (a, b and c) with nested (d, e) -> // a and d // a and e // b and c and d // b and c and e this.features = new(tree.Value)(this.permute(path).map(function (path) { path = path.map(function (fragment) { return fragment.toCSS ? fragment : new(tree.Anonymous)(fragment); }); for(i = path.length - 1; i > 0; i--) { path.splice(i, 0, new(tree.Anonymous)("and")); } return new(tree.Expression)(path); })); // Fake a tree-node that doesn't output anything. return new(tree.Ruleset)([], []); }, permute: function (arr) { if (arr.length === 0) { return []; } else if (arr.length === 1) { return arr[0]; } else { var result = []; var rest = this.permute(arr.slice(1)); for (var i = 0; i < rest.length; i++) { for (var j = 0; j < arr[0].length; j++) { result.push([arr[0][j]].concat(rest[i])); } } return result; } }, bubbleSelectors: function (selectors) { this.ruleset = new(tree.Ruleset)(selectors.slice(0), [this.ruleset]); } }; })(require('../tree')); (function (tree) { tree.mixin = {}; tree.mixin.Call = function (elements, args, index, currentFileInfo, important) { this.selector = new(tree.Selector)(elements); this.arguments = args; this.index = index; this.currentFileInfo = currentFileInfo; this.important = important; }; tree.mixin.Call.prototype = { type: "MixinCall", accept: function (visitor) { this.selector = visitor.visit(this.selector); this.arguments = visitor.visit(this.arguments); }, eval: function (env) { var mixins, mixin, args, rules = [], match = false, i, m, f, isRecursive, isOneFound; args = this.arguments && this.arguments.map(function (a) { return { name: a.name, value: a.value.eval(env) }; }); for (i = 0; i < env.frames.length; i++) { if ((mixins = env.frames[i].find(this.selector)).length > 0) { isOneFound = true; for (m = 0; m < mixins.length; m++) { mixin = mixins[m]; isRecursive = false; for(f = 0; f < env.frames.length; f++) { if ((!(mixin instanceof tree.mixin.Definition)) && mixin === (env.frames[f].originalRuleset || env.frames[f])) { isRecursive = true; break; } } if (isRecursive) { continue; } if (mixin.matchArgs(args, env)) { if (!mixin.matchCondition || mixin.matchCondition(args, env)) { try { Array.prototype.push.apply( rules, mixin.eval(env, args, this.important).rules); } catch (e) { throw { message: e.message, index: this.index, filename: this.currentFileInfo.filename, stack: e.stack }; } } match = true; } } if (match) { return rules; } } } if (isOneFound) { throw { type: 'Runtime', message: 'No matching definition was found for `' + this.selector.toCSS().trim() + '(' + (args ? args.map(function (a) { var argValue = ""; if (a.name) { argValue += a.name + ":"; } if (a.value.toCSS) { argValue += a.value.toCSS(); } else { argValue += "???"; } return argValue; }).join(', ') : "") + ")`", index: this.index, filename: this.currentFileInfo.filename }; } else { throw { type: 'Name', message: this.selector.toCSS().trim() + " is undefined", index: this.index, filename: this.currentFileInfo.filename }; } } }; tree.mixin.Definition = function (name, params, rules, condition, variadic) { this.name = name; this.selectors = [new(tree.Selector)([new(tree.Element)(null, name)])]; this.params = params; this.condition = condition; this.variadic = variadic; this.arity = params.length; this.rules = rules; this._lookups = {}; this.required = params.reduce(function (count, p) { if (!p.name || (p.name && !p.value)) { return count + 1 } else { return count } }, 0); this.parent = tree.Ruleset.prototype; this.frames = []; }; tree.mixin.Definition.prototype = { type: "MixinDefinition", accept: function (visitor) { this.params = visitor.visit(this.params); this.rules = visitor.visit(this.rules); this.condition = visitor.visit(this.condition); }, toCSS: function () { return ""; }, variable: function (name) { return this.parent.variable.call(this, name); }, variables: function () { return this.parent.variables.call(this); }, find: function () { return this.parent.find.apply(this, arguments); }, rulesets: function () { return this.parent.rulesets.apply(this); }, evalParams: function (env, mixinEnv, args, evaldArguments) { var frame = new(tree.Ruleset)(null, []), varargs, arg, params = this.params.slice(0), i, j, val, name, isNamedFound, argIndex; mixinEnv = new tree.evalEnv(mixinEnv, [frame].concat(mixinEnv.frames)); if (args) { args = args.slice(0); for(i = 0; i < args.length; i++) { arg = args[i]; if (name = (arg && arg.name)) { isNamedFound = false; for(j = 0; j < params.length; j++) { if (!evaldArguments[j] && name === params[j].name) { evaldArguments[j] = arg.value.eval(env); frame.rules.unshift(new(tree.Rule)(name, arg.value.eval(env))); isNamedFound = true; break; } } if (isNamedFound) { args.splice(i, 1); i--; continue; } else { throw { type: 'Runtime', message: "Named argument for " + this.name + ' ' + args[i].name + ' not found' }; } } } } argIndex = 0; for (i = 0; i < params.length; i++) { if (evaldArguments[i]) continue; arg = args && args[argIndex]; if (name = params[i].name) { if (params[i].variadic && args) { varargs = []; for (j = argIndex; j < args.length; j++) { varargs.push(args[j].value.eval(env)); } frame.rules.unshift(new(tree.Rule)(name, new(tree.Expression)(varargs).eval(env))); } else { val = arg && arg.value; if (val) { val = val.eval(env); } else if (params[i].value) { val = params[i].value.eval(mixinEnv); frame.resetCache(); } else { throw { type: 'Runtime', message: "wrong number of arguments for " + this.name + ' (' + args.length + ' for ' + this.arity + ')' }; } frame.rules.unshift(new(tree.Rule)(name, val)); evaldArguments[i] = val; } } if (params[i].variadic && args) { for (j = argIndex; j < args.length; j++) { evaldArguments[j] = args[j].value.eval(env); } } argIndex++; } return frame; }, eval: function (env, args, important) { var _arguments = [], mixinFrames = this.frames.concat(env.frames), frame = this.evalParams(env, new(tree.evalEnv)(env, mixinFrames), args, _arguments), context, rules, start, ruleset; frame.rules.unshift(new(tree.Rule)('@arguments', new(tree.Expression)(_arguments).eval(env))); rules = important ? this.parent.makeImportant.apply(this).rules : this.rules.slice(0); ruleset = new(tree.Ruleset)(null, rules).eval(new(tree.evalEnv)(env, [this, frame].concat(mixinFrames))); ruleset.originalRuleset = this; return ruleset; }, matchCondition: function (args, env) { if (this.condition && !this.condition.eval( new(tree.evalEnv)(env, [this.evalParams(env, new(tree.evalEnv)(env, this.frames.concat(env.frames)), args, [])] .concat(env.frames)))) { return false; } return true; }, matchArgs: function (args, env) { var argsLength = (args && args.length) || 0, len, frame; if (! this.variadic) { if (argsLength < this.required) { return false } if (argsLength > this.params.length) { return false } if ((this.required > 0) && (argsLength > this.params.length)) { return false } } len = Math.min(argsLength, this.arity); for (var i = 0; i < len; i++) { if (!this.params[i].name && !this.params[i].variadic) { if (args[i].value.eval(env).toCSS() != this.params[i].value.eval(env).toCSS()) { return false; } } } return true; } }; })(require('../tree')); (function (tree) { tree.Negative = function (node) { this.value = node; }; tree.Negative.prototype = { type: "Negative", accept: function (visitor) { this.value = visitor.visit(this.value); }, toCSS: function (env) { return '-' + this.value.toCSS(env); }, eval: function (env) { if (env.isMathOn()) { return (new(tree.Operation)('*', [new(tree.Dimension)(-1), this.value])).eval(env); } return new(tree.Negative)(this.value.eval(env)); } }; })(require('../tree')); (function (tree) { tree.Operation = function (op, operands, isSpaced) { this.op = op.trim(); this.operands = operands; this.isSpaced = isSpaced; }; tree.Operation.prototype = { type: "Operation", accept: function (visitor) { this.operands = visitor.visit(this.operands); }, eval: function (env) { var a = this.operands[0].eval(env), b = this.operands[1].eval(env), temp; if (env.isMathOn()) { if (a instanceof tree.Dimension && b instanceof tree.Color) { if (this.op === '*' || this.op === '+') { temp = b, b = a, a = temp; } else { throw { type: "Operation", message: "Can't substract or divide a color from a number" }; } } if (!a.operate) { throw { type: "Operation", message: "Operation on an invalid type" }; } return a.operate(env, this.op, b); } else { return new(tree.Operation)(this.op, [a, b], this.isSpaced); } }, toCSS: function (env) { var separator = this.isSpaced ? " " : ""; return this.operands[0].toCSS() + separator + this.op + separator + this.operands[1].toCSS(); } }; tree.operate = function (env, op, a, b) { switch (op) { case '+': return a + b; case '-': return a - b; case '*': return a * b; case '/': return a / b; } }; })(require('../tree')); (function (tree) { tree.Paren = function (node) { this.value = node; }; tree.Paren.prototype = { type: "Paren", accept: function (visitor) { this.value = visitor.visit(this.value); }, toCSS: function (env) { return '(' + this.value.toCSS(env).trim() + ')'; }, eval: function (env) { return new(tree.Paren)(this.value.eval(env)); } }; })(require('../tree')); (function (tree) { tree.Quoted = function (str, content, escaped, index, currentFileInfo) { this.escaped = escaped; this.value = content || ''; this.quote = str.charAt(0); this.index = index; this.currentFileInfo = currentFileInfo; }; tree.Quoted.prototype = { type: "Quoted", toCSS: function () { if (this.escaped) { return this.value; } else { return this.quote + this.value + this.quote; } }, eval: function (env) { var that = this; var value = this.value.replace(/`([^`]+)`/g, function (_, exp) { return new(tree.JavaScript)(exp, that.index, true).eval(env).value; }).replace(/@\{([\w-]+)\}/g, function (_, name) { var v = new(tree.Variable)('@' + name, that.index, that.currentFileInfo).eval(env, true); return (v instanceof tree.Quoted) ? v.value : v.toCSS(); }); return new(tree.Quoted)(this.quote + value + this.quote, value, this.escaped, this.index); }, compare: function (x) { if (!x.toCSS) { return -1; } var left = this.toCSS(), right = x.toCSS(); if (left === right) { return 0; } return left < right ? -1 : 1; } }; })(require('../tree')); (function (tree) { tree.Rule = function (name, value, important, index, currentFileInfo, inline) { this.name = name; this.value = (value instanceof tree.Value) ? value : new(tree.Value)([value]); this.important = important ? ' ' + important.trim() : ''; this.index = index; this.currentFileInfo = currentFileInfo; this.inline = inline || false; if (name.charAt(0) === '@') { this.variable = true; } else { this.variable = false } }; tree.Rule.prototype = { type: "Rule", accept: function (visitor) { this.value = visitor.visit(this.value); }, toCSS: function (env) { if (this.variable) { return "" } else { try { return this.name + (env.compress ? ':' : ': ') + this.value.toCSS(env) + this.important + (this.inline ? "" : ";"); } catch(e) { e.index = this.index; e.filename = this.currentFileInfo.filename; throw e; } } }, eval: function (env) { var strictMathBypass = false; if (this.name === "font" && env.strictMath === false) { strictMathBypass = true; env.strictMath = true; } try { return new(tree.Rule)(this.name, this.value.eval(env), this.important, this.index, this.currentFileInfo, this.inline); } finally { if (strictMathBypass) { env.strictMath = false; } } }, makeImportant: function () { return new(tree.Rule)(this.name, this.value, "!important", this.index, this.currentFileInfo, this.inline); } }; })(require('../tree')); (function (tree) { tree.Ruleset = function (selectors, rules, strictImports) { this.selectors = selectors; this.rules = rules; this._lookups = {}; this.strictImports = strictImports; }; tree.Ruleset.prototype = { type: "Ruleset", accept: function (visitor) { this.selectors = visitor.visit(this.selectors); this.rules = visitor.visit(this.rules); }, eval: function (env) { var selectors = this.selectors && this.selectors.map(function (s) { return s.eval(env) }); var ruleset = new(tree.Ruleset)(selectors, this.rules.slice(0), this.strictImports); var rules; ruleset.originalRuleset = this; ruleset.root = this.root; ruleset.firstRoot = this.firstRoot; ruleset.allowImports = this.allowImports; if(this.debugInfo) { ruleset.debugInfo = this.debugInfo; } // push the current ruleset to the frames stack env.frames.unshift(ruleset); // currrent selectors if (!env.selectors) { env.selectors = []; } env.selectors.unshift(this.selectors); // Evaluate imports if (ruleset.root || ruleset.allowImports || !ruleset.strictImports) { ruleset.evalImports(env); } // Store the frames around mixin definitions, // so they can be evaluated like closures when the time comes. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Definition) { ruleset.rules[i].frames = env.frames.slice(0); } } var mediaBlockCount = (env.mediaBlocks && env.mediaBlocks.length) || 0; // Evaluate mixin calls. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Call) { rules = ruleset.rules[i].eval(env).filter(function(r) { if ((r instanceof tree.Rule) && r.variable) { // do not pollute the scope if the variable is // already there. consider returning false here // but we need a way to "return" variable from mixins return !(ruleset.variable(r.name)); } return true; }); ruleset.rules.splice.apply(ruleset.rules, [i, 1].concat(rules)); i += rules.length-1; ruleset.resetCache(); } } // Evaluate everything else for (var i = 0, rule; i < ruleset.rules.length; i++) { rule = ruleset.rules[i]; if (! (rule instanceof tree.mixin.Definition)) { ruleset.rules[i] = rule.eval ? rule.eval(env) : rule; } } // Pop the stack env.frames.shift(); env.selectors.shift(); if (env.mediaBlocks) { for(var i = mediaBlockCount; i < env.mediaBlocks.length; i++) { env.mediaBlocks[i].bubbleSelectors(selectors); } } return ruleset; }, evalImports: function(env) { var i, rules; for (i = 0; i < this.rules.length; i++) { if (this.rules[i] instanceof tree.Import) { rules = this.rules[i].eval(env); if (typeof rules.length === "number") { this.rules.splice.apply(this.rules, [i, 1].concat(rules)); i+= rules.length-1; } else { this.rules.splice(i, 1, rules); } this.resetCache(); } } }, makeImportant: function() { return new tree.Ruleset(this.selectors, this.rules.map(function (r) { if (r.makeImportant) { return r.makeImportant(); } else { return r; } }), this.strictImports); }, matchArgs: function (args) { return !args || args.length === 0; }, resetCache: function () { this._rulesets = null; this._variables = null; this._lookups = {}; }, variables: function () { if (this._variables) { return this._variables } else { return this._variables = this.rules.reduce(function (hash, r) { if (r instanceof tree.Rule && r.variable === true) { hash[r.name] = r; } return hash; }, {}); } }, variable: function (name) { return this.variables()[name]; }, rulesets: function () { return this.rules.filter(function (r) { return (r instanceof tree.Ruleset) || (r instanceof tree.mixin.Definition); }); }, find: function (selector, self) { self = self || this; var rules = [], rule, match, key = selector.toCSS(); if (key in this._lookups) { return this._lookups[key] } this.rulesets().forEach(function (rule) { if (rule !== self) { for (var j = 0; j < rule.selectors.length; j++) { if (match = selector.match(rule.selectors[j])) { if (selector.elements.length > rule.selectors[j].elements.length) { Array.prototype.push.apply(rules, rule.find( new(tree.Selector)(selector.elements.slice(1)), self)); } else { rules.push(rule); } break; } } } }); return this._lookups[key] = rules; }, // // Entry point for code generation // // `context` holds an array of arrays. // toCSS: function (env) { var css = [], // The CSS output rules = [], // node.Rule instances _rules = [], // rulesets = [], // node.Ruleset instances selector, // The fully rendered selector debugInfo, // Line number debugging rule; // Compile rules and rulesets for (var i = 0; i < this.rules.length; i++) { rule = this.rules[i]; if (rule.rules || (rule instanceof tree.Media)) { rulesets.push(rule.toCSS(env)); } else if (rule instanceof tree.Directive) { var cssValue = rule.toCSS(env); // Output only the first @charset definition as such - convert the others // to comments in case debug is enabled if (rule.name === "@charset") { // Only output the debug info together with subsequent @charset definitions // a comment (or @media statement) before the actual @charset directive would // be considered illegal css as it has to be on the first line if (env.charset) { if (rule.debugInfo) { rulesets.push(tree.debugInfo(env, rule)); rulesets.push(new tree.Comment("/* "+cssValue.replace(/\n/g, "")+" */\n").toCSS(env)); } continue; } env.charset = true; } rulesets.push(cssValue); } else if (rule instanceof tree.Comment) { if (!rule.silent) { if (this.root) { rulesets.push(rule.toCSS(env)); } else { rules.push(rule.toCSS(env)); } } } else { if (rule.toCSS && !rule.variable) { if (this.firstRoot && rule instanceof tree.Rule) { throw { message: "properties must be inside selector blocks, they cannot be in the root.", index: rule.index, filename: rule.currentFileInfo ? rule.currentFileInfo.filename : null}; } rules.push(rule.toCSS(env)); } else if (rule.value && !rule.variable) { rules.push(rule.value.toString()); } } } // Remove last semicolon if (env.compress && rules.length) { rule = rules[rules.length - 1]; if (rule.charAt(rule.length - 1) === ';') { rules[rules.length - 1] = rule.substring(0, rule.length - 1); } } rulesets = rulesets.join(''); // If this is the root node, we don't render // a selector, or {}. // Otherwise, only output if this ruleset has rules. if (this.root) { css.push(rules.join(env.compress ? '' : '\n')); } else { if (rules.length > 0) { debugInfo = tree.debugInfo(env, this); selector = this.paths.map(function (p) { return p.map(function (s) { return s.toCSS(env); }).join('').trim(); }).join(env.compress ? ',' : ',\n'); // Remove duplicates for (var i = rules.length - 1; i >= 0; i--) { if (rules[i].slice(0, 2) === "/*" || _rules.indexOf(rules[i]) === -1) { _rules.unshift(rules[i]); } } rules = _rules; css.push(debugInfo + selector + (env.compress ? '{' : ' {\n ') + rules.join(env.compress ? '' : '\n ') + (env.compress ? '}' : '\n}\n')); } } css.push(rulesets); return css.join('') + (env.compress ? '\n' : ''); }, joinSelectors: function (paths, context, selectors) { for (var s = 0; s < selectors.length; s++) { this.joinSelector(paths, context, selectors[s]); } }, joinSelector: function (paths, context, selector) { var i, j, k, hasParentSelector, newSelectors, el, sel, parentSel, newSelectorPath, afterParentJoin, newJoinedSelector, newJoinedSelectorEmpty, lastSelector, currentElements, selectorsMultiplied; for (i = 0; i < selector.elements.length; i++) { el = selector.elements[i]; if (el.value === '&') { hasParentSelector = true; } } if (!hasParentSelector) { if (context.length > 0) { for(i = 0; i < context.length; i++) { paths.push(context[i].concat(selector)); } } else { paths.push([selector]); } return; } // The paths are [[Selector]] // The first list is a list of comma seperated selectors // The inner list is a list of inheritance seperated selectors // e.g. // .a, .b { // .c { // } // } // == [[.a] [.c]] [[.b] [.c]] // // the elements from the current selector so far currentElements = []; // the current list of new selectors to add to the path. // We will build it up. We initiate it with one empty selector as we "multiply" the new selectors // by the parents newSelectors = [[]]; for (i = 0; i < selector.elements.length; i++) { el = selector.elements[i]; // non parent reference elements just get added if (el.value !== "&") { currentElements.push(el); } else { // the new list of selectors to add selectorsMultiplied = []; // merge the current list of non parent selector elements // on to the current list of selectors to add if (currentElements.length > 0) { this.mergeElementsOnToSelectors(currentElements, newSelectors); } // loop through our current selectors for(j = 0; j < newSelectors.length; j++) { sel = newSelectors[j]; // if we don't have any parent paths, the & might be in a mixin so that it can be used // whether there are parents or not if (context.length == 0) { // the combinator used on el should now be applied to the next element instead so that // it is not lost if (sel.length > 0) { sel[0].elements = sel[0].elements.slice(0); sel[0].elements.push(new(tree.Element)(el.combinator, '', 0)); //new Element(el.Combinator, "")); } selectorsMultiplied.push(sel); } else { // and the parent selectors for(k = 0; k < context.length; k++) { parentSel = context[k]; // We need to put the current selectors // then join the last selector's elements on to the parents selectors // our new selector path newSelectorPath = []; // selectors from the parent after the join afterParentJoin = []; newJoinedSelectorEmpty = true; //construct the joined selector - if & is the first thing this will be empty, // if not newJoinedSelector will be the last set of elements in the selector if (sel.length > 0) { newSelectorPath = sel.slice(0); lastSelector = newSelectorPath.pop(); newJoinedSelector = new(tree.Selector)(lastSelector.elements.slice(0), selector.extendList); newJoinedSelectorEmpty = false; } else { newJoinedSelector = new(tree.Selector)([], selector.extendList); } //put together the parent selectors after the join if (parentSel.length > 1) { afterParentJoin = afterParentJoin.concat(parentSel.slice(1)); } if (parentSel.length > 0) { newJoinedSelectorEmpty = false; // join the elements so far with the first part of the parent newJoinedSelector.elements.push(new(tree.Element)(el.combinator, parentSel[0].elements[0].value, 0)); newJoinedSelector.elements = newJoinedSelector.elements.concat(parentSel[0].elements.slice(1)); } if (!newJoinedSelectorEmpty) { // now add the joined selector newSelectorPath.push(newJoinedSelector); } // and the rest of the parent newSelectorPath = newSelectorPath.concat(afterParentJoin); // add that to our new set of selectors selectorsMultiplied.push(newSelectorPath); } } } // our new selectors has been multiplied, so reset the state newSelectors = selectorsMultiplied; currentElements = []; } } // if we have any elements left over (e.g. .a& .b == .b) // add them on to all the current selectors if (currentElements.length > 0) { this.mergeElementsOnToSelectors(currentElements, newSelectors); } for(i = 0; i < newSelectors.length; i++) { if (newSelectors[i].length > 0) { paths.push(newSelectors[i]); } } }, mergeElementsOnToSelectors: function(elements, selectors) { var i, sel, extendList; if (selectors.length == 0) { selectors.push([ new(tree.Selector)(elements) ]); return; } for(i = 0; i < selectors.length; i++) { sel = selectors[i]; // if the previous thing in sel is a parent this needs to join on to it if (sel.length > 0) { sel[sel.length - 1] = new(tree.Selector)(sel[sel.length - 1].elements.concat(elements), sel[sel.length - 1].extendList); } else { sel.push(new(tree.Selector)(elements)); } } } }; })(require('../tree')); (function (tree) { tree.Selector = function (elements, extendList) { this.elements = elements; this.extendList = extendList || []; }; tree.Selector.prototype = { type: "Selector", accept: function (visitor) { this.elements = visitor.visit(this.elements); this.extendList = visitor.visit(this.extendList) }, match: function (other) { var elements = this.elements, len = elements.length, oelements, olen, max, i; oelements = other.elements.slice( (other.elements.length && other.elements[0].value === "&") ? 1 : 0); olen = oelements.length; max = Math.min(len, olen); if (olen === 0 || len < olen) { return false; } else { for (i = 0; i < max; i++) { if (elements[i].value !== oelements[i].value) { return false; } } } return true; }, eval: function (env) { return new(tree.Selector)(this.elements.map(function (e) { return e.eval(env); }), this.extendList.map(function(extend) { return extend.eval(env); })); }, toCSS: function (env) { if (this._css) { return this._css } if (this.elements[0].combinator.value === "") { this._css = ' '; } else { this._css = ''; } this._css += this.elements.map(function (e) { if (typeof(e) === 'string') { return ' ' + e.trim(); } else { return e.toCSS(env); } }).join(''); return this._css; } }; })(require('../tree')); (function (tree) { tree.UnicodeDescriptor = function (value) { this.value = value; }; tree.UnicodeDescriptor.prototype = { type: "UnicodeDescriptor", toCSS: function (env) { return this.value; }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.URL = function (val, currentFileInfo) { this.value = val; this.currentFileInfo = currentFileInfo; }; tree.URL.prototype = { type: "Url", accept: function (visitor) { this.value = visitor.visit(this.value); }, toCSS: function () { return "url(" + this.value.toCSS() + ")"; }, eval: function (ctx) { var val = this.value.eval(ctx), rootpath; // Add the base path if the URL is relative rootpath = this.currentFileInfo && this.currentFileInfo.rootpath; if (rootpath && typeof val.value === "string" && ctx.isPathRelative(val.value)) { if (!val.quote) { rootpath = rootpath.replace(/[\(\)'"\s]/g, function(match) { return "\\"+match; }); } val.value = rootpath + val.value; } return new(tree.URL)(val, null); } }; })(require('../tree')); (function (tree) { tree.Value = function (value) { this.value = value; }; tree.Value.prototype = { type: "Value", accept: function (visitor) { this.value = visitor.visit(this.value); }, eval: function (env) { if (this.value.length === 1) { return this.value[0].eval(env); } else { return new(tree.Value)(this.value.map(function (v) { return v.eval(env); })); } }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS(env); }).join(env.compress ? ',' : ', '); } }; })(require('../tree')); (function (tree) { tree.Variable = function (name, index, currentFileInfo) { this.name = name, this.index = index, this.currentFileInfo = currentFileInfo }; tree.Variable.prototype = { type: "Variable", eval: function (env) { var variable, v, name = this.name; if (name.indexOf('@@') == 0) { name = '@' + new(tree.Variable)(name.slice(1)).eval(env).value; } if (this.evaluating) { throw { type: 'Name', message: "Recursive variable definition for " + name, filename: this.currentFileInfo.file, index: this.index }; } this.evaluating = true; if (variable = tree.find(env.frames, function (frame) { if (v = frame.variable(name)) { return v.value.eval(env); } })) { this.evaluating = false; return variable; } else { throw { type: 'Name', message: "variable " + name + " is undefined", filename: this.currentFileInfo.filename, index: this.index }; } } }; })(require('../tree')); (function (tree) { tree.debugInfo = function(env, ctx) { var result=""; if (env.dumpLineNumbers && !env.compress) { switch(env.dumpLineNumbers) { case 'comments': result = tree.debugInfo.asComment(ctx); break; case 'mediaquery': result = tree.debugInfo.asMediaQuery(ctx); break; case 'all': result = tree.debugInfo.asComment(ctx)+tree.debugInfo.asMediaQuery(ctx); break; } } return result; }; tree.debugInfo.asComment = function(ctx) { return '/* line ' + ctx.debugInfo.lineNumber + ', ' + ctx.debugInfo.fileName + ' */\n'; }; tree.debugInfo.asMediaQuery = function(ctx) { return '@media -sass-debug-info{filename{font-family:' + ('file://' + ctx.debugInfo.fileName).replace(/([.:/\\])/g, function(a){if(a=='\\') a = '\/'; return '\\' + a}) + '}line{font-family:\\00003' + ctx.debugInfo.lineNumber + '}}\n'; }; tree.find = function (obj, fun) { for (var i = 0, r; i < obj.length; i++) { if (r = fun.call(obj, obj[i])) { return r } } return null; }; tree.jsify = function (obj) { if (Array.isArray(obj.value) && (obj.value.length > 1)) { return '[' + obj.value.map(function (v) { return v.toCSS(false) }).join(', ') + ']'; } else { return obj.toCSS(false); } }; })(require('./tree')); (function (tree) { var parseCopyProperties = [ 'paths', // option - unmodified - paths to search for imports on 'optimization', // option - optimization level (for the chunker) 'files', // list of files that have been imported, used for import-once 'contents', // browser-only, contents of all the files 'relativeUrls', // option - whether to adjust URL's to be relative 'strictImports', // option - 'dumpLineNumbers', // option - whether to dump line numbers 'compress', // option - whether to compress 'processImports', // option - whether to process imports. if false then imports will not be imported 'mime', // browser only - mime type for sheet import 'currentFileInfo' // information about the current file - for error reporting and importing and making urls relative etc. ]; //currentFileInfo = { // 'relativeUrls' - option - whether to adjust URL's to be relative // 'filename' - full resolved filename of current file // 'rootpath' - path to append to normal URLs for this node // 'currentDirectory' - path to the current file, absolute // 'rootFilename' - filename of the base file // 'entryPath' = absolute path to the entry file tree.parseEnv = function(options) { copyFromOriginal(options, this, parseCopyProperties); if (!this.contents) { this.contents = {}; } if (!this.files) { this.files = {}; } if (!this.currentFileInfo) { var filename = options.filename || "input"; options.filename = null; var entryPath = filename.replace(/[^\/\\]*$/, ""); this.currentFileInfo = { filename: filename, relativeUrls: this.relativeUrls, rootpath: options.rootpath || "", currentDirectory: entryPath, entryPath: entryPath, rootFilename: filename }; } }; tree.parseEnv.prototype.toSheet = function (path) { var env = new tree.parseEnv(this); env.href = path; //env.title = path; env.type = this.mime; return env; }; var evalCopyProperties = [ 'silent', // whether to swallow errors and warnings 'verbose', // whether to log more activity 'compress', // whether to compress 'ieCompat', // whether to enforce IE compatibility (IE8 data-uri) 'strictMath', // whether math has to be within parenthesis 'strictUnits' // whether units need to evaluate correctly ]; tree.evalEnv = function(options, frames) { copyFromOriginal(options, this, evalCopyProperties); this.frames = frames || []; }; tree.evalEnv.prototype.inParenthesis = function () { if (!this.parensStack) { this.parensStack = []; } this.parensStack.push(true); }; tree.evalEnv.prototype.outOfParenthesis = function () { this.parensStack.pop(); }; tree.evalEnv.prototype.isMathOn = function () { return this.strictMath ? (this.parensStack && this.parensStack.length) : true; }; tree.evalEnv.prototype.isPathRelative = function (path) { return !/^(?:[a-z-]+:|\/)/.test(path); }; //todo - do the same for the toCSS env //tree.toCSSEnv = function (options) { //}; var copyFromOriginal = function(original, destination, propertiesToCopy) { if (!original) { return; } for(var i = 0; i < propertiesToCopy.length; i++) { if (original.hasOwnProperty(propertiesToCopy[i])) { destination[propertiesToCopy[i]] = original[propertiesToCopy[i]]; } } } })(require('./tree'));(function (tree) { tree.visitor = function(implementation) { this._implementation = implementation; }; tree.visitor.prototype = { visit: function(node) { if (node instanceof Array) { return this.visitArray(node); } if (!node || !node.type) { return node; } var funcName = "visit" + node.type, func = this._implementation[funcName], visitArgs, newNode; if (func) { visitArgs = {visitDeeper: true}; newNode = func.call(this._implementation, node, visitArgs); if (this._implementation.isReplacing) { node = newNode; } } if ((!visitArgs || visitArgs.visitDeeper) && node && node.accept) { node.accept(this); } funcName = funcName + "Out"; if (this._implementation[funcName]) { this._implementation[funcName](node); } return node; }, visitArray: function(nodes) { var i, newNodes = []; for(i = 0; i < nodes.length; i++) { var evald = this.visit(nodes[i]); if (evald instanceof Array) { newNodes = newNodes.concat(evald); } else { newNodes.push(evald); } } if (this._implementation.isReplacing) { return newNodes; } return nodes; } }; })(require('./tree'));(function (tree) { tree.importVisitor = function(importer, finish, evalEnv) { this._visitor = new tree.visitor(this); this._importer = importer; this._finish = finish; this.env = evalEnv || new tree.evalEnv(); this.importCount = 0; }; tree.importVisitor.prototype = { isReplacing: true, run: function (root) { var error; try { // process the contents this._visitor.visit(root); } catch(e) { error = e; } this.isFinished = true; if (this.importCount === 0) { this._finish(error); } }, visitImport: function (importNode, visitArgs) { var importVisitor = this, evaldImportNode; if (!importNode.css) { try { evaldImportNode = importNode.evalForImport(this.env); } catch(e){ if (!e.filename) { e.index = importNode.index; e.filename = importNode.currentFileInfo.filename; } // attempt to eval properly and treat as css importNode.css = true; // if that fails, this error will be thrown importNode.error = e; } if (evaldImportNode && !evaldImportNode.css) { importNode = evaldImportNode; this.importCount++; var env = new tree.evalEnv(this.env, this.env.frames.slice(0)); this._importer.push(importNode.getPath(), importNode.currentFileInfo, function (e, root, imported) { if (e && !e.filename) { e.index = importNode.index; e.filename = importNode.currentFileInfo.filename; } if (imported && !importNode.options.multiple) { importNode.skip = imported; } var subFinish = function(e) { importVisitor.importCount--; if (importVisitor.importCount === 0 && importVisitor.isFinished) { importVisitor._finish(e); } }; if (root) { importNode.root = root; new(tree.importVisitor)(importVisitor._importer, subFinish, env) .run(root); } else { subFinish(); } }); } } visitArgs.visitDeeper = false; return importNode; }, visitRule: function (ruleNode, visitArgs) { visitArgs.visitDeeper = false; return ruleNode; }, visitDirective: function (directiveNode, visitArgs) { this.env.frames.unshift(directiveNode); return directiveNode; }, visitDirectiveOut: function (directiveNode) { this.env.frames.shift(); }, visitMixinDefinition: function (mixinDefinitionNode, visitArgs) { this.env.frames.unshift(mixinDefinitionNode); return mixinDefinitionNode; }, visitMixinDefinitionOut: function (mixinDefinitionNode) { this.env.frames.shift(); }, visitRuleset: function (rulesetNode, visitArgs) { this.env.frames.unshift(rulesetNode); return rulesetNode; }, visitRulesetOut: function (rulesetNode) { this.env.frames.shift(); }, visitMedia: function (mediaNode, visitArgs) { this.env.frames.unshift(mediaNode.ruleset); return mediaNode; }, visitMediaOut: function (mediaNode) { this.env.frames.shift(); } }; })(require('./tree'));(function (tree) { tree.joinSelectorVisitor = function() { this.contexts = [[]]; this._visitor = new tree.visitor(this); }; tree.joinSelectorVisitor.prototype = { run: function (root) { return this._visitor.visit(root); }, visitRule: function (ruleNode, visitArgs) { visitArgs.visitDeeper = false; }, visitMixinDefinition: function (mixinDefinitionNode, visitArgs) { visitArgs.visitDeeper = false; }, visitRuleset: function (rulesetNode, visitArgs) { var context = this.contexts[this.contexts.length - 1]; var paths = []; this.contexts.push(paths); if (! rulesetNode.root) { rulesetNode.joinSelectors(paths, context, rulesetNode.selectors); rulesetNode.paths = paths; } }, visitRulesetOut: function (rulesetNode) { this.contexts.length = this.contexts.length - 1; }, visitMedia: function (mediaNode, visitArgs) { var context = this.contexts[this.contexts.length - 1]; mediaNode.ruleset.root = (context.length === 0 || context[0].multiMedia); } }; })(require('./tree'));(function (tree) { tree.extendFinderVisitor = function() { this._visitor = new tree.visitor(this); this.contexts = []; this.allExtendsStack = [[]]; }; tree.extendFinderVisitor.prototype = { run: function (root) { root = this._visitor.visit(root); root.allExtends = this.allExtendsStack[0]; return root; }, visitRule: function (ruleNode, visitArgs) { visitArgs.visitDeeper = false; }, visitMixinDefinition: function (mixinDefinitionNode, visitArgs) { visitArgs.visitDeeper = false; }, visitRuleset: function (rulesetNode, visitArgs) { if (rulesetNode.root) { return; } var i, j, extend, allSelectorsExtendList = [], extendList; // get &:extend(.a); rules which apply to all selectors in this ruleset for(i = 0; i < rulesetNode.rules.length; i++) { if (rulesetNode.rules[i] instanceof tree.Extend) { allSelectorsExtendList.push(rulesetNode.rules[i]); } } // now find every selector and apply the extends that apply to all extends // and the ones which apply to an individual extend for(i = 0; i < rulesetNode.paths.length; i++) { var selectorPath = rulesetNode.paths[i], selector = selectorPath[selectorPath.length-1]; extendList = selector.extendList.slice(0).concat(allSelectorsExtendList).map(function(allSelectorsExtend) { return allSelectorsExtend.clone(); }); for(j = 0; j < extendList.length; j++) { this.foundExtends = true; extend = extendList[j]; extend.findSelfSelectors(selectorPath); extend.ruleset = rulesetNode; if (j === 0) { extend.firstExtendOnThisSelectorPath = true; } this.allExtendsStack[this.allExtendsStack.length-1].push(extend); } } this.contexts.push(rulesetNode.selectors); }, visitRulesetOut: function (rulesetNode) { if (!rulesetNode.root) { this.contexts.length = this.contexts.length - 1; } }, visitMedia: function (mediaNode, visitArgs) { mediaNode.allExtends = []; this.allExtendsStack.push(mediaNode.allExtends); }, visitMediaOut: function (mediaNode) { this.allExtendsStack.length = this.allExtendsStack.length - 1; }, visitDirective: function (directiveNode, visitArgs) { directiveNode.allExtends = []; this.allExtendsStack.push(directiveNode.allExtends); }, visitDirectiveOut: function (directiveNode) { this.allExtendsStack.length = this.allExtendsStack.length - 1; } }; tree.processExtendsVisitor = function() { this._visitor = new tree.visitor(this); }; tree.processExtendsVisitor.prototype = { run: function(root) { var extendFinder = new tree.extendFinderVisitor(); extendFinder.run(root); if (!extendFinder.foundExtends) { return root; } root.allExtends = root.allExtends.concat(this.doExtendChaining(root.allExtends, root.allExtends)); this.allExtendsStack = [root.allExtends]; return this._visitor.visit(root); }, doExtendChaining: function (extendsList, extendsListTarget, iterationCount) { // // chaining is different from normal extension.. if we extend an extend then we are not just copying, altering and pasting // the selector we would do normally, but we are also adding an extend with the same target selector // this means this new extend can then go and alter other extends // // this method deals with all the chaining work - without it, extend is flat and doesn't work on other extend selectors // this is also the most expensive.. and a match on one selector can cause an extension of a selector we had already processed if // we look at each selector at a time, as is done in visitRuleset var extendIndex, targetExtendIndex, matches, extendsToAdd = [], newSelector, extendVisitor = this, selectorPath, extend, targetExtend; iterationCount = iterationCount || 0; //loop through comparing every extend with every target extend. // a target extend is the one on the ruleset we are looking at copy/edit/pasting in place // e.g. .a:extend(.b) {} and .b:extend(.c) {} then the first extend extends the second one // and the second is the target. // the seperation into two lists allows us to process a subset of chains with a bigger set, as is the // case when processing media queries for(extendIndex = 0; extendIndex < extendsList.length; extendIndex++){ for(targetExtendIndex = 0; targetExtendIndex < extendsListTarget.length; targetExtendIndex++){ extend = extendsList[extendIndex]; targetExtend = extendsListTarget[targetExtendIndex]; // look for circular references if (this.inInheritanceChain(targetExtend, extend)) { continue; } // find a match in the target extends self selector (the bit before :extend) selectorPath = [targetExtend.selfSelectors[0]]; matches = extendVisitor.findMatch(extend, selectorPath); if (matches.length) { // we found a match, so for each self selector.. extend.selfSelectors.forEach(function(selfSelector) { // process the extend as usual newSelector = extendVisitor.extendSelector(matches, selectorPath, selfSelector); // but now we create a new extend from it newExtend = new(tree.Extend)(targetExtend.selector, targetExtend.option, 0); newExtend.selfSelectors = newSelector; // add the extend onto the list of extends for that selector newSelector[newSelector.length-1].extendList = [newExtend]; // record that we need to add it. extendsToAdd.push(newExtend); newExtend.ruleset = targetExtend.ruleset; //remember its parents for circular references newExtend.parents = [targetExtend, extend]; // only process the selector once.. if we have :extend(.a,.b) then multiple // extends will look at the same selector path, so when extending // we know that any others will be duplicates in terms of what is added to the css if (targetExtend.firstExtendOnThisSelectorPath) { newExtend.firstExtendOnThisSelectorPath = true; targetExtend.ruleset.paths.push(newSelector); } }); } } } if (extendsToAdd.length) { // try to detect circular references to stop a stack overflow. // may no longer be needed. this.extendChainCount++; if (iterationCount > 100) { var selectorOne = "{unable to calculate}"; var selectorTwo = "{unable to calculate}"; try { selectorOne = extendsToAdd[0].selfSelectors[0].toCSS(); selectorTwo = extendsToAdd[0].selector.toCSS(); } catch(e) {} throw {message: "extend circular reference detected. One of the circular extends is currently:"+selectorOne+":extend(" + selectorTwo+")"}; } // now process the new extends on the existing rules so that we can handle a extending b extending c ectending d extending e... return extendsToAdd.concat(extendVisitor.doExtendChaining(extendsToAdd, extendsListTarget, iterationCount+1)); } else { return extendsToAdd; } }, inInheritanceChain: function (possibleParent, possibleChild) { if (possibleParent === possibleChild) { return true; } if (possibleChild.parents) { if (this.inInheritanceChain(possibleParent, possibleChild.parents[0])) { return true; } if (this.inInheritanceChain(possibleParent, possibleChild.parents[1])) { return true; } } return false; }, visitRule: function (ruleNode, visitArgs) { visitArgs.visitDeeper = false; }, visitMixinDefinition: function (mixinDefinitionNode, visitArgs) { visitArgs.visitDeeper = false; }, visitSelector: function (selectorNode, visitArgs) { visitArgs.visitDeeper = false; }, visitRuleset: function (rulesetNode, visitArgs) { if (rulesetNode.root) { return; } var matches, pathIndex, extendIndex, allExtends = this.allExtendsStack[this.allExtendsStack.length-1], selectorsToAdd = [], extendVisitor = this; // look at each selector path in the ruleset, find any extend matches and then copy, find and replace for(extendIndex = 0; extendIndex < allExtends.length; extendIndex++) { for(pathIndex = 0; pathIndex < rulesetNode.paths.length; pathIndex++) { selectorPath = rulesetNode.paths[pathIndex]; // extending extends happens initially, before the main pass if (selectorPath[selectorPath.length-1].extendList.length) { continue; } matches = this.findMatch(allExtends[extendIndex], selectorPath); if (matches.length) { allExtends[extendIndex].selfSelectors.forEach(function(selfSelector) { selectorsToAdd.push(extendVisitor.extendSelector(matches, selectorPath, selfSelector)); }); } } } rulesetNode.paths = rulesetNode.paths.concat(selectorsToAdd); }, findMatch: function (extend, haystackSelectorPath) { // // look through the haystack selector path to try and find the needle - extend.selector // returns an array of selector matches that can then be replaced // var haystackSelectorIndex, hackstackSelector, hackstackElementIndex, haystackElement, targetCombinator, i, extendVisitor = this, needleElements = extend.selector.elements, potentialMatches = [], potentialMatch, matches = []; // loop through the haystack elements for(haystackSelectorIndex = 0; haystackSelectorIndex < haystackSelectorPath.length; haystackSelectorIndex++) { hackstackSelector = haystackSelectorPath[haystackSelectorIndex]; for(hackstackElementIndex = 0; hackstackElementIndex < hackstackSelector.elements.length; hackstackElementIndex++) { haystackElement = hackstackSelector.elements[hackstackElementIndex]; // if we allow elements before our match we can add a potential match every time. otherwise only at the first element. if (extend.allowBefore || (haystackSelectorIndex == 0 && hackstackElementIndex == 0)) { potentialMatches.push({pathIndex: haystackSelectorIndex, index: hackstackElementIndex, matched: 0, initialCombinator: haystackElement.combinator}); } for(i = 0; i < potentialMatches.length; i++) { potentialMatch = potentialMatches[i]; // selectors add " " onto the first element. When we use & it joins the selectors together, but if we don't // then each selector in haystackSelectorPath has a space before it added in the toCSS phase. so we need to work out // what the resulting combinator will be targetCombinator = haystackElement.combinator.value; if (targetCombinator == '' && hackstackElementIndex === 0) { targetCombinator = ' '; } // if we don't match, null our match to indicate failure if (!extendVisitor.isElementValuesEqual(needleElements[potentialMatch.matched].value, haystackElement.value) || (potentialMatch.matched > 0 && needleElements[potentialMatch.matched].combinator.value !== targetCombinator)) { potentialMatch = null; } else { potentialMatch.matched++; } // if we are still valid and have finished, test whether we have elements after and whether these are allowed if (potentialMatch) { potentialMatch.finished = potentialMatch.matched === needleElements.length; if (potentialMatch.finished && (!extend.allowAfter && (hackstackElementIndex+1 < hackstackSelector.elements.length || haystackSelectorIndex+1 < haystackSelectorPath.length))) { potentialMatch = null; } } // if null we remove, if not, we are still valid, so either push as a valid match or continue if (potentialMatch) { if (potentialMatch.finished) { potentialMatch.length = needleElements.length; potentialMatch.endPathIndex = haystackSelectorIndex; potentialMatch.endPathElementIndex = hackstackElementIndex + 1; // index after end of match potentialMatches.length = 0; // we don't allow matches to overlap, so start matching again matches.push(potentialMatch); } } else { potentialMatches.splice(i, 1); i--; } } } } return matches; }, isElementValuesEqual: function(elementValue1, elementValue2) { if (typeof elementValue1 === "string" || typeof elementValue2 === "string") { return elementValue1 === elementValue2; } if (elementValue1 instanceof tree.Attribute) { if (elementValue1.op !== elementValue2.op || elementValue1.key !== elementValue2.key) { return false; } if (!elementValue1.value || !elementValue2.value) { if (elementValue1.value || elementValue2.value) { return false; } return true; } elementValue1 = elementValue1.value.value || elementValue1.value; elementValue2 = elementValue2.value.value || elementValue2.value; return elementValue1 === elementValue2; } return false; }, extendSelector:function (matches, selectorPath, replacementSelector) { //for a set of matches, replace each match with the replacement selector var currentSelectorPathIndex = 0, currentSelectorPathElementIndex = 0, path = [], matchIndex, selector, firstElement; for (matchIndex = 0; matchIndex < matches.length; matchIndex++) { match = matches[matchIndex]; selector = selectorPath[match.pathIndex]; firstElement = new tree.Element( match.initialCombinator, replacementSelector.elements[0].value, replacementSelector.elements[0].index ); if (match.pathIndex > currentSelectorPathIndex && currentSelectorPathElementIndex > 0) { path[path.length - 1].elements = path[path.length - 1].elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex)); currentSelectorPathElementIndex = 0; currentSelectorPathIndex++; } path = path.concat(selectorPath.slice(currentSelectorPathIndex, match.pathIndex)); path.push(new tree.Selector( selector.elements .slice(currentSelectorPathElementIndex, match.index) .concat([firstElement]) .concat(replacementSelector.elements.slice(1)) )); currentSelectorPathIndex = match.endPathIndex; currentSelectorPathElementIndex = match.endPathElementIndex; if (currentSelectorPathElementIndex >= selector.elements.length) { currentSelectorPathElementIndex = 0; currentSelectorPathIndex++; } } if (currentSelectorPathIndex < selectorPath.length && currentSelectorPathElementIndex > 0) { path[path.length - 1].elements = path[path.length - 1].elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex)); currentSelectorPathElementIndex = 0; currentSelectorPathIndex++; } path = path.concat(selectorPath.slice(currentSelectorPathIndex, selectorPath.length)); return path; }, visitRulesetOut: function (rulesetNode) { }, visitMedia: function (mediaNode, visitArgs) { var newAllExtends = mediaNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length-1]); newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, mediaNode.allExtends)); this.allExtendsStack.push(newAllExtends); }, visitMediaOut: function (mediaNode) { this.allExtendsStack.length = this.allExtendsStack.length - 1; }, visitDirective: function (directiveNode, visitArgs) { var newAllExtends = directiveNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length-1]); newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, directiveNode.allExtends)); this.allExtendsStack.push(newAllExtends); }, visitDirectiveOut: function (directiveNode) { this.allExtendsStack.length = this.allExtendsStack.length - 1; } }; })(require('./tree'));// // browser.js - client-side engine // var isFileProtocol = /^(file|chrome(-extension)?|resource|qrc|app):/.test(location.protocol); less.env = less.env || (location.hostname == '127.0.0.1' || location.hostname == '0.0.0.0' || location.hostname == 'localhost' || location.port.length > 0 || isFileProtocol ? 'development' : 'production'); // Load styles asynchronously (default: false) // // This is set to `false` by default, so that the body // doesn't start loading before the stylesheets are parsed. // Setting this to `true` can result in flickering. // less.async = less.async || false; less.fileAsync = less.fileAsync || false; // Interval between watch polls less.poll = less.poll || (isFileProtocol ? 1000 : 1500); //Setup user functions if (less.functions) { for(var func in less.functions) { less.tree.functions[func] = less.functions[func]; } } var dumpLineNumbers = /!dumpLineNumbers:(comments|mediaquery|all)/.exec(location.hash); if (dumpLineNumbers) { less.dumpLineNumbers = dumpLineNumbers[1]; } // // Watch mode // less.watch = function () { if (!less.watchMode ){ less.env = 'development'; initRunningMode(); } return this.watchMode = true }; less.unwatch = function () {clearInterval(less.watchTimer); return this.watchMode = false; }; function initRunningMode(){ if (less.env === 'development') { less.optimization = 0; less.watchTimer = setInterval(function () { if (less.watchMode) { loadStyleSheets(function (e, root, _, sheet, env) { if (e) { error(e, sheet.href); } else if (root) { createCSS(root.toCSS(less), sheet, env.lastModified); } }); } }, less.poll); } else { less.optimization = 3; } } if (/!watch/.test(location.hash)) { less.watch(); } var cache = null; if (less.env != 'development') { try { cache = (typeof(window.localStorage) === 'undefined') ? null : window.localStorage; } catch (_) {} } // // Get all tags with the 'rel' attribute set to "stylesheet/less" // var links = document.getElementsByTagName('link'); var typePattern = /^text\/(x-)?less$/; less.sheets = []; for (var i = 0; i < links.length; i++) { if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) && (links[i].type.match(typePattern)))) { less.sheets.push(links[i]); } } // // With this function, it's possible to alter variables and re-render // CSS without reloading less-files // var session_cache = ''; less.modifyVars = function(record) { var str = session_cache; for (name in record) { str += ((name.slice(0,1) === '@')? '' : '@') + name +': '+ ((record[name].slice(-1) === ';')? record[name] : record[name] +';'); } new(less.Parser)(new less.tree.parseEnv(less)).parse(str, function (e, root) { if (e) { error(e, "session_cache"); } else { createCSS(root.toCSS(less), less.sheets[less.sheets.length - 1]); } }); }; less.refresh = function (reload) { var startTime, endTime; startTime = endTime = new(Date); loadStyleSheets(function (e, root, _, sheet, env) { if (e) { return error(e, sheet.href); } if (env.local) { log("loading " + sheet.href + " from cache."); } else { log("parsed " + sheet.href + " successfully."); createCSS(root.toCSS(less), sheet, env.lastModified); } log("css for " + sheet.href + " generated in " + (new(Date) - endTime) + 'ms'); (env.remaining === 0) && log("css generated in " + (new(Date) - startTime) + 'ms'); endTime = new(Date); }, reload); loadStyles(); }; less.refreshStyles = loadStyles; less.refresh(less.env === 'development'); function loadStyles() { var styles = document.getElementsByTagName('style'); for (var i = 0; i < styles.length; i++) { if (styles[i].type.match(typePattern)) { var env = new less.tree.parseEnv(less); env.filename = document.location.href.replace(/#.*$/, ''); new(less.Parser)(env).parse(styles[i].innerHTML || '', function (e, cssAST) { if (e) { return error(e, "inline"); } var css = cssAST.toCSS(less); var style = styles[i]; style.type = 'text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.innerHTML = css; } }); } } } function loadStyleSheets(callback, reload) { for (var i = 0; i < less.sheets.length; i++) { loadStyleSheet(less.sheets[i], callback, reload, less.sheets.length - (i + 1)); } } function pathDiff(url, baseUrl) { // diff between two paths to create a relative path var urlParts = extractUrlParts(url), baseUrlParts = extractUrlParts(baseUrl), i, max, urlDirectories, baseUrlDirectories, diff = ""; if (urlParts.hostPart !== baseUrlParts.hostPart) { return ""; } max = Math.max(baseUrlParts.directories.length, urlParts.directories.length); for(i = 0; i < max; i++) { if (baseUrlParts.directories[i] !== urlParts.directories[i]) { break; } } baseUrlDirectories = baseUrlParts.directories.slice(i); urlDirectories = urlParts.directories.slice(i); for(i = 0; i < baseUrlDirectories.length-1; i++) { diff += "../"; } for(i = 0; i < urlDirectories.length-1; i++) { diff += urlDirectories[i] + "/"; } return diff; } function extractUrlParts(url, baseUrl) { // urlParts[1] = protocol&hostname || / // urlParts[2] = / if path relative to host base // urlParts[3] = directories // urlParts[4] = filename // urlParts[5] = parameters var urlPartsRegex = /^((?:[a-z-]+:)?\/+?(?:[^\/\?#]*\/)|([\/\\]))?((?:[^\/\\\?#]*[\/\\])*)([^\/\\\?#]*)([#\?].*)?$/, urlParts = url.match(urlPartsRegex), returner = {}, directories = [], i, baseUrlParts; if (!urlParts) { throw new Error("Could not parse sheet href - '"+url+"'"); } // Stylesheets in IE don't always return the full path if (!urlParts[1] || urlParts[2]) { baseUrlParts = baseUrl.match(urlPartsRegex); if (!baseUrlParts) { throw new Error("Could not parse page url - '"+baseUrl+"'"); } urlParts[1] = urlParts[1] || baseUrlParts[1] || ""; if (!urlParts[2]) { urlParts[3] = baseUrlParts[3] + urlParts[3]; } } if (urlParts[3]) { directories = urlParts[3].replace("\\", "/").split("/"); // extract out . before .. so .. doesn't absorb a non-directory for(i = 0; i < directories.length; i++) { if (directories[i] === ".") { directories.splice(i, 1); i -= 1; } } for(i = 0; i < directories.length; i++) { if (directories[i] === ".." && i > 0) { directories.splice(i-1, 2); i -= 2; } } } returner.hostPart = urlParts[1]; returner.directories = directories; returner.path = urlParts[1] + directories.join("/"); returner.fileUrl = returner.path + (urlParts[4] || ""); returner.url = returner.fileUrl + (urlParts[5] || ""); return returner; } function loadStyleSheet(sheet, callback, reload, remaining) { // sheet may be set to the stylesheet for the initial load or a collection of properties including // some env variables for imports var hrefParts = extractUrlParts(sheet.href, window.location.href); var href = hrefParts.url; var css = cache && cache.getItem(href); var timestamp = cache && cache.getItem(href + ':timestamp'); var styles = { css: css, timestamp: timestamp }; var env; var newFileInfo = { relativeUrls: less.relativeUrls, currentDirectory: hrefParts.path, filename: href }; if (sheet instanceof less.tree.parseEnv) { env = new less.tree.parseEnv(sheet); newFileInfo.entryPath = env.currentFileInfo.entryPath; newFileInfo.rootpath = env.currentFileInfo.rootpath; newFileInfo.rootFilename = env.currentFileInfo.rootFilename; } else { env = new less.tree.parseEnv(less); env.mime = sheet.type; newFileInfo.entryPath = hrefParts.path; newFileInfo.rootpath = less.rootpath || hrefParts.path; newFileInfo.rootFilename = href; } if (env.relativeUrls) { //todo - this relies on option being set on less object rather than being passed in as an option // - need an originalRootpath if (less.rootpath) { newFileInfo.rootpath = extractUrlParts(less.rootpath + pathDiff(hrefParts.path, newFileInfo.entryPath)).path; } else { newFileInfo.rootpath = hrefParts.path; } } xhr(href, sheet.type, function (data, lastModified) { // Store data this session session_cache += data.replace(/@import .+?;/ig, ''); if (!reload && styles && lastModified && (new(Date)(lastModified).valueOf() === new(Date)(styles.timestamp).valueOf())) { // Use local copy createCSS(styles.css, sheet); callback(null, null, data, sheet, { local: true, remaining: remaining }, href); } else { // Use remote copy (re-parse) try { env.contents[href] = data; // Updating content cache env.paths = [hrefParts.path]; env.currentFileInfo = newFileInfo; new(less.Parser)(env).parse(data, function (e, root) { if (e) { return callback(e, null, null, sheet); } try { callback(e, root, data, sheet, { local: false, lastModified: lastModified, remaining: remaining }, href); //TODO - there must be a better way? A generic less-to-css function that can both call error //and removeNode where appropriate //should also add tests if (env.currentFileInfo.rootFilename === href) { removeNode(document.getElementById('less-error-message:' + extractId(href))); } } catch (e) { callback(e, null, null, sheet); } }); } catch (e) { callback(e, null, null, sheet); } } }, function (status, url) { callback({ type: 'File', message: "'" + url + "' wasn't found (" + status + ")" }, null, null, sheet); }); } function extractId(href) { return href.replace(/^[a-z-]+:\/+?[^\/]+/, '' ) // Remove protocol & domain .replace(/^\//, '' ) // Remove root / .replace(/\.[a-zA-Z]+$/, '' ) // Remove simple extension .replace(/[^\.\w-]+/g, '-') // Replace illegal characters .replace(/\./g, ':'); // Replace dots with colons(for valid id) } function createCSS(styles, sheet, lastModified) { // Strip the query-string var href = sheet.href || ''; // If there is no title set, use the filename, minus the extension var id = 'less:' + (sheet.title || extractId(href)); // If this has already been inserted into the DOM, we may need to replace it var oldCss = document.getElementById(id); var keepOldCss = false; // Create a new stylesheet node for insertion or (if necessary) replacement var css = document.createElement('style'); css.setAttribute('type', 'text/css'); if (sheet.media) { css.setAttribute('media', sheet.media); } css.id = id; if (css.styleSheet) { // IE try { css.styleSheet.cssText = styles; } catch (e) { throw new(Error)("Couldn't reassign styleSheet.cssText."); } } else { css.appendChild(document.createTextNode(styles)); // If new contents match contents of oldCss, don't replace oldCss keepOldCss = (oldCss !== null && oldCss.childNodes.length > 0 && css.childNodes.length > 0 && oldCss.firstChild.nodeValue === css.firstChild.nodeValue); } var head = document.getElementsByTagName('head')[0]; // If there is no oldCss, just append; otherwise, only append if we need // to replace oldCss with an updated stylesheet if (oldCss == null || keepOldCss === false) { var nextEl = sheet && sheet.nextSibling || null; (nextEl || document.getElementsByTagName('head')[0]).parentNode.insertBefore(css, nextEl); } if (oldCss && keepOldCss === false) { head.removeChild(oldCss); } // Don't update the local store if the file wasn't modified if (lastModified && cache) { log('saving ' + href + ' to cache.'); try { cache.setItem(href, styles); cache.setItem(href + ':timestamp', lastModified); } catch(e) { //TODO - could do with adding more robust error handling log('failed to save'); } } } function xhr(url, type, callback, errback) { var xhr = getXMLHttpRequest(); var async = isFileProtocol ? less.fileAsync : less.async; if (typeof(xhr.overrideMimeType) === 'function') { xhr.overrideMimeType('text/css'); } xhr.open('GET', url, async); xhr.setRequestHeader('Accept', type || 'text/x-less, text/css; q=0.9, */*; q=0.5'); xhr.send(null); if (isFileProtocol && !less.fileAsync) { if (xhr.status === 0 || (xhr.status >= 200 && xhr.status < 300)) { callback(xhr.responseText); } else { errback(xhr.status, url); } } else if (async) { xhr.onreadystatechange = function () { if (xhr.readyState == 4) { handleResponse(xhr, callback, errback); } }; } else { handleResponse(xhr, callback, errback); } function handleResponse(xhr, callback, errback) { if (xhr.status >= 200 && xhr.status < 300) { callback(xhr.responseText, xhr.getResponseHeader("Last-Modified")); } else if (typeof(errback) === 'function') { errback(xhr.status, url); } } } function getXMLHttpRequest() { if (window.XMLHttpRequest) { return new(XMLHttpRequest); } else { try { return new(ActiveXObject)("MSXML2.XMLHTTP.3.0"); } catch (e) { log("browser doesn't support AJAX."); return null; } } } function removeNode(node) { return node && node.parentNode.removeChild(node); } function log(str) { if (less.env == 'development' && typeof(console) !== "undefined") { console.log('less: ' + str) } } function error(e, rootHref) { var id = 'less-error-message:' + extractId(rootHref || ""); var template = '
  • {content}
  • '; var elem = document.createElement('div'), timer, content, error = []; var filename = e.filename || rootHref; var filenameNoPath = filename.match(/([^\/]+(\?.*)?)$/)[1]; elem.id = id; elem.className = "less-error-message"; content = '

    ' + (e.type || "Syntax") + "Error: " + (e.message || 'There is an error in your .less file') + '

    ' + '

    in ' + filenameNoPath + " "; var errorline = function (e, i, classname) { if (e.extract[i] != undefined) { error.push(template.replace(/\{line\}/, (parseInt(e.line) || 0) + (i - 1)) .replace(/\{class\}/, classname) .replace(/\{content\}/, e.extract[i])); } }; if (e.extract) { errorline(e, 0, ''); errorline(e, 1, 'line'); errorline(e, 2, ''); content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':

    ' + '
      ' + error.join('') + '
    '; } else if (e.stack) { content += '
    ' + e.stack.split('\n').slice(1).join('
    '); } elem.innerHTML = content; // CSS for error messages createCSS([ '.less-error-message ul, .less-error-message li {', 'list-style-type: none;', 'margin-right: 15px;', 'padding: 4px 0;', 'margin: 0;', '}', '.less-error-message label {', 'font-size: 12px;', 'margin-right: 15px;', 'padding: 4px 0;', 'color: #cc7777;', '}', '.less-error-message pre {', 'color: #dd6666;', 'padding: 4px 0;', 'margin: 0;', 'display: inline-block;', '}', '.less-error-message pre.line {', 'color: #ff0000;', '}', '.less-error-message h3 {', 'font-size: 20px;', 'font-weight: bold;', 'padding: 15px 0 5px 0;', 'margin: 0;', '}', '.less-error-message a {', 'color: #10a', '}', '.less-error-message .error {', 'color: red;', 'font-weight: bold;', 'padding-bottom: 2px;', 'border-bottom: 1px dashed red;', '}' ].join('\n'), { title: 'error-message' }); elem.style.cssText = [ "font-family: Arial, sans-serif", "border: 1px solid #e00", "background-color: #eee", "border-radius: 5px", "-webkit-border-radius: 5px", "-moz-border-radius: 5px", "color: #e00", "padding: 15px", "margin-bottom: 15px" ].join(';'); if (less.env == 'development') { timer = setInterval(function () { if (document.body) { if (document.getElementById(id)) { document.body.replaceChild(elem, document.getElementById(id)); } else { document.body.insertBefore(elem, document.body.firstChild); } clearInterval(timer); } }, 10); } } // amd.js // // Define Less as an AMD module. if (typeof define === "function" && define.amd) { define(function () { return less; } ); } })(window); less.js-1.4.2/dist/less-1.4.0-beta.min.js000066400000000000000000002324071217256642200175160ustar00rootroot00000000000000/* * LESS - Leaner CSS v1.4.0 * http://lesscss.org * * Copyright (c) 2009-2013, Alexis Sellier * Licensed under the Apache 2.0 License. * * @licence */(function(e,t){function n(t){return e.less[t.split("/")[1]]}function f(){r.env==="development"?(r.optimization=0,r.watchTimer=setInterval(function(){r.watchMode&&g(function(e,t,n,i,s){e?k(e,i.href):t&&S(t.toCSS(r),i,s.lastModified)})},r.poll)):r.optimization=3}function m(){var e=document.getElementsByTagName("style");for(var t=0;t0&&(s.splice(o-1,2),o-=2)}return i.hostPart=r[1],i.directories=s,i.path=r[1]+s.join("/"),i.fileUrl=i.path+(r[4]||""),i.url=i.fileUrl+(r[5]||""),i}function w(t,n,i,s){var o=b(t.href,e.location.href),u=o.url,a=l&&l.getItem(u),f=l&&l.getItem(u+":timestamp"),c={css:a,timestamp:f},h,p={relativeUrls:r.relativeUrls,currentDirectory:o.path,filename:u};t instanceof r.tree.parseEnv?(h=new r.tree.parseEnv(t),p.entryPath=h.currentFileInfo.entryPath,p.rootpath=h.currentFileInfo.rootpath,p.rootFilename=h.currentFileInfo.rootFilename):(h=new r.tree.parseEnv(r),h.mime=t.type,p.entryPath=o.path,p.rootpath=r.rootpath||o.path,p.rootFilename=u),h.relativeUrls&&(r.rootpath?p.rootpath=b(r.rootpath+y(o.path,p.entryPath)).path:p.rootpath=o.path),x(u,t.type,function(e,a){v+=e.replace(/@import .+?;/ig,"");if(!i&&c&&a&&(new Date(a)).valueOf()===(new Date(c.timestamp)).valueOf())S(c.css,t),n(null,null,e,t,{local:!0,remaining:s},u);else try{h.contents[u]=e,h.paths=[o.path],h.currentFileInfo=p,(new r.Parser(h)).parse(e,function(r,i){if(r)return n(r,null,null,t);try{n(r,i,e,t,{local:!1,lastModified:a,remaining:s},u),h.currentFileInfo.rootFilename===u&&N(document.getElementById("less-error-message:"+E(u)))}catch(r){n(r,null,null,t)}})}catch(f){n(f,null,null,t)}},function(e,r){n({type:"File",message:"'"+r+"' wasn't found ("+e+")"},null,null,t)})}function E(e){return e.replace(/^[a-z-]+:\/+?[^\/]+/,"").replace(/^\//,"").replace(/\.[a-zA-Z]+$/,"").replace(/[^\.\w-]+/g,"-").replace(/\./g,":")}function S(e,t,n){var r=t.href||"",i="less:"+(t.title||E(r)),s=document.getElementById(i),o=!1,u=document.createElement("style");u.setAttribute("type","text/css"),t.media&&u.setAttribute("media",t.media),u.id=i;if(u.styleSheet)try{u.styleSheet.cssText=e}catch(a){throw new Error("Couldn't reassign styleSheet.cssText.")}else u.appendChild(document.createTextNode(e)),o=s!==null&&s.childNodes.length>0&&u.childNodes.length>0&&s.firstChild.nodeValue===u.firstChild.nodeValue;var f=document.getElementsByTagName("head")[0];if(s==null||o===!1){var c=t&&t.nextSibling||null;(c||document.getElementsByTagName("head")[0]).parentNode.insertBefore(u,c)}s&&o===!1&&f.removeChild(s);if(n&&l){C("saving "+r+" to cache.");try{l.setItem(r,e),l.setItem(r+":timestamp",n)}catch(a){C("failed to save")}}}function x(e,t,n,i){function a(t,n,r){t.status>=200&&t.status<300?n(t.responseText,t.getResponseHeader("Last-Modified")):typeof r=="function"&&r(t.status,e)}var s=T(),u=o?r.fileAsync:r.async;typeof s.overrideMimeType=="function"&&s.overrideMimeType("text/css"),s.open("GET",e,u),s.setRequestHeader("Accept",t||"text/x-less, text/css; q=0.9, */*; q=0.5"),s.send(null),o&&!r.fileAsync?s.status===0||s.status>=200&&s.status<300?n(s.responseText):i(s.status,e):u?s.onreadystatechange=function(){s.readyState==4&&a(s,n,i)}:a(s,n,i)}function T(){if(e.XMLHttpRequest)return new XMLHttpRequest;try{return new ActiveXObject("MSXML2.XMLHTTP.3.0")}catch(t){return C("browser doesn't support AJAX."),null}}function N(e){return e&&e.parentNode.removeChild(e)}function C(e){r.env=="development"&&typeof console!="undefined"&&console.log("less: "+e)}function k(e,n){var i="less-error-message:"+E(n||""),s='
  • {content}
  • ',o=document.createElement("div"),u,a,f=[],l=e.filename||n,c=l.match(/([^\/]+(\?.*)?)$/)[1];o.id=i,o.className="less-error-message",a="

    "+(e.type||"Syntax")+"Error: "+(e.message||"There is an error in your .less file")+"

    "+'

    in '+c+" ";var h=function(e,n,r){e.extract[n]!=t&&f.push(s.replace(/\{line\}/,(parseInt(e.line)||0)+(n-1)).replace(/\{class\}/,r).replace(/\{content\}/,e.extract[n]))};e.extract?(h(e,0,""),h(e,1,"line"),h(e,2,""),a+="on line "+e.line+", column "+(e.column+1)+":

    "+"
      "+f.join("")+"
    "):e.stack&&(a+="
    "+e.stack.split("\n").slice(1).join("
    ")),o.innerHTML=a,S([".less-error-message ul, .less-error-message li {","list-style-type: none;","margin-right: 15px;","padding: 4px 0;","margin: 0;","}",".less-error-message label {","font-size: 12px;","margin-right: 15px;","padding: 4px 0;","color: #cc7777;","}",".less-error-message pre {","color: #dd6666;","padding: 4px 0;","margin: 0;","display: inline-block;","}",".less-error-message pre.line {","color: #ff0000;","}",".less-error-message h3 {","font-size: 20px;","font-weight: bold;","padding: 15px 0 5px 0;","margin: 0;","}",".less-error-message a {","color: #10a","}",".less-error-message .error {","color: red;","font-weight: bold;","padding-bottom: 2px;","border-bottom: 1px dashed red;","}"].join("\n"),{title:"error-message"}),o.style.cssText=["font-family: Arial, sans-serif","border: 1px solid #e00","background-color: #eee","border-radius: 5px","-webkit-border-radius: 5px","-moz-border-radius: 5px","color: #e00","padding: 15px","margin-bottom: 15px"].join(";"),r.env=="development"&&(u=setInterval(function(){document.body&&(document.getElementById(i)?document.body.replaceChild(o,document.getElementById(i)):document.body.insertBefore(o,document.body.firstChild),clearInterval(u))},10))}var r,i,s;typeof environment=="object"&&{}.toString.call(environment)==="[object Environment]"?(typeof e=="undefined"?r={}:r=e.less={},i=r.tree={},r.mode="rhino"):typeof e=="undefined"?(r=exports,i=n("./tree"),r.mode="node"):(typeof e.less=="undefined"&&(e.less={}),r=e.less,i=e.less.tree={},r.mode="browser"),r.Parser=function(t){function m(){a=c[u],f=o,h=o}function g(){c[u]=a,o=f,h=o}function y(){o>h&&(c[u]=c[u].slice(o-h),h=o)}function b(e){var t=e.charCodeAt(0);return t===32||t===10||t===9}function w(e){var t,n,r,i,a;if(e instanceof Function)return e.call(p.parsers);if(typeof e=="string")t=s.charAt(o)===e?e:null,r=1,y();else{y();if(!(t=e.exec(c[u])))return null;r=t[0].length}if(t)return E(r),typeof t=="string"?t:t.length===1?t[0]:t}function E(e){var t=o,n=u,r=o+c[u].length,i=o+=e;while(o=0&&t.charAt(n)!=="\n";n--)r++;return{line:typeof e=="number"?(t.slice(0,e).match(/\n/g)||"").length:null,column:r}}function k(e,t,i){var s=i.currentFileInfo.filename;return r.mode!=="browser"&&r.mode!=="rhino"&&(s=n("path").resolve(s)),{lineNumber:C(e,t).line+1,fileName:s}}function L(e,t){var n=N(e,t),r=C(e.index,n),i=r.line,s=r.column,o=n.split("\n");this.type=e.type||"Syntax",this.message=e.message,this.filename=e.filename||t.currentFileInfo.filename,this.index=e.index,this.line=typeof i=="number"?i+1:null,this.callLine=e.call&&C(e.call,n).line+1,this.callExtract=o[C(e.call,n).line],this.stack=e.stack,this.column=s,this.extract=[o[i-1],o[i],o[i+1]]}var s,o,u,a,f,l,c,h,p,d=this;t instanceof i.parseEnv||(t=new i.parseEnv(t));var v=this.imports={paths:t.paths||[],queue:[],files:t.files,contents:t.contents,mime:t.mime,error:null,push:function(e,n,i){var s=this;this.queue.push(e),r.Parser.importer(e,n,function(t,n,r){s.queue.splice(s.queue.indexOf(e),1);var o=r in s.files;s.files[r]=n,t&&!s.error&&(s.error=t),i(t,n,o)},t)}};return L.prototype=new Error,L.prototype.constructor=L,this.env=t=t||{},this.optimization="optimization"in this.env?this.env.optimization:1,p={imports:v,parse:function(e,a){var f,d,v,m,g,y,b=[],E,S=null;o=u=h=l=0,s=e.replace(/\r\n/g,"\n"),s=s.replace(/^\uFEFF/,""),c=function(e){var n=0,r=/(?:@\{[\w-]+\}|[^"'`\{\}\/\(\)\\])+/g,i=/\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g,o=/"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'|`((?:[^`]|\\.)*)`/g,u=0,a,f=e[0],l;for(var c=0,h,p;c0?"missing closing `}`":"missing opening `{`",filename:t.currentFileInfo.filename},t)),e.map(function(e){return e.join("")})}([[]]);if(S)return a(new L(S,t));try{f=new i.Ruleset([],w(this.parsers.primary)),f.root=!0,f.firstRoot=!0}catch(x){return a(new L(x,t))}f.toCSS=function(e){var s,o,u;return function(s,o){s=s||{};var u,a=new i.evalEnv(s);typeof o=="object"&&!Array.isArray(o)&&(o=Object.keys(o).map(function(e){var t=o[e];return t instanceof i.Value||(t instanceof i.Expression||(t=new i.Expression([t])),t=new i.Value([t])),new i.Rule("@"+e,t,!1,0)}),a.frames=[new i.Ruleset(null,o)]);try{var f=e.call(this,a);(new i.joinSelectorVisitor).run(f),(new i.processExtendsVisitor).run(f);var l=f.toCSS({compress:Boolean(s.compress),dumpLineNumbers:t.dumpLineNumbers,strictUnits:Boolean(s.strictUnits)})}catch(c){throw new L(c,t)}return s.yuicompress&&r.mode==="node"?n("ycssmin").cssmin(l,s.maxLineLen):s.compress?l.replace(/(\s)+/g,"$1"):l}}(f.eval);if(o=0&&s.charAt(T)!=="\n";T--)N++;S={type:"Parse",message:"Unrecognised input",index:o,filename:t.currentFileInfo.filename,line:g,column:N,extract:[y[g-2],y[g-1],y[g]]}}var C=function(e){e=S||e||p.imports.error,e?(e instanceof L||(e=new L(e,t)),a(e)):a(null,f)};t.processImports!==!1?(new i.importVisitor(this.imports,C)).run(f):C()},parsers:{primary:function(){var e,t=[];while((e=w(this.extendRule)||w(this.mixin.definition)||w(this.rule)||w(this.ruleset)||w(this.mixin.call)||w(this.comment)||w(this.directive))||w(/^[\s\n]+/)||w(/^;+/))e&&t.push(e);return t},comment:function(){var e;if(s.charAt(o)!=="/")return;if(s.charAt(o+1)==="/")return new i.Comment(w(/^\/\/.*/),!0);if(e=w(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/))return new i.Comment(e)},entities:{quoted:function(){var e,n=o,r,u=o;s.charAt(n)==="~"&&(n++,r=!0);if(s.charAt(n)!=='"'&&s.charAt(n)!=="'")return;r&&w("~");if(e=w(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/))return new i.Quoted(e[0],e[1]||e[2],r,u,t.currentFileInfo)},keyword:function(){var e;if(e=w(/^[_A-Za-z-][_A-Za-z0-9-]*/))return i.colors.hasOwnProperty(e)?new i.Color(i.colors[e].slice(1)):new i.Keyword(e)},call:function(){var e,n,r,s,a=o;if(!(e=/^([\w-]+|%|progid:[\w\.]+)\(/.exec(c[u])))return;e=e[1],n=e.toLowerCase();if(n==="url")return null;o+=e.length;if(n==="alpha"){s=w(this.alpha);if(typeof s!="undefined")return s}w("("),r=w(this.entities.arguments);if(!w(")"))return;if(e)return new i.Call(e,r,a,t.currentFileInfo)},arguments:function(){var e=[],t;while(t=w(this.entities.assignment)||w(this.expression)){e.push(t);if(!w(","))break}return e},literal:function(){return w(this.entities.dimension)||w(this.entities.color)||w(this.entities.quoted)||w(this.entities.unicodeDescriptor)},assignment:function(){var e,t;if((e=w(/^\w+(?=\s?=)/i))&&w("=")&&(t=w(this.entity)))return new i.Assignment(e,t)},url:function(){var e;if(s.charAt(o)!=="u"||!w(/^url\(/))return;return e=w(this.entities.quoted)||w(this.entities.variable)||w(/^(?:(?:\\[\(\)'"])|[^\(\)'"])+/)||"",S(")"),new i.URL(e.value!=null||e instanceof i.Variable?e:new i.Anonymous(e),t.currentFileInfo)},variable:function(){var e,n=o;if(s.charAt(o)==="@"&&(e=w(/^@@?[\w-]+/)))return new i.Variable(e,n,t.currentFileInfo)},variableCurly:function(){var e,n,r=o;if(s.charAt(o)==="@"&&(n=w(/^@\{([\w-]+)\}/)))return new i.Variable("@"+n[1],r,t.currentFileInfo)},color:function(){var e;if(s.charAt(o)==="#"&&(e=w(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/)))return new i.Color(e[1])},dimension:function(){var e,t=s.charCodeAt(o);if(t>57||t<43||t===47||t==44)return;if(e=w(/^([+-]?\d*\.?\d+)(%|[a-z]+)?/))return new i.Dimension(e[1],e[2])},unicodeDescriptor:function(){var e;if(e=w(/^U\+[0-9a-fA-F?]+(\-[0-9a-fA-F?]+)?/))return new i.UnicodeDescriptor(e[0])},javascript:function(){var e,t=o,n;s.charAt(t)==="~"&&(t++,n=!0);if(s.charAt(t)!=="`")return;n&&w("~");if(e=w(/^`([^`]*)`/))return new i.JavaScript(e[1],o,n)}},variable:function(){var e;if(s.charAt(o)==="@"&&(e=w(/^(@[\w-]+)\s*:/)))return e[1]},extend:function(e){var t,n,r=o,s,u=[];if(!w(e?/^&:extend\(/:/^:extend\(/))return;do{s=null,t=[];for(;;){s=w(/^(all)(?=\s*(\)|,))/);if(s)break;n=w(this.element);if(!n)break;t.push(n)}s=s&&s[1],u.push(new i.Extend(new i.Selector(t),s,r))}while(w(","));return S(/^\)/),e&&S(/^;/),u},extendRule:function(){return this.extend(!0)},mixin:{call:function(){var e=[],n,r,u,a,f,l=o,c=s.charAt(o),h=!1;if(c!=="."&&c!=="#")return;m();while(n=w(/^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/))e.push(new i.Element(r,n,o)),r=w(">");w("(")&&(u=this.mixin.args.call(this,!0).args,S(")")),u=u||[],w(this.important)&&(h=!0);if(e.length>0&&(w(";")||T("}")))return new i.mixin.Call(e,u,l,t.currentFileInfo,h);g()},args:function(e){var t=[],n=[],r,u=[],a,f,l,c,h,p={args:null,variadic:!1};for(;;){if(e)h=w(this.expression);else{w(this.comment);if(s.charAt(o)==="."&&w(/^\.{3}/)){p.variadic=!0,w(";")&&!r&&(r=!0),(r?n:u).push({variadic:!0});break}h=w(this.entities.variable)||w(this.entities.literal)||w(this.entities.keyword)}if(!h)break;l=null,h.throwAwayComments&&h.throwAwayComments(),c=h;var d=null;if(e){if(h.value.length==1)var d=h.value[0]}else d=h;if(d&&d instanceof i.Variable)if(w(":"))t.length>0&&(r&&x("Cannot mix ; and , as delimiter types"),a=!0),c=S(this.expression),l=f=d.name;else{if(!e&&w(/^\.{3}/)){p.variadic=!0,w(";")&&!r&&(r=!0),(r?n:u).push({name:h.name,variadic:!0});break}e||(f=l=d.name,c=null)}c&&t.push(c),u.push({name:l,value:c});if(w(","))continue;if(w(";")||r)a&&x("Cannot mix ; and , as delimiter types"),r=!0,t.length>1&&(c=new i.Value(t)),n.push({name:f,value:c}),f=null,t=[],a=!1}return p.args=r?n:u,p},definition:function(){var e,t=[],n,r,u,a,f,c=!1;if(s.charAt(o)!=="."&&s.charAt(o)!=="#"||T(/^[^{]*\}/))return;m();if(n=w(/^([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/)){e=n[1];var h=this.mixin.args.call(this,!1);t=h.args,c=h.variadic,w(")")||(l=o,g()),w(this.comment),w(/^when/)&&(f=S(this.conditions,"expected condition")),r=w(this.block);if(r)return new i.mixin.Definition(e,t,r,f,c);g()}}},entity:function(){return w(this.entities.literal)||w(this.entities.variable)||w(this.entities.url)||w(this.entities.call)||w(this.entities.keyword)||w(this.entities.javascript)||w(this.comment)},end:function(){return w(";")||T("}")},alpha:function(){var e;if(!w(/^\(opacity=/i))return;if(e=w(/^\d+/)||w(this.entities.variable))return S(")"),new i.Alpha(e)},element:function(){var e,t,n,r;n=w(this.combinator),e=w(/^(?:\d+\.\d+|\d+)%/)||w(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/)||w("*")||w("&")||w(this.attribute)||w(/^\([^()@]+\)/)||w(/^[\.#](?=@)/)||w(this.entities.variableCurly),e||w("(")&&(r=w(this.selector))&&w(")")&&(e=new i.Paren(r));if(e)return new i.Element(n,e,o)},combinator:function(){var e,t=s.charAt(o);if(t===">"||t==="+"||t==="~"||t==="|"){o++;while(s.charAt(o).match(/\s/))o++;return new i.Combinator(t)}return s.charAt(o-1).match(/\s/)?new i.Combinator(" "):new i.Combinator(null)},selector:function(){var e,t,n=[],r,u,a,f=[];while((a=w(this.extend))||(t=w(this.element))){a?f.push.apply(f,a):(f.length&&x("Extend can only be used at the end of selector"),r=s.charAt(o),n.push(t),t=null);if(r==="{"||r==="}"||r===";"||r===","||r===")")break}if(n.length>0)return new i.Selector(n,f);f.length&&x("Extend must be used to extend a selector, it cannot be used on its own")},attribute:function(){var e="",t,n,r;if(!w("["))return;(t=w(this.entities.variableCurly))||(t=S(/^(?:[_A-Za-z0-9-\*]*\|)?(?:[_A-Za-z0-9-]|\\.)+/));if(r=w(/^[|~*$^]?=/))n=w(this.entities.quoted)||w(/^[\w-]+/)||w(this.entities.variableCurly);return S("]"),new i.Attribute(t,r,n)},block:function(){var e;if(w("{")&&(e=w(this.primary))&&w("}"))return e},ruleset:function(){var e=[],n,r,u,a;m(),t.dumpLineNumbers&&(a=k(o,s,t));while(n=w(this.selector)){e.push(n),w(this.comment);if(!w(","))break;w(this.comment)}if(e.length>0&&(r=w(this.block))){var f=new i.Ruleset(e,r,t.strictImports);return t.dumpLineNumbers&&(f.debugInfo=a),f}l=o,g()},rule:function(e){var n,r,u=s.charAt(o),a,c;m();if(u==="."||u==="#"||u==="&")return;if(n=w(this.variable)||w(this.property)){r=!e&&(t.compress||n.charAt(0)==="@")?w(this.value)||w(this.anonymousValue):w(this.anonymousValue)||w(this.value),a=w(this.important);if(r&&w(this.end))return new i.Rule(n,r,a,f,t.currentFileInfo);l=o,g();if(r&&!e)return this.rule(!0)}},anonymousValue:function(){if(match=/^([^@+\/'"*`(;{}-]*);/.exec(c[u]))return o+=match[0].length-1,new i.Anonymous(match[1])},"import":function(){var e,n,r=o;m();var s=w(/^@import?\s+/),u=(s?w(this.importOptions):null)||{};if(s&&(e=w(this.entities.quoted)||w(this.entities.url))){n=w(this.mediaFeatures);if(w(";"))return n=n&&new i.Value(n),new i.Import(e,n,u,r,t.currentFileInfo)}g()},importOptions:function(){var e,t={},n,r;if(!w("("))return null;do if(e=w(this.importOption)){n=e,r=!0;switch(n){case"css":n="less",r=!1;break;case"once":n="multiple",r=!1}t[n]=r;if(!w(","))break}while(e);return S(")"),t},importOption:function(){var e=w(/^(less|css|multiple|once)/);if(e)return e[1]},mediaFeature:function(){var e,n,r=[];do if(e=w(this.entities.keyword))r.push(e);else if(w("(")){n=w(this.property),e=w(this.value);if(!w(")"))return null;if(n&&e)r.push(new i.Paren(new i.Rule(n,e,null,o,t.currentFileInfo,!0)));else{if(!e)return null;r.push(new i.Paren(e))}}while(e);if(r.length>0)return new i.Expression(r)},mediaFeatures:function(){var e,t=[];do if(e=w(this.mediaFeature)){t.push(e);if(!w(","))break}else if(e=w(this.entities.variable)){t.push(e);if(!w(","))break}while(e);return t.length>0?t:null},media:function(){var e,n,r,u;t.dumpLineNumbers&&(u=k(o,s,t));if(w(/^@media/)){e=w(this.mediaFeatures);if(n=w(this.block))return r=new i.Media(n,e),t.dumpLineNumbers&&(r.debugInfo=u),r}},directive:function(){var e,n,r,u,a,f,l,c,h,p;if(s.charAt(o)!=="@")return;if(n=w(this["import"])||w(this.media))return n;m(),e=w(/^@[a-z-]+/);if(!e)return;l=e,e.charAt(1)=="-"&&e.indexOf("-",2)>0&&(l="@"+e.slice(e.indexOf("-",2)+1));switch(l){case"@font-face":c=!0;break;case"@viewport":case"@top-left":case"@top-left-corner":case"@top-center":case"@top-right":case"@top-right-corner":case"@bottom-left":case"@bottom-left-corner":case"@bottom-center":case"@bottom-right":case"@bottom-right-corner":case"@left-top":case"@left-middle":case"@left-bottom":case"@right-top":case"@right-middle":case"@right-bottom":c=!0;break;case"@page":case"@document":case"@supports":case"@keyframes":c=!0,h=!0;break;case"@namespace":p=!0}h&&(e+=" "+(w(/^[^{]+/)||"").trim());if(c){if(r=w(this.block))return new i.Directive(e,r)}else if((n=p?w(this.expression):w(this.entity))&&w(";")){var d=new i.Directive(e,n);return t.dumpLineNumbers&&(d.debugInfo=k(o,s,t)),d}g()},value:function(){var e,t=[],n;while(e=w(this.expression)){t.push(e);if(!w(","))break}if(t.length>0)return new i.Value(t)},important:function(){if(s.charAt(o)==="!")return w(/^! *important/)},sub:function(){var e,t;if(w("("))if(e=w(this.addition))return t=new i.Expression([e]),S(")"),t.parens=!0,t},multiplication:function(){var e,t,n,r,u,a=[];if(e=w(this.operand)){u=b(s.charAt(o-1));while(!T(/^\/[*\/]/)&&(n=w("/")||w("*"))){if(!(t=w(this.operand)))break;e.parensInOp=!0,t.parensInOp=!0,r=new i.Operation(n,[r||e,t],u),u=b(s.charAt(o-1))}return r||e}},addition:function(){var e,t,n,r,u;if(e=w(this.multiplication)){u=b(s.charAt(o-1));while((n=w(/^[-+]\s+/)||!u&&(w("+")||w("-")))&&(t=w(this.multiplication)))e.parensInOp=!0,t.parensInOp=!0,r=new i.Operation(n,[r||e,t],u),u=b(s.charAt(o-1));return r||e}},conditions:function(){var e,t,n=o,r;if(e=w(this.condition)){while(w(",")&&(t=w(this.condition)))r=new i.Condition("or",r||e,t,n);return r||e}},condition:function(){var e,t,n,r,s=o,u=!1;w(/^not/)&&(u=!0),S("(");if(e=w(this.addition)||w(this.entities.keyword)||w(this.entities.quoted))return(r=w(/^(?:>=|=<|[<=>])/))?(t=w(this.addition)||w(this.entities.keyword)||w(this.entities.quoted))?n=new i.Condition(r,e,t,s,u):x("expected expression"):n=new i.Condition("=",e,new i.Keyword("true"),s,u),S(")"),w(/^and/)?new i.Condition("and",n,w(this.condition)):n},operand:function(){var e,t=s.charAt(o+1);s.charAt(o)==="-"&&(t==="@"||t==="(")&&(e=w("-"));var n=w(this.sub)||w(this.entities.dimension)||w(this.entities.color)||w(this.entities.variable)||w(this.entities.call);return e&&(n.parensInOp=!0,n=new i.Negative(n)),n},expression:function(){var e,t,n=[],r;while(e=w(this.addition)||w(this.entity))n.push(e),!T(/^\/[\/*]/)&&(t=w("/"))&&n.push(new i.Anonymous(t));if(n.length>0)return new i.Expression(n)},property:function(){var e;if(e=w(/^(\*?-?[_a-z0-9-]+)\s*:/))return e[1]}}}};if(r.mode==="browser"||r.mode==="rhino")r.Parser.importer=function(e,t,n,r){!/^([a-z-]+:)?\//.test(e)&&t.currentDirectory&&(e=t.currentDirectory+e);var i=r.toSheet(e);i.processImports=!1,i.currentFileInfo=t,w(i,function(e,t,r,i,s,o){n.call(null,e,t,o)},!0)};(function(r){function u(e){return r.functions.hsla(e.h,e.s,e.l,e.a)}function a(e,t){return e instanceof r.Dimension&&e.unit.is("%")?parseFloat(e.value*t/100):f(e)}function f(e){if(e instanceof r.Dimension)return parseFloat(e.unit.is("%")?e.value/100:e.value);if(typeof e=="number")return e;throw{error:"RuntimeError",message:"color functions take numbers as parameters"}}function l(e){return Math.min(1,Math.max(0,e))}r.functions={rgb:function(e,t,n){return this.rgba(e,t,n,1)},rgba:function(e,t,n,i){var s=[e,t,n].map(function(e){return a(e,256)});return i=f(i),new r.Color(s,i)},hsl:function(e,t,n){return this.hsla(e,t,n,1)},hsla:function(e,t,n,r){function o(e){return e=e<0?e+1:e>1?e-1:e,e*6<1?s+(i-s)*e*6:e*2<1?i:e*3<2?s+(i-s)*(2/3-e)*6:s}e=f(e)%360/360,t=l(f(t)),n=l(f(n)),r=l(f(r));var i=n<=.5?n*(t+1):n+t-n*t,s=n*2-i;return this.rgba(o(e+1/3)*255,o(e)*255,o(e-1/3)*255,r)},hsv:function(e,t,n){return this.hsva(e,t,n,1)},hsva:function(e,t,n,r){e=f(e)%360/360*360,t=f(t),n=f(n),r=f(r);var i,s;i=Math.floor(e/60%6),s=e/60-i;var o=[n,n*(1-t),n*(1-s*t),n*(1-(1-s)*t)],u=[[0,3,1],[2,0,1],[1,0,3],[1,2,0],[3,1,0],[0,1,2]];return this.rgba(o[u[i][0]]*255,o[u[i][1]]*255,o[u[i][2]]*255,r)},hue:function(e){return new r.Dimension(Math.round(e.toHSL().h))},saturation:function(e){return new r.Dimension(Math.round(e.toHSL().s*100),"%")},lightness:function(e){return new r.Dimension(Math.round(e.toHSL().l*100),"%")},hsvhue:function(e){return new r.Dimension(Math.round(e.toHSV().h))},hsvsaturation:function(e){return new r.Dimension(Math.round(e.toHSV().s*100),"%")},hsvvalue:function(e){return new r.Dimension(Math.round(e.toHSV().v*100),"%")},red:function(e){return new r.Dimension(e.rgb[0])},green:function(e){return new r.Dimension(e.rgb[1])},blue:function(e){return new r.Dimension(e.rgb[2])},alpha:function(e){return new r.Dimension(e.toHSL().a)},luma:function(e){return new r.Dimension(Math.round(e.luma()*e.alpha*100),"%")},saturate:function(e,t){var n=e.toHSL();return n.s+=t.value/100,n.s=l(n.s),u(n)},desaturate:function(e,t){var n=e.toHSL();return n.s-=t.value/100,n.s=l(n.s),u(n)},lighten:function(e,t){var n=e.toHSL();return n.l+=t.value/100,n.l=l(n.l),u(n)},darken:function(e,t){var n=e.toHSL();return n.l-=t.value/100,n.l=l(n.l),u(n)},fadein:function(e,t){var n=e.toHSL();return n.a+=t.value/100,n.a=l(n.a),u(n)},fadeout:function(e,t){var n=e.toHSL();return n.a-=t.value/100,n.a=l(n.a),u(n)},fade:function(e,t){var n=e.toHSL();return n.a=t.value/100,n.a=l(n.a),u(n)},spin:function(e,t){var n=e.toHSL(),r=(n.h+t.value)%360;return n.h=r<0?360+r:r,u(n)},mix:function(e,t,n){n||(n=new r.Dimension(50));var i=n.value/100,s=i*2-1,o=e.toHSL().a-t.toHSL().a,u=((s*o==-1?s:(s+o)/(1+s*o))+1)/2,a=1-u,f=[e.rgb[0]*u+t.rgb[0]*a,e.rgb[1]*u+t.rgb[1]*a,e.rgb[2]*u+t.rgb[2]*a],l=e.alpha*i+t.alpha*(1-i);return new r.Color(f,l)},greyscale:function(e){return this.desaturate(e,new r.Dimension(100))},contrast:function(e,t,n,r){if(!e.rgb)return null;typeof n=="undefined"&&(n=this.rgba(255,255,255,1)),typeof t=="undefined"&&(t=this.rgba(0,0,0,1));if(t.luma()>n.luma()){var i=n;n=t,t=i}return typeof r=="undefined"?r=.43:r=f(r),e.luma()*e.alpha=d){if(this.env.ieCompat!==!1)return this.env.silent||console.warn("Skipped data-uri embedding of %s because its size (%dKB) exceeds IE8-safe %dKB!",o,v,d),(new r.URL(i||t,this.currentFileInfo)).eval(this.env);this.env.silent||console.warn("WARNING: Embedding %s (%dKB) exceeds IE8's data-uri size limit of %dKB!",o,v,d)}p=f?p.toString("base64"):encodeURIComponent(p);var m="'data:"+s+","+p+"'";return new r.URL(new r.Anonymous(m))}},r._mime={_types:{".htm":"text/html",".html":"text/html",".gif":"image/gif",".jpg":"image/jpeg",".jpeg":"image/jpeg",".png":"image/png"},lookup:function(e){var i=n("path").extname(e),s=r._mime._types[i];if(s===t)throw new Error('Optional dependency "mime" is required for '+i);return s},charsets:{lookup:function(e){return e&&/^text\//.test(e)?"UTF-8":""}}};var i=[{name:"ceil"},{name:"floor"},{name:"sqrt"},{name:"abs"},{name:"tan",unit:""},{name:"sin",unit:""},{name:"cos",unit:""},{name:"atan",unit:"rad"},{name:"asin",unit:"rad"},{name:"acos",unit:"rad"}],s=function(e,t){return function(n){return t!=null&&(n=n.unify()),this._math(Math[e],t,n)}};for(var o=0;o255?255:e<0?0:e).toString(16),e.length===1?"0"+e:e}).join("");return n&&(r=r.split(""),r[0]==r[1]&&r[2]==r[3]&&r[4]==r[5]?r=r[0]+r[2]+r[4]:r=r.join("")),"#"+r},operate:function(t,n,r){var i=[];r instanceof e.Color||(r=r.toColor());for(var s=0;s<3;s++)i[s]=e.operate(t,n,this.rgb[s],r.rgb[s]);return new e.Color(i,this.alpha+r.alpha)},toHSL:function(){var e=this.rgb[0]/255,t=this.rgb[1]/255,n=this.rgb[2]/255,r=this.alpha,i=Math.max(e,t,n),s=Math.min(e,t,n),o,u,a=(i+s)/2,f=i-s;if(i===s)o=u=0;else{u=a>.5?f/(2-i-s):f/(i+s);switch(i){case e:o=(t-n)/f+(t255?255:e<0?0:e).toString(16),e.length===1?"0"+e:e}).join("")},compare:function(e){return e.rgb?e.rgb[0]===this.rgb[0]&&e.rgb[1]===this.rgb[1]&&e.rgb[2]===this.rgb[2]&&e.alpha===this.alpha?0:-1:-1}}}(n("../tree")),function(e){e.Comment=function(e,t){this.value=e,this.silent=!!t},e.Comment.prototype={type:"Comment",toCSS:function(e){return e.compress?"":this.value},eval:function(){return this}}}(n("../tree")),function(e){e.Condition=function(e,t,n,r,i){this.op=e.trim(),this.lvalue=t,this.rvalue=n,this.index=r,this.negate=i},e.Condition.prototype={type:"Condition",accept:function(e){this.lvalue=e.visit(this.lvalue),this.rvalue=e.visit(this.rvalue)},eval:function(e){var t=this.lvalue.eval(e),n=this.rvalue.eval(e),r=this.index,i,i=function(e){switch(e){case"and":return t&&n;case"or":return t||n;default:if(t.compare)i=t.compare(n);else{if(!n.compare)throw{type:"Type",message:"Unable to perform comparison",index:r};i=n.compare(t)}switch(i){case-1:return e==="<"||e==="=<";case 0:return e==="="||e===">="||e==="=<";case 1:return e===">"||e===">="}}}(this.op);return this.negate?!i:i}}}(n("../tree")),function(e){e.Dimension=function(n,r){this.value=parseFloat(n),this.unit=r&&r instanceof e.Unit?r:new e.Unit(r?[r]:t)},e.Dimension.prototype={type:"Dimension",accept:function(e){this.unit=e.visit(this.unit)},eval:function(e){return this},toColor:function(){return new e.Color([this.value,this.value,this.value])},toCSS:function(e){if(e&&e.strictUnits&&!this.unit.isSingular())throw new Error("Multiple units in dimension. Correct the units or use the unit function. Bad unit: "+this.unit.toString());var t=this.value,n=String(t);t!==0&&t<1e-6&&t>-0.000001&&(n=t.toFixed(20).replace(/0+$/,""));if(e&&e.compress){if(t===0&&!this.unit.isAngle())return n;t>0&&t<1&&(n=n.substr(1))}return n+this.unit.toCSS(e)},operate:function(t,n,r){var i=e.operate(t,n,this.value,r.value),s=this.unit.clone();if(n==="+"||n==="-"){if(s.numerator.length===0&&s.denominator.length===0)s.numerator=r.unit.numerator.slice(0),s.denominator=r.unit.denominator.slice(0);else if(r.unit.numerator.length!=0||s.denominator.length!=0){r=r.convertTo(this.unit.usedUnits());if(t.strictUnits&&r.unit.toString()!==s.toString())throw new Error("Incompatible units. Change the units or use the unit function. Bad units: '"+s.toString()+"' and '"+r.unit.toString()+"'.");i=e.operate(t,n,this.value,r.value)}}else n==="*"?(s.numerator=s.numerator.concat(r.unit.numerator).sort(),s.denominator=s.denominator.concat(r.unit.denominator).sort(),s.cancel()):n==="/"&&(s.numerator=s.numerator.concat(r.unit.denominator).sort(),s.denominator=s.denominator.concat(r.unit.numerator).sort(),s.cancel());return new e.Dimension(i,s)},compare:function(t){if(t instanceof e.Dimension){var n=this.unify(),r=t.unify(),i=n.value,s=r.value;return s>i?-1:s=1?this.numerator[0]:this.denominator.length>=1?this.denominator[0]:(!e||!e.strictUnits)&&this.backupUnit?this.backupUnit:""},toString:function(){var e,t=this.numerator.join("*");for(e=0;e0)for(n=0;n":e.compress?">":" > ","|":e.compress?"|":" | "}[this.value]}}}(n("../tree")),function(e){e.Expression=function(e){this.value=e},e.Expression.prototype={type:"Expression",accept:function(e){this.value=e.visit(this.value)},eval:function(t){var n,r=this.parens&&!this.parensInOp,i=!1;return r&&t.inParenthesis(),this.value.length>1?n=new e.Expression(this.value.map(function(e){return e.eval(t)})):this.value.length===1?(this.value[0].parens&&!this.value[0].parensInOp&&(i=!0),n=this.value[0].eval(t)):n=this,r&&t.outOfParenthesis(),this.parens&&this.parensInOp&&!t.isMathOn()&&!i&&(n=new e.Paren(n)),n},toCSS:function(e){return this.value.map(function(t){return t.toCSS?t.toCSS(e):""}).join(" ")},throwAwayComments:function(){this.value=this.value.filter(function(t){return!(t instanceof e.Comment)})}}}(n("../tree")),function(e){e.Extend=function(t,n,r){this.selector=t,this.option=n,this.index=r;switch(n){case"all":this.allowBefore=!0,this.allowAfter=!0;break;default:this.allowBefore=!1,this.allowAfter=!1}},e.Extend.prototype={type:"Extend",accept:function(e){this.selector=e.visit(this.selector)},eval:function(t){return new e.Extend(this.selector.eval(t),this.option,this.index)},clone:function(t){return new e.Extend(this.selector,this.option,this.index)},findSelfSelectors:function(e){var t=[];for(d=0;d1){var r=this.emptySelectors();n=new e.Ruleset(r,t.mediaBlocks),n.multiMedia=!0}return delete t.mediaBlocks,delete t.mediaPath,n},evalNested:function(t){var n,r,i=t.mediaPath.concat([this]);for(n=0;n0;n--)t.splice(n,0,new e.Anonymous("and"));return new e.Expression(t)})),new e.Ruleset([],[])},permute:function(e){if(e.length===0)return[];if(e.length===1)return e[0];var t=[],n=this.permute(e.slice(1));for(var r=0;r0){c=!0;for(a=0;athis.params.length)return!1;if(this.required>0&&n>this.params.length)return!1}r=Math.min(n,this.arity);for(var s=0;si.selectors[o].elements.length?Array.prototype.push.apply(r,i.find(new e.Selector(t.elements.slice(1)),n)):r.push(i);break}}),this._lookups[o]=r)},toCSS:function(t){var n=[],r=[],i=[],s=[],o,u,a;for(var f=0;f0){u=e.debugInfo(t,this),o=this.paths.map(function(e){return e.map(function(e){return e.toCSS(t)}).join("").trim()}).join(t.compress?",":",\n");for(var f=r.length-1;f>=0;f--)(r[f].slice(0,2)==="/*"||i.indexOf(r[f])===-1)&&i.unshift(r[f]);r=i,n.push(u+o+(t.compress?"{":" {\n ")+r.join(t.compress?"":"\n ")+(t.compress?"}":"\n}\n"))}return n.push(s),n.join("")+(t.compress?"\n":"")},joinSelectors:function(e,t,n){for(var r=0;r0)for(i=0;i0&&this.mergeElementsOnToSelectors(g,a);for(s=0;s0&&(l[0].elements=l[0].elements.slice(0),l[0].elements.push(new e.Element(f.combinator,"",0))),y.push(l);else for(o=0;o0?(h=l.slice(0),m=h.pop(),d=new e.Selector(m.elements.slice(0),r.extendList),v=!1):d=new e.Selector([],r.extendList),c.length>1&&(p=p.concat(c.slice(1))),c.length>0&&(v=!1,d.elements.push(new e.Element(f.combinator,c[0].elements[0].value,0)),d.elements=d.elements.concat(c[0].elements.slice(1))),v||h.push(d),h=h.concat(p),y.push(h)}a=y,g=[]}}g.length>0&&this.mergeElementsOnToSelectors(g,a);for(i=0;i0&&t.push(a[i])},mergeElementsOnToSelectors:function(t,n){var r,i,s;if(n.length==0){n.push([new e.Selector(t)]);return}for(r=0;r0?i[i.length-1]=new e.Selector(i[i.length-1].elements.concat(t),i[i.length-1].extendList):i.push(new e.Selector(t))}}}(n("../tree")),function(e){e.Selector=function(e,t){this.elements=e,this.extendList=t||[]},e.Selector.prototype={type:"Selector",accept:function(e){this.elements=e.visit(this.elements),this.extendList=e.visit(this.extendList)},match:function(e){var t=this.elements,n=t.length,r,i,s,o;r=e.elements.slice(e.elements.length&&e.elements[0].value==="&"?1:0),i=r.length,s=Math.min(n,i);if(i===0||n1?"["+e.value.map(function(e){return e.toCSS(!1)}).join(", ")+"]":e.toCSS(!1)}}(n("./tree")),function(e){var t=["paths","optimization","files","contents","relativeUrls","strictImports","dumpLineNumbers","compress","processImports","mime","currentFileInfo"];e.parseEnv=function(e){r(e,this,t),this.contents||(this.contents={}),this.files||(this.files={});if(!this.currentFileInfo){var n=e.filename||"input";e.filename=null;var i=n.replace(/[^\/\\]*$/,"");this.currentFileInfo={filename:n,relativeUrls:this.relativeUrls,rootpath:e.rootpath||"",currentDirectory:i,entryPath:i,rootFilename:n}}},e.parseEnv.prototype.toSheet=function(t){var n=new e.parseEnv(this);return n.href=t,n.type=this.mime,n};var n=["silent","verbose","compress","ieCompat","strictMath","strictUnits"];e.evalEnv=function(e,t){r(e,this,n),this.frames=t||[]},e.evalEnv.prototype.inParenthesis=function(){this.parensStack||(this.parensStack=[]),this.parensStack.push(!0)},e.evalEnv.prototype.outOfParenthesis=function(){this.parensStack.pop()},e.evalEnv.prototype.isMathOn=function(){return this.strictMath?this.parensStack&&this.parensStack.length:!0},e.evalEnv.prototype.isPathRelative=function(e){return!/^(?:[a-z-]+:|\/)/.test(e)};var r=function(e,t,n){if(!e)return;for(var r=0;r100){var p="{unable to calculate}",d="{unable to calculate}";try{p=u[0].selfSelectors[0].toCSS(),d=u[0].selector.toCSS()}catch(v){}throw{message:"extend circular reference detected. One of the circular extends is currently:"+p+":extend("+d+")"}}return u.concat(f.doExtendChaining(u,n,r+1))}return u},inInheritanceChain:function(e,t){if(e===t)return!0;if(t.parents){if(this.inInheritanceChain(e,t.parents[0]))return!0;if(this.inInheritanceChain(e,t.parents[1]))return!0}return!1},visitRule:function(e,t){t.visitDeeper=!1},visitMixinDefinition:function(e,t){t.visitDeeper=!1},visitSelector:function(e,t){t.visitDeeper=!1},visitRuleset:function(e,t){if(e.root)return;var n,r,i,s=this.allExtendsStack[this.allExtendsStack.length-1],o=[],u=this;for(i=0;i0&&f[c.matched].combinator.value!==o?c=null:c.matched++,c&&(c.finished=c.matched===f.length,c.finished&&!e.allowAfter&&(i+1i&&s>0&&(o[o.length-1].elements=o[o.length-1].elements.concat(n[i].elements.slice(s)),s=0,i++),o=o.concat(n.slice(i,match.pathIndex)),o.push(new e.Selector(a.elements.slice(s,match.index).concat([f]).concat(r.elements.slice(1)))),i=match.endPathIndex,s=match.endPathElementIndex,s>=a.elements.length&&(s=0,i++);return i0&&(o[o.length-1].elements=o[o.length-1].elements.concat(n[i].elements.slice(s)),s=0,i++),o=o.concat(n.slice(i,n.length)),o},visitRulesetOut:function(e){},visitMedia:function(e,t){var n=e.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length-1]);n=n.concat(this.doExtendChaining(n,e.allExtends)),this.allExtendsStack.push(n)},visitMediaOut:function(e){this.allExtendsStack.length=this.allExtendsStack.length-1},visitDirective:function(e,t){var n=e.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length-1]);n=n.concat(this.doExtendChaining(n,e.allExtends)),this.allExtendsStack.push(n)},visitDirectiveOut:function(e){this.allExtendsStack.length=this.allExtendsStack.length-1}}}(n("./tree"));var o=/^(file|chrome(-extension)?|resource|qrc|app):/.test(location.protocol);r.env=r.env||(location.hostname=="127.0.0.1"||location.hostname=="0.0.0.0"||location.hostname=="localhost"||location.port.length>0||o?"development":"production"),r.async=r.async||!1,r.fileAsync=r.fileAsync||!1,r.poll=r.poll||(o?1e3:1500);if(r.functions)for(var u in r.functions)r.tree.functions[u]=r.functions[u];var a=/!dumpLineNumbers:(comments|mediaquery|all)/.exec(location.hash);a&&(r.dumpLineNumbers=a[1]),r.watch=function(){return r.watchMode||(r.env="development",f()),this.watchMode=!0},r.unwatch=function(){return clearInterval(r.watchTimer),this.watchMode=!1},/!watch/.test(location.hash)&&r.watch();var l=null;if(r.env!="development")try{l=typeof e.localStorage=="undefined"?null:e.localStorage}catch(c){}var h=document.getElementsByTagName("link"),p=/^text\/(x-)?less$/;r.sheets=[];for(var d=0;d current) { chunks[j] = chunks[j].slice(i - current); current = i; } } function isWhitespace(c) { // Could change to \s? var code = c.charCodeAt(0); return code === 32 || code === 10 || code === 9; } // // Parse from a token, regexp or string, and move forward if match // function $(tok) { var match, args, length, index, k; // // Non-terminal // if (tok instanceof Function) { return tok.call(parser.parsers); // // Terminal // // Either match a single character in the input, // or match a regexp in the current chunk (chunk[j]). // } else if (typeof(tok) === 'string') { match = input.charAt(i) === tok ? tok : null; length = 1; sync (); } else { sync (); if (match = tok.exec(chunks[j])) { length = match[0].length; } else { return null; } } // The match is confirmed, add the match length to `i`, // and consume any extra white-space characters (' ' || '\n') // which come after that. The reason for this is that LeSS's // grammar is mostly white-space insensitive. // if (match) { skipWhitespace(length); if(typeof(match) === 'string') { return match; } else { return match.length === 1 ? match[0] : match; } } } function skipWhitespace(length) { var oldi = i, oldj = j, endIndex = i + chunks[j].length, mem = i += length; while (i < endIndex) { if (! isWhitespace(input.charAt(i))) { break } i++; } chunks[j] = chunks[j].slice(length + (i - mem)); current = i; if (chunks[j].length === 0 && j < chunks.length - 1) { j++ } return oldi !== i || oldj !== j; } function expect(arg, msg) { var result = $(arg); if (! result) { error(msg || (typeof(arg) === 'string' ? "expected '" + arg + "' got '" + input.charAt(i) + "'" : "unexpected token")); } else { return result; } } function error(msg, type) { var e = new Error(msg); e.index = i; e.type = type || 'Syntax'; throw e; } // Same as $(), but don't change the state of the parser, // just return the match. function peek(tok) { if (typeof(tok) === 'string') { return input.charAt(i) === tok; } else { if (tok.test(chunks[j])) { return true; } else { return false; } } } function getInput(e, env) { if (e.filename && env.currentFileInfo.filename && (e.filename !== env.currentFileInfo.filename)) { return parser.imports.contents[e.filename]; } else { return input; } } function getLocation(index, input) { for (var n = index, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } return { line: typeof(index) === 'number' ? (input.slice(0, index).match(/\n/g) || "").length : null, column: column }; } function getDebugInfo(index, inputStream, env) { var filename = env.currentFileInfo.filename; if(less.mode !== 'browser' && less.mode !== 'rhino') { filename = require('path').resolve(filename); } return { lineNumber: getLocation(index, inputStream).line + 1, fileName: filename }; } function LessError(e, env) { var input = getInput(e, env), loc = getLocation(e.index, input), line = loc.line, col = loc.column, lines = input.split('\n'); this.type = e.type || 'Syntax'; this.message = e.message; this.filename = e.filename || env.currentFileInfo.filename; this.index = e.index; this.line = typeof(line) === 'number' ? line + 1 : null; this.callLine = e.call && (getLocation(e.call, input).line + 1); this.callExtract = lines[getLocation(e.call, input).line]; this.stack = e.stack; this.column = col; this.extract = [ lines[line - 1], lines[line], lines[line + 1] ]; } LessError.prototype = new Error(); LessError.prototype.constructor = LessError; this.env = env = env || {}; // The optimization level dictates the thoroughness of the parser, // the lower the number, the less nodes it will create in the tree. // This could matter for debugging, or if you want to access // the individual nodes in the tree. this.optimization = ('optimization' in this.env) ? this.env.optimization : 1; // // The Parser // return parser = { imports: imports, // // Parse an input string into an abstract syntax tree, // call `callback` when done. // parse: function (str, callback) { var root, start, end, zone, line, lines, buff = [], c, error = null; i = j = current = furthest = 0; input = str.replace(/\r\n/g, '\n'); // Remove potential UTF Byte Order Mark input = input.replace(/^\uFEFF/, ''); // Split the input into chunks. chunks = (function (chunks) { var j = 0, skip = /(?:@\{[\w-]+\}|[^"'`\{\}\/\(\)\\])+/g, comment = /\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g, string = /"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'|`((?:[^`]|\\.)*)`/g, level = 0, match, chunk = chunks[0], inParam; for (var i = 0, c, cc; i < input.length;) { skip.lastIndex = i; if (match = skip.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); } } c = input.charAt(i); comment.lastIndex = string.lastIndex = i; if (match = string.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); continue; } } if (!inParam && c === '/') { cc = input.charAt(i + 1); if (cc === '/' || cc === '*') { if (match = comment.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); continue; } } } } switch (c) { case '{': if (! inParam) { level ++; chunk.push(c); break } case '}': if (! inParam) { level --; chunk.push(c); chunks[++j] = chunk = []; break } case '(': if (! inParam) { inParam = true; chunk.push(c); break } case ')': if ( inParam) { inParam = false; chunk.push(c); break } default: chunk.push(c); } i++; } if (level != 0) { error = new(LessError)({ index: i-1, type: 'Parse', message: (level > 0) ? "missing closing `}`" : "missing opening `{`", filename: env.currentFileInfo.filename }, env); } return chunks.map(function (c) { return c.join('') });; })([[]]); if (error) { return callback(new(LessError)(error, env)); } // Start with the primary rule. // The whole syntax tree is held under a Ruleset node, // with the `root` property set to true, so no `{}` are // output. The callback is called when the input is parsed. try { root = new(tree.Ruleset)([], $(this.parsers.primary)); root.root = true; root.firstRoot = true; } catch (e) { return callback(new(LessError)(e, env)); } root.toCSS = (function (evaluate) { var line, lines, column; return function (options, variables) { options = options || {}; var importError, evalEnv = new tree.evalEnv(options); // // Allows setting variables with a hash, so: // // `{ color: new(tree.Color)('#f01') }` will become: // // new(tree.Rule)('@color', // new(tree.Value)([ // new(tree.Expression)([ // new(tree.Color)('#f01') // ]) // ]) // ) // if (typeof(variables) === 'object' && !Array.isArray(variables)) { variables = Object.keys(variables).map(function (k) { var value = variables[k]; if (! (value instanceof tree.Value)) { if (! (value instanceof tree.Expression)) { value = new(tree.Expression)([value]); } value = new(tree.Value)([value]); } return new(tree.Rule)('@' + k, value, false, 0); }); evalEnv.frames = [new(tree.Ruleset)(null, variables)]; } try { var evaldRoot = evaluate.call(this, evalEnv); new(tree.joinSelectorVisitor)() .run(evaldRoot); new(tree.processExtendsVisitor)() .run(evaldRoot); var css = evaldRoot.toCSS({ compress: Boolean(options.compress), dumpLineNumbers: env.dumpLineNumbers, strictUnits: Boolean(options.strictUnits)}); } catch (e) { throw new(LessError)(e, env); } if (options.yuicompress && less.mode === 'node') { return require('ycssmin').cssmin(css, options.maxLineLen); } else if (options.compress) { return css.replace(/(\s)+/g, "$1"); } else { return css; } }; })(root.eval); // If `i` is smaller than the `input.length - 1`, // it means the parser wasn't able to parse the whole // string, so we've got a parsing error. // // We try to extract a \n delimited string, // showing the line where the parse error occured. // We split it up into two parts (the part which parsed, // and the part which didn't), so we can color them differently. if (i < input.length - 1) { i = furthest; lines = input.split('\n'); line = (input.slice(0, i).match(/\n/g) || "").length + 1; for (var n = i, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } error = { type: "Parse", message: "Unrecognised input", index: i, filename: env.currentFileInfo.filename, line: line, column: column, extract: [ lines[line - 2], lines[line - 1], lines[line] ] }; } var finish = function (e) { e = error || e || parser.imports.error; if (e) { if (!(e instanceof LessError)) { e = new(LessError)(e, env); } callback(e); } else { callback(null, root); } }; if (env.processImports !== false) { new tree.importVisitor(this.imports, finish) .run(root); } else { finish(); } }, // // Here in, the parsing rules/functions // // The basic structure of the syntax tree generated is as follows: // // Ruleset -> Rule -> Value -> Expression -> Entity // // Here's some LESS code: // // .class { // color: #fff; // border: 1px solid #000; // width: @w + 4px; // > .child {...} // } // // And here's what the parse tree might look like: // // Ruleset (Selector '.class', [ // Rule ("color", Value ([Expression [Color #fff]])) // Rule ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]])) // Rule ("width", Value ([Expression [Operation "+" [Variable "@w"][Dimension 4px]]])) // Ruleset (Selector [Element '>', '.child'], [...]) // ]) // // In general, most rules will try to parse a token with the `$()` function, and if the return // value is truly, will return a new node, of the relevant type. Sometimes, we need to check // first, before parsing, that's when we use `peek()`. // parsers: { // // The `primary` rule is the *entry* and *exit* point of the parser. // The rules here can appear at any level of the parse tree. // // The recursive nature of the grammar is an interplay between the `block` // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule, // as represented by this simplified grammar: // // primary → (ruleset | rule)+ // ruleset → selector+ block // block → '{' primary '}' // // Only at one point is the primary rule not called from the // block rule: at the root level. // primary: function () { var node, root = []; while ((node = $(this.extendRule) || $(this.mixin.definition) || $(this.rule) || $(this.ruleset) || $(this.mixin.call) || $(this.comment) || $(this.directive)) || $(/^[\s\n]+/) || $(/^;+/)) { node && root.push(node); } return root; }, // We create a Comment node for CSS comments `/* */`, // but keep the LeSS comments `//` silent, by just skipping // over them. comment: function () { var comment; if (input.charAt(i) !== '/') return; if (input.charAt(i + 1) === '/') { return new(tree.Comment)($(/^\/\/.*/), true); } else if (comment = $(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/)) { return new(tree.Comment)(comment); } }, // // Entities are tokens which can be found inside an Expression // entities: { // // A string, which supports escaping " and ' // // "milky way" 'he\'s the one!' // quoted: function () { var str, j = i, e, index = i; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '"' && input.charAt(j) !== "'") return; e && $('~'); if (str = $(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/)) { return new(tree.Quoted)(str[0], str[1] || str[2], e, index, env.currentFileInfo); } }, // // A catch-all word, such as: // // black border-collapse // keyword: function () { var k; if (k = $(/^[_A-Za-z-][_A-Za-z0-9-]*/)) { if (tree.colors.hasOwnProperty(k)) { // detect named color return new(tree.Color)(tree.colors[k].slice(1)); } else { return new(tree.Keyword)(k); } } }, // // A function call // // rgb(255, 0, 255) // // We also try to catch IE's `alpha()`, but let the `alpha` parser // deal with the details. // // The arguments are parsed with the `entities.arguments` parser. // call: function () { var name, nameLC, args, alpha_ret, index = i; if (! (name = /^([\w-]+|%|progid:[\w\.]+)\(/.exec(chunks[j]))) return; name = name[1]; nameLC = name.toLowerCase(); if (nameLC === 'url') { return null } else { i += name.length } if (nameLC === 'alpha') { alpha_ret = $(this.alpha); if(typeof alpha_ret !== 'undefined') { return alpha_ret; } } $('('); // Parse the '(' and consume whitespace. args = $(this.entities.arguments); if (! $(')')) { return; } if (name) { return new(tree.Call)(name, args, index, env.currentFileInfo); } }, arguments: function () { var args = [], arg; while (arg = $(this.entities.assignment) || $(this.expression)) { args.push(arg); if (! $(',')) { break } } return args; }, literal: function () { return $(this.entities.dimension) || $(this.entities.color) || $(this.entities.quoted) || $(this.entities.unicodeDescriptor); }, // Assignments are argument entities for calls. // They are present in ie filter properties as shown below. // // filter: progid:DXImageTransform.Microsoft.Alpha( *opacity=50* ) // assignment: function () { var key, value; if ((key = $(/^\w+(?=\s?=)/i)) && $('=') && (value = $(this.entity))) { return new(tree.Assignment)(key, value); } }, // // Parse url() tokens // // We use a specific rule for urls, because they don't really behave like // standard function calls. The difference is that the argument doesn't have // to be enclosed within a string, so it can't be parsed as an Expression. // url: function () { var value; if (input.charAt(i) !== 'u' || !$(/^url\(/)) return; value = $(this.entities.quoted) || $(this.entities.variable) || $(/^(?:(?:\\[\(\)'"])|[^\(\)'"])+/) || ""; expect(')'); return new(tree.URL)((value.value != null || value instanceof tree.Variable) ? value : new(tree.Anonymous)(value), env.currentFileInfo); }, // // A Variable entity, such as `@fink`, in // // width: @fink + 2px // // We use a different parser for variable definitions, // see `parsers.variable`. // variable: function () { var name, index = i; if (input.charAt(i) === '@' && (name = $(/^@@?[\w-]+/))) { return new(tree.Variable)(name, index, env.currentFileInfo); } }, // A variable entity useing the protective {} e.g. @{var} variableCurly: function () { var name, curly, index = i; if (input.charAt(i) === '@' && (curly = $(/^@\{([\w-]+)\}/))) { return new(tree.Variable)("@" + curly[1], index, env.currentFileInfo); } }, // // A Hexadecimal color // // #4F3C2F // // `rgb` and `hsl` colors are parsed through the `entities.call` parser. // color: function () { var rgb; if (input.charAt(i) === '#' && (rgb = $(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/))) { return new(tree.Color)(rgb[1]); } }, // // A Dimension, that is, a number and a unit // // 0.5em 95% // dimension: function () { var value, c = input.charCodeAt(i); //Is the first char of the dimension 0-9, '.', '+' or '-' if ((c > 57 || c < 43) || c === 47 || c == 44) return; if (value = $(/^([+-]?\d*\.?\d+)(%|[a-z]+)?/)) { return new(tree.Dimension)(value[1], value[2]); } }, // // A unicode descriptor, as is used in unicode-range // // U+0?? or U+00A1-00A9 // unicodeDescriptor: function () { var ud; if (ud = $(/^U\+[0-9a-fA-F?]+(\-[0-9a-fA-F?]+)?/)) { return new(tree.UnicodeDescriptor)(ud[0]); } }, // // JavaScript code to be evaluated // // `window.location.href` // javascript: function () { var str, j = i, e; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '`') { return } e && $('~'); if (str = $(/^`([^`]*)`/)) { return new(tree.JavaScript)(str[1], i, e); } } }, // // The variable part of a variable definition. Used in the `rule` parser // // @fink: // variable: function () { var name; if (input.charAt(i) === '@' && (name = $(/^(@[\w-]+)\s*:/))) { return name[1] } }, // // extend syntax - used to extend selectors // extend: function(isRule) { var elements, e, index = i, option, extendList = []; if (!$(isRule ? /^&:extend\(/ : /^:extend\(/)) { return; } do { option = null; elements = []; while (true) { option = $(/^(all)(?=\s*(\)|,))/); if (option) { break; } e = $(this.element); if (!e) { break; } elements.push(e); } option = option && option[1]; extendList.push(new(tree.Extend)(new(tree.Selector)(elements), option, index)); } while($(",")) expect(/^\)/); if (isRule) { expect(/^;/); } return extendList; }, // // extendRule - used in a rule to extend all the parent selectors // extendRule: function() { return this.extend(true); }, // // Mixins // mixin: { // // A Mixin call, with an optional argument list // // #mixins > .square(#fff); // .rounded(4px, black); // .button; // // The `while` loop is there because mixins can be // namespaced, but we only support the child and descendant // selector for now. // call: function () { var elements = [], e, c, args, delim, arg, index = i, s = input.charAt(i), important = false; if (s !== '.' && s !== '#') { return } save(); // stop us absorbing part of an invalid selector while (e = $(/^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/)) { elements.push(new(tree.Element)(c, e, i)); c = $('>'); } if ($('(')) { args = this.mixin.args.call(this, true).args; expect(')'); } args = args || []; if ($(this.important)) { important = true; } if (elements.length > 0 && ($(';') || peek('}'))) { return new(tree.mixin.Call)(elements, args, index, env.currentFileInfo, important); } restore(); }, args: function (isCall) { var expressions = [], argsSemiColon = [], isSemiColonSeperated, argsComma = [], expressionContainsNamed, name, nameLoop, value, arg, returner = {args:null, variadic: false}; while (true) { if (isCall) { arg = $(this.expression); } else { $(this.comment); if (input.charAt(i) === '.' && $(/^\.{3}/)) { returner.variadic = true; if ($(";") && !isSemiColonSeperated) { isSemiColonSeperated = true; } (isSemiColonSeperated ? argsSemiColon : argsComma) .push({ variadic: true }); break; } arg = $(this.entities.variable) || $(this.entities.literal) || $(this.entities.keyword); } if (!arg) { break; } nameLoop = null; if (arg.throwAwayComments) { arg.throwAwayComments(); } value = arg; var val = null; if (isCall) { // Variable if (arg.value.length == 1) { var val = arg.value[0]; } } else { val = arg; } if (val && val instanceof tree.Variable) { if ($(':')) { if (expressions.length > 0) { if (isSemiColonSeperated) { error("Cannot mix ; and , as delimiter types"); } expressionContainsNamed = true; } value = expect(this.expression); nameLoop = (name = val.name); } else if (!isCall && $(/^\.{3}/)) { returner.variadic = true; if ($(";") && !isSemiColonSeperated) { isSemiColonSeperated = true; } (isSemiColonSeperated ? argsSemiColon : argsComma) .push({ name: arg.name, variadic: true }); break; } else if (!isCall) { name = nameLoop = val.name; value = null; } } if (value) { expressions.push(value); } argsComma.push({ name:nameLoop, value:value }); if ($(',')) { continue; } if ($(';') || isSemiColonSeperated) { if (expressionContainsNamed) { error("Cannot mix ; and , as delimiter types"); } isSemiColonSeperated = true; if (expressions.length > 1) { value = new (tree.Value)(expressions); } argsSemiColon.push({ name:name, value:value }); name = null; expressions = []; expressionContainsNamed = false; } } returner.args = isSemiColonSeperated ? argsSemiColon : argsComma; return returner; }, // // A Mixin definition, with a list of parameters // // .rounded (@radius: 2px, @color) { // ... // } // // Until we have a finer grained state-machine, we have to // do a look-ahead, to make sure we don't have a mixin call. // See the `rule` function for more information. // // We start by matching `.rounded (`, and then proceed on to // the argument list, which has optional default values. // We store the parameters in `params`, with a `value` key, // if there is a value, such as in the case of `@radius`. // // Once we've got our params list, and a closing `)`, we parse // the `{...}` block. // definition: function () { var name, params = [], match, ruleset, param, value, cond, variadic = false; if ((input.charAt(i) !== '.' && input.charAt(i) !== '#') || peek(/^[^{]*\}/)) return; save(); if (match = $(/^([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/)) { name = match[1]; var argInfo = this.mixin.args.call(this, false); params = argInfo.args; variadic = argInfo.variadic; // .mixincall("@{a}"); // looks a bit like a mixin definition.. so we have to be nice and restore if (!$(')')) { furthest = i; restore(); } $(this.comment); if ($(/^when/)) { // Guard cond = expect(this.conditions, 'expected condition'); } ruleset = $(this.block); if (ruleset) { return new(tree.mixin.Definition)(name, params, ruleset, cond, variadic); } else { restore(); } } } }, // // Entities are the smallest recognized token, // and can be found inside a rule's value. // entity: function () { return $(this.entities.literal) || $(this.entities.variable) || $(this.entities.url) || $(this.entities.call) || $(this.entities.keyword) ||$(this.entities.javascript) || $(this.comment); }, // // A Rule terminator. Note that we use `peek()` to check for '}', // because the `block` rule will be expecting it, but we still need to make sure // it's there, if ';' was ommitted. // end: function () { return $(';') || peek('}'); }, // // IE's alpha function // // alpha(opacity=88) // alpha: function () { var value; if (! $(/^\(opacity=/i)) return; if (value = $(/^\d+/) || $(this.entities.variable)) { expect(')'); return new(tree.Alpha)(value); } }, // // A Selector Element // // div // + h1 // #socks // input[type="text"] // // Elements are the building blocks for Selectors, // they are made out of a `Combinator` (see combinator rule), // and an element name, such as a tag a class, or `*`. // element: function () { var e, t, c, v; c = $(this.combinator); e = $(/^(?:\d+\.\d+|\d+)%/) || $(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/) || $('*') || $('&') || $(this.attribute) || $(/^\([^()@]+\)/) || $(/^[\.#](?=@)/) || $(this.entities.variableCurly); if (! e) { if ($('(')) { if ((v = ($(this.selector))) && $(')')) { e = new(tree.Paren)(v); } } } if (e) { return new(tree.Element)(c, e, i) } }, // // Combinators combine elements together, in a Selector. // // Because our parser isn't white-space sensitive, special care // has to be taken, when parsing the descendant combinator, ` `, // as it's an empty space. We have to check the previous character // in the input, to see if it's a ` ` character. More info on how // we deal with this in *combinator.js*. // combinator: function () { var match, c = input.charAt(i); if (c === '>' || c === '+' || c === '~' || c === '|') { i++; while (input.charAt(i).match(/\s/)) { i++ } return new(tree.Combinator)(c); } else if (input.charAt(i - 1).match(/\s/)) { return new(tree.Combinator)(" "); } else { return new(tree.Combinator)(null); } }, // // A CSS Selector // // .class > div + h1 // li a:hover // // Selectors are made out of one or more Elements, see above. // selector: function () { var sel, e, elements = [], c, match, extend, extendList = []; while ((extend = $(this.extend)) || (e = $(this.element))) { if (extend) { extendList.push.apply(extendList, extend); } else { if (extendList.length) { error("Extend can only be used at the end of selector"); } c = input.charAt(i); elements.push(e) e = null; } if (c === '{' || c === '}' || c === ';' || c === ',' || c === ')') { break } } if (elements.length > 0) { return new(tree.Selector)(elements, extendList); } if (extendList.length) { error("Extend must be used to extend a selector, it cannot be used on its own"); } }, attribute: function () { var attr = '', key, val, op; if (! $('[')) return; if (!(key = $(this.entities.variableCurly))) { key = expect(/^(?:[_A-Za-z0-9-\*]*\|)?(?:[_A-Za-z0-9-]|\\.)+/); } if ((op = $(/^[|~*$^]?=/))) { val = $(this.entities.quoted) || $(/^[\w-]+/) || $(this.entities.variableCurly); } expect(']'); return new(tree.Attribute)(key, op, val); }, // // The `block` rule is used by `ruleset` and `mixin.definition`. // It's a wrapper around the `primary` rule, with added `{}`. // block: function () { var content; if ($('{') && (content = $(this.primary)) && $('}')) { return content; } }, // // div, .class, body > p {...} // ruleset: function () { var selectors = [], s, rules, match, debugInfo; save(); if (env.dumpLineNumbers) debugInfo = getDebugInfo(i, input, env); while (s = $(this.selector)) { selectors.push(s); $(this.comment); if (! $(',')) { break } $(this.comment); } if (selectors.length > 0 && (rules = $(this.block))) { var ruleset = new(tree.Ruleset)(selectors, rules, env.strictImports); if (env.dumpLineNumbers) ruleset.debugInfo = debugInfo; return ruleset; } else { // Backtrack furthest = i; restore(); } }, rule: function (tryAnonymous) { var name, value, c = input.charAt(i), important, match; save(); if (c === '.' || c === '#' || c === '&') { return } if (name = $(this.variable) || $(this.property)) { // prefer to try to parse first if its a variable or we are compressing // but always fallback on the other one value = !tryAnonymous && (env.compress || (name.charAt(0) === '@')) ? ($(this.value) || $(this.anonymousValue)) : ($(this.anonymousValue) || $(this.value)); important = $(this.important); if (value && $(this.end)) { return new(tree.Rule)(name, value, important, memo, env.currentFileInfo); } else { furthest = i; restore(); if (value && !tryAnonymous) { return this.rule(true); } } } }, anonymousValue: function () { if (match = /^([^@+\/'"*`(;{}-]*);/.exec(chunks[j])) { i += match[0].length - 1; return new(tree.Anonymous)(match[1]); } }, // // An @import directive // // @import "lib"; // // Depending on our environemnt, importing is done differently: // In the browser, it's an XHR request, in Node, it would be a // file-system operation. The function used for importing is // stored in `import`, which we pass to the Import constructor. // "import": function () { var path, features, index = i; save(); var dir = $(/^@import?\s+/); var options = (dir ? $(this.importOptions) : null) || {}; if (dir && (path = $(this.entities.quoted) || $(this.entities.url))) { features = $(this.mediaFeatures); if ($(';')) { features = features && new(tree.Value)(features); return new(tree.Import)(path, features, options, index, env.currentFileInfo); } } restore(); }, importOptions: function() { var o, options = {}, optionName, value; // list of options, surrounded by parens if (! $('(')) { return null; } do { if (o = $(this.importOption)) { optionName = o; value = true; switch(optionName) { case "css": optionName = "less"; value = false; break; case "once": optionName = "multiple"; value = false; break; } options[optionName] = value; if (! $(',')) { break } } } while (o); expect(')'); return options; }, importOption: function() { var opt = $(/^(less|css|multiple|once)/); if (opt) { return opt[1]; } }, mediaFeature: function () { var e, p, nodes = []; do { if (e = $(this.entities.keyword)) { nodes.push(e); } else if ($('(')) { p = $(this.property); e = $(this.value); if ($(')')) { if (p && e) { nodes.push(new(tree.Paren)(new(tree.Rule)(p, e, null, i, env.currentFileInfo, true))); } else if (e) { nodes.push(new(tree.Paren)(e)); } else { return null; } } else { return null } } } while (e); if (nodes.length > 0) { return new(tree.Expression)(nodes); } }, mediaFeatures: function () { var e, features = []; do { if (e = $(this.mediaFeature)) { features.push(e); if (! $(',')) { break } } else if (e = $(this.entities.variable)) { features.push(e); if (! $(',')) { break } } } while (e); return features.length > 0 ? features : null; }, media: function () { var features, rules, media, debugInfo; if (env.dumpLineNumbers) debugInfo = getDebugInfo(i, input, env); if ($(/^@media/)) { features = $(this.mediaFeatures); if (rules = $(this.block)) { media = new(tree.Media)(rules, features); if(env.dumpLineNumbers) media.debugInfo = debugInfo; return media; } } }, // // A CSS Directive // // @charset "utf-8"; // directive: function () { var name, value, rules, identifier, e, nodes, nonVendorSpecificName, hasBlock, hasIdentifier, hasExpression; if (input.charAt(i) !== '@') return; if (value = $(this['import']) || $(this.media)) { return value; } save(); name = $(/^@[a-z-]+/); if (!name) return; nonVendorSpecificName = name; if (name.charAt(1) == '-' && name.indexOf('-', 2) > 0) { nonVendorSpecificName = "@" + name.slice(name.indexOf('-', 2) + 1); } switch(nonVendorSpecificName) { case "@font-face": hasBlock = true; break; case "@viewport": case "@top-left": case "@top-left-corner": case "@top-center": case "@top-right": case "@top-right-corner": case "@bottom-left": case "@bottom-left-corner": case "@bottom-center": case "@bottom-right": case "@bottom-right-corner": case "@left-top": case "@left-middle": case "@left-bottom": case "@right-top": case "@right-middle": case "@right-bottom": hasBlock = true; break; case "@page": case "@document": case "@supports": case "@keyframes": hasBlock = true; hasIdentifier = true; break; case "@namespace": hasExpression = true; break; } if (hasIdentifier) { name += " " + ($(/^[^{]+/) || '').trim(); } if (hasBlock) { if (rules = $(this.block)) { return new(tree.Directive)(name, rules); } } else { if ((value = hasExpression ? $(this.expression) : $(this.entity)) && $(';')) { var directive = new(tree.Directive)(name, value); if (env.dumpLineNumbers) { directive.debugInfo = getDebugInfo(i, input, env); } return directive; } } restore(); }, // // A Value is a comma-delimited list of Expressions // // font-family: Baskerville, Georgia, serif; // // In a Rule, a Value represents everything after the `:`, // and before the `;`. // value: function () { var e, expressions = [], important; while (e = $(this.expression)) { expressions.push(e); if (! $(',')) { break } } if (expressions.length > 0) { return new(tree.Value)(expressions); } }, important: function () { if (input.charAt(i) === '!') { return $(/^! *important/); } }, sub: function () { var a, e; if ($('(')) { if (a = $(this.addition)) { e = new(tree.Expression)([a]); expect(')'); e.parens = true; return e; } } }, multiplication: function () { var m, a, op, operation, isSpaced, expression = []; if (m = $(this.operand)) { isSpaced = isWhitespace(input.charAt(i - 1)); while (!peek(/^\/[*\/]/) && (op = ($('/') || $('*')))) { if (a = $(this.operand)) { m.parensInOp = true; a.parensInOp = true; operation = new(tree.Operation)(op, [operation || m, a], isSpaced); isSpaced = isWhitespace(input.charAt(i - 1)); } else { break; } } return operation || m; } }, addition: function () { var m, a, op, operation, isSpaced; if (m = $(this.multiplication)) { isSpaced = isWhitespace(input.charAt(i - 1)); while ((op = $(/^[-+]\s+/) || (!isSpaced && ($('+') || $('-')))) && (a = $(this.multiplication))) { m.parensInOp = true; a.parensInOp = true; operation = new(tree.Operation)(op, [operation || m, a], isSpaced); isSpaced = isWhitespace(input.charAt(i - 1)); } return operation || m; } }, conditions: function () { var a, b, index = i, condition; if (a = $(this.condition)) { while ($(',') && (b = $(this.condition))) { condition = new(tree.Condition)('or', condition || a, b, index); } return condition || a; } }, condition: function () { var a, b, c, op, index = i, negate = false; if ($(/^not/)) { negate = true } expect('('); if (a = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) { if (op = $(/^(?:>=|=<|[<=>])/)) { if (b = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) { c = new(tree.Condition)(op, a, b, index, negate); } else { error('expected expression'); } } else { c = new(tree.Condition)('=', a, new(tree.Keyword)('true'), index, negate); } expect(')'); return $(/^and/) ? new(tree.Condition)('and', c, $(this.condition)) : c; } }, // // An operand is anything that can be part of an operation, // such as a Color, or a Variable // operand: function () { var negate, p = input.charAt(i + 1); if (input.charAt(i) === '-' && (p === '@' || p === '(')) { negate = $('-') } var o = $(this.sub) || $(this.entities.dimension) || $(this.entities.color) || $(this.entities.variable) || $(this.entities.call); if (negate) { o.parensInOp = true; o = new(tree.Negative)(o); } return o; }, // // Expressions either represent mathematical operations, // or white-space delimited Entities. // // 1px solid black // @var * 2 // expression: function () { var e, delim, entities = [], d; while (e = $(this.addition) || $(this.entity)) { entities.push(e); // operations do not allow keyword "/" dimension (e.g. small/20px) so we support that here if (!peek(/^\/[\/*]/) && (delim = $('/'))) { entities.push(new(tree.Anonymous)(delim)); } } if (entities.length > 0) { return new(tree.Expression)(entities); } }, property: function () { var name; if (name = $(/^(\*?-?[_a-z0-9-]+)\s*:/)) { return name[1]; } } } }; }; if (less.mode === 'browser' || less.mode === 'rhino') { // // Used by `@import` directives // less.Parser.importer = function (path, currentFileInfo, callback, env) { if (!/^([a-z-]+:)?\//.test(path) && currentFileInfo.currentDirectory) { path = currentFileInfo.currentDirectory + path; } var sheetEnv = env.toSheet(path); sheetEnv.processImports = false; sheetEnv.currentFileInfo = currentFileInfo; // We pass `true` as 3rd argument, to force the reload of the import. // This is so we can get the syntax tree as opposed to just the CSS output, // as we need this to evaluate the current stylesheet. loadStyleSheet(sheetEnv, function (e, root, data, sheet, _, path) { callback.call(null, e, root, path); }, true); }; } (function (tree) { tree.functions = { rgb: function (r, g, b) { return this.rgba(r, g, b, 1.0); }, rgba: function (r, g, b, a) { var rgb = [r, g, b].map(function (c) { return scaled(c, 256); }); a = number(a); return new(tree.Color)(rgb, a); }, hsl: function (h, s, l) { return this.hsla(h, s, l, 1.0); }, hsla: function (h, s, l, a) { h = (number(h) % 360) / 360; s = clamp(number(s)); l = clamp(number(l)); a = clamp(number(a)); var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s; var m1 = l * 2 - m2; return this.rgba(hue(h + 1/3) * 255, hue(h) * 255, hue(h - 1/3) * 255, a); function hue(h) { h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h); if (h * 6 < 1) return m1 + (m2 - m1) * h * 6; else if (h * 2 < 1) return m2; else if (h * 3 < 2) return m1 + (m2 - m1) * (2/3 - h) * 6; else return m1; } }, hsv: function(h, s, v) { return this.hsva(h, s, v, 1.0); }, hsva: function(h, s, v, a) { h = ((number(h) % 360) / 360) * 360; s = number(s); v = number(v); a = number(a); var i, f; i = Math.floor((h / 60) % 6); f = (h / 60) - i; var vs = [v, v * (1 - s), v * (1 - f * s), v * (1 - (1 - f) * s)]; var perm = [[0, 3, 1], [2, 0, 1], [1, 0, 3], [1, 2, 0], [3, 1, 0], [0, 1, 2]]; return this.rgba(vs[perm[i][0]] * 255, vs[perm[i][1]] * 255, vs[perm[i][2]] * 255, a); }, hue: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().h)); }, saturation: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().s * 100), '%'); }, lightness: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().l * 100), '%'); }, hsvhue: function(color) { return new(tree.Dimension)(Math.round(color.toHSV().h)); }, hsvsaturation: function (color) { return new(tree.Dimension)(Math.round(color.toHSV().s * 100), '%'); }, hsvvalue: function (color) { return new(tree.Dimension)(Math.round(color.toHSV().v * 100), '%'); }, red: function (color) { return new(tree.Dimension)(color.rgb[0]); }, green: function (color) { return new(tree.Dimension)(color.rgb[1]); }, blue: function (color) { return new(tree.Dimension)(color.rgb[2]); }, alpha: function (color) { return new(tree.Dimension)(color.toHSL().a); }, luma: function (color) { return new(tree.Dimension)(Math.round(color.luma() * color.alpha * 100), '%'); }, saturate: function (color, amount) { var hsl = color.toHSL(); hsl.s += amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, desaturate: function (color, amount) { var hsl = color.toHSL(); hsl.s -= amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, lighten: function (color, amount) { var hsl = color.toHSL(); hsl.l += amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, darken: function (color, amount) { var hsl = color.toHSL(); hsl.l -= amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, fadein: function (color, amount) { var hsl = color.toHSL(); hsl.a += amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, fadeout: function (color, amount) { var hsl = color.toHSL(); hsl.a -= amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, fade: function (color, amount) { var hsl = color.toHSL(); hsl.a = amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, spin: function (color, amount) { var hsl = color.toHSL(); var hue = (hsl.h + amount.value) % 360; hsl.h = hue < 0 ? 360 + hue : hue; return hsla(hsl); }, // // Copyright (c) 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein // http://sass-lang.com // mix: function (color1, color2, weight) { if (!weight) { weight = new(tree.Dimension)(50); } var p = weight.value / 100.0; var w = p * 2 - 1; var a = color1.toHSL().a - color2.toHSL().a; var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0; var w2 = 1 - w1; var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2, color1.rgb[1] * w1 + color2.rgb[1] * w2, color1.rgb[2] * w1 + color2.rgb[2] * w2]; var alpha = color1.alpha * p + color2.alpha * (1 - p); return new(tree.Color)(rgb, alpha); }, greyscale: function (color) { return this.desaturate(color, new(tree.Dimension)(100)); }, contrast: function (color, dark, light, threshold) { // filter: contrast(3.2); // should be kept as is, so check for color if (!color.rgb) { return null; } if (typeof light === 'undefined') { light = this.rgba(255, 255, 255, 1.0); } if (typeof dark === 'undefined') { dark = this.rgba(0, 0, 0, 1.0); } //Figure out which is actually light and dark! if (dark.luma() > light.luma()) { var t = light; light = dark; dark = t; } if (typeof threshold === 'undefined') { threshold = 0.43; } else { threshold = number(threshold); } if ((color.luma() * color.alpha) < threshold) { return light; } else { return dark; } }, e: function (str) { return new(tree.Anonymous)(str instanceof tree.JavaScript ? str.evaluated : str); }, escape: function (str) { return new(tree.Anonymous)(encodeURI(str.value).replace(/=/g, "%3D").replace(/:/g, "%3A").replace(/#/g, "%23").replace(/;/g, "%3B").replace(/\(/g, "%28").replace(/\)/g, "%29")); }, '%': function (quoted /* arg, arg, ...*/) { var args = Array.prototype.slice.call(arguments, 1), str = quoted.value; for (var i = 0; i < args.length; i++) { str = str.replace(/%[sda]/i, function(token) { var value = token.match(/s/i) ? args[i].value : args[i].toCSS(); return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value; }); } str = str.replace(/%%/g, '%'); return new(tree.Quoted)('"' + str + '"', str); }, unit: function (val, unit) { return new(tree.Dimension)(val.value, unit ? unit.toCSS() : ""); }, convert: function (val, unit) { return val.convertTo(unit.value); }, round: function (n, f) { var fraction = typeof(f) === "undefined" ? 0 : f.value; return this._math(function(num) { return num.toFixed(fraction); }, null, n); }, pi: function () { return new(tree.Dimension)(Math.PI); }, mod: function(a, b) { return new(tree.Dimension)(a.value % b.value, a.unit); }, pow: function(x, y) { if (typeof x === "number" && typeof y === "number") { x = new(tree.Dimension)(x); y = new(tree.Dimension)(y); } else if (!(x instanceof tree.Dimension) || !(y instanceof tree.Dimension)) { throw { type: "Argument", message: "arguments must be numbers" }; } return new(tree.Dimension)(Math.pow(x.value, y.value), x.unit); }, _math: function (fn, unit, n) { if (n instanceof tree.Dimension) { return new(tree.Dimension)(fn(parseFloat(n.value)), unit == null ? n.unit : unit); } else if (typeof(n) === 'number') { return fn(n); } else { throw { type: "Argument", message: "argument must be a number" }; } }, argb: function (color) { return new(tree.Anonymous)(color.toARGB()); }, percentage: function (n) { return new(tree.Dimension)(n.value * 100, '%'); }, color: function (n) { if (n instanceof tree.Quoted) { return new(tree.Color)(n.value.slice(1)); } else { throw { type: "Argument", message: "argument must be a string" }; } }, iscolor: function (n) { return this._isa(n, tree.Color); }, isnumber: function (n) { return this._isa(n, tree.Dimension); }, isstring: function (n) { return this._isa(n, tree.Quoted); }, iskeyword: function (n) { return this._isa(n, tree.Keyword); }, isurl: function (n) { return this._isa(n, tree.URL); }, ispixel: function (n) { return this.isunit(n, 'px'); }, ispercentage: function (n) { return this.isunit(n, '%'); }, isem: function (n) { return this.isunit(n, 'em'); }, isunit: function (n, unit) { return (n instanceof tree.Dimension) && n.unit.is(unit.value || unit) ? tree.True : tree.False; }, _isa: function (n, Type) { return (n instanceof Type) ? tree.True : tree.False; }, /* Blending modes */ multiply: function(color1, color2) { var r = color1.rgb[0] * color2.rgb[0] / 255; var g = color1.rgb[1] * color2.rgb[1] / 255; var b = color1.rgb[2] * color2.rgb[2] / 255; return this.rgb(r, g, b); }, screen: function(color1, color2) { var r = 255 - (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255; var g = 255 - (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255; var b = 255 - (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255; return this.rgb(r, g, b); }, overlay: function(color1, color2) { var r = color1.rgb[0] < 128 ? 2 * color1.rgb[0] * color2.rgb[0] / 255 : 255 - 2 * (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255; var g = color1.rgb[1] < 128 ? 2 * color1.rgb[1] * color2.rgb[1] / 255 : 255 - 2 * (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255; var b = color1.rgb[2] < 128 ? 2 * color1.rgb[2] * color2.rgb[2] / 255 : 255 - 2 * (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255; return this.rgb(r, g, b); }, softlight: function(color1, color2) { var t = color2.rgb[0] * color1.rgb[0] / 255; var r = t + color1.rgb[0] * (255 - (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255 - t) / 255; t = color2.rgb[1] * color1.rgb[1] / 255; var g = t + color1.rgb[1] * (255 - (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255 - t) / 255; t = color2.rgb[2] * color1.rgb[2] / 255; var b = t + color1.rgb[2] * (255 - (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255 - t) / 255; return this.rgb(r, g, b); }, hardlight: function(color1, color2) { var r = color2.rgb[0] < 128 ? 2 * color2.rgb[0] * color1.rgb[0] / 255 : 255 - 2 * (255 - color2.rgb[0]) * (255 - color1.rgb[0]) / 255; var g = color2.rgb[1] < 128 ? 2 * color2.rgb[1] * color1.rgb[1] / 255 : 255 - 2 * (255 - color2.rgb[1]) * (255 - color1.rgb[1]) / 255; var b = color2.rgb[2] < 128 ? 2 * color2.rgb[2] * color1.rgb[2] / 255 : 255 - 2 * (255 - color2.rgb[2]) * (255 - color1.rgb[2]) / 255; return this.rgb(r, g, b); }, difference: function(color1, color2) { var r = Math.abs(color1.rgb[0] - color2.rgb[0]); var g = Math.abs(color1.rgb[1] - color2.rgb[1]); var b = Math.abs(color1.rgb[2] - color2.rgb[2]); return this.rgb(r, g, b); }, exclusion: function(color1, color2) { var r = color1.rgb[0] + color2.rgb[0] * (255 - color1.rgb[0] - color1.rgb[0]) / 255; var g = color1.rgb[1] + color2.rgb[1] * (255 - color1.rgb[1] - color1.rgb[1]) / 255; var b = color1.rgb[2] + color2.rgb[2] * (255 - color1.rgb[2] - color1.rgb[2]) / 255; return this.rgb(r, g, b); }, average: function(color1, color2) { var r = (color1.rgb[0] + color2.rgb[0]) / 2; var g = (color1.rgb[1] + color2.rgb[1]) / 2; var b = (color1.rgb[2] + color2.rgb[2]) / 2; return this.rgb(r, g, b); }, negation: function(color1, color2) { var r = 255 - Math.abs(255 - color2.rgb[0] - color1.rgb[0]); var g = 255 - Math.abs(255 - color2.rgb[1] - color1.rgb[1]); var b = 255 - Math.abs(255 - color2.rgb[2] - color1.rgb[2]); return this.rgb(r, g, b); }, tint: function(color, amount) { return this.mix(this.rgb(255,255,255), color, amount); }, shade: function(color, amount) { return this.mix(this.rgb(0, 0, 0), color, amount); }, extract: function(values, index) { index = index.value - 1; // (1-based index) return values.value[index]; }, "data-uri": function(mimetypeNode, filePathNode) { if (typeof window !== 'undefined') { return new tree.URL(filePathNode || mimetypeNode, this.currentFileInfo).eval(this.env); } var mimetype = mimetypeNode.value; var filePath = (filePathNode && filePathNode.value); var fs = require("fs"), path = require("path"), useBase64 = false; if (arguments.length < 2) { filePath = mimetype; } if (this.env.isPathRelative(filePath)) { if (this.currentFileInfo.relativeUrls) { filePath = path.join(this.currentFileInfo.currentDirectory, filePath); } else { filePath = path.join(this.currentFileInfo.entryPath, filePath); } } // detect the mimetype if not given if (arguments.length < 2) { var mime; try { mime = require('mime'); } catch (ex) { mime = tree._mime; } mimetype = mime.lookup(filePath); // use base 64 unless it's an ASCII or UTF-8 format var charset = mime.charsets.lookup(mimetype); useBase64 = ['US-ASCII', 'UTF-8'].indexOf(charset) < 0; if (useBase64) mimetype += ';base64'; } else { useBase64 = /;base64$/.test(mimetype) } var buf = fs.readFileSync(filePath); // IE8 cannot handle a data-uri larger than 32KB. If this is exceeded // and the --ieCompat flag is enabled, return a normal url() instead. var DATA_URI_MAX_KB = 32, fileSizeInKB = parseInt((buf.length / 1024), 10); if (fileSizeInKB >= DATA_URI_MAX_KB) { if (this.env.ieCompat !== false) { if (!this.env.silent) { console.warn("Skipped data-uri embedding of %s because its size (%dKB) exceeds IE8-safe %dKB!", filePath, fileSizeInKB, DATA_URI_MAX_KB); } return new tree.URL(filePathNode || mimetypeNode, this.currentFileInfo).eval(this.env); } else if (!this.env.silent) { // if explicitly disabled (via --no-ie-compat on CLI, or env.ieCompat === false), merely warn console.warn("WARNING: Embedding %s (%dKB) exceeds IE8's data-uri size limit of %dKB!", filePath, fileSizeInKB, DATA_URI_MAX_KB); } } buf = useBase64 ? buf.toString('base64') : encodeURIComponent(buf); var uri = "'data:" + mimetype + ',' + buf + "'"; return new(tree.URL)(new(tree.Anonymous)(uri)); } }; // these static methods are used as a fallback when the optional 'mime' dependency is missing tree._mime = { // this map is intentionally incomplete // if you want more, install 'mime' dep _types: { '.htm' : 'text/html', '.html': 'text/html', '.gif' : 'image/gif', '.jpg' : 'image/jpeg', '.jpeg': 'image/jpeg', '.png' : 'image/png' }, lookup: function (filepath) { var ext = require('path').extname(filepath), type = tree._mime._types[ext]; if (type === undefined) { throw new Error('Optional dependency "mime" is required for ' + ext); } return type; }, charsets: { lookup: function (type) { // assumes all text types are UTF-8 return type && (/^text\//).test(type) ? 'UTF-8' : ''; } } }; var mathFunctions = [{name:"ceil"}, {name:"floor"}, {name: "sqrt"}, {name:"abs"}, {name:"tan", unit: ""}, {name:"sin", unit: ""}, {name:"cos", unit: ""}, {name:"atan", unit: "rad"}, {name:"asin", unit: "rad"}, {name:"acos", unit: "rad"}], createMathFunction = function(name, unit) { return function(n) { if (unit != null) { n = n.unify(); } return this._math(Math[name], unit, n); }; }; for(var i = 0; i < mathFunctions.length; i++) { tree.functions[mathFunctions[i].name] = createMathFunction(mathFunctions[i].name, mathFunctions[i].unit); } function hsla(color) { return tree.functions.hsla(color.h, color.s, color.l, color.a); } function scaled(n, size) { if (n instanceof tree.Dimension && n.unit.is('%')) { return parseFloat(n.value * size / 100); } else { return number(n); } } function number(n) { if (n instanceof tree.Dimension) { return parseFloat(n.unit.is('%') ? n.value / 100 : n.value); } else if (typeof(n) === 'number') { return n; } else { throw { error: "RuntimeError", message: "color functions take numbers as parameters" }; } } function clamp(val) { return Math.min(1, Math.max(0, val)); } tree.functionCall = function(env, currentFileInfo) { this.env = env; this.currentFileInfo = currentFileInfo; }; tree.functionCall.prototype = tree.functions; })(require('./tree')); (function (tree) { tree.colors = { 'aliceblue':'#f0f8ff', 'antiquewhite':'#faebd7', 'aqua':'#00ffff', 'aquamarine':'#7fffd4', 'azure':'#f0ffff', 'beige':'#f5f5dc', 'bisque':'#ffe4c4', 'black':'#000000', 'blanchedalmond':'#ffebcd', 'blue':'#0000ff', 'blueviolet':'#8a2be2', 'brown':'#a52a2a', 'burlywood':'#deb887', 'cadetblue':'#5f9ea0', 'chartreuse':'#7fff00', 'chocolate':'#d2691e', 'coral':'#ff7f50', 'cornflowerblue':'#6495ed', 'cornsilk':'#fff8dc', 'crimson':'#dc143c', 'cyan':'#00ffff', 'darkblue':'#00008b', 'darkcyan':'#008b8b', 'darkgoldenrod':'#b8860b', 'darkgray':'#a9a9a9', 'darkgrey':'#a9a9a9', 'darkgreen':'#006400', 'darkkhaki':'#bdb76b', 'darkmagenta':'#8b008b', 'darkolivegreen':'#556b2f', 'darkorange':'#ff8c00', 'darkorchid':'#9932cc', 'darkred':'#8b0000', 'darksalmon':'#e9967a', 'darkseagreen':'#8fbc8f', 'darkslateblue':'#483d8b', 'darkslategray':'#2f4f4f', 'darkslategrey':'#2f4f4f', 'darkturquoise':'#00ced1', 'darkviolet':'#9400d3', 'deeppink':'#ff1493', 'deepskyblue':'#00bfff', 'dimgray':'#696969', 'dimgrey':'#696969', 'dodgerblue':'#1e90ff', 'firebrick':'#b22222', 'floralwhite':'#fffaf0', 'forestgreen':'#228b22', 'fuchsia':'#ff00ff', 'gainsboro':'#dcdcdc', 'ghostwhite':'#f8f8ff', 'gold':'#ffd700', 'goldenrod':'#daa520', 'gray':'#808080', 'grey':'#808080', 'green':'#008000', 'greenyellow':'#adff2f', 'honeydew':'#f0fff0', 'hotpink':'#ff69b4', 'indianred':'#cd5c5c', 'indigo':'#4b0082', 'ivory':'#fffff0', 'khaki':'#f0e68c', 'lavender':'#e6e6fa', 'lavenderblush':'#fff0f5', 'lawngreen':'#7cfc00', 'lemonchiffon':'#fffacd', 'lightblue':'#add8e6', 'lightcoral':'#f08080', 'lightcyan':'#e0ffff', 'lightgoldenrodyellow':'#fafad2', 'lightgray':'#d3d3d3', 'lightgrey':'#d3d3d3', 'lightgreen':'#90ee90', 'lightpink':'#ffb6c1', 'lightsalmon':'#ffa07a', 'lightseagreen':'#20b2aa', 'lightskyblue':'#87cefa', 'lightslategray':'#778899', 'lightslategrey':'#778899', 'lightsteelblue':'#b0c4de', 'lightyellow':'#ffffe0', 'lime':'#00ff00', 'limegreen':'#32cd32', 'linen':'#faf0e6', 'magenta':'#ff00ff', 'maroon':'#800000', 'mediumaquamarine':'#66cdaa', 'mediumblue':'#0000cd', 'mediumorchid':'#ba55d3', 'mediumpurple':'#9370d8', 'mediumseagreen':'#3cb371', 'mediumslateblue':'#7b68ee', 'mediumspringgreen':'#00fa9a', 'mediumturquoise':'#48d1cc', 'mediumvioletred':'#c71585', 'midnightblue':'#191970', 'mintcream':'#f5fffa', 'mistyrose':'#ffe4e1', 'moccasin':'#ffe4b5', 'navajowhite':'#ffdead', 'navy':'#000080', 'oldlace':'#fdf5e6', 'olive':'#808000', 'olivedrab':'#6b8e23', 'orange':'#ffa500', 'orangered':'#ff4500', 'orchid':'#da70d6', 'palegoldenrod':'#eee8aa', 'palegreen':'#98fb98', 'paleturquoise':'#afeeee', 'palevioletred':'#d87093', 'papayawhip':'#ffefd5', 'peachpuff':'#ffdab9', 'peru':'#cd853f', 'pink':'#ffc0cb', 'plum':'#dda0dd', 'powderblue':'#b0e0e6', 'purple':'#800080', 'red':'#ff0000', 'rosybrown':'#bc8f8f', 'royalblue':'#4169e1', 'saddlebrown':'#8b4513', 'salmon':'#fa8072', 'sandybrown':'#f4a460', 'seagreen':'#2e8b57', 'seashell':'#fff5ee', 'sienna':'#a0522d', 'silver':'#c0c0c0', 'skyblue':'#87ceeb', 'slateblue':'#6a5acd', 'slategray':'#708090', 'slategrey':'#708090', 'snow':'#fffafa', 'springgreen':'#00ff7f', 'steelblue':'#4682b4', 'tan':'#d2b48c', 'teal':'#008080', 'thistle':'#d8bfd8', 'tomato':'#ff6347', // 'transparent':'rgba(0,0,0,0)', 'turquoise':'#40e0d0', 'violet':'#ee82ee', 'wheat':'#f5deb3', 'white':'#ffffff', 'whitesmoke':'#f5f5f5', 'yellow':'#ffff00', 'yellowgreen':'#9acd32' }; })(require('./tree')); (function (tree) { tree.Alpha = function (val) { this.value = val; }; tree.Alpha.prototype = { type: "Alpha", accept: function (visitor) { this.value = visitor.visit(this.value); }, eval: function (env) { if (this.value.eval) { this.value = this.value.eval(env) } return this; }, toCSS: function () { return "alpha(opacity=" + (this.value.toCSS ? this.value.toCSS() : this.value) + ")"; } }; })(require('../tree')); (function (tree) { tree.Anonymous = function (string) { this.value = string.value || string; }; tree.Anonymous.prototype = { type: "Anonymous", toCSS: function () { return this.value; }, eval: function () { return this }, compare: function (x) { if (!x.toCSS) { return -1; } var left = this.toCSS(), right = x.toCSS(); if (left === right) { return 0; } return left < right ? -1 : 1; } }; })(require('../tree')); (function (tree) { tree.Assignment = function (key, val) { this.key = key; this.value = val; }; tree.Assignment.prototype = { type: "Assignment", accept: function (visitor) { this.value = visitor.visit(this.value); }, toCSS: function () { return this.key + '=' + (this.value.toCSS ? this.value.toCSS() : this.value); }, eval: function (env) { if (this.value.eval) { return new(tree.Assignment)(this.key, this.value.eval(env)); } return this; } }; })(require('../tree'));(function (tree) { // // A function call node. // tree.Call = function (name, args, index, currentFileInfo) { this.name = name; this.args = args; this.index = index; this.currentFileInfo = currentFileInfo; }; tree.Call.prototype = { type: "Call", accept: function (visitor) { this.args = visitor.visit(this.args); }, // // When evaluating a function call, // we either find the function in `tree.functions` [1], // in which case we call it, passing the evaluated arguments, // if this returns null or we cannot find the function, we // simply print it out as it appeared originally [2]. // // The *functions.js* file contains the built-in functions. // // The reason why we evaluate the arguments, is in the case where // we try to pass a variable to a function, like: `saturate(@color)`. // The function should receive the value, not the variable. // eval: function (env) { var args = this.args.map(function (a) { return a.eval(env); }), nameLC = this.name.toLowerCase(), result, func; if (nameLC in tree.functions) { // 1. try { func = new tree.functionCall(env, this.currentFileInfo); result = func[nameLC].apply(func, args); if (result != null) { return result; } } catch (e) { throw { type: e.type || "Runtime", message: "error evaluating function `" + this.name + "`" + (e.message ? ': ' + e.message : ''), index: this.index, filename: this.currentFileInfo.filename }; } } // 2. return new(tree.Anonymous)(this.name + "(" + args.map(function (a) { return a.toCSS(env); }).join(', ') + ")"); }, toCSS: function (env) { return this.eval(env).toCSS(); } }; })(require('../tree')); (function (tree) { // // RGB Colors - #ff0014, #eee // tree.Color = function (rgb, a) { // // The end goal here, is to parse the arguments // into an integer triplet, such as `128, 255, 0` // // This facilitates operations and conversions. // if (Array.isArray(rgb)) { this.rgb = rgb; } else if (rgb.length == 6) { this.rgb = rgb.match(/.{2}/g).map(function (c) { return parseInt(c, 16); }); } else { this.rgb = rgb.split('').map(function (c) { return parseInt(c + c, 16); }); } this.alpha = typeof(a) === 'number' ? a : 1; }; tree.Color.prototype = { type: "Color", eval: function () { return this }, luma: function () { return (0.2126 * this.rgb[0] / 255) + (0.7152 * this.rgb[1] / 255) + (0.0722 * this.rgb[2] / 255); }, // // If we have some transparency, the only way to represent it // is via `rgba`. Otherwise, we use the hex representation, // which has better compatibility with older browsers. // Values are capped between `0` and `255`, rounded and zero-padded. // toCSS: function (env, doNotCompress) { var compress = env && env.compress && !doNotCompress; if (this.alpha < 1.0) { return "rgba(" + this.rgb.map(function (c) { return Math.round(c); }).concat(this.alpha).join(',' + (compress ? '' : ' ')) + ")"; } else { var color = this.rgb.map(function (i) { i = Math.round(i); i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16); return i.length === 1 ? '0' + i : i; }).join(''); if (compress) { color = color.split(''); // Convert color to short format if (color[0] == color[1] && color[2] == color[3] && color[4] == color[5]) { color = color[0] + color[2] + color[4]; } else { color = color.join(''); } } return '#' + color; } }, // // Operations have to be done per-channel, if not, // channels will spill onto each other. Once we have // our result, in the form of an integer triplet, // we create a new Color node to hold the result. // operate: function (env, op, other) { var result = []; if (! (other instanceof tree.Color)) { other = other.toColor(); } for (var c = 0; c < 3; c++) { result[c] = tree.operate(env, op, this.rgb[c], other.rgb[c]); } return new(tree.Color)(result, this.alpha + other.alpha); }, toHSL: function () { var r = this.rgb[0] / 255, g = this.rgb[1] / 255, b = this.rgb[2] / 255, a = this.alpha; var max = Math.max(r, g, b), min = Math.min(r, g, b); var h, s, l = (max + min) / 2, d = max - min; if (max === min) { h = s = 0; } else { s = l > 0.5 ? d / (2 - max - min) : d / (max + min); switch (max) { case r: h = (g - b) / d + (g < b ? 6 : 0); break; case g: h = (b - r) / d + 2; break; case b: h = (r - g) / d + 4; break; } h /= 6; } return { h: h * 360, s: s, l: l, a: a }; }, //Adapted from http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript toHSV: function () { var r = this.rgb[0] / 255, g = this.rgb[1] / 255, b = this.rgb[2] / 255, a = this.alpha; var max = Math.max(r, g, b), min = Math.min(r, g, b); var h, s, v = max; var d = max - min; if (max === 0) { s = 0; } else { s = d / max; } if (max === min) { h = 0; } else { switch(max){ case r: h = (g - b) / d + (g < b ? 6 : 0); break; case g: h = (b - r) / d + 2; break; case b: h = (r - g) / d + 4; break; } h /= 6; } return { h: h * 360, s: s, v: v, a: a }; }, toARGB: function () { var argb = [Math.round(this.alpha * 255)].concat(this.rgb); return '#' + argb.map(function (i) { i = Math.round(i); i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16); return i.length === 1 ? '0' + i : i; }).join(''); }, compare: function (x) { if (!x.rgb) { return -1; } return (x.rgb[0] === this.rgb[0] && x.rgb[1] === this.rgb[1] && x.rgb[2] === this.rgb[2] && x.alpha === this.alpha) ? 0 : -1; } }; })(require('../tree')); (function (tree) { tree.Comment = function (value, silent) { this.value = value; this.silent = !!silent; }; tree.Comment.prototype = { type: "Comment", toCSS: function (env) { return env.compress ? '' : this.value; }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.Condition = function (op, l, r, i, negate) { this.op = op.trim(); this.lvalue = l; this.rvalue = r; this.index = i; this.negate = negate; }; tree.Condition.prototype = { type: "Condition", accept: function (visitor) { this.lvalue = visitor.visit(this.lvalue); this.rvalue = visitor.visit(this.rvalue); }, eval: function (env) { var a = this.lvalue.eval(env), b = this.rvalue.eval(env); var i = this.index, result; var result = (function (op) { switch (op) { case 'and': return a && b; case 'or': return a || b; default: if (a.compare) { result = a.compare(b); } else if (b.compare) { result = b.compare(a); } else { throw { type: "Type", message: "Unable to perform comparison", index: i }; } switch (result) { case -1: return op === '<' || op === '=<'; case 0: return op === '=' || op === '>=' || op === '=<'; case 1: return op === '>' || op === '>='; } } })(this.op); return this.negate ? !result : result; } }; })(require('../tree')); (function (tree) { // // A number with a unit // tree.Dimension = function (value, unit) { this.value = parseFloat(value); this.unit = (unit && unit instanceof tree.Unit) ? unit : new(tree.Unit)(unit ? [unit] : undefined); }; tree.Dimension.prototype = { type: "Dimension", accept: function (visitor) { this.unit = visitor.visit(this.unit); }, eval: function (env) { return this; }, toColor: function () { return new(tree.Color)([this.value, this.value, this.value]); }, toCSS: function (env) { if ((env && env.strictUnits) && !this.unit.isSingular()) { throw new Error("Multiple units in dimension. Correct the units or use the unit function. Bad unit: "+this.unit.toString()); } var value = this.value, strValue = String(value); if (value !== 0 && value < 0.000001 && value > -0.000001) { // would be output 1e-6 etc. strValue = value.toFixed(20).replace(/0+$/, ""); } if (env && env.compress) { // Zero values doesn't need a unit if (value === 0 && !this.unit.isAngle()) { return strValue; } // Float values doesn't need a leading zero if (value > 0 && value < 1) { strValue = (strValue).substr(1); } } return strValue + this.unit.toCSS(env); }, // In an operation between two Dimensions, // we default to the first Dimension's unit, // so `1px + 2` will yield `3px`. operate: function (env, op, other) { var value = tree.operate(env, op, this.value, other.value), unit = this.unit.clone(); if (op === '+' || op === '-') { if (unit.numerator.length === 0 && unit.denominator.length === 0) { unit.numerator = other.unit.numerator.slice(0); unit.denominator = other.unit.denominator.slice(0); } else if (other.unit.numerator.length == 0 && unit.denominator.length == 0) { // do nothing } else { other = other.convertTo(this.unit.usedUnits()); if(env.strictUnits && other.unit.toString() !== unit.toString()) { throw new Error("Incompatible units. Change the units or use the unit function. Bad units: '" + unit.toString() + "' and '" + other.unit.toString() + "'."); } value = tree.operate(env, op, this.value, other.value); } } else if (op === '*') { unit.numerator = unit.numerator.concat(other.unit.numerator).sort(); unit.denominator = unit.denominator.concat(other.unit.denominator).sort(); unit.cancel(); } else if (op === '/') { unit.numerator = unit.numerator.concat(other.unit.denominator).sort(); unit.denominator = unit.denominator.concat(other.unit.numerator).sort(); unit.cancel(); } return new(tree.Dimension)(value, unit); }, compare: function (other) { if (other instanceof tree.Dimension) { var a = this.unify(), b = other.unify(), aValue = a.value, bValue = b.value; if (bValue > aValue) { return -1; } else if (bValue < aValue) { return 1; } else { if (!b.unit.isEmpty() && a.unit.compare(b.unit) !== 0) { return -1; } return 0; } } else { return -1; } }, unify: function () { return this.convertTo({ length: 'm', duration: 's', angle: 'rad' }); }, convertTo: function (conversions) { var value = this.value, unit = this.unit.clone(), i, groupName, group, conversion, targetUnit, derivedConversions = {}; if (typeof conversions === 'string') { for(i in tree.UnitConversions) { if (tree.UnitConversions[i].hasOwnProperty(conversions)) { derivedConversions = {}; derivedConversions[i] = conversions; } } conversions = derivedConversions; } for (groupName in conversions) { if (conversions.hasOwnProperty(groupName)) { targetUnit = conversions[groupName]; group = tree.UnitConversions[groupName]; unit.map(function (atomicUnit, denominator) { if (group.hasOwnProperty(atomicUnit)) { if (denominator) { value = value / (group[atomicUnit] / group[targetUnit]); } else { value = value * (group[atomicUnit] / group[targetUnit]); } return targetUnit; } return atomicUnit; }); } } unit.cancel(); return new(tree.Dimension)(value, unit); } }; // http://www.w3.org/TR/css3-values/#absolute-lengths tree.UnitConversions = { length: { 'm': 1, 'cm': 0.01, 'mm': 0.001, 'in': 0.0254, 'pt': 0.0254 / 72, 'pc': 0.0254 / 72 * 12 }, duration: { 's': 1, 'ms': 0.001 }, angle: { 'rad': 1/(2*Math.PI), 'deg': 1/360, 'grad': 1/400, 'turn': 1 } }; tree.Unit = function (numerator, denominator, backupUnit) { this.numerator = numerator ? numerator.slice(0).sort() : []; this.denominator = denominator ? denominator.slice(0).sort() : []; this.backupUnit = backupUnit; }; tree.Unit.prototype = { type: "Unit", clone: function () { return new tree.Unit(this.numerator.slice(0), this.denominator.slice(0), this.backupUnit); }, toCSS: function (env) { if (this.numerator.length >= 1) { return this.numerator[0]; } if (this.denominator.length >= 1) { return this.denominator[0]; } if ((!env || !env.strictUnits) && this.backupUnit) { return this.backupUnit; } return ""; }, toString: function () { var i, returnStr = this.numerator.join("*"); for (i = 0; i < this.denominator.length; i++) { returnStr += "/" + this.denominator[i]; } return returnStr; }, compare: function (other) { return this.is(other.toString()) ? 0 : -1; }, is: function (unitString) { return this.toString() === unitString; }, isAngle: function () { return tree.UnitConversions.angle.hasOwnProperty(this.toCSS()); }, isEmpty: function () { return this.numerator.length == 0 && this.denominator.length == 0; }, isSingular: function() { return this.numerator.length <= 1 && this.denominator.length == 0; }, map: function(callback) { var i; for (i = 0; i < this.numerator.length; i++) { this.numerator[i] = callback(this.numerator[i], false); } for (i = 0; i < this.denominator.length; i++) { this.denominator[i] = callback(this.denominator[i], true); } }, usedUnits: function() { var group, groupName, result = {}; for (groupName in tree.UnitConversions) { if (tree.UnitConversions.hasOwnProperty(groupName)) { group = tree.UnitConversions[groupName]; this.map(function (atomicUnit) { if (group.hasOwnProperty(atomicUnit) && !result[groupName]) { result[groupName] = atomicUnit; } return atomicUnit; }); } } return result; }, cancel: function () { var counter = {}, atomicUnit, i, backup; for (i = 0; i < this.numerator.length; i++) { atomicUnit = this.numerator[i]; if (!backup) { backup = atomicUnit; } counter[atomicUnit] = (counter[atomicUnit] || 0) + 1; } for (i = 0; i < this.denominator.length; i++) { atomicUnit = this.denominator[i]; if (!backup) { backup = atomicUnit; } counter[atomicUnit] = (counter[atomicUnit] || 0) - 1; } this.numerator = []; this.denominator = []; for (atomicUnit in counter) { if (counter.hasOwnProperty(atomicUnit)) { var count = counter[atomicUnit]; if (count > 0) { for (i = 0; i < count; i++) { this.numerator.push(atomicUnit); } } else if (count < 0) { for (i = 0; i < -count; i++) { this.denominator.push(atomicUnit); } } } } if (this.numerator.length === 0 && this.denominator.length === 0 && backup) { this.backupUnit = backup; } this.numerator.sort(); this.denominator.sort(); } }; })(require('../tree')); (function (tree) { tree.Directive = function (name, value) { this.name = name; if (Array.isArray(value)) { this.ruleset = new(tree.Ruleset)([], value); this.ruleset.allowImports = true; } else { this.value = value; } }; tree.Directive.prototype = { type: "Directive", accept: function (visitor) { this.ruleset = visitor.visit(this.ruleset); this.value = visitor.visit(this.value); }, toCSS: function (env) { if (this.ruleset) { this.ruleset.root = true; return this.name + (env.compress ? '{' : ' {\n ') + this.ruleset.toCSS(env).trim().replace(/\n/g, '\n ') + (env.compress ? '}': '\n}\n'); } else { return this.name + ' ' + this.value.toCSS() + ';\n'; } }, eval: function (env) { var evaldDirective = this; if (this.ruleset) { env.frames.unshift(this); evaldDirective = new(tree.Directive)(this.name); evaldDirective.ruleset = this.ruleset.eval(env); env.frames.shift(); } return evaldDirective; }, variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) }, find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) }, rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) } }; })(require('../tree')); (function (tree) { tree.Element = function (combinator, value, index) { this.combinator = combinator instanceof tree.Combinator ? combinator : new(tree.Combinator)(combinator); if (typeof(value) === 'string') { this.value = value.trim(); } else if (value) { this.value = value; } else { this.value = ""; } this.index = index; }; tree.Element.prototype = { type: "Element", accept: function (visitor) { this.combinator = visitor.visit(this.combinator); this.value = visitor.visit(this.value); }, eval: function (env) { return new(tree.Element)(this.combinator, this.value.eval ? this.value.eval(env) : this.value, this.index); }, toCSS: function (env) { var value = (this.value.toCSS ? this.value.toCSS(env) : this.value); if (value == '' && this.combinator.value.charAt(0) == '&') { return ''; } else { return this.combinator.toCSS(env || {}) + value; } } }; tree.Attribute = function (key, op, value) { this.key = key; this.op = op; this.value = value; }; tree.Attribute.prototype = { type: "Attribute", accept: function (visitor) { this.value = visitor.visit(this.value); }, eval: function (env) { return new(tree.Attribute)(this.key.eval ? this.key.eval(env) : this.key, this.op, (this.value && this.value.eval) ? this.value.eval(env) : this.value); }, toCSS: function (env) { var value = this.key.toCSS ? this.key.toCSS(env) : this.key; if (this.op) { value += this.op; value += (this.value.toCSS ? this.value.toCSS(env) : this.value); } return '[' + value + ']'; } }; tree.Combinator = function (value) { if (value === ' ') { this.value = ' '; } else { this.value = value ? value.trim() : ""; } }; tree.Combinator.prototype = { type: "Combinator", toCSS: function (env) { return { '' : '', ' ' : ' ', ':' : ' :', '+' : env.compress ? '+' : ' + ', '~' : env.compress ? '~' : ' ~ ', '>' : env.compress ? '>' : ' > ', '|' : env.compress ? '|' : ' | ' }[this.value]; } }; })(require('../tree')); (function (tree) { tree.Expression = function (value) { this.value = value; }; tree.Expression.prototype = { type: "Expression", accept: function (visitor) { this.value = visitor.visit(this.value); }, eval: function (env) { var returnValue, inParenthesis = this.parens && !this.parensInOp, doubleParen = false; if (inParenthesis) { env.inParenthesis(); } if (this.value.length > 1) { returnValue = new(tree.Expression)(this.value.map(function (e) { return e.eval(env); })); } else if (this.value.length === 1) { if (this.value[0].parens && !this.value[0].parensInOp) { doubleParen = true; } returnValue = this.value[0].eval(env); } else { returnValue = this; } if (inParenthesis) { env.outOfParenthesis(); } if (this.parens && this.parensInOp && !(env.isMathOn()) && !doubleParen) { returnValue = new(tree.Paren)(returnValue); } return returnValue; }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS ? e.toCSS(env) : ''; }).join(' '); }, throwAwayComments: function () { this.value = this.value.filter(function(v) { return !(v instanceof tree.Comment); }); } }; })(require('../tree')); (function (tree) { tree.Extend = function Extend(selector, option, index) { this.selector = selector; this.option = option; this.index = index; switch(option) { case "all": this.allowBefore = true; this.allowAfter = true; break; default: this.allowBefore = false; this.allowAfter = false; break; } }; tree.Extend.prototype = { type: "Extend", accept: function (visitor) { this.selector = visitor.visit(this.selector); }, eval: function (env) { return new(tree.Extend)(this.selector.eval(env), this.option, this.index); }, clone: function (env) { return new(tree.Extend)(this.selector, this.option, this.index); }, findSelfSelectors: function (selectors) { var selfElements = []; for(i = 0; i < selectors.length; i++) { selfElements = selfElements.concat(selectors[i].elements); } this.selfSelectors = [{ elements: selfElements }]; } }; })(require('../tree')); (function (tree) { // // CSS @import node // // The general strategy here is that we don't want to wait // for the parsing to be completed, before we start importing // the file. That's because in the context of a browser, // most of the time will be spent waiting for the server to respond. // // On creation, we push the import path to our import queue, though // `import,push`, we also pass it a callback, which it'll call once // the file has been fetched, and parsed. // tree.Import = function (path, features, options, index, currentFileInfo) { var that = this; this.options = options; this.index = index; this.path = path; this.features = features; this.currentFileInfo = currentFileInfo; if (this.options.less !== undefined) { this.css = !this.options.less; } else { var pathValue = this.getPath(); if (pathValue && /css([\?;].*)?$/.test(pathValue)) { this.css = true; } } }; // // The actual import node doesn't return anything, when converted to CSS. // The reason is that it's used at the evaluation stage, so that the rules // it imports can be treated like any other rules. // // In `eval`, we make sure all Import nodes get evaluated, recursively, so // we end up with a flat structure, which can easily be imported in the parent // ruleset. // tree.Import.prototype = { type: "Import", accept: function (visitor) { this.features = visitor.visit(this.features); this.path = visitor.visit(this.path); this.root = visitor.visit(this.root); }, toCSS: function (env) { var features = this.features ? ' ' + this.features.toCSS(env) : ''; if (this.css) { return "@import " + this.path.toCSS() + features + ';\n'; } else { return ""; } }, getPath: function () { if (this.path instanceof tree.Quoted) { var path = this.path.value; return (this.css !== undefined || /(\.[a-z]*$)|([\?;].*)$/.test(path)) ? path : path + '.less'; } else if (this.path instanceof tree.URL) { return this.path.value.value; } return null; }, evalForImport: function (env) { return new(tree.Import)(this.path.eval(env), this.features, this.options, this.index, this.currentFileInfo); }, evalPath: function (env) { var path = this.path.eval(env); var rootpath = this.currentFileInfo && this.currentFileInfo.rootpath; if (rootpath && !(path instanceof tree.URL)) { var pathValue = path.value; // Add the base path if the import is relative if (pathValue && env.isPathRelative(pathValue)) { path.value = rootpath + pathValue; } } return path; }, eval: function (env) { var ruleset, features = this.features && this.features.eval(env); if (this.skip) { return []; } if (this.css) { var newImport = new(tree.Import)(this.evalPath(env), features, this.options, this.index); if (!newImport.css && this.error) { throw this.error; } return newImport; } else { ruleset = new(tree.Ruleset)([], this.root.rules.slice(0)); ruleset.evalImports(env); return this.features ? new(tree.Media)(ruleset.rules, this.features.value) : ruleset.rules; } } }; })(require('../tree')); (function (tree) { tree.JavaScript = function (string, index, escaped) { this.escaped = escaped; this.expression = string; this.index = index; }; tree.JavaScript.prototype = { type: "JavaScript", eval: function (env) { var result, that = this, context = {}; var expression = this.expression.replace(/@\{([\w-]+)\}/g, function (_, name) { return tree.jsify(new(tree.Variable)('@' + name, that.index).eval(env)); }); try { expression = new(Function)('return (' + expression + ')'); } catch (e) { throw { message: "JavaScript evaluation error: `" + expression + "`" , index: this.index }; } for (var k in env.frames[0].variables()) { context[k.slice(1)] = { value: env.frames[0].variables()[k].value, toJS: function () { return this.value.eval(env).toCSS(); } }; } try { result = expression.call(context); } catch (e) { throw { message: "JavaScript evaluation error: '" + e.name + ': ' + e.message + "'" , index: this.index }; } if (typeof(result) === 'string') { return new(tree.Quoted)('"' + result + '"', result, this.escaped, this.index); } else if (Array.isArray(result)) { return new(tree.Anonymous)(result.join(', ')); } else { return new(tree.Anonymous)(result); } } }; })(require('../tree')); (function (tree) { tree.Keyword = function (value) { this.value = value }; tree.Keyword.prototype = { type: "Keyword", eval: function () { return this; }, toCSS: function () { return this.value; }, compare: function (other) { if (other instanceof tree.Keyword) { return other.value === this.value ? 0 : 1; } else { return -1; } } }; tree.True = new(tree.Keyword)('true'); tree.False = new(tree.Keyword)('false'); })(require('../tree')); (function (tree) { tree.Media = function (value, features) { var selectors = this.emptySelectors(); this.features = new(tree.Value)(features); this.ruleset = new(tree.Ruleset)(selectors, value); this.ruleset.allowImports = true; }; tree.Media.prototype = { type: "Media", accept: function (visitor) { this.features = visitor.visit(this.features); this.ruleset = visitor.visit(this.ruleset); }, toCSS: function (env) { var features = this.features.toCSS(env); return '@media ' + features + (env.compress ? '{' : ' {\n ') + this.ruleset.toCSS(env).trim().replace(/\n/g, '\n ') + (env.compress ? '}': '\n}\n'); }, eval: function (env) { if (!env.mediaBlocks) { env.mediaBlocks = []; env.mediaPath = []; } var media = new(tree.Media)([], []); if(this.debugInfo) { this.ruleset.debugInfo = this.debugInfo; media.debugInfo = this.debugInfo; } var strictMathBypass = false; if (!env.strictMath) { strictMathBypass = true; env.strictMath = true; } try { media.features = this.features.eval(env); } finally { if (strictMathBypass) { env.strictMath = false; } } env.mediaPath.push(media); env.mediaBlocks.push(media); env.frames.unshift(this.ruleset); media.ruleset = this.ruleset.eval(env); env.frames.shift(); env.mediaPath.pop(); return env.mediaPath.length === 0 ? media.evalTop(env) : media.evalNested(env) }, variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) }, find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) }, rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) }, emptySelectors: function() { var el = new(tree.Element)('', '&', 0); return [new(tree.Selector)([el])]; }, evalTop: function (env) { var result = this; // Render all dependent Media blocks. if (env.mediaBlocks.length > 1) { var selectors = this.emptySelectors(); result = new(tree.Ruleset)(selectors, env.mediaBlocks); result.multiMedia = true; } delete env.mediaBlocks; delete env.mediaPath; return result; }, evalNested: function (env) { var i, value, path = env.mediaPath.concat([this]); // Extract the media-query conditions separated with `,` (OR). for (i = 0; i < path.length; i++) { value = path[i].features instanceof tree.Value ? path[i].features.value : path[i].features; path[i] = Array.isArray(value) ? value : [value]; } // Trace all permutations to generate the resulting media-query. // // (a, b and c) with nested (d, e) -> // a and d // a and e // b and c and d // b and c and e this.features = new(tree.Value)(this.permute(path).map(function (path) { path = path.map(function (fragment) { return fragment.toCSS ? fragment : new(tree.Anonymous)(fragment); }); for(i = path.length - 1; i > 0; i--) { path.splice(i, 0, new(tree.Anonymous)("and")); } return new(tree.Expression)(path); })); // Fake a tree-node that doesn't output anything. return new(tree.Ruleset)([], []); }, permute: function (arr) { if (arr.length === 0) { return []; } else if (arr.length === 1) { return arr[0]; } else { var result = []; var rest = this.permute(arr.slice(1)); for (var i = 0; i < rest.length; i++) { for (var j = 0; j < arr[0].length; j++) { result.push([arr[0][j]].concat(rest[i])); } } return result; } }, bubbleSelectors: function (selectors) { this.ruleset = new(tree.Ruleset)(selectors.slice(0), [this.ruleset]); } }; })(require('../tree')); (function (tree) { tree.mixin = {}; tree.mixin.Call = function (elements, args, index, currentFileInfo, important) { this.selector = new(tree.Selector)(elements); this.arguments = args; this.index = index; this.currentFileInfo = currentFileInfo; this.important = important; }; tree.mixin.Call.prototype = { type: "MixinCall", accept: function (visitor) { this.selector = visitor.visit(this.selector); this.arguments = visitor.visit(this.arguments); }, eval: function (env) { var mixins, mixin, args, rules = [], match = false, i, m, f, isRecursive, isOneFound; args = this.arguments && this.arguments.map(function (a) { return { name: a.name, value: a.value.eval(env) }; }); for (i = 0; i < env.frames.length; i++) { if ((mixins = env.frames[i].find(this.selector)).length > 0) { isOneFound = true; for (m = 0; m < mixins.length; m++) { mixin = mixins[m]; isRecursive = false; for(f = 0; f < env.frames.length; f++) { if ((!(mixin instanceof tree.mixin.Definition)) && mixin === (env.frames[f].originalRuleset || env.frames[f])) { isRecursive = true; break; } } if (isRecursive) { continue; } if (mixin.matchArgs(args, env)) { if (!mixin.matchCondition || mixin.matchCondition(args, env)) { try { Array.prototype.push.apply( rules, mixin.eval(env, args, this.important).rules); } catch (e) { throw { message: e.message, index: this.index, filename: this.currentFileInfo.filename, stack: e.stack }; } } match = true; } } if (match) { return rules; } } } if (isOneFound) { throw { type: 'Runtime', message: 'No matching definition was found for `' + this.selector.toCSS().trim() + '(' + (args ? args.map(function (a) { var argValue = ""; if (a.name) { argValue += a.name + ":"; } if (a.value.toCSS) { argValue += a.value.toCSS(); } else { argValue += "???"; } return argValue; }).join(', ') : "") + ")`", index: this.index, filename: this.currentFileInfo.filename }; } else { throw { type: 'Name', message: this.selector.toCSS().trim() + " is undefined", index: this.index, filename: this.currentFileInfo.filename }; } } }; tree.mixin.Definition = function (name, params, rules, condition, variadic) { this.name = name; this.selectors = [new(tree.Selector)([new(tree.Element)(null, name)])]; this.params = params; this.condition = condition; this.variadic = variadic; this.arity = params.length; this.rules = rules; this._lookups = {}; this.required = params.reduce(function (count, p) { if (!p.name || (p.name && !p.value)) { return count + 1 } else { return count } }, 0); this.parent = tree.Ruleset.prototype; this.frames = []; }; tree.mixin.Definition.prototype = { type: "MixinDefinition", accept: function (visitor) { this.params = visitor.visit(this.params); this.rules = visitor.visit(this.rules); this.condition = visitor.visit(this.condition); }, toCSS: function () { return ""; }, variable: function (name) { return this.parent.variable.call(this, name); }, variables: function () { return this.parent.variables.call(this); }, find: function () { return this.parent.find.apply(this, arguments); }, rulesets: function () { return this.parent.rulesets.apply(this); }, evalParams: function (env, mixinEnv, args, evaldArguments) { var frame = new(tree.Ruleset)(null, []), varargs, arg, params = this.params.slice(0), i, j, val, name, isNamedFound, argIndex; mixinEnv = new tree.evalEnv(mixinEnv, [frame].concat(mixinEnv.frames)); if (args) { args = args.slice(0); for(i = 0; i < args.length; i++) { arg = args[i]; if (name = (arg && arg.name)) { isNamedFound = false; for(j = 0; j < params.length; j++) { if (!evaldArguments[j] && name === params[j].name) { evaldArguments[j] = arg.value.eval(env); frame.rules.unshift(new(tree.Rule)(name, arg.value.eval(env))); isNamedFound = true; break; } } if (isNamedFound) { args.splice(i, 1); i--; continue; } else { throw { type: 'Runtime', message: "Named argument for " + this.name + ' ' + args[i].name + ' not found' }; } } } } argIndex = 0; for (i = 0; i < params.length; i++) { if (evaldArguments[i]) continue; arg = args && args[argIndex]; if (name = params[i].name) { if (params[i].variadic && args) { varargs = []; for (j = argIndex; j < args.length; j++) { varargs.push(args[j].value.eval(env)); } frame.rules.unshift(new(tree.Rule)(name, new(tree.Expression)(varargs).eval(env))); } else { val = arg && arg.value; if (val) { val = val.eval(env); } else if (params[i].value) { val = params[i].value.eval(mixinEnv); frame.resetCache(); } else { throw { type: 'Runtime', message: "wrong number of arguments for " + this.name + ' (' + args.length + ' for ' + this.arity + ')' }; } frame.rules.unshift(new(tree.Rule)(name, val)); evaldArguments[i] = val; } } if (params[i].variadic && args) { for (j = argIndex; j < args.length; j++) { evaldArguments[j] = args[j].value.eval(env); } } argIndex++; } return frame; }, eval: function (env, args, important) { var _arguments = [], mixinFrames = this.frames.concat(env.frames), frame = this.evalParams(env, new(tree.evalEnv)(env, mixinFrames), args, _arguments), context, rules, start, ruleset; frame.rules.unshift(new(tree.Rule)('@arguments', new(tree.Expression)(_arguments).eval(env))); rules = important ? this.parent.makeImportant.apply(this).rules : this.rules.slice(0); ruleset = new(tree.Ruleset)(null, rules).eval(new(tree.evalEnv)(env, [this, frame].concat(mixinFrames))); ruleset.originalRuleset = this; return ruleset; }, matchCondition: function (args, env) { if (this.condition && !this.condition.eval( new(tree.evalEnv)(env, [this.evalParams(env, new(tree.evalEnv)(env, this.frames.concat(env.frames)), args, [])] .concat(env.frames)))) { return false; } return true; }, matchArgs: function (args, env) { var argsLength = (args && args.length) || 0, len, frame; if (! this.variadic) { if (argsLength < this.required) { return false } if (argsLength > this.params.length) { return false } if ((this.required > 0) && (argsLength > this.params.length)) { return false } } len = Math.min(argsLength, this.arity); for (var i = 0; i < len; i++) { if (!this.params[i].name && !this.params[i].variadic) { if (args[i].value.eval(env).toCSS() != this.params[i].value.eval(env).toCSS()) { return false; } } } return true; } }; })(require('../tree')); (function (tree) { tree.Negative = function (node) { this.value = node; }; tree.Negative.prototype = { type: "Negative", accept: function (visitor) { this.value = visitor.visit(this.value); }, toCSS: function (env) { return '-' + this.value.toCSS(env); }, eval: function (env) { if (env.isMathOn()) { return (new(tree.Operation)('*', [new(tree.Dimension)(-1), this.value])).eval(env); } return new(tree.Negative)(this.value.eval(env)); } }; })(require('../tree')); (function (tree) { tree.Operation = function (op, operands, isSpaced) { this.op = op.trim(); this.operands = operands; this.isSpaced = isSpaced; }; tree.Operation.prototype = { type: "Operation", accept: function (visitor) { this.operands = visitor.visit(this.operands); }, eval: function (env) { var a = this.operands[0].eval(env), b = this.operands[1].eval(env), temp; if (env.isMathOn()) { if (a instanceof tree.Dimension && b instanceof tree.Color) { if (this.op === '*' || this.op === '+') { temp = b, b = a, a = temp; } else { throw { type: "Operation", message: "Can't substract or divide a color from a number" }; } } if (!a.operate) { throw { type: "Operation", message: "Operation on an invalid type" }; } return a.operate(env, this.op, b); } else { return new(tree.Operation)(this.op, [a, b], this.isSpaced); } }, toCSS: function (env) { var separator = this.isSpaced ? " " : ""; return this.operands[0].toCSS() + separator + this.op + separator + this.operands[1].toCSS(); } }; tree.operate = function (env, op, a, b) { switch (op) { case '+': return a + b; case '-': return a - b; case '*': return a * b; case '/': return a / b; } }; })(require('../tree')); (function (tree) { tree.Paren = function (node) { this.value = node; }; tree.Paren.prototype = { type: "Paren", accept: function (visitor) { this.value = visitor.visit(this.value); }, toCSS: function (env) { return '(' + this.value.toCSS(env).trim() + ')'; }, eval: function (env) { return new(tree.Paren)(this.value.eval(env)); } }; })(require('../tree')); (function (tree) { tree.Quoted = function (str, content, escaped, index, currentFileInfo) { this.escaped = escaped; this.value = content || ''; this.quote = str.charAt(0); this.index = index; this.currentFileInfo = currentFileInfo; }; tree.Quoted.prototype = { type: "Quoted", toCSS: function () { if (this.escaped) { return this.value; } else { return this.quote + this.value + this.quote; } }, eval: function (env) { var that = this; var value = this.value.replace(/`([^`]+)`/g, function (_, exp) { return new(tree.JavaScript)(exp, that.index, true).eval(env).value; }).replace(/@\{([\w-]+)\}/g, function (_, name) { var v = new(tree.Variable)('@' + name, that.index, that.currentFileInfo).eval(env, true); return (v instanceof tree.Quoted) ? v.value : v.toCSS(); }); return new(tree.Quoted)(this.quote + value + this.quote, value, this.escaped, this.index); }, compare: function (x) { if (!x.toCSS) { return -1; } var left = this.toCSS(), right = x.toCSS(); if (left === right) { return 0; } return left < right ? -1 : 1; } }; })(require('../tree')); (function (tree) { tree.Rule = function (name, value, important, index, currentFileInfo, inline) { this.name = name; this.value = (value instanceof tree.Value) ? value : new(tree.Value)([value]); this.important = important ? ' ' + important.trim() : ''; this.index = index; this.currentFileInfo = currentFileInfo; this.inline = inline || false; if (name.charAt(0) === '@') { this.variable = true; } else { this.variable = false } }; tree.Rule.prototype = { type: "Rule", accept: function (visitor) { this.value = visitor.visit(this.value); }, toCSS: function (env) { if (this.variable) { return "" } else { try { return this.name + (env.compress ? ':' : ': ') + this.value.toCSS(env) + this.important + (this.inline ? "" : ";"); } catch(e) { e.index = this.index; e.filename = this.currentFileInfo.filename; throw e; } } }, eval: function (env) { var strictMathBypass = false; if (this.name === "font" && env.strictMath === false) { strictMathBypass = true; env.strictMath = true; } try { return new(tree.Rule)(this.name, this.value.eval(env), this.important, this.index, this.currentFileInfo, this.inline); } finally { if (strictMathBypass) { env.strictMath = false; } } }, makeImportant: function () { return new(tree.Rule)(this.name, this.value, "!important", this.index, this.currentFileInfo, this.inline); } }; })(require('../tree')); (function (tree) { tree.Ruleset = function (selectors, rules, strictImports) { this.selectors = selectors; this.rules = rules; this._lookups = {}; this.strictImports = strictImports; }; tree.Ruleset.prototype = { type: "Ruleset", accept: function (visitor) { this.selectors = visitor.visit(this.selectors); this.rules = visitor.visit(this.rules); }, eval: function (env) { var selectors = this.selectors && this.selectors.map(function (s) { return s.eval(env) }); var ruleset = new(tree.Ruleset)(selectors, this.rules.slice(0), this.strictImports); var rules; ruleset.originalRuleset = this; ruleset.root = this.root; ruleset.firstRoot = this.firstRoot; ruleset.allowImports = this.allowImports; if(this.debugInfo) { ruleset.debugInfo = this.debugInfo; } // push the current ruleset to the frames stack env.frames.unshift(ruleset); // currrent selectors if (!env.selectors) { env.selectors = []; } env.selectors.unshift(this.selectors); // Evaluate imports if (ruleset.root || ruleset.allowImports || !ruleset.strictImports) { ruleset.evalImports(env); } // Store the frames around mixin definitions, // so they can be evaluated like closures when the time comes. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Definition) { ruleset.rules[i].frames = env.frames.slice(0); } } var mediaBlockCount = (env.mediaBlocks && env.mediaBlocks.length) || 0; // Evaluate mixin calls. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Call) { rules = ruleset.rules[i].eval(env).filter(function(r) { if ((r instanceof tree.Rule) && r.variable) { // do not pollute the scope if the variable is // already there. consider returning false here // but we need a way to "return" variable from mixins return !(ruleset.variable(r.name)); } return true; }); ruleset.rules.splice.apply(ruleset.rules, [i, 1].concat(rules)); i += rules.length-1; ruleset.resetCache(); } } // Evaluate everything else for (var i = 0, rule; i < ruleset.rules.length; i++) { rule = ruleset.rules[i]; if (! (rule instanceof tree.mixin.Definition)) { ruleset.rules[i] = rule.eval ? rule.eval(env) : rule; } } // Pop the stack env.frames.shift(); env.selectors.shift(); if (env.mediaBlocks) { for(var i = mediaBlockCount; i < env.mediaBlocks.length; i++) { env.mediaBlocks[i].bubbleSelectors(selectors); } } return ruleset; }, evalImports: function(env) { var i, rules; for (i = 0; i < this.rules.length; i++) { if (this.rules[i] instanceof tree.Import) { rules = this.rules[i].eval(env); if (typeof rules.length === "number") { this.rules.splice.apply(this.rules, [i, 1].concat(rules)); i+= rules.length-1; } else { this.rules.splice(i, 1, rules); } this.resetCache(); } } }, makeImportant: function() { return new tree.Ruleset(this.selectors, this.rules.map(function (r) { if (r.makeImportant) { return r.makeImportant(); } else { return r; } }), this.strictImports); }, matchArgs: function (args) { return !args || args.length === 0; }, resetCache: function () { this._rulesets = null; this._variables = null; this._lookups = {}; }, variables: function () { if (this._variables) { return this._variables } else { return this._variables = this.rules.reduce(function (hash, r) { if (r instanceof tree.Rule && r.variable === true) { hash[r.name] = r; } return hash; }, {}); } }, variable: function (name) { return this.variables()[name]; }, rulesets: function () { return this.rules.filter(function (r) { return (r instanceof tree.Ruleset) || (r instanceof tree.mixin.Definition); }); }, find: function (selector, self) { self = self || this; var rules = [], rule, match, key = selector.toCSS(); if (key in this._lookups) { return this._lookups[key] } this.rulesets().forEach(function (rule) { if (rule !== self) { for (var j = 0; j < rule.selectors.length; j++) { if (match = selector.match(rule.selectors[j])) { if (selector.elements.length > rule.selectors[j].elements.length) { Array.prototype.push.apply(rules, rule.find( new(tree.Selector)(selector.elements.slice(1)), self)); } else { rules.push(rule); } break; } } } }); return this._lookups[key] = rules; }, // // Entry point for code generation // // `context` holds an array of arrays. // toCSS: function (env) { var css = [], // The CSS output rules = [], // node.Rule instances _rules = [], // rulesets = [], // node.Ruleset instances selector, // The fully rendered selector debugInfo, // Line number debugging rule; // Compile rules and rulesets for (var i = 0; i < this.rules.length; i++) { rule = this.rules[i]; if (rule.rules || (rule instanceof tree.Media)) { rulesets.push(rule.toCSS(env)); } else if (rule instanceof tree.Directive) { var cssValue = rule.toCSS(env); // Output only the first @charset definition as such - convert the others // to comments in case debug is enabled if (rule.name === "@charset") { // Only output the debug info together with subsequent @charset definitions // a comment (or @media statement) before the actual @charset directive would // be considered illegal css as it has to be on the first line if (env.charset) { if (rule.debugInfo) { rulesets.push(tree.debugInfo(env, rule)); rulesets.push(new tree.Comment("/* "+cssValue.replace(/\n/g, "")+" */\n").toCSS(env)); } continue; } env.charset = true; } rulesets.push(cssValue); } else if (rule instanceof tree.Comment) { if (!rule.silent) { if (this.root) { rulesets.push(rule.toCSS(env)); } else { rules.push(rule.toCSS(env)); } } } else { if (rule.toCSS && !rule.variable) { if (this.firstRoot && rule instanceof tree.Rule) { throw { message: "properties must be inside selector blocks, they cannot be in the root.", index: rule.index, filename: rule.currentFileInfo ? rule.currentFileInfo.filename : null}; } rules.push(rule.toCSS(env)); } else if (rule.value && !rule.variable) { rules.push(rule.value.toString()); } } } // Remove last semicolon if (env.compress && rules.length) { rule = rules[rules.length - 1]; if (rule.charAt(rule.length - 1) === ';') { rules[rules.length - 1] = rule.substring(0, rule.length - 1); } } rulesets = rulesets.join(''); // If this is the root node, we don't render // a selector, or {}. // Otherwise, only output if this ruleset has rules. if (this.root) { css.push(rules.join(env.compress ? '' : '\n')); } else { if (rules.length > 0) { debugInfo = tree.debugInfo(env, this); selector = this.paths.map(function (p) { return p.map(function (s) { return s.toCSS(env); }).join('').trim(); }).join(env.compress ? ',' : ',\n'); // Remove duplicates for (var i = rules.length - 1; i >= 0; i--) { if (rules[i].slice(0, 2) === "/*" || _rules.indexOf(rules[i]) === -1) { _rules.unshift(rules[i]); } } rules = _rules; css.push(debugInfo + selector + (env.compress ? '{' : ' {\n ') + rules.join(env.compress ? '' : '\n ') + (env.compress ? '}' : '\n}\n')); } } css.push(rulesets); return css.join('') + (env.compress ? '\n' : ''); }, joinSelectors: function (paths, context, selectors) { for (var s = 0; s < selectors.length; s++) { this.joinSelector(paths, context, selectors[s]); } }, joinSelector: function (paths, context, selector) { var i, j, k, hasParentSelector, newSelectors, el, sel, parentSel, newSelectorPath, afterParentJoin, newJoinedSelector, newJoinedSelectorEmpty, lastSelector, currentElements, selectorsMultiplied; for (i = 0; i < selector.elements.length; i++) { el = selector.elements[i]; if (el.value === '&') { hasParentSelector = true; } } if (!hasParentSelector) { if (context.length > 0) { for(i = 0; i < context.length; i++) { paths.push(context[i].concat(selector)); } } else { paths.push([selector]); } return; } // The paths are [[Selector]] // The first list is a list of comma seperated selectors // The inner list is a list of inheritance seperated selectors // e.g. // .a, .b { // .c { // } // } // == [[.a] [.c]] [[.b] [.c]] // // the elements from the current selector so far currentElements = []; // the current list of new selectors to add to the path. // We will build it up. We initiate it with one empty selector as we "multiply" the new selectors // by the parents newSelectors = [[]]; for (i = 0; i < selector.elements.length; i++) { el = selector.elements[i]; // non parent reference elements just get added if (el.value !== "&") { currentElements.push(el); } else { // the new list of selectors to add selectorsMultiplied = []; // merge the current list of non parent selector elements // on to the current list of selectors to add if (currentElements.length > 0) { this.mergeElementsOnToSelectors(currentElements, newSelectors); } // loop through our current selectors for(j = 0; j < newSelectors.length; j++) { sel = newSelectors[j]; // if we don't have any parent paths, the & might be in a mixin so that it can be used // whether there are parents or not if (context.length == 0) { // the combinator used on el should now be applied to the next element instead so that // it is not lost if (sel.length > 0) { sel[0].elements = sel[0].elements.slice(0); sel[0].elements.push(new(tree.Element)(el.combinator, '', 0)); //new Element(el.Combinator, "")); } selectorsMultiplied.push(sel); } else { // and the parent selectors for(k = 0; k < context.length; k++) { parentSel = context[k]; // We need to put the current selectors // then join the last selector's elements on to the parents selectors // our new selector path newSelectorPath = []; // selectors from the parent after the join afterParentJoin = []; newJoinedSelectorEmpty = true; //construct the joined selector - if & is the first thing this will be empty, // if not newJoinedSelector will be the last set of elements in the selector if (sel.length > 0) { newSelectorPath = sel.slice(0); lastSelector = newSelectorPath.pop(); newJoinedSelector = new(tree.Selector)(lastSelector.elements.slice(0), selector.extendList); newJoinedSelectorEmpty = false; } else { newJoinedSelector = new(tree.Selector)([], selector.extendList); } //put together the parent selectors after the join if (parentSel.length > 1) { afterParentJoin = afterParentJoin.concat(parentSel.slice(1)); } if (parentSel.length > 0) { newJoinedSelectorEmpty = false; // join the elements so far with the first part of the parent newJoinedSelector.elements.push(new(tree.Element)(el.combinator, parentSel[0].elements[0].value, 0)); newJoinedSelector.elements = newJoinedSelector.elements.concat(parentSel[0].elements.slice(1)); } if (!newJoinedSelectorEmpty) { // now add the joined selector newSelectorPath.push(newJoinedSelector); } // and the rest of the parent newSelectorPath = newSelectorPath.concat(afterParentJoin); // add that to our new set of selectors selectorsMultiplied.push(newSelectorPath); } } } // our new selectors has been multiplied, so reset the state newSelectors = selectorsMultiplied; currentElements = []; } } // if we have any elements left over (e.g. .a& .b == .b) // add them on to all the current selectors if (currentElements.length > 0) { this.mergeElementsOnToSelectors(currentElements, newSelectors); } for(i = 0; i < newSelectors.length; i++) { if (newSelectors[i].length > 0) { paths.push(newSelectors[i]); } } }, mergeElementsOnToSelectors: function(elements, selectors) { var i, sel, extendList; if (selectors.length == 0) { selectors.push([ new(tree.Selector)(elements) ]); return; } for(i = 0; i < selectors.length; i++) { sel = selectors[i]; // if the previous thing in sel is a parent this needs to join on to it if (sel.length > 0) { sel[sel.length - 1] = new(tree.Selector)(sel[sel.length - 1].elements.concat(elements), sel[sel.length - 1].extendList); } else { sel.push(new(tree.Selector)(elements)); } } } }; })(require('../tree')); (function (tree) { tree.Selector = function (elements, extendList) { this.elements = elements; this.extendList = extendList || []; }; tree.Selector.prototype = { type: "Selector", accept: function (visitor) { this.elements = visitor.visit(this.elements); this.extendList = visitor.visit(this.extendList) }, match: function (other) { var elements = this.elements, len = elements.length, oelements, olen, max, i; oelements = other.elements.slice( (other.elements.length && other.elements[0].value === "&") ? 1 : 0); olen = oelements.length; max = Math.min(len, olen); if (olen === 0 || len < olen) { return false; } else { for (i = 0; i < max; i++) { if (elements[i].value !== oelements[i].value) { return false; } } } return true; }, eval: function (env) { return new(tree.Selector)(this.elements.map(function (e) { return e.eval(env); }), this.extendList.map(function(extend) { return extend.eval(env); })); }, toCSS: function (env) { if (this._css) { return this._css } if (this.elements[0].combinator.value === "") { this._css = ' '; } else { this._css = ''; } this._css += this.elements.map(function (e) { if (typeof(e) === 'string') { return ' ' + e.trim(); } else { return e.toCSS(env); } }).join(''); return this._css; } }; })(require('../tree')); (function (tree) { tree.UnicodeDescriptor = function (value) { this.value = value; }; tree.UnicodeDescriptor.prototype = { type: "UnicodeDescriptor", toCSS: function (env) { return this.value; }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.URL = function (val, currentFileInfo) { this.value = val; this.currentFileInfo = currentFileInfo; }; tree.URL.prototype = { type: "Url", accept: function (visitor) { this.value = visitor.visit(this.value); }, toCSS: function () { return "url(" + this.value.toCSS() + ")"; }, eval: function (ctx) { var val = this.value.eval(ctx), rootpath; // Add the base path if the URL is relative rootpath = this.currentFileInfo && this.currentFileInfo.rootpath; if (rootpath && typeof val.value === "string" && ctx.isPathRelative(val.value)) { if (!val.quote) { rootpath = rootpath.replace(/[\(\)'"\s]/g, function(match) { return "\\"+match; }); } val.value = rootpath + val.value; } return new(tree.URL)(val, null); } }; })(require('../tree')); (function (tree) { tree.Value = function (value) { this.value = value; }; tree.Value.prototype = { type: "Value", accept: function (visitor) { this.value = visitor.visit(this.value); }, eval: function (env) { if (this.value.length === 1) { return this.value[0].eval(env); } else { return new(tree.Value)(this.value.map(function (v) { return v.eval(env); })); } }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS(env); }).join(env.compress ? ',' : ', '); } }; })(require('../tree')); (function (tree) { tree.Variable = function (name, index, currentFileInfo) { this.name = name, this.index = index, this.currentFileInfo = currentFileInfo }; tree.Variable.prototype = { type: "Variable", eval: function (env) { var variable, v, name = this.name; if (name.indexOf('@@') == 0) { name = '@' + new(tree.Variable)(name.slice(1)).eval(env).value; } if (this.evaluating) { throw { type: 'Name', message: "Recursive variable definition for " + name, filename: this.currentFileInfo.file, index: this.index }; } this.evaluating = true; if (variable = tree.find(env.frames, function (frame) { if (v = frame.variable(name)) { return v.value.eval(env); } })) { this.evaluating = false; return variable; } else { throw { type: 'Name', message: "variable " + name + " is undefined", filename: this.currentFileInfo.filename, index: this.index }; } } }; })(require('../tree')); (function (tree) { tree.debugInfo = function(env, ctx) { var result=""; if (env.dumpLineNumbers && !env.compress) { switch(env.dumpLineNumbers) { case 'comments': result = tree.debugInfo.asComment(ctx); break; case 'mediaquery': result = tree.debugInfo.asMediaQuery(ctx); break; case 'all': result = tree.debugInfo.asComment(ctx)+tree.debugInfo.asMediaQuery(ctx); break; } } return result; }; tree.debugInfo.asComment = function(ctx) { return '/* line ' + ctx.debugInfo.lineNumber + ', ' + ctx.debugInfo.fileName + ' */\n'; }; tree.debugInfo.asMediaQuery = function(ctx) { return '@media -sass-debug-info{filename{font-family:' + ('file://' + ctx.debugInfo.fileName).replace(/([.:/\\])/g, function(a){if(a=='\\') a = '\/'; return '\\' + a}) + '}line{font-family:\\00003' + ctx.debugInfo.lineNumber + '}}\n'; }; tree.find = function (obj, fun) { for (var i = 0, r; i < obj.length; i++) { if (r = fun.call(obj, obj[i])) { return r } } return null; }; tree.jsify = function (obj) { if (Array.isArray(obj.value) && (obj.value.length > 1)) { return '[' + obj.value.map(function (v) { return v.toCSS(false) }).join(', ') + ']'; } else { return obj.toCSS(false); } }; })(require('./tree')); (function (tree) { var parseCopyProperties = [ 'paths', // option - unmodified - paths to search for imports on 'optimization', // option - optimization level (for the chunker) 'files', // list of files that have been imported, used for import-once 'contents', // browser-only, contents of all the files 'relativeUrls', // option - whether to adjust URL's to be relative 'strictImports', // option - 'dumpLineNumbers', // option - whether to dump line numbers 'compress', // option - whether to compress 'processImports', // option - whether to process imports. if false then imports will not be imported 'mime', // browser only - mime type for sheet import 'currentFileInfo' // information about the current file - for error reporting and importing and making urls relative etc. ]; //currentFileInfo = { // 'relativeUrls' - option - whether to adjust URL's to be relative // 'filename' - full resolved filename of current file // 'rootpath' - path to append to normal URLs for this node // 'currentDirectory' - path to the current file, absolute // 'rootFilename' - filename of the base file // 'entryPath' = absolute path to the entry file tree.parseEnv = function(options) { copyFromOriginal(options, this, parseCopyProperties); if (!this.contents) { this.contents = {}; } if (!this.files) { this.files = {}; } if (!this.currentFileInfo) { var filename = options.filename || "input"; options.filename = null; var entryPath = filename.replace(/[^\/\\]*$/, ""); this.currentFileInfo = { filename: filename, relativeUrls: this.relativeUrls, rootpath: options.rootpath || "", currentDirectory: entryPath, entryPath: entryPath, rootFilename: filename }; } }; tree.parseEnv.prototype.toSheet = function (path) { var env = new tree.parseEnv(this); env.href = path; //env.title = path; env.type = this.mime; return env; }; var evalCopyProperties = [ 'silent', // whether to swallow errors and warnings 'verbose', // whether to log more activity 'compress', // whether to compress 'ieCompat', // whether to enforce IE compatibility (IE8 data-uri) 'strictMath', // whether math has to be within parenthesis 'strictUnits' // whether units need to evaluate correctly ]; tree.evalEnv = function(options, frames) { copyFromOriginal(options, this, evalCopyProperties); this.frames = frames || []; }; tree.evalEnv.prototype.inParenthesis = function () { if (!this.parensStack) { this.parensStack = []; } this.parensStack.push(true); }; tree.evalEnv.prototype.outOfParenthesis = function () { this.parensStack.pop(); }; tree.evalEnv.prototype.isMathOn = function () { return this.strictMath ? (this.parensStack && this.parensStack.length) : true; }; tree.evalEnv.prototype.isPathRelative = function (path) { return !/^(?:[a-z-]+:|\/)/.test(path); }; //todo - do the same for the toCSS env //tree.toCSSEnv = function (options) { //}; var copyFromOriginal = function(original, destination, propertiesToCopy) { if (!original) { return; } for(var i = 0; i < propertiesToCopy.length; i++) { if (original.hasOwnProperty(propertiesToCopy[i])) { destination[propertiesToCopy[i]] = original[propertiesToCopy[i]]; } } } })(require('./tree'));(function (tree) { tree.visitor = function(implementation) { this._implementation = implementation; }; tree.visitor.prototype = { visit: function(node) { if (node instanceof Array) { return this.visitArray(node); } if (!node || !node.type) { return node; } var funcName = "visit" + node.type, func = this._implementation[funcName], visitArgs, newNode; if (func) { visitArgs = {visitDeeper: true}; newNode = func.call(this._implementation, node, visitArgs); if (this._implementation.isReplacing) { node = newNode; } } if ((!visitArgs || visitArgs.visitDeeper) && node && node.accept) { node.accept(this); } funcName = funcName + "Out"; if (this._implementation[funcName]) { this._implementation[funcName](node); } return node; }, visitArray: function(nodes) { var i, newNodes = []; for(i = 0; i < nodes.length; i++) { var evald = this.visit(nodes[i]); if (evald instanceof Array) { newNodes = newNodes.concat(evald); } else { newNodes.push(evald); } } if (this._implementation.isReplacing) { return newNodes; } return nodes; } }; })(require('./tree'));(function (tree) { tree.importVisitor = function(importer, finish, evalEnv) { this._visitor = new tree.visitor(this); this._importer = importer; this._finish = finish; this.env = evalEnv || new tree.evalEnv(); this.importCount = 0; }; tree.importVisitor.prototype = { isReplacing: true, run: function (root) { var error; try { // process the contents this._visitor.visit(root); } catch(e) { error = e; } this.isFinished = true; if (this.importCount === 0) { this._finish(error); } }, visitImport: function (importNode, visitArgs) { var importVisitor = this, evaldImportNode; if (!importNode.css) { try { evaldImportNode = importNode.evalForImport(this.env); } catch(e){ if (!e.filename) { e.index = importNode.index; e.filename = importNode.currentFileInfo.filename; } // attempt to eval properly and treat as css importNode.css = true; // if that fails, this error will be thrown importNode.error = e; } if (evaldImportNode && !evaldImportNode.css) { importNode = evaldImportNode; this.importCount++; var env = new tree.evalEnv(this.env, this.env.frames.slice(0)); this._importer.push(importNode.getPath(), importNode.currentFileInfo, function (e, root, imported) { if (e && !e.filename) { e.index = importNode.index; e.filename = importNode.currentFileInfo.filename; } if (imported && !importNode.options.multiple) { importNode.skip = imported; } var subFinish = function(e) { importVisitor.importCount--; if (importVisitor.importCount === 0 && importVisitor.isFinished) { importVisitor._finish(e); } }; if (root) { importNode.root = root; new(tree.importVisitor)(importVisitor._importer, subFinish, env) .run(root); } else { subFinish(); } }); } } visitArgs.visitDeeper = false; return importNode; }, visitRule: function (ruleNode, visitArgs) { visitArgs.visitDeeper = false; return ruleNode; }, visitDirective: function (directiveNode, visitArgs) { this.env.frames.unshift(directiveNode); return directiveNode; }, visitDirectiveOut: function (directiveNode) { this.env.frames.shift(); }, visitMixinDefinition: function (mixinDefinitionNode, visitArgs) { this.env.frames.unshift(mixinDefinitionNode); return mixinDefinitionNode; }, visitMixinDefinitionOut: function (mixinDefinitionNode) { this.env.frames.shift(); }, visitRuleset: function (rulesetNode, visitArgs) { this.env.frames.unshift(rulesetNode); return rulesetNode; }, visitRulesetOut: function (rulesetNode) { this.env.frames.shift(); }, visitMedia: function (mediaNode, visitArgs) { this.env.frames.unshift(mediaNode.ruleset); return mediaNode; }, visitMediaOut: function (mediaNode) { this.env.frames.shift(); } }; })(require('./tree'));(function (tree) { tree.joinSelectorVisitor = function() { this.contexts = [[]]; this._visitor = new tree.visitor(this); }; tree.joinSelectorVisitor.prototype = { run: function (root) { return this._visitor.visit(root); }, visitRule: function (ruleNode, visitArgs) { visitArgs.visitDeeper = false; }, visitMixinDefinition: function (mixinDefinitionNode, visitArgs) { visitArgs.visitDeeper = false; }, visitRuleset: function (rulesetNode, visitArgs) { var context = this.contexts[this.contexts.length - 1]; var paths = []; this.contexts.push(paths); if (! rulesetNode.root) { rulesetNode.joinSelectors(paths, context, rulesetNode.selectors); rulesetNode.paths = paths; } }, visitRulesetOut: function (rulesetNode) { this.contexts.length = this.contexts.length - 1; }, visitMedia: function (mediaNode, visitArgs) { var context = this.contexts[this.contexts.length - 1]; mediaNode.ruleset.root = (context.length === 0 || context[0].multiMedia); } }; })(require('./tree'));(function (tree) { tree.extendFinderVisitor = function() { this._visitor = new tree.visitor(this); this.contexts = []; this.allExtendsStack = [[]]; }; tree.extendFinderVisitor.prototype = { run: function (root) { root = this._visitor.visit(root); root.allExtends = this.allExtendsStack[0]; return root; }, visitRule: function (ruleNode, visitArgs) { visitArgs.visitDeeper = false; }, visitMixinDefinition: function (mixinDefinitionNode, visitArgs) { visitArgs.visitDeeper = false; }, visitRuleset: function (rulesetNode, visitArgs) { if (rulesetNode.root) { return; } var i, j, extend, allSelectorsExtendList = [], extendList; // get &:extend(.a); rules which apply to all selectors in this ruleset for(i = 0; i < rulesetNode.rules.length; i++) { if (rulesetNode.rules[i] instanceof tree.Extend) { allSelectorsExtendList.push(rulesetNode.rules[i]); } } // now find every selector and apply the extends that apply to all extends // and the ones which apply to an individual extend for(i = 0; i < rulesetNode.paths.length; i++) { var selectorPath = rulesetNode.paths[i], selector = selectorPath[selectorPath.length-1]; extendList = selector.extendList.slice(0).concat(allSelectorsExtendList).map(function(allSelectorsExtend) { return allSelectorsExtend.clone(); }); for(j = 0; j < extendList.length; j++) { this.foundExtends = true; extend = extendList[j]; extend.findSelfSelectors(selectorPath); extend.ruleset = rulesetNode; if (j === 0) { extend.firstExtendOnThisSelectorPath = true; } this.allExtendsStack[this.allExtendsStack.length-1].push(extend); } } this.contexts.push(rulesetNode.selectors); }, visitRulesetOut: function (rulesetNode) { if (!rulesetNode.root) { this.contexts.length = this.contexts.length - 1; } }, visitMedia: function (mediaNode, visitArgs) { mediaNode.allExtends = []; this.allExtendsStack.push(mediaNode.allExtends); }, visitMediaOut: function (mediaNode) { this.allExtendsStack.length = this.allExtendsStack.length - 1; }, visitDirective: function (directiveNode, visitArgs) { directiveNode.allExtends = []; this.allExtendsStack.push(directiveNode.allExtends); }, visitDirectiveOut: function (directiveNode) { this.allExtendsStack.length = this.allExtendsStack.length - 1; } }; tree.processExtendsVisitor = function() { this._visitor = new tree.visitor(this); }; tree.processExtendsVisitor.prototype = { run: function(root) { var extendFinder = new tree.extendFinderVisitor(); extendFinder.run(root); if (!extendFinder.foundExtends) { return root; } root.allExtends = root.allExtends.concat(this.doExtendChaining(root.allExtends, root.allExtends)); this.allExtendsStack = [root.allExtends]; return this._visitor.visit(root); }, doExtendChaining: function (extendsList, extendsListTarget, iterationCount) { // // chaining is different from normal extension.. if we extend an extend then we are not just copying, altering and pasting // the selector we would do normally, but we are also adding an extend with the same target selector // this means this new extend can then go and alter other extends // // this method deals with all the chaining work - without it, extend is flat and doesn't work on other extend selectors // this is also the most expensive.. and a match on one selector can cause an extension of a selector we had already processed if // we look at each selector at a time, as is done in visitRuleset var extendIndex, targetExtendIndex, matches, extendsToAdd = [], newSelector, extendVisitor = this, selectorPath, extend, targetExtend; iterationCount = iterationCount || 0; //loop through comparing every extend with every target extend. // a target extend is the one on the ruleset we are looking at copy/edit/pasting in place // e.g. .a:extend(.b) {} and .b:extend(.c) {} then the first extend extends the second one // and the second is the target. // the seperation into two lists allows us to process a subset of chains with a bigger set, as is the // case when processing media queries for(extendIndex = 0; extendIndex < extendsList.length; extendIndex++){ for(targetExtendIndex = 0; targetExtendIndex < extendsListTarget.length; targetExtendIndex++){ extend = extendsList[extendIndex]; targetExtend = extendsListTarget[targetExtendIndex]; // look for circular references if (this.inInheritanceChain(targetExtend, extend)) { continue; } // find a match in the target extends self selector (the bit before :extend) selectorPath = [targetExtend.selfSelectors[0]]; matches = extendVisitor.findMatch(extend, selectorPath); if (matches.length) { // we found a match, so for each self selector.. extend.selfSelectors.forEach(function(selfSelector) { // process the extend as usual newSelector = extendVisitor.extendSelector(matches, selectorPath, selfSelector); // but now we create a new extend from it newExtend = new(tree.Extend)(targetExtend.selector, targetExtend.option, 0); newExtend.selfSelectors = newSelector; // add the extend onto the list of extends for that selector newSelector[newSelector.length-1].extendList = [newExtend]; // record that we need to add it. extendsToAdd.push(newExtend); newExtend.ruleset = targetExtend.ruleset; //remember its parents for circular references newExtend.parents = [targetExtend, extend]; // only process the selector once.. if we have :extend(.a,.b) then multiple // extends will look at the same selector path, so when extending // we know that any others will be duplicates in terms of what is added to the css if (targetExtend.firstExtendOnThisSelectorPath) { newExtend.firstExtendOnThisSelectorPath = true; targetExtend.ruleset.paths.push(newSelector); } }); } } } if (extendsToAdd.length) { // try to detect circular references to stop a stack overflow. // may no longer be needed. this.extendChainCount++; if (iterationCount > 100) { var selectorOne = "{unable to calculate}"; var selectorTwo = "{unable to calculate}"; try { selectorOne = extendsToAdd[0].selfSelectors[0].toCSS(); selectorTwo = extendsToAdd[0].selector.toCSS(); } catch(e) {} throw {message: "extend circular reference detected. One of the circular extends is currently:"+selectorOne+":extend(" + selectorTwo+")"}; } // now process the new extends on the existing rules so that we can handle a extending b extending c ectending d extending e... return extendsToAdd.concat(extendVisitor.doExtendChaining(extendsToAdd, extendsListTarget, iterationCount+1)); } else { return extendsToAdd; } }, inInheritanceChain: function (possibleParent, possibleChild) { if (possibleParent === possibleChild) { return true; } if (possibleChild.parents) { if (this.inInheritanceChain(possibleParent, possibleChild.parents[0])) { return true; } if (this.inInheritanceChain(possibleParent, possibleChild.parents[1])) { return true; } } return false; }, visitRule: function (ruleNode, visitArgs) { visitArgs.visitDeeper = false; }, visitMixinDefinition: function (mixinDefinitionNode, visitArgs) { visitArgs.visitDeeper = false; }, visitSelector: function (selectorNode, visitArgs) { visitArgs.visitDeeper = false; }, visitRuleset: function (rulesetNode, visitArgs) { if (rulesetNode.root) { return; } var matches, pathIndex, extendIndex, allExtends = this.allExtendsStack[this.allExtendsStack.length-1], selectorsToAdd = [], extendVisitor = this; // look at each selector path in the ruleset, find any extend matches and then copy, find and replace for(extendIndex = 0; extendIndex < allExtends.length; extendIndex++) { for(pathIndex = 0; pathIndex < rulesetNode.paths.length; pathIndex++) { selectorPath = rulesetNode.paths[pathIndex]; // extending extends happens initially, before the main pass if (selectorPath[selectorPath.length-1].extendList.length) { continue; } matches = this.findMatch(allExtends[extendIndex], selectorPath); if (matches.length) { allExtends[extendIndex].selfSelectors.forEach(function(selfSelector) { selectorsToAdd.push(extendVisitor.extendSelector(matches, selectorPath, selfSelector)); }); } } } rulesetNode.paths = rulesetNode.paths.concat(selectorsToAdd); }, findMatch: function (extend, haystackSelectorPath) { // // look through the haystack selector path to try and find the needle - extend.selector // returns an array of selector matches that can then be replaced // var haystackSelectorIndex, hackstackSelector, hackstackElementIndex, haystackElement, targetCombinator, i, extendVisitor = this, needleElements = extend.selector.elements, potentialMatches = [], potentialMatch, matches = []; // loop through the haystack elements for(haystackSelectorIndex = 0; haystackSelectorIndex < haystackSelectorPath.length; haystackSelectorIndex++) { hackstackSelector = haystackSelectorPath[haystackSelectorIndex]; for(hackstackElementIndex = 0; hackstackElementIndex < hackstackSelector.elements.length; hackstackElementIndex++) { haystackElement = hackstackSelector.elements[hackstackElementIndex]; // if we allow elements before our match we can add a potential match every time. otherwise only at the first element. if (extend.allowBefore || (haystackSelectorIndex == 0 && hackstackElementIndex == 0)) { potentialMatches.push({pathIndex: haystackSelectorIndex, index: hackstackElementIndex, matched: 0, initialCombinator: haystackElement.combinator}); } for(i = 0; i < potentialMatches.length; i++) { potentialMatch = potentialMatches[i]; // selectors add " " onto the first element. When we use & it joins the selectors together, but if we don't // then each selector in haystackSelectorPath has a space before it added in the toCSS phase. so we need to work out // what the resulting combinator will be targetCombinator = haystackElement.combinator.value; if (targetCombinator == '' && hackstackElementIndex === 0) { targetCombinator = ' '; } // if we don't match, null our match to indicate failure if (!extendVisitor.isElementValuesEqual(needleElements[potentialMatch.matched].value, haystackElement.value) || (potentialMatch.matched > 0 && needleElements[potentialMatch.matched].combinator.value !== targetCombinator)) { potentialMatch = null; } else { potentialMatch.matched++; } // if we are still valid and have finished, test whether we have elements after and whether these are allowed if (potentialMatch) { potentialMatch.finished = potentialMatch.matched === needleElements.length; if (potentialMatch.finished && (!extend.allowAfter && (hackstackElementIndex+1 < hackstackSelector.elements.length || haystackSelectorIndex+1 < haystackSelectorPath.length))) { potentialMatch = null; } } // if null we remove, if not, we are still valid, so either push as a valid match or continue if (potentialMatch) { if (potentialMatch.finished) { potentialMatch.length = needleElements.length; potentialMatch.endPathIndex = haystackSelectorIndex; potentialMatch.endPathElementIndex = hackstackElementIndex + 1; // index after end of match potentialMatches.length = 0; // we don't allow matches to overlap, so start matching again matches.push(potentialMatch); } } else { potentialMatches.splice(i, 1); i--; } } } } return matches; }, isElementValuesEqual: function(elementValue1, elementValue2) { if (typeof elementValue1 === "string" || typeof elementValue2 === "string") { return elementValue1 === elementValue2; } if (elementValue1 instanceof tree.Attribute) { if (elementValue1.op !== elementValue2.op || elementValue1.key !== elementValue2.key) { return false; } if (!elementValue1.value || !elementValue2.value) { if (elementValue1.value || elementValue2.value) { return false; } return true; } elementValue1 = elementValue1.value.value || elementValue1.value; elementValue2 = elementValue2.value.value || elementValue2.value; return elementValue1 === elementValue2; } return false; }, extendSelector:function (matches, selectorPath, replacementSelector) { //for a set of matches, replace each match with the replacement selector var currentSelectorPathIndex = 0, currentSelectorPathElementIndex = 0, path = [], matchIndex, selector, firstElement; for (matchIndex = 0; matchIndex < matches.length; matchIndex++) { match = matches[matchIndex]; selector = selectorPath[match.pathIndex]; firstElement = new tree.Element( match.initialCombinator, replacementSelector.elements[0].value, replacementSelector.elements[0].index ); if (match.pathIndex > currentSelectorPathIndex && currentSelectorPathElementIndex > 0) { path[path.length - 1].elements = path[path.length - 1].elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex)); currentSelectorPathElementIndex = 0; currentSelectorPathIndex++; } path = path.concat(selectorPath.slice(currentSelectorPathIndex, match.pathIndex)); path.push(new tree.Selector( selector.elements .slice(currentSelectorPathElementIndex, match.index) .concat([firstElement]) .concat(replacementSelector.elements.slice(1)) )); currentSelectorPathIndex = match.endPathIndex; currentSelectorPathElementIndex = match.endPathElementIndex; if (currentSelectorPathElementIndex >= selector.elements.length) { currentSelectorPathElementIndex = 0; currentSelectorPathIndex++; } } if (currentSelectorPathIndex < selectorPath.length && currentSelectorPathElementIndex > 0) { path[path.length - 1].elements = path[path.length - 1].elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex)); currentSelectorPathElementIndex = 0; currentSelectorPathIndex++; } path = path.concat(selectorPath.slice(currentSelectorPathIndex, selectorPath.length)); return path; }, visitRulesetOut: function (rulesetNode) { }, visitMedia: function (mediaNode, visitArgs) { var newAllExtends = mediaNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length-1]); newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, mediaNode.allExtends)); this.allExtendsStack.push(newAllExtends); }, visitMediaOut: function (mediaNode) { this.allExtendsStack.length = this.allExtendsStack.length - 1; }, visitDirective: function (directiveNode, visitArgs) { var newAllExtends = directiveNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length-1]); newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, directiveNode.allExtends)); this.allExtendsStack.push(newAllExtends); }, visitDirectiveOut: function (directiveNode) { this.allExtendsStack.length = this.allExtendsStack.length - 1; } }; })(require('./tree'));// // browser.js - client-side engine // var isFileProtocol = /^(file|chrome(-extension)?|resource|qrc|app):/.test(location.protocol); less.env = less.env || (location.hostname == '127.0.0.1' || location.hostname == '0.0.0.0' || location.hostname == 'localhost' || location.port.length > 0 || isFileProtocol ? 'development' : 'production'); // Load styles asynchronously (default: false) // // This is set to `false` by default, so that the body // doesn't start loading before the stylesheets are parsed. // Setting this to `true` can result in flickering. // less.async = less.async || false; less.fileAsync = less.fileAsync || false; // Interval between watch polls less.poll = less.poll || (isFileProtocol ? 1000 : 1500); //Setup user functions if (less.functions) { for(var func in less.functions) { less.tree.functions[func] = less.functions[func]; } } var dumpLineNumbers = /!dumpLineNumbers:(comments|mediaquery|all)/.exec(location.hash); if (dumpLineNumbers) { less.dumpLineNumbers = dumpLineNumbers[1]; } // // Watch mode // less.watch = function () { if (!less.watchMode ){ less.env = 'development'; initRunningMode(); } return this.watchMode = true }; less.unwatch = function () {clearInterval(less.watchTimer); return this.watchMode = false; }; function initRunningMode(){ if (less.env === 'development') { less.optimization = 0; less.watchTimer = setInterval(function () { if (less.watchMode) { loadStyleSheets(function (e, root, _, sheet, env) { if (e) { error(e, sheet.href); } else if (root) { createCSS(root.toCSS(less), sheet, env.lastModified); } }); } }, less.poll); } else { less.optimization = 3; } } if (/!watch/.test(location.hash)) { less.watch(); } var cache = null; if (less.env != 'development') { try { cache = (typeof(window.localStorage) === 'undefined') ? null : window.localStorage; } catch (_) {} } // // Get all tags with the 'rel' attribute set to "stylesheet/less" // var links = document.getElementsByTagName('link'); var typePattern = /^text\/(x-)?less$/; less.sheets = []; for (var i = 0; i < links.length; i++) { if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) && (links[i].type.match(typePattern)))) { less.sheets.push(links[i]); } } // // With this function, it's possible to alter variables and re-render // CSS without reloading less-files // var session_cache = ''; less.modifyVars = function(record) { var str = session_cache; for (name in record) { str += ((name.slice(0,1) === '@')? '' : '@') + name +': '+ ((record[name].slice(-1) === ';')? record[name] : record[name] +';'); } new(less.Parser)(new less.tree.parseEnv(less)).parse(str, function (e, root) { if (e) { error(e, "session_cache"); } else { createCSS(root.toCSS(less), less.sheets[less.sheets.length - 1]); } }); }; less.refresh = function (reload) { var startTime, endTime; startTime = endTime = new(Date); loadStyleSheets(function (e, root, _, sheet, env) { if (e) { return error(e, sheet.href); } if (env.local) { log("loading " + sheet.href + " from cache."); } else { log("parsed " + sheet.href + " successfully."); createCSS(root.toCSS(less), sheet, env.lastModified); } log("css for " + sheet.href + " generated in " + (new(Date) - endTime) + 'ms'); (env.remaining === 0) && log("css generated in " + (new(Date) - startTime) + 'ms'); endTime = new(Date); }, reload); loadStyles(); }; less.refreshStyles = loadStyles; less.refresh(less.env === 'development'); function loadStyles() { var styles = document.getElementsByTagName('style'); for (var i = 0; i < styles.length; i++) { if (styles[i].type.match(typePattern)) { var env = new less.tree.parseEnv(less); env.filename = document.location.href.replace(/#.*$/, ''); new(less.Parser)(env).parse(styles[i].innerHTML || '', function (e, cssAST) { if (e) { return error(e, "inline"); } var css = cssAST.toCSS(less); var style = styles[i]; style.type = 'text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.innerHTML = css; } }); } } } function loadStyleSheets(callback, reload) { for (var i = 0; i < less.sheets.length; i++) { loadStyleSheet(less.sheets[i], callback, reload, less.sheets.length - (i + 1)); } } function pathDiff(url, baseUrl) { // diff between two paths to create a relative path var urlParts = extractUrlParts(url), baseUrlParts = extractUrlParts(baseUrl), i, max, urlDirectories, baseUrlDirectories, diff = ""; if (urlParts.hostPart !== baseUrlParts.hostPart) { return ""; } max = Math.max(baseUrlParts.directories.length, urlParts.directories.length); for(i = 0; i < max; i++) { if (baseUrlParts.directories[i] !== urlParts.directories[i]) { break; } } baseUrlDirectories = baseUrlParts.directories.slice(i); urlDirectories = urlParts.directories.slice(i); for(i = 0; i < baseUrlDirectories.length-1; i++) { diff += "../"; } for(i = 0; i < urlDirectories.length-1; i++) { diff += urlDirectories[i] + "/"; } return diff; } function extractUrlParts(url, baseUrl) { // urlParts[1] = protocol&hostname || / // urlParts[2] = / if path relative to host base // urlParts[3] = directories // urlParts[4] = filename // urlParts[5] = parameters var urlPartsRegex = /^((?:[a-z-]+:)?\/+?(?:[^\/\?#]*\/)|([\/\\]))?((?:[^\/\\\?#]*[\/\\])*)([^\/\\\?#]*)([#\?].*)?$/, urlParts = url.match(urlPartsRegex), returner = {}, directories = [], i, baseUrlParts; if (!urlParts) { throw new Error("Could not parse sheet href - '"+url+"'"); } // Stylesheets in IE don't always return the full path if (!urlParts[1] || urlParts[2]) { baseUrlParts = baseUrl.match(urlPartsRegex); if (!baseUrlParts) { throw new Error("Could not parse page url - '"+baseUrl+"'"); } urlParts[1] = urlParts[1] || baseUrlParts[1] || ""; if (!urlParts[2]) { urlParts[3] = baseUrlParts[3] + urlParts[3]; } } if (urlParts[3]) { directories = urlParts[3].replace("\\", "/").split("/"); // extract out . before .. so .. doesn't absorb a non-directory for(i = 0; i < directories.length; i++) { if (directories[i] === ".") { directories.splice(i, 1); i -= 1; } } for(i = 0; i < directories.length; i++) { if (directories[i] === ".." && i > 0) { directories.splice(i-1, 2); i -= 2; } } } returner.hostPart = urlParts[1]; returner.directories = directories; returner.path = urlParts[1] + directories.join("/"); returner.fileUrl = returner.path + (urlParts[4] || ""); returner.url = returner.fileUrl + (urlParts[5] || ""); return returner; } function loadStyleSheet(sheet, callback, reload, remaining) { // sheet may be set to the stylesheet for the initial load or a collection of properties including // some env variables for imports var hrefParts = extractUrlParts(sheet.href, window.location.href); var href = hrefParts.url; var css = cache && cache.getItem(href); var timestamp = cache && cache.getItem(href + ':timestamp'); var styles = { css: css, timestamp: timestamp }; var env; var newFileInfo = { relativeUrls: less.relativeUrls, currentDirectory: hrefParts.path, filename: href }; if (sheet instanceof less.tree.parseEnv) { env = new less.tree.parseEnv(sheet); newFileInfo.entryPath = env.currentFileInfo.entryPath; newFileInfo.rootpath = env.currentFileInfo.rootpath; newFileInfo.rootFilename = env.currentFileInfo.rootFilename; } else { env = new less.tree.parseEnv(less); env.mime = sheet.type; newFileInfo.entryPath = hrefParts.path; newFileInfo.rootpath = less.rootpath || hrefParts.path; newFileInfo.rootFilename = href; } if (env.relativeUrls) { //todo - this relies on option being set on less object rather than being passed in as an option // - need an originalRootpath if (less.rootpath) { newFileInfo.rootpath = extractUrlParts(less.rootpath + pathDiff(hrefParts.path, newFileInfo.entryPath)).path; } else { newFileInfo.rootpath = hrefParts.path; } } xhr(href, sheet.type, function (data, lastModified) { // Store data this session session_cache += data.replace(/@import .+?;/ig, ''); if (!reload && styles && lastModified && (new(Date)(lastModified).valueOf() === new(Date)(styles.timestamp).valueOf())) { // Use local copy createCSS(styles.css, sheet); callback(null, null, data, sheet, { local: true, remaining: remaining }, href); } else { // Use remote copy (re-parse) try { env.contents[href] = data; // Updating content cache env.paths = [hrefParts.path]; env.currentFileInfo = newFileInfo; new(less.Parser)(env).parse(data, function (e, root) { if (e) { return callback(e, null, null, sheet); } try { callback(e, root, data, sheet, { local: false, lastModified: lastModified, remaining: remaining }, href); //TODO - there must be a better way? A generic less-to-css function that can both call error //and removeNode where appropriate //should also add tests if (env.currentFileInfo.rootFilename === href) { removeNode(document.getElementById('less-error-message:' + extractId(href))); } } catch (e) { callback(e, null, null, sheet); } }); } catch (e) { callback(e, null, null, sheet); } } }, function (status, url) { callback({ type: 'File', message: "'" + url + "' wasn't found (" + status + ")" }, null, null, sheet); }); } function extractId(href) { return href.replace(/^[a-z-]+:\/+?[^\/]+/, '' ) // Remove protocol & domain .replace(/^\//, '' ) // Remove root / .replace(/\.[a-zA-Z]+$/, '' ) // Remove simple extension .replace(/[^\.\w-]+/g, '-') // Replace illegal characters .replace(/\./g, ':'); // Replace dots with colons(for valid id) } function createCSS(styles, sheet, lastModified) { // Strip the query-string var href = sheet.href || ''; // If there is no title set, use the filename, minus the extension var id = 'less:' + (sheet.title || extractId(href)); // If this has already been inserted into the DOM, we may need to replace it var oldCss = document.getElementById(id); var keepOldCss = false; // Create a new stylesheet node for insertion or (if necessary) replacement var css = document.createElement('style'); css.setAttribute('type', 'text/css'); if (sheet.media) { css.setAttribute('media', sheet.media); } css.id = id; if (css.styleSheet) { // IE try { css.styleSheet.cssText = styles; } catch (e) { throw new(Error)("Couldn't reassign styleSheet.cssText."); } } else { css.appendChild(document.createTextNode(styles)); // If new contents match contents of oldCss, don't replace oldCss keepOldCss = (oldCss !== null && oldCss.childNodes.length > 0 && css.childNodes.length > 0 && oldCss.firstChild.nodeValue === css.firstChild.nodeValue); } var head = document.getElementsByTagName('head')[0]; // If there is no oldCss, just append; otherwise, only append if we need // to replace oldCss with an updated stylesheet if (oldCss == null || keepOldCss === false) { var nextEl = sheet && sheet.nextSibling || null; (nextEl || document.getElementsByTagName('head')[0]).parentNode.insertBefore(css, nextEl); } if (oldCss && keepOldCss === false) { head.removeChild(oldCss); } // Don't update the local store if the file wasn't modified if (lastModified && cache) { log('saving ' + href + ' to cache.'); try { cache.setItem(href, styles); cache.setItem(href + ':timestamp', lastModified); } catch(e) { //TODO - could do with adding more robust error handling log('failed to save'); } } } function xhr(url, type, callback, errback) { var xhr = getXMLHttpRequest(); var async = isFileProtocol ? less.fileAsync : less.async; if (typeof(xhr.overrideMimeType) === 'function') { xhr.overrideMimeType('text/css'); } xhr.open('GET', url, async); xhr.setRequestHeader('Accept', type || 'text/x-less, text/css; q=0.9, */*; q=0.5'); xhr.send(null); if (isFileProtocol && !less.fileAsync) { if (xhr.status === 0 || (xhr.status >= 200 && xhr.status < 300)) { callback(xhr.responseText); } else { errback(xhr.status, url); } } else if (async) { xhr.onreadystatechange = function () { if (xhr.readyState == 4) { handleResponse(xhr, callback, errback); } }; } else { handleResponse(xhr, callback, errback); } function handleResponse(xhr, callback, errback) { if (xhr.status >= 200 && xhr.status < 300) { callback(xhr.responseText, xhr.getResponseHeader("Last-Modified")); } else if (typeof(errback) === 'function') { errback(xhr.status, url); } } } function getXMLHttpRequest() { if (window.XMLHttpRequest) { return new(XMLHttpRequest); } else { try { return new(ActiveXObject)("MSXML2.XMLHTTP.3.0"); } catch (e) { log("browser doesn't support AJAX."); return null; } } } function removeNode(node) { return node && node.parentNode.removeChild(node); } function log(str) { if (less.env == 'development' && typeof(console) !== "undefined") { console.log('less: ' + str) } } function error(e, rootHref) { var id = 'less-error-message:' + extractId(rootHref || ""); var template = '
  • {content}
  • '; var elem = document.createElement('div'), timer, content, error = []; var filename = e.filename || rootHref; var filenameNoPath = filename.match(/([^\/]+(\?.*)?)$/)[1]; elem.id = id; elem.className = "less-error-message"; content = '

    ' + (e.type || "Syntax") + "Error: " + (e.message || 'There is an error in your .less file') + '

    ' + '

    in ' + filenameNoPath + " "; var errorline = function (e, i, classname) { if (e.extract[i] != undefined) { error.push(template.replace(/\{line\}/, (parseInt(e.line) || 0) + (i - 1)) .replace(/\{class\}/, classname) .replace(/\{content\}/, e.extract[i])); } }; if (e.extract) { errorline(e, 0, ''); errorline(e, 1, 'line'); errorline(e, 2, ''); content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':

    ' + '
      ' + error.join('') + '
    '; } else if (e.stack) { content += '
    ' + e.stack.split('\n').slice(1).join('
    '); } elem.innerHTML = content; // CSS for error messages createCSS([ '.less-error-message ul, .less-error-message li {', 'list-style-type: none;', 'margin-right: 15px;', 'padding: 4px 0;', 'margin: 0;', '}', '.less-error-message label {', 'font-size: 12px;', 'margin-right: 15px;', 'padding: 4px 0;', 'color: #cc7777;', '}', '.less-error-message pre {', 'color: #dd6666;', 'padding: 4px 0;', 'margin: 0;', 'display: inline-block;', '}', '.less-error-message pre.line {', 'color: #ff0000;', '}', '.less-error-message h3 {', 'font-size: 20px;', 'font-weight: bold;', 'padding: 15px 0 5px 0;', 'margin: 0;', '}', '.less-error-message a {', 'color: #10a', '}', '.less-error-message .error {', 'color: red;', 'font-weight: bold;', 'padding-bottom: 2px;', 'border-bottom: 1px dashed red;', '}' ].join('\n'), { title: 'error-message' }); elem.style.cssText = [ "font-family: Arial, sans-serif", "border: 1px solid #e00", "background-color: #eee", "border-radius: 5px", "-webkit-border-radius: 5px", "-moz-border-radius: 5px", "color: #e00", "padding: 15px", "margin-bottom: 15px" ].join(';'); if (less.env == 'development') { timer = setInterval(function () { if (document.body) { if (document.getElementById(id)) { document.body.replaceChild(elem, document.getElementById(id)); } else { document.body.insertBefore(elem, document.body.firstChild); } clearInterval(timer); } }, 10); } } // amd.js // // Define Less as an AMD module. if (typeof define === "function" && define.amd) { define(function () { return less; } ); } })(window); less.js-1.4.2/dist/less-1.4.0.min.js000066400000000000000000002324071217256642200166050ustar00rootroot00000000000000/* * LESS - Leaner CSS v1.4.0 * http://lesscss.org * * Copyright (c) 2009-2013, Alexis Sellier * Licensed under the Apache 2.0 License. * * @licence */(function(e,t){function n(t){return e.less[t.split("/")[1]]}function f(){r.env==="development"?(r.optimization=0,r.watchTimer=setInterval(function(){r.watchMode&&g(function(e,t,n,i,s){e?k(e,i.href):t&&S(t.toCSS(r),i,s.lastModified)})},r.poll)):r.optimization=3}function m(){var e=document.getElementsByTagName("style");for(var t=0;t0&&(s.splice(o-1,2),o-=2)}return i.hostPart=r[1],i.directories=s,i.path=r[1]+s.join("/"),i.fileUrl=i.path+(r[4]||""),i.url=i.fileUrl+(r[5]||""),i}function w(t,n,i,s){var o=b(t.href,e.location.href),u=o.url,a=l&&l.getItem(u),f=l&&l.getItem(u+":timestamp"),c={css:a,timestamp:f},h,p={relativeUrls:r.relativeUrls,currentDirectory:o.path,filename:u};t instanceof r.tree.parseEnv?(h=new r.tree.parseEnv(t),p.entryPath=h.currentFileInfo.entryPath,p.rootpath=h.currentFileInfo.rootpath,p.rootFilename=h.currentFileInfo.rootFilename):(h=new r.tree.parseEnv(r),h.mime=t.type,p.entryPath=o.path,p.rootpath=r.rootpath||o.path,p.rootFilename=u),h.relativeUrls&&(r.rootpath?p.rootpath=b(r.rootpath+y(o.path,p.entryPath)).path:p.rootpath=o.path),x(u,t.type,function(e,a){v+=e.replace(/@import .+?;/ig,"");if(!i&&c&&a&&(new Date(a)).valueOf()===(new Date(c.timestamp)).valueOf())S(c.css,t),n(null,null,e,t,{local:!0,remaining:s},u);else try{h.contents[u]=e,h.paths=[o.path],h.currentFileInfo=p,(new r.Parser(h)).parse(e,function(r,i){if(r)return n(r,null,null,t);try{n(r,i,e,t,{local:!1,lastModified:a,remaining:s},u),h.currentFileInfo.rootFilename===u&&N(document.getElementById("less-error-message:"+E(u)))}catch(r){n(r,null,null,t)}})}catch(f){n(f,null,null,t)}},function(e,r){n({type:"File",message:"'"+r+"' wasn't found ("+e+")"},null,null,t)})}function E(e){return e.replace(/^[a-z-]+:\/+?[^\/]+/,"").replace(/^\//,"").replace(/\.[a-zA-Z]+$/,"").replace(/[^\.\w-]+/g,"-").replace(/\./g,":")}function S(e,t,n){var r=t.href||"",i="less:"+(t.title||E(r)),s=document.getElementById(i),o=!1,u=document.createElement("style");u.setAttribute("type","text/css"),t.media&&u.setAttribute("media",t.media),u.id=i;if(u.styleSheet)try{u.styleSheet.cssText=e}catch(a){throw new Error("Couldn't reassign styleSheet.cssText.")}else u.appendChild(document.createTextNode(e)),o=s!==null&&s.childNodes.length>0&&u.childNodes.length>0&&s.firstChild.nodeValue===u.firstChild.nodeValue;var f=document.getElementsByTagName("head")[0];if(s==null||o===!1){var c=t&&t.nextSibling||null;(c||document.getElementsByTagName("head")[0]).parentNode.insertBefore(u,c)}s&&o===!1&&f.removeChild(s);if(n&&l){C("saving "+r+" to cache.");try{l.setItem(r,e),l.setItem(r+":timestamp",n)}catch(a){C("failed to save")}}}function x(e,t,n,i){function a(t,n,r){t.status>=200&&t.status<300?n(t.responseText,t.getResponseHeader("Last-Modified")):typeof r=="function"&&r(t.status,e)}var s=T(),u=o?r.fileAsync:r.async;typeof s.overrideMimeType=="function"&&s.overrideMimeType("text/css"),s.open("GET",e,u),s.setRequestHeader("Accept",t||"text/x-less, text/css; q=0.9, */*; q=0.5"),s.send(null),o&&!r.fileAsync?s.status===0||s.status>=200&&s.status<300?n(s.responseText):i(s.status,e):u?s.onreadystatechange=function(){s.readyState==4&&a(s,n,i)}:a(s,n,i)}function T(){if(e.XMLHttpRequest)return new XMLHttpRequest;try{return new ActiveXObject("MSXML2.XMLHTTP.3.0")}catch(t){return C("browser doesn't support AJAX."),null}}function N(e){return e&&e.parentNode.removeChild(e)}function C(e){r.env=="development"&&typeof console!="undefined"&&console.log("less: "+e)}function k(e,n){var i="less-error-message:"+E(n||""),s='
  • {content}
  • ',o=document.createElement("div"),u,a,f=[],l=e.filename||n,c=l.match(/([^\/]+(\?.*)?)$/)[1];o.id=i,o.className="less-error-message",a="

    "+(e.type||"Syntax")+"Error: "+(e.message||"There is an error in your .less file")+"

    "+'

    in '+c+" ";var h=function(e,n,r){e.extract[n]!=t&&f.push(s.replace(/\{line\}/,(parseInt(e.line)||0)+(n-1)).replace(/\{class\}/,r).replace(/\{content\}/,e.extract[n]))};e.extract?(h(e,0,""),h(e,1,"line"),h(e,2,""),a+="on line "+e.line+", column "+(e.column+1)+":

    "+"
      "+f.join("")+"
    "):e.stack&&(a+="
    "+e.stack.split("\n").slice(1).join("
    ")),o.innerHTML=a,S([".less-error-message ul, .less-error-message li {","list-style-type: none;","margin-right: 15px;","padding: 4px 0;","margin: 0;","}",".less-error-message label {","font-size: 12px;","margin-right: 15px;","padding: 4px 0;","color: #cc7777;","}",".less-error-message pre {","color: #dd6666;","padding: 4px 0;","margin: 0;","display: inline-block;","}",".less-error-message pre.line {","color: #ff0000;","}",".less-error-message h3 {","font-size: 20px;","font-weight: bold;","padding: 15px 0 5px 0;","margin: 0;","}",".less-error-message a {","color: #10a","}",".less-error-message .error {","color: red;","font-weight: bold;","padding-bottom: 2px;","border-bottom: 1px dashed red;","}"].join("\n"),{title:"error-message"}),o.style.cssText=["font-family: Arial, sans-serif","border: 1px solid #e00","background-color: #eee","border-radius: 5px","-webkit-border-radius: 5px","-moz-border-radius: 5px","color: #e00","padding: 15px","margin-bottom: 15px"].join(";"),r.env=="development"&&(u=setInterval(function(){document.body&&(document.getElementById(i)?document.body.replaceChild(o,document.getElementById(i)):document.body.insertBefore(o,document.body.firstChild),clearInterval(u))},10))}var r,i,s;typeof environment=="object"&&{}.toString.call(environment)==="[object Environment]"?(typeof e=="undefined"?r={}:r=e.less={},i=r.tree={},r.mode="rhino"):typeof e=="undefined"?(r=exports,i=n("./tree"),r.mode="node"):(typeof e.less=="undefined"&&(e.less={}),r=e.less,i=e.less.tree={},r.mode="browser"),r.Parser=function(t){function m(){a=c[u],f=o,h=o}function g(){c[u]=a,o=f,h=o}function y(){o>h&&(c[u]=c[u].slice(o-h),h=o)}function b(e){var t=e.charCodeAt(0);return t===32||t===10||t===9}function w(e){var t,n,r,i,a;if(e instanceof Function)return e.call(p.parsers);if(typeof e=="string")t=s.charAt(o)===e?e:null,r=1,y();else{y();if(!(t=e.exec(c[u])))return null;r=t[0].length}if(t)return E(r),typeof t=="string"?t:t.length===1?t[0]:t}function E(e){var t=o,n=u,r=o+c[u].length,i=o+=e;while(o=0&&t.charAt(n)!=="\n";n--)r++;return{line:typeof e=="number"?(t.slice(0,e).match(/\n/g)||"").length:null,column:r}}function k(e,t,i){var s=i.currentFileInfo.filename;return r.mode!=="browser"&&r.mode!=="rhino"&&(s=n("path").resolve(s)),{lineNumber:C(e,t).line+1,fileName:s}}function L(e,t){var n=N(e,t),r=C(e.index,n),i=r.line,s=r.column,o=n.split("\n");this.type=e.type||"Syntax",this.message=e.message,this.filename=e.filename||t.currentFileInfo.filename,this.index=e.index,this.line=typeof i=="number"?i+1:null,this.callLine=e.call&&C(e.call,n).line+1,this.callExtract=o[C(e.call,n).line],this.stack=e.stack,this.column=s,this.extract=[o[i-1],o[i],o[i+1]]}var s,o,u,a,f,l,c,h,p,d=this;t instanceof i.parseEnv||(t=new i.parseEnv(t));var v=this.imports={paths:t.paths||[],queue:[],files:t.files,contents:t.contents,mime:t.mime,error:null,push:function(e,n,i){var s=this;this.queue.push(e),r.Parser.importer(e,n,function(t,n,r){s.queue.splice(s.queue.indexOf(e),1);var o=r in s.files;s.files[r]=n,t&&!s.error&&(s.error=t),i(t,n,o)},t)}};return L.prototype=new Error,L.prototype.constructor=L,this.env=t=t||{},this.optimization="optimization"in this.env?this.env.optimization:1,p={imports:v,parse:function(e,a){var f,d,v,m,g,y,b=[],E,S=null;o=u=h=l=0,s=e.replace(/\r\n/g,"\n"),s=s.replace(/^\uFEFF/,""),c=function(e){var n=0,r=/(?:@\{[\w-]+\}|[^"'`\{\}\/\(\)\\])+/g,i=/\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g,o=/"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'|`((?:[^`]|\\.)*)`/g,u=0,a,f=e[0],l;for(var c=0,h,p;c0?"missing closing `}`":"missing opening `{`",filename:t.currentFileInfo.filename},t)),e.map(function(e){return e.join("")})}([[]]);if(S)return a(new L(S,t));try{f=new i.Ruleset([],w(this.parsers.primary)),f.root=!0,f.firstRoot=!0}catch(x){return a(new L(x,t))}f.toCSS=function(e){var s,o,u;return function(s,o){s=s||{};var u,a=new i.evalEnv(s);typeof o=="object"&&!Array.isArray(o)&&(o=Object.keys(o).map(function(e){var t=o[e];return t instanceof i.Value||(t instanceof i.Expression||(t=new i.Expression([t])),t=new i.Value([t])),new i.Rule("@"+e,t,!1,0)}),a.frames=[new i.Ruleset(null,o)]);try{var f=e.call(this,a);(new i.joinSelectorVisitor).run(f),(new i.processExtendsVisitor).run(f);var l=f.toCSS({compress:Boolean(s.compress),dumpLineNumbers:t.dumpLineNumbers,strictUnits:Boolean(s.strictUnits)})}catch(c){throw new L(c,t)}return s.yuicompress&&r.mode==="node"?n("ycssmin").cssmin(l,s.maxLineLen):s.compress?l.replace(/(\s)+/g,"$1"):l}}(f.eval);if(o=0&&s.charAt(T)!=="\n";T--)N++;S={type:"Parse",message:"Unrecognised input",index:o,filename:t.currentFileInfo.filename,line:g,column:N,extract:[y[g-2],y[g-1],y[g]]}}var C=function(e){e=S||e||p.imports.error,e?(e instanceof L||(e=new L(e,t)),a(e)):a(null,f)};t.processImports!==!1?(new i.importVisitor(this.imports,C)).run(f):C()},parsers:{primary:function(){var e,t=[];while((e=w(this.extendRule)||w(this.mixin.definition)||w(this.rule)||w(this.ruleset)||w(this.mixin.call)||w(this.comment)||w(this.directive))||w(/^[\s\n]+/)||w(/^;+/))e&&t.push(e);return t},comment:function(){var e;if(s.charAt(o)!=="/")return;if(s.charAt(o+1)==="/")return new i.Comment(w(/^\/\/.*/),!0);if(e=w(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/))return new i.Comment(e)},entities:{quoted:function(){var e,n=o,r,u=o;s.charAt(n)==="~"&&(n++,r=!0);if(s.charAt(n)!=='"'&&s.charAt(n)!=="'")return;r&&w("~");if(e=w(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/))return new i.Quoted(e[0],e[1]||e[2],r,u,t.currentFileInfo)},keyword:function(){var e;if(e=w(/^[_A-Za-z-][_A-Za-z0-9-]*/))return i.colors.hasOwnProperty(e)?new i.Color(i.colors[e].slice(1)):new i.Keyword(e)},call:function(){var e,n,r,s,a=o;if(!(e=/^([\w-]+|%|progid:[\w\.]+)\(/.exec(c[u])))return;e=e[1],n=e.toLowerCase();if(n==="url")return null;o+=e.length;if(n==="alpha"){s=w(this.alpha);if(typeof s!="undefined")return s}w("("),r=w(this.entities.arguments);if(!w(")"))return;if(e)return new i.Call(e,r,a,t.currentFileInfo)},arguments:function(){var e=[],t;while(t=w(this.entities.assignment)||w(this.expression)){e.push(t);if(!w(","))break}return e},literal:function(){return w(this.entities.dimension)||w(this.entities.color)||w(this.entities.quoted)||w(this.entities.unicodeDescriptor)},assignment:function(){var e,t;if((e=w(/^\w+(?=\s?=)/i))&&w("=")&&(t=w(this.entity)))return new i.Assignment(e,t)},url:function(){var e;if(s.charAt(o)!=="u"||!w(/^url\(/))return;return e=w(this.entities.quoted)||w(this.entities.variable)||w(/^(?:(?:\\[\(\)'"])|[^\(\)'"])+/)||"",S(")"),new i.URL(e.value!=null||e instanceof i.Variable?e:new i.Anonymous(e),t.currentFileInfo)},variable:function(){var e,n=o;if(s.charAt(o)==="@"&&(e=w(/^@@?[\w-]+/)))return new i.Variable(e,n,t.currentFileInfo)},variableCurly:function(){var e,n,r=o;if(s.charAt(o)==="@"&&(n=w(/^@\{([\w-]+)\}/)))return new i.Variable("@"+n[1],r,t.currentFileInfo)},color:function(){var e;if(s.charAt(o)==="#"&&(e=w(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/)))return new i.Color(e[1])},dimension:function(){var e,t=s.charCodeAt(o);if(t>57||t<43||t===47||t==44)return;if(e=w(/^([+-]?\d*\.?\d+)(%|[a-z]+)?/))return new i.Dimension(e[1],e[2])},unicodeDescriptor:function(){var e;if(e=w(/^U\+[0-9a-fA-F?]+(\-[0-9a-fA-F?]+)?/))return new i.UnicodeDescriptor(e[0])},javascript:function(){var e,t=o,n;s.charAt(t)==="~"&&(t++,n=!0);if(s.charAt(t)!=="`")return;n&&w("~");if(e=w(/^`([^`]*)`/))return new i.JavaScript(e[1],o,n)}},variable:function(){var e;if(s.charAt(o)==="@"&&(e=w(/^(@[\w-]+)\s*:/)))return e[1]},extend:function(e){var t,n,r=o,s,u=[];if(!w(e?/^&:extend\(/:/^:extend\(/))return;do{s=null,t=[];for(;;){s=w(/^(all)(?=\s*(\)|,))/);if(s)break;n=w(this.element);if(!n)break;t.push(n)}s=s&&s[1],u.push(new i.Extend(new i.Selector(t),s,r))}while(w(","));return S(/^\)/),e&&S(/^;/),u},extendRule:function(){return this.extend(!0)},mixin:{call:function(){var e=[],n,r,u,a,f,l=o,c=s.charAt(o),h=!1;if(c!=="."&&c!=="#")return;m();while(n=w(/^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/))e.push(new i.Element(r,n,o)),r=w(">");w("(")&&(u=this.mixin.args.call(this,!0).args,S(")")),u=u||[],w(this.important)&&(h=!0);if(e.length>0&&(w(";")||T("}")))return new i.mixin.Call(e,u,l,t.currentFileInfo,h);g()},args:function(e){var t=[],n=[],r,u=[],a,f,l,c,h,p={args:null,variadic:!1};for(;;){if(e)h=w(this.expression);else{w(this.comment);if(s.charAt(o)==="."&&w(/^\.{3}/)){p.variadic=!0,w(";")&&!r&&(r=!0),(r?n:u).push({variadic:!0});break}h=w(this.entities.variable)||w(this.entities.literal)||w(this.entities.keyword)}if(!h)break;l=null,h.throwAwayComments&&h.throwAwayComments(),c=h;var d=null;if(e){if(h.value.length==1)var d=h.value[0]}else d=h;if(d&&d instanceof i.Variable)if(w(":"))t.length>0&&(r&&x("Cannot mix ; and , as delimiter types"),a=!0),c=S(this.expression),l=f=d.name;else{if(!e&&w(/^\.{3}/)){p.variadic=!0,w(";")&&!r&&(r=!0),(r?n:u).push({name:h.name,variadic:!0});break}e||(f=l=d.name,c=null)}c&&t.push(c),u.push({name:l,value:c});if(w(","))continue;if(w(";")||r)a&&x("Cannot mix ; and , as delimiter types"),r=!0,t.length>1&&(c=new i.Value(t)),n.push({name:f,value:c}),f=null,t=[],a=!1}return p.args=r?n:u,p},definition:function(){var e,t=[],n,r,u,a,f,c=!1;if(s.charAt(o)!=="."&&s.charAt(o)!=="#"||T(/^[^{]*\}/))return;m();if(n=w(/^([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/)){e=n[1];var h=this.mixin.args.call(this,!1);t=h.args,c=h.variadic,w(")")||(l=o,g()),w(this.comment),w(/^when/)&&(f=S(this.conditions,"expected condition")),r=w(this.block);if(r)return new i.mixin.Definition(e,t,r,f,c);g()}}},entity:function(){return w(this.entities.literal)||w(this.entities.variable)||w(this.entities.url)||w(this.entities.call)||w(this.entities.keyword)||w(this.entities.javascript)||w(this.comment)},end:function(){return w(";")||T("}")},alpha:function(){var e;if(!w(/^\(opacity=/i))return;if(e=w(/^\d+/)||w(this.entities.variable))return S(")"),new i.Alpha(e)},element:function(){var e,t,n,r;n=w(this.combinator),e=w(/^(?:\d+\.\d+|\d+)%/)||w(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/)||w("*")||w("&")||w(this.attribute)||w(/^\([^()@]+\)/)||w(/^[\.#](?=@)/)||w(this.entities.variableCurly),e||w("(")&&(r=w(this.selector))&&w(")")&&(e=new i.Paren(r));if(e)return new i.Element(n,e,o)},combinator:function(){var e,t=s.charAt(o);if(t===">"||t==="+"||t==="~"||t==="|"){o++;while(s.charAt(o).match(/\s/))o++;return new i.Combinator(t)}return s.charAt(o-1).match(/\s/)?new i.Combinator(" "):new i.Combinator(null)},selector:function(){var e,t,n=[],r,u,a,f=[];while((a=w(this.extend))||(t=w(this.element))){a?f.push.apply(f,a):(f.length&&x("Extend can only be used at the end of selector"),r=s.charAt(o),n.push(t),t=null);if(r==="{"||r==="}"||r===";"||r===","||r===")")break}if(n.length>0)return new i.Selector(n,f);f.length&&x("Extend must be used to extend a selector, it cannot be used on its own")},attribute:function(){var e="",t,n,r;if(!w("["))return;(t=w(this.entities.variableCurly))||(t=S(/^(?:[_A-Za-z0-9-\*]*\|)?(?:[_A-Za-z0-9-]|\\.)+/));if(r=w(/^[|~*$^]?=/))n=w(this.entities.quoted)||w(/^[\w-]+/)||w(this.entities.variableCurly);return S("]"),new i.Attribute(t,r,n)},block:function(){var e;if(w("{")&&(e=w(this.primary))&&w("}"))return e},ruleset:function(){var e=[],n,r,u,a;m(),t.dumpLineNumbers&&(a=k(o,s,t));while(n=w(this.selector)){e.push(n),w(this.comment);if(!w(","))break;w(this.comment)}if(e.length>0&&(r=w(this.block))){var f=new i.Ruleset(e,r,t.strictImports);return t.dumpLineNumbers&&(f.debugInfo=a),f}l=o,g()},rule:function(e){var n,r,u=s.charAt(o),a,c;m();if(u==="."||u==="#"||u==="&")return;if(n=w(this.variable)||w(this.property)){r=!e&&(t.compress||n.charAt(0)==="@")?w(this.value)||w(this.anonymousValue):w(this.anonymousValue)||w(this.value),a=w(this.important);if(r&&w(this.end))return new i.Rule(n,r,a,f,t.currentFileInfo);l=o,g();if(r&&!e)return this.rule(!0)}},anonymousValue:function(){if(match=/^([^@+\/'"*`(;{}-]*);/.exec(c[u]))return o+=match[0].length-1,new i.Anonymous(match[1])},"import":function(){var e,n,r=o;m();var s=w(/^@import?\s+/),u=(s?w(this.importOptions):null)||{};if(s&&(e=w(this.entities.quoted)||w(this.entities.url))){n=w(this.mediaFeatures);if(w(";"))return n=n&&new i.Value(n),new i.Import(e,n,u,r,t.currentFileInfo)}g()},importOptions:function(){var e,t={},n,r;if(!w("("))return null;do if(e=w(this.importOption)){n=e,r=!0;switch(n){case"css":n="less",r=!1;break;case"once":n="multiple",r=!1}t[n]=r;if(!w(","))break}while(e);return S(")"),t},importOption:function(){var e=w(/^(less|css|multiple|once)/);if(e)return e[1]},mediaFeature:function(){var e,n,r=[];do if(e=w(this.entities.keyword))r.push(e);else if(w("(")){n=w(this.property),e=w(this.value);if(!w(")"))return null;if(n&&e)r.push(new i.Paren(new i.Rule(n,e,null,o,t.currentFileInfo,!0)));else{if(!e)return null;r.push(new i.Paren(e))}}while(e);if(r.length>0)return new i.Expression(r)},mediaFeatures:function(){var e,t=[];do if(e=w(this.mediaFeature)){t.push(e);if(!w(","))break}else if(e=w(this.entities.variable)){t.push(e);if(!w(","))break}while(e);return t.length>0?t:null},media:function(){var e,n,r,u;t.dumpLineNumbers&&(u=k(o,s,t));if(w(/^@media/)){e=w(this.mediaFeatures);if(n=w(this.block))return r=new i.Media(n,e),t.dumpLineNumbers&&(r.debugInfo=u),r}},directive:function(){var e,n,r,u,a,f,l,c,h,p;if(s.charAt(o)!=="@")return;if(n=w(this["import"])||w(this.media))return n;m(),e=w(/^@[a-z-]+/);if(!e)return;l=e,e.charAt(1)=="-"&&e.indexOf("-",2)>0&&(l="@"+e.slice(e.indexOf("-",2)+1));switch(l){case"@font-face":c=!0;break;case"@viewport":case"@top-left":case"@top-left-corner":case"@top-center":case"@top-right":case"@top-right-corner":case"@bottom-left":case"@bottom-left-corner":case"@bottom-center":case"@bottom-right":case"@bottom-right-corner":case"@left-top":case"@left-middle":case"@left-bottom":case"@right-top":case"@right-middle":case"@right-bottom":c=!0;break;case"@page":case"@document":case"@supports":case"@keyframes":c=!0,h=!0;break;case"@namespace":p=!0}h&&(e+=" "+(w(/^[^{]+/)||"").trim());if(c){if(r=w(this.block))return new i.Directive(e,r)}else if((n=p?w(this.expression):w(this.entity))&&w(";")){var d=new i.Directive(e,n);return t.dumpLineNumbers&&(d.debugInfo=k(o,s,t)),d}g()},value:function(){var e,t=[],n;while(e=w(this.expression)){t.push(e);if(!w(","))break}if(t.length>0)return new i.Value(t)},important:function(){if(s.charAt(o)==="!")return w(/^! *important/)},sub:function(){var e,t;if(w("("))if(e=w(this.addition))return t=new i.Expression([e]),S(")"),t.parens=!0,t},multiplication:function(){var e,t,n,r,u,a=[];if(e=w(this.operand)){u=b(s.charAt(o-1));while(!T(/^\/[*\/]/)&&(n=w("/")||w("*"))){if(!(t=w(this.operand)))break;e.parensInOp=!0,t.parensInOp=!0,r=new i.Operation(n,[r||e,t],u),u=b(s.charAt(o-1))}return r||e}},addition:function(){var e,t,n,r,u;if(e=w(this.multiplication)){u=b(s.charAt(o-1));while((n=w(/^[-+]\s+/)||!u&&(w("+")||w("-")))&&(t=w(this.multiplication)))e.parensInOp=!0,t.parensInOp=!0,r=new i.Operation(n,[r||e,t],u),u=b(s.charAt(o-1));return r||e}},conditions:function(){var e,t,n=o,r;if(e=w(this.condition)){while(w(",")&&(t=w(this.condition)))r=new i.Condition("or",r||e,t,n);return r||e}},condition:function(){var e,t,n,r,s=o,u=!1;w(/^not/)&&(u=!0),S("(");if(e=w(this.addition)||w(this.entities.keyword)||w(this.entities.quoted))return(r=w(/^(?:>=|=<|[<=>])/))?(t=w(this.addition)||w(this.entities.keyword)||w(this.entities.quoted))?n=new i.Condition(r,e,t,s,u):x("expected expression"):n=new i.Condition("=",e,new i.Keyword("true"),s,u),S(")"),w(/^and/)?new i.Condition("and",n,w(this.condition)):n},operand:function(){var e,t=s.charAt(o+1);s.charAt(o)==="-"&&(t==="@"||t==="(")&&(e=w("-"));var n=w(this.sub)||w(this.entities.dimension)||w(this.entities.color)||w(this.entities.variable)||w(this.entities.call);return e&&(n.parensInOp=!0,n=new i.Negative(n)),n},expression:function(){var e,t,n=[],r;while(e=w(this.addition)||w(this.entity))n.push(e),!T(/^\/[\/*]/)&&(t=w("/"))&&n.push(new i.Anonymous(t));if(n.length>0)return new i.Expression(n)},property:function(){var e;if(e=w(/^(\*?-?[_a-z0-9-]+)\s*:/))return e[1]}}}};if(r.mode==="browser"||r.mode==="rhino")r.Parser.importer=function(e,t,n,r){!/^([a-z-]+:)?\//.test(e)&&t.currentDirectory&&(e=t.currentDirectory+e);var i=r.toSheet(e);i.processImports=!1,i.currentFileInfo=t,w(i,function(e,t,r,i,s,o){n.call(null,e,t,o)},!0)};(function(r){function u(e){return r.functions.hsla(e.h,e.s,e.l,e.a)}function a(e,t){return e instanceof r.Dimension&&e.unit.is("%")?parseFloat(e.value*t/100):f(e)}function f(e){if(e instanceof r.Dimension)return parseFloat(e.unit.is("%")?e.value/100:e.value);if(typeof e=="number")return e;throw{error:"RuntimeError",message:"color functions take numbers as parameters"}}function l(e){return Math.min(1,Math.max(0,e))}r.functions={rgb:function(e,t,n){return this.rgba(e,t,n,1)},rgba:function(e,t,n,i){var s=[e,t,n].map(function(e){return a(e,256)});return i=f(i),new r.Color(s,i)},hsl:function(e,t,n){return this.hsla(e,t,n,1)},hsla:function(e,t,n,r){function o(e){return e=e<0?e+1:e>1?e-1:e,e*6<1?s+(i-s)*e*6:e*2<1?i:e*3<2?s+(i-s)*(2/3-e)*6:s}e=f(e)%360/360,t=l(f(t)),n=l(f(n)),r=l(f(r));var i=n<=.5?n*(t+1):n+t-n*t,s=n*2-i;return this.rgba(o(e+1/3)*255,o(e)*255,o(e-1/3)*255,r)},hsv:function(e,t,n){return this.hsva(e,t,n,1)},hsva:function(e,t,n,r){e=f(e)%360/360*360,t=f(t),n=f(n),r=f(r);var i,s;i=Math.floor(e/60%6),s=e/60-i;var o=[n,n*(1-t),n*(1-s*t),n*(1-(1-s)*t)],u=[[0,3,1],[2,0,1],[1,0,3],[1,2,0],[3,1,0],[0,1,2]];return this.rgba(o[u[i][0]]*255,o[u[i][1]]*255,o[u[i][2]]*255,r)},hue:function(e){return new r.Dimension(Math.round(e.toHSL().h))},saturation:function(e){return new r.Dimension(Math.round(e.toHSL().s*100),"%")},lightness:function(e){return new r.Dimension(Math.round(e.toHSL().l*100),"%")},hsvhue:function(e){return new r.Dimension(Math.round(e.toHSV().h))},hsvsaturation:function(e){return new r.Dimension(Math.round(e.toHSV().s*100),"%")},hsvvalue:function(e){return new r.Dimension(Math.round(e.toHSV().v*100),"%")},red:function(e){return new r.Dimension(e.rgb[0])},green:function(e){return new r.Dimension(e.rgb[1])},blue:function(e){return new r.Dimension(e.rgb[2])},alpha:function(e){return new r.Dimension(e.toHSL().a)},luma:function(e){return new r.Dimension(Math.round(e.luma()*e.alpha*100),"%")},saturate:function(e,t){var n=e.toHSL();return n.s+=t.value/100,n.s=l(n.s),u(n)},desaturate:function(e,t){var n=e.toHSL();return n.s-=t.value/100,n.s=l(n.s),u(n)},lighten:function(e,t){var n=e.toHSL();return n.l+=t.value/100,n.l=l(n.l),u(n)},darken:function(e,t){var n=e.toHSL();return n.l-=t.value/100,n.l=l(n.l),u(n)},fadein:function(e,t){var n=e.toHSL();return n.a+=t.value/100,n.a=l(n.a),u(n)},fadeout:function(e,t){var n=e.toHSL();return n.a-=t.value/100,n.a=l(n.a),u(n)},fade:function(e,t){var n=e.toHSL();return n.a=t.value/100,n.a=l(n.a),u(n)},spin:function(e,t){var n=e.toHSL(),r=(n.h+t.value)%360;return n.h=r<0?360+r:r,u(n)},mix:function(e,t,n){n||(n=new r.Dimension(50));var i=n.value/100,s=i*2-1,o=e.toHSL().a-t.toHSL().a,u=((s*o==-1?s:(s+o)/(1+s*o))+1)/2,a=1-u,f=[e.rgb[0]*u+t.rgb[0]*a,e.rgb[1]*u+t.rgb[1]*a,e.rgb[2]*u+t.rgb[2]*a],l=e.alpha*i+t.alpha*(1-i);return new r.Color(f,l)},greyscale:function(e){return this.desaturate(e,new r.Dimension(100))},contrast:function(e,t,n,r){if(!e.rgb)return null;typeof n=="undefined"&&(n=this.rgba(255,255,255,1)),typeof t=="undefined"&&(t=this.rgba(0,0,0,1));if(t.luma()>n.luma()){var i=n;n=t,t=i}return typeof r=="undefined"?r=.43:r=f(r),e.luma()*e.alpha=d){if(this.env.ieCompat!==!1)return this.env.silent||console.warn("Skipped data-uri embedding of %s because its size (%dKB) exceeds IE8-safe %dKB!",o,v,d),(new r.URL(i||t,this.currentFileInfo)).eval(this.env);this.env.silent||console.warn("WARNING: Embedding %s (%dKB) exceeds IE8's data-uri size limit of %dKB!",o,v,d)}p=f?p.toString("base64"):encodeURIComponent(p);var m="'data:"+s+","+p+"'";return new r.URL(new r.Anonymous(m))}},r._mime={_types:{".htm":"text/html",".html":"text/html",".gif":"image/gif",".jpg":"image/jpeg",".jpeg":"image/jpeg",".png":"image/png"},lookup:function(e){var i=n("path").extname(e),s=r._mime._types[i];if(s===t)throw new Error('Optional dependency "mime" is required for '+i);return s},charsets:{lookup:function(e){return e&&/^text\//.test(e)?"UTF-8":""}}};var i=[{name:"ceil"},{name:"floor"},{name:"sqrt"},{name:"abs"},{name:"tan",unit:""},{name:"sin",unit:""},{name:"cos",unit:""},{name:"atan",unit:"rad"},{name:"asin",unit:"rad"},{name:"acos",unit:"rad"}],s=function(e,t){return function(n){return t!=null&&(n=n.unify()),this._math(Math[e],t,n)}};for(var o=0;o255?255:e<0?0:e).toString(16),e.length===1?"0"+e:e}).join("");return n&&(r=r.split(""),r[0]==r[1]&&r[2]==r[3]&&r[4]==r[5]?r=r[0]+r[2]+r[4]:r=r.join("")),"#"+r},operate:function(t,n,r){var i=[];r instanceof e.Color||(r=r.toColor());for(var s=0;s<3;s++)i[s]=e.operate(t,n,this.rgb[s],r.rgb[s]);return new e.Color(i,this.alpha+r.alpha)},toHSL:function(){var e=this.rgb[0]/255,t=this.rgb[1]/255,n=this.rgb[2]/255,r=this.alpha,i=Math.max(e,t,n),s=Math.min(e,t,n),o,u,a=(i+s)/2,f=i-s;if(i===s)o=u=0;else{u=a>.5?f/(2-i-s):f/(i+s);switch(i){case e:o=(t-n)/f+(t255?255:e<0?0:e).toString(16),e.length===1?"0"+e:e}).join("")},compare:function(e){return e.rgb?e.rgb[0]===this.rgb[0]&&e.rgb[1]===this.rgb[1]&&e.rgb[2]===this.rgb[2]&&e.alpha===this.alpha?0:-1:-1}}}(n("../tree")),function(e){e.Comment=function(e,t){this.value=e,this.silent=!!t},e.Comment.prototype={type:"Comment",toCSS:function(e){return e.compress?"":this.value},eval:function(){return this}}}(n("../tree")),function(e){e.Condition=function(e,t,n,r,i){this.op=e.trim(),this.lvalue=t,this.rvalue=n,this.index=r,this.negate=i},e.Condition.prototype={type:"Condition",accept:function(e){this.lvalue=e.visit(this.lvalue),this.rvalue=e.visit(this.rvalue)},eval:function(e){var t=this.lvalue.eval(e),n=this.rvalue.eval(e),r=this.index,i,i=function(e){switch(e){case"and":return t&&n;case"or":return t||n;default:if(t.compare)i=t.compare(n);else{if(!n.compare)throw{type:"Type",message:"Unable to perform comparison",index:r};i=n.compare(t)}switch(i){case-1:return e==="<"||e==="=<";case 0:return e==="="||e===">="||e==="=<";case 1:return e===">"||e===">="}}}(this.op);return this.negate?!i:i}}}(n("../tree")),function(e){e.Dimension=function(n,r){this.value=parseFloat(n),this.unit=r&&r instanceof e.Unit?r:new e.Unit(r?[r]:t)},e.Dimension.prototype={type:"Dimension",accept:function(e){this.unit=e.visit(this.unit)},eval:function(e){return this},toColor:function(){return new e.Color([this.value,this.value,this.value])},toCSS:function(e){if(e&&e.strictUnits&&!this.unit.isSingular())throw new Error("Multiple units in dimension. Correct the units or use the unit function. Bad unit: "+this.unit.toString());var t=this.value,n=String(t);t!==0&&t<1e-6&&t>-0.000001&&(n=t.toFixed(20).replace(/0+$/,""));if(e&&e.compress){if(t===0&&!this.unit.isAngle())return n;t>0&&t<1&&(n=n.substr(1))}return n+this.unit.toCSS(e)},operate:function(t,n,r){var i=e.operate(t,n,this.value,r.value),s=this.unit.clone();if(n==="+"||n==="-"){if(s.numerator.length===0&&s.denominator.length===0)s.numerator=r.unit.numerator.slice(0),s.denominator=r.unit.denominator.slice(0);else if(r.unit.numerator.length!=0||s.denominator.length!=0){r=r.convertTo(this.unit.usedUnits());if(t.strictUnits&&r.unit.toString()!==s.toString())throw new Error("Incompatible units. Change the units or use the unit function. Bad units: '"+s.toString()+"' and '"+r.unit.toString()+"'.");i=e.operate(t,n,this.value,r.value)}}else n==="*"?(s.numerator=s.numerator.concat(r.unit.numerator).sort(),s.denominator=s.denominator.concat(r.unit.denominator).sort(),s.cancel()):n==="/"&&(s.numerator=s.numerator.concat(r.unit.denominator).sort(),s.denominator=s.denominator.concat(r.unit.numerator).sort(),s.cancel());return new e.Dimension(i,s)},compare:function(t){if(t instanceof e.Dimension){var n=this.unify(),r=t.unify(),i=n.value,s=r.value;return s>i?-1:s=1?this.numerator[0]:this.denominator.length>=1?this.denominator[0]:(!e||!e.strictUnits)&&this.backupUnit?this.backupUnit:""},toString:function(){var e,t=this.numerator.join("*");for(e=0;e0)for(n=0;n":e.compress?">":" > ","|":e.compress?"|":" | "}[this.value]}}}(n("../tree")),function(e){e.Expression=function(e){this.value=e},e.Expression.prototype={type:"Expression",accept:function(e){this.value=e.visit(this.value)},eval:function(t){var n,r=this.parens&&!this.parensInOp,i=!1;return r&&t.inParenthesis(),this.value.length>1?n=new e.Expression(this.value.map(function(e){return e.eval(t)})):this.value.length===1?(this.value[0].parens&&!this.value[0].parensInOp&&(i=!0),n=this.value[0].eval(t)):n=this,r&&t.outOfParenthesis(),this.parens&&this.parensInOp&&!t.isMathOn()&&!i&&(n=new e.Paren(n)),n},toCSS:function(e){return this.value.map(function(t){return t.toCSS?t.toCSS(e):""}).join(" ")},throwAwayComments:function(){this.value=this.value.filter(function(t){return!(t instanceof e.Comment)})}}}(n("../tree")),function(e){e.Extend=function(t,n,r){this.selector=t,this.option=n,this.index=r;switch(n){case"all":this.allowBefore=!0,this.allowAfter=!0;break;default:this.allowBefore=!1,this.allowAfter=!1}},e.Extend.prototype={type:"Extend",accept:function(e){this.selector=e.visit(this.selector)},eval:function(t){return new e.Extend(this.selector.eval(t),this.option,this.index)},clone:function(t){return new e.Extend(this.selector,this.option,this.index)},findSelfSelectors:function(e){var t=[];for(d=0;d1){var r=this.emptySelectors();n=new e.Ruleset(r,t.mediaBlocks),n.multiMedia=!0}return delete t.mediaBlocks,delete t.mediaPath,n},evalNested:function(t){var n,r,i=t.mediaPath.concat([this]);for(n=0;n0;n--)t.splice(n,0,new e.Anonymous("and"));return new e.Expression(t)})),new e.Ruleset([],[])},permute:function(e){if(e.length===0)return[];if(e.length===1)return e[0];var t=[],n=this.permute(e.slice(1));for(var r=0;r0){c=!0;for(a=0;athis.params.length)return!1;if(this.required>0&&n>this.params.length)return!1}r=Math.min(n,this.arity);for(var s=0;si.selectors[o].elements.length?Array.prototype.push.apply(r,i.find(new e.Selector(t.elements.slice(1)),n)):r.push(i);break}}),this._lookups[o]=r)},toCSS:function(t){var n=[],r=[],i=[],s=[],o,u,a;for(var f=0;f0){u=e.debugInfo(t,this),o=this.paths.map(function(e){return e.map(function(e){return e.toCSS(t)}).join("").trim()}).join(t.compress?",":",\n");for(var f=r.length-1;f>=0;f--)(r[f].slice(0,2)==="/*"||i.indexOf(r[f])===-1)&&i.unshift(r[f]);r=i,n.push(u+o+(t.compress?"{":" {\n ")+r.join(t.compress?"":"\n ")+(t.compress?"}":"\n}\n"))}return n.push(s),n.join("")+(t.compress?"\n":"")},joinSelectors:function(e,t,n){for(var r=0;r0)for(i=0;i0&&this.mergeElementsOnToSelectors(g,a);for(s=0;s0&&(l[0].elements=l[0].elements.slice(0),l[0].elements.push(new e.Element(f.combinator,"",0))),y.push(l);else for(o=0;o0?(h=l.slice(0),m=h.pop(),d=new e.Selector(m.elements.slice(0),r.extendList),v=!1):d=new e.Selector([],r.extendList),c.length>1&&(p=p.concat(c.slice(1))),c.length>0&&(v=!1,d.elements.push(new e.Element(f.combinator,c[0].elements[0].value,0)),d.elements=d.elements.concat(c[0].elements.slice(1))),v||h.push(d),h=h.concat(p),y.push(h)}a=y,g=[]}}g.length>0&&this.mergeElementsOnToSelectors(g,a);for(i=0;i0&&t.push(a[i])},mergeElementsOnToSelectors:function(t,n){var r,i,s;if(n.length==0){n.push([new e.Selector(t)]);return}for(r=0;r0?i[i.length-1]=new e.Selector(i[i.length-1].elements.concat(t),i[i.length-1].extendList):i.push(new e.Selector(t))}}}(n("../tree")),function(e){e.Selector=function(e,t){this.elements=e,this.extendList=t||[]},e.Selector.prototype={type:"Selector",accept:function(e){this.elements=e.visit(this.elements),this.extendList=e.visit(this.extendList)},match:function(e){var t=this.elements,n=t.length,r,i,s,o;r=e.elements.slice(e.elements.length&&e.elements[0].value==="&"?1:0),i=r.length,s=Math.min(n,i);if(i===0||n1?"["+e.value.map(function(e){return e.toCSS(!1)}).join(", ")+"]":e.toCSS(!1)}}(n("./tree")),function(e){var t=["paths","optimization","files","contents","relativeUrls","strictImports","dumpLineNumbers","compress","processImports","mime","currentFileInfo"];e.parseEnv=function(e){r(e,this,t),this.contents||(this.contents={}),this.files||(this.files={});if(!this.currentFileInfo){var n=e.filename||"input";e.filename=null;var i=n.replace(/[^\/\\]*$/,"");this.currentFileInfo={filename:n,relativeUrls:this.relativeUrls,rootpath:e.rootpath||"",currentDirectory:i,entryPath:i,rootFilename:n}}},e.parseEnv.prototype.toSheet=function(t){var n=new e.parseEnv(this);return n.href=t,n.type=this.mime,n};var n=["silent","verbose","compress","ieCompat","strictMath","strictUnits"];e.evalEnv=function(e,t){r(e,this,n),this.frames=t||[]},e.evalEnv.prototype.inParenthesis=function(){this.parensStack||(this.parensStack=[]),this.parensStack.push(!0)},e.evalEnv.prototype.outOfParenthesis=function(){this.parensStack.pop()},e.evalEnv.prototype.isMathOn=function(){return this.strictMath?this.parensStack&&this.parensStack.length:!0},e.evalEnv.prototype.isPathRelative=function(e){return!/^(?:[a-z-]+:|\/)/.test(e)};var r=function(e,t,n){if(!e)return;for(var r=0;r100){var p="{unable to calculate}",d="{unable to calculate}";try{p=u[0].selfSelectors[0].toCSS(),d=u[0].selector.toCSS()}catch(v){}throw{message:"extend circular reference detected. One of the circular extends is currently:"+p+":extend("+d+")"}}return u.concat(f.doExtendChaining(u,n,r+1))}return u},inInheritanceChain:function(e,t){if(e===t)return!0;if(t.parents){if(this.inInheritanceChain(e,t.parents[0]))return!0;if(this.inInheritanceChain(e,t.parents[1]))return!0}return!1},visitRule:function(e,t){t.visitDeeper=!1},visitMixinDefinition:function(e,t){t.visitDeeper=!1},visitSelector:function(e,t){t.visitDeeper=!1},visitRuleset:function(e,t){if(e.root)return;var n,r,i,s=this.allExtendsStack[this.allExtendsStack.length-1],o=[],u=this;for(i=0;i0&&f[c.matched].combinator.value!==o?c=null:c.matched++,c&&(c.finished=c.matched===f.length,c.finished&&!e.allowAfter&&(i+1i&&s>0&&(o[o.length-1].elements=o[o.length-1].elements.concat(n[i].elements.slice(s)),s=0,i++),o=o.concat(n.slice(i,match.pathIndex)),o.push(new e.Selector(a.elements.slice(s,match.index).concat([f]).concat(r.elements.slice(1)))),i=match.endPathIndex,s=match.endPathElementIndex,s>=a.elements.length&&(s=0,i++);return i0&&(o[o.length-1].elements=o[o.length-1].elements.concat(n[i].elements.slice(s)),s=0,i++),o=o.concat(n.slice(i,n.length)),o},visitRulesetOut:function(e){},visitMedia:function(e,t){var n=e.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length-1]);n=n.concat(this.doExtendChaining(n,e.allExtends)),this.allExtendsStack.push(n)},visitMediaOut:function(e){this.allExtendsStack.length=this.allExtendsStack.length-1},visitDirective:function(e,t){var n=e.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length-1]);n=n.concat(this.doExtendChaining(n,e.allExtends)),this.allExtendsStack.push(n)},visitDirectiveOut:function(e){this.allExtendsStack.length=this.allExtendsStack.length-1}}}(n("./tree"));var o=/^(file|chrome(-extension)?|resource|qrc|app):/.test(location.protocol);r.env=r.env||(location.hostname=="127.0.0.1"||location.hostname=="0.0.0.0"||location.hostname=="localhost"||location.port.length>0||o?"development":"production"),r.async=r.async||!1,r.fileAsync=r.fileAsync||!1,r.poll=r.poll||(o?1e3:1500);if(r.functions)for(var u in r.functions)r.tree.functions[u]=r.functions[u];var a=/!dumpLineNumbers:(comments|mediaquery|all)/.exec(location.hash);a&&(r.dumpLineNumbers=a[1]),r.watch=function(){return r.watchMode||(r.env="development",f()),this.watchMode=!0},r.unwatch=function(){return clearInterval(r.watchTimer),this.watchMode=!1},/!watch/.test(location.hash)&&r.watch();var l=null;if(r.env!="development")try{l=typeof e.localStorage=="undefined"?null:e.localStorage}catch(c){}var h=document.getElementsByTagName("link"),p=/^text\/(x-)?less$/;r.sheets=[];for(var d=0;d current) { chunks[j] = chunks[j].slice(i - current); current = i; } } function isWhitespace(c) { // Could change to \s? var code = c.charCodeAt(0); return code === 32 || code === 10 || code === 9; } // // Parse from a token, regexp or string, and move forward if match // function $(tok) { var match, args, length, index, k; // // Non-terminal // if (tok instanceof Function) { return tok.call(parser.parsers); // // Terminal // // Either match a single character in the input, // or match a regexp in the current chunk (chunk[j]). // } else if (typeof(tok) === 'string') { match = input.charAt(i) === tok ? tok : null; length = 1; sync (); } else { sync (); if (match = tok.exec(chunks[j])) { length = match[0].length; } else { return null; } } // The match is confirmed, add the match length to `i`, // and consume any extra white-space characters (' ' || '\n') // which come after that. The reason for this is that LeSS's // grammar is mostly white-space insensitive. // if (match) { skipWhitespace(length); if(typeof(match) === 'string') { return match; } else { return match.length === 1 ? match[0] : match; } } } function skipWhitespace(length) { var oldi = i, oldj = j, endIndex = i + chunks[j].length, mem = i += length; while (i < endIndex) { if (! isWhitespace(input.charAt(i))) { break } i++; } chunks[j] = chunks[j].slice(length + (i - mem)); current = i; if (chunks[j].length === 0 && j < chunks.length - 1) { j++ } return oldi !== i || oldj !== j; } function expect(arg, msg) { var result = $(arg); if (! result) { error(msg || (typeof(arg) === 'string' ? "expected '" + arg + "' got '" + input.charAt(i) + "'" : "unexpected token")); } else { return result; } } function error(msg, type) { var e = new Error(msg); e.index = i; e.type = type || 'Syntax'; throw e; } // Same as $(), but don't change the state of the parser, // just return the match. function peek(tok) { if (typeof(tok) === 'string') { return input.charAt(i) === tok; } else { if (tok.test(chunks[j])) { return true; } else { return false; } } } function getInput(e, env) { if (e.filename && env.currentFileInfo.filename && (e.filename !== env.currentFileInfo.filename)) { return parser.imports.contents[e.filename]; } else { return input; } } function getLocation(index, input) { for (var n = index, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } return { line: typeof(index) === 'number' ? (input.slice(0, index).match(/\n/g) || "").length : null, column: column }; } function getDebugInfo(index, inputStream, env) { var filename = env.currentFileInfo.filename; if(less.mode !== 'browser' && less.mode !== 'rhino') { filename = require('path').resolve(filename); } return { lineNumber: getLocation(index, inputStream).line + 1, fileName: filename }; } function LessError(e, env) { var input = getInput(e, env), loc = getLocation(e.index, input), line = loc.line, col = loc.column, lines = input.split('\n'); this.type = e.type || 'Syntax'; this.message = e.message; this.filename = e.filename || env.currentFileInfo.filename; this.index = e.index; this.line = typeof(line) === 'number' ? line + 1 : null; this.callLine = e.call && (getLocation(e.call, input).line + 1); this.callExtract = lines[getLocation(e.call, input).line]; this.stack = e.stack; this.column = col; this.extract = [ lines[line - 1], lines[line], lines[line + 1] ]; } LessError.prototype = new Error(); LessError.prototype.constructor = LessError; this.env = env = env || {}; // The optimization level dictates the thoroughness of the parser, // the lower the number, the less nodes it will create in the tree. // This could matter for debugging, or if you want to access // the individual nodes in the tree. this.optimization = ('optimization' in this.env) ? this.env.optimization : 1; // // The Parser // return parser = { imports: imports, // // Parse an input string into an abstract syntax tree, // call `callback` when done. // parse: function (str, callback) { var root, start, end, zone, line, lines, buff = [], c, error = null; i = j = current = furthest = 0; input = str.replace(/\r\n/g, '\n'); // Remove potential UTF Byte Order Mark input = input.replace(/^\uFEFF/, ''); // Split the input into chunks. chunks = (function (chunks) { var j = 0, skip = /(?:@\{[\w-]+\}|[^"'`\{\}\/\(\)\\])+/g, comment = /\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g, string = /"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'|`((?:[^`]|\\.)*)`/g, level = 0, match, chunk = chunks[0], inParam; for (var i = 0, c, cc; i < input.length;) { skip.lastIndex = i; if (match = skip.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); } } c = input.charAt(i); comment.lastIndex = string.lastIndex = i; if (match = string.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); continue; } } if (!inParam && c === '/') { cc = input.charAt(i + 1); if (cc === '/' || cc === '*') { if (match = comment.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); continue; } } } } switch (c) { case '{': if (! inParam) { level ++; chunk.push(c); break } case '}': if (! inParam) { level --; chunk.push(c); chunks[++j] = chunk = []; break } case '(': if (! inParam) { inParam = true; chunk.push(c); break } case ')': if ( inParam) { inParam = false; chunk.push(c); break } default: chunk.push(c); } i++; } if (level != 0) { error = new(LessError)({ index: i-1, type: 'Parse', message: (level > 0) ? "missing closing `}`" : "missing opening `{`", filename: env.currentFileInfo.filename }, env); } return chunks.map(function (c) { return c.join('') });; })([[]]); if (error) { return callback(new(LessError)(error, env)); } // Start with the primary rule. // The whole syntax tree is held under a Ruleset node, // with the `root` property set to true, so no `{}` are // output. The callback is called when the input is parsed. try { root = new(tree.Ruleset)([], $(this.parsers.primary)); root.root = true; root.firstRoot = true; } catch (e) { return callback(new(LessError)(e, env)); } root.toCSS = (function (evaluate) { var line, lines, column; return function (options, variables) { options = options || {}; var importError, evalEnv = new tree.evalEnv(options); // // Allows setting variables with a hash, so: // // `{ color: new(tree.Color)('#f01') }` will become: // // new(tree.Rule)('@color', // new(tree.Value)([ // new(tree.Expression)([ // new(tree.Color)('#f01') // ]) // ]) // ) // if (typeof(variables) === 'object' && !Array.isArray(variables)) { variables = Object.keys(variables).map(function (k) { var value = variables[k]; if (! (value instanceof tree.Value)) { if (! (value instanceof tree.Expression)) { value = new(tree.Expression)([value]); } value = new(tree.Value)([value]); } return new(tree.Rule)('@' + k, value, false, 0); }); evalEnv.frames = [new(tree.Ruleset)(null, variables)]; } try { var evaldRoot = evaluate.call(this, evalEnv); new(tree.joinSelectorVisitor)() .run(evaldRoot); new(tree.processExtendsVisitor)() .run(evaldRoot); var css = evaldRoot.toCSS({ compress: Boolean(options.compress), dumpLineNumbers: env.dumpLineNumbers, strictUnits: Boolean(options.strictUnits)}); } catch (e) { throw new(LessError)(e, env); } if (options.yuicompress && less.mode === 'node') { return require('ycssmin').cssmin(css, options.maxLineLen); } else if (options.compress) { return css.replace(/(\s)+/g, "$1"); } else { return css; } }; })(root.eval); // If `i` is smaller than the `input.length - 1`, // it means the parser wasn't able to parse the whole // string, so we've got a parsing error. // // We try to extract a \n delimited string, // showing the line where the parse error occured. // We split it up into two parts (the part which parsed, // and the part which didn't), so we can color them differently. if (i < input.length - 1) { i = furthest; lines = input.split('\n'); line = (input.slice(0, i).match(/\n/g) || "").length + 1; for (var n = i, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } error = { type: "Parse", message: "Unrecognised input", index: i, filename: env.currentFileInfo.filename, line: line, column: column, extract: [ lines[line - 2], lines[line - 1], lines[line] ] }; } var finish = function (e) { e = error || e || parser.imports.error; if (e) { if (!(e instanceof LessError)) { e = new(LessError)(e, env); } callback(e); } else { callback(null, root); } }; if (env.processImports !== false) { new tree.importVisitor(this.imports, finish) .run(root); } else { finish(); } }, // // Here in, the parsing rules/functions // // The basic structure of the syntax tree generated is as follows: // // Ruleset -> Rule -> Value -> Expression -> Entity // // Here's some LESS code: // // .class { // color: #fff; // border: 1px solid #000; // width: @w + 4px; // > .child {...} // } // // And here's what the parse tree might look like: // // Ruleset (Selector '.class', [ // Rule ("color", Value ([Expression [Color #fff]])) // Rule ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]])) // Rule ("width", Value ([Expression [Operation "+" [Variable "@w"][Dimension 4px]]])) // Ruleset (Selector [Element '>', '.child'], [...]) // ]) // // In general, most rules will try to parse a token with the `$()` function, and if the return // value is truly, will return a new node, of the relevant type. Sometimes, we need to check // first, before parsing, that's when we use `peek()`. // parsers: { // // The `primary` rule is the *entry* and *exit* point of the parser. // The rules here can appear at any level of the parse tree. // // The recursive nature of the grammar is an interplay between the `block` // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule, // as represented by this simplified grammar: // // primary → (ruleset | rule)+ // ruleset → selector+ block // block → '{' primary '}' // // Only at one point is the primary rule not called from the // block rule: at the root level. // primary: function () { var node, root = []; while ((node = $(this.extendRule) || $(this.mixin.definition) || $(this.rule) || $(this.ruleset) || $(this.mixin.call) || $(this.comment) || $(this.directive)) || $(/^[\s\n]+/) || $(/^;+/)) { node && root.push(node); } return root; }, // We create a Comment node for CSS comments `/* */`, // but keep the LeSS comments `//` silent, by just skipping // over them. comment: function () { var comment; if (input.charAt(i) !== '/') return; if (input.charAt(i + 1) === '/') { return new(tree.Comment)($(/^\/\/.*/), true); } else if (comment = $(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/)) { return new(tree.Comment)(comment); } }, // // Entities are tokens which can be found inside an Expression // entities: { // // A string, which supports escaping " and ' // // "milky way" 'he\'s the one!' // quoted: function () { var str, j = i, e, index = i; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '"' && input.charAt(j) !== "'") return; e && $('~'); if (str = $(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/)) { return new(tree.Quoted)(str[0], str[1] || str[2], e, index, env.currentFileInfo); } }, // // A catch-all word, such as: // // black border-collapse // keyword: function () { var k; if (k = $(/^[_A-Za-z-][_A-Za-z0-9-]*/)) { if (tree.colors.hasOwnProperty(k)) { // detect named color return new(tree.Color)(tree.colors[k].slice(1)); } else { return new(tree.Keyword)(k); } } }, // // A function call // // rgb(255, 0, 255) // // We also try to catch IE's `alpha()`, but let the `alpha` parser // deal with the details. // // The arguments are parsed with the `entities.arguments` parser. // call: function () { var name, nameLC, args, alpha_ret, index = i; if (! (name = /^([\w-]+|%|progid:[\w\.]+)\(/.exec(chunks[j]))) return; name = name[1]; nameLC = name.toLowerCase(); if (nameLC === 'url') { return null } else { i += name.length } if (nameLC === 'alpha') { alpha_ret = $(this.alpha); if(typeof alpha_ret !== 'undefined') { return alpha_ret; } } $('('); // Parse the '(' and consume whitespace. args = $(this.entities.arguments); if (! $(')')) { return; } if (name) { return new(tree.Call)(name, args, index, env.currentFileInfo); } }, arguments: function () { var args = [], arg; while (arg = $(this.entities.assignment) || $(this.expression)) { args.push(arg); if (! $(',')) { break } } return args; }, literal: function () { return $(this.entities.dimension) || $(this.entities.color) || $(this.entities.quoted) || $(this.entities.unicodeDescriptor); }, // Assignments are argument entities for calls. // They are present in ie filter properties as shown below. // // filter: progid:DXImageTransform.Microsoft.Alpha( *opacity=50* ) // assignment: function () { var key, value; if ((key = $(/^\w+(?=\s?=)/i)) && $('=') && (value = $(this.entity))) { return new(tree.Assignment)(key, value); } }, // // Parse url() tokens // // We use a specific rule for urls, because they don't really behave like // standard function calls. The difference is that the argument doesn't have // to be enclosed within a string, so it can't be parsed as an Expression. // url: function () { var value; if (input.charAt(i) !== 'u' || !$(/^url\(/)) return; value = $(this.entities.quoted) || $(this.entities.variable) || $(/^(?:(?:\\[\(\)'"])|[^\(\)'"])+/) || ""; expect(')'); return new(tree.URL)((value.value != null || value instanceof tree.Variable) ? value : new(tree.Anonymous)(value), env.currentFileInfo); }, // // A Variable entity, such as `@fink`, in // // width: @fink + 2px // // We use a different parser for variable definitions, // see `parsers.variable`. // variable: function () { var name, index = i; if (input.charAt(i) === '@' && (name = $(/^@@?[\w-]+/))) { return new(tree.Variable)(name, index, env.currentFileInfo); } }, // A variable entity useing the protective {} e.g. @{var} variableCurly: function () { var name, curly, index = i; if (input.charAt(i) === '@' && (curly = $(/^@\{([\w-]+)\}/))) { return new(tree.Variable)("@" + curly[1], index, env.currentFileInfo); } }, // // A Hexadecimal color // // #4F3C2F // // `rgb` and `hsl` colors are parsed through the `entities.call` parser. // color: function () { var rgb; if (input.charAt(i) === '#' && (rgb = $(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/))) { return new(tree.Color)(rgb[1]); } }, // // A Dimension, that is, a number and a unit // // 0.5em 95% // dimension: function () { var value, c = input.charCodeAt(i); //Is the first char of the dimension 0-9, '.', '+' or '-' if ((c > 57 || c < 43) || c === 47 || c == 44) return; if (value = $(/^([+-]?\d*\.?\d+)(%|[a-z]+)?/)) { return new(tree.Dimension)(value[1], value[2]); } }, // // A unicode descriptor, as is used in unicode-range // // U+0?? or U+00A1-00A9 // unicodeDescriptor: function () { var ud; if (ud = $(/^U\+[0-9a-fA-F?]+(\-[0-9a-fA-F?]+)?/)) { return new(tree.UnicodeDescriptor)(ud[0]); } }, // // JavaScript code to be evaluated // // `window.location.href` // javascript: function () { var str, j = i, e; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '`') { return } e && $('~'); if (str = $(/^`([^`]*)`/)) { return new(tree.JavaScript)(str[1], i, e); } } }, // // The variable part of a variable definition. Used in the `rule` parser // // @fink: // variable: function () { var name; if (input.charAt(i) === '@' && (name = $(/^(@[\w-]+)\s*:/))) { return name[1] } }, // // extend syntax - used to extend selectors // extend: function(isRule) { var elements, e, index = i, option, extendList = []; if (!$(isRule ? /^&:extend\(/ : /^:extend\(/)) { return; } do { option = null; elements = []; while (true) { option = $(/^(all)(?=\s*(\)|,))/); if (option) { break; } e = $(this.element); if (!e) { break; } elements.push(e); } option = option && option[1]; extendList.push(new(tree.Extend)(new(tree.Selector)(elements), option, index)); } while($(",")) expect(/^\)/); if (isRule) { expect(/^;/); } return extendList; }, // // extendRule - used in a rule to extend all the parent selectors // extendRule: function() { return this.extend(true); }, // // Mixins // mixin: { // // A Mixin call, with an optional argument list // // #mixins > .square(#fff); // .rounded(4px, black); // .button; // // The `while` loop is there because mixins can be // namespaced, but we only support the child and descendant // selector for now. // call: function () { var elements = [], e, c, args, delim, arg, index = i, s = input.charAt(i), important = false; if (s !== '.' && s !== '#') { return } save(); // stop us absorbing part of an invalid selector while (e = $(/^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/)) { elements.push(new(tree.Element)(c, e, i)); c = $('>'); } if ($('(')) { args = this.mixin.args.call(this, true).args; expect(')'); } args = args || []; if ($(this.important)) { important = true; } if (elements.length > 0 && ($(';') || peek('}'))) { return new(tree.mixin.Call)(elements, args, index, env.currentFileInfo, important); } restore(); }, args: function (isCall) { var expressions = [], argsSemiColon = [], isSemiColonSeperated, argsComma = [], expressionContainsNamed, name, nameLoop, value, arg, returner = {args:null, variadic: false}; while (true) { if (isCall) { arg = $(this.expression); } else { $(this.comment); if (input.charAt(i) === '.' && $(/^\.{3}/)) { returner.variadic = true; if ($(";") && !isSemiColonSeperated) { isSemiColonSeperated = true; } (isSemiColonSeperated ? argsSemiColon : argsComma) .push({ variadic: true }); break; } arg = $(this.entities.variable) || $(this.entities.literal) || $(this.entities.keyword); } if (!arg) { break; } nameLoop = null; if (arg.throwAwayComments) { arg.throwAwayComments(); } value = arg; var val = null; if (isCall) { // Variable if (arg.value.length == 1) { var val = arg.value[0]; } } else { val = arg; } if (val && val instanceof tree.Variable) { if ($(':')) { if (expressions.length > 0) { if (isSemiColonSeperated) { error("Cannot mix ; and , as delimiter types"); } expressionContainsNamed = true; } value = expect(this.expression); nameLoop = (name = val.name); } else if (!isCall && $(/^\.{3}/)) { returner.variadic = true; if ($(";") && !isSemiColonSeperated) { isSemiColonSeperated = true; } (isSemiColonSeperated ? argsSemiColon : argsComma) .push({ name: arg.name, variadic: true }); break; } else if (!isCall) { name = nameLoop = val.name; value = null; } } if (value) { expressions.push(value); } argsComma.push({ name:nameLoop, value:value }); if ($(',')) { continue; } if ($(';') || isSemiColonSeperated) { if (expressionContainsNamed) { error("Cannot mix ; and , as delimiter types"); } isSemiColonSeperated = true; if (expressions.length > 1) { value = new (tree.Value)(expressions); } argsSemiColon.push({ name:name, value:value }); name = null; expressions = []; expressionContainsNamed = false; } } returner.args = isSemiColonSeperated ? argsSemiColon : argsComma; return returner; }, // // A Mixin definition, with a list of parameters // // .rounded (@radius: 2px, @color) { // ... // } // // Until we have a finer grained state-machine, we have to // do a look-ahead, to make sure we don't have a mixin call. // See the `rule` function for more information. // // We start by matching `.rounded (`, and then proceed on to // the argument list, which has optional default values. // We store the parameters in `params`, with a `value` key, // if there is a value, such as in the case of `@radius`. // // Once we've got our params list, and a closing `)`, we parse // the `{...}` block. // definition: function () { var name, params = [], match, ruleset, param, value, cond, variadic = false; if ((input.charAt(i) !== '.' && input.charAt(i) !== '#') || peek(/^[^{]*\}/)) return; save(); if (match = $(/^([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/)) { name = match[1]; var argInfo = this.mixin.args.call(this, false); params = argInfo.args; variadic = argInfo.variadic; // .mixincall("@{a}"); // looks a bit like a mixin definition.. so we have to be nice and restore if (!$(')')) { furthest = i; restore(); } $(this.comment); if ($(/^when/)) { // Guard cond = expect(this.conditions, 'expected condition'); } ruleset = $(this.block); if (ruleset) { return new(tree.mixin.Definition)(name, params, ruleset, cond, variadic); } else { restore(); } } } }, // // Entities are the smallest recognized token, // and can be found inside a rule's value. // entity: function () { return $(this.entities.literal) || $(this.entities.variable) || $(this.entities.url) || $(this.entities.call) || $(this.entities.keyword) ||$(this.entities.javascript) || $(this.comment); }, // // A Rule terminator. Note that we use `peek()` to check for '}', // because the `block` rule will be expecting it, but we still need to make sure // it's there, if ';' was ommitted. // end: function () { return $(';') || peek('}'); }, // // IE's alpha function // // alpha(opacity=88) // alpha: function () { var value; if (! $(/^\(opacity=/i)) return; if (value = $(/^\d+/) || $(this.entities.variable)) { expect(')'); return new(tree.Alpha)(value); } }, // // A Selector Element // // div // + h1 // #socks // input[type="text"] // // Elements are the building blocks for Selectors, // they are made out of a `Combinator` (see combinator rule), // and an element name, such as a tag a class, or `*`. // element: function () { var e, t, c, v; c = $(this.combinator); e = $(/^(?:\d+\.\d+|\d+)%/) || $(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/) || $('*') || $('&') || $(this.attribute) || $(/^\([^()@]+\)/) || $(/^[\.#](?=@)/) || $(this.entities.variableCurly); if (! e) { if ($('(')) { if ((v = ($(this.selector))) && $(')')) { e = new(tree.Paren)(v); } } } if (e) { return new(tree.Element)(c, e, i) } }, // // Combinators combine elements together, in a Selector. // // Because our parser isn't white-space sensitive, special care // has to be taken, when parsing the descendant combinator, ` `, // as it's an empty space. We have to check the previous character // in the input, to see if it's a ` ` character. More info on how // we deal with this in *combinator.js*. // combinator: function () { var c = input.charAt(i); if (c === '>' || c === '+' || c === '~' || c === '|') { i++; while (input.charAt(i).match(/\s/)) { i++ } return new(tree.Combinator)(c); } else if (input.charAt(i - 1).match(/\s/)) { return new(tree.Combinator)(" "); } else { return new(tree.Combinator)(null); } }, // // A CSS Selector // // .class > div + h1 // li a:hover // // Selectors are made out of one or more Elements, see above. // selector: function () { var sel, e, elements = [], c, extend, extendList = []; while ((extend = $(this.extend)) || (e = $(this.element))) { if (extend) { extendList.push.apply(extendList, extend); } else { if (extendList.length) { error("Extend can only be used at the end of selector"); } c = input.charAt(i); elements.push(e) e = null; } if (c === '{' || c === '}' || c === ';' || c === ',' || c === ')') { break } } if (elements.length > 0) { return new(tree.Selector)(elements, extendList); } if (extendList.length) { error("Extend must be used to extend a selector, it cannot be used on its own"); } }, attribute: function () { var attr = '', key, val, op; if (! $('[')) return; if (!(key = $(this.entities.variableCurly))) { key = expect(/^(?:[_A-Za-z0-9-\*]*\|)?(?:[_A-Za-z0-9-]|\\.)+/); } if ((op = $(/^[|~*$^]?=/))) { val = $(this.entities.quoted) || $(/^[\w-]+/) || $(this.entities.variableCurly); } expect(']'); return new(tree.Attribute)(key, op, val); }, // // The `block` rule is used by `ruleset` and `mixin.definition`. // It's a wrapper around the `primary` rule, with added `{}`. // block: function () { var content; if ($('{') && (content = $(this.primary)) && $('}')) { return content; } }, // // div, .class, body > p {...} // ruleset: function () { var selectors = [], s, rules, debugInfo; save(); if (env.dumpLineNumbers) debugInfo = getDebugInfo(i, input, env); while (s = $(this.selector)) { selectors.push(s); $(this.comment); if (! $(',')) { break } $(this.comment); } if (selectors.length > 0 && (rules = $(this.block))) { var ruleset = new(tree.Ruleset)(selectors, rules, env.strictImports); if (env.dumpLineNumbers) ruleset.debugInfo = debugInfo; return ruleset; } else { // Backtrack furthest = i; restore(); } }, rule: function (tryAnonymous) { var name, value, c = input.charAt(i), important; save(); if (c === '.' || c === '#' || c === '&') { return } if (name = $(this.variable) || $(this.property)) { // prefer to try to parse first if its a variable or we are compressing // but always fallback on the other one value = !tryAnonymous && (env.compress || (name.charAt(0) === '@')) ? ($(this.value) || $(this.anonymousValue)) : ($(this.anonymousValue) || $(this.value)); important = $(this.important); if (value && $(this.end)) { return new(tree.Rule)(name, value, important, memo, env.currentFileInfo); } else { furthest = i; restore(); if (value && !tryAnonymous) { return this.rule(true); } } } }, anonymousValue: function () { var match; if (match = /^([^@+\/'"*`(;{}-]*);/.exec(chunks[j])) { i += match[0].length - 1; return new(tree.Anonymous)(match[1]); } }, // // An @import directive // // @import "lib"; // // Depending on our environemnt, importing is done differently: // In the browser, it's an XHR request, in Node, it would be a // file-system operation. The function used for importing is // stored in `import`, which we pass to the Import constructor. // "import": function () { var path, features, index = i; save(); var dir = $(/^@import?\s+/); var options = (dir ? $(this.importOptions) : null) || {}; if (dir && (path = $(this.entities.quoted) || $(this.entities.url))) { features = $(this.mediaFeatures); if ($(';')) { features = features && new(tree.Value)(features); return new(tree.Import)(path, features, options, index, env.currentFileInfo); } } restore(); }, importOptions: function() { var o, options = {}, optionName, value; // list of options, surrounded by parens if (! $('(')) { return null; } do { if (o = $(this.importOption)) { optionName = o; value = true; switch(optionName) { case "css": optionName = "less"; value = false; break; case "once": optionName = "multiple"; value = false; break; } options[optionName] = value; if (! $(',')) { break } } } while (o); expect(')'); return options; }, importOption: function() { var opt = $(/^(less|css|multiple|once)/); if (opt) { return opt[1]; } }, mediaFeature: function () { var e, p, nodes = []; do { if (e = $(this.entities.keyword)) { nodes.push(e); } else if ($('(')) { p = $(this.property); e = $(this.value); if ($(')')) { if (p && e) { nodes.push(new(tree.Paren)(new(tree.Rule)(p, e, null, i, env.currentFileInfo, true))); } else if (e) { nodes.push(new(tree.Paren)(e)); } else { return null; } } else { return null } } } while (e); if (nodes.length > 0) { return new(tree.Expression)(nodes); } }, mediaFeatures: function () { var e, features = []; do { if (e = $(this.mediaFeature)) { features.push(e); if (! $(',')) { break } } else if (e = $(this.entities.variable)) { features.push(e); if (! $(',')) { break } } } while (e); return features.length > 0 ? features : null; }, media: function () { var features, rules, media, debugInfo; if (env.dumpLineNumbers) debugInfo = getDebugInfo(i, input, env); if ($(/^@media/)) { features = $(this.mediaFeatures); if (rules = $(this.block)) { media = new(tree.Media)(rules, features); if(env.dumpLineNumbers) media.debugInfo = debugInfo; return media; } } }, // // A CSS Directive // // @charset "utf-8"; // directive: function () { var name, value, rules, identifier, e, nodes, nonVendorSpecificName, hasBlock, hasIdentifier, hasExpression; if (input.charAt(i) !== '@') return; if (value = $(this['import']) || $(this.media)) { return value; } save(); name = $(/^@[a-z-]+/); if (!name) return; nonVendorSpecificName = name; if (name.charAt(1) == '-' && name.indexOf('-', 2) > 0) { nonVendorSpecificName = "@" + name.slice(name.indexOf('-', 2) + 1); } switch(nonVendorSpecificName) { case "@font-face": hasBlock = true; break; case "@viewport": case "@top-left": case "@top-left-corner": case "@top-center": case "@top-right": case "@top-right-corner": case "@bottom-left": case "@bottom-left-corner": case "@bottom-center": case "@bottom-right": case "@bottom-right-corner": case "@left-top": case "@left-middle": case "@left-bottom": case "@right-top": case "@right-middle": case "@right-bottom": hasBlock = true; break; case "@page": case "@document": case "@supports": case "@keyframes": hasBlock = true; hasIdentifier = true; break; case "@namespace": hasExpression = true; break; } if (hasIdentifier) { name += " " + ($(/^[^{]+/) || '').trim(); } if (hasBlock) { if (rules = $(this.block)) { return new(tree.Directive)(name, rules); } } else { if ((value = hasExpression ? $(this.expression) : $(this.entity)) && $(';')) { var directive = new(tree.Directive)(name, value); if (env.dumpLineNumbers) { directive.debugInfo = getDebugInfo(i, input, env); } return directive; } } restore(); }, // // A Value is a comma-delimited list of Expressions // // font-family: Baskerville, Georgia, serif; // // In a Rule, a Value represents everything after the `:`, // and before the `;`. // value: function () { var e, expressions = [], important; while (e = $(this.expression)) { expressions.push(e); if (! $(',')) { break } } if (expressions.length > 0) { return new(tree.Value)(expressions); } }, important: function () { if (input.charAt(i) === '!') { return $(/^! *important/); } }, sub: function () { var a, e; if ($('(')) { if (a = $(this.addition)) { e = new(tree.Expression)([a]); expect(')'); e.parens = true; return e; } } }, multiplication: function () { var m, a, op, operation, isSpaced, expression = []; if (m = $(this.operand)) { isSpaced = isWhitespace(input.charAt(i - 1)); while (!peek(/^\/[*\/]/) && (op = ($('/') || $('*')))) { if (a = $(this.operand)) { m.parensInOp = true; a.parensInOp = true; operation = new(tree.Operation)(op, [operation || m, a], isSpaced); isSpaced = isWhitespace(input.charAt(i - 1)); } else { break; } } return operation || m; } }, addition: function () { var m, a, op, operation, isSpaced; if (m = $(this.multiplication)) { isSpaced = isWhitespace(input.charAt(i - 1)); while ((op = $(/^[-+]\s+/) || (!isSpaced && ($('+') || $('-')))) && (a = $(this.multiplication))) { m.parensInOp = true; a.parensInOp = true; operation = new(tree.Operation)(op, [operation || m, a], isSpaced); isSpaced = isWhitespace(input.charAt(i - 1)); } return operation || m; } }, conditions: function () { var a, b, index = i, condition; if (a = $(this.condition)) { while ($(',') && (b = $(this.condition))) { condition = new(tree.Condition)('or', condition || a, b, index); } return condition || a; } }, condition: function () { var a, b, c, op, index = i, negate = false; if ($(/^not/)) { negate = true } expect('('); if (a = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) { if (op = $(/^(?:>=|=<|[<=>])/)) { if (b = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) { c = new(tree.Condition)(op, a, b, index, negate); } else { error('expected expression'); } } else { c = new(tree.Condition)('=', a, new(tree.Keyword)('true'), index, negate); } expect(')'); return $(/^and/) ? new(tree.Condition)('and', c, $(this.condition)) : c; } }, // // An operand is anything that can be part of an operation, // such as a Color, or a Variable // operand: function () { var negate, p = input.charAt(i + 1); if (input.charAt(i) === '-' && (p === '@' || p === '(')) { negate = $('-') } var o = $(this.sub) || $(this.entities.dimension) || $(this.entities.color) || $(this.entities.variable) || $(this.entities.call); if (negate) { o.parensInOp = true; o = new(tree.Negative)(o); } return o; }, // // Expressions either represent mathematical operations, // or white-space delimited Entities. // // 1px solid black // @var * 2 // expression: function () { var e, delim, entities = [], d; while (e = $(this.addition) || $(this.entity)) { entities.push(e); // operations do not allow keyword "/" dimension (e.g. small/20px) so we support that here if (!peek(/^\/[\/*]/) && (delim = $('/'))) { entities.push(new(tree.Anonymous)(delim)); } } if (entities.length > 0) { return new(tree.Expression)(entities); } }, property: function () { var name; if (name = $(/^(\*?-?[_a-z0-9-]+)\s*:/)) { return name[1]; } } } }; }; if (less.mode === 'browser' || less.mode === 'rhino') { // // Used by `@import` directives // less.Parser.importer = function (path, currentFileInfo, callback, env) { if (!/^([a-z-]+:)?\//.test(path) && currentFileInfo.currentDirectory) { path = currentFileInfo.currentDirectory + path; } var sheetEnv = env.toSheet(path); sheetEnv.processImports = false; sheetEnv.currentFileInfo = currentFileInfo; // We pass `true` as 3rd argument, to force the reload of the import. // This is so we can get the syntax tree as opposed to just the CSS output, // as we need this to evaluate the current stylesheet. loadStyleSheet(sheetEnv, function (e, root, data, sheet, _, path) { callback.call(null, e, root, path); }, true); }; } (function (tree) { tree.functions = { rgb: function (r, g, b) { return this.rgba(r, g, b, 1.0); }, rgba: function (r, g, b, a) { var rgb = [r, g, b].map(function (c) { return scaled(c, 256); }); a = number(a); return new(tree.Color)(rgb, a); }, hsl: function (h, s, l) { return this.hsla(h, s, l, 1.0); }, hsla: function (h, s, l, a) { h = (number(h) % 360) / 360; s = clamp(number(s)); l = clamp(number(l)); a = clamp(number(a)); var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s; var m1 = l * 2 - m2; return this.rgba(hue(h + 1/3) * 255, hue(h) * 255, hue(h - 1/3) * 255, a); function hue(h) { h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h); if (h * 6 < 1) return m1 + (m2 - m1) * h * 6; else if (h * 2 < 1) return m2; else if (h * 3 < 2) return m1 + (m2 - m1) * (2/3 - h) * 6; else return m1; } }, hsv: function(h, s, v) { return this.hsva(h, s, v, 1.0); }, hsva: function(h, s, v, a) { h = ((number(h) % 360) / 360) * 360; s = number(s); v = number(v); a = number(a); var i, f; i = Math.floor((h / 60) % 6); f = (h / 60) - i; var vs = [v, v * (1 - s), v * (1 - f * s), v * (1 - (1 - f) * s)]; var perm = [[0, 3, 1], [2, 0, 1], [1, 0, 3], [1, 2, 0], [3, 1, 0], [0, 1, 2]]; return this.rgba(vs[perm[i][0]] * 255, vs[perm[i][1]] * 255, vs[perm[i][2]] * 255, a); }, hue: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().h)); }, saturation: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().s * 100), '%'); }, lightness: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().l * 100), '%'); }, hsvhue: function(color) { return new(tree.Dimension)(Math.round(color.toHSV().h)); }, hsvsaturation: function (color) { return new(tree.Dimension)(Math.round(color.toHSV().s * 100), '%'); }, hsvvalue: function (color) { return new(tree.Dimension)(Math.round(color.toHSV().v * 100), '%'); }, red: function (color) { return new(tree.Dimension)(color.rgb[0]); }, green: function (color) { return new(tree.Dimension)(color.rgb[1]); }, blue: function (color) { return new(tree.Dimension)(color.rgb[2]); }, alpha: function (color) { return new(tree.Dimension)(color.toHSL().a); }, luma: function (color) { return new(tree.Dimension)(Math.round(color.luma() * color.alpha * 100), '%'); }, saturate: function (color, amount) { var hsl = color.toHSL(); hsl.s += amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, desaturate: function (color, amount) { var hsl = color.toHSL(); hsl.s -= amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, lighten: function (color, amount) { var hsl = color.toHSL(); hsl.l += amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, darken: function (color, amount) { var hsl = color.toHSL(); hsl.l -= amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, fadein: function (color, amount) { var hsl = color.toHSL(); hsl.a += amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, fadeout: function (color, amount) { var hsl = color.toHSL(); hsl.a -= amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, fade: function (color, amount) { var hsl = color.toHSL(); hsl.a = amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, spin: function (color, amount) { var hsl = color.toHSL(); var hue = (hsl.h + amount.value) % 360; hsl.h = hue < 0 ? 360 + hue : hue; return hsla(hsl); }, // // Copyright (c) 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein // http://sass-lang.com // mix: function (color1, color2, weight) { if (!weight) { weight = new(tree.Dimension)(50); } var p = weight.value / 100.0; var w = p * 2 - 1; var a = color1.toHSL().a - color2.toHSL().a; var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0; var w2 = 1 - w1; var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2, color1.rgb[1] * w1 + color2.rgb[1] * w2, color1.rgb[2] * w1 + color2.rgb[2] * w2]; var alpha = color1.alpha * p + color2.alpha * (1 - p); return new(tree.Color)(rgb, alpha); }, greyscale: function (color) { return this.desaturate(color, new(tree.Dimension)(100)); }, contrast: function (color, dark, light, threshold) { // filter: contrast(3.2); // should be kept as is, so check for color if (!color.rgb) { return null; } if (typeof light === 'undefined') { light = this.rgba(255, 255, 255, 1.0); } if (typeof dark === 'undefined') { dark = this.rgba(0, 0, 0, 1.0); } //Figure out which is actually light and dark! if (dark.luma() > light.luma()) { var t = light; light = dark; dark = t; } if (typeof threshold === 'undefined') { threshold = 0.43; } else { threshold = number(threshold); } if ((color.luma() * color.alpha) < threshold) { return light; } else { return dark; } }, e: function (str) { return new(tree.Anonymous)(str instanceof tree.JavaScript ? str.evaluated : str); }, escape: function (str) { return new(tree.Anonymous)(encodeURI(str.value).replace(/=/g, "%3D").replace(/:/g, "%3A").replace(/#/g, "%23").replace(/;/g, "%3B").replace(/\(/g, "%28").replace(/\)/g, "%29")); }, '%': function (quoted /* arg, arg, ...*/) { var args = Array.prototype.slice.call(arguments, 1), str = quoted.value; for (var i = 0; i < args.length; i++) { str = str.replace(/%[sda]/i, function(token) { var value = token.match(/s/i) ? args[i].value : args[i].toCSS(); return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value; }); } str = str.replace(/%%/g, '%'); return new(tree.Quoted)('"' + str + '"', str); }, unit: function (val, unit) { return new(tree.Dimension)(val.value, unit ? unit.toCSS() : ""); }, convert: function (val, unit) { return val.convertTo(unit.value); }, round: function (n, f) { var fraction = typeof(f) === "undefined" ? 0 : f.value; return this._math(function(num) { return num.toFixed(fraction); }, null, n); }, pi: function () { return new(tree.Dimension)(Math.PI); }, mod: function(a, b) { return new(tree.Dimension)(a.value % b.value, a.unit); }, pow: function(x, y) { if (typeof x === "number" && typeof y === "number") { x = new(tree.Dimension)(x); y = new(tree.Dimension)(y); } else if (!(x instanceof tree.Dimension) || !(y instanceof tree.Dimension)) { throw { type: "Argument", message: "arguments must be numbers" }; } return new(tree.Dimension)(Math.pow(x.value, y.value), x.unit); }, _math: function (fn, unit, n) { if (n instanceof tree.Dimension) { return new(tree.Dimension)(fn(parseFloat(n.value)), unit == null ? n.unit : unit); } else if (typeof(n) === 'number') { return fn(n); } else { throw { type: "Argument", message: "argument must be a number" }; } }, argb: function (color) { return new(tree.Anonymous)(color.toARGB()); }, percentage: function (n) { return new(tree.Dimension)(n.value * 100, '%'); }, color: function (n) { if (n instanceof tree.Quoted) { return new(tree.Color)(n.value.slice(1)); } else { throw { type: "Argument", message: "argument must be a string" }; } }, iscolor: function (n) { return this._isa(n, tree.Color); }, isnumber: function (n) { return this._isa(n, tree.Dimension); }, isstring: function (n) { return this._isa(n, tree.Quoted); }, iskeyword: function (n) { return this._isa(n, tree.Keyword); }, isurl: function (n) { return this._isa(n, tree.URL); }, ispixel: function (n) { return this.isunit(n, 'px'); }, ispercentage: function (n) { return this.isunit(n, '%'); }, isem: function (n) { return this.isunit(n, 'em'); }, isunit: function (n, unit) { return (n instanceof tree.Dimension) && n.unit.is(unit.value || unit) ? tree.True : tree.False; }, _isa: function (n, Type) { return (n instanceof Type) ? tree.True : tree.False; }, /* Blending modes */ multiply: function(color1, color2) { var r = color1.rgb[0] * color2.rgb[0] / 255; var g = color1.rgb[1] * color2.rgb[1] / 255; var b = color1.rgb[2] * color2.rgb[2] / 255; return this.rgb(r, g, b); }, screen: function(color1, color2) { var r = 255 - (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255; var g = 255 - (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255; var b = 255 - (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255; return this.rgb(r, g, b); }, overlay: function(color1, color2) { var r = color1.rgb[0] < 128 ? 2 * color1.rgb[0] * color2.rgb[0] / 255 : 255 - 2 * (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255; var g = color1.rgb[1] < 128 ? 2 * color1.rgb[1] * color2.rgb[1] / 255 : 255 - 2 * (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255; var b = color1.rgb[2] < 128 ? 2 * color1.rgb[2] * color2.rgb[2] / 255 : 255 - 2 * (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255; return this.rgb(r, g, b); }, softlight: function(color1, color2) { var t = color2.rgb[0] * color1.rgb[0] / 255; var r = t + color1.rgb[0] * (255 - (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255 - t) / 255; t = color2.rgb[1] * color1.rgb[1] / 255; var g = t + color1.rgb[1] * (255 - (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255 - t) / 255; t = color2.rgb[2] * color1.rgb[2] / 255; var b = t + color1.rgb[2] * (255 - (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255 - t) / 255; return this.rgb(r, g, b); }, hardlight: function(color1, color2) { var r = color2.rgb[0] < 128 ? 2 * color2.rgb[0] * color1.rgb[0] / 255 : 255 - 2 * (255 - color2.rgb[0]) * (255 - color1.rgb[0]) / 255; var g = color2.rgb[1] < 128 ? 2 * color2.rgb[1] * color1.rgb[1] / 255 : 255 - 2 * (255 - color2.rgb[1]) * (255 - color1.rgb[1]) / 255; var b = color2.rgb[2] < 128 ? 2 * color2.rgb[2] * color1.rgb[2] / 255 : 255 - 2 * (255 - color2.rgb[2]) * (255 - color1.rgb[2]) / 255; return this.rgb(r, g, b); }, difference: function(color1, color2) { var r = Math.abs(color1.rgb[0] - color2.rgb[0]); var g = Math.abs(color1.rgb[1] - color2.rgb[1]); var b = Math.abs(color1.rgb[2] - color2.rgb[2]); return this.rgb(r, g, b); }, exclusion: function(color1, color2) { var r = color1.rgb[0] + color2.rgb[0] * (255 - color1.rgb[0] - color1.rgb[0]) / 255; var g = color1.rgb[1] + color2.rgb[1] * (255 - color1.rgb[1] - color1.rgb[1]) / 255; var b = color1.rgb[2] + color2.rgb[2] * (255 - color1.rgb[2] - color1.rgb[2]) / 255; return this.rgb(r, g, b); }, average: function(color1, color2) { var r = (color1.rgb[0] + color2.rgb[0]) / 2; var g = (color1.rgb[1] + color2.rgb[1]) / 2; var b = (color1.rgb[2] + color2.rgb[2]) / 2; return this.rgb(r, g, b); }, negation: function(color1, color2) { var r = 255 - Math.abs(255 - color2.rgb[0] - color1.rgb[0]); var g = 255 - Math.abs(255 - color2.rgb[1] - color1.rgb[1]); var b = 255 - Math.abs(255 - color2.rgb[2] - color1.rgb[2]); return this.rgb(r, g, b); }, tint: function(color, amount) { return this.mix(this.rgb(255,255,255), color, amount); }, shade: function(color, amount) { return this.mix(this.rgb(0, 0, 0), color, amount); }, extract: function(values, index) { index = index.value - 1; // (1-based index) return values.value[index]; }, "data-uri": function(mimetypeNode, filePathNode) { if (typeof window !== 'undefined') { return new tree.URL(filePathNode || mimetypeNode, this.currentFileInfo).eval(this.env); } var mimetype = mimetypeNode.value; var filePath = (filePathNode && filePathNode.value); var fs = require("fs"), path = require("path"), useBase64 = false; if (arguments.length < 2) { filePath = mimetype; } if (this.env.isPathRelative(filePath)) { if (this.currentFileInfo.relativeUrls) { filePath = path.join(this.currentFileInfo.currentDirectory, filePath); } else { filePath = path.join(this.currentFileInfo.entryPath, filePath); } } // detect the mimetype if not given if (arguments.length < 2) { var mime; try { mime = require('mime'); } catch (ex) { mime = tree._mime; } mimetype = mime.lookup(filePath); // use base 64 unless it's an ASCII or UTF-8 format var charset = mime.charsets.lookup(mimetype); useBase64 = ['US-ASCII', 'UTF-8'].indexOf(charset) < 0; if (useBase64) mimetype += ';base64'; } else { useBase64 = /;base64$/.test(mimetype) } var buf = fs.readFileSync(filePath); // IE8 cannot handle a data-uri larger than 32KB. If this is exceeded // and the --ieCompat flag is enabled, return a normal url() instead. var DATA_URI_MAX_KB = 32, fileSizeInKB = parseInt((buf.length / 1024), 10); if (fileSizeInKB >= DATA_URI_MAX_KB) { if (this.env.ieCompat !== false) { if (!this.env.silent) { console.warn("Skipped data-uri embedding of %s because its size (%dKB) exceeds IE8-safe %dKB!", filePath, fileSizeInKB, DATA_URI_MAX_KB); } return new tree.URL(filePathNode || mimetypeNode, this.currentFileInfo).eval(this.env); } else if (!this.env.silent) { // if explicitly disabled (via --no-ie-compat on CLI, or env.ieCompat === false), merely warn console.warn("WARNING: Embedding %s (%dKB) exceeds IE8's data-uri size limit of %dKB!", filePath, fileSizeInKB, DATA_URI_MAX_KB); } } buf = useBase64 ? buf.toString('base64') : encodeURIComponent(buf); var uri = "'data:" + mimetype + ',' + buf + "'"; return new(tree.URL)(new(tree.Anonymous)(uri)); } }; // these static methods are used as a fallback when the optional 'mime' dependency is missing tree._mime = { // this map is intentionally incomplete // if you want more, install 'mime' dep _types: { '.htm' : 'text/html', '.html': 'text/html', '.gif' : 'image/gif', '.jpg' : 'image/jpeg', '.jpeg': 'image/jpeg', '.png' : 'image/png' }, lookup: function (filepath) { var ext = require('path').extname(filepath), type = tree._mime._types[ext]; if (type === undefined) { throw new Error('Optional dependency "mime" is required for ' + ext); } return type; }, charsets: { lookup: function (type) { // assumes all text types are UTF-8 return type && (/^text\//).test(type) ? 'UTF-8' : ''; } } }; var mathFunctions = [{name:"ceil"}, {name:"floor"}, {name: "sqrt"}, {name:"abs"}, {name:"tan", unit: ""}, {name:"sin", unit: ""}, {name:"cos", unit: ""}, {name:"atan", unit: "rad"}, {name:"asin", unit: "rad"}, {name:"acos", unit: "rad"}], createMathFunction = function(name, unit) { return function(n) { if (unit != null) { n = n.unify(); } return this._math(Math[name], unit, n); }; }; for(var i = 0; i < mathFunctions.length; i++) { tree.functions[mathFunctions[i].name] = createMathFunction(mathFunctions[i].name, mathFunctions[i].unit); } function hsla(color) { return tree.functions.hsla(color.h, color.s, color.l, color.a); } function scaled(n, size) { if (n instanceof tree.Dimension && n.unit.is('%')) { return parseFloat(n.value * size / 100); } else { return number(n); } } function number(n) { if (n instanceof tree.Dimension) { return parseFloat(n.unit.is('%') ? n.value / 100 : n.value); } else if (typeof(n) === 'number') { return n; } else { throw { error: "RuntimeError", message: "color functions take numbers as parameters" }; } } function clamp(val) { return Math.min(1, Math.max(0, val)); } tree.functionCall = function(env, currentFileInfo) { this.env = env; this.currentFileInfo = currentFileInfo; }; tree.functionCall.prototype = tree.functions; })(require('./tree')); (function (tree) { tree.colors = { 'aliceblue':'#f0f8ff', 'antiquewhite':'#faebd7', 'aqua':'#00ffff', 'aquamarine':'#7fffd4', 'azure':'#f0ffff', 'beige':'#f5f5dc', 'bisque':'#ffe4c4', 'black':'#000000', 'blanchedalmond':'#ffebcd', 'blue':'#0000ff', 'blueviolet':'#8a2be2', 'brown':'#a52a2a', 'burlywood':'#deb887', 'cadetblue':'#5f9ea0', 'chartreuse':'#7fff00', 'chocolate':'#d2691e', 'coral':'#ff7f50', 'cornflowerblue':'#6495ed', 'cornsilk':'#fff8dc', 'crimson':'#dc143c', 'cyan':'#00ffff', 'darkblue':'#00008b', 'darkcyan':'#008b8b', 'darkgoldenrod':'#b8860b', 'darkgray':'#a9a9a9', 'darkgrey':'#a9a9a9', 'darkgreen':'#006400', 'darkkhaki':'#bdb76b', 'darkmagenta':'#8b008b', 'darkolivegreen':'#556b2f', 'darkorange':'#ff8c00', 'darkorchid':'#9932cc', 'darkred':'#8b0000', 'darksalmon':'#e9967a', 'darkseagreen':'#8fbc8f', 'darkslateblue':'#483d8b', 'darkslategray':'#2f4f4f', 'darkslategrey':'#2f4f4f', 'darkturquoise':'#00ced1', 'darkviolet':'#9400d3', 'deeppink':'#ff1493', 'deepskyblue':'#00bfff', 'dimgray':'#696969', 'dimgrey':'#696969', 'dodgerblue':'#1e90ff', 'firebrick':'#b22222', 'floralwhite':'#fffaf0', 'forestgreen':'#228b22', 'fuchsia':'#ff00ff', 'gainsboro':'#dcdcdc', 'ghostwhite':'#f8f8ff', 'gold':'#ffd700', 'goldenrod':'#daa520', 'gray':'#808080', 'grey':'#808080', 'green':'#008000', 'greenyellow':'#adff2f', 'honeydew':'#f0fff0', 'hotpink':'#ff69b4', 'indianred':'#cd5c5c', 'indigo':'#4b0082', 'ivory':'#fffff0', 'khaki':'#f0e68c', 'lavender':'#e6e6fa', 'lavenderblush':'#fff0f5', 'lawngreen':'#7cfc00', 'lemonchiffon':'#fffacd', 'lightblue':'#add8e6', 'lightcoral':'#f08080', 'lightcyan':'#e0ffff', 'lightgoldenrodyellow':'#fafad2', 'lightgray':'#d3d3d3', 'lightgrey':'#d3d3d3', 'lightgreen':'#90ee90', 'lightpink':'#ffb6c1', 'lightsalmon':'#ffa07a', 'lightseagreen':'#20b2aa', 'lightskyblue':'#87cefa', 'lightslategray':'#778899', 'lightslategrey':'#778899', 'lightsteelblue':'#b0c4de', 'lightyellow':'#ffffe0', 'lime':'#00ff00', 'limegreen':'#32cd32', 'linen':'#faf0e6', 'magenta':'#ff00ff', 'maroon':'#800000', 'mediumaquamarine':'#66cdaa', 'mediumblue':'#0000cd', 'mediumorchid':'#ba55d3', 'mediumpurple':'#9370d8', 'mediumseagreen':'#3cb371', 'mediumslateblue':'#7b68ee', 'mediumspringgreen':'#00fa9a', 'mediumturquoise':'#48d1cc', 'mediumvioletred':'#c71585', 'midnightblue':'#191970', 'mintcream':'#f5fffa', 'mistyrose':'#ffe4e1', 'moccasin':'#ffe4b5', 'navajowhite':'#ffdead', 'navy':'#000080', 'oldlace':'#fdf5e6', 'olive':'#808000', 'olivedrab':'#6b8e23', 'orange':'#ffa500', 'orangered':'#ff4500', 'orchid':'#da70d6', 'palegoldenrod':'#eee8aa', 'palegreen':'#98fb98', 'paleturquoise':'#afeeee', 'palevioletred':'#d87093', 'papayawhip':'#ffefd5', 'peachpuff':'#ffdab9', 'peru':'#cd853f', 'pink':'#ffc0cb', 'plum':'#dda0dd', 'powderblue':'#b0e0e6', 'purple':'#800080', 'red':'#ff0000', 'rosybrown':'#bc8f8f', 'royalblue':'#4169e1', 'saddlebrown':'#8b4513', 'salmon':'#fa8072', 'sandybrown':'#f4a460', 'seagreen':'#2e8b57', 'seashell':'#fff5ee', 'sienna':'#a0522d', 'silver':'#c0c0c0', 'skyblue':'#87ceeb', 'slateblue':'#6a5acd', 'slategray':'#708090', 'slategrey':'#708090', 'snow':'#fffafa', 'springgreen':'#00ff7f', 'steelblue':'#4682b4', 'tan':'#d2b48c', 'teal':'#008080', 'thistle':'#d8bfd8', 'tomato':'#ff6347', // 'transparent':'rgba(0,0,0,0)', 'turquoise':'#40e0d0', 'violet':'#ee82ee', 'wheat':'#f5deb3', 'white':'#ffffff', 'whitesmoke':'#f5f5f5', 'yellow':'#ffff00', 'yellowgreen':'#9acd32' }; })(require('./tree')); (function (tree) { tree.Alpha = function (val) { this.value = val; }; tree.Alpha.prototype = { type: "Alpha", accept: function (visitor) { this.value = visitor.visit(this.value); }, eval: function (env) { if (this.value.eval) { this.value = this.value.eval(env) } return this; }, toCSS: function () { return "alpha(opacity=" + (this.value.toCSS ? this.value.toCSS() : this.value) + ")"; } }; })(require('../tree')); (function (tree) { tree.Anonymous = function (string) { this.value = string.value || string; }; tree.Anonymous.prototype = { type: "Anonymous", toCSS: function () { return this.value; }, eval: function () { return this }, compare: function (x) { if (!x.toCSS) { return -1; } var left = this.toCSS(), right = x.toCSS(); if (left === right) { return 0; } return left < right ? -1 : 1; } }; })(require('../tree')); (function (tree) { tree.Assignment = function (key, val) { this.key = key; this.value = val; }; tree.Assignment.prototype = { type: "Assignment", accept: function (visitor) { this.value = visitor.visit(this.value); }, toCSS: function () { return this.key + '=' + (this.value.toCSS ? this.value.toCSS() : this.value); }, eval: function (env) { if (this.value.eval) { return new(tree.Assignment)(this.key, this.value.eval(env)); } return this; } }; })(require('../tree'));(function (tree) { // // A function call node. // tree.Call = function (name, args, index, currentFileInfo) { this.name = name; this.args = args; this.index = index; this.currentFileInfo = currentFileInfo; }; tree.Call.prototype = { type: "Call", accept: function (visitor) { this.args = visitor.visit(this.args); }, // // When evaluating a function call, // we either find the function in `tree.functions` [1], // in which case we call it, passing the evaluated arguments, // if this returns null or we cannot find the function, we // simply print it out as it appeared originally [2]. // // The *functions.js* file contains the built-in functions. // // The reason why we evaluate the arguments, is in the case where // we try to pass a variable to a function, like: `saturate(@color)`. // The function should receive the value, not the variable. // eval: function (env) { var args = this.args.map(function (a) { return a.eval(env); }), nameLC = this.name.toLowerCase(), result, func; if (nameLC in tree.functions) { // 1. try { func = new tree.functionCall(env, this.currentFileInfo); result = func[nameLC].apply(func, args); if (result != null) { return result; } } catch (e) { throw { type: e.type || "Runtime", message: "error evaluating function `" + this.name + "`" + (e.message ? ': ' + e.message : ''), index: this.index, filename: this.currentFileInfo.filename }; } } // 2. return new(tree.Anonymous)(this.name + "(" + args.map(function (a) { return a.toCSS(env); }).join(', ') + ")"); }, toCSS: function (env) { return this.eval(env).toCSS(); } }; })(require('../tree')); (function (tree) { // // RGB Colors - #ff0014, #eee // tree.Color = function (rgb, a) { // // The end goal here, is to parse the arguments // into an integer triplet, such as `128, 255, 0` // // This facilitates operations and conversions. // if (Array.isArray(rgb)) { this.rgb = rgb; } else if (rgb.length == 6) { this.rgb = rgb.match(/.{2}/g).map(function (c) { return parseInt(c, 16); }); } else { this.rgb = rgb.split('').map(function (c) { return parseInt(c + c, 16); }); } this.alpha = typeof(a) === 'number' ? a : 1; }; tree.Color.prototype = { type: "Color", eval: function () { return this }, luma: function () { return (0.2126 * this.rgb[0] / 255) + (0.7152 * this.rgb[1] / 255) + (0.0722 * this.rgb[2] / 255); }, // // If we have some transparency, the only way to represent it // is via `rgba`. Otherwise, we use the hex representation, // which has better compatibility with older browsers. // Values are capped between `0` and `255`, rounded and zero-padded. // toCSS: function (env, doNotCompress) { var compress = env && env.compress && !doNotCompress; if (this.alpha < 1.0) { return "rgba(" + this.rgb.map(function (c) { return Math.round(c); }).concat(this.alpha).join(',' + (compress ? '' : ' ')) + ")"; } else { var color = this.rgb.map(function (i) { i = Math.round(i); i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16); return i.length === 1 ? '0' + i : i; }).join(''); if (compress) { color = color.split(''); // Convert color to short format if (color[0] == color[1] && color[2] == color[3] && color[4] == color[5]) { color = color[0] + color[2] + color[4]; } else { color = color.join(''); } } return '#' + color; } }, // // Operations have to be done per-channel, if not, // channels will spill onto each other. Once we have // our result, in the form of an integer triplet, // we create a new Color node to hold the result. // operate: function (env, op, other) { var result = []; if (! (other instanceof tree.Color)) { other = other.toColor(); } for (var c = 0; c < 3; c++) { result[c] = tree.operate(env, op, this.rgb[c], other.rgb[c]); } return new(tree.Color)(result, this.alpha + other.alpha); }, toHSL: function () { var r = this.rgb[0] / 255, g = this.rgb[1] / 255, b = this.rgb[2] / 255, a = this.alpha; var max = Math.max(r, g, b), min = Math.min(r, g, b); var h, s, l = (max + min) / 2, d = max - min; if (max === min) { h = s = 0; } else { s = l > 0.5 ? d / (2 - max - min) : d / (max + min); switch (max) { case r: h = (g - b) / d + (g < b ? 6 : 0); break; case g: h = (b - r) / d + 2; break; case b: h = (r - g) / d + 4; break; } h /= 6; } return { h: h * 360, s: s, l: l, a: a }; }, //Adapted from http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript toHSV: function () { var r = this.rgb[0] / 255, g = this.rgb[1] / 255, b = this.rgb[2] / 255, a = this.alpha; var max = Math.max(r, g, b), min = Math.min(r, g, b); var h, s, v = max; var d = max - min; if (max === 0) { s = 0; } else { s = d / max; } if (max === min) { h = 0; } else { switch(max){ case r: h = (g - b) / d + (g < b ? 6 : 0); break; case g: h = (b - r) / d + 2; break; case b: h = (r - g) / d + 4; break; } h /= 6; } return { h: h * 360, s: s, v: v, a: a }; }, toARGB: function () { var argb = [Math.round(this.alpha * 255)].concat(this.rgb); return '#' + argb.map(function (i) { i = Math.round(i); i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16); return i.length === 1 ? '0' + i : i; }).join(''); }, compare: function (x) { if (!x.rgb) { return -1; } return (x.rgb[0] === this.rgb[0] && x.rgb[1] === this.rgb[1] && x.rgb[2] === this.rgb[2] && x.alpha === this.alpha) ? 0 : -1; } }; })(require('../tree')); (function (tree) { tree.Comment = function (value, silent) { this.value = value; this.silent = !!silent; }; tree.Comment.prototype = { type: "Comment", toCSS: function (env) { return env.compress ? '' : this.value; }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.Condition = function (op, l, r, i, negate) { this.op = op.trim(); this.lvalue = l; this.rvalue = r; this.index = i; this.negate = negate; }; tree.Condition.prototype = { type: "Condition", accept: function (visitor) { this.lvalue = visitor.visit(this.lvalue); this.rvalue = visitor.visit(this.rvalue); }, eval: function (env) { var a = this.lvalue.eval(env), b = this.rvalue.eval(env); var i = this.index, result; var result = (function (op) { switch (op) { case 'and': return a && b; case 'or': return a || b; default: if (a.compare) { result = a.compare(b); } else if (b.compare) { result = b.compare(a); } else { throw { type: "Type", message: "Unable to perform comparison", index: i }; } switch (result) { case -1: return op === '<' || op === '=<'; case 0: return op === '=' || op === '>=' || op === '=<'; case 1: return op === '>' || op === '>='; } } })(this.op); return this.negate ? !result : result; } }; })(require('../tree')); (function (tree) { // // A number with a unit // tree.Dimension = function (value, unit) { this.value = parseFloat(value); this.unit = (unit && unit instanceof tree.Unit) ? unit : new(tree.Unit)(unit ? [unit] : undefined); }; tree.Dimension.prototype = { type: "Dimension", accept: function (visitor) { this.unit = visitor.visit(this.unit); }, eval: function (env) { return this; }, toColor: function () { return new(tree.Color)([this.value, this.value, this.value]); }, toCSS: function (env) { if ((env && env.strictUnits) && !this.unit.isSingular()) { throw new Error("Multiple units in dimension. Correct the units or use the unit function. Bad unit: "+this.unit.toString()); } var value = this.value, strValue = String(value); if (value !== 0 && value < 0.000001 && value > -0.000001) { // would be output 1e-6 etc. strValue = value.toFixed(20).replace(/0+$/, ""); } if (env && env.compress) { // Zero values doesn't need a unit if (value === 0 && !this.unit.isAngle()) { return strValue; } // Float values doesn't need a leading zero if (value > 0 && value < 1) { strValue = (strValue).substr(1); } } return strValue + this.unit.toCSS(env); }, // In an operation between two Dimensions, // we default to the first Dimension's unit, // so `1px + 2` will yield `3px`. operate: function (env, op, other) { var value = tree.operate(env, op, this.value, other.value), unit = this.unit.clone(); if (op === '+' || op === '-') { if (unit.numerator.length === 0 && unit.denominator.length === 0) { unit.numerator = other.unit.numerator.slice(0); unit.denominator = other.unit.denominator.slice(0); } else if (other.unit.numerator.length == 0 && unit.denominator.length == 0) { // do nothing } else { other = other.convertTo(this.unit.usedUnits()); if(env.strictUnits && other.unit.toString() !== unit.toString()) { throw new Error("Incompatible units. Change the units or use the unit function. Bad units: '" + unit.toString() + "' and '" + other.unit.toString() + "'."); } value = tree.operate(env, op, this.value, other.value); } } else if (op === '*') { unit.numerator = unit.numerator.concat(other.unit.numerator).sort(); unit.denominator = unit.denominator.concat(other.unit.denominator).sort(); unit.cancel(); } else if (op === '/') { unit.numerator = unit.numerator.concat(other.unit.denominator).sort(); unit.denominator = unit.denominator.concat(other.unit.numerator).sort(); unit.cancel(); } return new(tree.Dimension)(value, unit); }, compare: function (other) { if (other instanceof tree.Dimension) { var a = this.unify(), b = other.unify(), aValue = a.value, bValue = b.value; if (bValue > aValue) { return -1; } else if (bValue < aValue) { return 1; } else { if (!b.unit.isEmpty() && a.unit.compare(b.unit) !== 0) { return -1; } return 0; } } else { return -1; } }, unify: function () { return this.convertTo({ length: 'm', duration: 's', angle: 'rad' }); }, convertTo: function (conversions) { var value = this.value, unit = this.unit.clone(), i, groupName, group, conversion, targetUnit, derivedConversions = {}; if (typeof conversions === 'string') { for(i in tree.UnitConversions) { if (tree.UnitConversions[i].hasOwnProperty(conversions)) { derivedConversions = {}; derivedConversions[i] = conversions; } } conversions = derivedConversions; } for (groupName in conversions) { if (conversions.hasOwnProperty(groupName)) { targetUnit = conversions[groupName]; group = tree.UnitConversions[groupName]; unit.map(function (atomicUnit, denominator) { if (group.hasOwnProperty(atomicUnit)) { if (denominator) { value = value / (group[atomicUnit] / group[targetUnit]); } else { value = value * (group[atomicUnit] / group[targetUnit]); } return targetUnit; } return atomicUnit; }); } } unit.cancel(); return new(tree.Dimension)(value, unit); } }; // http://www.w3.org/TR/css3-values/#absolute-lengths tree.UnitConversions = { length: { 'm': 1, 'cm': 0.01, 'mm': 0.001, 'in': 0.0254, 'pt': 0.0254 / 72, 'pc': 0.0254 / 72 * 12 }, duration: { 's': 1, 'ms': 0.001 }, angle: { 'rad': 1/(2*Math.PI), 'deg': 1/360, 'grad': 1/400, 'turn': 1 } }; tree.Unit = function (numerator, denominator, backupUnit) { this.numerator = numerator ? numerator.slice(0).sort() : []; this.denominator = denominator ? denominator.slice(0).sort() : []; this.backupUnit = backupUnit; }; tree.Unit.prototype = { type: "Unit", clone: function () { return new tree.Unit(this.numerator.slice(0), this.denominator.slice(0), this.backupUnit); }, toCSS: function (env) { if (this.numerator.length >= 1) { return this.numerator[0]; } if (this.denominator.length >= 1) { return this.denominator[0]; } if ((!env || !env.strictUnits) && this.backupUnit) { return this.backupUnit; } return ""; }, toString: function () { var i, returnStr = this.numerator.join("*"); for (i = 0; i < this.denominator.length; i++) { returnStr += "/" + this.denominator[i]; } return returnStr; }, compare: function (other) { return this.is(other.toString()) ? 0 : -1; }, is: function (unitString) { return this.toString() === unitString; }, isAngle: function () { return tree.UnitConversions.angle.hasOwnProperty(this.toCSS()); }, isEmpty: function () { return this.numerator.length == 0 && this.denominator.length == 0; }, isSingular: function() { return this.numerator.length <= 1 && this.denominator.length == 0; }, map: function(callback) { var i; for (i = 0; i < this.numerator.length; i++) { this.numerator[i] = callback(this.numerator[i], false); } for (i = 0; i < this.denominator.length; i++) { this.denominator[i] = callback(this.denominator[i], true); } }, usedUnits: function() { var group, groupName, result = {}; for (groupName in tree.UnitConversions) { if (tree.UnitConversions.hasOwnProperty(groupName)) { group = tree.UnitConversions[groupName]; this.map(function (atomicUnit) { if (group.hasOwnProperty(atomicUnit) && !result[groupName]) { result[groupName] = atomicUnit; } return atomicUnit; }); } } return result; }, cancel: function () { var counter = {}, atomicUnit, i, backup; for (i = 0; i < this.numerator.length; i++) { atomicUnit = this.numerator[i]; if (!backup) { backup = atomicUnit; } counter[atomicUnit] = (counter[atomicUnit] || 0) + 1; } for (i = 0; i < this.denominator.length; i++) { atomicUnit = this.denominator[i]; if (!backup) { backup = atomicUnit; } counter[atomicUnit] = (counter[atomicUnit] || 0) - 1; } this.numerator = []; this.denominator = []; for (atomicUnit in counter) { if (counter.hasOwnProperty(atomicUnit)) { var count = counter[atomicUnit]; if (count > 0) { for (i = 0; i < count; i++) { this.numerator.push(atomicUnit); } } else if (count < 0) { for (i = 0; i < -count; i++) { this.denominator.push(atomicUnit); } } } } if (this.numerator.length === 0 && this.denominator.length === 0 && backup) { this.backupUnit = backup; } this.numerator.sort(); this.denominator.sort(); } }; })(require('../tree')); (function (tree) { tree.Directive = function (name, value) { this.name = name; if (Array.isArray(value)) { this.ruleset = new(tree.Ruleset)([], value); this.ruleset.allowImports = true; } else { this.value = value; } }; tree.Directive.prototype = { type: "Directive", accept: function (visitor) { this.ruleset = visitor.visit(this.ruleset); this.value = visitor.visit(this.value); }, toCSS: function (env) { if (this.ruleset) { this.ruleset.root = true; return this.name + (env.compress ? '{' : ' {\n ') + this.ruleset.toCSS(env).trim().replace(/\n/g, '\n ') + (env.compress ? '}': '\n}\n'); } else { return this.name + ' ' + this.value.toCSS() + ';\n'; } }, eval: function (env) { var evaldDirective = this; if (this.ruleset) { env.frames.unshift(this); evaldDirective = new(tree.Directive)(this.name); evaldDirective.ruleset = this.ruleset.eval(env); env.frames.shift(); } return evaldDirective; }, variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) }, find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) }, rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) } }; })(require('../tree')); (function (tree) { tree.Element = function (combinator, value, index) { this.combinator = combinator instanceof tree.Combinator ? combinator : new(tree.Combinator)(combinator); if (typeof(value) === 'string') { this.value = value.trim(); } else if (value) { this.value = value; } else { this.value = ""; } this.index = index; }; tree.Element.prototype = { type: "Element", accept: function (visitor) { this.combinator = visitor.visit(this.combinator); this.value = visitor.visit(this.value); }, eval: function (env) { return new(tree.Element)(this.combinator, this.value.eval ? this.value.eval(env) : this.value, this.index); }, toCSS: function (env) { var value = (this.value.toCSS ? this.value.toCSS(env) : this.value); if (value == '' && this.combinator.value.charAt(0) == '&') { return ''; } else { return this.combinator.toCSS(env || {}) + value; } } }; tree.Attribute = function (key, op, value) { this.key = key; this.op = op; this.value = value; }; tree.Attribute.prototype = { type: "Attribute", accept: function (visitor) { this.value = visitor.visit(this.value); }, eval: function (env) { return new(tree.Attribute)(this.key.eval ? this.key.eval(env) : this.key, this.op, (this.value && this.value.eval) ? this.value.eval(env) : this.value); }, toCSS: function (env) { var value = this.key.toCSS ? this.key.toCSS(env) : this.key; if (this.op) { value += this.op; value += (this.value.toCSS ? this.value.toCSS(env) : this.value); } return '[' + value + ']'; } }; tree.Combinator = function (value) { if (value === ' ') { this.value = ' '; } else { this.value = value ? value.trim() : ""; } }; tree.Combinator.prototype = { type: "Combinator", toCSS: function (env) { return { '' : '', ' ' : ' ', ':' : ' :', '+' : env.compress ? '+' : ' + ', '~' : env.compress ? '~' : ' ~ ', '>' : env.compress ? '>' : ' > ', '|' : env.compress ? '|' : ' | ' }[this.value]; } }; })(require('../tree')); (function (tree) { tree.Expression = function (value) { this.value = value; }; tree.Expression.prototype = { type: "Expression", accept: function (visitor) { this.value = visitor.visit(this.value); }, eval: function (env) { var returnValue, inParenthesis = this.parens && !this.parensInOp, doubleParen = false; if (inParenthesis) { env.inParenthesis(); } if (this.value.length > 1) { returnValue = new(tree.Expression)(this.value.map(function (e) { return e.eval(env); })); } else if (this.value.length === 1) { if (this.value[0].parens && !this.value[0].parensInOp) { doubleParen = true; } returnValue = this.value[0].eval(env); } else { returnValue = this; } if (inParenthesis) { env.outOfParenthesis(); } if (this.parens && this.parensInOp && !(env.isMathOn()) && !doubleParen) { returnValue = new(tree.Paren)(returnValue); } return returnValue; }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS ? e.toCSS(env) : ''; }).join(' '); }, throwAwayComments: function () { this.value = this.value.filter(function(v) { return !(v instanceof tree.Comment); }); } }; })(require('../tree')); (function (tree) { tree.Extend = function Extend(selector, option, index) { this.selector = selector; this.option = option; this.index = index; switch(option) { case "all": this.allowBefore = true; this.allowAfter = true; break; default: this.allowBefore = false; this.allowAfter = false; break; } }; tree.Extend.prototype = { type: "Extend", accept: function (visitor) { this.selector = visitor.visit(this.selector); }, eval: function (env) { return new(tree.Extend)(this.selector.eval(env), this.option, this.index); }, clone: function (env) { return new(tree.Extend)(this.selector, this.option, this.index); }, findSelfSelectors: function (selectors) { var selfElements = [], i; for(i = 0; i < selectors.length; i++) { selfElements = selfElements.concat(selectors[i].elements); } this.selfSelectors = [{ elements: selfElements }]; } }; })(require('../tree')); (function (tree) { // // CSS @import node // // The general strategy here is that we don't want to wait // for the parsing to be completed, before we start importing // the file. That's because in the context of a browser, // most of the time will be spent waiting for the server to respond. // // On creation, we push the import path to our import queue, though // `import,push`, we also pass it a callback, which it'll call once // the file has been fetched, and parsed. // tree.Import = function (path, features, options, index, currentFileInfo) { var that = this; this.options = options; this.index = index; this.path = path; this.features = features; this.currentFileInfo = currentFileInfo; if (this.options.less !== undefined) { this.css = !this.options.less; } else { var pathValue = this.getPath(); if (pathValue && /css([\?;].*)?$/.test(pathValue)) { this.css = true; } } }; // // The actual import node doesn't return anything, when converted to CSS. // The reason is that it's used at the evaluation stage, so that the rules // it imports can be treated like any other rules. // // In `eval`, we make sure all Import nodes get evaluated, recursively, so // we end up with a flat structure, which can easily be imported in the parent // ruleset. // tree.Import.prototype = { type: "Import", accept: function (visitor) { this.features = visitor.visit(this.features); this.path = visitor.visit(this.path); this.root = visitor.visit(this.root); }, toCSS: function (env) { var features = this.features ? ' ' + this.features.toCSS(env) : ''; if (this.css) { return "@import " + this.path.toCSS() + features + ';\n'; } else { return ""; } }, getPath: function () { if (this.path instanceof tree.Quoted) { var path = this.path.value; return (this.css !== undefined || /(\.[a-z]*$)|([\?;].*)$/.test(path)) ? path : path + '.less'; } else if (this.path instanceof tree.URL) { return this.path.value.value; } return null; }, evalForImport: function (env) { return new(tree.Import)(this.path.eval(env), this.features, this.options, this.index, this.currentFileInfo); }, evalPath: function (env) { var path = this.path.eval(env); var rootpath = this.currentFileInfo && this.currentFileInfo.rootpath; if (rootpath && !(path instanceof tree.URL)) { var pathValue = path.value; // Add the base path if the import is relative if (pathValue && env.isPathRelative(pathValue)) { path.value = rootpath + pathValue; } } return path; }, eval: function (env) { var ruleset, features = this.features && this.features.eval(env); if (this.skip) { return []; } if (this.css) { var newImport = new(tree.Import)(this.evalPath(env), features, this.options, this.index); if (!newImport.css && this.error) { throw this.error; } return newImport; } else { ruleset = new(tree.Ruleset)([], this.root.rules.slice(0)); ruleset.evalImports(env); return this.features ? new(tree.Media)(ruleset.rules, this.features.value) : ruleset.rules; } } }; })(require('../tree')); (function (tree) { tree.JavaScript = function (string, index, escaped) { this.escaped = escaped; this.expression = string; this.index = index; }; tree.JavaScript.prototype = { type: "JavaScript", eval: function (env) { var result, that = this, context = {}; var expression = this.expression.replace(/@\{([\w-]+)\}/g, function (_, name) { return tree.jsify(new(tree.Variable)('@' + name, that.index).eval(env)); }); try { expression = new(Function)('return (' + expression + ')'); } catch (e) { throw { message: "JavaScript evaluation error: `" + expression + "`" , index: this.index }; } for (var k in env.frames[0].variables()) { context[k.slice(1)] = { value: env.frames[0].variables()[k].value, toJS: function () { return this.value.eval(env).toCSS(); } }; } try { result = expression.call(context); } catch (e) { throw { message: "JavaScript evaluation error: '" + e.name + ': ' + e.message + "'" , index: this.index }; } if (typeof(result) === 'string') { return new(tree.Quoted)('"' + result + '"', result, this.escaped, this.index); } else if (Array.isArray(result)) { return new(tree.Anonymous)(result.join(', ')); } else { return new(tree.Anonymous)(result); } } }; })(require('../tree')); (function (tree) { tree.Keyword = function (value) { this.value = value }; tree.Keyword.prototype = { type: "Keyword", eval: function () { return this; }, toCSS: function () { return this.value; }, compare: function (other) { if (other instanceof tree.Keyword) { return other.value === this.value ? 0 : 1; } else { return -1; } } }; tree.True = new(tree.Keyword)('true'); tree.False = new(tree.Keyword)('false'); })(require('../tree')); (function (tree) { tree.Media = function (value, features) { var selectors = this.emptySelectors(); this.features = new(tree.Value)(features); this.ruleset = new(tree.Ruleset)(selectors, value); this.ruleset.allowImports = true; }; tree.Media.prototype = { type: "Media", accept: function (visitor) { this.features = visitor.visit(this.features); this.ruleset = visitor.visit(this.ruleset); }, toCSS: function (env) { var features = this.features.toCSS(env); return '@media ' + features + (env.compress ? '{' : ' {\n ') + this.ruleset.toCSS(env).trim().replace(/\n/g, '\n ') + (env.compress ? '}': '\n}\n'); }, eval: function (env) { if (!env.mediaBlocks) { env.mediaBlocks = []; env.mediaPath = []; } var media = new(tree.Media)([], []); if(this.debugInfo) { this.ruleset.debugInfo = this.debugInfo; media.debugInfo = this.debugInfo; } var strictMathBypass = false; if (!env.strictMath) { strictMathBypass = true; env.strictMath = true; } try { media.features = this.features.eval(env); } finally { if (strictMathBypass) { env.strictMath = false; } } env.mediaPath.push(media); env.mediaBlocks.push(media); env.frames.unshift(this.ruleset); media.ruleset = this.ruleset.eval(env); env.frames.shift(); env.mediaPath.pop(); return env.mediaPath.length === 0 ? media.evalTop(env) : media.evalNested(env) }, variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) }, find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) }, rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) }, emptySelectors: function() { var el = new(tree.Element)('', '&', 0); return [new(tree.Selector)([el])]; }, evalTop: function (env) { var result = this; // Render all dependent Media blocks. if (env.mediaBlocks.length > 1) { var selectors = this.emptySelectors(); result = new(tree.Ruleset)(selectors, env.mediaBlocks); result.multiMedia = true; } delete env.mediaBlocks; delete env.mediaPath; return result; }, evalNested: function (env) { var i, value, path = env.mediaPath.concat([this]); // Extract the media-query conditions separated with `,` (OR). for (i = 0; i < path.length; i++) { value = path[i].features instanceof tree.Value ? path[i].features.value : path[i].features; path[i] = Array.isArray(value) ? value : [value]; } // Trace all permutations to generate the resulting media-query. // // (a, b and c) with nested (d, e) -> // a and d // a and e // b and c and d // b and c and e this.features = new(tree.Value)(this.permute(path).map(function (path) { path = path.map(function (fragment) { return fragment.toCSS ? fragment : new(tree.Anonymous)(fragment); }); for(i = path.length - 1; i > 0; i--) { path.splice(i, 0, new(tree.Anonymous)("and")); } return new(tree.Expression)(path); })); // Fake a tree-node that doesn't output anything. return new(tree.Ruleset)([], []); }, permute: function (arr) { if (arr.length === 0) { return []; } else if (arr.length === 1) { return arr[0]; } else { var result = []; var rest = this.permute(arr.slice(1)); for (var i = 0; i < rest.length; i++) { for (var j = 0; j < arr[0].length; j++) { result.push([arr[0][j]].concat(rest[i])); } } return result; } }, bubbleSelectors: function (selectors) { this.ruleset = new(tree.Ruleset)(selectors.slice(0), [this.ruleset]); } }; })(require('../tree')); (function (tree) { tree.mixin = {}; tree.mixin.Call = function (elements, args, index, currentFileInfo, important) { this.selector = new(tree.Selector)(elements); this.arguments = args; this.index = index; this.currentFileInfo = currentFileInfo; this.important = important; }; tree.mixin.Call.prototype = { type: "MixinCall", accept: function (visitor) { this.selector = visitor.visit(this.selector); this.arguments = visitor.visit(this.arguments); }, eval: function (env) { var mixins, mixin, args, rules = [], match = false, i, m, f, isRecursive, isOneFound; args = this.arguments && this.arguments.map(function (a) { return { name: a.name, value: a.value.eval(env) }; }); for (i = 0; i < env.frames.length; i++) { if ((mixins = env.frames[i].find(this.selector)).length > 0) { isOneFound = true; for (m = 0; m < mixins.length; m++) { mixin = mixins[m]; isRecursive = false; for(f = 0; f < env.frames.length; f++) { if ((!(mixin instanceof tree.mixin.Definition)) && mixin === (env.frames[f].originalRuleset || env.frames[f])) { isRecursive = true; break; } } if (isRecursive) { continue; } if (mixin.matchArgs(args, env)) { if (!mixin.matchCondition || mixin.matchCondition(args, env)) { try { Array.prototype.push.apply( rules, mixin.eval(env, args, this.important).rules); } catch (e) { throw { message: e.message, index: this.index, filename: this.currentFileInfo.filename, stack: e.stack }; } } match = true; } } if (match) { return rules; } } } if (isOneFound) { throw { type: 'Runtime', message: 'No matching definition was found for `' + this.selector.toCSS().trim() + '(' + (args ? args.map(function (a) { var argValue = ""; if (a.name) { argValue += a.name + ":"; } if (a.value.toCSS) { argValue += a.value.toCSS(); } else { argValue += "???"; } return argValue; }).join(', ') : "") + ")`", index: this.index, filename: this.currentFileInfo.filename }; } else { throw { type: 'Name', message: this.selector.toCSS().trim() + " is undefined", index: this.index, filename: this.currentFileInfo.filename }; } } }; tree.mixin.Definition = function (name, params, rules, condition, variadic) { this.name = name; this.selectors = [new(tree.Selector)([new(tree.Element)(null, name)])]; this.params = params; this.condition = condition; this.variadic = variadic; this.arity = params.length; this.rules = rules; this._lookups = {}; this.required = params.reduce(function (count, p) { if (!p.name || (p.name && !p.value)) { return count + 1 } else { return count } }, 0); this.parent = tree.Ruleset.prototype; this.frames = []; }; tree.mixin.Definition.prototype = { type: "MixinDefinition", accept: function (visitor) { this.params = visitor.visit(this.params); this.rules = visitor.visit(this.rules); this.condition = visitor.visit(this.condition); }, toCSS: function () { return ""; }, variable: function (name) { return this.parent.variable.call(this, name); }, variables: function () { return this.parent.variables.call(this); }, find: function () { return this.parent.find.apply(this, arguments); }, rulesets: function () { return this.parent.rulesets.apply(this); }, evalParams: function (env, mixinEnv, args, evaldArguments) { var frame = new(tree.Ruleset)(null, []), varargs, arg, params = this.params.slice(0), i, j, val, name, isNamedFound, argIndex; mixinEnv = new tree.evalEnv(mixinEnv, [frame].concat(mixinEnv.frames)); if (args) { args = args.slice(0); for(i = 0; i < args.length; i++) { arg = args[i]; if (name = (arg && arg.name)) { isNamedFound = false; for(j = 0; j < params.length; j++) { if (!evaldArguments[j] && name === params[j].name) { evaldArguments[j] = arg.value.eval(env); frame.rules.unshift(new(tree.Rule)(name, arg.value.eval(env))); isNamedFound = true; break; } } if (isNamedFound) { args.splice(i, 1); i--; continue; } else { throw { type: 'Runtime', message: "Named argument for " + this.name + ' ' + args[i].name + ' not found' }; } } } } argIndex = 0; for (i = 0; i < params.length; i++) { if (evaldArguments[i]) continue; arg = args && args[argIndex]; if (name = params[i].name) { if (params[i].variadic && args) { varargs = []; for (j = argIndex; j < args.length; j++) { varargs.push(args[j].value.eval(env)); } frame.rules.unshift(new(tree.Rule)(name, new(tree.Expression)(varargs).eval(env))); } else { val = arg && arg.value; if (val) { val = val.eval(env); } else if (params[i].value) { val = params[i].value.eval(mixinEnv); frame.resetCache(); } else { throw { type: 'Runtime', message: "wrong number of arguments for " + this.name + ' (' + args.length + ' for ' + this.arity + ')' }; } frame.rules.unshift(new(tree.Rule)(name, val)); evaldArguments[i] = val; } } if (params[i].variadic && args) { for (j = argIndex; j < args.length; j++) { evaldArguments[j] = args[j].value.eval(env); } } argIndex++; } return frame; }, eval: function (env, args, important) { var _arguments = [], mixinFrames = this.frames.concat(env.frames), frame = this.evalParams(env, new(tree.evalEnv)(env, mixinFrames), args, _arguments), context, rules, start, ruleset; frame.rules.unshift(new(tree.Rule)('@arguments', new(tree.Expression)(_arguments).eval(env))); rules = important ? this.parent.makeImportant.apply(this).rules : this.rules.slice(0); ruleset = new(tree.Ruleset)(null, rules).eval(new(tree.evalEnv)(env, [this, frame].concat(mixinFrames))); ruleset.originalRuleset = this; return ruleset; }, matchCondition: function (args, env) { if (this.condition && !this.condition.eval( new(tree.evalEnv)(env, [this.evalParams(env, new(tree.evalEnv)(env, this.frames.concat(env.frames)), args, [])] .concat(env.frames)))) { return false; } return true; }, matchArgs: function (args, env) { var argsLength = (args && args.length) || 0, len, frame; if (! this.variadic) { if (argsLength < this.required) { return false } if (argsLength > this.params.length) { return false } if ((this.required > 0) && (argsLength > this.params.length)) { return false } } len = Math.min(argsLength, this.arity); for (var i = 0; i < len; i++) { if (!this.params[i].name && !this.params[i].variadic) { if (args[i].value.eval(env).toCSS() != this.params[i].value.eval(env).toCSS()) { return false; } } } return true; } }; })(require('../tree')); (function (tree) { tree.Negative = function (node) { this.value = node; }; tree.Negative.prototype = { type: "Negative", accept: function (visitor) { this.value = visitor.visit(this.value); }, toCSS: function (env) { return '-' + this.value.toCSS(env); }, eval: function (env) { if (env.isMathOn()) { return (new(tree.Operation)('*', [new(tree.Dimension)(-1), this.value])).eval(env); } return new(tree.Negative)(this.value.eval(env)); } }; })(require('../tree')); (function (tree) { tree.Operation = function (op, operands, isSpaced) { this.op = op.trim(); this.operands = operands; this.isSpaced = isSpaced; }; tree.Operation.prototype = { type: "Operation", accept: function (visitor) { this.operands = visitor.visit(this.operands); }, eval: function (env) { var a = this.operands[0].eval(env), b = this.operands[1].eval(env), temp; if (env.isMathOn()) { if (a instanceof tree.Dimension && b instanceof tree.Color) { if (this.op === '*' || this.op === '+') { temp = b, b = a, a = temp; } else { throw { type: "Operation", message: "Can't substract or divide a color from a number" }; } } if (!a.operate) { throw { type: "Operation", message: "Operation on an invalid type" }; } return a.operate(env, this.op, b); } else { return new(tree.Operation)(this.op, [a, b], this.isSpaced); } }, toCSS: function (env) { var separator = this.isSpaced ? " " : ""; return this.operands[0].toCSS() + separator + this.op + separator + this.operands[1].toCSS(); } }; tree.operate = function (env, op, a, b) { switch (op) { case '+': return a + b; case '-': return a - b; case '*': return a * b; case '/': return a / b; } }; })(require('../tree')); (function (tree) { tree.Paren = function (node) { this.value = node; }; tree.Paren.prototype = { type: "Paren", accept: function (visitor) { this.value = visitor.visit(this.value); }, toCSS: function (env) { return '(' + this.value.toCSS(env).trim() + ')'; }, eval: function (env) { return new(tree.Paren)(this.value.eval(env)); } }; })(require('../tree')); (function (tree) { tree.Quoted = function (str, content, escaped, index, currentFileInfo) { this.escaped = escaped; this.value = content || ''; this.quote = str.charAt(0); this.index = index; this.currentFileInfo = currentFileInfo; }; tree.Quoted.prototype = { type: "Quoted", toCSS: function () { if (this.escaped) { return this.value; } else { return this.quote + this.value + this.quote; } }, eval: function (env) { var that = this; var value = this.value.replace(/`([^`]+)`/g, function (_, exp) { return new(tree.JavaScript)(exp, that.index, true).eval(env).value; }).replace(/@\{([\w-]+)\}/g, function (_, name) { var v = new(tree.Variable)('@' + name, that.index, that.currentFileInfo).eval(env, true); return (v instanceof tree.Quoted) ? v.value : v.toCSS(); }); return new(tree.Quoted)(this.quote + value + this.quote, value, this.escaped, this.index); }, compare: function (x) { if (!x.toCSS) { return -1; } var left = this.toCSS(), right = x.toCSS(); if (left === right) { return 0; } return left < right ? -1 : 1; } }; })(require('../tree')); (function (tree) { tree.Rule = function (name, value, important, index, currentFileInfo, inline) { this.name = name; this.value = (value instanceof tree.Value) ? value : new(tree.Value)([value]); this.important = important ? ' ' + important.trim() : ''; this.index = index; this.currentFileInfo = currentFileInfo; this.inline = inline || false; if (name.charAt(0) === '@') { this.variable = true; } else { this.variable = false } }; tree.Rule.prototype = { type: "Rule", accept: function (visitor) { this.value = visitor.visit(this.value); }, toCSS: function (env) { if (this.variable) { return "" } else { try { return this.name + (env.compress ? ':' : ': ') + this.value.toCSS(env) + this.important + (this.inline ? "" : ";"); } catch(e) { e.index = this.index; e.filename = this.currentFileInfo.filename; throw e; } } }, eval: function (env) { var strictMathBypass = false; if (this.name === "font" && env.strictMath === false) { strictMathBypass = true; env.strictMath = true; } try { return new(tree.Rule)(this.name, this.value.eval(env), this.important, this.index, this.currentFileInfo, this.inline); } finally { if (strictMathBypass) { env.strictMath = false; } } }, makeImportant: function () { return new(tree.Rule)(this.name, this.value, "!important", this.index, this.currentFileInfo, this.inline); } }; })(require('../tree')); (function (tree) { tree.Ruleset = function (selectors, rules, strictImports) { this.selectors = selectors; this.rules = rules; this._lookups = {}; this.strictImports = strictImports; }; tree.Ruleset.prototype = { type: "Ruleset", accept: function (visitor) { this.selectors = visitor.visit(this.selectors); this.rules = visitor.visit(this.rules); }, eval: function (env) { var selectors = this.selectors && this.selectors.map(function (s) { return s.eval(env) }); var ruleset = new(tree.Ruleset)(selectors, this.rules.slice(0), this.strictImports); var rules; ruleset.originalRuleset = this; ruleset.root = this.root; ruleset.firstRoot = this.firstRoot; ruleset.allowImports = this.allowImports; if(this.debugInfo) { ruleset.debugInfo = this.debugInfo; } // push the current ruleset to the frames stack env.frames.unshift(ruleset); // currrent selectors if (!env.selectors) { env.selectors = []; } env.selectors.unshift(this.selectors); // Evaluate imports if (ruleset.root || ruleset.allowImports || !ruleset.strictImports) { ruleset.evalImports(env); } // Store the frames around mixin definitions, // so they can be evaluated like closures when the time comes. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Definition) { ruleset.rules[i].frames = env.frames.slice(0); } } var mediaBlockCount = (env.mediaBlocks && env.mediaBlocks.length) || 0; // Evaluate mixin calls. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Call) { rules = ruleset.rules[i].eval(env).filter(function(r) { if ((r instanceof tree.Rule) && r.variable) { // do not pollute the scope if the variable is // already there. consider returning false here // but we need a way to "return" variable from mixins return !(ruleset.variable(r.name)); } return true; }); ruleset.rules.splice.apply(ruleset.rules, [i, 1].concat(rules)); i += rules.length-1; ruleset.resetCache(); } } // Evaluate everything else for (var i = 0, rule; i < ruleset.rules.length; i++) { rule = ruleset.rules[i]; if (! (rule instanceof tree.mixin.Definition)) { ruleset.rules[i] = rule.eval ? rule.eval(env) : rule; } } // Pop the stack env.frames.shift(); env.selectors.shift(); if (env.mediaBlocks) { for(var i = mediaBlockCount; i < env.mediaBlocks.length; i++) { env.mediaBlocks[i].bubbleSelectors(selectors); } } return ruleset; }, evalImports: function(env) { var i, rules; for (i = 0; i < this.rules.length; i++) { if (this.rules[i] instanceof tree.Import) { rules = this.rules[i].eval(env); if (typeof rules.length === "number") { this.rules.splice.apply(this.rules, [i, 1].concat(rules)); i+= rules.length-1; } else { this.rules.splice(i, 1, rules); } this.resetCache(); } } }, makeImportant: function() { return new tree.Ruleset(this.selectors, this.rules.map(function (r) { if (r.makeImportant) { return r.makeImportant(); } else { return r; } }), this.strictImports); }, matchArgs: function (args) { return !args || args.length === 0; }, resetCache: function () { this._rulesets = null; this._variables = null; this._lookups = {}; }, variables: function () { if (this._variables) { return this._variables } else { return this._variables = this.rules.reduce(function (hash, r) { if (r instanceof tree.Rule && r.variable === true) { hash[r.name] = r; } return hash; }, {}); } }, variable: function (name) { return this.variables()[name]; }, rulesets: function () { return this.rules.filter(function (r) { return (r instanceof tree.Ruleset) || (r instanceof tree.mixin.Definition); }); }, find: function (selector, self) { self = self || this; var rules = [], rule, match, key = selector.toCSS(); if (key in this._lookups) { return this._lookups[key] } this.rulesets().forEach(function (rule) { if (rule !== self) { for (var j = 0; j < rule.selectors.length; j++) { if (match = selector.match(rule.selectors[j])) { if (selector.elements.length > rule.selectors[j].elements.length) { Array.prototype.push.apply(rules, rule.find( new(tree.Selector)(selector.elements.slice(1)), self)); } else { rules.push(rule); } break; } } } }); return this._lookups[key] = rules; }, // // Entry point for code generation // // `context` holds an array of arrays. // toCSS: function (env) { var css = [], // The CSS output rules = [], // node.Rule instances _rules = [], // rulesets = [], // node.Ruleset instances selector, // The fully rendered selector debugInfo, // Line number debugging rule; // Compile rules and rulesets for (var i = 0; i < this.rules.length; i++) { rule = this.rules[i]; if (rule.rules || (rule instanceof tree.Media)) { rulesets.push(rule.toCSS(env)); } else if (rule instanceof tree.Directive) { var cssValue = rule.toCSS(env); // Output only the first @charset definition as such - convert the others // to comments in case debug is enabled if (rule.name === "@charset") { // Only output the debug info together with subsequent @charset definitions // a comment (or @media statement) before the actual @charset directive would // be considered illegal css as it has to be on the first line if (env.charset) { if (rule.debugInfo) { rulesets.push(tree.debugInfo(env, rule)); rulesets.push(new tree.Comment("/* "+cssValue.replace(/\n/g, "")+" */\n").toCSS(env)); } continue; } env.charset = true; } rulesets.push(cssValue); } else if (rule instanceof tree.Comment) { if (!rule.silent) { if (this.root) { rulesets.push(rule.toCSS(env)); } else { rules.push(rule.toCSS(env)); } } } else { if (rule.toCSS && !rule.variable) { if (this.firstRoot && rule instanceof tree.Rule) { throw { message: "properties must be inside selector blocks, they cannot be in the root.", index: rule.index, filename: rule.currentFileInfo ? rule.currentFileInfo.filename : null}; } rules.push(rule.toCSS(env)); } else if (rule.value && !rule.variable) { rules.push(rule.value.toString()); } } } // Remove last semicolon if (env.compress && rules.length) { rule = rules[rules.length - 1]; if (rule.charAt(rule.length - 1) === ';') { rules[rules.length - 1] = rule.substring(0, rule.length - 1); } } rulesets = rulesets.join(''); // If this is the root node, we don't render // a selector, or {}. // Otherwise, only output if this ruleset has rules. if (this.root) { css.push(rules.join(env.compress ? '' : '\n')); } else { if (rules.length > 0) { debugInfo = tree.debugInfo(env, this); selector = this.paths.map(function (p) { return p.map(function (s) { return s.toCSS(env); }).join('').trim(); }).join(env.compress ? ',' : ',\n'); // Remove duplicates for (var i = rules.length - 1; i >= 0; i--) { if (rules[i].slice(0, 2) === "/*" || _rules.indexOf(rules[i]) === -1) { _rules.unshift(rules[i]); } } rules = _rules; css.push(debugInfo + selector + (env.compress ? '{' : ' {\n ') + rules.join(env.compress ? '' : '\n ') + (env.compress ? '}' : '\n}\n')); } } css.push(rulesets); return css.join('') + (env.compress ? '\n' : ''); }, joinSelectors: function (paths, context, selectors) { for (var s = 0; s < selectors.length; s++) { this.joinSelector(paths, context, selectors[s]); } }, joinSelector: function (paths, context, selector) { var i, j, k, hasParentSelector, newSelectors, el, sel, parentSel, newSelectorPath, afterParentJoin, newJoinedSelector, newJoinedSelectorEmpty, lastSelector, currentElements, selectorsMultiplied; for (i = 0; i < selector.elements.length; i++) { el = selector.elements[i]; if (el.value === '&') { hasParentSelector = true; } } if (!hasParentSelector) { if (context.length > 0) { for(i = 0; i < context.length; i++) { paths.push(context[i].concat(selector)); } } else { paths.push([selector]); } return; } // The paths are [[Selector]] // The first list is a list of comma seperated selectors // The inner list is a list of inheritance seperated selectors // e.g. // .a, .b { // .c { // } // } // == [[.a] [.c]] [[.b] [.c]] // // the elements from the current selector so far currentElements = []; // the current list of new selectors to add to the path. // We will build it up. We initiate it with one empty selector as we "multiply" the new selectors // by the parents newSelectors = [[]]; for (i = 0; i < selector.elements.length; i++) { el = selector.elements[i]; // non parent reference elements just get added if (el.value !== "&") { currentElements.push(el); } else { // the new list of selectors to add selectorsMultiplied = []; // merge the current list of non parent selector elements // on to the current list of selectors to add if (currentElements.length > 0) { this.mergeElementsOnToSelectors(currentElements, newSelectors); } // loop through our current selectors for(j = 0; j < newSelectors.length; j++) { sel = newSelectors[j]; // if we don't have any parent paths, the & might be in a mixin so that it can be used // whether there are parents or not if (context.length == 0) { // the combinator used on el should now be applied to the next element instead so that // it is not lost if (sel.length > 0) { sel[0].elements = sel[0].elements.slice(0); sel[0].elements.push(new(tree.Element)(el.combinator, '', 0)); //new Element(el.Combinator, "")); } selectorsMultiplied.push(sel); } else { // and the parent selectors for(k = 0; k < context.length; k++) { parentSel = context[k]; // We need to put the current selectors // then join the last selector's elements on to the parents selectors // our new selector path newSelectorPath = []; // selectors from the parent after the join afterParentJoin = []; newJoinedSelectorEmpty = true; //construct the joined selector - if & is the first thing this will be empty, // if not newJoinedSelector will be the last set of elements in the selector if (sel.length > 0) { newSelectorPath = sel.slice(0); lastSelector = newSelectorPath.pop(); newJoinedSelector = new(tree.Selector)(lastSelector.elements.slice(0), selector.extendList); newJoinedSelectorEmpty = false; } else { newJoinedSelector = new(tree.Selector)([], selector.extendList); } //put together the parent selectors after the join if (parentSel.length > 1) { afterParentJoin = afterParentJoin.concat(parentSel.slice(1)); } if (parentSel.length > 0) { newJoinedSelectorEmpty = false; // join the elements so far with the first part of the parent newJoinedSelector.elements.push(new(tree.Element)(el.combinator, parentSel[0].elements[0].value, 0)); newJoinedSelector.elements = newJoinedSelector.elements.concat(parentSel[0].elements.slice(1)); } if (!newJoinedSelectorEmpty) { // now add the joined selector newSelectorPath.push(newJoinedSelector); } // and the rest of the parent newSelectorPath = newSelectorPath.concat(afterParentJoin); // add that to our new set of selectors selectorsMultiplied.push(newSelectorPath); } } } // our new selectors has been multiplied, so reset the state newSelectors = selectorsMultiplied; currentElements = []; } } // if we have any elements left over (e.g. .a& .b == .b) // add them on to all the current selectors if (currentElements.length > 0) { this.mergeElementsOnToSelectors(currentElements, newSelectors); } for(i = 0; i < newSelectors.length; i++) { if (newSelectors[i].length > 0) { paths.push(newSelectors[i]); } } }, mergeElementsOnToSelectors: function(elements, selectors) { var i, sel, extendList; if (selectors.length == 0) { selectors.push([ new(tree.Selector)(elements) ]); return; } for(i = 0; i < selectors.length; i++) { sel = selectors[i]; // if the previous thing in sel is a parent this needs to join on to it if (sel.length > 0) { sel[sel.length - 1] = new(tree.Selector)(sel[sel.length - 1].elements.concat(elements), sel[sel.length - 1].extendList); } else { sel.push(new(tree.Selector)(elements)); } } } }; })(require('../tree')); (function (tree) { tree.Selector = function (elements, extendList) { this.elements = elements; this.extendList = extendList || []; }; tree.Selector.prototype = { type: "Selector", accept: function (visitor) { this.elements = visitor.visit(this.elements); this.extendList = visitor.visit(this.extendList) }, match: function (other) { var elements = this.elements, len = elements.length, oelements, olen, max, i; oelements = other.elements.slice( (other.elements.length && other.elements[0].value === "&") ? 1 : 0); olen = oelements.length; max = Math.min(len, olen); if (olen === 0 || len < olen) { return false; } else { for (i = 0; i < max; i++) { if (elements[i].value !== oelements[i].value) { return false; } } } return true; }, eval: function (env) { return new(tree.Selector)(this.elements.map(function (e) { return e.eval(env); }), this.extendList.map(function(extend) { return extend.eval(env); })); }, toCSS: function (env) { if (this._css) { return this._css } if (this.elements[0].combinator.value === "") { this._css = ' '; } else { this._css = ''; } this._css += this.elements.map(function (e) { if (typeof(e) === 'string') { return ' ' + e.trim(); } else { return e.toCSS(env); } }).join(''); return this._css; } }; })(require('../tree')); (function (tree) { tree.UnicodeDescriptor = function (value) { this.value = value; }; tree.UnicodeDescriptor.prototype = { type: "UnicodeDescriptor", toCSS: function (env) { return this.value; }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.URL = function (val, currentFileInfo) { this.value = val; this.currentFileInfo = currentFileInfo; }; tree.URL.prototype = { type: "Url", accept: function (visitor) { this.value = visitor.visit(this.value); }, toCSS: function () { return "url(" + this.value.toCSS() + ")"; }, eval: function (ctx) { var val = this.value.eval(ctx), rootpath; // Add the base path if the URL is relative rootpath = this.currentFileInfo && this.currentFileInfo.rootpath; if (rootpath && typeof val.value === "string" && ctx.isPathRelative(val.value)) { if (!val.quote) { rootpath = rootpath.replace(/[\(\)'"\s]/g, function(match) { return "\\"+match; }); } val.value = rootpath + val.value; } return new(tree.URL)(val, null); } }; })(require('../tree')); (function (tree) { tree.Value = function (value) { this.value = value; }; tree.Value.prototype = { type: "Value", accept: function (visitor) { this.value = visitor.visit(this.value); }, eval: function (env) { if (this.value.length === 1) { return this.value[0].eval(env); } else { return new(tree.Value)(this.value.map(function (v) { return v.eval(env); })); } }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS(env); }).join(env.compress ? ',' : ', '); } }; })(require('../tree')); (function (tree) { tree.Variable = function (name, index, currentFileInfo) { this.name = name, this.index = index, this.currentFileInfo = currentFileInfo }; tree.Variable.prototype = { type: "Variable", eval: function (env) { var variable, v, name = this.name; if (name.indexOf('@@') == 0) { name = '@' + new(tree.Variable)(name.slice(1)).eval(env).value; } if (this.evaluating) { throw { type: 'Name', message: "Recursive variable definition for " + name, filename: this.currentFileInfo.file, index: this.index }; } this.evaluating = true; if (variable = tree.find(env.frames, function (frame) { if (v = frame.variable(name)) { return v.value.eval(env); } })) { this.evaluating = false; return variable; } else { throw { type: 'Name', message: "variable " + name + " is undefined", filename: this.currentFileInfo.filename, index: this.index }; } } }; })(require('../tree')); (function (tree) { tree.debugInfo = function(env, ctx) { var result=""; if (env.dumpLineNumbers && !env.compress) { switch(env.dumpLineNumbers) { case 'comments': result = tree.debugInfo.asComment(ctx); break; case 'mediaquery': result = tree.debugInfo.asMediaQuery(ctx); break; case 'all': result = tree.debugInfo.asComment(ctx)+tree.debugInfo.asMediaQuery(ctx); break; } } return result; }; tree.debugInfo.asComment = function(ctx) { return '/* line ' + ctx.debugInfo.lineNumber + ', ' + ctx.debugInfo.fileName + ' */\n'; }; tree.debugInfo.asMediaQuery = function(ctx) { return '@media -sass-debug-info{filename{font-family:' + ('file://' + ctx.debugInfo.fileName).replace(/([.:/\\])/g, function(a){if(a=='\\') a = '\/'; return '\\' + a}) + '}line{font-family:\\00003' + ctx.debugInfo.lineNumber + '}}\n'; }; tree.find = function (obj, fun) { for (var i = 0, r; i < obj.length; i++) { if (r = fun.call(obj, obj[i])) { return r } } return null; }; tree.jsify = function (obj) { if (Array.isArray(obj.value) && (obj.value.length > 1)) { return '[' + obj.value.map(function (v) { return v.toCSS(false) }).join(', ') + ']'; } else { return obj.toCSS(false); } }; })(require('./tree')); (function (tree) { var parseCopyProperties = [ 'paths', // option - unmodified - paths to search for imports on 'optimization', // option - optimization level (for the chunker) 'files', // list of files that have been imported, used for import-once 'contents', // browser-only, contents of all the files 'relativeUrls', // option - whether to adjust URL's to be relative 'strictImports', // option - 'dumpLineNumbers', // option - whether to dump line numbers 'compress', // option - whether to compress 'processImports', // option - whether to process imports. if false then imports will not be imported 'syncImport', // option - whether to import synchronously 'mime', // browser only - mime type for sheet import 'currentFileInfo' // information about the current file - for error reporting and importing and making urls relative etc. ]; //currentFileInfo = { // 'relativeUrls' - option - whether to adjust URL's to be relative // 'filename' - full resolved filename of current file // 'rootpath' - path to append to normal URLs for this node // 'currentDirectory' - path to the current file, absolute // 'rootFilename' - filename of the base file // 'entryPath' = absolute path to the entry file tree.parseEnv = function(options) { copyFromOriginal(options, this, parseCopyProperties); if (!this.contents) { this.contents = {}; } if (!this.files) { this.files = {}; } if (!this.currentFileInfo) { var filename = (options && options.filename) || "input"; var entryPath = filename.replace(/[^\/\\]*$/, ""); if (options) { options.filename = null; } this.currentFileInfo = { filename: filename, relativeUrls: this.relativeUrls, rootpath: (options && options.rootpath) || "", currentDirectory: entryPath, entryPath: entryPath, rootFilename: filename }; } }; tree.parseEnv.prototype.toSheet = function (path) { var env = new tree.parseEnv(this); env.href = path; //env.title = path; env.type = this.mime; return env; }; var evalCopyProperties = [ 'silent', // whether to swallow errors and warnings 'verbose', // whether to log more activity 'compress', // whether to compress 'yuicompress', // whether to compress with the outside tool yui compressor 'ieCompat', // whether to enforce IE compatibility (IE8 data-uri) 'strictMath', // whether math has to be within parenthesis 'strictUnits' // whether units need to evaluate correctly ]; tree.evalEnv = function(options, frames) { copyFromOriginal(options, this, evalCopyProperties); this.frames = frames || []; }; tree.evalEnv.prototype.inParenthesis = function () { if (!this.parensStack) { this.parensStack = []; } this.parensStack.push(true); }; tree.evalEnv.prototype.outOfParenthesis = function () { this.parensStack.pop(); }; tree.evalEnv.prototype.isMathOn = function () { return this.strictMath ? (this.parensStack && this.parensStack.length) : true; }; tree.evalEnv.prototype.isPathRelative = function (path) { return !/^(?:[a-z-]+:|\/)/.test(path); }; //todo - do the same for the toCSS env //tree.toCSSEnv = function (options) { //}; var copyFromOriginal = function(original, destination, propertiesToCopy) { if (!original) { return; } for(var i = 0; i < propertiesToCopy.length; i++) { if (original.hasOwnProperty(propertiesToCopy[i])) { destination[propertiesToCopy[i]] = original[propertiesToCopy[i]]; } } } })(require('./tree'));(function (tree) { tree.visitor = function(implementation) { this._implementation = implementation; }; tree.visitor.prototype = { visit: function(node) { if (node instanceof Array) { return this.visitArray(node); } if (!node || !node.type) { return node; } var funcName = "visit" + node.type, func = this._implementation[funcName], visitArgs, newNode; if (func) { visitArgs = {visitDeeper: true}; newNode = func.call(this._implementation, node, visitArgs); if (this._implementation.isReplacing) { node = newNode; } } if ((!visitArgs || visitArgs.visitDeeper) && node && node.accept) { node.accept(this); } funcName = funcName + "Out"; if (this._implementation[funcName]) { this._implementation[funcName](node); } return node; }, visitArray: function(nodes) { var i, newNodes = []; for(i = 0; i < nodes.length; i++) { var evald = this.visit(nodes[i]); if (evald instanceof Array) { newNodes = newNodes.concat(evald); } else { newNodes.push(evald); } } if (this._implementation.isReplacing) { return newNodes; } return nodes; } }; })(require('./tree'));(function (tree) { tree.importVisitor = function(importer, finish, evalEnv) { this._visitor = new tree.visitor(this); this._importer = importer; this._finish = finish; this.env = evalEnv || new tree.evalEnv(); this.importCount = 0; }; tree.importVisitor.prototype = { isReplacing: true, run: function (root) { var error; try { // process the contents this._visitor.visit(root); } catch(e) { error = e; } this.isFinished = true; if (this.importCount === 0) { this._finish(error); } }, visitImport: function (importNode, visitArgs) { var importVisitor = this, evaldImportNode; if (!importNode.css) { try { evaldImportNode = importNode.evalForImport(this.env); } catch(e){ if (!e.filename) { e.index = importNode.index; e.filename = importNode.currentFileInfo.filename; } // attempt to eval properly and treat as css importNode.css = true; // if that fails, this error will be thrown importNode.error = e; } if (evaldImportNode && !evaldImportNode.css) { importNode = evaldImportNode; this.importCount++; var env = new tree.evalEnv(this.env, this.env.frames.slice(0)); this._importer.push(importNode.getPath(), importNode.currentFileInfo, function (e, root, imported) { if (e && !e.filename) { e.index = importNode.index; e.filename = importNode.currentFileInfo.filename; } if (imported && !importNode.options.multiple) { importNode.skip = imported; } var subFinish = function(e) { importVisitor.importCount--; if (importVisitor.importCount === 0 && importVisitor.isFinished) { importVisitor._finish(e); } }; if (root) { importNode.root = root; new(tree.importVisitor)(importVisitor._importer, subFinish, env) .run(root); } else { subFinish(); } }); } } visitArgs.visitDeeper = false; return importNode; }, visitRule: function (ruleNode, visitArgs) { visitArgs.visitDeeper = false; return ruleNode; }, visitDirective: function (directiveNode, visitArgs) { this.env.frames.unshift(directiveNode); return directiveNode; }, visitDirectiveOut: function (directiveNode) { this.env.frames.shift(); }, visitMixinDefinition: function (mixinDefinitionNode, visitArgs) { this.env.frames.unshift(mixinDefinitionNode); return mixinDefinitionNode; }, visitMixinDefinitionOut: function (mixinDefinitionNode) { this.env.frames.shift(); }, visitRuleset: function (rulesetNode, visitArgs) { this.env.frames.unshift(rulesetNode); return rulesetNode; }, visitRulesetOut: function (rulesetNode) { this.env.frames.shift(); }, visitMedia: function (mediaNode, visitArgs) { this.env.frames.unshift(mediaNode.ruleset); return mediaNode; }, visitMediaOut: function (mediaNode) { this.env.frames.shift(); } }; })(require('./tree'));(function (tree) { tree.joinSelectorVisitor = function() { this.contexts = [[]]; this._visitor = new tree.visitor(this); }; tree.joinSelectorVisitor.prototype = { run: function (root) { return this._visitor.visit(root); }, visitRule: function (ruleNode, visitArgs) { visitArgs.visitDeeper = false; }, visitMixinDefinition: function (mixinDefinitionNode, visitArgs) { visitArgs.visitDeeper = false; }, visitRuleset: function (rulesetNode, visitArgs) { var context = this.contexts[this.contexts.length - 1]; var paths = []; this.contexts.push(paths); if (! rulesetNode.root) { rulesetNode.joinSelectors(paths, context, rulesetNode.selectors); rulesetNode.paths = paths; } }, visitRulesetOut: function (rulesetNode) { this.contexts.length = this.contexts.length - 1; }, visitMedia: function (mediaNode, visitArgs) { var context = this.contexts[this.contexts.length - 1]; mediaNode.ruleset.root = (context.length === 0 || context[0].multiMedia); } }; })(require('./tree'));(function (tree) { tree.extendFinderVisitor = function() { this._visitor = new tree.visitor(this); this.contexts = []; this.allExtendsStack = [[]]; }; tree.extendFinderVisitor.prototype = { run: function (root) { root = this._visitor.visit(root); root.allExtends = this.allExtendsStack[0]; return root; }, visitRule: function (ruleNode, visitArgs) { visitArgs.visitDeeper = false; }, visitMixinDefinition: function (mixinDefinitionNode, visitArgs) { visitArgs.visitDeeper = false; }, visitRuleset: function (rulesetNode, visitArgs) { if (rulesetNode.root) { return; } var i, j, extend, allSelectorsExtendList = [], extendList; // get &:extend(.a); rules which apply to all selectors in this ruleset for(i = 0; i < rulesetNode.rules.length; i++) { if (rulesetNode.rules[i] instanceof tree.Extend) { allSelectorsExtendList.push(rulesetNode.rules[i]); } } // now find every selector and apply the extends that apply to all extends // and the ones which apply to an individual extend for(i = 0; i < rulesetNode.paths.length; i++) { var selectorPath = rulesetNode.paths[i], selector = selectorPath[selectorPath.length-1]; extendList = selector.extendList.slice(0).concat(allSelectorsExtendList).map(function(allSelectorsExtend) { return allSelectorsExtend.clone(); }); for(j = 0; j < extendList.length; j++) { this.foundExtends = true; extend = extendList[j]; extend.findSelfSelectors(selectorPath); extend.ruleset = rulesetNode; if (j === 0) { extend.firstExtendOnThisSelectorPath = true; } this.allExtendsStack[this.allExtendsStack.length-1].push(extend); } } this.contexts.push(rulesetNode.selectors); }, visitRulesetOut: function (rulesetNode) { if (!rulesetNode.root) { this.contexts.length = this.contexts.length - 1; } }, visitMedia: function (mediaNode, visitArgs) { mediaNode.allExtends = []; this.allExtendsStack.push(mediaNode.allExtends); }, visitMediaOut: function (mediaNode) { this.allExtendsStack.length = this.allExtendsStack.length - 1; }, visitDirective: function (directiveNode, visitArgs) { directiveNode.allExtends = []; this.allExtendsStack.push(directiveNode.allExtends); }, visitDirectiveOut: function (directiveNode) { this.allExtendsStack.length = this.allExtendsStack.length - 1; } }; tree.processExtendsVisitor = function() { this._visitor = new tree.visitor(this); }; tree.processExtendsVisitor.prototype = { run: function(root) { var extendFinder = new tree.extendFinderVisitor(); extendFinder.run(root); if (!extendFinder.foundExtends) { return root; } root.allExtends = root.allExtends.concat(this.doExtendChaining(root.allExtends, root.allExtends)); this.allExtendsStack = [root.allExtends]; return this._visitor.visit(root); }, doExtendChaining: function (extendsList, extendsListTarget, iterationCount) { // // chaining is different from normal extension.. if we extend an extend then we are not just copying, altering and pasting // the selector we would do normally, but we are also adding an extend with the same target selector // this means this new extend can then go and alter other extends // // this method deals with all the chaining work - without it, extend is flat and doesn't work on other extend selectors // this is also the most expensive.. and a match on one selector can cause an extension of a selector we had already processed if // we look at each selector at a time, as is done in visitRuleset var extendIndex, targetExtendIndex, matches, extendsToAdd = [], newSelector, extendVisitor = this, selectorPath, extend, targetExtend, newExtend; iterationCount = iterationCount || 0; //loop through comparing every extend with every target extend. // a target extend is the one on the ruleset we are looking at copy/edit/pasting in place // e.g. .a:extend(.b) {} and .b:extend(.c) {} then the first extend extends the second one // and the second is the target. // the seperation into two lists allows us to process a subset of chains with a bigger set, as is the // case when processing media queries for(extendIndex = 0; extendIndex < extendsList.length; extendIndex++){ for(targetExtendIndex = 0; targetExtendIndex < extendsListTarget.length; targetExtendIndex++){ extend = extendsList[extendIndex]; targetExtend = extendsListTarget[targetExtendIndex]; // look for circular references if (this.inInheritanceChain(targetExtend, extend)) { continue; } // find a match in the target extends self selector (the bit before :extend) selectorPath = [targetExtend.selfSelectors[0]]; matches = extendVisitor.findMatch(extend, selectorPath); if (matches.length) { // we found a match, so for each self selector.. extend.selfSelectors.forEach(function(selfSelector) { // process the extend as usual newSelector = extendVisitor.extendSelector(matches, selectorPath, selfSelector); // but now we create a new extend from it newExtend = new(tree.Extend)(targetExtend.selector, targetExtend.option, 0); newExtend.selfSelectors = newSelector; // add the extend onto the list of extends for that selector newSelector[newSelector.length-1].extendList = [newExtend]; // record that we need to add it. extendsToAdd.push(newExtend); newExtend.ruleset = targetExtend.ruleset; //remember its parents for circular references newExtend.parents = [targetExtend, extend]; // only process the selector once.. if we have :extend(.a,.b) then multiple // extends will look at the same selector path, so when extending // we know that any others will be duplicates in terms of what is added to the css if (targetExtend.firstExtendOnThisSelectorPath) { newExtend.firstExtendOnThisSelectorPath = true; targetExtend.ruleset.paths.push(newSelector); } }); } } } if (extendsToAdd.length) { // try to detect circular references to stop a stack overflow. // may no longer be needed. this.extendChainCount++; if (iterationCount > 100) { var selectorOne = "{unable to calculate}"; var selectorTwo = "{unable to calculate}"; try { selectorOne = extendsToAdd[0].selfSelectors[0].toCSS(); selectorTwo = extendsToAdd[0].selector.toCSS(); } catch(e) {} throw {message: "extend circular reference detected. One of the circular extends is currently:"+selectorOne+":extend(" + selectorTwo+")"}; } // now process the new extends on the existing rules so that we can handle a extending b extending c ectending d extending e... return extendsToAdd.concat(extendVisitor.doExtendChaining(extendsToAdd, extendsListTarget, iterationCount+1)); } else { return extendsToAdd; } }, inInheritanceChain: function (possibleParent, possibleChild) { if (possibleParent === possibleChild) { return true; } if (possibleChild.parents) { if (this.inInheritanceChain(possibleParent, possibleChild.parents[0])) { return true; } if (this.inInheritanceChain(possibleParent, possibleChild.parents[1])) { return true; } } return false; }, visitRule: function (ruleNode, visitArgs) { visitArgs.visitDeeper = false; }, visitMixinDefinition: function (mixinDefinitionNode, visitArgs) { visitArgs.visitDeeper = false; }, visitSelector: function (selectorNode, visitArgs) { visitArgs.visitDeeper = false; }, visitRuleset: function (rulesetNode, visitArgs) { if (rulesetNode.root) { return; } var matches, pathIndex, extendIndex, allExtends = this.allExtendsStack[this.allExtendsStack.length-1], selectorsToAdd = [], extendVisitor = this, selectorPath; // look at each selector path in the ruleset, find any extend matches and then copy, find and replace for(extendIndex = 0; extendIndex < allExtends.length; extendIndex++) { for(pathIndex = 0; pathIndex < rulesetNode.paths.length; pathIndex++) { selectorPath = rulesetNode.paths[pathIndex]; // extending extends happens initially, before the main pass if (selectorPath[selectorPath.length-1].extendList.length) { continue; } matches = this.findMatch(allExtends[extendIndex], selectorPath); if (matches.length) { allExtends[extendIndex].selfSelectors.forEach(function(selfSelector) { selectorsToAdd.push(extendVisitor.extendSelector(matches, selectorPath, selfSelector)); }); } } } rulesetNode.paths = rulesetNode.paths.concat(selectorsToAdd); }, findMatch: function (extend, haystackSelectorPath) { // // look through the haystack selector path to try and find the needle - extend.selector // returns an array of selector matches that can then be replaced // var haystackSelectorIndex, hackstackSelector, hackstackElementIndex, haystackElement, targetCombinator, i, extendVisitor = this, needleElements = extend.selector.elements, potentialMatches = [], potentialMatch, matches = []; // loop through the haystack elements for(haystackSelectorIndex = 0; haystackSelectorIndex < haystackSelectorPath.length; haystackSelectorIndex++) { hackstackSelector = haystackSelectorPath[haystackSelectorIndex]; for(hackstackElementIndex = 0; hackstackElementIndex < hackstackSelector.elements.length; hackstackElementIndex++) { haystackElement = hackstackSelector.elements[hackstackElementIndex]; // if we allow elements before our match we can add a potential match every time. otherwise only at the first element. if (extend.allowBefore || (haystackSelectorIndex == 0 && hackstackElementIndex == 0)) { potentialMatches.push({pathIndex: haystackSelectorIndex, index: hackstackElementIndex, matched: 0, initialCombinator: haystackElement.combinator}); } for(i = 0; i < potentialMatches.length; i++) { potentialMatch = potentialMatches[i]; // selectors add " " onto the first element. When we use & it joins the selectors together, but if we don't // then each selector in haystackSelectorPath has a space before it added in the toCSS phase. so we need to work out // what the resulting combinator will be targetCombinator = haystackElement.combinator.value; if (targetCombinator == '' && hackstackElementIndex === 0) { targetCombinator = ' '; } // if we don't match, null our match to indicate failure if (!extendVisitor.isElementValuesEqual(needleElements[potentialMatch.matched].value, haystackElement.value) || (potentialMatch.matched > 0 && needleElements[potentialMatch.matched].combinator.value !== targetCombinator)) { potentialMatch = null; } else { potentialMatch.matched++; } // if we are still valid and have finished, test whether we have elements after and whether these are allowed if (potentialMatch) { potentialMatch.finished = potentialMatch.matched === needleElements.length; if (potentialMatch.finished && (!extend.allowAfter && (hackstackElementIndex+1 < hackstackSelector.elements.length || haystackSelectorIndex+1 < haystackSelectorPath.length))) { potentialMatch = null; } } // if null we remove, if not, we are still valid, so either push as a valid match or continue if (potentialMatch) { if (potentialMatch.finished) { potentialMatch.length = needleElements.length; potentialMatch.endPathIndex = haystackSelectorIndex; potentialMatch.endPathElementIndex = hackstackElementIndex + 1; // index after end of match potentialMatches.length = 0; // we don't allow matches to overlap, so start matching again matches.push(potentialMatch); } } else { potentialMatches.splice(i, 1); i--; } } } } return matches; }, isElementValuesEqual: function(elementValue1, elementValue2) { if (typeof elementValue1 === "string" || typeof elementValue2 === "string") { return elementValue1 === elementValue2; } if (elementValue1 instanceof tree.Attribute) { if (elementValue1.op !== elementValue2.op || elementValue1.key !== elementValue2.key) { return false; } if (!elementValue1.value || !elementValue2.value) { if (elementValue1.value || elementValue2.value) { return false; } return true; } elementValue1 = elementValue1.value.value || elementValue1.value; elementValue2 = elementValue2.value.value || elementValue2.value; return elementValue1 === elementValue2; } return false; }, extendSelector:function (matches, selectorPath, replacementSelector) { //for a set of matches, replace each match with the replacement selector var currentSelectorPathIndex = 0, currentSelectorPathElementIndex = 0, path = [], matchIndex, selector, firstElement, match; for (matchIndex = 0; matchIndex < matches.length; matchIndex++) { match = matches[matchIndex]; selector = selectorPath[match.pathIndex]; firstElement = new tree.Element( match.initialCombinator, replacementSelector.elements[0].value, replacementSelector.elements[0].index ); if (match.pathIndex > currentSelectorPathIndex && currentSelectorPathElementIndex > 0) { path[path.length - 1].elements = path[path.length - 1].elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex)); currentSelectorPathElementIndex = 0; currentSelectorPathIndex++; } path = path.concat(selectorPath.slice(currentSelectorPathIndex, match.pathIndex)); path.push(new tree.Selector( selector.elements .slice(currentSelectorPathElementIndex, match.index) .concat([firstElement]) .concat(replacementSelector.elements.slice(1)) )); currentSelectorPathIndex = match.endPathIndex; currentSelectorPathElementIndex = match.endPathElementIndex; if (currentSelectorPathElementIndex >= selector.elements.length) { currentSelectorPathElementIndex = 0; currentSelectorPathIndex++; } } if (currentSelectorPathIndex < selectorPath.length && currentSelectorPathElementIndex > 0) { path[path.length - 1].elements = path[path.length - 1].elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex)); currentSelectorPathElementIndex = 0; currentSelectorPathIndex++; } path = path.concat(selectorPath.slice(currentSelectorPathIndex, selectorPath.length)); return path; }, visitRulesetOut: function (rulesetNode) { }, visitMedia: function (mediaNode, visitArgs) { var newAllExtends = mediaNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length-1]); newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, mediaNode.allExtends)); this.allExtendsStack.push(newAllExtends); }, visitMediaOut: function (mediaNode) { this.allExtendsStack.length = this.allExtendsStack.length - 1; }, visitDirective: function (directiveNode, visitArgs) { var newAllExtends = directiveNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length-1]); newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, directiveNode.allExtends)); this.allExtendsStack.push(newAllExtends); }, visitDirectiveOut: function (directiveNode) { this.allExtendsStack.length = this.allExtendsStack.length - 1; } }; })(require('./tree'));// // browser.js - client-side engine // var isFileProtocol = /^(file|chrome(-extension)?|resource|qrc|app):/.test(location.protocol); less.env = less.env || (location.hostname == '127.0.0.1' || location.hostname == '0.0.0.0' || location.hostname == 'localhost' || location.port.length > 0 || isFileProtocol ? 'development' : 'production'); // Load styles asynchronously (default: false) // // This is set to `false` by default, so that the body // doesn't start loading before the stylesheets are parsed. // Setting this to `true` can result in flickering. // less.async = less.async || false; less.fileAsync = less.fileAsync || false; // Interval between watch polls less.poll = less.poll || (isFileProtocol ? 1000 : 1500); //Setup user functions if (less.functions) { for(var func in less.functions) { less.tree.functions[func] = less.functions[func]; } } var dumpLineNumbers = /!dumpLineNumbers:(comments|mediaquery|all)/.exec(location.hash); if (dumpLineNumbers) { less.dumpLineNumbers = dumpLineNumbers[1]; } // // Watch mode // less.watch = function () { if (!less.watchMode ){ less.env = 'development'; initRunningMode(); } return this.watchMode = true }; less.unwatch = function () {clearInterval(less.watchTimer); return this.watchMode = false; }; function initRunningMode(){ if (less.env === 'development') { less.optimization = 0; less.watchTimer = setInterval(function () { if (less.watchMode) { loadStyleSheets(function (e, root, _, sheet, env) { if (e) { error(e, sheet.href); } else if (root) { createCSS(root.toCSS(less), sheet, env.lastModified); } }); } }, less.poll); } else { less.optimization = 3; } } if (/!watch/.test(location.hash)) { less.watch(); } var cache = null; if (less.env != 'development') { try { cache = (typeof(window.localStorage) === 'undefined') ? null : window.localStorage; } catch (_) {} } // // Get all tags with the 'rel' attribute set to "stylesheet/less" // var links = document.getElementsByTagName('link'); var typePattern = /^text\/(x-)?less$/; less.sheets = []; for (var i = 0; i < links.length; i++) { if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) && (links[i].type.match(typePattern)))) { less.sheets.push(links[i]); } } // // With this function, it's possible to alter variables and re-render // CSS without reloading less-files // var session_cache = ''; less.modifyVars = function(record) { var str = session_cache; for (var name in record) { str += ((name.slice(0,1) === '@')? '' : '@') + name +': '+ ((record[name].slice(-1) === ';')? record[name] : record[name] +';'); } new(less.Parser)(new less.tree.parseEnv(less)).parse(str, function (e, root) { if (e) { error(e, "session_cache"); } else { createCSS(root.toCSS(less), less.sheets[less.sheets.length - 1]); } }); }; less.refresh = function (reload) { var startTime, endTime; startTime = endTime = new(Date); loadStyleSheets(function (e, root, _, sheet, env) { if (e) { return error(e, sheet.href); } if (env.local) { log("loading " + sheet.href + " from cache."); } else { log("parsed " + sheet.href + " successfully."); createCSS(root.toCSS(less), sheet, env.lastModified); } log("css for " + sheet.href + " generated in " + (new(Date) - endTime) + 'ms'); (env.remaining === 0) && log("css generated in " + (new(Date) - startTime) + 'ms'); endTime = new(Date); }, reload); loadStyles(); }; less.refreshStyles = loadStyles; less.refresh(less.env === 'development'); function loadStyles() { var styles = document.getElementsByTagName('style'); for (var i = 0; i < styles.length; i++) { if (styles[i].type.match(typePattern)) { var env = new less.tree.parseEnv(less); env.filename = document.location.href.replace(/#.*$/, ''); new(less.Parser)(env).parse(styles[i].innerHTML || '', function (e, cssAST) { if (e) { return error(e, "inline"); } var css = cssAST.toCSS(less); var style = styles[i]; style.type = 'text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.innerHTML = css; } }); } } } function loadStyleSheets(callback, reload) { for (var i = 0; i < less.sheets.length; i++) { loadStyleSheet(less.sheets[i], callback, reload, less.sheets.length - (i + 1)); } } function pathDiff(url, baseUrl) { // diff between two paths to create a relative path var urlParts = extractUrlParts(url), baseUrlParts = extractUrlParts(baseUrl), i, max, urlDirectories, baseUrlDirectories, diff = ""; if (urlParts.hostPart !== baseUrlParts.hostPart) { return ""; } max = Math.max(baseUrlParts.directories.length, urlParts.directories.length); for(i = 0; i < max; i++) { if (baseUrlParts.directories[i] !== urlParts.directories[i]) { break; } } baseUrlDirectories = baseUrlParts.directories.slice(i); urlDirectories = urlParts.directories.slice(i); for(i = 0; i < baseUrlDirectories.length-1; i++) { diff += "../"; } for(i = 0; i < urlDirectories.length-1; i++) { diff += urlDirectories[i] + "/"; } return diff; } function extractUrlParts(url, baseUrl) { // urlParts[1] = protocol&hostname || / // urlParts[2] = / if path relative to host base // urlParts[3] = directories // urlParts[4] = filename // urlParts[5] = parameters var urlPartsRegex = /^((?:[a-z-]+:)?\/+?(?:[^\/\?#]*\/)|([\/\\]))?((?:[^\/\\\?#]*[\/\\])*)([^\/\\\?#]*)([#\?].*)?$/, urlParts = url.match(urlPartsRegex), returner = {}, directories = [], i, baseUrlParts; if (!urlParts) { throw new Error("Could not parse sheet href - '"+url+"'"); } // Stylesheets in IE don't always return the full path if (!urlParts[1] || urlParts[2]) { baseUrlParts = baseUrl.match(urlPartsRegex); if (!baseUrlParts) { throw new Error("Could not parse page url - '"+baseUrl+"'"); } urlParts[1] = urlParts[1] || baseUrlParts[1] || ""; if (!urlParts[2]) { urlParts[3] = baseUrlParts[3] + urlParts[3]; } } if (urlParts[3]) { directories = urlParts[3].replace("\\", "/").split("/"); // extract out . before .. so .. doesn't absorb a non-directory for(i = 0; i < directories.length; i++) { if (directories[i] === ".") { directories.splice(i, 1); i -= 1; } } for(i = 0; i < directories.length; i++) { if (directories[i] === ".." && i > 0) { directories.splice(i-1, 2); i -= 2; } } } returner.hostPart = urlParts[1]; returner.directories = directories; returner.path = urlParts[1] + directories.join("/"); returner.fileUrl = returner.path + (urlParts[4] || ""); returner.url = returner.fileUrl + (urlParts[5] || ""); return returner; } function loadStyleSheet(sheet, callback, reload, remaining) { // sheet may be set to the stylesheet for the initial load or a collection of properties including // some env variables for imports var hrefParts = extractUrlParts(sheet.href, window.location.href); var href = hrefParts.url; var css = cache && cache.getItem(href); var timestamp = cache && cache.getItem(href + ':timestamp'); var styles = { css: css, timestamp: timestamp }; var env; var newFileInfo = { relativeUrls: less.relativeUrls, currentDirectory: hrefParts.path, filename: href }; if (sheet instanceof less.tree.parseEnv) { env = new less.tree.parseEnv(sheet); newFileInfo.entryPath = env.currentFileInfo.entryPath; newFileInfo.rootpath = env.currentFileInfo.rootpath; newFileInfo.rootFilename = env.currentFileInfo.rootFilename; } else { env = new less.tree.parseEnv(less); env.mime = sheet.type; newFileInfo.entryPath = hrefParts.path; newFileInfo.rootpath = less.rootpath || hrefParts.path; newFileInfo.rootFilename = href; } if (env.relativeUrls) { //todo - this relies on option being set on less object rather than being passed in as an option // - need an originalRootpath if (less.rootpath) { newFileInfo.rootpath = extractUrlParts(less.rootpath + pathDiff(hrefParts.path, newFileInfo.entryPath)).path; } else { newFileInfo.rootpath = hrefParts.path; } } xhr(href, sheet.type, function (data, lastModified) { // Store data this session session_cache += data.replace(/@import .+?;/ig, ''); if (!reload && styles && lastModified && (new(Date)(lastModified).valueOf() === new(Date)(styles.timestamp).valueOf())) { // Use local copy createCSS(styles.css, sheet); callback(null, null, data, sheet, { local: true, remaining: remaining }, href); } else { // Use remote copy (re-parse) try { env.contents[href] = data; // Updating content cache env.paths = [hrefParts.path]; env.currentFileInfo = newFileInfo; new(less.Parser)(env).parse(data, function (e, root) { if (e) { return callback(e, null, null, sheet); } try { callback(e, root, data, sheet, { local: false, lastModified: lastModified, remaining: remaining }, href); //TODO - there must be a better way? A generic less-to-css function that can both call error //and removeNode where appropriate //should also add tests if (env.currentFileInfo.rootFilename === href) { removeNode(document.getElementById('less-error-message:' + extractId(href))); } } catch (e) { callback(e, null, null, sheet); } }); } catch (e) { callback(e, null, null, sheet); } } }, function (status, url) { callback({ type: 'File', message: "'" + url + "' wasn't found (" + status + ")" }, null, null, sheet); }); } function extractId(href) { return href.replace(/^[a-z-]+:\/+?[^\/]+/, '' ) // Remove protocol & domain .replace(/^\//, '' ) // Remove root / .replace(/\.[a-zA-Z]+$/, '' ) // Remove simple extension .replace(/[^\.\w-]+/g, '-') // Replace illegal characters .replace(/\./g, ':'); // Replace dots with colons(for valid id) } function createCSS(styles, sheet, lastModified) { // Strip the query-string var href = sheet.href || ''; // If there is no title set, use the filename, minus the extension var id = 'less:' + (sheet.title || extractId(href)); // If this has already been inserted into the DOM, we may need to replace it var oldCss = document.getElementById(id); var keepOldCss = false; // Create a new stylesheet node for insertion or (if necessary) replacement var css = document.createElement('style'); css.setAttribute('type', 'text/css'); if (sheet.media) { css.setAttribute('media', sheet.media); } css.id = id; if (css.styleSheet) { // IE try { css.styleSheet.cssText = styles; } catch (e) { throw new(Error)("Couldn't reassign styleSheet.cssText."); } } else { css.appendChild(document.createTextNode(styles)); // If new contents match contents of oldCss, don't replace oldCss keepOldCss = (oldCss !== null && oldCss.childNodes.length > 0 && css.childNodes.length > 0 && oldCss.firstChild.nodeValue === css.firstChild.nodeValue); } var head = document.getElementsByTagName('head')[0]; // If there is no oldCss, just append; otherwise, only append if we need // to replace oldCss with an updated stylesheet if (oldCss == null || keepOldCss === false) { var nextEl = sheet && sheet.nextSibling || null; (nextEl || document.getElementsByTagName('head')[0]).parentNode.insertBefore(css, nextEl); } if (oldCss && keepOldCss === false) { head.removeChild(oldCss); } // Don't update the local store if the file wasn't modified if (lastModified && cache) { log('saving ' + href + ' to cache.'); try { cache.setItem(href, styles); cache.setItem(href + ':timestamp', lastModified); } catch(e) { //TODO - could do with adding more robust error handling log('failed to save'); } } } function xhr(url, type, callback, errback) { var xhr = getXMLHttpRequest(); var async = isFileProtocol ? less.fileAsync : less.async; if (typeof(xhr.overrideMimeType) === 'function') { xhr.overrideMimeType('text/css'); } xhr.open('GET', url, async); xhr.setRequestHeader('Accept', type || 'text/x-less, text/css; q=0.9, */*; q=0.5'); xhr.send(null); if (isFileProtocol && !less.fileAsync) { if (xhr.status === 0 || (xhr.status >= 200 && xhr.status < 300)) { callback(xhr.responseText); } else { errback(xhr.status, url); } } else if (async) { xhr.onreadystatechange = function () { if (xhr.readyState == 4) { handleResponse(xhr, callback, errback); } }; } else { handleResponse(xhr, callback, errback); } function handleResponse(xhr, callback, errback) { if (xhr.status >= 200 && xhr.status < 300) { callback(xhr.responseText, xhr.getResponseHeader("Last-Modified")); } else if (typeof(errback) === 'function') { errback(xhr.status, url); } } } function getXMLHttpRequest() { if (window.XMLHttpRequest) { return new(XMLHttpRequest); } else { try { return new(ActiveXObject)("MSXML2.XMLHTTP.3.0"); } catch (e) { log("browser doesn't support AJAX."); return null; } } } function removeNode(node) { return node && node.parentNode.removeChild(node); } function log(str) { if (less.env == 'development' && typeof(console) !== "undefined") { console.log('less: ' + str) } } function error(e, rootHref) { var id = 'less-error-message:' + extractId(rootHref || ""); var template = '
  • {content}
  • '; var elem = document.createElement('div'), timer, content, error = []; var filename = e.filename || rootHref; var filenameNoPath = filename.match(/([^\/]+(\?.*)?)$/)[1]; elem.id = id; elem.className = "less-error-message"; content = '

    ' + (e.type || "Syntax") + "Error: " + (e.message || 'There is an error in your .less file') + '

    ' + '

    in ' + filenameNoPath + " "; var errorline = function (e, i, classname) { if (e.extract[i] != undefined) { error.push(template.replace(/\{line\}/, (parseInt(e.line) || 0) + (i - 1)) .replace(/\{class\}/, classname) .replace(/\{content\}/, e.extract[i])); } }; if (e.extract) { errorline(e, 0, ''); errorline(e, 1, 'line'); errorline(e, 2, ''); content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':

    ' + '
      ' + error.join('') + '
    '; } else if (e.stack) { content += '
    ' + e.stack.split('\n').slice(1).join('
    '); } elem.innerHTML = content; // CSS for error messages createCSS([ '.less-error-message ul, .less-error-message li {', 'list-style-type: none;', 'margin-right: 15px;', 'padding: 4px 0;', 'margin: 0;', '}', '.less-error-message label {', 'font-size: 12px;', 'margin-right: 15px;', 'padding: 4px 0;', 'color: #cc7777;', '}', '.less-error-message pre {', 'color: #dd6666;', 'padding: 4px 0;', 'margin: 0;', 'display: inline-block;', '}', '.less-error-message pre.line {', 'color: #ff0000;', '}', '.less-error-message h3 {', 'font-size: 20px;', 'font-weight: bold;', 'padding: 15px 0 5px 0;', 'margin: 0;', '}', '.less-error-message a {', 'color: #10a', '}', '.less-error-message .error {', 'color: red;', 'font-weight: bold;', 'padding-bottom: 2px;', 'border-bottom: 1px dashed red;', '}' ].join('\n'), { title: 'error-message' }); elem.style.cssText = [ "font-family: Arial, sans-serif", "border: 1px solid #e00", "background-color: #eee", "border-radius: 5px", "-webkit-border-radius: 5px", "-moz-border-radius: 5px", "color: #e00", "padding: 15px", "margin-bottom: 15px" ].join(';'); if (less.env == 'development') { timer = setInterval(function () { if (document.body) { if (document.getElementById(id)) { document.body.replaceChild(elem, document.getElementById(id)); } else { document.body.insertBefore(elem, document.body.firstChild); } clearInterval(timer); } }, 10); } } // amd.js // // Define Less as an AMD module. if (typeof define === "function" && define.amd) { define(function () { return less; } ); } })(window); less.js-1.4.2/dist/less-1.4.1.min.js000066400000000000000000002322061217256642200166030ustar00rootroot00000000000000/* * LESS - Leaner CSS v1.4.1 * http://lesscss.org * * Copyright (c) 2009-2013, Alexis Sellier * Licensed under the Apache 2.0 License. * * @licence */(function(e,t){function n(t){return e.less[t.split("/")[1]]}function f(){r.env==="development"?(r.optimization=0,r.watchTimer=setInterval(function(){r.watchMode&&g(function(e,t,n,i,s){e?k(e,i.href):t&&S(t.toCSS(r),i,s.lastModified)})},r.poll)):r.optimization=3}function m(){var e=document.getElementsByTagName("style");for(var t=0;t0&&(s.splice(o-1,2),o-=2)}return i.hostPart=r[1],i.directories=s,i.path=r[1]+s.join("/"),i.fileUrl=i.path+(r[4]||""),i.url=i.fileUrl+(r[5]||""),i}function w(t,n,i,s){var o=b(t.href,e.location.href),u=o.url,a=l&&l.getItem(u),f=l&&l.getItem(u+":timestamp"),c={css:a,timestamp:f},h,p={relativeUrls:r.relativeUrls,currentDirectory:o.path,filename:u};t instanceof r.tree.parseEnv?(h=new r.tree.parseEnv(t),p.entryPath=h.currentFileInfo.entryPath,p.rootpath=h.currentFileInfo.rootpath,p.rootFilename=h.currentFileInfo.rootFilename):(h=new r.tree.parseEnv(r),h.mime=t.type,p.entryPath=o.path,p.rootpath=r.rootpath||o.path,p.rootFilename=u),h.relativeUrls&&(r.rootpath?p.rootpath=b(r.rootpath+y(o.path,p.entryPath)).path:p.rootpath=o.path),x(u,t.type,function(e,a){v+=e.replace(/@import .+?;/ig,"");if(!i&&c&&a&&(new Date(a)).valueOf()===(new Date(c.timestamp)).valueOf())S(c.css,t),n(null,null,e,t,{local:!0,remaining:s},u);else try{h.contents[u]=e,h.paths=[o.path],h.currentFileInfo=p,(new r.Parser(h)).parse(e,function(r,i){if(r)return n(r,null,null,t);try{n(r,i,e,t,{local:!1,lastModified:a,remaining:s},u),h.currentFileInfo.rootFilename===u&&N(document.getElementById("less-error-message:"+E(u)))}catch(r){n(r,null,null,t)}})}catch(f){n(f,null,null,t)}},function(e,r){n({type:"File",message:"'"+r+"' wasn't found ("+e+")"},null,null,t)})}function E(e){return e.replace(/^[a-z-]+:\/+?[^\/]+/,"").replace(/^\//,"").replace(/\.[a-zA-Z]+$/,"").replace(/[^\.\w-]+/g,"-").replace(/\./g,":")}function S(e,t,n){var r=t.href||"",i="less:"+(t.title||E(r)),s=document.getElementById(i),o=!1,u=document.createElement("style");u.setAttribute("type","text/css"),t.media&&u.setAttribute("media",t.media),u.id=i;if(u.styleSheet)try{u.styleSheet.cssText=e}catch(a){throw new Error("Couldn't reassign styleSheet.cssText.")}else u.appendChild(document.createTextNode(e)),o=s!==null&&s.childNodes.length>0&&u.childNodes.length>0&&s.firstChild.nodeValue===u.firstChild.nodeValue;var f=document.getElementsByTagName("head")[0];if(s==null||o===!1){var c=t&&t.nextSibling||null;(c||document.getElementsByTagName("head")[0]).parentNode.insertBefore(u,c)}s&&o===!1&&f.removeChild(s);if(n&&l){C("saving "+r+" to cache.");try{l.setItem(r,e),l.setItem(r+":timestamp",n)}catch(a){C("failed to save")}}}function x(e,t,n,i){function a(t,n,r){t.status>=200&&t.status<300?n(t.responseText,t.getResponseHeader("Last-Modified")):typeof r=="function"&&r(t.status,e)}var s=T(),u=o?r.fileAsync:r.async;typeof s.overrideMimeType=="function"&&s.overrideMimeType("text/css"),s.open("GET",e,u),s.setRequestHeader("Accept",t||"text/x-less, text/css; q=0.9, */*; q=0.5"),s.send(null),o&&!r.fileAsync?s.status===0||s.status>=200&&s.status<300?n(s.responseText):i(s.status,e):u?s.onreadystatechange=function(){s.readyState==4&&a(s,n,i)}:a(s,n,i)}function T(){if(e.XMLHttpRequest)return new XMLHttpRequest;try{return new ActiveXObject("MSXML2.XMLHTTP.3.0")}catch(t){return C("browser doesn't support AJAX."),null}}function N(e){return e&&e.parentNode.removeChild(e)}function C(e){r.env=="development"&&typeof console!="undefined"&&console.log("less: "+e)}function k(e,n){var i="less-error-message:"+E(n||""),s='
  • {content}
  • ',o=document.createElement("div"),u,a,f=[],l=e.filename||n,c=l.match(/([^\/]+(\?.*)?)$/)[1];o.id=i,o.className="less-error-message",a="

    "+(e.type||"Syntax")+"Error: "+(e.message||"There is an error in your .less file")+"

    "+'

    in '+c+" ";var h=function(e,n,r){e.extract[n]!=t&&f.push(s.replace(/\{line\}/,(parseInt(e.line)||0)+(n-1)).replace(/\{class\}/,r).replace(/\{content\}/,e.extract[n]))};e.extract?(h(e,0,""),h(e,1,"line"),h(e,2,""),a+="on line "+e.line+", column "+(e.column+1)+":

    "+"
      "+f.join("")+"
    "):e.stack&&(a+="
    "+e.stack.split("\n").slice(1).join("
    ")),o.innerHTML=a,S([".less-error-message ul, .less-error-message li {","list-style-type: none;","margin-right: 15px;","padding: 4px 0;","margin: 0;","}",".less-error-message label {","font-size: 12px;","margin-right: 15px;","padding: 4px 0;","color: #cc7777;","}",".less-error-message pre {","color: #dd6666;","padding: 4px 0;","margin: 0;","display: inline-block;","}",".less-error-message pre.line {","color: #ff0000;","}",".less-error-message h3 {","font-size: 20px;","font-weight: bold;","padding: 15px 0 5px 0;","margin: 0;","}",".less-error-message a {","color: #10a","}",".less-error-message .error {","color: red;","font-weight: bold;","padding-bottom: 2px;","border-bottom: 1px dashed red;","}"].join("\n"),{title:"error-message"}),o.style.cssText=["font-family: Arial, sans-serif","border: 1px solid #e00","background-color: #eee","border-radius: 5px","-webkit-border-radius: 5px","-moz-border-radius: 5px","color: #e00","padding: 15px","margin-bottom: 15px"].join(";"),r.env=="development"&&(u=setInterval(function(){document.body&&(document.getElementById(i)?document.body.replaceChild(o,document.getElementById(i)):document.body.insertBefore(o,document.body.firstChild),clearInterval(u))},10))}var r,i,s;typeof environment=="object"&&{}.toString.call(environment)==="[object Environment]"?(typeof e=="undefined"?r={}:r=e.less={},i=r.tree={},r.mode="rhino"):typeof e=="undefined"?(r=exports,i=n("./tree"),r.mode="node"):(typeof e.less=="undefined"&&(e.less={}),r=e.less,i=e.less.tree={},r.mode="browser"),r.Parser=function(t){function m(){a=c[u],f=o,h=o}function g(){c[u]=a,o=f,h=o}function y(){o>h&&(c[u]=c[u].slice(o-h),h=o)}function b(e){var t=e.charCodeAt(0);return t===32||t===10||t===9}function w(e){var t,n,r,i,a;if(e instanceof Function)return e.call(p.parsers);if(typeof e=="string")t=s.charAt(o)===e?e:null,r=1,y();else{y();if(!(t=e.exec(c[u])))return null;r=t[0].length}if(t)return E(r),typeof t=="string"?t:t.length===1?t[0]:t}function E(e){var t=o,n=u,r=o+c[u].length,i=o+=e;while(o=0&&t.charAt(n)!=="\n";n--)r++;return{line:typeof e=="number"?(t.slice(0,e).match(/\n/g)||"").length:null,column:r}}function k(e,t,i){var s=i.currentFileInfo.filename;return r.mode!=="browser"&&r.mode!=="rhino"&&(s=n("path").resolve(s)),{lineNumber:C(e,t).line+1,fileName:s}}function L(e,t){var n=N(e,t),r=C(e.index,n),i=r.line,s=r.column,o=n.split("\n");this.type=e.type||"Syntax",this.message=e.message,this.filename=e.filename||t.currentFileInfo.filename,this.index=e.index,this.line=typeof i=="number"?i+1:null,this.callLine=e.call&&C(e.call,n).line+1,this.callExtract=o[C(e.call,n).line],this.stack=e.stack,this.column=s,this.extract=[o[i-1],o[i],o[i+1]]}var s,o,u,a,f,l,c,h,p,d=this;t instanceof i.parseEnv||(t=new i.parseEnv(t));var v=this.imports={paths:t.paths||[],queue:[],files:t.files,contents:t.contents,mime:t.mime,error:null,push:function(e,n,i){var s=this;this.queue.push(e),r.Parser.importer(e,n,function(t,n,r){s.queue.splice(s.queue.indexOf(e),1);var o=r in s.files;s.files[r]=n,t&&!s.error&&(s.error=t),i(t,n,o)},t)}};return L.prototype=new Error,L.prototype.constructor=L,this.env=t=t||{},this.optimization="optimization"in this.env?this.env.optimization:1,p={imports:v,parse:function(e,a){var f,d,v,m,g,y,b=[],E,S=null;o=u=h=l=0,s=e.replace(/\r\n/g,"\n"),s=s.replace(/^\uFEFF/,""),c=function(e){var n=0,r=/(?:@\{[\w-]+\}|[^"'`\{\}\/\(\)\\])+/g,i=/\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g,o=/"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'|`((?:[^`]|\\.)*)`/g,u=0,a,f=e[0],l;for(var c=0,h,p;c0?"missing closing `}`":"missing opening `{`",filename:t.currentFileInfo.filename},t)),e.map(function(e){return e.join("")})}([[]]);if(S)return a(new L(S,t));try{f=new i.Ruleset([],w(this.parsers.primary)),f.root=!0,f.firstRoot=!0}catch(x){return a(new L(x,t))}f.toCSS=function(e){var s,o,u;return function(s,o){s=s||{};var u,a=new i.evalEnv(s);typeof o=="object"&&!Array.isArray(o)&&(o=Object.keys(o).map(function(e){var t=o[e];return t instanceof i.Value||(t instanceof i.Expression||(t=new i.Expression([t])),t=new i.Value([t])),new i.Rule("@"+e,t,!1,0)}),a.frames=[new i.Ruleset(null,o)]);try{var f=e.call(this,a);(new i.joinSelectorVisitor).run(f),(new i.processExtendsVisitor).run(f);var l=f.toCSS({compress:Boolean(s.compress),dumpLineNumbers:t.dumpLineNumbers,strictUnits:Boolean(s.strictUnits)})}catch(c){throw new L(c,t)}return s.yuicompress&&r.mode==="node"?n("ycssmin").cssmin(l,s.maxLineLen):s.compress?l.replace(/(\s)+/g,"$1"):l}}(f.eval);if(o=0&&s.charAt(T)!=="\n";T--)N++;S={type:"Parse",message:"Unrecognised input",index:o,filename:t.currentFileInfo.filename,line:g,column:N,extract:[y[g-2],y[g-1],y[g]]}}var C=function(e){e=S||e||p.imports.error,e?(e instanceof L||(e=new L(e,t)),a(e)):a(null,f)};t.processImports!==!1?(new i.importVisitor(this.imports,C)).run(f):C()},parsers:{primary:function(){var e,t=[];while((e=w(this.extendRule)||w(this.mixin.definition)||w(this.rule)||w(this.ruleset)||w(this.mixin.call)||w(this.comment)||w(this.directive))||w(/^[\s\n]+/)||w(/^;+/))e&&t.push(e);return t},comment:function(){var e;if(s.charAt(o)!=="/")return;if(s.charAt(o+1)==="/")return new i.Comment(w(/^\/\/.*/),!0);if(e=w(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/))return new i.Comment(e)},entities:{quoted:function(){var e,n=o,r,u=o;s.charAt(n)==="~"&&(n++,r=!0);if(s.charAt(n)!=='"'&&s.charAt(n)!=="'")return;r&&w("~");if(e=w(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/))return new i.Quoted(e[0],e[1]||e[2],r,u,t.currentFileInfo)},keyword:function(){var e;if(e=w(/^[_A-Za-z-][_A-Za-z0-9-]*/))return i.colors.hasOwnProperty(e)?new i.Color(i.colors[e].slice(1)):new i.Keyword(e)},call:function(){var e,n,r,s,a=o;if(!(e=/^([\w-]+|%|progid:[\w\.]+)\(/.exec(c[u])))return;e=e[1],n=e.toLowerCase();if(n==="url")return null;o+=e.length;if(n==="alpha"){s=w(this.alpha);if(typeof s!="undefined")return s}w("("),r=w(this.entities.arguments);if(!w(")"))return;if(e)return new i.Call(e,r,a,t.currentFileInfo)},arguments:function(){var e=[],t;while(t=w(this.entities.assignment)||w(this.expression)){e.push(t);if(!w(","))break}return e},literal:function(){return w(this.entities.dimension)||w(this.entities.color)||w(this.entities.quoted)||w(this.entities.unicodeDescriptor)},assignment:function(){var e,t;if((e=w(/^\w+(?=\s?=)/i))&&w("=")&&(t=w(this.entity)))return new i.Assignment(e,t)},url:function(){var e;if(s.charAt(o)!=="u"||!w(/^url\(/))return;return e=w(this.entities.quoted)||w(this.entities.variable)||w(/^(?:(?:\\[\(\)'"])|[^\(\)'"])+/)||"",S(")"),new i.URL(e.value!=null||e instanceof i.Variable?e:new i.Anonymous(e),t.currentFileInfo)},variable:function(){var e,n=o;if(s.charAt(o)==="@"&&(e=w(/^@@?[\w-]+/)))return new i.Variable(e,n,t.currentFileInfo)},variableCurly:function(){var e,n,r=o;if(s.charAt(o)==="@"&&(n=w(/^@\{([\w-]+)\}/)))return new i.Variable("@"+n[1],r,t.currentFileInfo)},color:function(){var e;if(s.charAt(o)==="#"&&(e=w(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/)))return new i.Color(e[1])},dimension:function(){var e,t=s.charCodeAt(o);if(t>57||t<43||t===47||t==44)return;if(e=w(/^([+-]?\d*\.?\d+)(%|[a-z]+)?/))return new i.Dimension(e[1],e[2])},unicodeDescriptor:function(){var e;if(e=w(/^U\+[0-9a-fA-F?]+(\-[0-9a-fA-F?]+)?/))return new i.UnicodeDescriptor(e[0])},javascript:function(){var e,t=o,n;s.charAt(t)==="~"&&(t++,n=!0);if(s.charAt(t)!=="`")return;n&&w("~");if(e=w(/^`([^`]*)`/))return new i.JavaScript(e[1],o,n)}},variable:function(){var e;if(s.charAt(o)==="@"&&(e=w(/^(@[\w-]+)\s*:/)))return e[1]},extend:function(e){var t,n,r=o,s,u=[];if(!w(e?/^&:extend\(/:/^:extend\(/))return;do{s=null,t=[];for(;;){s=w(/^(all)(?=\s*(\)|,))/);if(s)break;n=w(this.element);if(!n)break;t.push(n)}s=s&&s[1],u.push(new i.Extend(new i.Selector(t),s,r))}while(w(","));return S(/^\)/),e&&S(/^;/),u},extendRule:function(){return this.extend(!0)},mixin:{call:function(){var e=[],n,r,u,a,f,l=o,c=s.charAt(o),h=!1;if(c!=="."&&c!=="#")return;m();while(n=w(/^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/))e.push(new i.Element(r,n,o)),r=w(">");w("(")&&(u=this.mixin.args.call(this,!0).args,S(")")),u=u||[],w(this.important)&&(h=!0);if(e.length>0&&(w(";")||T("}")))return new i.mixin.Call(e,u,l,t.currentFileInfo,h);g()},args:function(e){var t=[],n=[],r,u=[],a,f,l,c,h,p={args:null,variadic:!1};for(;;){if(e)h=w(this.expression);else{w(this.comment);if(s.charAt(o)==="."&&w(/^\.{3}/)){p.variadic=!0,w(";")&&!r&&(r=!0),(r?n:u).push({variadic:!0});break}h=w(this.entities.variable)||w(this.entities.literal)||w(this.entities.keyword)}if(!h)break;l=null,h.throwAwayComments&&h.throwAwayComments(),c=h;var d=null;if(e){if(h.value.length==1)var d=h.value[0]}else d=h;if(d&&d instanceof i.Variable)if(w(":"))t.length>0&&(r&&x("Cannot mix ; and , as delimiter types"),a=!0),c=S(this.expression),l=f=d.name;else{if(!e&&w(/^\.{3}/)){p.variadic=!0,w(";")&&!r&&(r=!0),(r?n:u).push({name:h.name,variadic:!0});break}e||(f=l=d.name,c=null)}c&&t.push(c),u.push({name:l,value:c});if(w(","))continue;if(w(";")||r)a&&x("Cannot mix ; and , as delimiter types"),r=!0,t.length>1&&(c=new i.Value(t)),n.push({name:f,value:c}),f=null,t=[],a=!1}return p.args=r?n:u,p},definition:function(){var e,t=[],n,r,u,a,f,c=!1;if(s.charAt(o)!=="."&&s.charAt(o)!=="#"||T(/^[^{]*\}/))return;m();if(n=w(/^([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/)){e=n[1];var h=this.mixin.args.call(this,!1);t=h.args,c=h.variadic,w(")")||(l=o,g()),w(this.comment),w(/^when/)&&(f=S(this.conditions,"expected condition")),r=w(this.block);if(r)return new i.mixin.Definition(e,t,r,f,c);g()}}},entity:function(){return w(this.entities.literal)||w(this.entities.variable)||w(this.entities.url)||w(this.entities.call)||w(this.entities.keyword)||w(this.entities.javascript)||w(this.comment)},end:function(){return w(";")||T("}")},alpha:function(){var e;if(!w(/^\(opacity=/i))return;if(e=w(/^\d+/)||w(this.entities.variable))return S(")"),new i.Alpha(e)},element:function(){var e,t,n,r;n=w(this.combinator),e=w(/^(?:\d+\.\d+|\d+)%/)||w(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/)||w("*")||w("&")||w(this.attribute)||w(/^\([^()@]+\)/)||w(/^[\.#](?=@)/)||w(this.entities.variableCurly),e||w("(")&&(r=w(this.selector))&&w(")")&&(e=new i.Paren(r));if(e)return new i.Element(n,e,o)},combinator:function(){var e=s.charAt(o);if(e===">"||e==="+"||e==="~"||e==="|"){o++;while(s.charAt(o).match(/\s/))o++;return new i.Combinator(e)}return s.charAt(o-1).match(/\s/)?new i.Combinator(" "):new i.Combinator(null)},selector:function(){var e,t,n=[],r,u,a=[];while((u=w(this.extend))||(t=w(this.element))){u?a.push.apply(a,u):(a.length&&x("Extend can only be used at the end of selector"),r=s.charAt(o),n.push(t),t=null);if(r==="{"||r==="}"||r===";"||r===","||r===")")break}if(n.length>0)return new i.Selector(n,a);a.length&&x("Extend must be used to extend a selector, it cannot be used on its own")},attribute:function(){var e="",t,n,r;if(!w("["))return;(t=w(this.entities.variableCurly))||(t=S(/^(?:[_A-Za-z0-9-\*]*\|)?(?:[_A-Za-z0-9-]|\\.)+/));if(r=w(/^[|~*$^]?=/))n=w(this.entities.quoted)||w(/^[\w-]+/)||w(this.entities.variableCurly);return S("]"),new i.Attribute(t,r,n)},block:function(){var e;if(w("{")&&(e=w(this.primary))&&w("}"))return e},ruleset:function(){var e=[],n,r,u;m(),t.dumpLineNumbers&&(u=k(o,s,t));while(n=w(this.selector)){e.push(n),w(this.comment);if(!w(","))break;w(this.comment)}if(e.length>0&&(r=w(this.block))){var a=new i.Ruleset(e,r,t.strictImports);return t.dumpLineNumbers&&(a.debugInfo=u),a}l=o,g()},rule:function(e){var n,r,u=s.charAt(o),a;m();if(u==="."||u==="#"||u==="&")return;if(n=w(this.variable)||w(this.property)){r=!e&&(t.compress||n.charAt(0)==="@")?w(this.value)||w(this.anonymousValue):w(this.anonymousValue)||w(this.value),a=w(this.important);if(r&&w(this.end))return new i.Rule(n,r,a,f,t.currentFileInfo);l=o,g();if(r&&!e)return this.rule(!0)}},anonymousValue:function(){var e;if(e=/^([^@+\/'"*`(;{}-]*);/.exec(c[u]))return o+=e[0].length-1,new i.Anonymous(e[1])},"import":function(){var e,n,r=o;m();var s=w(/^@import?\s+/),u=(s?w(this.importOptions):null)||{};if(s&&(e=w(this.entities.quoted)||w(this.entities.url))){n=w(this.mediaFeatures);if(w(";"))return n=n&&new i.Value(n),new i.Import(e,n,u,r,t.currentFileInfo)}g()},importOptions:function(){var e,t={},n,r;if(!w("("))return null;do if(e=w(this.importOption)){n=e,r=!0;switch(n){case"css":n="less",r=!1;break;case"once":n="multiple",r=!1}t[n]=r;if(!w(","))break}while(e);return S(")"),t},importOption:function(){var e=w(/^(less|css|multiple|once)/);if(e)return e[1]},mediaFeature:function(){var e,n,r=[];do if(e=w(this.entities.keyword))r.push(e);else if(w("(")){n=w(this.property),e=w(this.value);if(!w(")"))return null;if(n&&e)r.push(new i.Paren(new i.Rule(n,e,null,o,t.currentFileInfo,!0)));else{if(!e)return null;r.push(new i.Paren(e))}}while(e);if(r.length>0)return new i.Expression(r)},mediaFeatures:function(){var e,t=[];do if(e=w(this.mediaFeature)){t.push(e);if(!w(","))break}else if(e=w(this.entities.variable)){t.push(e);if(!w(","))break}while(e);return t.length>0?t:null},media:function(){var e,n,r,u;t.dumpLineNumbers&&(u=k(o,s,t));if(w(/^@media/)){e=w(this.mediaFeatures);if(n=w(this.block))return r=new i.Media(n,e),t.dumpLineNumbers&&(r.debugInfo=u),r}},directive:function(){var e,n,r,u,a,f,l,c,h,p;if(s.charAt(o)!=="@")return;if(n=w(this["import"])||w(this.media))return n;m(),e=w(/^@[a-z-]+/);if(!e)return;l=e,e.charAt(1)=="-"&&e.indexOf("-",2)>0&&(l="@"+e.slice(e.indexOf("-",2)+1));switch(l){case"@font-face":c=!0;break;case"@viewport":case"@top-left":case"@top-left-corner":case"@top-center":case"@top-right":case"@top-right-corner":case"@bottom-left":case"@bottom-left-corner":case"@bottom-center":case"@bottom-right":case"@bottom-right-corner":case"@left-top":case"@left-middle":case"@left-bottom":case"@right-top":case"@right-middle":case"@right-bottom":c=!0;break;case"@page":case"@document":case"@supports":case"@keyframes":c=!0,h=!0;break;case"@namespace":p=!0}h&&(e+=" "+(w(/^[^{]+/)||"").trim());if(c){if(r=w(this.block))return new i.Directive(e,r)}else if((n=p?w(this.expression):w(this.entity))&&w(";")){var d=new i.Directive(e,n);return t.dumpLineNumbers&&(d.debugInfo=k(o,s,t)),d}g()},value:function(){var e,t=[],n;while(e=w(this.expression)){t.push(e);if(!w(","))break}if(t.length>0)return new i.Value(t)},important:function(){if(s.charAt(o)==="!")return w(/^! *important/)},sub:function(){var e,t;if(w("("))if(e=w(this.addition))return t=new i.Expression([e]),S(")"),t.parens=!0,t},multiplication:function(){var e,t,n,r,u,a=[];if(e=w(this.operand)){u=b(s.charAt(o-1));while(!T(/^\/[*\/]/)&&(n=w("/")||w("*"))){if(!(t=w(this.operand)))break;e.parensInOp=!0,t.parensInOp=!0,r=new i.Operation(n,[r||e,t],u),u=b(s.charAt(o-1))}return r||e}},addition:function(){var e,t,n,r,u;if(e=w(this.multiplication)){u=b(s.charAt(o-1));while((n=w(/^[-+]\s+/)||!u&&(w("+")||w("-")))&&(t=w(this.multiplication)))e.parensInOp=!0,t.parensInOp=!0,r=new i.Operation(n,[r||e,t],u),u=b(s.charAt(o-1));return r||e}},conditions:function(){var e,t,n=o,r;if(e=w(this.condition)){while(w(",")&&(t=w(this.condition)))r=new i.Condition("or",r||e,t,n);return r||e}},condition:function(){var e,t,n,r,s=o,u=!1;w(/^not/)&&(u=!0),S("(");if(e=w(this.addition)||w(this.entities.keyword)||w(this.entities.quoted))return(r=w(/^(?:>=|=<|[<=>])/))?(t=w(this.addition)||w(this.entities.keyword)||w(this.entities.quoted))?n=new i.Condition(r,e,t,s,u):x("expected expression"):n=new i.Condition("=",e,new i.Keyword("true"),s,u),S(")"),w(/^and/)?new i.Condition("and",n,w(this.condition)):n},operand:function(){var e,t=s.charAt(o+1);s.charAt(o)==="-"&&(t==="@"||t==="(")&&(e=w("-"));var n=w(this.sub)||w(this.entities.dimension)||w(this.entities.color)||w(this.entities.variable)||w(this.entities.call);return e&&(n.parensInOp=!0,n=new i.Negative(n)),n},expression:function(){var e,t,n=[],r;while(e=w(this.addition)||w(this.entity))n.push(e),!T(/^\/[\/*]/)&&(t=w("/"))&&n.push(new i.Anonymous(t));if(n.length>0)return new i.Expression(n)},property:function(){var e;if(e=w(/^(\*?-?[_a-z0-9-]+)\s*:/))return e[1]}}}};if(r.mode==="browser"||r.mode==="rhino")r.Parser.importer=function(e,t,n,r){!/^([a-z-]+:)?\//.test(e)&&t.currentDirectory&&(e=t.currentDirectory+e);var i=r.toSheet(e);i.processImports=!1,i.currentFileInfo=t,w(i,function(e,t,r,i,s,o){n.call(null,e,t,o)},!0)};(function(r){function u(e){return r.functions.hsla(e.h,e.s,e.l,e.a)}function a(e,t){return e instanceof r.Dimension&&e.unit.is("%")?parseFloat(e.value*t/100):f(e)}function f(e){if(e instanceof r.Dimension)return parseFloat(e.unit.is("%")?e.value/100:e.value);if(typeof e=="number")return e;throw{error:"RuntimeError",message:"color functions take numbers as parameters"}}function l(e){return Math.min(1,Math.max(0,e))}r.functions={rgb:function(e,t,n){return this.rgba(e,t,n,1)},rgba:function(e,t,n,i){var s=[e,t,n].map(function(e){return a(e,256)});return i=f(i),new r.Color(s,i)},hsl:function(e,t,n){return this.hsla(e,t,n,1)},hsla:function(e,t,n,r){function o(e){return e=e<0?e+1:e>1?e-1:e,e*6<1?s+(i-s)*e*6:e*2<1?i:e*3<2?s+(i-s)*(2/3-e)*6:s}e=f(e)%360/360,t=l(f(t)),n=l(f(n)),r=l(f(r));var i=n<=.5?n*(t+1):n+t-n*t,s=n*2-i;return this.rgba(o(e+1/3)*255,o(e)*255,o(e-1/3)*255,r)},hsv:function(e,t,n){return this.hsva(e,t,n,1)},hsva:function(e,t,n,r){e=f(e)%360/360*360,t=f(t),n=f(n),r=f(r);var i,s;i=Math.floor(e/60%6),s=e/60-i;var o=[n,n*(1-t),n*(1-s*t),n*(1-(1-s)*t)],u=[[0,3,1],[2,0,1],[1,0,3],[1,2,0],[3,1,0],[0,1,2]];return this.rgba(o[u[i][0]]*255,o[u[i][1]]*255,o[u[i][2]]*255,r)},hue:function(e){return new r.Dimension(Math.round(e.toHSL().h))},saturation:function(e){return new r.Dimension(Math.round(e.toHSL().s*100),"%")},lightness:function(e){return new r.Dimension(Math.round(e.toHSL().l*100),"%")},hsvhue:function(e){return new r.Dimension(Math.round(e.toHSV().h))},hsvsaturation:function(e){return new r.Dimension(Math.round(e.toHSV().s*100),"%")},hsvvalue:function(e){return new r.Dimension(Math.round(e.toHSV().v*100),"%")},red:function(e){return new r.Dimension(e.rgb[0])},green:function(e){return new r.Dimension(e.rgb[1])},blue:function(e){return new r.Dimension(e.rgb[2])},alpha:function(e){return new r.Dimension(e.toHSL().a)},luma:function(e){return new r.Dimension(Math.round(e.luma()*e.alpha*100),"%")},saturate:function(e,t){var n=e.toHSL();return n.s+=t.value/100,n.s=l(n.s),u(n)},desaturate:function(e,t){var n=e.toHSL();return n.s-=t.value/100,n.s=l(n.s),u(n)},lighten:function(e,t){var n=e.toHSL();return n.l+=t.value/100,n.l=l(n.l),u(n)},darken:function(e,t){var n=e.toHSL();return n.l-=t.value/100,n.l=l(n.l),u(n)},fadein:function(e,t){var n=e.toHSL();return n.a+=t.value/100,n.a=l(n.a),u(n)},fadeout:function(e,t){var n=e.toHSL();return n.a-=t.value/100,n.a=l(n.a),u(n)},fade:function(e,t){var n=e.toHSL();return n.a=t.value/100,n.a=l(n.a),u(n)},spin:function(e,t){var n=e.toHSL(),r=(n.h+t.value)%360;return n.h=r<0?360+r:r,u(n)},mix:function(e,t,n){n||(n=new r.Dimension(50));var i=n.value/100,s=i*2-1,o=e.toHSL().a-t.toHSL().a,u=((s*o==-1?s:(s+o)/(1+s*o))+1)/2,a=1-u,f=[e.rgb[0]*u+t.rgb[0]*a,e.rgb[1]*u+t.rgb[1]*a,e.rgb[2]*u+t.rgb[2]*a],l=e.alpha*i+t.alpha*(1-i);return new r.Color(f,l)},greyscale:function(e){return this.desaturate(e,new r.Dimension(100))},contrast:function(e,t,n,r){if(!e.rgb)return null;typeof n=="undefined"&&(n=this.rgba(255,255,255,1)),typeof t=="undefined"&&(t=this.rgba(0,0,0,1));if(t.luma()>n.luma()){var i=n;n=t,t=i}return typeof r=="undefined"?r=.43:r=f(r),e.luma()*e.alpha=d){if(this.env.ieCompat!==!1)return this.env.silent||console.warn("Skipped data-uri embedding of %s because its size (%dKB) exceeds IE8-safe %dKB!",o,v,d),(new r.URL(i||t,this.currentFileInfo)).eval(this.env);this.env.silent||console.warn("WARNING: Embedding %s (%dKB) exceeds IE8's data-uri size limit of %dKB!",o,v,d)}p=f?p.toString("base64"):encodeURIComponent(p);var m="'data:"+s+","+p+"'";return new r.URL(new r.Anonymous(m))}},r._mime={_types:{".htm":"text/html",".html":"text/html",".gif":"image/gif",".jpg":"image/jpeg",".jpeg":"image/jpeg",".png":"image/png"},lookup:function(e){var i=n("path").extname(e),s=r._mime._types[i];if(s===t)throw new Error('Optional dependency "mime" is required for '+i);return s},charsets:{lookup:function(e){return e&&/^text\//.test(e)?"UTF-8":""}}};var i=[{name:"ceil"},{name:"floor"},{name:"sqrt"},{name:"abs"},{name:"tan",unit:""},{name:"sin",unit:""},{name:"cos",unit:""},{name:"atan",unit:"rad"},{name:"asin",unit:"rad"},{name:"acos",unit:"rad"}],s=function(e,t){return function(n){return t!=null&&(n=n.unify()),this._math(Math[e],t,n)}};for(var o=0;o255?255:e<0?0:e).toString(16),e.length===1?"0"+e:e}).join("");return n&&(r=r.split(""),r[0]==r[1]&&r[2]==r[3]&&r[4]==r[5]?r=r[0]+r[2]+r[4]:r=r.join("")),"#"+r},operate:function(t,n,r){var i=[];r instanceof e.Color||(r=r.toColor());for(var s=0;s<3;s++)i[s]=e.operate(t,n,this.rgb[s],r.rgb[s]);return new e.Color(i,this.alpha+r.alpha)},toHSL:function(){var e=this.rgb[0]/255,t=this.rgb[1]/255,n=this.rgb[2]/255,r=this.alpha,i=Math.max(e,t,n),s=Math.min(e,t,n),o,u,a=(i+s)/2,f=i-s;if(i===s)o=u=0;else{u=a>.5?f/(2-i-s):f/(i+s);switch(i){case e:o=(t-n)/f+(t255?255:e<0?0:e).toString(16),e.length===1?"0"+e:e}).join("")},compare:function(e){return e.rgb?e.rgb[0]===this.rgb[0]&&e.rgb[1]===this.rgb[1]&&e.rgb[2]===this.rgb[2]&&e.alpha===this.alpha?0:-1:-1}}}(n("../tree")),function(e){e.Comment=function(e,t){this.value=e,this.silent=!!t},e.Comment.prototype={type:"Comment",toCSS:function(e){return e.compress?"":this.value},eval:function(){return this}}}(n("../tree")),function(e){e.Condition=function(e,t,n,r,i){this.op=e.trim(),this.lvalue=t,this.rvalue=n,this.index=r,this.negate=i},e.Condition.prototype={type:"Condition",accept:function(e){this.lvalue=e.visit(this.lvalue),this.rvalue=e.visit(this.rvalue)},eval:function(e){var t=this.lvalue.eval(e),n=this.rvalue.eval(e),r=this.index,i,i=function(e){switch(e){case"and":return t&&n;case"or":return t||n;default:if(t.compare)i=t.compare(n);else{if(!n.compare)throw{type:"Type",message:"Unable to perform comparison",index:r};i=n.compare(t)}switch(i){case-1:return e==="<"||e==="=<";case 0:return e==="="||e===">="||e==="=<";case 1:return e===">"||e===">="}}}(this.op);return this.negate?!i:i}}}(n("../tree")),function(e){e.Dimension=function(n,r){this.value=parseFloat(n),this.unit=r&&r instanceof e.Unit?r:new e.Unit(r?[r]:t)},e.Dimension.prototype={type:"Dimension",accept:function(e){this.unit=e.visit(this.unit)},eval:function(e){return this},toColor:function(){return new e.Color([this.value,this.value,this.value])},toCSS:function(e){if(e&&e.strictUnits&&!this.unit.isSingular())throw new Error("Multiple units in dimension. Correct the units or use the unit function. Bad unit: "+this.unit.toString());var t=this.value,n=String(t);t!==0&&t<1e-6&&t>-0.000001&&(n=t.toFixed(20).replace(/0+$/,""));if(e&&e.compress){if(t===0&&!this.unit.isAngle())return n;t>0&&t<1&&(n=n.substr(1))}return n+this.unit.toCSS(e)},operate:function(t,n,r){var i=e.operate(t,n,this.value,r.value),s=this.unit.clone();if(n==="+"||n==="-"){if(s.numerator.length===0&&s.denominator.length===0)s.numerator=r.unit.numerator.slice(0),s.denominator=r.unit.denominator.slice(0);else if(r.unit.numerator.length!=0||s.denominator.length!=0){r=r.convertTo(this.unit.usedUnits());if(t.strictUnits&&r.unit.toString()!==s.toString())throw new Error("Incompatible units. Change the units or use the unit function. Bad units: '"+s.toString()+"' and '"+r.unit.toString()+"'.");i=e.operate(t,n,this.value,r.value)}}else n==="*"?(s.numerator=s.numerator.concat(r.unit.numerator).sort(),s.denominator=s.denominator.concat(r.unit.denominator).sort(),s.cancel()):n==="/"&&(s.numerator=s.numerator.concat(r.unit.denominator).sort(),s.denominator=s.denominator.concat(r.unit.numerator).sort(),s.cancel());return new e.Dimension(i,s)},compare:function(t){if(t instanceof e.Dimension){var n=this.unify(),r=t.unify(),i=n.value,s=r.value;return s>i?-1:s=1?this.numerator[0]:this.denominator.length>=1?this.denominator[0]:(!e||!e.strictUnits)&&this.backupUnit?this.backupUnit:""},toString:function(){var e,t=this.numerator.join("*");for(e=0;e0)for(n=0;n":e.compress?">":" > ","|":e.compress?"|":" | "}[this.value]}}}(n("../tree")),function(e){e.Expression=function(e){this.value=e},e.Expression.prototype={type:"Expression",accept:function(e){this.value=e.visit(this.value)},eval:function(t){var n,r=this.parens&&!this.parensInOp,i=!1;return r&&t.inParenthesis(),this.value.length>1?n=new e.Expression(this.value.map(function(e){return e.eval(t)})):this.value.length===1?(this.value[0].parens&&!this.value[0].parensInOp&&(i=!0),n=this.value[0].eval(t)):n=this,r&&t.outOfParenthesis(),this.parens&&this.parensInOp&&!t.isMathOn()&&!i&&(n=new e.Paren(n)),n},toCSS:function(e){return this.value.map(function(t){return t.toCSS?t.toCSS(e):""}).join(" ")},throwAwayComments:function(){this.value=this.value.filter(function(t){return!(t instanceof e.Comment)})}}}(n("../tree")),function(e){e.Extend=function(t,n,r){this.selector=t,this.option=n,this.index=r;switch(n){case"all":this.allowBefore=!0,this.allowAfter=!0;break;default:this.allowBefore=!1,this.allowAfter=!1}},e.Extend.prototype={type:"Extend",accept:function(e){this.selector=e.visit(this.selector)},eval:function(t){return new e.Extend(this.selector.eval(t),this.option,this.index)},clone:function(t){return new e.Extend(this.selector,this.option,this.index)},findSelfSelectors:function(e){var t=[],n;for(n=0;n1){var r=this.emptySelectors();n=new e.Ruleset(r,t.mediaBlocks),n.multiMedia=!0}return delete t.mediaBlocks,delete t.mediaPath,n},evalNested:function(t){var n,r,i=t.mediaPath.concat([this]);for(n=0;n0;n--)t.splice(n,0,new e.Anonymous("and"));return new e.Expression(t)})),new e.Ruleset([],[])},permute:function(e){if(e.length===0)return[];if(e.length===1)return e[0];var t=[],n=this.permute(e.slice(1));for(var r=0;r0){c=!0;for(a=0;athis.params.length)return!1;if(this.required>0&&n>this.params.length)return!1}r=Math.min(n,this.arity);for(var s=0;si.selectors[o].elements.length?Array.prototype.push.apply(r,i.find(new e.Selector(t.elements.slice(1)),n)):r.push(i);break}}),this._lookups[o]=r)},toCSS:function(t){var n=[],r=[],i=[],s=[],o,u,a;for(var f=0;f0){u=e.debugInfo(t,this),o=this.paths.map(function(e){return e.map(function(e){return e.toCSS(t)}).join("").trim()}).join(t.compress?",":",\n");for(var f=r.length-1;f>=0;f--)(r[f].slice(0,2)==="/*"||i.indexOf(r[f])===-1)&&i.unshift(r[f]);r=i,n.push(u+o+(t.compress?"{":" {\n ")+r.join(t.compress?"":"\n ")+(t.compress?"}":"\n}\n"))}return n.push(s),n.join("")+(t.compress?"\n":"")},joinSelectors:function(e,t,n){for(var r=0;r0)for(i=0;i0&&this.mergeElementsOnToSelectors(g,a);for(s=0;s0&&(l[0].elements=l[0].elements.slice(0),l[0].elements.push(new e.Element(f.combinator,"",0))),y.push(l);else for(o=0;o0?(h=l.slice(0),m=h.pop(),d=new e.Selector(m.elements.slice(0),r.extendList),v=!1):d=new e.Selector([],r.extendList),c.length>1&&(p=p.concat(c.slice(1))),c.length>0&&(v=!1,d.elements.push(new e.Element(f.combinator,c[0].elements[0].value,0)),d.elements=d.elements.concat(c[0].elements.slice(1))),v||h.push(d),h=h.concat(p),y.push(h)}a=y,g=[]}}g.length>0&&this.mergeElementsOnToSelectors(g,a);for(i=0;i0&&t.push(a[i])},mergeElementsOnToSelectors:function(t,n){var r,i,s;if(n.length==0){n.push([new e.Selector(t)]);return}for(r=0;r0?i[i.length-1]=new e.Selector(i[i.length-1].elements.concat(t),i[i.length-1].extendList):i.push(new e.Selector(t))}}}(n("../tree")),function(e){e.Selector=function(e,t){this.elements=e,this.extendList=t||[]},e.Selector.prototype={type:"Selector",accept:function(e){this.elements=e.visit(this.elements),this.extendList=e.visit(this.extendList)},match:function(e){var t=this.elements,n=t.length,r,i,s,o;r=e.elements.slice(e.elements.length&&e.elements[0].value==="&"?1:0),i=r.length,s=Math.min(n,i);if(i===0||n1?"["+e.value.map(function(e){return e.toCSS(!1)}).join(", ")+"]":e.toCSS(!1)}}(n("./tree")),function(e){var t=["paths","optimization","files","contents","relativeUrls","strictImports","dumpLineNumbers","compress","processImports","syncImport","mime","currentFileInfo"];e.parseEnv=function(e){r(e,this,t),this.contents||(this.contents={}),this.files||(this.files={});if(!this.currentFileInfo){var n=e&&e.filename||"input",i=n.replace(/[^\/\\]*$/,"");e&&(e.filename=null),this.currentFileInfo={filename:n,relativeUrls:this.relativeUrls,rootpath:e&&e.rootpath||"",currentDirectory:i,entryPath:i,rootFilename:n}}},e.parseEnv.prototype.toSheet=function(t){var n=new e.parseEnv(this);return n.href=t,n.type=this.mime,n};var n=["silent","verbose","compress","yuicompress","ieCompat","strictMath","strictUnits"];e.evalEnv=function(e,t){r(e,this,n),this.frames=t||[]},e.evalEnv.prototype.inParenthesis=function(){this.parensStack||(this.parensStack=[]),this.parensStack.push(!0)},e.evalEnv.prototype.outOfParenthesis=function(){this.parensStack.pop()},e.evalEnv.prototype.isMathOn=function(){return this.strictMath?this.parensStack&&this.parensStack.length:!0},e.evalEnv.prototype.isPathRelative=function(e){return!/^(?:[a-z-]+:|\/)/.test(e)};var r=function(e,t,n){if(!e)return;for(var r=0;r100){var d="{unable to calculate}",v="{unable to calculate}";try{d=u[0].selfSelectors[0].toCSS(),v=u[0].selector.toCSS()}catch(m){}throw{message:"extend circular reference detected. One of the circular extends is currently:"+d+":extend("+v+")"}}return u.concat(f.doExtendChaining(u,n,r+1))}return u},inInheritanceChain:function(e,t){if(e===t)return!0;if(t.parents){if(this.inInheritanceChain(e,t.parents[0]))return!0;if(this.inInheritanceChain(e,t.parents[1]))return!0}return!1},visitRule:function(e,t){t.visitDeeper=!1},visitMixinDefinition:function(e,t){t.visitDeeper=!1},visitSelector:function(e,t){t.visitDeeper=!1},visitRuleset:function(e,t){if(e.root)return;var n,r,i,s=this.allExtendsStack[this.allExtendsStack.length-1],o=[],u=this,a;for(i=0;i0&&f[c.matched].combinator.value!==o?c=null:c.matched++,c&&(c.finished=c.matched===f.length,c.finished&&!e.allowAfter&&(i+1i&&s>0&&(o[o.length-1].elements=o[o.length-1].elements.concat(n[i].elements.slice(s)),s=0,i++),o=o.concat(n.slice(i,l.pathIndex)),o.push(new e.Selector(a.elements.slice(s,l.index).concat([f]).concat(r.elements.slice(1)))),i=l.endPathIndex,s=l.endPathElementIndex,s>=a.elements.length&&(s=0,i++);return i0&&(o[o.length-1].elements=o[o.length-1].elements.concat(n[i].elements.slice(s)),s=0,i++),o=o.concat(n.slice(i,n.length)),o},visitRulesetOut:function(e){},visitMedia:function(e,t){var n=e.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length-1]);n=n.concat(this.doExtendChaining(n,e.allExtends)),this.allExtendsStack.push(n)},visitMediaOut:function(e){this.allExtendsStack.length=this.allExtendsStack.length-1},visitDirective:function(e,t){var n=e.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length-1]);n=n.concat(this.doExtendChaining(n,e.allExtends)),this.allExtendsStack.push(n)},visitDirectiveOut:function(e){this.allExtendsStack.length=this.allExtendsStack.length-1}}}(n("./tree"));var o=/^(file|chrome(-extension)?|resource|qrc|app):/.test(location.protocol);r.env=r.env||(location.hostname=="127.0.0.1"||location.hostname=="0.0.0.0"||location.hostname=="localhost"||location.port.length>0||o?"development":"production"),r.async=r.async||!1,r.fileAsync=r.fileAsync||!1,r.poll=r.poll||(o?1e3:1500);if(r.functions)for(var u in r.functions)r.tree.functions[u]=r.functions[u];var a=/!dumpLineNumbers:(comments|mediaquery|all)/.exec(location.hash);a&&(r.dumpLineNumbers=a[1]),r.watch=function(){return r.watchMode||(r.env="development",f()),this.watchMode=!0},r.unwatch=function(){return clearInterval(r.watchTimer),this.watchMode=!1},/!watch/.test(location.hash)&&r.watch();var l=null;if(r.env!="development")try{l=typeof e.localStorage=="undefined"?null:e.localStorage}catch(c){}var h=document.getElementsByTagName("link"),p=/^text\/(x-)?less$/;r.sheets=[];for(var d=0;d current) { chunks[j] = chunks[j].slice(i - current); current = i; } } function isWhitespace(c) { // Could change to \s? var code = c.charCodeAt(0); return code === 32 || code === 10 || code === 9; } // // Parse from a token, regexp or string, and move forward if match // function $(tok) { var match, args, length, index, k; // // Non-terminal // if (tok instanceof Function) { return tok.call(parser.parsers); // // Terminal // // Either match a single character in the input, // or match a regexp in the current chunk (chunk[j]). // } else if (typeof(tok) === 'string') { match = input.charAt(i) === tok ? tok : null; length = 1; sync (); } else { sync (); if (match = tok.exec(chunks[j])) { length = match[0].length; } else { return null; } } // The match is confirmed, add the match length to `i`, // and consume any extra white-space characters (' ' || '\n') // which come after that. The reason for this is that LeSS's // grammar is mostly white-space insensitive. // if (match) { skipWhitespace(length); if(typeof(match) === 'string') { return match; } else { return match.length === 1 ? match[0] : match; } } } function skipWhitespace(length) { var oldi = i, oldj = j, endIndex = i + chunks[j].length, mem = i += length; while (i < endIndex) { if (! isWhitespace(input.charAt(i))) { break } i++; } chunks[j] = chunks[j].slice(length + (i - mem)); current = i; if (chunks[j].length === 0 && j < chunks.length - 1) { j++ } return oldi !== i || oldj !== j; } function expect(arg, msg) { var result = $(arg); if (! result) { error(msg || (typeof(arg) === 'string' ? "expected '" + arg + "' got '" + input.charAt(i) + "'" : "unexpected token")); } else { return result; } } function error(msg, type) { var e = new Error(msg); e.index = i; e.type = type || 'Syntax'; throw e; } // Same as $(), but don't change the state of the parser, // just return the match. function peek(tok) { if (typeof(tok) === 'string') { return input.charAt(i) === tok; } else { if (tok.test(chunks[j])) { return true; } else { return false; } } } function getInput(e, env) { if (e.filename && env.currentFileInfo.filename && (e.filename !== env.currentFileInfo.filename)) { return parser.imports.contents[e.filename]; } else { return input; } } function getLocation(index, input) { for (var n = index, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } return { line: typeof(index) === 'number' ? (input.slice(0, index).match(/\n/g) || "").length : null, column: column }; } function getDebugInfo(index, inputStream, env) { var filename = env.currentFileInfo.filename; if(less.mode !== 'browser' && less.mode !== 'rhino') { filename = require('path').resolve(filename); } return { lineNumber: getLocation(index, inputStream).line + 1, fileName: filename }; } function LessError(e, env) { var input = getInput(e, env), loc = getLocation(e.index, input), line = loc.line, col = loc.column, lines = input.split('\n'); this.type = e.type || 'Syntax'; this.message = e.message; this.filename = e.filename || env.currentFileInfo.filename; this.index = e.index; this.line = typeof(line) === 'number' ? line + 1 : null; this.callLine = e.call && (getLocation(e.call, input).line + 1); this.callExtract = lines[getLocation(e.call, input).line]; this.stack = e.stack; this.column = col; this.extract = [ lines[line - 1], lines[line], lines[line + 1] ]; } LessError.prototype = new Error(); LessError.prototype.constructor = LessError; this.env = env = env || {}; // The optimization level dictates the thoroughness of the parser, // the lower the number, the less nodes it will create in the tree. // This could matter for debugging, or if you want to access // the individual nodes in the tree. this.optimization = ('optimization' in this.env) ? this.env.optimization : 1; // // The Parser // return parser = { imports: imports, // // Parse an input string into an abstract syntax tree, // call `callback` when done. // parse: function (str, callback) { var root, start, end, zone, line, lines, buff = [], c, error = null; i = j = current = furthest = 0; input = str.replace(/\r\n/g, '\n'); // Remove potential UTF Byte Order Mark input = input.replace(/^\uFEFF/, ''); // Split the input into chunks. chunks = (function (chunks) { var j = 0, skip = /(?:@\{[\w-]+\}|[^"'`\{\}\/\(\)\\])+/g, comment = /\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g, string = /"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'|`((?:[^`]|\\.)*)`/g, level = 0, match, chunk = chunks[0], inParam; for (var i = 0, c, cc; i < input.length;) { skip.lastIndex = i; if (match = skip.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); } } c = input.charAt(i); comment.lastIndex = string.lastIndex = i; if (match = string.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); continue; } } if (!inParam && c === '/') { cc = input.charAt(i + 1); if (cc === '/' || cc === '*') { if (match = comment.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); continue; } } } } switch (c) { case '{': if (! inParam) { level ++; chunk.push(c); break } case '}': if (! inParam) { level --; chunk.push(c); chunks[++j] = chunk = []; break } case '(': if (! inParam) { inParam = true; chunk.push(c); break } case ')': if ( inParam) { inParam = false; chunk.push(c); break } default: chunk.push(c); } i++; } if (level != 0) { error = new(LessError)({ index: i-1, type: 'Parse', message: (level > 0) ? "missing closing `}`" : "missing opening `{`", filename: env.currentFileInfo.filename }, env); } return chunks.map(function (c) { return c.join('') });; })([[]]); if (error) { return callback(new(LessError)(error, env)); } // Start with the primary rule. // The whole syntax tree is held under a Ruleset node, // with the `root` property set to true, so no `{}` are // output. The callback is called when the input is parsed. try { root = new(tree.Ruleset)([], $(this.parsers.primary)); root.root = true; root.firstRoot = true; } catch (e) { return callback(new(LessError)(e, env)); } root.toCSS = (function (evaluate) { var line, lines, column; return function (options, variables) { options = options || {}; var importError, evalEnv = new tree.evalEnv(options); // // Allows setting variables with a hash, so: // // `{ color: new(tree.Color)('#f01') }` will become: // // new(tree.Rule)('@color', // new(tree.Value)([ // new(tree.Expression)([ // new(tree.Color)('#f01') // ]) // ]) // ) // if (typeof(variables) === 'object' && !Array.isArray(variables)) { variables = Object.keys(variables).map(function (k) { var value = variables[k]; if (! (value instanceof tree.Value)) { if (! (value instanceof tree.Expression)) { value = new(tree.Expression)([value]); } value = new(tree.Value)([value]); } return new(tree.Rule)('@' + k, value, false, 0); }); evalEnv.frames = [new(tree.Ruleset)(null, variables)]; } try { var evaldRoot = evaluate.call(this, evalEnv); new(tree.joinSelectorVisitor)() .run(evaldRoot); new(tree.processExtendsVisitor)() .run(evaldRoot); var css = evaldRoot.toCSS({ compress: Boolean(options.compress), dumpLineNumbers: env.dumpLineNumbers, strictUnits: Boolean(options.strictUnits)}); } catch (e) { throw new(LessError)(e, env); } if (options.yuicompress && less.mode === 'node') { return require('ycssmin').cssmin(css, options.maxLineLen); } else if (options.compress) { return css.replace(/(\s)+/g, "$1"); } else { return css; } }; })(root.eval); // If `i` is smaller than the `input.length - 1`, // it means the parser wasn't able to parse the whole // string, so we've got a parsing error. // // We try to extract a \n delimited string, // showing the line where the parse error occured. // We split it up into two parts (the part which parsed, // and the part which didn't), so we can color them differently. if (i < input.length - 1) { i = furthest; lines = input.split('\n'); line = (input.slice(0, i).match(/\n/g) || "").length + 1; for (var n = i, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } error = { type: "Parse", message: "Unrecognised input", index: i, filename: env.currentFileInfo.filename, line: line, column: column, extract: [ lines[line - 2], lines[line - 1], lines[line] ] }; } var finish = function (e) { e = error || e || parser.imports.error; if (e) { if (!(e instanceof LessError)) { e = new(LessError)(e, env); } callback(e); } else { callback(null, root); } }; if (env.processImports !== false) { new tree.importVisitor(this.imports, finish) .run(root); } else { finish(); } }, // // Here in, the parsing rules/functions // // The basic structure of the syntax tree generated is as follows: // // Ruleset -> Rule -> Value -> Expression -> Entity // // Here's some LESS code: // // .class { // color: #fff; // border: 1px solid #000; // width: @w + 4px; // > .child {...} // } // // And here's what the parse tree might look like: // // Ruleset (Selector '.class', [ // Rule ("color", Value ([Expression [Color #fff]])) // Rule ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]])) // Rule ("width", Value ([Expression [Operation "+" [Variable "@w"][Dimension 4px]]])) // Ruleset (Selector [Element '>', '.child'], [...]) // ]) // // In general, most rules will try to parse a token with the `$()` function, and if the return // value is truly, will return a new node, of the relevant type. Sometimes, we need to check // first, before parsing, that's when we use `peek()`. // parsers: { // // The `primary` rule is the *entry* and *exit* point of the parser. // The rules here can appear at any level of the parse tree. // // The recursive nature of the grammar is an interplay between the `block` // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule, // as represented by this simplified grammar: // // primary → (ruleset | rule)+ // ruleset → selector+ block // block → '{' primary '}' // // Only at one point is the primary rule not called from the // block rule: at the root level. // primary: function () { var node, root = []; while ((node = $(this.extendRule) || $(this.mixin.definition) || $(this.rule) || $(this.ruleset) || $(this.mixin.call) || $(this.comment) || $(this.directive)) || $(/^[\s\n]+/) || $(/^;+/)) { node && root.push(node); } return root; }, // We create a Comment node for CSS comments `/* */`, // but keep the LeSS comments `//` silent, by just skipping // over them. comment: function () { var comment; if (input.charAt(i) !== '/') return; if (input.charAt(i + 1) === '/') { return new(tree.Comment)($(/^\/\/.*/), true); } else if (comment = $(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/)) { return new(tree.Comment)(comment); } }, // // Entities are tokens which can be found inside an Expression // entities: { // // A string, which supports escaping " and ' // // "milky way" 'he\'s the one!' // quoted: function () { var str, j = i, e, index = i; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '"' && input.charAt(j) !== "'") return; e && $('~'); if (str = $(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/)) { return new(tree.Quoted)(str[0], str[1] || str[2], e, index, env.currentFileInfo); } }, // // A catch-all word, such as: // // black border-collapse // keyword: function () { var k; if (k = $(/^[_A-Za-z-][_A-Za-z0-9-]*/)) { if (tree.colors.hasOwnProperty(k)) { // detect named color return new(tree.Color)(tree.colors[k].slice(1)); } else { return new(tree.Keyword)(k); } } }, // // A function call // // rgb(255, 0, 255) // // We also try to catch IE's `alpha()`, but let the `alpha` parser // deal with the details. // // The arguments are parsed with the `entities.arguments` parser. // call: function () { var name, nameLC, args, alpha_ret, index = i; if (! (name = /^([\w-]+|%|progid:[\w\.]+)\(/.exec(chunks[j]))) return; name = name[1]; nameLC = name.toLowerCase(); if (nameLC === 'url') { return null } else { i += name.length } if (nameLC === 'alpha') { alpha_ret = $(this.alpha); if(typeof alpha_ret !== 'undefined') { return alpha_ret; } } $('('); // Parse the '(' and consume whitespace. args = $(this.entities.arguments); if (! $(')')) { return; } if (name) { return new(tree.Call)(name, args, index, env.currentFileInfo); } }, arguments: function () { var args = [], arg; while (arg = $(this.entities.assignment) || $(this.expression)) { args.push(arg); if (! $(',')) { break } } return args; }, literal: function () { return $(this.entities.dimension) || $(this.entities.color) || $(this.entities.quoted) || $(this.entities.unicodeDescriptor); }, // Assignments are argument entities for calls. // They are present in ie filter properties as shown below. // // filter: progid:DXImageTransform.Microsoft.Alpha( *opacity=50* ) // assignment: function () { var key, value; if ((key = $(/^\w+(?=\s?=)/i)) && $('=') && (value = $(this.entity))) { return new(tree.Assignment)(key, value); } }, // // Parse url() tokens // // We use a specific rule for urls, because they don't really behave like // standard function calls. The difference is that the argument doesn't have // to be enclosed within a string, so it can't be parsed as an Expression. // url: function () { var value; if (input.charAt(i) !== 'u' || !$(/^url\(/)) return; value = $(this.entities.quoted) || $(this.entities.variable) || $(/^(?:(?:\\[\(\)'"])|[^\(\)'"])+/) || ""; expect(')'); return new(tree.URL)((value.value != null || value instanceof tree.Variable) ? value : new(tree.Anonymous)(value), env.currentFileInfo); }, // // A Variable entity, such as `@fink`, in // // width: @fink + 2px // // We use a different parser for variable definitions, // see `parsers.variable`. // variable: function () { var name, index = i; if (input.charAt(i) === '@' && (name = $(/^@@?[\w-]+/))) { return new(tree.Variable)(name, index, env.currentFileInfo); } }, // A variable entity useing the protective {} e.g. @{var} variableCurly: function () { var name, curly, index = i; if (input.charAt(i) === '@' && (curly = $(/^@\{([\w-]+)\}/))) { return new(tree.Variable)("@" + curly[1], index, env.currentFileInfo); } }, // // A Hexadecimal color // // #4F3C2F // // `rgb` and `hsl` colors are parsed through the `entities.call` parser. // color: function () { var rgb; if (input.charAt(i) === '#' && (rgb = $(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/))) { return new(tree.Color)(rgb[1]); } }, // // A Dimension, that is, a number and a unit // // 0.5em 95% // dimension: function () { var value, c = input.charCodeAt(i); //Is the first char of the dimension 0-9, '.', '+' or '-' if ((c > 57 || c < 43) || c === 47 || c == 44) return; if (value = $(/^([+-]?\d*\.?\d+)(%|[a-z]+)?/)) { return new(tree.Dimension)(value[1], value[2]); } }, // // A unicode descriptor, as is used in unicode-range // // U+0?? or U+00A1-00A9 // unicodeDescriptor: function () { var ud; if (ud = $(/^U\+[0-9a-fA-F?]+(\-[0-9a-fA-F?]+)?/)) { return new(tree.UnicodeDescriptor)(ud[0]); } }, // // JavaScript code to be evaluated // // `window.location.href` // javascript: function () { var str, j = i, e; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '`') { return } e && $('~'); if (str = $(/^`([^`]*)`/)) { return new(tree.JavaScript)(str[1], i, e); } } }, // // The variable part of a variable definition. Used in the `rule` parser // // @fink: // variable: function () { var name; if (input.charAt(i) === '@' && (name = $(/^(@[\w-]+)\s*:/))) { return name[1] } }, // // extend syntax - used to extend selectors // extend: function(isRule) { var elements, e, index = i, option, extendList = []; if (!$(isRule ? /^&:extend\(/ : /^:extend\(/)) { return; } do { option = null; elements = []; while (true) { option = $(/^(all)(?=\s*(\)|,))/); if (option) { break; } e = $(this.element); if (!e) { break; } elements.push(e); } option = option && option[1]; extendList.push(new(tree.Extend)(new(tree.Selector)(elements), option, index)); } while($(",")) expect(/^\)/); if (isRule) { expect(/^;/); } return extendList; }, // // extendRule - used in a rule to extend all the parent selectors // extendRule: function() { return this.extend(true); }, // // Mixins // mixin: { // // A Mixin call, with an optional argument list // // #mixins > .square(#fff); // .rounded(4px, black); // .button; // // The `while` loop is there because mixins can be // namespaced, but we only support the child and descendant // selector for now. // call: function () { var elements = [], e, c, args, delim, arg, index = i, s = input.charAt(i), important = false; if (s !== '.' && s !== '#') { return } save(); // stop us absorbing part of an invalid selector while (e = $(/^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/)) { elements.push(new(tree.Element)(c, e, i)); c = $('>'); } if ($('(')) { args = this.mixin.args.call(this, true).args; expect(')'); } args = args || []; if ($(this.important)) { important = true; } if (elements.length > 0 && ($(';') || peek('}'))) { return new(tree.mixin.Call)(elements, args, index, env.currentFileInfo, important); } restore(); }, args: function (isCall) { var expressions = [], argsSemiColon = [], isSemiColonSeperated, argsComma = [], expressionContainsNamed, name, nameLoop, value, arg, returner = {args:null, variadic: false}; while (true) { if (isCall) { arg = $(this.expression); } else { $(this.comment); if (input.charAt(i) === '.' && $(/^\.{3}/)) { returner.variadic = true; if ($(";") && !isSemiColonSeperated) { isSemiColonSeperated = true; } (isSemiColonSeperated ? argsSemiColon : argsComma) .push({ variadic: true }); break; } arg = $(this.entities.variable) || $(this.entities.literal) || $(this.entities.keyword); } if (!arg) { break; } nameLoop = null; if (arg.throwAwayComments) { arg.throwAwayComments(); } value = arg; var val = null; if (isCall) { // Variable if (arg.value.length == 1) { var val = arg.value[0]; } } else { val = arg; } if (val && val instanceof tree.Variable) { if ($(':')) { if (expressions.length > 0) { if (isSemiColonSeperated) { error("Cannot mix ; and , as delimiter types"); } expressionContainsNamed = true; } value = expect(this.expression); nameLoop = (name = val.name); } else if (!isCall && $(/^\.{3}/)) { returner.variadic = true; if ($(";") && !isSemiColonSeperated) { isSemiColonSeperated = true; } (isSemiColonSeperated ? argsSemiColon : argsComma) .push({ name: arg.name, variadic: true }); break; } else if (!isCall) { name = nameLoop = val.name; value = null; } } if (value) { expressions.push(value); } argsComma.push({ name:nameLoop, value:value }); if ($(',')) { continue; } if ($(';') || isSemiColonSeperated) { if (expressionContainsNamed) { error("Cannot mix ; and , as delimiter types"); } isSemiColonSeperated = true; if (expressions.length > 1) { value = new (tree.Value)(expressions); } argsSemiColon.push({ name:name, value:value }); name = null; expressions = []; expressionContainsNamed = false; } } returner.args = isSemiColonSeperated ? argsSemiColon : argsComma; return returner; }, // // A Mixin definition, with a list of parameters // // .rounded (@radius: 2px, @color) { // ... // } // // Until we have a finer grained state-machine, we have to // do a look-ahead, to make sure we don't have a mixin call. // See the `rule` function for more information. // // We start by matching `.rounded (`, and then proceed on to // the argument list, which has optional default values. // We store the parameters in `params`, with a `value` key, // if there is a value, such as in the case of `@radius`. // // Once we've got our params list, and a closing `)`, we parse // the `{...}` block. // definition: function () { var name, params = [], match, ruleset, param, value, cond, variadic = false; if ((input.charAt(i) !== '.' && input.charAt(i) !== '#') || peek(/^[^{]*\}/)) return; save(); if (match = $(/^([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/)) { name = match[1]; var argInfo = this.mixin.args.call(this, false); params = argInfo.args; variadic = argInfo.variadic; // .mixincall("@{a}"); // looks a bit like a mixin definition.. so we have to be nice and restore if (!$(')')) { furthest = i; restore(); } $(this.comment); if ($(/^when/)) { // Guard cond = expect(this.conditions, 'expected condition'); } ruleset = $(this.block); if (ruleset) { return new(tree.mixin.Definition)(name, params, ruleset, cond, variadic); } else { restore(); } } } }, // // Entities are the smallest recognized token, // and can be found inside a rule's value. // entity: function () { return $(this.entities.literal) || $(this.entities.variable) || $(this.entities.url) || $(this.entities.call) || $(this.entities.keyword) ||$(this.entities.javascript) || $(this.comment); }, // // A Rule terminator. Note that we use `peek()` to check for '}', // because the `block` rule will be expecting it, but we still need to make sure // it's there, if ';' was ommitted. // end: function () { return $(';') || peek('}'); }, // // IE's alpha function // // alpha(opacity=88) // alpha: function () { var value; if (! $(/^\(opacity=/i)) return; if (value = $(/^\d+/) || $(this.entities.variable)) { expect(')'); return new(tree.Alpha)(value); } }, // // A Selector Element // // div // + h1 // #socks // input[type="text"] // // Elements are the building blocks for Selectors, // they are made out of a `Combinator` (see combinator rule), // and an element name, such as a tag a class, or `*`. // element: function () { var e, t, c, v; c = $(this.combinator); e = $(/^(?:\d+\.\d+|\d+)%/) || $(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/) || $('*') || $('&') || $(this.attribute) || $(/^\([^()@]+\)/) || $(/^[\.#](?=@)/) || $(this.entities.variableCurly); if (! e) { if ($('(')) { if ((v = ($(this.selector))) && $(')')) { e = new(tree.Paren)(v); } } } if (e) { return new(tree.Element)(c, e, i) } }, // // Combinators combine elements together, in a Selector. // // Because our parser isn't white-space sensitive, special care // has to be taken, when parsing the descendant combinator, ` `, // as it's an empty space. We have to check the previous character // in the input, to see if it's a ` ` character. More info on how // we deal with this in *combinator.js*. // combinator: function () { var c = input.charAt(i); if (c === '>' || c === '+' || c === '~' || c === '|') { i++; while (input.charAt(i).match(/\s/)) { i++ } return new(tree.Combinator)(c); } else if (input.charAt(i - 1).match(/\s/)) { return new(tree.Combinator)(" "); } else { return new(tree.Combinator)(null); } }, // // A CSS Selector // // .class > div + h1 // li a:hover // // Selectors are made out of one or more Elements, see above. // selector: function () { var sel, e, elements = [], c, extend, extendList = []; while ((extend = $(this.extend)) || (e = $(this.element))) { if (extend) { extendList.push.apply(extendList, extend); } else { if (extendList.length) { error("Extend can only be used at the end of selector"); } c = input.charAt(i); elements.push(e) e = null; } if (c === '{' || c === '}' || c === ';' || c === ',' || c === ')') { break } } if (elements.length > 0) { return new(tree.Selector)(elements, extendList); } if (extendList.length) { error("Extend must be used to extend a selector, it cannot be used on its own"); } }, attribute: function () { var attr = '', key, val, op; if (! $('[')) return; if (!(key = $(this.entities.variableCurly))) { key = expect(/^(?:[_A-Za-z0-9-\*]*\|)?(?:[_A-Za-z0-9-]|\\.)+/); } if ((op = $(/^[|~*$^]?=/))) { val = $(this.entities.quoted) || $(/^[\w-]+/) || $(this.entities.variableCurly); } expect(']'); return new(tree.Attribute)(key, op, val); }, // // The `block` rule is used by `ruleset` and `mixin.definition`. // It's a wrapper around the `primary` rule, with added `{}`. // block: function () { var content; if ($('{') && (content = $(this.primary)) && $('}')) { return content; } }, // // div, .class, body > p {...} // ruleset: function () { var selectors = [], s, rules, debugInfo; save(); if (env.dumpLineNumbers) debugInfo = getDebugInfo(i, input, env); while (s = $(this.selector)) { selectors.push(s); $(this.comment); if (! $(',')) { break } $(this.comment); } if (selectors.length > 0 && (rules = $(this.block))) { var ruleset = new(tree.Ruleset)(selectors, rules, env.strictImports); if (env.dumpLineNumbers) ruleset.debugInfo = debugInfo; return ruleset; } else { // Backtrack furthest = i; restore(); } }, rule: function (tryAnonymous) { var name, value, c = input.charAt(i), important; save(); if (c === '.' || c === '#' || c === '&') { return } if (name = $(this.variable) || $(this.property)) { // prefer to try to parse first if its a variable or we are compressing // but always fallback on the other one value = !tryAnonymous && (env.compress || (name.charAt(0) === '@')) ? ($(this.value) || $(this.anonymousValue)) : ($(this.anonymousValue) || $(this.value)); important = $(this.important); if (value && $(this.end)) { return new(tree.Rule)(name, value, important, memo, env.currentFileInfo); } else { furthest = i; restore(); if (value && !tryAnonymous) { return this.rule(true); } } } }, anonymousValue: function () { var match; if (match = /^([^@+\/'"*`(;{}-]*);/.exec(chunks[j])) { i += match[0].length - 1; return new(tree.Anonymous)(match[1]); } }, // // An @import directive // // @import "lib"; // // Depending on our environemnt, importing is done differently: // In the browser, it's an XHR request, in Node, it would be a // file-system operation. The function used for importing is // stored in `import`, which we pass to the Import constructor. // "import": function () { var path, features, index = i; save(); var dir = $(/^@import?\s+/); var options = (dir ? $(this.importOptions) : null) || {}; if (dir && (path = $(this.entities.quoted) || $(this.entities.url))) { features = $(this.mediaFeatures); if ($(';')) { features = features && new(tree.Value)(features); return new(tree.Import)(path, features, options, index, env.currentFileInfo); } } restore(); }, importOptions: function() { var o, options = {}, optionName, value; // list of options, surrounded by parens if (! $('(')) { return null; } do { if (o = $(this.importOption)) { optionName = o; value = true; switch(optionName) { case "css": optionName = "less"; value = false; break; case "once": optionName = "multiple"; value = false; break; } options[optionName] = value; if (! $(',')) { break } } } while (o); expect(')'); return options; }, importOption: function() { var opt = $(/^(less|css|multiple|once)/); if (opt) { return opt[1]; } }, mediaFeature: function () { var e, p, nodes = []; do { if (e = $(this.entities.keyword)) { nodes.push(e); } else if ($('(')) { p = $(this.property); e = $(this.value); if ($(')')) { if (p && e) { nodes.push(new(tree.Paren)(new(tree.Rule)(p, e, null, i, env.currentFileInfo, true))); } else if (e) { nodes.push(new(tree.Paren)(e)); } else { return null; } } else { return null } } } while (e); if (nodes.length > 0) { return new(tree.Expression)(nodes); } }, mediaFeatures: function () { var e, features = []; do { if (e = $(this.mediaFeature)) { features.push(e); if (! $(',')) { break } } else if (e = $(this.entities.variable)) { features.push(e); if (! $(',')) { break } } } while (e); return features.length > 0 ? features : null; }, media: function () { var features, rules, media, debugInfo; if (env.dumpLineNumbers) debugInfo = getDebugInfo(i, input, env); if ($(/^@media/)) { features = $(this.mediaFeatures); if (rules = $(this.block)) { media = new(tree.Media)(rules, features); if(env.dumpLineNumbers) media.debugInfo = debugInfo; return media; } } }, // // A CSS Directive // // @charset "utf-8"; // directive: function () { var name, value, rules, identifier, e, nodes, nonVendorSpecificName, hasBlock, hasIdentifier, hasExpression; if (input.charAt(i) !== '@') return; if (value = $(this['import']) || $(this.media)) { return value; } save(); name = $(/^@[a-z-]+/); if (!name) return; nonVendorSpecificName = name; if (name.charAt(1) == '-' && name.indexOf('-', 2) > 0) { nonVendorSpecificName = "@" + name.slice(name.indexOf('-', 2) + 1); } switch(nonVendorSpecificName) { case "@font-face": hasBlock = true; break; case "@viewport": case "@top-left": case "@top-left-corner": case "@top-center": case "@top-right": case "@top-right-corner": case "@bottom-left": case "@bottom-left-corner": case "@bottom-center": case "@bottom-right": case "@bottom-right-corner": case "@left-top": case "@left-middle": case "@left-bottom": case "@right-top": case "@right-middle": case "@right-bottom": hasBlock = true; break; case "@page": case "@document": case "@supports": case "@keyframes": hasBlock = true; hasIdentifier = true; break; case "@namespace": hasExpression = true; break; } if (hasIdentifier) { name += " " + ($(/^[^{]+/) || '').trim(); } if (hasBlock) { if (rules = $(this.block)) { return new(tree.Directive)(name, rules); } } else { if ((value = hasExpression ? $(this.expression) : $(this.entity)) && $(';')) { var directive = new(tree.Directive)(name, value); if (env.dumpLineNumbers) { directive.debugInfo = getDebugInfo(i, input, env); } return directive; } } restore(); }, // // A Value is a comma-delimited list of Expressions // // font-family: Baskerville, Georgia, serif; // // In a Rule, a Value represents everything after the `:`, // and before the `;`. // value: function () { var e, expressions = [], important; while (e = $(this.expression)) { expressions.push(e); if (! $(',')) { break } } if (expressions.length > 0) { return new(tree.Value)(expressions); } }, important: function () { if (input.charAt(i) === '!') { return $(/^! *important/); } }, sub: function () { var a, e; if ($('(')) { if (a = $(this.addition)) { e = new(tree.Expression)([a]); expect(')'); e.parens = true; return e; } } }, multiplication: function () { var m, a, op, operation, isSpaced, expression = []; if (m = $(this.operand)) { isSpaced = isWhitespace(input.charAt(i - 1)); while (!peek(/^\/[*\/]/) && (op = ($('/') || $('*')))) { if (a = $(this.operand)) { m.parensInOp = true; a.parensInOp = true; operation = new(tree.Operation)(op, [operation || m, a], isSpaced); isSpaced = isWhitespace(input.charAt(i - 1)); } else { break; } } return operation || m; } }, addition: function () { var m, a, op, operation, isSpaced; if (m = $(this.multiplication)) { isSpaced = isWhitespace(input.charAt(i - 1)); while ((op = $(/^[-+]\s+/) || (!isSpaced && ($('+') || $('-')))) && (a = $(this.multiplication))) { m.parensInOp = true; a.parensInOp = true; operation = new(tree.Operation)(op, [operation || m, a], isSpaced); isSpaced = isWhitespace(input.charAt(i - 1)); } return operation || m; } }, conditions: function () { var a, b, index = i, condition; if (a = $(this.condition)) { while ($(',') && (b = $(this.condition))) { condition = new(tree.Condition)('or', condition || a, b, index); } return condition || a; } }, condition: function () { var a, b, c, op, index = i, negate = false; if ($(/^not/)) { negate = true } expect('('); if (a = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) { if (op = $(/^(?:>=|=<|[<=>])/)) { if (b = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) { c = new(tree.Condition)(op, a, b, index, negate); } else { error('expected expression'); } } else { c = new(tree.Condition)('=', a, new(tree.Keyword)('true'), index, negate); } expect(')'); return $(/^and/) ? new(tree.Condition)('and', c, $(this.condition)) : c; } }, // // An operand is anything that can be part of an operation, // such as a Color, or a Variable // operand: function () { var negate, p = input.charAt(i + 1); if (input.charAt(i) === '-' && (p === '@' || p === '(')) { negate = $('-') } var o = $(this.sub) || $(this.entities.dimension) || $(this.entities.color) || $(this.entities.variable) || $(this.entities.call); if (negate) { o.parensInOp = true; o = new(tree.Negative)(o); } return o; }, // // Expressions either represent mathematical operations, // or white-space delimited Entities. // // 1px solid black // @var * 2 // expression: function () { var e, delim, entities = [], d; while (e = $(this.addition) || $(this.entity)) { entities.push(e); // operations do not allow keyword "/" dimension (e.g. small/20px) so we support that here if (!peek(/^\/[\/*]/) && (delim = $('/'))) { entities.push(new(tree.Anonymous)(delim)); } } if (entities.length > 0) { return new(tree.Expression)(entities); } }, property: function () { var name; if (name = $(/^(\*?-?[_a-zA-Z0-9-]+)\s*:/)) { return name[1]; } } } }; }; if (less.mode === 'browser' || less.mode === 'rhino') { // // Used by `@import` directives // less.Parser.importer = function (path, currentFileInfo, callback, env) { if (!/^([a-z-]+:)?\//.test(path) && currentFileInfo.currentDirectory) { path = currentFileInfo.currentDirectory + path; } var sheetEnv = env.toSheet(path); sheetEnv.processImports = false; sheetEnv.currentFileInfo = currentFileInfo; // We pass `true` as 3rd argument, to force the reload of the import. // This is so we can get the syntax tree as opposed to just the CSS output, // as we need this to evaluate the current stylesheet. loadStyleSheet(sheetEnv, function (e, root, data, sheet, _, path) { callback.call(null, e, root, path); }, true); }; } (function (tree) { tree.functions = { rgb: function (r, g, b) { return this.rgba(r, g, b, 1.0); }, rgba: function (r, g, b, a) { var rgb = [r, g, b].map(function (c) { return scaled(c, 256); }); a = number(a); return new(tree.Color)(rgb, a); }, hsl: function (h, s, l) { return this.hsla(h, s, l, 1.0); }, hsla: function (h, s, l, a) { h = (number(h) % 360) / 360; s = clamp(number(s)); l = clamp(number(l)); a = clamp(number(a)); var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s; var m1 = l * 2 - m2; return this.rgba(hue(h + 1/3) * 255, hue(h) * 255, hue(h - 1/3) * 255, a); function hue(h) { h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h); if (h * 6 < 1) return m1 + (m2 - m1) * h * 6; else if (h * 2 < 1) return m2; else if (h * 3 < 2) return m1 + (m2 - m1) * (2/3 - h) * 6; else return m1; } }, hsv: function(h, s, v) { return this.hsva(h, s, v, 1.0); }, hsva: function(h, s, v, a) { h = ((number(h) % 360) / 360) * 360; s = number(s); v = number(v); a = number(a); var i, f; i = Math.floor((h / 60) % 6); f = (h / 60) - i; var vs = [v, v * (1 - s), v * (1 - f * s), v * (1 - (1 - f) * s)]; var perm = [[0, 3, 1], [2, 0, 1], [1, 0, 3], [1, 2, 0], [3, 1, 0], [0, 1, 2]]; return this.rgba(vs[perm[i][0]] * 255, vs[perm[i][1]] * 255, vs[perm[i][2]] * 255, a); }, hue: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().h)); }, saturation: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().s * 100), '%'); }, lightness: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().l * 100), '%'); }, hsvhue: function(color) { return new(tree.Dimension)(Math.round(color.toHSV().h)); }, hsvsaturation: function (color) { return new(tree.Dimension)(Math.round(color.toHSV().s * 100), '%'); }, hsvvalue: function (color) { return new(tree.Dimension)(Math.round(color.toHSV().v * 100), '%'); }, red: function (color) { return new(tree.Dimension)(color.rgb[0]); }, green: function (color) { return new(tree.Dimension)(color.rgb[1]); }, blue: function (color) { return new(tree.Dimension)(color.rgb[2]); }, alpha: function (color) { return new(tree.Dimension)(color.toHSL().a); }, luma: function (color) { return new(tree.Dimension)(Math.round(color.luma() * color.alpha * 100), '%'); }, saturate: function (color, amount) { var hsl = color.toHSL(); hsl.s += amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, desaturate: function (color, amount) { var hsl = color.toHSL(); hsl.s -= amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, lighten: function (color, amount) { var hsl = color.toHSL(); hsl.l += amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, darken: function (color, amount) { var hsl = color.toHSL(); hsl.l -= amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, fadein: function (color, amount) { var hsl = color.toHSL(); hsl.a += amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, fadeout: function (color, amount) { var hsl = color.toHSL(); hsl.a -= amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, fade: function (color, amount) { var hsl = color.toHSL(); hsl.a = amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, spin: function (color, amount) { var hsl = color.toHSL(); var hue = (hsl.h + amount.value) % 360; hsl.h = hue < 0 ? 360 + hue : hue; return hsla(hsl); }, // // Copyright (c) 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein // http://sass-lang.com // mix: function (color1, color2, weight) { if (!weight) { weight = new(tree.Dimension)(50); } var p = weight.value / 100.0; var w = p * 2 - 1; var a = color1.toHSL().a - color2.toHSL().a; var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0; var w2 = 1 - w1; var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2, color1.rgb[1] * w1 + color2.rgb[1] * w2, color1.rgb[2] * w1 + color2.rgb[2] * w2]; var alpha = color1.alpha * p + color2.alpha * (1 - p); return new(tree.Color)(rgb, alpha); }, greyscale: function (color) { return this.desaturate(color, new(tree.Dimension)(100)); }, contrast: function (color, dark, light, threshold) { // filter: contrast(3.2); // should be kept as is, so check for color if (!color.rgb) { return null; } if (typeof light === 'undefined') { light = this.rgba(255, 255, 255, 1.0); } if (typeof dark === 'undefined') { dark = this.rgba(0, 0, 0, 1.0); } //Figure out which is actually light and dark! if (dark.luma() > light.luma()) { var t = light; light = dark; dark = t; } if (typeof threshold === 'undefined') { threshold = 0.43; } else { threshold = number(threshold); } if ((color.luma() * color.alpha) < threshold) { return light; } else { return dark; } }, e: function (str) { return new(tree.Anonymous)(str instanceof tree.JavaScript ? str.evaluated : str); }, escape: function (str) { return new(tree.Anonymous)(encodeURI(str.value).replace(/=/g, "%3D").replace(/:/g, "%3A").replace(/#/g, "%23").replace(/;/g, "%3B").replace(/\(/g, "%28").replace(/\)/g, "%29")); }, '%': function (quoted /* arg, arg, ...*/) { var args = Array.prototype.slice.call(arguments, 1), str = quoted.value; for (var i = 0; i < args.length; i++) { str = str.replace(/%[sda]/i, function(token) { var value = token.match(/s/i) ? args[i].value : args[i].toCSS(); return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value; }); } str = str.replace(/%%/g, '%'); return new(tree.Quoted)('"' + str + '"', str); }, unit: function (val, unit) { return new(tree.Dimension)(val.value, unit ? unit.toCSS() : ""); }, convert: function (val, unit) { return val.convertTo(unit.value); }, round: function (n, f) { var fraction = typeof(f) === "undefined" ? 0 : f.value; return this._math(function(num) { return num.toFixed(fraction); }, null, n); }, pi: function () { return new(tree.Dimension)(Math.PI); }, mod: function(a, b) { return new(tree.Dimension)(a.value % b.value, a.unit); }, pow: function(x, y) { if (typeof x === "number" && typeof y === "number") { x = new(tree.Dimension)(x); y = new(tree.Dimension)(y); } else if (!(x instanceof tree.Dimension) || !(y instanceof tree.Dimension)) { throw { type: "Argument", message: "arguments must be numbers" }; } return new(tree.Dimension)(Math.pow(x.value, y.value), x.unit); }, _math: function (fn, unit, n) { if (n instanceof tree.Dimension) { return new(tree.Dimension)(fn(parseFloat(n.value)), unit == null ? n.unit : unit); } else if (typeof(n) === 'number') { return fn(n); } else { throw { type: "Argument", message: "argument must be a number" }; } }, argb: function (color) { return new(tree.Anonymous)(color.toARGB()); }, percentage: function (n) { return new(tree.Dimension)(n.value * 100, '%'); }, color: function (n) { if (n instanceof tree.Quoted) { return new(tree.Color)(n.value.slice(1)); } else { throw { type: "Argument", message: "argument must be a string" }; } }, iscolor: function (n) { return this._isa(n, tree.Color); }, isnumber: function (n) { return this._isa(n, tree.Dimension); }, isstring: function (n) { return this._isa(n, tree.Quoted); }, iskeyword: function (n) { return this._isa(n, tree.Keyword); }, isurl: function (n) { return this._isa(n, tree.URL); }, ispixel: function (n) { return this.isunit(n, 'px'); }, ispercentage: function (n) { return this.isunit(n, '%'); }, isem: function (n) { return this.isunit(n, 'em'); }, isunit: function (n, unit) { return (n instanceof tree.Dimension) && n.unit.is(unit.value || unit) ? tree.True : tree.False; }, _isa: function (n, Type) { return (n instanceof Type) ? tree.True : tree.False; }, /* Blending modes */ multiply: function(color1, color2) { var r = color1.rgb[0] * color2.rgb[0] / 255; var g = color1.rgb[1] * color2.rgb[1] / 255; var b = color1.rgb[2] * color2.rgb[2] / 255; return this.rgb(r, g, b); }, screen: function(color1, color2) { var r = 255 - (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255; var g = 255 - (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255; var b = 255 - (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255; return this.rgb(r, g, b); }, overlay: function(color1, color2) { var r = color1.rgb[0] < 128 ? 2 * color1.rgb[0] * color2.rgb[0] / 255 : 255 - 2 * (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255; var g = color1.rgb[1] < 128 ? 2 * color1.rgb[1] * color2.rgb[1] / 255 : 255 - 2 * (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255; var b = color1.rgb[2] < 128 ? 2 * color1.rgb[2] * color2.rgb[2] / 255 : 255 - 2 * (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255; return this.rgb(r, g, b); }, softlight: function(color1, color2) { var t = color2.rgb[0] * color1.rgb[0] / 255; var r = t + color1.rgb[0] * (255 - (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255 - t) / 255; t = color2.rgb[1] * color1.rgb[1] / 255; var g = t + color1.rgb[1] * (255 - (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255 - t) / 255; t = color2.rgb[2] * color1.rgb[2] / 255; var b = t + color1.rgb[2] * (255 - (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255 - t) / 255; return this.rgb(r, g, b); }, hardlight: function(color1, color2) { var r = color2.rgb[0] < 128 ? 2 * color2.rgb[0] * color1.rgb[0] / 255 : 255 - 2 * (255 - color2.rgb[0]) * (255 - color1.rgb[0]) / 255; var g = color2.rgb[1] < 128 ? 2 * color2.rgb[1] * color1.rgb[1] / 255 : 255 - 2 * (255 - color2.rgb[1]) * (255 - color1.rgb[1]) / 255; var b = color2.rgb[2] < 128 ? 2 * color2.rgb[2] * color1.rgb[2] / 255 : 255 - 2 * (255 - color2.rgb[2]) * (255 - color1.rgb[2]) / 255; return this.rgb(r, g, b); }, difference: function(color1, color2) { var r = Math.abs(color1.rgb[0] - color2.rgb[0]); var g = Math.abs(color1.rgb[1] - color2.rgb[1]); var b = Math.abs(color1.rgb[2] - color2.rgb[2]); return this.rgb(r, g, b); }, exclusion: function(color1, color2) { var r = color1.rgb[0] + color2.rgb[0] * (255 - color1.rgb[0] - color1.rgb[0]) / 255; var g = color1.rgb[1] + color2.rgb[1] * (255 - color1.rgb[1] - color1.rgb[1]) / 255; var b = color1.rgb[2] + color2.rgb[2] * (255 - color1.rgb[2] - color1.rgb[2]) / 255; return this.rgb(r, g, b); }, average: function(color1, color2) { var r = (color1.rgb[0] + color2.rgb[0]) / 2; var g = (color1.rgb[1] + color2.rgb[1]) / 2; var b = (color1.rgb[2] + color2.rgb[2]) / 2; return this.rgb(r, g, b); }, negation: function(color1, color2) { var r = 255 - Math.abs(255 - color2.rgb[0] - color1.rgb[0]); var g = 255 - Math.abs(255 - color2.rgb[1] - color1.rgb[1]); var b = 255 - Math.abs(255 - color2.rgb[2] - color1.rgb[2]); return this.rgb(r, g, b); }, tint: function(color, amount) { return this.mix(this.rgb(255,255,255), color, amount); }, shade: function(color, amount) { return this.mix(this.rgb(0, 0, 0), color, amount); }, extract: function(values, index) { index = index.value - 1; // (1-based index) return values.value[index]; }, "data-uri": function(mimetypeNode, filePathNode) { if (typeof window !== 'undefined') { return new tree.URL(filePathNode || mimetypeNode, this.currentFileInfo).eval(this.env); } var mimetype = mimetypeNode.value; var filePath = (filePathNode && filePathNode.value); var fs = require("fs"), path = require("path"), useBase64 = false; if (arguments.length < 2) { filePath = mimetype; } if (this.env.isPathRelative(filePath)) { if (this.currentFileInfo.relativeUrls) { filePath = path.join(this.currentFileInfo.currentDirectory, filePath); } else { filePath = path.join(this.currentFileInfo.entryPath, filePath); } } // detect the mimetype if not given if (arguments.length < 2) { var mime; try { mime = require('mime'); } catch (ex) { mime = tree._mime; } mimetype = mime.lookup(filePath); // use base 64 unless it's an ASCII or UTF-8 format var charset = mime.charsets.lookup(mimetype); useBase64 = ['US-ASCII', 'UTF-8'].indexOf(charset) < 0; if (useBase64) mimetype += ';base64'; } else { useBase64 = /;base64$/.test(mimetype) } var buf = fs.readFileSync(filePath); // IE8 cannot handle a data-uri larger than 32KB. If this is exceeded // and the --ieCompat flag is enabled, return a normal url() instead. var DATA_URI_MAX_KB = 32, fileSizeInKB = parseInt((buf.length / 1024), 10); if (fileSizeInKB >= DATA_URI_MAX_KB) { if (this.env.ieCompat !== false) { if (!this.env.silent) { console.warn("Skipped data-uri embedding of %s because its size (%dKB) exceeds IE8-safe %dKB!", filePath, fileSizeInKB, DATA_URI_MAX_KB); } return new tree.URL(filePathNode || mimetypeNode, this.currentFileInfo).eval(this.env); } else if (!this.env.silent) { // if explicitly disabled (via --no-ie-compat on CLI, or env.ieCompat === false), merely warn console.warn("WARNING: Embedding %s (%dKB) exceeds IE8's data-uri size limit of %dKB!", filePath, fileSizeInKB, DATA_URI_MAX_KB); } } buf = useBase64 ? buf.toString('base64') : encodeURIComponent(buf); var uri = "'data:" + mimetype + ',' + buf + "'"; return new(tree.URL)(new(tree.Anonymous)(uri)); } }; // these static methods are used as a fallback when the optional 'mime' dependency is missing tree._mime = { // this map is intentionally incomplete // if you want more, install 'mime' dep _types: { '.htm' : 'text/html', '.html': 'text/html', '.gif' : 'image/gif', '.jpg' : 'image/jpeg', '.jpeg': 'image/jpeg', '.png' : 'image/png' }, lookup: function (filepath) { var ext = require('path').extname(filepath), type = tree._mime._types[ext]; if (type === undefined) { throw new Error('Optional dependency "mime" is required for ' + ext); } return type; }, charsets: { lookup: function (type) { // assumes all text types are UTF-8 return type && (/^text\//).test(type) ? 'UTF-8' : ''; } } }; var mathFunctions = [{name:"ceil"}, {name:"floor"}, {name: "sqrt"}, {name:"abs"}, {name:"tan", unit: ""}, {name:"sin", unit: ""}, {name:"cos", unit: ""}, {name:"atan", unit: "rad"}, {name:"asin", unit: "rad"}, {name:"acos", unit: "rad"}], createMathFunction = function(name, unit) { return function(n) { if (unit != null) { n = n.unify(); } return this._math(Math[name], unit, n); }; }; for(var i = 0; i < mathFunctions.length; i++) { tree.functions[mathFunctions[i].name] = createMathFunction(mathFunctions[i].name, mathFunctions[i].unit); } function hsla(color) { return tree.functions.hsla(color.h, color.s, color.l, color.a); } function scaled(n, size) { if (n instanceof tree.Dimension && n.unit.is('%')) { return parseFloat(n.value * size / 100); } else { return number(n); } } function number(n) { if (n instanceof tree.Dimension) { return parseFloat(n.unit.is('%') ? n.value / 100 : n.value); } else if (typeof(n) === 'number') { return n; } else { throw { error: "RuntimeError", message: "color functions take numbers as parameters" }; } } function clamp(val) { return Math.min(1, Math.max(0, val)); } tree.functionCall = function(env, currentFileInfo) { this.env = env; this.currentFileInfo = currentFileInfo; }; tree.functionCall.prototype = tree.functions; })(require('./tree')); (function (tree) { tree.colors = { 'aliceblue':'#f0f8ff', 'antiquewhite':'#faebd7', 'aqua':'#00ffff', 'aquamarine':'#7fffd4', 'azure':'#f0ffff', 'beige':'#f5f5dc', 'bisque':'#ffe4c4', 'black':'#000000', 'blanchedalmond':'#ffebcd', 'blue':'#0000ff', 'blueviolet':'#8a2be2', 'brown':'#a52a2a', 'burlywood':'#deb887', 'cadetblue':'#5f9ea0', 'chartreuse':'#7fff00', 'chocolate':'#d2691e', 'coral':'#ff7f50', 'cornflowerblue':'#6495ed', 'cornsilk':'#fff8dc', 'crimson':'#dc143c', 'cyan':'#00ffff', 'darkblue':'#00008b', 'darkcyan':'#008b8b', 'darkgoldenrod':'#b8860b', 'darkgray':'#a9a9a9', 'darkgrey':'#a9a9a9', 'darkgreen':'#006400', 'darkkhaki':'#bdb76b', 'darkmagenta':'#8b008b', 'darkolivegreen':'#556b2f', 'darkorange':'#ff8c00', 'darkorchid':'#9932cc', 'darkred':'#8b0000', 'darksalmon':'#e9967a', 'darkseagreen':'#8fbc8f', 'darkslateblue':'#483d8b', 'darkslategray':'#2f4f4f', 'darkslategrey':'#2f4f4f', 'darkturquoise':'#00ced1', 'darkviolet':'#9400d3', 'deeppink':'#ff1493', 'deepskyblue':'#00bfff', 'dimgray':'#696969', 'dimgrey':'#696969', 'dodgerblue':'#1e90ff', 'firebrick':'#b22222', 'floralwhite':'#fffaf0', 'forestgreen':'#228b22', 'fuchsia':'#ff00ff', 'gainsboro':'#dcdcdc', 'ghostwhite':'#f8f8ff', 'gold':'#ffd700', 'goldenrod':'#daa520', 'gray':'#808080', 'grey':'#808080', 'green':'#008000', 'greenyellow':'#adff2f', 'honeydew':'#f0fff0', 'hotpink':'#ff69b4', 'indianred':'#cd5c5c', 'indigo':'#4b0082', 'ivory':'#fffff0', 'khaki':'#f0e68c', 'lavender':'#e6e6fa', 'lavenderblush':'#fff0f5', 'lawngreen':'#7cfc00', 'lemonchiffon':'#fffacd', 'lightblue':'#add8e6', 'lightcoral':'#f08080', 'lightcyan':'#e0ffff', 'lightgoldenrodyellow':'#fafad2', 'lightgray':'#d3d3d3', 'lightgrey':'#d3d3d3', 'lightgreen':'#90ee90', 'lightpink':'#ffb6c1', 'lightsalmon':'#ffa07a', 'lightseagreen':'#20b2aa', 'lightskyblue':'#87cefa', 'lightslategray':'#778899', 'lightslategrey':'#778899', 'lightsteelblue':'#b0c4de', 'lightyellow':'#ffffe0', 'lime':'#00ff00', 'limegreen':'#32cd32', 'linen':'#faf0e6', 'magenta':'#ff00ff', 'maroon':'#800000', 'mediumaquamarine':'#66cdaa', 'mediumblue':'#0000cd', 'mediumorchid':'#ba55d3', 'mediumpurple':'#9370d8', 'mediumseagreen':'#3cb371', 'mediumslateblue':'#7b68ee', 'mediumspringgreen':'#00fa9a', 'mediumturquoise':'#48d1cc', 'mediumvioletred':'#c71585', 'midnightblue':'#191970', 'mintcream':'#f5fffa', 'mistyrose':'#ffe4e1', 'moccasin':'#ffe4b5', 'navajowhite':'#ffdead', 'navy':'#000080', 'oldlace':'#fdf5e6', 'olive':'#808000', 'olivedrab':'#6b8e23', 'orange':'#ffa500', 'orangered':'#ff4500', 'orchid':'#da70d6', 'palegoldenrod':'#eee8aa', 'palegreen':'#98fb98', 'paleturquoise':'#afeeee', 'palevioletred':'#d87093', 'papayawhip':'#ffefd5', 'peachpuff':'#ffdab9', 'peru':'#cd853f', 'pink':'#ffc0cb', 'plum':'#dda0dd', 'powderblue':'#b0e0e6', 'purple':'#800080', 'red':'#ff0000', 'rosybrown':'#bc8f8f', 'royalblue':'#4169e1', 'saddlebrown':'#8b4513', 'salmon':'#fa8072', 'sandybrown':'#f4a460', 'seagreen':'#2e8b57', 'seashell':'#fff5ee', 'sienna':'#a0522d', 'silver':'#c0c0c0', 'skyblue':'#87ceeb', 'slateblue':'#6a5acd', 'slategray':'#708090', 'slategrey':'#708090', 'snow':'#fffafa', 'springgreen':'#00ff7f', 'steelblue':'#4682b4', 'tan':'#d2b48c', 'teal':'#008080', 'thistle':'#d8bfd8', 'tomato':'#ff6347', // 'transparent':'rgba(0,0,0,0)', 'turquoise':'#40e0d0', 'violet':'#ee82ee', 'wheat':'#f5deb3', 'white':'#ffffff', 'whitesmoke':'#f5f5f5', 'yellow':'#ffff00', 'yellowgreen':'#9acd32' }; })(require('./tree')); (function (tree) { tree.Alpha = function (val) { this.value = val; }; tree.Alpha.prototype = { type: "Alpha", accept: function (visitor) { this.value = visitor.visit(this.value); }, eval: function (env) { if (this.value.eval) { this.value = this.value.eval(env) } return this; }, toCSS: function () { return "alpha(opacity=" + (this.value.toCSS ? this.value.toCSS() : this.value) + ")"; } }; })(require('../tree')); (function (tree) { tree.Anonymous = function (string) { this.value = string.value || string; }; tree.Anonymous.prototype = { type: "Anonymous", toCSS: function () { return this.value; }, eval: function () { return this }, compare: function (x) { if (!x.toCSS) { return -1; } var left = this.toCSS(), right = x.toCSS(); if (left === right) { return 0; } return left < right ? -1 : 1; } }; })(require('../tree')); (function (tree) { tree.Assignment = function (key, val) { this.key = key; this.value = val; }; tree.Assignment.prototype = { type: "Assignment", accept: function (visitor) { this.value = visitor.visit(this.value); }, toCSS: function () { return this.key + '=' + (this.value.toCSS ? this.value.toCSS() : this.value); }, eval: function (env) { if (this.value.eval) { return new(tree.Assignment)(this.key, this.value.eval(env)); } return this; } }; })(require('../tree'));(function (tree) { // // A function call node. // tree.Call = function (name, args, index, currentFileInfo) { this.name = name; this.args = args; this.index = index; this.currentFileInfo = currentFileInfo; }; tree.Call.prototype = { type: "Call", accept: function (visitor) { this.args = visitor.visit(this.args); }, // // When evaluating a function call, // we either find the function in `tree.functions` [1], // in which case we call it, passing the evaluated arguments, // if this returns null or we cannot find the function, we // simply print it out as it appeared originally [2]. // // The *functions.js* file contains the built-in functions. // // The reason why we evaluate the arguments, is in the case where // we try to pass a variable to a function, like: `saturate(@color)`. // The function should receive the value, not the variable. // eval: function (env) { var args = this.args.map(function (a) { return a.eval(env); }), nameLC = this.name.toLowerCase(), result, func; if (nameLC in tree.functions) { // 1. try { func = new tree.functionCall(env, this.currentFileInfo); result = func[nameLC].apply(func, args); if (result != null) { return result; } } catch (e) { throw { type: e.type || "Runtime", message: "error evaluating function `" + this.name + "`" + (e.message ? ': ' + e.message : ''), index: this.index, filename: this.currentFileInfo.filename }; } } // 2. return new(tree.Anonymous)(this.name + "(" + args.map(function (a) { return a.toCSS(env); }).join(', ') + ")"); }, toCSS: function (env) { return this.eval(env).toCSS(); } }; })(require('../tree')); (function (tree) { // // RGB Colors - #ff0014, #eee // tree.Color = function (rgb, a) { // // The end goal here, is to parse the arguments // into an integer triplet, such as `128, 255, 0` // // This facilitates operations and conversions. // if (Array.isArray(rgb)) { this.rgb = rgb; } else if (rgb.length == 6) { this.rgb = rgb.match(/.{2}/g).map(function (c) { return parseInt(c, 16); }); } else { this.rgb = rgb.split('').map(function (c) { return parseInt(c + c, 16); }); } this.alpha = typeof(a) === 'number' ? a : 1; }; tree.Color.prototype = { type: "Color", eval: function () { return this }, luma: function () { return (0.2126 * this.rgb[0] / 255) + (0.7152 * this.rgb[1] / 255) + (0.0722 * this.rgb[2] / 255); }, // // If we have some transparency, the only way to represent it // is via `rgba`. Otherwise, we use the hex representation, // which has better compatibility with older browsers. // Values are capped between `0` and `255`, rounded and zero-padded. // toCSS: function (env, doNotCompress) { var compress = env && env.compress && !doNotCompress; if (this.alpha < 1.0) { return "rgba(" + this.rgb.map(function (c) { return Math.round(c); }).concat(this.alpha).join(',' + (compress ? '' : ' ')) + ")"; } else { var color = this.rgb.map(function (i) { i = Math.round(i); i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16); return i.length === 1 ? '0' + i : i; }).join(''); if (compress) { color = color.split(''); // Convert color to short format if (color[0] == color[1] && color[2] == color[3] && color[4] == color[5]) { color = color[0] + color[2] + color[4]; } else { color = color.join(''); } } return '#' + color; } }, // // Operations have to be done per-channel, if not, // channels will spill onto each other. Once we have // our result, in the form of an integer triplet, // we create a new Color node to hold the result. // operate: function (env, op, other) { var result = []; if (! (other instanceof tree.Color)) { other = other.toColor(); } for (var c = 0; c < 3; c++) { result[c] = tree.operate(env, op, this.rgb[c], other.rgb[c]); } return new(tree.Color)(result, this.alpha + other.alpha); }, toHSL: function () { var r = this.rgb[0] / 255, g = this.rgb[1] / 255, b = this.rgb[2] / 255, a = this.alpha; var max = Math.max(r, g, b), min = Math.min(r, g, b); var h, s, l = (max + min) / 2, d = max - min; if (max === min) { h = s = 0; } else { s = l > 0.5 ? d / (2 - max - min) : d / (max + min); switch (max) { case r: h = (g - b) / d + (g < b ? 6 : 0); break; case g: h = (b - r) / d + 2; break; case b: h = (r - g) / d + 4; break; } h /= 6; } return { h: h * 360, s: s, l: l, a: a }; }, //Adapted from http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript toHSV: function () { var r = this.rgb[0] / 255, g = this.rgb[1] / 255, b = this.rgb[2] / 255, a = this.alpha; var max = Math.max(r, g, b), min = Math.min(r, g, b); var h, s, v = max; var d = max - min; if (max === 0) { s = 0; } else { s = d / max; } if (max === min) { h = 0; } else { switch(max){ case r: h = (g - b) / d + (g < b ? 6 : 0); break; case g: h = (b - r) / d + 2; break; case b: h = (r - g) / d + 4; break; } h /= 6; } return { h: h * 360, s: s, v: v, a: a }; }, toARGB: function () { var argb = [Math.round(this.alpha * 255)].concat(this.rgb); return '#' + argb.map(function (i) { i = Math.round(i); i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16); return i.length === 1 ? '0' + i : i; }).join(''); }, compare: function (x) { if (!x.rgb) { return -1; } return (x.rgb[0] === this.rgb[0] && x.rgb[1] === this.rgb[1] && x.rgb[2] === this.rgb[2] && x.alpha === this.alpha) ? 0 : -1; } }; })(require('../tree')); (function (tree) { tree.Comment = function (value, silent) { this.value = value; this.silent = !!silent; }; tree.Comment.prototype = { type: "Comment", toCSS: function (env) { return env.compress ? '' : this.value; }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.Condition = function (op, l, r, i, negate) { this.op = op.trim(); this.lvalue = l; this.rvalue = r; this.index = i; this.negate = negate; }; tree.Condition.prototype = { type: "Condition", accept: function (visitor) { this.lvalue = visitor.visit(this.lvalue); this.rvalue = visitor.visit(this.rvalue); }, eval: function (env) { var a = this.lvalue.eval(env), b = this.rvalue.eval(env); var i = this.index, result; var result = (function (op) { switch (op) { case 'and': return a && b; case 'or': return a || b; default: if (a.compare) { result = a.compare(b); } else if (b.compare) { result = b.compare(a); } else { throw { type: "Type", message: "Unable to perform comparison", index: i }; } switch (result) { case -1: return op === '<' || op === '=<'; case 0: return op === '=' || op === '>=' || op === '=<'; case 1: return op === '>' || op === '>='; } } })(this.op); return this.negate ? !result : result; } }; })(require('../tree')); (function (tree) { // // A number with a unit // tree.Dimension = function (value, unit) { this.value = parseFloat(value); this.unit = (unit && unit instanceof tree.Unit) ? unit : new(tree.Unit)(unit ? [unit] : undefined); }; tree.Dimension.prototype = { type: "Dimension", accept: function (visitor) { this.unit = visitor.visit(this.unit); }, eval: function (env) { return this; }, toColor: function () { return new(tree.Color)([this.value, this.value, this.value]); }, toCSS: function (env) { if ((env && env.strictUnits) && !this.unit.isSingular()) { throw new Error("Multiple units in dimension. Correct the units or use the unit function. Bad unit: "+this.unit.toString()); } var value = this.value, strValue = String(value); if (value !== 0 && value < 0.000001 && value > -0.000001) { // would be output 1e-6 etc. strValue = value.toFixed(20).replace(/0+$/, ""); } if (env && env.compress) { // Zero values doesn't need a unit if (value === 0 && !this.unit.isAngle()) { return strValue; } // Float values doesn't need a leading zero if (value > 0 && value < 1) { strValue = (strValue).substr(1); } } return strValue + this.unit.toCSS(env); }, // In an operation between two Dimensions, // we default to the first Dimension's unit, // so `1px + 2` will yield `3px`. operate: function (env, op, other) { var value = tree.operate(env, op, this.value, other.value), unit = this.unit.clone(); if (op === '+' || op === '-') { if (unit.numerator.length === 0 && unit.denominator.length === 0) { unit.numerator = other.unit.numerator.slice(0); unit.denominator = other.unit.denominator.slice(0); } else if (other.unit.numerator.length == 0 && unit.denominator.length == 0) { // do nothing } else { other = other.convertTo(this.unit.usedUnits()); if(env.strictUnits && other.unit.toString() !== unit.toString()) { throw new Error("Incompatible units. Change the units or use the unit function. Bad units: '" + unit.toString() + "' and '" + other.unit.toString() + "'."); } value = tree.operate(env, op, this.value, other.value); } } else if (op === '*') { unit.numerator = unit.numerator.concat(other.unit.numerator).sort(); unit.denominator = unit.denominator.concat(other.unit.denominator).sort(); unit.cancel(); } else if (op === '/') { unit.numerator = unit.numerator.concat(other.unit.denominator).sort(); unit.denominator = unit.denominator.concat(other.unit.numerator).sort(); unit.cancel(); } return new(tree.Dimension)(value, unit); }, compare: function (other) { if (other instanceof tree.Dimension) { var a = this.unify(), b = other.unify(), aValue = a.value, bValue = b.value; if (bValue > aValue) { return -1; } else if (bValue < aValue) { return 1; } else { if (!b.unit.isEmpty() && a.unit.compare(b.unit) !== 0) { return -1; } return 0; } } else { return -1; } }, unify: function () { return this.convertTo({ length: 'm', duration: 's', angle: 'rad' }); }, convertTo: function (conversions) { var value = this.value, unit = this.unit.clone(), i, groupName, group, conversion, targetUnit, derivedConversions = {}; if (typeof conversions === 'string') { for(i in tree.UnitConversions) { if (tree.UnitConversions[i].hasOwnProperty(conversions)) { derivedConversions = {}; derivedConversions[i] = conversions; } } conversions = derivedConversions; } for (groupName in conversions) { if (conversions.hasOwnProperty(groupName)) { targetUnit = conversions[groupName]; group = tree.UnitConversions[groupName]; unit.map(function (atomicUnit, denominator) { if (group.hasOwnProperty(atomicUnit)) { if (denominator) { value = value / (group[atomicUnit] / group[targetUnit]); } else { value = value * (group[atomicUnit] / group[targetUnit]); } return targetUnit; } return atomicUnit; }); } } unit.cancel(); return new(tree.Dimension)(value, unit); } }; // http://www.w3.org/TR/css3-values/#absolute-lengths tree.UnitConversions = { length: { 'm': 1, 'cm': 0.01, 'mm': 0.001, 'in': 0.0254, 'pt': 0.0254 / 72, 'pc': 0.0254 / 72 * 12 }, duration: { 's': 1, 'ms': 0.001 }, angle: { 'rad': 1/(2*Math.PI), 'deg': 1/360, 'grad': 1/400, 'turn': 1 } }; tree.Unit = function (numerator, denominator, backupUnit) { this.numerator = numerator ? numerator.slice(0).sort() : []; this.denominator = denominator ? denominator.slice(0).sort() : []; this.backupUnit = backupUnit; }; tree.Unit.prototype = { type: "Unit", clone: function () { return new tree.Unit(this.numerator.slice(0), this.denominator.slice(0), this.backupUnit); }, toCSS: function (env) { if (this.numerator.length >= 1) { return this.numerator[0]; } if (this.denominator.length >= 1) { return this.denominator[0]; } if ((!env || !env.strictUnits) && this.backupUnit) { return this.backupUnit; } return ""; }, toString: function () { var i, returnStr = this.numerator.join("*"); for (i = 0; i < this.denominator.length; i++) { returnStr += "/" + this.denominator[i]; } return returnStr; }, compare: function (other) { return this.is(other.toString()) ? 0 : -1; }, is: function (unitString) { return this.toString() === unitString; }, isAngle: function () { return tree.UnitConversions.angle.hasOwnProperty(this.toCSS()); }, isEmpty: function () { return this.numerator.length == 0 && this.denominator.length == 0; }, isSingular: function() { return this.numerator.length <= 1 && this.denominator.length == 0; }, map: function(callback) { var i; for (i = 0; i < this.numerator.length; i++) { this.numerator[i] = callback(this.numerator[i], false); } for (i = 0; i < this.denominator.length; i++) { this.denominator[i] = callback(this.denominator[i], true); } }, usedUnits: function() { var group, groupName, result = {}; for (groupName in tree.UnitConversions) { if (tree.UnitConversions.hasOwnProperty(groupName)) { group = tree.UnitConversions[groupName]; this.map(function (atomicUnit) { if (group.hasOwnProperty(atomicUnit) && !result[groupName]) { result[groupName] = atomicUnit; } return atomicUnit; }); } } return result; }, cancel: function () { var counter = {}, atomicUnit, i, backup; for (i = 0; i < this.numerator.length; i++) { atomicUnit = this.numerator[i]; if (!backup) { backup = atomicUnit; } counter[atomicUnit] = (counter[atomicUnit] || 0) + 1; } for (i = 0; i < this.denominator.length; i++) { atomicUnit = this.denominator[i]; if (!backup) { backup = atomicUnit; } counter[atomicUnit] = (counter[atomicUnit] || 0) - 1; } this.numerator = []; this.denominator = []; for (atomicUnit in counter) { if (counter.hasOwnProperty(atomicUnit)) { var count = counter[atomicUnit]; if (count > 0) { for (i = 0; i < count; i++) { this.numerator.push(atomicUnit); } } else if (count < 0) { for (i = 0; i < -count; i++) { this.denominator.push(atomicUnit); } } } } if (this.numerator.length === 0 && this.denominator.length === 0 && backup) { this.backupUnit = backup; } this.numerator.sort(); this.denominator.sort(); } }; })(require('../tree')); (function (tree) { tree.Directive = function (name, value) { this.name = name; if (Array.isArray(value)) { this.ruleset = new(tree.Ruleset)([], value); this.ruleset.allowImports = true; } else { this.value = value; } }; tree.Directive.prototype = { type: "Directive", accept: function (visitor) { this.ruleset = visitor.visit(this.ruleset); this.value = visitor.visit(this.value); }, toCSS: function (env) { if (this.ruleset) { this.ruleset.root = true; return this.name + (env.compress ? '{' : ' {\n ') + this.ruleset.toCSS(env).trim().replace(/\n/g, '\n ') + (env.compress ? '}': '\n}\n'); } else { return this.name + ' ' + this.value.toCSS() + ';\n'; } }, eval: function (env) { var evaldDirective = this; if (this.ruleset) { env.frames.unshift(this); evaldDirective = new(tree.Directive)(this.name); evaldDirective.ruleset = this.ruleset.eval(env); env.frames.shift(); } return evaldDirective; }, variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) }, find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) }, rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) } }; })(require('../tree')); (function (tree) { tree.Element = function (combinator, value, index) { this.combinator = combinator instanceof tree.Combinator ? combinator : new(tree.Combinator)(combinator); if (typeof(value) === 'string') { this.value = value.trim(); } else if (value) { this.value = value; } else { this.value = ""; } this.index = index; }; tree.Element.prototype = { type: "Element", accept: function (visitor) { this.combinator = visitor.visit(this.combinator); this.value = visitor.visit(this.value); }, eval: function (env) { return new(tree.Element)(this.combinator, this.value.eval ? this.value.eval(env) : this.value, this.index); }, toCSS: function (env) { var value = (this.value.toCSS ? this.value.toCSS(env) : this.value); if (value == '' && this.combinator.value.charAt(0) == '&') { return ''; } else { return this.combinator.toCSS(env || {}) + value; } } }; tree.Attribute = function (key, op, value) { this.key = key; this.op = op; this.value = value; }; tree.Attribute.prototype = { type: "Attribute", accept: function (visitor) { this.value = visitor.visit(this.value); }, eval: function (env) { return new(tree.Attribute)(this.key.eval ? this.key.eval(env) : this.key, this.op, (this.value && this.value.eval) ? this.value.eval(env) : this.value); }, toCSS: function (env) { var value = this.key.toCSS ? this.key.toCSS(env) : this.key; if (this.op) { value += this.op; value += (this.value.toCSS ? this.value.toCSS(env) : this.value); } return '[' + value + ']'; } }; tree.Combinator = function (value) { if (value === ' ') { this.value = ' '; } else { this.value = value ? value.trim() : ""; } }; tree.Combinator.prototype = { type: "Combinator", toCSS: function (env) { return { '' : '', ' ' : ' ', ':' : ' :', '+' : env.compress ? '+' : ' + ', '~' : env.compress ? '~' : ' ~ ', '>' : env.compress ? '>' : ' > ', '|' : env.compress ? '|' : ' | ' }[this.value]; } }; })(require('../tree')); (function (tree) { tree.Expression = function (value) { this.value = value; }; tree.Expression.prototype = { type: "Expression", accept: function (visitor) { this.value = visitor.visit(this.value); }, eval: function (env) { var returnValue, inParenthesis = this.parens && !this.parensInOp, doubleParen = false; if (inParenthesis) { env.inParenthesis(); } if (this.value.length > 1) { returnValue = new(tree.Expression)(this.value.map(function (e) { return e.eval(env); })); } else if (this.value.length === 1) { if (this.value[0].parens && !this.value[0].parensInOp) { doubleParen = true; } returnValue = this.value[0].eval(env); } else { returnValue = this; } if (inParenthesis) { env.outOfParenthesis(); } if (this.parens && this.parensInOp && !(env.isMathOn()) && !doubleParen) { returnValue = new(tree.Paren)(returnValue); } return returnValue; }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS ? e.toCSS(env) : ''; }).join(' '); }, throwAwayComments: function () { this.value = this.value.filter(function(v) { return !(v instanceof tree.Comment); }); } }; })(require('../tree')); (function (tree) { tree.Extend = function Extend(selector, option, index) { this.selector = selector; this.option = option; this.index = index; switch(option) { case "all": this.allowBefore = true; this.allowAfter = true; break; default: this.allowBefore = false; this.allowAfter = false; break; } }; tree.Extend.prototype = { type: "Extend", accept: function (visitor) { this.selector = visitor.visit(this.selector); }, eval: function (env) { return new(tree.Extend)(this.selector.eval(env), this.option, this.index); }, clone: function (env) { return new(tree.Extend)(this.selector, this.option, this.index); }, findSelfSelectors: function (selectors) { var selfElements = [], i; for(i = 0; i < selectors.length; i++) { selfElements = selfElements.concat(selectors[i].elements); } this.selfSelectors = [{ elements: selfElements }]; } }; })(require('../tree')); (function (tree) { // // CSS @import node // // The general strategy here is that we don't want to wait // for the parsing to be completed, before we start importing // the file. That's because in the context of a browser, // most of the time will be spent waiting for the server to respond. // // On creation, we push the import path to our import queue, though // `import,push`, we also pass it a callback, which it'll call once // the file has been fetched, and parsed. // tree.Import = function (path, features, options, index, currentFileInfo) { var that = this; this.options = options; this.index = index; this.path = path; this.features = features; this.currentFileInfo = currentFileInfo; if (this.options.less !== undefined) { this.css = !this.options.less; } else { var pathValue = this.getPath(); if (pathValue && /css([\?;].*)?$/.test(pathValue)) { this.css = true; } } }; // // The actual import node doesn't return anything, when converted to CSS. // The reason is that it's used at the evaluation stage, so that the rules // it imports can be treated like any other rules. // // In `eval`, we make sure all Import nodes get evaluated, recursively, so // we end up with a flat structure, which can easily be imported in the parent // ruleset. // tree.Import.prototype = { type: "Import", accept: function (visitor) { this.features = visitor.visit(this.features); this.path = visitor.visit(this.path); this.root = visitor.visit(this.root); }, toCSS: function (env) { var features = this.features ? ' ' + this.features.toCSS(env) : ''; if (this.css) { return "@import " + this.path.toCSS() + features + ';\n'; } else { return ""; } }, getPath: function () { if (this.path instanceof tree.Quoted) { var path = this.path.value; return (this.css !== undefined || /(\.[a-z]*$)|([\?;].*)$/.test(path)) ? path : path + '.less'; } else if (this.path instanceof tree.URL) { return this.path.value.value; } return null; }, evalForImport: function (env) { return new(tree.Import)(this.path.eval(env), this.features, this.options, this.index, this.currentFileInfo); }, evalPath: function (env) { var path = this.path.eval(env); var rootpath = this.currentFileInfo && this.currentFileInfo.rootpath; if (rootpath && !(path instanceof tree.URL)) { var pathValue = path.value; // Add the base path if the import is relative if (pathValue && env.isPathRelative(pathValue)) { path.value = rootpath + pathValue; } } return path; }, eval: function (env) { var ruleset, features = this.features && this.features.eval(env); if (this.skip) { return []; } if (this.css) { var newImport = new(tree.Import)(this.evalPath(env), features, this.options, this.index); if (!newImport.css && this.error) { throw this.error; } return newImport; } else { ruleset = new(tree.Ruleset)([], this.root.rules.slice(0)); ruleset.evalImports(env); return this.features ? new(tree.Media)(ruleset.rules, this.features.value) : ruleset.rules; } } }; })(require('../tree')); (function (tree) { tree.JavaScript = function (string, index, escaped) { this.escaped = escaped; this.expression = string; this.index = index; }; tree.JavaScript.prototype = { type: "JavaScript", eval: function (env) { var result, that = this, context = {}; var expression = this.expression.replace(/@\{([\w-]+)\}/g, function (_, name) { return tree.jsify(new(tree.Variable)('@' + name, that.index).eval(env)); }); try { expression = new(Function)('return (' + expression + ')'); } catch (e) { throw { message: "JavaScript evaluation error: `" + expression + "`" , index: this.index }; } for (var k in env.frames[0].variables()) { context[k.slice(1)] = { value: env.frames[0].variables()[k].value, toJS: function () { return this.value.eval(env).toCSS(); } }; } try { result = expression.call(context); } catch (e) { throw { message: "JavaScript evaluation error: '" + e.name + ': ' + e.message + "'" , index: this.index }; } if (typeof(result) === 'string') { return new(tree.Quoted)('"' + result + '"', result, this.escaped, this.index); } else if (Array.isArray(result)) { return new(tree.Anonymous)(result.join(', ')); } else { return new(tree.Anonymous)(result); } } }; })(require('../tree')); (function (tree) { tree.Keyword = function (value) { this.value = value }; tree.Keyword.prototype = { type: "Keyword", eval: function () { return this; }, toCSS: function () { return this.value; }, compare: function (other) { if (other instanceof tree.Keyword) { return other.value === this.value ? 0 : 1; } else { return -1; } } }; tree.True = new(tree.Keyword)('true'); tree.False = new(tree.Keyword)('false'); })(require('../tree')); (function (tree) { tree.Media = function (value, features) { var selectors = this.emptySelectors(); this.features = new(tree.Value)(features); this.ruleset = new(tree.Ruleset)(selectors, value); this.ruleset.allowImports = true; }; tree.Media.prototype = { type: "Media", accept: function (visitor) { this.features = visitor.visit(this.features); this.ruleset = visitor.visit(this.ruleset); }, toCSS: function (env) { var features = this.features.toCSS(env); return '@media ' + features + (env.compress ? '{' : ' {\n ') + this.ruleset.toCSS(env).trim().replace(/\n/g, '\n ') + (env.compress ? '}': '\n}\n'); }, eval: function (env) { if (!env.mediaBlocks) { env.mediaBlocks = []; env.mediaPath = []; } var media = new(tree.Media)([], []); if(this.debugInfo) { this.ruleset.debugInfo = this.debugInfo; media.debugInfo = this.debugInfo; } var strictMathBypass = false; if (!env.strictMath) { strictMathBypass = true; env.strictMath = true; } try { media.features = this.features.eval(env); } finally { if (strictMathBypass) { env.strictMath = false; } } env.mediaPath.push(media); env.mediaBlocks.push(media); env.frames.unshift(this.ruleset); media.ruleset = this.ruleset.eval(env); env.frames.shift(); env.mediaPath.pop(); return env.mediaPath.length === 0 ? media.evalTop(env) : media.evalNested(env) }, variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) }, find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) }, rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) }, emptySelectors: function() { var el = new(tree.Element)('', '&', 0); return [new(tree.Selector)([el])]; }, evalTop: function (env) { var result = this; // Render all dependent Media blocks. if (env.mediaBlocks.length > 1) { var selectors = this.emptySelectors(); result = new(tree.Ruleset)(selectors, env.mediaBlocks); result.multiMedia = true; } delete env.mediaBlocks; delete env.mediaPath; return result; }, evalNested: function (env) { var i, value, path = env.mediaPath.concat([this]); // Extract the media-query conditions separated with `,` (OR). for (i = 0; i < path.length; i++) { value = path[i].features instanceof tree.Value ? path[i].features.value : path[i].features; path[i] = Array.isArray(value) ? value : [value]; } // Trace all permutations to generate the resulting media-query. // // (a, b and c) with nested (d, e) -> // a and d // a and e // b and c and d // b and c and e this.features = new(tree.Value)(this.permute(path).map(function (path) { path = path.map(function (fragment) { return fragment.toCSS ? fragment : new(tree.Anonymous)(fragment); }); for(i = path.length - 1; i > 0; i--) { path.splice(i, 0, new(tree.Anonymous)("and")); } return new(tree.Expression)(path); })); // Fake a tree-node that doesn't output anything. return new(tree.Ruleset)([], []); }, permute: function (arr) { if (arr.length === 0) { return []; } else if (arr.length === 1) { return arr[0]; } else { var result = []; var rest = this.permute(arr.slice(1)); for (var i = 0; i < rest.length; i++) { for (var j = 0; j < arr[0].length; j++) { result.push([arr[0][j]].concat(rest[i])); } } return result; } }, bubbleSelectors: function (selectors) { this.ruleset = new(tree.Ruleset)(selectors.slice(0), [this.ruleset]); } }; })(require('../tree')); (function (tree) { tree.mixin = {}; tree.mixin.Call = function (elements, args, index, currentFileInfo, important) { this.selector = new(tree.Selector)(elements); this.arguments = args; this.index = index; this.currentFileInfo = currentFileInfo; this.important = important; }; tree.mixin.Call.prototype = { type: "MixinCall", accept: function (visitor) { this.selector = visitor.visit(this.selector); this.arguments = visitor.visit(this.arguments); }, eval: function (env) { var mixins, mixin, args, rules = [], match = false, i, m, f, isRecursive, isOneFound; args = this.arguments && this.arguments.map(function (a) { return { name: a.name, value: a.value.eval(env) }; }); for (i = 0; i < env.frames.length; i++) { if ((mixins = env.frames[i].find(this.selector)).length > 0) { isOneFound = true; for (m = 0; m < mixins.length; m++) { mixin = mixins[m]; isRecursive = false; for(f = 0; f < env.frames.length; f++) { if ((!(mixin instanceof tree.mixin.Definition)) && mixin === (env.frames[f].originalRuleset || env.frames[f])) { isRecursive = true; break; } } if (isRecursive) { continue; } if (mixin.matchArgs(args, env)) { if (!mixin.matchCondition || mixin.matchCondition(args, env)) { try { Array.prototype.push.apply( rules, mixin.eval(env, args, this.important).rules); } catch (e) { throw { message: e.message, index: this.index, filename: this.currentFileInfo.filename, stack: e.stack }; } } match = true; } } if (match) { return rules; } } } if (isOneFound) { throw { type: 'Runtime', message: 'No matching definition was found for `' + this.selector.toCSS().trim() + '(' + (args ? args.map(function (a) { var argValue = ""; if (a.name) { argValue += a.name + ":"; } if (a.value.toCSS) { argValue += a.value.toCSS(); } else { argValue += "???"; } return argValue; }).join(', ') : "") + ")`", index: this.index, filename: this.currentFileInfo.filename }; } else { throw { type: 'Name', message: this.selector.toCSS().trim() + " is undefined", index: this.index, filename: this.currentFileInfo.filename }; } } }; tree.mixin.Definition = function (name, params, rules, condition, variadic) { this.name = name; this.selectors = [new(tree.Selector)([new(tree.Element)(null, name)])]; this.params = params; this.condition = condition; this.variadic = variadic; this.arity = params.length; this.rules = rules; this._lookups = {}; this.required = params.reduce(function (count, p) { if (!p.name || (p.name && !p.value)) { return count + 1 } else { return count } }, 0); this.parent = tree.Ruleset.prototype; this.frames = []; }; tree.mixin.Definition.prototype = { type: "MixinDefinition", accept: function (visitor) { this.params = visitor.visit(this.params); this.rules = visitor.visit(this.rules); this.condition = visitor.visit(this.condition); }, toCSS: function () { return ""; }, variable: function (name) { return this.parent.variable.call(this, name); }, variables: function () { return this.parent.variables.call(this); }, find: function () { return this.parent.find.apply(this, arguments); }, rulesets: function () { return this.parent.rulesets.apply(this); }, evalParams: function (env, mixinEnv, args, evaldArguments) { var frame = new(tree.Ruleset)(null, []), varargs, arg, params = this.params.slice(0), i, j, val, name, isNamedFound, argIndex; mixinEnv = new tree.evalEnv(mixinEnv, [frame].concat(mixinEnv.frames)); if (args) { args = args.slice(0); for(i = 0; i < args.length; i++) { arg = args[i]; if (name = (arg && arg.name)) { isNamedFound = false; for(j = 0; j < params.length; j++) { if (!evaldArguments[j] && name === params[j].name) { evaldArguments[j] = arg.value.eval(env); frame.rules.unshift(new(tree.Rule)(name, arg.value.eval(env))); isNamedFound = true; break; } } if (isNamedFound) { args.splice(i, 1); i--; continue; } else { throw { type: 'Runtime', message: "Named argument for " + this.name + ' ' + args[i].name + ' not found' }; } } } } argIndex = 0; for (i = 0; i < params.length; i++) { if (evaldArguments[i]) continue; arg = args && args[argIndex]; if (name = params[i].name) { if (params[i].variadic && args) { varargs = []; for (j = argIndex; j < args.length; j++) { varargs.push(args[j].value.eval(env)); } frame.rules.unshift(new(tree.Rule)(name, new(tree.Expression)(varargs).eval(env))); } else { val = arg && arg.value; if (val) { val = val.eval(env); } else if (params[i].value) { val = params[i].value.eval(mixinEnv); frame.resetCache(); } else { throw { type: 'Runtime', message: "wrong number of arguments for " + this.name + ' (' + args.length + ' for ' + this.arity + ')' }; } frame.rules.unshift(new(tree.Rule)(name, val)); evaldArguments[i] = val; } } if (params[i].variadic && args) { for (j = argIndex; j < args.length; j++) { evaldArguments[j] = args[j].value.eval(env); } } argIndex++; } return frame; }, eval: function (env, args, important) { var _arguments = [], mixinFrames = this.frames.concat(env.frames), frame = this.evalParams(env, new(tree.evalEnv)(env, mixinFrames), args, _arguments), context, rules, start, ruleset; frame.rules.unshift(new(tree.Rule)('@arguments', new(tree.Expression)(_arguments).eval(env))); rules = important ? this.parent.makeImportant.apply(this).rules : this.rules.slice(0); ruleset = new(tree.Ruleset)(null, rules).eval(new(tree.evalEnv)(env, [this, frame].concat(mixinFrames))); ruleset.originalRuleset = this; return ruleset; }, matchCondition: function (args, env) { if (this.condition && !this.condition.eval( new(tree.evalEnv)(env, [this.evalParams(env, new(tree.evalEnv)(env, this.frames.concat(env.frames)), args, [])] .concat(env.frames)))) { return false; } return true; }, matchArgs: function (args, env) { var argsLength = (args && args.length) || 0, len, frame; if (! this.variadic) { if (argsLength < this.required) { return false } if (argsLength > this.params.length) { return false } if ((this.required > 0) && (argsLength > this.params.length)) { return false } } len = Math.min(argsLength, this.arity); for (var i = 0; i < len; i++) { if (!this.params[i].name && !this.params[i].variadic) { if (args[i].value.eval(env).toCSS() != this.params[i].value.eval(env).toCSS()) { return false; } } } return true; } }; })(require('../tree')); (function (tree) { tree.Negative = function (node) { this.value = node; }; tree.Negative.prototype = { type: "Negative", accept: function (visitor) { this.value = visitor.visit(this.value); }, toCSS: function (env) { return '-' + this.value.toCSS(env); }, eval: function (env) { if (env.isMathOn()) { return (new(tree.Operation)('*', [new(tree.Dimension)(-1), this.value])).eval(env); } return new(tree.Negative)(this.value.eval(env)); } }; })(require('../tree')); (function (tree) { tree.Operation = function (op, operands, isSpaced) { this.op = op.trim(); this.operands = operands; this.isSpaced = isSpaced; }; tree.Operation.prototype = { type: "Operation", accept: function (visitor) { this.operands = visitor.visit(this.operands); }, eval: function (env) { var a = this.operands[0].eval(env), b = this.operands[1].eval(env), temp; if (env.isMathOn()) { if (a instanceof tree.Dimension && b instanceof tree.Color) { if (this.op === '*' || this.op === '+') { temp = b, b = a, a = temp; } else { throw { type: "Operation", message: "Can't substract or divide a color from a number" }; } } if (!a.operate) { throw { type: "Operation", message: "Operation on an invalid type" }; } return a.operate(env, this.op, b); } else { return new(tree.Operation)(this.op, [a, b], this.isSpaced); } }, toCSS: function (env) { var separator = this.isSpaced ? " " : ""; return this.operands[0].toCSS() + separator + this.op + separator + this.operands[1].toCSS(); } }; tree.operate = function (env, op, a, b) { switch (op) { case '+': return a + b; case '-': return a - b; case '*': return a * b; case '/': return a / b; } }; })(require('../tree')); (function (tree) { tree.Paren = function (node) { this.value = node; }; tree.Paren.prototype = { type: "Paren", accept: function (visitor) { this.value = visitor.visit(this.value); }, toCSS: function (env) { return '(' + this.value.toCSS(env).trim() + ')'; }, eval: function (env) { return new(tree.Paren)(this.value.eval(env)); } }; })(require('../tree')); (function (tree) { tree.Quoted = function (str, content, escaped, index, currentFileInfo) { this.escaped = escaped; this.value = content || ''; this.quote = str.charAt(0); this.index = index; this.currentFileInfo = currentFileInfo; }; tree.Quoted.prototype = { type: "Quoted", toCSS: function () { if (this.escaped) { return this.value; } else { return this.quote + this.value + this.quote; } }, eval: function (env) { var that = this; var value = this.value.replace(/`([^`]+)`/g, function (_, exp) { return new(tree.JavaScript)(exp, that.index, true).eval(env).value; }).replace(/@\{([\w-]+)\}/g, function (_, name) { var v = new(tree.Variable)('@' + name, that.index, that.currentFileInfo).eval(env, true); return (v instanceof tree.Quoted) ? v.value : v.toCSS(); }); return new(tree.Quoted)(this.quote + value + this.quote, value, this.escaped, this.index); }, compare: function (x) { if (!x.toCSS) { return -1; } var left = this.toCSS(), right = x.toCSS(); if (left === right) { return 0; } return left < right ? -1 : 1; } }; })(require('../tree')); (function (tree) { tree.Rule = function (name, value, important, index, currentFileInfo, inline) { this.name = name; this.value = (value instanceof tree.Value) ? value : new(tree.Value)([value]); this.important = important ? ' ' + important.trim() : ''; this.index = index; this.currentFileInfo = currentFileInfo; this.inline = inline || false; if (name.charAt(0) === '@') { this.variable = true; } else { this.variable = false } }; tree.Rule.prototype = { type: "Rule", accept: function (visitor) { this.value = visitor.visit(this.value); }, toCSS: function (env) { if (this.variable) { return "" } else { try { return this.name + (env.compress ? ':' : ': ') + this.value.toCSS(env) + this.important + (this.inline ? "" : ";"); } catch(e) { e.index = this.index; e.filename = this.currentFileInfo.filename; throw e; } } }, eval: function (env) { var strictMathBypass = false; if (this.name === "font" && !env.strictMath) { strictMathBypass = true; env.strictMath = true; } try { return new(tree.Rule)(this.name, this.value.eval(env), this.important, this.index, this.currentFileInfo, this.inline); } finally { if (strictMathBypass) { env.strictMath = false; } } }, makeImportant: function () { return new(tree.Rule)(this.name, this.value, "!important", this.index, this.currentFileInfo, this.inline); } }; })(require('../tree')); (function (tree) { tree.Ruleset = function (selectors, rules, strictImports) { this.selectors = selectors; this.rules = rules; this._lookups = {}; this.strictImports = strictImports; }; tree.Ruleset.prototype = { type: "Ruleset", accept: function (visitor) { this.selectors = visitor.visit(this.selectors); this.rules = visitor.visit(this.rules); }, eval: function (env) { var selectors = this.selectors && this.selectors.map(function (s) { return s.eval(env) }); var ruleset = new(tree.Ruleset)(selectors, this.rules.slice(0), this.strictImports); var rules; ruleset.originalRuleset = this; ruleset.root = this.root; ruleset.firstRoot = this.firstRoot; ruleset.allowImports = this.allowImports; if(this.debugInfo) { ruleset.debugInfo = this.debugInfo; } // push the current ruleset to the frames stack env.frames.unshift(ruleset); // currrent selectors if (!env.selectors) { env.selectors = []; } env.selectors.unshift(this.selectors); // Evaluate imports if (ruleset.root || ruleset.allowImports || !ruleset.strictImports) { ruleset.evalImports(env); } // Store the frames around mixin definitions, // so they can be evaluated like closures when the time comes. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Definition) { ruleset.rules[i].frames = env.frames.slice(0); } } var mediaBlockCount = (env.mediaBlocks && env.mediaBlocks.length) || 0; // Evaluate mixin calls. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Call) { rules = ruleset.rules[i].eval(env).filter(function(r) { if ((r instanceof tree.Rule) && r.variable) { // do not pollute the scope if the variable is // already there. consider returning false here // but we need a way to "return" variable from mixins return !(ruleset.variable(r.name)); } return true; }); ruleset.rules.splice.apply(ruleset.rules, [i, 1].concat(rules)); i += rules.length-1; ruleset.resetCache(); } } // Evaluate everything else for (var i = 0, rule; i < ruleset.rules.length; i++) { rule = ruleset.rules[i]; if (! (rule instanceof tree.mixin.Definition)) { ruleset.rules[i] = rule.eval ? rule.eval(env) : rule; } } // Pop the stack env.frames.shift(); env.selectors.shift(); if (env.mediaBlocks) { for(var i = mediaBlockCount; i < env.mediaBlocks.length; i++) { env.mediaBlocks[i].bubbleSelectors(selectors); } } return ruleset; }, evalImports: function(env) { var i, rules; for (i = 0; i < this.rules.length; i++) { if (this.rules[i] instanceof tree.Import) { rules = this.rules[i].eval(env); if (typeof rules.length === "number") { this.rules.splice.apply(this.rules, [i, 1].concat(rules)); i+= rules.length-1; } else { this.rules.splice(i, 1, rules); } this.resetCache(); } } }, makeImportant: function() { return new tree.Ruleset(this.selectors, this.rules.map(function (r) { if (r.makeImportant) { return r.makeImportant(); } else { return r; } }), this.strictImports); }, matchArgs: function (args) { return !args || args.length === 0; }, resetCache: function () { this._rulesets = null; this._variables = null; this._lookups = {}; }, variables: function () { if (this._variables) { return this._variables } else { return this._variables = this.rules.reduce(function (hash, r) { if (r instanceof tree.Rule && r.variable === true) { hash[r.name] = r; } return hash; }, {}); } }, variable: function (name) { return this.variables()[name]; }, rulesets: function () { return this.rules.filter(function (r) { return (r instanceof tree.Ruleset) || (r instanceof tree.mixin.Definition); }); }, find: function (selector, self) { self = self || this; var rules = [], rule, match, key = selector.toCSS(); if (key in this._lookups) { return this._lookups[key] } this.rulesets().forEach(function (rule) { if (rule !== self) { for (var j = 0; j < rule.selectors.length; j++) { if (match = selector.match(rule.selectors[j])) { if (selector.elements.length > rule.selectors[j].elements.length) { Array.prototype.push.apply(rules, rule.find( new(tree.Selector)(selector.elements.slice(1)), self)); } else { rules.push(rule); } break; } } } }); return this._lookups[key] = rules; }, // // Entry point for code generation // // `context` holds an array of arrays. // toCSS: function (env) { var css = [], // The CSS output rules = [], // node.Rule instances _rules = [], // rulesets = [], // node.Ruleset instances selector, // The fully rendered selector debugInfo, // Line number debugging rule; // Compile rules and rulesets for (var i = 0; i < this.rules.length; i++) { rule = this.rules[i]; if (rule.rules || (rule instanceof tree.Media)) { rulesets.push(rule.toCSS(env)); } else if (rule instanceof tree.Directive) { var cssValue = rule.toCSS(env); // Output only the first @charset definition as such - convert the others // to comments in case debug is enabled if (rule.name === "@charset") { // Only output the debug info together with subsequent @charset definitions // a comment (or @media statement) before the actual @charset directive would // be considered illegal css as it has to be on the first line if (env.charset) { if (rule.debugInfo) { rulesets.push(tree.debugInfo(env, rule)); rulesets.push(new tree.Comment("/* "+cssValue.replace(/\n/g, "")+" */\n").toCSS(env)); } continue; } env.charset = true; } rulesets.push(cssValue); } else if (rule instanceof tree.Comment) { if (!rule.silent) { if (this.root) { rulesets.push(rule.toCSS(env)); } else { rules.push(rule.toCSS(env)); } } } else { if (rule.toCSS && !rule.variable) { if (this.firstRoot && rule instanceof tree.Rule) { throw { message: "properties must be inside selector blocks, they cannot be in the root.", index: rule.index, filename: rule.currentFileInfo ? rule.currentFileInfo.filename : null}; } rules.push(rule.toCSS(env)); } else if (rule.value && !rule.variable) { rules.push(rule.value.toString()); } } } // Remove last semicolon if (env.compress && rules.length) { rule = rules[rules.length - 1]; if (rule.charAt(rule.length - 1) === ';') { rules[rules.length - 1] = rule.substring(0, rule.length - 1); } } rulesets = rulesets.join(''); // If this is the root node, we don't render // a selector, or {}. // Otherwise, only output if this ruleset has rules. if (this.root) { css.push(rules.join(env.compress ? '' : '\n')); } else { if (rules.length > 0) { debugInfo = tree.debugInfo(env, this); selector = this.paths.map(function (p) { return p.map(function (s) { return s.toCSS(env); }).join('').trim(); }).join(env.compress ? ',' : ',\n'); // Remove duplicates for (var i = rules.length - 1; i >= 0; i--) { if (rules[i].slice(0, 2) === "/*" || _rules.indexOf(rules[i]) === -1) { _rules.unshift(rules[i]); } } rules = _rules; css.push(debugInfo + selector + (env.compress ? '{' : ' {\n ') + rules.join(env.compress ? '' : '\n ') + (env.compress ? '}' : '\n}\n')); } } css.push(rulesets); return css.join('') + (env.compress ? '\n' : ''); }, joinSelectors: function (paths, context, selectors) { for (var s = 0; s < selectors.length; s++) { this.joinSelector(paths, context, selectors[s]); } }, joinSelector: function (paths, context, selector) { var i, j, k, hasParentSelector, newSelectors, el, sel, parentSel, newSelectorPath, afterParentJoin, newJoinedSelector, newJoinedSelectorEmpty, lastSelector, currentElements, selectorsMultiplied; for (i = 0; i < selector.elements.length; i++) { el = selector.elements[i]; if (el.value === '&') { hasParentSelector = true; } } if (!hasParentSelector) { if (context.length > 0) { for(i = 0; i < context.length; i++) { paths.push(context[i].concat(selector)); } } else { paths.push([selector]); } return; } // The paths are [[Selector]] // The first list is a list of comma seperated selectors // The inner list is a list of inheritance seperated selectors // e.g. // .a, .b { // .c { // } // } // == [[.a] [.c]] [[.b] [.c]] // // the elements from the current selector so far currentElements = []; // the current list of new selectors to add to the path. // We will build it up. We initiate it with one empty selector as we "multiply" the new selectors // by the parents newSelectors = [[]]; for (i = 0; i < selector.elements.length; i++) { el = selector.elements[i]; // non parent reference elements just get added if (el.value !== "&") { currentElements.push(el); } else { // the new list of selectors to add selectorsMultiplied = []; // merge the current list of non parent selector elements // on to the current list of selectors to add if (currentElements.length > 0) { this.mergeElementsOnToSelectors(currentElements, newSelectors); } // loop through our current selectors for(j = 0; j < newSelectors.length; j++) { sel = newSelectors[j]; // if we don't have any parent paths, the & might be in a mixin so that it can be used // whether there are parents or not if (context.length == 0) { // the combinator used on el should now be applied to the next element instead so that // it is not lost if (sel.length > 0) { sel[0].elements = sel[0].elements.slice(0); sel[0].elements.push(new(tree.Element)(el.combinator, '', 0)); //new Element(el.Combinator, "")); } selectorsMultiplied.push(sel); } else { // and the parent selectors for(k = 0; k < context.length; k++) { parentSel = context[k]; // We need to put the current selectors // then join the last selector's elements on to the parents selectors // our new selector path newSelectorPath = []; // selectors from the parent after the join afterParentJoin = []; newJoinedSelectorEmpty = true; //construct the joined selector - if & is the first thing this will be empty, // if not newJoinedSelector will be the last set of elements in the selector if (sel.length > 0) { newSelectorPath = sel.slice(0); lastSelector = newSelectorPath.pop(); newJoinedSelector = new(tree.Selector)(lastSelector.elements.slice(0), selector.extendList); newJoinedSelectorEmpty = false; } else { newJoinedSelector = new(tree.Selector)([], selector.extendList); } //put together the parent selectors after the join if (parentSel.length > 1) { afterParentJoin = afterParentJoin.concat(parentSel.slice(1)); } if (parentSel.length > 0) { newJoinedSelectorEmpty = false; // join the elements so far with the first part of the parent newJoinedSelector.elements.push(new(tree.Element)(el.combinator, parentSel[0].elements[0].value, 0)); newJoinedSelector.elements = newJoinedSelector.elements.concat(parentSel[0].elements.slice(1)); } if (!newJoinedSelectorEmpty) { // now add the joined selector newSelectorPath.push(newJoinedSelector); } // and the rest of the parent newSelectorPath = newSelectorPath.concat(afterParentJoin); // add that to our new set of selectors selectorsMultiplied.push(newSelectorPath); } } } // our new selectors has been multiplied, so reset the state newSelectors = selectorsMultiplied; currentElements = []; } } // if we have any elements left over (e.g. .a& .b == .b) // add them on to all the current selectors if (currentElements.length > 0) { this.mergeElementsOnToSelectors(currentElements, newSelectors); } for(i = 0; i < newSelectors.length; i++) { if (newSelectors[i].length > 0) { paths.push(newSelectors[i]); } } }, mergeElementsOnToSelectors: function(elements, selectors) { var i, sel, extendList; if (selectors.length == 0) { selectors.push([ new(tree.Selector)(elements) ]); return; } for(i = 0; i < selectors.length; i++) { sel = selectors[i]; // if the previous thing in sel is a parent this needs to join on to it if (sel.length > 0) { sel[sel.length - 1] = new(tree.Selector)(sel[sel.length - 1].elements.concat(elements), sel[sel.length - 1].extendList); } else { sel.push(new(tree.Selector)(elements)); } } } }; })(require('../tree')); (function (tree) { tree.Selector = function (elements, extendList) { this.elements = elements; this.extendList = extendList || []; }; tree.Selector.prototype = { type: "Selector", accept: function (visitor) { this.elements = visitor.visit(this.elements); this.extendList = visitor.visit(this.extendList) }, match: function (other) { var elements = this.elements, len = elements.length, oelements, olen, max, i; oelements = other.elements.slice( (other.elements.length && other.elements[0].value === "&") ? 1 : 0); olen = oelements.length; max = Math.min(len, olen); if (olen === 0 || len < olen) { return false; } else { for (i = 0; i < max; i++) { if (elements[i].value !== oelements[i].value) { return false; } } } return true; }, eval: function (env) { return new(tree.Selector)(this.elements.map(function (e) { return e.eval(env); }), this.extendList.map(function(extend) { return extend.eval(env); })); }, toCSS: function (env) { if (this._css) { return this._css } if (this.elements[0].combinator.value === "") { this._css = ' '; } else { this._css = ''; } this._css += this.elements.map(function (e) { if (typeof(e) === 'string') { return ' ' + e.trim(); } else { return e.toCSS(env); } }).join(''); return this._css; } }; })(require('../tree')); (function (tree) { tree.UnicodeDescriptor = function (value) { this.value = value; }; tree.UnicodeDescriptor.prototype = { type: "UnicodeDescriptor", toCSS: function (env) { return this.value; }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.URL = function (val, currentFileInfo) { this.value = val; this.currentFileInfo = currentFileInfo; }; tree.URL.prototype = { type: "Url", accept: function (visitor) { this.value = visitor.visit(this.value); }, toCSS: function () { return "url(" + this.value.toCSS() + ")"; }, eval: function (ctx) { var val = this.value.eval(ctx), rootpath; // Add the base path if the URL is relative rootpath = this.currentFileInfo && this.currentFileInfo.rootpath; if (rootpath && typeof val.value === "string" && ctx.isPathRelative(val.value)) { if (!val.quote) { rootpath = rootpath.replace(/[\(\)'"\s]/g, function(match) { return "\\"+match; }); } val.value = rootpath + val.value; } return new(tree.URL)(val, null); } }; })(require('../tree')); (function (tree) { tree.Value = function (value) { this.value = value; }; tree.Value.prototype = { type: "Value", accept: function (visitor) { this.value = visitor.visit(this.value); }, eval: function (env) { if (this.value.length === 1) { return this.value[0].eval(env); } else { return new(tree.Value)(this.value.map(function (v) { return v.eval(env); })); } }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS(env); }).join(env.compress ? ',' : ', '); } }; })(require('../tree')); (function (tree) { tree.Variable = function (name, index, currentFileInfo) { this.name = name, this.index = index, this.currentFileInfo = currentFileInfo }; tree.Variable.prototype = { type: "Variable", eval: function (env) { var variable, v, name = this.name; if (name.indexOf('@@') == 0) { name = '@' + new(tree.Variable)(name.slice(1)).eval(env).value; } if (this.evaluating) { throw { type: 'Name', message: "Recursive variable definition for " + name, filename: this.currentFileInfo.file, index: this.index }; } this.evaluating = true; if (variable = tree.find(env.frames, function (frame) { if (v = frame.variable(name)) { return v.value.eval(env); } })) { this.evaluating = false; return variable; } else { throw { type: 'Name', message: "variable " + name + " is undefined", filename: this.currentFileInfo.filename, index: this.index }; } } }; })(require('../tree')); (function (tree) { tree.debugInfo = function(env, ctx) { var result=""; if (env.dumpLineNumbers && !env.compress) { switch(env.dumpLineNumbers) { case 'comments': result = tree.debugInfo.asComment(ctx); break; case 'mediaquery': result = tree.debugInfo.asMediaQuery(ctx); break; case 'all': result = tree.debugInfo.asComment(ctx)+tree.debugInfo.asMediaQuery(ctx); break; } } return result; }; tree.debugInfo.asComment = function(ctx) { return '/* line ' + ctx.debugInfo.lineNumber + ', ' + ctx.debugInfo.fileName + ' */\n'; }; tree.debugInfo.asMediaQuery = function(ctx) { return '@media -sass-debug-info{filename{font-family:' + ('file://' + ctx.debugInfo.fileName).replace(/([.:/\\])/g, function(a){if(a=='\\') a = '\/'; return '\\' + a}) + '}line{font-family:\\00003' + ctx.debugInfo.lineNumber + '}}\n'; }; tree.find = function (obj, fun) { for (var i = 0, r; i < obj.length; i++) { if (r = fun.call(obj, obj[i])) { return r } } return null; }; tree.jsify = function (obj) { if (Array.isArray(obj.value) && (obj.value.length > 1)) { return '[' + obj.value.map(function (v) { return v.toCSS(false) }).join(', ') + ']'; } else { return obj.toCSS(false); } }; })(require('./tree')); (function (tree) { var parseCopyProperties = [ 'paths', // option - unmodified - paths to search for imports on 'optimization', // option - optimization level (for the chunker) 'files', // list of files that have been imported, used for import-once 'contents', // browser-only, contents of all the files 'relativeUrls', // option - whether to adjust URL's to be relative 'strictImports', // option - 'dumpLineNumbers', // option - whether to dump line numbers 'compress', // option - whether to compress 'processImports', // option - whether to process imports. if false then imports will not be imported 'syncImport', // option - whether to import synchronously 'mime', // browser only - mime type for sheet import 'currentFileInfo' // information about the current file - for error reporting and importing and making urls relative etc. ]; //currentFileInfo = { // 'relativeUrls' - option - whether to adjust URL's to be relative // 'filename' - full resolved filename of current file // 'rootpath' - path to append to normal URLs for this node // 'currentDirectory' - path to the current file, absolute // 'rootFilename' - filename of the base file // 'entryPath' = absolute path to the entry file tree.parseEnv = function(options) { copyFromOriginal(options, this, parseCopyProperties); if (!this.contents) { this.contents = {}; } if (!this.files) { this.files = {}; } if (!this.currentFileInfo) { var filename = (options && options.filename) || "input"; var entryPath = filename.replace(/[^\/\\]*$/, ""); if (options) { options.filename = null; } this.currentFileInfo = { filename: filename, relativeUrls: this.relativeUrls, rootpath: (options && options.rootpath) || "", currentDirectory: entryPath, entryPath: entryPath, rootFilename: filename }; } }; tree.parseEnv.prototype.toSheet = function (path) { var env = new tree.parseEnv(this); env.href = path; //env.title = path; env.type = this.mime; return env; }; var evalCopyProperties = [ 'silent', // whether to swallow errors and warnings 'verbose', // whether to log more activity 'compress', // whether to compress 'yuicompress', // whether to compress with the outside tool yui compressor 'ieCompat', // whether to enforce IE compatibility (IE8 data-uri) 'strictMath', // whether math has to be within parenthesis 'strictUnits' // whether units need to evaluate correctly ]; tree.evalEnv = function(options, frames) { copyFromOriginal(options, this, evalCopyProperties); this.frames = frames || []; }; tree.evalEnv.prototype.inParenthesis = function () { if (!this.parensStack) { this.parensStack = []; } this.parensStack.push(true); }; tree.evalEnv.prototype.outOfParenthesis = function () { this.parensStack.pop(); }; tree.evalEnv.prototype.isMathOn = function () { return this.strictMath ? (this.parensStack && this.parensStack.length) : true; }; tree.evalEnv.prototype.isPathRelative = function (path) { return !/^(?:[a-z-]+:|\/)/.test(path); }; //todo - do the same for the toCSS env //tree.toCSSEnv = function (options) { //}; var copyFromOriginal = function(original, destination, propertiesToCopy) { if (!original) { return; } for(var i = 0; i < propertiesToCopy.length; i++) { if (original.hasOwnProperty(propertiesToCopy[i])) { destination[propertiesToCopy[i]] = original[propertiesToCopy[i]]; } } } })(require('./tree'));(function (tree) { tree.visitor = function(implementation) { this._implementation = implementation; }; tree.visitor.prototype = { visit: function(node) { if (node instanceof Array) { return this.visitArray(node); } if (!node || !node.type) { return node; } var funcName = "visit" + node.type, func = this._implementation[funcName], visitArgs, newNode; if (func) { visitArgs = {visitDeeper: true}; newNode = func.call(this._implementation, node, visitArgs); if (this._implementation.isReplacing) { node = newNode; } } if ((!visitArgs || visitArgs.visitDeeper) && node && node.accept) { node.accept(this); } funcName = funcName + "Out"; if (this._implementation[funcName]) { this._implementation[funcName](node); } return node; }, visitArray: function(nodes) { var i, newNodes = []; for(i = 0; i < nodes.length; i++) { var evald = this.visit(nodes[i]); if (evald instanceof Array) { newNodes = newNodes.concat(evald); } else { newNodes.push(evald); } } if (this._implementation.isReplacing) { return newNodes; } return nodes; } }; })(require('./tree'));(function (tree) { tree.importVisitor = function(importer, finish, evalEnv) { this._visitor = new tree.visitor(this); this._importer = importer; this._finish = finish; this.env = evalEnv || new tree.evalEnv(); this.importCount = 0; }; tree.importVisitor.prototype = { isReplacing: true, run: function (root) { var error; try { // process the contents this._visitor.visit(root); } catch(e) { error = e; } this.isFinished = true; if (this.importCount === 0) { this._finish(error); } }, visitImport: function (importNode, visitArgs) { var importVisitor = this, evaldImportNode; if (!importNode.css) { try { evaldImportNode = importNode.evalForImport(this.env); } catch(e){ if (!e.filename) { e.index = importNode.index; e.filename = importNode.currentFileInfo.filename; } // attempt to eval properly and treat as css importNode.css = true; // if that fails, this error will be thrown importNode.error = e; } if (evaldImportNode && !evaldImportNode.css) { importNode = evaldImportNode; this.importCount++; var env = new tree.evalEnv(this.env, this.env.frames.slice(0)); this._importer.push(importNode.getPath(), importNode.currentFileInfo, function (e, root, imported) { if (e && !e.filename) { e.index = importNode.index; e.filename = importNode.currentFileInfo.filename; } if (imported && !importNode.options.multiple) { importNode.skip = imported; } var subFinish = function(e) { importVisitor.importCount--; if (importVisitor.importCount === 0 && importVisitor.isFinished) { importVisitor._finish(e); } }; if (root) { importNode.root = root; new(tree.importVisitor)(importVisitor._importer, subFinish, env) .run(root); } else { subFinish(); } }); } } visitArgs.visitDeeper = false; return importNode; }, visitRule: function (ruleNode, visitArgs) { visitArgs.visitDeeper = false; return ruleNode; }, visitDirective: function (directiveNode, visitArgs) { this.env.frames.unshift(directiveNode); return directiveNode; }, visitDirectiveOut: function (directiveNode) { this.env.frames.shift(); }, visitMixinDefinition: function (mixinDefinitionNode, visitArgs) { this.env.frames.unshift(mixinDefinitionNode); return mixinDefinitionNode; }, visitMixinDefinitionOut: function (mixinDefinitionNode) { this.env.frames.shift(); }, visitRuleset: function (rulesetNode, visitArgs) { this.env.frames.unshift(rulesetNode); return rulesetNode; }, visitRulesetOut: function (rulesetNode) { this.env.frames.shift(); }, visitMedia: function (mediaNode, visitArgs) { this.env.frames.unshift(mediaNode.ruleset); return mediaNode; }, visitMediaOut: function (mediaNode) { this.env.frames.shift(); } }; })(require('./tree'));(function (tree) { tree.joinSelectorVisitor = function() { this.contexts = [[]]; this._visitor = new tree.visitor(this); }; tree.joinSelectorVisitor.prototype = { run: function (root) { return this._visitor.visit(root); }, visitRule: function (ruleNode, visitArgs) { visitArgs.visitDeeper = false; }, visitMixinDefinition: function (mixinDefinitionNode, visitArgs) { visitArgs.visitDeeper = false; }, visitRuleset: function (rulesetNode, visitArgs) { var context = this.contexts[this.contexts.length - 1]; var paths = []; this.contexts.push(paths); if (! rulesetNode.root) { rulesetNode.joinSelectors(paths, context, rulesetNode.selectors); rulesetNode.paths = paths; } }, visitRulesetOut: function (rulesetNode) { this.contexts.length = this.contexts.length - 1; }, visitMedia: function (mediaNode, visitArgs) { var context = this.contexts[this.contexts.length - 1]; mediaNode.ruleset.root = (context.length === 0 || context[0].multiMedia); } }; })(require('./tree'));(function (tree) { tree.extendFinderVisitor = function() { this._visitor = new tree.visitor(this); this.contexts = []; this.allExtendsStack = [[]]; }; tree.extendFinderVisitor.prototype = { run: function (root) { root = this._visitor.visit(root); root.allExtends = this.allExtendsStack[0]; return root; }, visitRule: function (ruleNode, visitArgs) { visitArgs.visitDeeper = false; }, visitMixinDefinition: function (mixinDefinitionNode, visitArgs) { visitArgs.visitDeeper = false; }, visitRuleset: function (rulesetNode, visitArgs) { if (rulesetNode.root) { return; } var i, j, extend, allSelectorsExtendList = [], extendList; // get &:extend(.a); rules which apply to all selectors in this ruleset for(i = 0; i < rulesetNode.rules.length; i++) { if (rulesetNode.rules[i] instanceof tree.Extend) { allSelectorsExtendList.push(rulesetNode.rules[i]); } } // now find every selector and apply the extends that apply to all extends // and the ones which apply to an individual extend for(i = 0; i < rulesetNode.paths.length; i++) { var selectorPath = rulesetNode.paths[i], selector = selectorPath[selectorPath.length-1]; extendList = selector.extendList.slice(0).concat(allSelectorsExtendList).map(function(allSelectorsExtend) { return allSelectorsExtend.clone(); }); for(j = 0; j < extendList.length; j++) { this.foundExtends = true; extend = extendList[j]; extend.findSelfSelectors(selectorPath); extend.ruleset = rulesetNode; if (j === 0) { extend.firstExtendOnThisSelectorPath = true; } this.allExtendsStack[this.allExtendsStack.length-1].push(extend); } } this.contexts.push(rulesetNode.selectors); }, visitRulesetOut: function (rulesetNode) { if (!rulesetNode.root) { this.contexts.length = this.contexts.length - 1; } }, visitMedia: function (mediaNode, visitArgs) { mediaNode.allExtends = []; this.allExtendsStack.push(mediaNode.allExtends); }, visitMediaOut: function (mediaNode) { this.allExtendsStack.length = this.allExtendsStack.length - 1; }, visitDirective: function (directiveNode, visitArgs) { directiveNode.allExtends = []; this.allExtendsStack.push(directiveNode.allExtends); }, visitDirectiveOut: function (directiveNode) { this.allExtendsStack.length = this.allExtendsStack.length - 1; } }; tree.processExtendsVisitor = function() { this._visitor = new tree.visitor(this); }; tree.processExtendsVisitor.prototype = { run: function(root) { var extendFinder = new tree.extendFinderVisitor(); extendFinder.run(root); if (!extendFinder.foundExtends) { return root; } root.allExtends = root.allExtends.concat(this.doExtendChaining(root.allExtends, root.allExtends)); this.allExtendsStack = [root.allExtends]; return this._visitor.visit(root); }, doExtendChaining: function (extendsList, extendsListTarget, iterationCount) { // // chaining is different from normal extension.. if we extend an extend then we are not just copying, altering and pasting // the selector we would do normally, but we are also adding an extend with the same target selector // this means this new extend can then go and alter other extends // // this method deals with all the chaining work - without it, extend is flat and doesn't work on other extend selectors // this is also the most expensive.. and a match on one selector can cause an extension of a selector we had already processed if // we look at each selector at a time, as is done in visitRuleset var extendIndex, targetExtendIndex, matches, extendsToAdd = [], newSelector, extendVisitor = this, selectorPath, extend, targetExtend, newExtend; iterationCount = iterationCount || 0; //loop through comparing every extend with every target extend. // a target extend is the one on the ruleset we are looking at copy/edit/pasting in place // e.g. .a:extend(.b) {} and .b:extend(.c) {} then the first extend extends the second one // and the second is the target. // the seperation into two lists allows us to process a subset of chains with a bigger set, as is the // case when processing media queries for(extendIndex = 0; extendIndex < extendsList.length; extendIndex++){ for(targetExtendIndex = 0; targetExtendIndex < extendsListTarget.length; targetExtendIndex++){ extend = extendsList[extendIndex]; targetExtend = extendsListTarget[targetExtendIndex]; // look for circular references if (this.inInheritanceChain(targetExtend, extend)) { continue; } // find a match in the target extends self selector (the bit before :extend) selectorPath = [targetExtend.selfSelectors[0]]; matches = extendVisitor.findMatch(extend, selectorPath); if (matches.length) { // we found a match, so for each self selector.. extend.selfSelectors.forEach(function(selfSelector) { // process the extend as usual newSelector = extendVisitor.extendSelector(matches, selectorPath, selfSelector); // but now we create a new extend from it newExtend = new(tree.Extend)(targetExtend.selector, targetExtend.option, 0); newExtend.selfSelectors = newSelector; // add the extend onto the list of extends for that selector newSelector[newSelector.length-1].extendList = [newExtend]; // record that we need to add it. extendsToAdd.push(newExtend); newExtend.ruleset = targetExtend.ruleset; //remember its parents for circular references newExtend.parents = [targetExtend, extend]; // only process the selector once.. if we have :extend(.a,.b) then multiple // extends will look at the same selector path, so when extending // we know that any others will be duplicates in terms of what is added to the css if (targetExtend.firstExtendOnThisSelectorPath) { newExtend.firstExtendOnThisSelectorPath = true; targetExtend.ruleset.paths.push(newSelector); } }); } } } if (extendsToAdd.length) { // try to detect circular references to stop a stack overflow. // may no longer be needed. this.extendChainCount++; if (iterationCount > 100) { var selectorOne = "{unable to calculate}"; var selectorTwo = "{unable to calculate}"; try { selectorOne = extendsToAdd[0].selfSelectors[0].toCSS(); selectorTwo = extendsToAdd[0].selector.toCSS(); } catch(e) {} throw {message: "extend circular reference detected. One of the circular extends is currently:"+selectorOne+":extend(" + selectorTwo+")"}; } // now process the new extends on the existing rules so that we can handle a extending b extending c ectending d extending e... return extendsToAdd.concat(extendVisitor.doExtendChaining(extendsToAdd, extendsListTarget, iterationCount+1)); } else { return extendsToAdd; } }, inInheritanceChain: function (possibleParent, possibleChild) { if (possibleParent === possibleChild) { return true; } if (possibleChild.parents) { if (this.inInheritanceChain(possibleParent, possibleChild.parents[0])) { return true; } if (this.inInheritanceChain(possibleParent, possibleChild.parents[1])) { return true; } } return false; }, visitRule: function (ruleNode, visitArgs) { visitArgs.visitDeeper = false; }, visitMixinDefinition: function (mixinDefinitionNode, visitArgs) { visitArgs.visitDeeper = false; }, visitSelector: function (selectorNode, visitArgs) { visitArgs.visitDeeper = false; }, visitRuleset: function (rulesetNode, visitArgs) { if (rulesetNode.root) { return; } var matches, pathIndex, extendIndex, allExtends = this.allExtendsStack[this.allExtendsStack.length-1], selectorsToAdd = [], extendVisitor = this, selectorPath; // look at each selector path in the ruleset, find any extend matches and then copy, find and replace for(extendIndex = 0; extendIndex < allExtends.length; extendIndex++) { for(pathIndex = 0; pathIndex < rulesetNode.paths.length; pathIndex++) { selectorPath = rulesetNode.paths[pathIndex]; // extending extends happens initially, before the main pass if (selectorPath[selectorPath.length-1].extendList.length) { continue; } matches = this.findMatch(allExtends[extendIndex], selectorPath); if (matches.length) { allExtends[extendIndex].selfSelectors.forEach(function(selfSelector) { selectorsToAdd.push(extendVisitor.extendSelector(matches, selectorPath, selfSelector)); }); } } } rulesetNode.paths = rulesetNode.paths.concat(selectorsToAdd); }, findMatch: function (extend, haystackSelectorPath) { // // look through the haystack selector path to try and find the needle - extend.selector // returns an array of selector matches that can then be replaced // var haystackSelectorIndex, hackstackSelector, hackstackElementIndex, haystackElement, targetCombinator, i, extendVisitor = this, needleElements = extend.selector.elements, potentialMatches = [], potentialMatch, matches = []; // loop through the haystack elements for(haystackSelectorIndex = 0; haystackSelectorIndex < haystackSelectorPath.length; haystackSelectorIndex++) { hackstackSelector = haystackSelectorPath[haystackSelectorIndex]; for(hackstackElementIndex = 0; hackstackElementIndex < hackstackSelector.elements.length; hackstackElementIndex++) { haystackElement = hackstackSelector.elements[hackstackElementIndex]; // if we allow elements before our match we can add a potential match every time. otherwise only at the first element. if (extend.allowBefore || (haystackSelectorIndex == 0 && hackstackElementIndex == 0)) { potentialMatches.push({pathIndex: haystackSelectorIndex, index: hackstackElementIndex, matched: 0, initialCombinator: haystackElement.combinator}); } for(i = 0; i < potentialMatches.length; i++) { potentialMatch = potentialMatches[i]; // selectors add " " onto the first element. When we use & it joins the selectors together, but if we don't // then each selector in haystackSelectorPath has a space before it added in the toCSS phase. so we need to work out // what the resulting combinator will be targetCombinator = haystackElement.combinator.value; if (targetCombinator == '' && hackstackElementIndex === 0) { targetCombinator = ' '; } // if we don't match, null our match to indicate failure if (!extendVisitor.isElementValuesEqual(needleElements[potentialMatch.matched].value, haystackElement.value) || (potentialMatch.matched > 0 && needleElements[potentialMatch.matched].combinator.value !== targetCombinator)) { potentialMatch = null; } else { potentialMatch.matched++; } // if we are still valid and have finished, test whether we have elements after and whether these are allowed if (potentialMatch) { potentialMatch.finished = potentialMatch.matched === needleElements.length; if (potentialMatch.finished && (!extend.allowAfter && (hackstackElementIndex+1 < hackstackSelector.elements.length || haystackSelectorIndex+1 < haystackSelectorPath.length))) { potentialMatch = null; } } // if null we remove, if not, we are still valid, so either push as a valid match or continue if (potentialMatch) { if (potentialMatch.finished) { potentialMatch.length = needleElements.length; potentialMatch.endPathIndex = haystackSelectorIndex; potentialMatch.endPathElementIndex = hackstackElementIndex + 1; // index after end of match potentialMatches.length = 0; // we don't allow matches to overlap, so start matching again matches.push(potentialMatch); } } else { potentialMatches.splice(i, 1); i--; } } } } return matches; }, isElementValuesEqual: function(elementValue1, elementValue2) { if (typeof elementValue1 === "string" || typeof elementValue2 === "string") { return elementValue1 === elementValue2; } if (elementValue1 instanceof tree.Attribute) { if (elementValue1.op !== elementValue2.op || elementValue1.key !== elementValue2.key) { return false; } if (!elementValue1.value || !elementValue2.value) { if (elementValue1.value || elementValue2.value) { return false; } return true; } elementValue1 = elementValue1.value.value || elementValue1.value; elementValue2 = elementValue2.value.value || elementValue2.value; return elementValue1 === elementValue2; } return false; }, extendSelector:function (matches, selectorPath, replacementSelector) { //for a set of matches, replace each match with the replacement selector var currentSelectorPathIndex = 0, currentSelectorPathElementIndex = 0, path = [], matchIndex, selector, firstElement, match; for (matchIndex = 0; matchIndex < matches.length; matchIndex++) { match = matches[matchIndex]; selector = selectorPath[match.pathIndex]; firstElement = new tree.Element( match.initialCombinator, replacementSelector.elements[0].value, replacementSelector.elements[0].index ); if (match.pathIndex > currentSelectorPathIndex && currentSelectorPathElementIndex > 0) { path[path.length - 1].elements = path[path.length - 1].elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex)); currentSelectorPathElementIndex = 0; currentSelectorPathIndex++; } path = path.concat(selectorPath.slice(currentSelectorPathIndex, match.pathIndex)); path.push(new tree.Selector( selector.elements .slice(currentSelectorPathElementIndex, match.index) .concat([firstElement]) .concat(replacementSelector.elements.slice(1)) )); currentSelectorPathIndex = match.endPathIndex; currentSelectorPathElementIndex = match.endPathElementIndex; if (currentSelectorPathElementIndex >= selector.elements.length) { currentSelectorPathElementIndex = 0; currentSelectorPathIndex++; } } if (currentSelectorPathIndex < selectorPath.length && currentSelectorPathElementIndex > 0) { path[path.length - 1].elements = path[path.length - 1].elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex)); currentSelectorPathElementIndex = 0; currentSelectorPathIndex++; } path = path.concat(selectorPath.slice(currentSelectorPathIndex, selectorPath.length)); return path; }, visitRulesetOut: function (rulesetNode) { }, visitMedia: function (mediaNode, visitArgs) { var newAllExtends = mediaNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length-1]); newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, mediaNode.allExtends)); this.allExtendsStack.push(newAllExtends); }, visitMediaOut: function (mediaNode) { this.allExtendsStack.length = this.allExtendsStack.length - 1; }, visitDirective: function (directiveNode, visitArgs) { var newAllExtends = directiveNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length-1]); newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, directiveNode.allExtends)); this.allExtendsStack.push(newAllExtends); }, visitDirectiveOut: function (directiveNode) { this.allExtendsStack.length = this.allExtendsStack.length - 1; } }; })(require('./tree'));// // browser.js - client-side engine // var isFileProtocol = /^(file|chrome(-extension)?|resource|qrc|app):/.test(location.protocol); less.env = less.env || (location.hostname == '127.0.0.1' || location.hostname == '0.0.0.0' || location.hostname == 'localhost' || location.port.length > 0 || isFileProtocol ? 'development' : 'production'); // Load styles asynchronously (default: false) // // This is set to `false` by default, so that the body // doesn't start loading before the stylesheets are parsed. // Setting this to `true` can result in flickering. // less.async = less.async || false; less.fileAsync = less.fileAsync || false; // Interval between watch polls less.poll = less.poll || (isFileProtocol ? 1000 : 1500); //Setup user functions if (less.functions) { for(var func in less.functions) { less.tree.functions[func] = less.functions[func]; } } var dumpLineNumbers = /!dumpLineNumbers:(comments|mediaquery|all)/.exec(location.hash); if (dumpLineNumbers) { less.dumpLineNumbers = dumpLineNumbers[1]; } // // Watch mode // less.watch = function () { if (!less.watchMode ){ less.env = 'development'; initRunningMode(); } return this.watchMode = true }; less.unwatch = function () {clearInterval(less.watchTimer); return this.watchMode = false; }; function initRunningMode(){ if (less.env === 'development') { less.optimization = 0; less.watchTimer = setInterval(function () { if (less.watchMode) { loadStyleSheets(function (e, root, _, sheet, env) { if (e) { error(e, sheet.href); } else if (root) { createCSS(root.toCSS(less), sheet, env.lastModified); } }); } }, less.poll); } else { less.optimization = 3; } } if (/!watch/.test(location.hash)) { less.watch(); } var cache = null; if (less.env != 'development') { try { cache = (typeof(window.localStorage) === 'undefined') ? null : window.localStorage; } catch (_) {} } // // Get all tags with the 'rel' attribute set to "stylesheet/less" // var links = document.getElementsByTagName('link'); var typePattern = /^text\/(x-)?less$/; less.sheets = []; for (var i = 0; i < links.length; i++) { if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) && (links[i].type.match(typePattern)))) { less.sheets.push(links[i]); } } // // With this function, it's possible to alter variables and re-render // CSS without reloading less-files // var session_cache = ''; less.modifyVars = function(record) { var str = session_cache; for (var name in record) { str += ((name.slice(0,1) === '@')? '' : '@') + name +': '+ ((record[name].slice(-1) === ';')? record[name] : record[name] +';'); } new(less.Parser)(new less.tree.parseEnv(less)).parse(str, function (e, root) { if (e) { error(e, "session_cache"); } else { createCSS(root.toCSS(less), less.sheets[less.sheets.length - 1]); } }); }; less.refresh = function (reload) { var startTime, endTime; startTime = endTime = new(Date); loadStyleSheets(function (e, root, _, sheet, env) { if (e) { return error(e, sheet.href); } if (env.local) { log("loading " + sheet.href + " from cache."); } else { log("parsed " + sheet.href + " successfully."); createCSS(root.toCSS(less), sheet, env.lastModified); } log("css for " + sheet.href + " generated in " + (new(Date) - endTime) + 'ms'); (env.remaining === 0) && log("css generated in " + (new(Date) - startTime) + 'ms'); endTime = new(Date); }, reload); loadStyles(); }; less.refreshStyles = loadStyles; less.refresh(less.env === 'development'); function loadStyles() { var styles = document.getElementsByTagName('style'); for (var i = 0; i < styles.length; i++) { if (styles[i].type.match(typePattern)) { var env = new less.tree.parseEnv(less); env.filename = document.location.href.replace(/#.*$/, ''); new(less.Parser)(env).parse(styles[i].innerHTML || '', function (e, cssAST) { if (e) { return error(e, "inline"); } var css = cssAST.toCSS(less); var style = styles[i]; style.type = 'text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.innerHTML = css; } }); } } } function loadStyleSheets(callback, reload) { for (var i = 0; i < less.sheets.length; i++) { loadStyleSheet(less.sheets[i], callback, reload, less.sheets.length - (i + 1)); } } function pathDiff(url, baseUrl) { // diff between two paths to create a relative path var urlParts = extractUrlParts(url), baseUrlParts = extractUrlParts(baseUrl), i, max, urlDirectories, baseUrlDirectories, diff = ""; if (urlParts.hostPart !== baseUrlParts.hostPart) { return ""; } max = Math.max(baseUrlParts.directories.length, urlParts.directories.length); for(i = 0; i < max; i++) { if (baseUrlParts.directories[i] !== urlParts.directories[i]) { break; } } baseUrlDirectories = baseUrlParts.directories.slice(i); urlDirectories = urlParts.directories.slice(i); for(i = 0; i < baseUrlDirectories.length-1; i++) { diff += "../"; } for(i = 0; i < urlDirectories.length-1; i++) { diff += urlDirectories[i] + "/"; } return diff; } function extractUrlParts(url, baseUrl) { // urlParts[1] = protocol&hostname || / // urlParts[2] = / if path relative to host base // urlParts[3] = directories // urlParts[4] = filename // urlParts[5] = parameters var urlPartsRegex = /^((?:[a-z-]+:)?\/+?(?:[^\/\?#]*\/)|([\/\\]))?((?:[^\/\\\?#]*[\/\\])*)([^\/\\\?#]*)([#\?].*)?$/i, urlParts = url.match(urlPartsRegex), returner = {}, directories = [], i, baseUrlParts; if (!urlParts) { throw new Error("Could not parse sheet href - '"+url+"'"); } // Stylesheets in IE don't always return the full path if (!urlParts[1] || urlParts[2]) { baseUrlParts = baseUrl.match(urlPartsRegex); if (!baseUrlParts) { throw new Error("Could not parse page url - '"+baseUrl+"'"); } urlParts[1] = urlParts[1] || baseUrlParts[1] || ""; if (!urlParts[2]) { urlParts[3] = baseUrlParts[3] + urlParts[3]; } } if (urlParts[3]) { directories = urlParts[3].replace(/\\/g, "/").split("/"); // extract out . before .. so .. doesn't absorb a non-directory for(i = 0; i < directories.length; i++) { if (directories[i] === ".") { directories.splice(i, 1); i -= 1; } } for(i = 0; i < directories.length; i++) { if (directories[i] === ".." && i > 0) { directories.splice(i-1, 2); i -= 2; } } } returner.hostPart = urlParts[1]; returner.directories = directories; returner.path = urlParts[1] + directories.join("/"); returner.fileUrl = returner.path + (urlParts[4] || ""); returner.url = returner.fileUrl + (urlParts[5] || ""); return returner; } function loadStyleSheet(sheet, callback, reload, remaining) { // sheet may be set to the stylesheet for the initial load or a collection of properties including // some env variables for imports var hrefParts = extractUrlParts(sheet.href, window.location.href); var href = hrefParts.url; var css = cache && cache.getItem(href); var timestamp = cache && cache.getItem(href + ':timestamp'); var styles = { css: css, timestamp: timestamp }; var env; var newFileInfo = { relativeUrls: less.relativeUrls, currentDirectory: hrefParts.path, filename: href }; if (sheet instanceof less.tree.parseEnv) { env = new less.tree.parseEnv(sheet); newFileInfo.entryPath = env.currentFileInfo.entryPath; newFileInfo.rootpath = env.currentFileInfo.rootpath; newFileInfo.rootFilename = env.currentFileInfo.rootFilename; } else { env = new less.tree.parseEnv(less); env.mime = sheet.type; newFileInfo.entryPath = hrefParts.path; newFileInfo.rootpath = less.rootpath || hrefParts.path; newFileInfo.rootFilename = href; } if (env.relativeUrls) { //todo - this relies on option being set on less object rather than being passed in as an option // - need an originalRootpath if (less.rootpath) { newFileInfo.rootpath = extractUrlParts(less.rootpath + pathDiff(hrefParts.path, newFileInfo.entryPath)).path; } else { newFileInfo.rootpath = hrefParts.path; } } xhr(href, sheet.type, function (data, lastModified) { // Store data this session session_cache += data.replace(/@import .+?;/ig, ''); if (!reload && styles && lastModified && (new(Date)(lastModified).valueOf() === new(Date)(styles.timestamp).valueOf())) { // Use local copy createCSS(styles.css, sheet); callback(null, null, data, sheet, { local: true, remaining: remaining }, href); } else { // Use remote copy (re-parse) try { env.contents[href] = data; // Updating content cache env.paths = [hrefParts.path]; env.currentFileInfo = newFileInfo; new(less.Parser)(env).parse(data, function (e, root) { if (e) { return callback(e, null, null, sheet); } try { callback(e, root, data, sheet, { local: false, lastModified: lastModified, remaining: remaining }, href); //TODO - there must be a better way? A generic less-to-css function that can both call error //and removeNode where appropriate //should also add tests if (env.currentFileInfo.rootFilename === href) { removeNode(document.getElementById('less-error-message:' + extractId(href))); } } catch (e) { callback(e, null, null, sheet); } }); } catch (e) { callback(e, null, null, sheet); } } }, function (status, url) { callback({ type: 'File', message: "'" + url + "' wasn't found (" + status + ")" }, null, null, sheet); }); } function extractId(href) { return href.replace(/^[a-z-]+:\/+?[^\/]+/, '' ) // Remove protocol & domain .replace(/^\//, '' ) // Remove root / .replace(/\.[a-zA-Z]+$/, '' ) // Remove simple extension .replace(/[^\.\w-]+/g, '-') // Replace illegal characters .replace(/\./g, ':'); // Replace dots with colons(for valid id) } function createCSS(styles, sheet, lastModified) { // Strip the query-string var href = sheet.href || ''; // If there is no title set, use the filename, minus the extension var id = 'less:' + (sheet.title || extractId(href)); // If this has already been inserted into the DOM, we may need to replace it var oldCss = document.getElementById(id); var keepOldCss = false; // Create a new stylesheet node for insertion or (if necessary) replacement var css = document.createElement('style'); css.setAttribute('type', 'text/css'); if (sheet.media) { css.setAttribute('media', sheet.media); } css.id = id; if (css.styleSheet) { // IE try { css.styleSheet.cssText = styles; } catch (e) { throw new(Error)("Couldn't reassign styleSheet.cssText."); } } else { css.appendChild(document.createTextNode(styles)); // If new contents match contents of oldCss, don't replace oldCss keepOldCss = (oldCss !== null && oldCss.childNodes.length > 0 && css.childNodes.length > 0 && oldCss.firstChild.nodeValue === css.firstChild.nodeValue); } var head = document.getElementsByTagName('head')[0]; // If there is no oldCss, just append; otherwise, only append if we need // to replace oldCss with an updated stylesheet if (oldCss == null || keepOldCss === false) { var nextEl = sheet && sheet.nextSibling || null; (nextEl || document.getElementsByTagName('head')[0]).parentNode.insertBefore(css, nextEl); } if (oldCss && keepOldCss === false) { head.removeChild(oldCss); } // Don't update the local store if the file wasn't modified if (lastModified && cache) { log('saving ' + href + ' to cache.'); try { cache.setItem(href, styles); cache.setItem(href + ':timestamp', lastModified); } catch(e) { //TODO - could do with adding more robust error handling log('failed to save'); } } } function xhr(url, type, callback, errback) { var xhr = getXMLHttpRequest(); var async = isFileProtocol ? less.fileAsync : less.async; if (typeof(xhr.overrideMimeType) === 'function') { xhr.overrideMimeType('text/css'); } xhr.open('GET', url, async); xhr.setRequestHeader('Accept', type || 'text/x-less, text/css; q=0.9, */*; q=0.5'); xhr.send(null); if (isFileProtocol && !less.fileAsync) { if (xhr.status === 0 || (xhr.status >= 200 && xhr.status < 300)) { callback(xhr.responseText); } else { errback(xhr.status, url); } } else if (async) { xhr.onreadystatechange = function () { if (xhr.readyState == 4) { handleResponse(xhr, callback, errback); } }; } else { handleResponse(xhr, callback, errback); } function handleResponse(xhr, callback, errback) { if (xhr.status >= 200 && xhr.status < 300) { callback(xhr.responseText, xhr.getResponseHeader("Last-Modified")); } else if (typeof(errback) === 'function') { errback(xhr.status, url); } } } function getXMLHttpRequest() { if (window.XMLHttpRequest) { return new(XMLHttpRequest); } else { try { return new(ActiveXObject)("MSXML2.XMLHTTP.3.0"); } catch (e) { log("browser doesn't support AJAX."); return null; } } } function removeNode(node) { return node && node.parentNode.removeChild(node); } function log(str) { if (less.env == 'development' && typeof(console) !== "undefined") { console.log('less: ' + str) } } function error(e, rootHref) { var id = 'less-error-message:' + extractId(rootHref || ""); var template = '
  • {content}
  • '; var elem = document.createElement('div'), timer, content, error = []; var filename = e.filename || rootHref; var filenameNoPath = filename.match(/([^\/]+(\?.*)?)$/)[1]; elem.id = id; elem.className = "less-error-message"; content = '

    ' + (e.type || "Syntax") + "Error: " + (e.message || 'There is an error in your .less file') + '

    ' + '

    in ' + filenameNoPath + " "; var errorline = function (e, i, classname) { if (e.extract[i] != undefined) { error.push(template.replace(/\{line\}/, (parseInt(e.line) || 0) + (i - 1)) .replace(/\{class\}/, classname) .replace(/\{content\}/, e.extract[i])); } }; if (e.extract) { errorline(e, 0, ''); errorline(e, 1, 'line'); errorline(e, 2, ''); content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':

    ' + '
      ' + error.join('') + '
    '; } else if (e.stack) { content += '
    ' + e.stack.split('\n').slice(1).join('
    '); } elem.innerHTML = content; // CSS for error messages createCSS([ '.less-error-message ul, .less-error-message li {', 'list-style-type: none;', 'margin-right: 15px;', 'padding: 4px 0;', 'margin: 0;', '}', '.less-error-message label {', 'font-size: 12px;', 'margin-right: 15px;', 'padding: 4px 0;', 'color: #cc7777;', '}', '.less-error-message pre {', 'color: #dd6666;', 'padding: 4px 0;', 'margin: 0;', 'display: inline-block;', '}', '.less-error-message pre.line {', 'color: #ff0000;', '}', '.less-error-message h3 {', 'font-size: 20px;', 'font-weight: bold;', 'padding: 15px 0 5px 0;', 'margin: 0;', '}', '.less-error-message a {', 'color: #10a', '}', '.less-error-message .error {', 'color: red;', 'font-weight: bold;', 'padding-bottom: 2px;', 'border-bottom: 1px dashed red;', '}' ].join('\n'), { title: 'error-message' }); elem.style.cssText = [ "font-family: Arial, sans-serif", "border: 1px solid #e00", "background-color: #eee", "border-radius: 5px", "-webkit-border-radius: 5px", "-moz-border-radius: 5px", "color: #e00", "padding: 15px", "margin-bottom: 15px" ].join(';'); if (less.env == 'development') { timer = setInterval(function () { if (document.body) { if (document.getElementById(id)) { document.body.replaceChild(elem, document.getElementById(id)); } else { document.body.insertBefore(elem, document.body.firstChild); } clearInterval(timer); } }, 10); } } // amd.js // // Define Less as an AMD module. if (typeof define === "function" && define.amd) { define(function () { return less; } ); } })(window); less.js-1.4.2/dist/less-1.4.2.min.js000066400000000000000000002322071217256642200166050ustar00rootroot00000000000000/* * LESS - Leaner CSS v1.4.2 * http://lesscss.org * * Copyright (c) 2009-2013, Alexis Sellier * Licensed under the Apache 2.0 License. * * @licence */(function(e,t){function n(t){return e.less[t.split("/")[1]]}function f(){r.env==="development"?(r.optimization=0,r.watchTimer=setInterval(function(){r.watchMode&&g(function(e,t,n,i,s){e?k(e,i.href):t&&S(t.toCSS(r),i,s.lastModified)})},r.poll)):r.optimization=3}function m(){var e=document.getElementsByTagName("style");for(var t=0;t0&&(s.splice(o-1,2),o-=2)}return i.hostPart=r[1],i.directories=s,i.path=r[1]+s.join("/"),i.fileUrl=i.path+(r[4]||""),i.url=i.fileUrl+(r[5]||""),i}function w(t,n,i,s){var o=b(t.href,e.location.href),u=o.url,a=l&&l.getItem(u),f=l&&l.getItem(u+":timestamp"),c={css:a,timestamp:f},h,p={relativeUrls:r.relativeUrls,currentDirectory:o.path,filename:u};t instanceof r.tree.parseEnv?(h=new r.tree.parseEnv(t),p.entryPath=h.currentFileInfo.entryPath,p.rootpath=h.currentFileInfo.rootpath,p.rootFilename=h.currentFileInfo.rootFilename):(h=new r.tree.parseEnv(r),h.mime=t.type,p.entryPath=o.path,p.rootpath=r.rootpath||o.path,p.rootFilename=u),h.relativeUrls&&(r.rootpath?p.rootpath=b(r.rootpath+y(o.path,p.entryPath)).path:p.rootpath=o.path),x(u,t.type,function(e,a){v+=e.replace(/@import .+?;/ig,"");if(!i&&c&&a&&(new Date(a)).valueOf()===(new Date(c.timestamp)).valueOf())S(c.css,t),n(null,null,e,t,{local:!0,remaining:s},u);else try{h.contents[u]=e,h.paths=[o.path],h.currentFileInfo=p,(new r.Parser(h)).parse(e,function(r,i){if(r)return n(r,null,null,t);try{n(r,i,e,t,{local:!1,lastModified:a,remaining:s},u),h.currentFileInfo.rootFilename===u&&N(document.getElementById("less-error-message:"+E(u)))}catch(r){n(r,null,null,t)}})}catch(f){n(f,null,null,t)}},function(e,r){n({type:"File",message:"'"+r+"' wasn't found ("+e+")"},null,null,t)})}function E(e){return e.replace(/^[a-z-]+:\/+?[^\/]+/,"").replace(/^\//,"").replace(/\.[a-zA-Z]+$/,"").replace(/[^\.\w-]+/g,"-").replace(/\./g,":")}function S(e,t,n){var r=t.href||"",i="less:"+(t.title||E(r)),s=document.getElementById(i),o=!1,u=document.createElement("style");u.setAttribute("type","text/css"),t.media&&u.setAttribute("media",t.media),u.id=i;if(u.styleSheet)try{u.styleSheet.cssText=e}catch(a){throw new Error("Couldn't reassign styleSheet.cssText.")}else u.appendChild(document.createTextNode(e)),o=s!==null&&s.childNodes.length>0&&u.childNodes.length>0&&s.firstChild.nodeValue===u.firstChild.nodeValue;var f=document.getElementsByTagName("head")[0];if(s==null||o===!1){var c=t&&t.nextSibling||null;(c||document.getElementsByTagName("head")[0]).parentNode.insertBefore(u,c)}s&&o===!1&&f.removeChild(s);if(n&&l){C("saving "+r+" to cache.");try{l.setItem(r,e),l.setItem(r+":timestamp",n)}catch(a){C("failed to save")}}}function x(e,t,n,i){function a(t,n,r){t.status>=200&&t.status<300?n(t.responseText,t.getResponseHeader("Last-Modified")):typeof r=="function"&&r(t.status,e)}var s=T(),u=o?r.fileAsync:r.async;typeof s.overrideMimeType=="function"&&s.overrideMimeType("text/css"),s.open("GET",e,u),s.setRequestHeader("Accept",t||"text/x-less, text/css; q=0.9, */*; q=0.5"),s.send(null),o&&!r.fileAsync?s.status===0||s.status>=200&&s.status<300?n(s.responseText):i(s.status,e):u?s.onreadystatechange=function(){s.readyState==4&&a(s,n,i)}:a(s,n,i)}function T(){if(e.XMLHttpRequest)return new XMLHttpRequest;try{return new ActiveXObject("MSXML2.XMLHTTP.3.0")}catch(t){return C("browser doesn't support AJAX."),null}}function N(e){return e&&e.parentNode.removeChild(e)}function C(e){r.env=="development"&&typeof console!="undefined"&&console.log("less: "+e)}function k(e,n){var i="less-error-message:"+E(n||""),s='
  • {content}
  • ',o=document.createElement("div"),u,a,f=[],l=e.filename||n,c=l.match(/([^\/]+(\?.*)?)$/)[1];o.id=i,o.className="less-error-message",a="

    "+(e.type||"Syntax")+"Error: "+(e.message||"There is an error in your .less file")+"

    "+'

    in '+c+" ";var h=function(e,n,r){e.extract[n]!=t&&f.push(s.replace(/\{line\}/,(parseInt(e.line)||0)+(n-1)).replace(/\{class\}/,r).replace(/\{content\}/,e.extract[n]))};e.extract?(h(e,0,""),h(e,1,"line"),h(e,2,""),a+="on line "+e.line+", column "+(e.column+1)+":

    "+"
      "+f.join("")+"
    "):e.stack&&(a+="
    "+e.stack.split("\n").slice(1).join("
    ")),o.innerHTML=a,S([".less-error-message ul, .less-error-message li {","list-style-type: none;","margin-right: 15px;","padding: 4px 0;","margin: 0;","}",".less-error-message label {","font-size: 12px;","margin-right: 15px;","padding: 4px 0;","color: #cc7777;","}",".less-error-message pre {","color: #dd6666;","padding: 4px 0;","margin: 0;","display: inline-block;","}",".less-error-message pre.line {","color: #ff0000;","}",".less-error-message h3 {","font-size: 20px;","font-weight: bold;","padding: 15px 0 5px 0;","margin: 0;","}",".less-error-message a {","color: #10a","}",".less-error-message .error {","color: red;","font-weight: bold;","padding-bottom: 2px;","border-bottom: 1px dashed red;","}"].join("\n"),{title:"error-message"}),o.style.cssText=["font-family: Arial, sans-serif","border: 1px solid #e00","background-color: #eee","border-radius: 5px","-webkit-border-radius: 5px","-moz-border-radius: 5px","color: #e00","padding: 15px","margin-bottom: 15px"].join(";"),r.env=="development"&&(u=setInterval(function(){document.body&&(document.getElementById(i)?document.body.replaceChild(o,document.getElementById(i)):document.body.insertBefore(o,document.body.firstChild),clearInterval(u))},10))}var r,i,s;typeof environment=="object"&&{}.toString.call(environment)==="[object Environment]"?(typeof e=="undefined"?r={}:r=e.less={},i=r.tree={},r.mode="rhino"):typeof e=="undefined"?(r=exports,i=n("./tree"),r.mode="node"):(typeof e.less=="undefined"&&(e.less={}),r=e.less,i=e.less.tree={},r.mode="browser"),r.Parser=function(t){function m(){a=c[u],f=o,h=o}function g(){c[u]=a,o=f,h=o}function y(){o>h&&(c[u]=c[u].slice(o-h),h=o)}function b(e){var t=e.charCodeAt(0);return t===32||t===10||t===9}function w(e){var t,n,r,i,a;if(e instanceof Function)return e.call(p.parsers);if(typeof e=="string")t=s.charAt(o)===e?e:null,r=1,y();else{y();if(!(t=e.exec(c[u])))return null;r=t[0].length}if(t)return E(r),typeof t=="string"?t:t.length===1?t[0]:t}function E(e){var t=o,n=u,r=o+c[u].length,i=o+=e;while(o=0&&t.charAt(n)!=="\n";n--)r++;return{line:typeof e=="number"?(t.slice(0,e).match(/\n/g)||"").length:null,column:r}}function k(e,t,i){var s=i.currentFileInfo.filename;return r.mode!=="browser"&&r.mode!=="rhino"&&(s=n("path").resolve(s)),{lineNumber:C(e,t).line+1,fileName:s}}function L(e,t){var n=N(e,t),r=C(e.index,n),i=r.line,s=r.column,o=n.split("\n");this.type=e.type||"Syntax",this.message=e.message,this.filename=e.filename||t.currentFileInfo.filename,this.index=e.index,this.line=typeof i=="number"?i+1:null,this.callLine=e.call&&C(e.call,n).line+1,this.callExtract=o[C(e.call,n).line],this.stack=e.stack,this.column=s,this.extract=[o[i-1],o[i],o[i+1]]}var s,o,u,a,f,l,c,h,p,d=this;t instanceof i.parseEnv||(t=new i.parseEnv(t));var v=this.imports={paths:t.paths||[],queue:[],files:t.files,contents:t.contents,mime:t.mime,error:null,push:function(e,n,i){var s=this;this.queue.push(e),r.Parser.importer(e,n,function(t,n,r){s.queue.splice(s.queue.indexOf(e),1);var o=r in s.files;s.files[r]=n,t&&!s.error&&(s.error=t),i(t,n,o)},t)}};return L.prototype=new Error,L.prototype.constructor=L,this.env=t=t||{},this.optimization="optimization"in this.env?this.env.optimization:1,p={imports:v,parse:function(e,a){var f,d,v,m,g,y,b=[],E,S=null;o=u=h=l=0,s=e.replace(/\r\n/g,"\n"),s=s.replace(/^\uFEFF/,""),c=function(e){var n=0,r=/(?:@\{[\w-]+\}|[^"'`\{\}\/\(\)\\])+/g,i=/\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g,o=/"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'|`((?:[^`]|\\.)*)`/g,u=0,a,f=e[0],l;for(var c=0,h,p;c0?"missing closing `}`":"missing opening `{`",filename:t.currentFileInfo.filename},t)),e.map(function(e){return e.join("")})}([[]]);if(S)return a(new L(S,t));try{f=new i.Ruleset([],w(this.parsers.primary)),f.root=!0,f.firstRoot=!0}catch(x){return a(new L(x,t))}f.toCSS=function(e){var s,o,u;return function(s,o){s=s||{};var u,a=new i.evalEnv(s);typeof o=="object"&&!Array.isArray(o)&&(o=Object.keys(o).map(function(e){var t=o[e];return t instanceof i.Value||(t instanceof i.Expression||(t=new i.Expression([t])),t=new i.Value([t])),new i.Rule("@"+e,t,!1,0)}),a.frames=[new i.Ruleset(null,o)]);try{var f=e.call(this,a);(new i.joinSelectorVisitor).run(f),(new i.processExtendsVisitor).run(f);var l=f.toCSS({compress:Boolean(s.compress),dumpLineNumbers:t.dumpLineNumbers,strictUnits:Boolean(s.strictUnits)})}catch(c){throw new L(c,t)}return s.yuicompress&&r.mode==="node"?n("ycssmin").cssmin(l,s.maxLineLen):s.compress?l.replace(/(\s)+/g,"$1"):l}}(f.eval);if(o=0&&s.charAt(T)!=="\n";T--)N++;S={type:"Parse",message:"Unrecognised input",index:o,filename:t.currentFileInfo.filename,line:g,column:N,extract:[y[g-2],y[g-1],y[g]]}}var C=function(e){e=S||e||p.imports.error,e?(e instanceof L||(e=new L(e,t)),a(e)):a(null,f)};t.processImports!==!1?(new i.importVisitor(this.imports,C)).run(f):C()},parsers:{primary:function(){var e,t=[];while((e=w(this.extendRule)||w(this.mixin.definition)||w(this.rule)||w(this.ruleset)||w(this.mixin.call)||w(this.comment)||w(this.directive))||w(/^[\s\n]+/)||w(/^;+/))e&&t.push(e);return t},comment:function(){var e;if(s.charAt(o)!=="/")return;if(s.charAt(o+1)==="/")return new i.Comment(w(/^\/\/.*/),!0);if(e=w(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/))return new i.Comment(e)},entities:{quoted:function(){var e,n=o,r,u=o;s.charAt(n)==="~"&&(n++,r=!0);if(s.charAt(n)!=='"'&&s.charAt(n)!=="'")return;r&&w("~");if(e=w(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/))return new i.Quoted(e[0],e[1]||e[2],r,u,t.currentFileInfo)},keyword:function(){var e;if(e=w(/^[_A-Za-z-][_A-Za-z0-9-]*/))return i.colors.hasOwnProperty(e)?new i.Color(i.colors[e].slice(1)):new i.Keyword(e)},call:function(){var e,n,r,s,a=o;if(!(e=/^([\w-]+|%|progid:[\w\.]+)\(/.exec(c[u])))return;e=e[1],n=e.toLowerCase();if(n==="url")return null;o+=e.length;if(n==="alpha"){s=w(this.alpha);if(typeof s!="undefined")return s}w("("),r=w(this.entities.arguments);if(!w(")"))return;if(e)return new i.Call(e,r,a,t.currentFileInfo)},arguments:function(){var e=[],t;while(t=w(this.entities.assignment)||w(this.expression)){e.push(t);if(!w(","))break}return e},literal:function(){return w(this.entities.dimension)||w(this.entities.color)||w(this.entities.quoted)||w(this.entities.unicodeDescriptor)},assignment:function(){var e,t;if((e=w(/^\w+(?=\s?=)/i))&&w("=")&&(t=w(this.entity)))return new i.Assignment(e,t)},url:function(){var e;if(s.charAt(o)!=="u"||!w(/^url\(/))return;return e=w(this.entities.quoted)||w(this.entities.variable)||w(/^(?:(?:\\[\(\)'"])|[^\(\)'"])+/)||"",S(")"),new i.URL(e.value!=null||e instanceof i.Variable?e:new i.Anonymous(e),t.currentFileInfo)},variable:function(){var e,n=o;if(s.charAt(o)==="@"&&(e=w(/^@@?[\w-]+/)))return new i.Variable(e,n,t.currentFileInfo)},variableCurly:function(){var e,n,r=o;if(s.charAt(o)==="@"&&(n=w(/^@\{([\w-]+)\}/)))return new i.Variable("@"+n[1],r,t.currentFileInfo)},color:function(){var e;if(s.charAt(o)==="#"&&(e=w(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/)))return new i.Color(e[1])},dimension:function(){var e,t=s.charCodeAt(o);if(t>57||t<43||t===47||t==44)return;if(e=w(/^([+-]?\d*\.?\d+)(%|[a-z]+)?/))return new i.Dimension(e[1],e[2])},unicodeDescriptor:function(){var e;if(e=w(/^U\+[0-9a-fA-F?]+(\-[0-9a-fA-F?]+)?/))return new i.UnicodeDescriptor(e[0])},javascript:function(){var e,t=o,n;s.charAt(t)==="~"&&(t++,n=!0);if(s.charAt(t)!=="`")return;n&&w("~");if(e=w(/^`([^`]*)`/))return new i.JavaScript(e[1],o,n)}},variable:function(){var e;if(s.charAt(o)==="@"&&(e=w(/^(@[\w-]+)\s*:/)))return e[1]},extend:function(e){var t,n,r=o,s,u=[];if(!w(e?/^&:extend\(/:/^:extend\(/))return;do{s=null,t=[];for(;;){s=w(/^(all)(?=\s*(\)|,))/);if(s)break;n=w(this.element);if(!n)break;t.push(n)}s=s&&s[1],u.push(new i.Extend(new i.Selector(t),s,r))}while(w(","));return S(/^\)/),e&&S(/^;/),u},extendRule:function(){return this.extend(!0)},mixin:{call:function(){var e=[],n,r,u,a,f,l=o,c=s.charAt(o),h=!1;if(c!=="."&&c!=="#")return;m();while(n=w(/^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/))e.push(new i.Element(r,n,o)),r=w(">");w("(")&&(u=this.mixin.args.call(this,!0).args,S(")")),u=u||[],w(this.important)&&(h=!0);if(e.length>0&&(w(";")||T("}")))return new i.mixin.Call(e,u,l,t.currentFileInfo,h);g()},args:function(e){var t=[],n=[],r,u=[],a,f,l,c,h,p={args:null,variadic:!1};for(;;){if(e)h=w(this.expression);else{w(this.comment);if(s.charAt(o)==="."&&w(/^\.{3}/)){p.variadic=!0,w(";")&&!r&&(r=!0),(r?n:u).push({variadic:!0});break}h=w(this.entities.variable)||w(this.entities.literal)||w(this.entities.keyword)}if(!h)break;l=null,h.throwAwayComments&&h.throwAwayComments(),c=h;var d=null;if(e){if(h.value.length==1)var d=h.value[0]}else d=h;if(d&&d instanceof i.Variable)if(w(":"))t.length>0&&(r&&x("Cannot mix ; and , as delimiter types"),a=!0),c=S(this.expression),l=f=d.name;else{if(!e&&w(/^\.{3}/)){p.variadic=!0,w(";")&&!r&&(r=!0),(r?n:u).push({name:h.name,variadic:!0});break}e||(f=l=d.name,c=null)}c&&t.push(c),u.push({name:l,value:c});if(w(","))continue;if(w(";")||r)a&&x("Cannot mix ; and , as delimiter types"),r=!0,t.length>1&&(c=new i.Value(t)),n.push({name:f,value:c}),f=null,t=[],a=!1}return p.args=r?n:u,p},definition:function(){var e,t=[],n,r,u,a,f,c=!1;if(s.charAt(o)!=="."&&s.charAt(o)!=="#"||T(/^[^{]*\}/))return;m();if(n=w(/^([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/)){e=n[1];var h=this.mixin.args.call(this,!1);t=h.args,c=h.variadic,w(")")||(l=o,g()),w(this.comment),w(/^when/)&&(f=S(this.conditions,"expected condition")),r=w(this.block);if(r)return new i.mixin.Definition(e,t,r,f,c);g()}}},entity:function(){return w(this.entities.literal)||w(this.entities.variable)||w(this.entities.url)||w(this.entities.call)||w(this.entities.keyword)||w(this.entities.javascript)||w(this.comment)},end:function(){return w(";")||T("}")},alpha:function(){var e;if(!w(/^\(opacity=/i))return;if(e=w(/^\d+/)||w(this.entities.variable))return S(")"),new i.Alpha(e)},element:function(){var e,t,n,r;n=w(this.combinator),e=w(/^(?:\d+\.\d+|\d+)%/)||w(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/)||w("*")||w("&")||w(this.attribute)||w(/^\([^()@]+\)/)||w(/^[\.#](?=@)/)||w(this.entities.variableCurly),e||w("(")&&(r=w(this.selector))&&w(")")&&(e=new i.Paren(r));if(e)return new i.Element(n,e,o)},combinator:function(){var e=s.charAt(o);if(e===">"||e==="+"||e==="~"||e==="|"){o++;while(s.charAt(o).match(/\s/))o++;return new i.Combinator(e)}return s.charAt(o-1).match(/\s/)?new i.Combinator(" "):new i.Combinator(null)},selector:function(){var e,t,n=[],r,u,a=[];while((u=w(this.extend))||(t=w(this.element))){u?a.push.apply(a,u):(a.length&&x("Extend can only be used at the end of selector"),r=s.charAt(o),n.push(t),t=null);if(r==="{"||r==="}"||r===";"||r===","||r===")")break}if(n.length>0)return new i.Selector(n,a);a.length&&x("Extend must be used to extend a selector, it cannot be used on its own")},attribute:function(){var e="",t,n,r;if(!w("["))return;(t=w(this.entities.variableCurly))||(t=S(/^(?:[_A-Za-z0-9-\*]*\|)?(?:[_A-Za-z0-9-]|\\.)+/));if(r=w(/^[|~*$^]?=/))n=w(this.entities.quoted)||w(/^[\w-]+/)||w(this.entities.variableCurly);return S("]"),new i.Attribute(t,r,n)},block:function(){var e;if(w("{")&&(e=w(this.primary))&&w("}"))return e},ruleset:function(){var e=[],n,r,u;m(),t.dumpLineNumbers&&(u=k(o,s,t));while(n=w(this.selector)){e.push(n),w(this.comment);if(!w(","))break;w(this.comment)}if(e.length>0&&(r=w(this.block))){var a=new i.Ruleset(e,r,t.strictImports);return t.dumpLineNumbers&&(a.debugInfo=u),a}l=o,g()},rule:function(e){var n,r,u=s.charAt(o),a;m();if(u==="."||u==="#"||u==="&")return;if(n=w(this.variable)||w(this.property)){r=!e&&(t.compress||n.charAt(0)==="@")?w(this.value)||w(this.anonymousValue):w(this.anonymousValue)||w(this.value),a=w(this.important);if(r&&w(this.end))return new i.Rule(n,r,a,f,t.currentFileInfo);l=o,g();if(r&&!e)return this.rule(!0)}},anonymousValue:function(){var e;if(e=/^([^@+\/'"*`(;{}-]*);/.exec(c[u]))return o+=e[0].length-1,new i.Anonymous(e[1])},"import":function(){var e,n,r=o;m();var s=w(/^@import?\s+/),u=(s?w(this.importOptions):null)||{};if(s&&(e=w(this.entities.quoted)||w(this.entities.url))){n=w(this.mediaFeatures);if(w(";"))return n=n&&new i.Value(n),new i.Import(e,n,u,r,t.currentFileInfo)}g()},importOptions:function(){var e,t={},n,r;if(!w("("))return null;do if(e=w(this.importOption)){n=e,r=!0;switch(n){case"css":n="less",r=!1;break;case"once":n="multiple",r=!1}t[n]=r;if(!w(","))break}while(e);return S(")"),t},importOption:function(){var e=w(/^(less|css|multiple|once)/);if(e)return e[1]},mediaFeature:function(){var e,n,r=[];do if(e=w(this.entities.keyword))r.push(e);else if(w("(")){n=w(this.property),e=w(this.value);if(!w(")"))return null;if(n&&e)r.push(new i.Paren(new i.Rule(n,e,null,o,t.currentFileInfo,!0)));else{if(!e)return null;r.push(new i.Paren(e))}}while(e);if(r.length>0)return new i.Expression(r)},mediaFeatures:function(){var e,t=[];do if(e=w(this.mediaFeature)){t.push(e);if(!w(","))break}else if(e=w(this.entities.variable)){t.push(e);if(!w(","))break}while(e);return t.length>0?t:null},media:function(){var e,n,r,u;t.dumpLineNumbers&&(u=k(o,s,t));if(w(/^@media/)){e=w(this.mediaFeatures);if(n=w(this.block))return r=new i.Media(n,e),t.dumpLineNumbers&&(r.debugInfo=u),r}},directive:function(){var e,n,r,u,a,f,l,c,h,p;if(s.charAt(o)!=="@")return;if(n=w(this["import"])||w(this.media))return n;m(),e=w(/^@[a-z-]+/);if(!e)return;l=e,e.charAt(1)=="-"&&e.indexOf("-",2)>0&&(l="@"+e.slice(e.indexOf("-",2)+1));switch(l){case"@font-face":c=!0;break;case"@viewport":case"@top-left":case"@top-left-corner":case"@top-center":case"@top-right":case"@top-right-corner":case"@bottom-left":case"@bottom-left-corner":case"@bottom-center":case"@bottom-right":case"@bottom-right-corner":case"@left-top":case"@left-middle":case"@left-bottom":case"@right-top":case"@right-middle":case"@right-bottom":c=!0;break;case"@page":case"@document":case"@supports":case"@keyframes":c=!0,h=!0;break;case"@namespace":p=!0}h&&(e+=" "+(w(/^[^{]+/)||"").trim());if(c){if(r=w(this.block))return new i.Directive(e,r)}else if((n=p?w(this.expression):w(this.entity))&&w(";")){var d=new i.Directive(e,n);return t.dumpLineNumbers&&(d.debugInfo=k(o,s,t)),d}g()},value:function(){var e,t=[],n;while(e=w(this.expression)){t.push(e);if(!w(","))break}if(t.length>0)return new i.Value(t)},important:function(){if(s.charAt(o)==="!")return w(/^! *important/)},sub:function(){var e,t;if(w("("))if(e=w(this.addition))return t=new i.Expression([e]),S(")"),t.parens=!0,t},multiplication:function(){var e,t,n,r,u,a=[];if(e=w(this.operand)){u=b(s.charAt(o-1));while(!T(/^\/[*\/]/)&&(n=w("/")||w("*"))){if(!(t=w(this.operand)))break;e.parensInOp=!0,t.parensInOp=!0,r=new i.Operation(n,[r||e,t],u),u=b(s.charAt(o-1))}return r||e}},addition:function(){var e,t,n,r,u;if(e=w(this.multiplication)){u=b(s.charAt(o-1));while((n=w(/^[-+]\s+/)||!u&&(w("+")||w("-")))&&(t=w(this.multiplication)))e.parensInOp=!0,t.parensInOp=!0,r=new i.Operation(n,[r||e,t],u),u=b(s.charAt(o-1));return r||e}},conditions:function(){var e,t,n=o,r;if(e=w(this.condition)){while(w(",")&&(t=w(this.condition)))r=new i.Condition("or",r||e,t,n);return r||e}},condition:function(){var e,t,n,r,s=o,u=!1;w(/^not/)&&(u=!0),S("(");if(e=w(this.addition)||w(this.entities.keyword)||w(this.entities.quoted))return(r=w(/^(?:>=|=<|[<=>])/))?(t=w(this.addition)||w(this.entities.keyword)||w(this.entities.quoted))?n=new i.Condition(r,e,t,s,u):x("expected expression"):n=new i.Condition("=",e,new i.Keyword("true"),s,u),S(")"),w(/^and/)?new i.Condition("and",n,w(this.condition)):n},operand:function(){var e,t=s.charAt(o+1);s.charAt(o)==="-"&&(t==="@"||t==="(")&&(e=w("-"));var n=w(this.sub)||w(this.entities.dimension)||w(this.entities.color)||w(this.entities.variable)||w(this.entities.call);return e&&(n.parensInOp=!0,n=new i.Negative(n)),n},expression:function(){var e,t,n=[],r;while(e=w(this.addition)||w(this.entity))n.push(e),!T(/^\/[\/*]/)&&(t=w("/"))&&n.push(new i.Anonymous(t));if(n.length>0)return new i.Expression(n)},property:function(){var e;if(e=w(/^(\*?-?[_a-zA-Z0-9-]+)\s*:/))return e[1]}}}};if(r.mode==="browser"||r.mode==="rhino")r.Parser.importer=function(e,t,n,r){!/^([a-z-]+:)?\//.test(e)&&t.currentDirectory&&(e=t.currentDirectory+e);var i=r.toSheet(e);i.processImports=!1,i.currentFileInfo=t,w(i,function(e,t,r,i,s,o){n.call(null,e,t,o)},!0)};(function(r){function u(e){return r.functions.hsla(e.h,e.s,e.l,e.a)}function a(e,t){return e instanceof r.Dimension&&e.unit.is("%")?parseFloat(e.value*t/100):f(e)}function f(e){if(e instanceof r.Dimension)return parseFloat(e.unit.is("%")?e.value/100:e.value);if(typeof e=="number")return e;throw{error:"RuntimeError",message:"color functions take numbers as parameters"}}function l(e){return Math.min(1,Math.max(0,e))}r.functions={rgb:function(e,t,n){return this.rgba(e,t,n,1)},rgba:function(e,t,n,i){var s=[e,t,n].map(function(e){return a(e,256)});return i=f(i),new r.Color(s,i)},hsl:function(e,t,n){return this.hsla(e,t,n,1)},hsla:function(e,t,n,r){function o(e){return e=e<0?e+1:e>1?e-1:e,e*6<1?s+(i-s)*e*6:e*2<1?i:e*3<2?s+(i-s)*(2/3-e)*6:s}e=f(e)%360/360,t=l(f(t)),n=l(f(n)),r=l(f(r));var i=n<=.5?n*(t+1):n+t-n*t,s=n*2-i;return this.rgba(o(e+1/3)*255,o(e)*255,o(e-1/3)*255,r)},hsv:function(e,t,n){return this.hsva(e,t,n,1)},hsva:function(e,t,n,r){e=f(e)%360/360*360,t=f(t),n=f(n),r=f(r);var i,s;i=Math.floor(e/60%6),s=e/60-i;var o=[n,n*(1-t),n*(1-s*t),n*(1-(1-s)*t)],u=[[0,3,1],[2,0,1],[1,0,3],[1,2,0],[3,1,0],[0,1,2]];return this.rgba(o[u[i][0]]*255,o[u[i][1]]*255,o[u[i][2]]*255,r)},hue:function(e){return new r.Dimension(Math.round(e.toHSL().h))},saturation:function(e){return new r.Dimension(Math.round(e.toHSL().s*100),"%")},lightness:function(e){return new r.Dimension(Math.round(e.toHSL().l*100),"%")},hsvhue:function(e){return new r.Dimension(Math.round(e.toHSV().h))},hsvsaturation:function(e){return new r.Dimension(Math.round(e.toHSV().s*100),"%")},hsvvalue:function(e){return new r.Dimension(Math.round(e.toHSV().v*100),"%")},red:function(e){return new r.Dimension(e.rgb[0])},green:function(e){return new r.Dimension(e.rgb[1])},blue:function(e){return new r.Dimension(e.rgb[2])},alpha:function(e){return new r.Dimension(e.toHSL().a)},luma:function(e){return new r.Dimension(Math.round(e.luma()*e.alpha*100),"%")},saturate:function(e,t){var n=e.toHSL();return n.s+=t.value/100,n.s=l(n.s),u(n)},desaturate:function(e,t){var n=e.toHSL();return n.s-=t.value/100,n.s=l(n.s),u(n)},lighten:function(e,t){var n=e.toHSL();return n.l+=t.value/100,n.l=l(n.l),u(n)},darken:function(e,t){var n=e.toHSL();return n.l-=t.value/100,n.l=l(n.l),u(n)},fadein:function(e,t){var n=e.toHSL();return n.a+=t.value/100,n.a=l(n.a),u(n)},fadeout:function(e,t){var n=e.toHSL();return n.a-=t.value/100,n.a=l(n.a),u(n)},fade:function(e,t){var n=e.toHSL();return n.a=t.value/100,n.a=l(n.a),u(n)},spin:function(e,t){var n=e.toHSL(),r=(n.h+t.value)%360;return n.h=r<0?360+r:r,u(n)},mix:function(e,t,n){n||(n=new r.Dimension(50));var i=n.value/100,s=i*2-1,o=e.toHSL().a-t.toHSL().a,u=((s*o==-1?s:(s+o)/(1+s*o))+1)/2,a=1-u,f=[e.rgb[0]*u+t.rgb[0]*a,e.rgb[1]*u+t.rgb[1]*a,e.rgb[2]*u+t.rgb[2]*a],l=e.alpha*i+t.alpha*(1-i);return new r.Color(f,l)},greyscale:function(e){return this.desaturate(e,new r.Dimension(100))},contrast:function(e,t,n,r){if(!e.rgb)return null;typeof n=="undefined"&&(n=this.rgba(255,255,255,1)),typeof t=="undefined"&&(t=this.rgba(0,0,0,1));if(t.luma()>n.luma()){var i=n;n=t,t=i}return typeof r=="undefined"?r=.43:r=f(r),e.luma()*e.alpha=d){if(this.env.ieCompat!==!1)return this.env.silent||console.warn("Skipped data-uri embedding of %s because its size (%dKB) exceeds IE8-safe %dKB!",o,v,d),(new r.URL(i||t,this.currentFileInfo)).eval(this.env);this.env.silent||console.warn("WARNING: Embedding %s (%dKB) exceeds IE8's data-uri size limit of %dKB!",o,v,d)}p=f?p.toString("base64"):encodeURIComponent(p);var m="'data:"+s+","+p+"'";return new r.URL(new r.Anonymous(m))}},r._mime={_types:{".htm":"text/html",".html":"text/html",".gif":"image/gif",".jpg":"image/jpeg",".jpeg":"image/jpeg",".png":"image/png"},lookup:function(e){var i=n("path").extname(e),s=r._mime._types[i];if(s===t)throw new Error('Optional dependency "mime" is required for '+i);return s},charsets:{lookup:function(e){return e&&/^text\//.test(e)?"UTF-8":""}}};var i=[{name:"ceil"},{name:"floor"},{name:"sqrt"},{name:"abs"},{name:"tan",unit:""},{name:"sin",unit:""},{name:"cos",unit:""},{name:"atan",unit:"rad"},{name:"asin",unit:"rad"},{name:"acos",unit:"rad"}],s=function(e,t){return function(n){return t!=null&&(n=n.unify()),this._math(Math[e],t,n)}};for(var o=0;o255?255:e<0?0:e).toString(16),e.length===1?"0"+e:e}).join("");return n&&(r=r.split(""),r[0]==r[1]&&r[2]==r[3]&&r[4]==r[5]?r=r[0]+r[2]+r[4]:r=r.join("")),"#"+r},operate:function(t,n,r){var i=[];r instanceof e.Color||(r=r.toColor());for(var s=0;s<3;s++)i[s]=e.operate(t,n,this.rgb[s],r.rgb[s]);return new e.Color(i,this.alpha+r.alpha)},toHSL:function(){var e=this.rgb[0]/255,t=this.rgb[1]/255,n=this.rgb[2]/255,r=this.alpha,i=Math.max(e,t,n),s=Math.min(e,t,n),o,u,a=(i+s)/2,f=i-s;if(i===s)o=u=0;else{u=a>.5?f/(2-i-s):f/(i+s);switch(i){case e:o=(t-n)/f+(t255?255:e<0?0:e).toString(16),e.length===1?"0"+e:e}).join("")},compare:function(e){return e.rgb?e.rgb[0]===this.rgb[0]&&e.rgb[1]===this.rgb[1]&&e.rgb[2]===this.rgb[2]&&e.alpha===this.alpha?0:-1:-1}}}(n("../tree")),function(e){e.Comment=function(e,t){this.value=e,this.silent=!!t},e.Comment.prototype={type:"Comment",toCSS:function(e){return e.compress?"":this.value},eval:function(){return this}}}(n("../tree")),function(e){e.Condition=function(e,t,n,r,i){this.op=e.trim(),this.lvalue=t,this.rvalue=n,this.index=r,this.negate=i},e.Condition.prototype={type:"Condition",accept:function(e){this.lvalue=e.visit(this.lvalue),this.rvalue=e.visit(this.rvalue)},eval:function(e){var t=this.lvalue.eval(e),n=this.rvalue.eval(e),r=this.index,i,i=function(e){switch(e){case"and":return t&&n;case"or":return t||n;default:if(t.compare)i=t.compare(n);else{if(!n.compare)throw{type:"Type",message:"Unable to perform comparison",index:r};i=n.compare(t)}switch(i){case-1:return e==="<"||e==="=<";case 0:return e==="="||e===">="||e==="=<";case 1:return e===">"||e===">="}}}(this.op);return this.negate?!i:i}}}(n("../tree")),function(e){e.Dimension=function(n,r){this.value=parseFloat(n),this.unit=r&&r instanceof e.Unit?r:new e.Unit(r?[r]:t)},e.Dimension.prototype={type:"Dimension",accept:function(e){this.unit=e.visit(this.unit)},eval:function(e){return this},toColor:function(){return new e.Color([this.value,this.value,this.value])},toCSS:function(e){if(e&&e.strictUnits&&!this.unit.isSingular())throw new Error("Multiple units in dimension. Correct the units or use the unit function. Bad unit: "+this.unit.toString());var t=this.value,n=String(t);t!==0&&t<1e-6&&t>-0.000001&&(n=t.toFixed(20).replace(/0+$/,""));if(e&&e.compress){if(t===0&&!this.unit.isAngle())return n;t>0&&t<1&&(n=n.substr(1))}return n+this.unit.toCSS(e)},operate:function(t,n,r){var i=e.operate(t,n,this.value,r.value),s=this.unit.clone();if(n==="+"||n==="-"){if(s.numerator.length===0&&s.denominator.length===0)s.numerator=r.unit.numerator.slice(0),s.denominator=r.unit.denominator.slice(0);else if(r.unit.numerator.length!=0||s.denominator.length!=0){r=r.convertTo(this.unit.usedUnits());if(t.strictUnits&&r.unit.toString()!==s.toString())throw new Error("Incompatible units. Change the units or use the unit function. Bad units: '"+s.toString()+"' and '"+r.unit.toString()+"'.");i=e.operate(t,n,this.value,r.value)}}else n==="*"?(s.numerator=s.numerator.concat(r.unit.numerator).sort(),s.denominator=s.denominator.concat(r.unit.denominator).sort(),s.cancel()):n==="/"&&(s.numerator=s.numerator.concat(r.unit.denominator).sort(),s.denominator=s.denominator.concat(r.unit.numerator).sort(),s.cancel());return new e.Dimension(i,s)},compare:function(t){if(t instanceof e.Dimension){var n=this.unify(),r=t.unify(),i=n.value,s=r.value;return s>i?-1:s=1?this.numerator[0]:this.denominator.length>=1?this.denominator[0]:(!e||!e.strictUnits)&&this.backupUnit?this.backupUnit:""},toString:function(){var e,t=this.numerator.join("*");for(e=0;e0)for(n=0;n":e.compress?">":" > ","|":e.compress?"|":" | "}[this.value]}}}(n("../tree")),function(e){e.Expression=function(e){this.value=e},e.Expression.prototype={type:"Expression",accept:function(e){this.value=e.visit(this.value)},eval:function(t){var n,r=this.parens&&!this.parensInOp,i=!1;return r&&t.inParenthesis(),this.value.length>1?n=new e.Expression(this.value.map(function(e){return e.eval(t)})):this.value.length===1?(this.value[0].parens&&!this.value[0].parensInOp&&(i=!0),n=this.value[0].eval(t)):n=this,r&&t.outOfParenthesis(),this.parens&&this.parensInOp&&!t.isMathOn()&&!i&&(n=new e.Paren(n)),n},toCSS:function(e){return this.value.map(function(t){return t.toCSS?t.toCSS(e):""}).join(" ")},throwAwayComments:function(){this.value=this.value.filter(function(t){return!(t instanceof e.Comment)})}}}(n("../tree")),function(e){e.Extend=function(t,n,r){this.selector=t,this.option=n,this.index=r;switch(n){case"all":this.allowBefore=!0,this.allowAfter=!0;break;default:this.allowBefore=!1,this.allowAfter=!1}},e.Extend.prototype={type:"Extend",accept:function(e){this.selector=e.visit(this.selector)},eval:function(t){return new e.Extend(this.selector.eval(t),this.option,this.index)},clone:function(t){return new e.Extend(this.selector,this.option,this.index)},findSelfSelectors:function(e){var t=[],n;for(n=0;n1){var r=this.emptySelectors();n=new e.Ruleset(r,t.mediaBlocks),n.multiMedia=!0}return delete t.mediaBlocks,delete t.mediaPath,n},evalNested:function(t){var n,r,i=t.mediaPath.concat([this]);for(n=0;n0;n--)t.splice(n,0,new e.Anonymous("and"));return new e.Expression(t)})),new e.Ruleset([],[])},permute:function(e){if(e.length===0)return[];if(e.length===1)return e[0];var t=[],n=this.permute(e.slice(1));for(var r=0;r0){c=!0;for(a=0;athis.params.length)return!1;if(this.required>0&&n>this.params.length)return!1}r=Math.min(n,this.arity);for(var s=0;si.selectors[o].elements.length?Array.prototype.push.apply(r,i.find(new e.Selector(t.elements.slice(1)),n)):r.push(i);break}}),this._lookups[o]=r)},toCSS:function(t){var n=[],r=[],i=[],s=[],o,u,a;for(var f=0;f0){u=e.debugInfo(t,this),o=this.paths.map(function(e){return e.map(function(e){return e.toCSS(t)}).join("").trim()}).join(t.compress?",":",\n");for(var f=r.length-1;f>=0;f--)(r[f].slice(0,2)==="/*"||i.indexOf(r[f])===-1)&&i.unshift(r[f]);r=i,n.push(u+o+(t.compress?"{":" {\n ")+r.join(t.compress?"":"\n ")+(t.compress?"}":"\n}\n"))}return n.push(s),n.join("")+(t.compress?"\n":"")},joinSelectors:function(e,t,n){for(var r=0;r0)for(i=0;i0&&this.mergeElementsOnToSelectors(g,a);for(s=0;s0&&(l[0].elements=l[0].elements.slice(0),l[0].elements.push(new e.Element(f.combinator,"",0))),y.push(l);else for(o=0;o0?(h=l.slice(0),m=h.pop(),d=new e.Selector(m.elements.slice(0),r.extendList),v=!1):d=new e.Selector([],r.extendList),c.length>1&&(p=p.concat(c.slice(1))),c.length>0&&(v=!1,d.elements.push(new e.Element(f.combinator,c[0].elements[0].value,0)),d.elements=d.elements.concat(c[0].elements.slice(1))),v||h.push(d),h=h.concat(p),y.push(h)}a=y,g=[]}}g.length>0&&this.mergeElementsOnToSelectors(g,a);for(i=0;i0&&t.push(a[i])},mergeElementsOnToSelectors:function(t,n){var r,i,s;if(n.length==0){n.push([new e.Selector(t)]);return}for(r=0;r0?i[i.length-1]=new e.Selector(i[i.length-1].elements.concat(t),i[i.length-1].extendList):i.push(new e.Selector(t))}}}(n("../tree")),function(e){e.Selector=function(e,t){this.elements=e,this.extendList=t||[]},e.Selector.prototype={type:"Selector",accept:function(e){this.elements=e.visit(this.elements),this.extendList=e.visit(this.extendList)},match:function(e){var t=this.elements,n=t.length,r,i,s,o;r=e.elements.slice(e.elements.length&&e.elements[0].value==="&"?1:0),i=r.length,s=Math.min(n,i);if(i===0||n1?"["+e.value.map(function(e){return e.toCSS(!1)}).join(", ")+"]":e.toCSS(!1)}}(n("./tree")),function(e){var t=["paths","optimization","files","contents","relativeUrls","strictImports","dumpLineNumbers","compress","processImports","syncImport","mime","currentFileInfo"];e.parseEnv=function(e){r(e,this,t),this.contents||(this.contents={}),this.files||(this.files={});if(!this.currentFileInfo){var n=e&&e.filename||"input",i=n.replace(/[^\/\\]*$/,"");e&&(e.filename=null),this.currentFileInfo={filename:n,relativeUrls:this.relativeUrls,rootpath:e&&e.rootpath||"",currentDirectory:i,entryPath:i,rootFilename:n}}},e.parseEnv.prototype.toSheet=function(t){var n=new e.parseEnv(this);return n.href=t,n.type=this.mime,n};var n=["silent","verbose","compress","yuicompress","ieCompat","strictMath","strictUnits"];e.evalEnv=function(e,t){r(e,this,n),this.frames=t||[]},e.evalEnv.prototype.inParenthesis=function(){this.parensStack||(this.parensStack=[]),this.parensStack.push(!0)},e.evalEnv.prototype.outOfParenthesis=function(){this.parensStack.pop()},e.evalEnv.prototype.isMathOn=function(){return this.strictMath?this.parensStack&&this.parensStack.length:!0},e.evalEnv.prototype.isPathRelative=function(e){return!/^(?:[a-z-]+:|\/)/.test(e)};var r=function(e,t,n){if(!e)return;for(var r=0;r100){var d="{unable to calculate}",v="{unable to calculate}";try{d=u[0].selfSelectors[0].toCSS(),v=u[0].selector.toCSS()}catch(m){}throw{message:"extend circular reference detected. One of the circular extends is currently:"+d+":extend("+v+")"}}return u.concat(f.doExtendChaining(u,n,r+1))}return u},inInheritanceChain:function(e,t){if(e===t)return!0;if(t.parents){if(this.inInheritanceChain(e,t.parents[0]))return!0;if(this.inInheritanceChain(e,t.parents[1]))return!0}return!1},visitRule:function(e,t){t.visitDeeper=!1},visitMixinDefinition:function(e,t){t.visitDeeper=!1},visitSelector:function(e,t){t.visitDeeper=!1},visitRuleset:function(e,t){if(e.root)return;var n,r,i,s=this.allExtendsStack[this.allExtendsStack.length-1],o=[],u=this,a;for(i=0;i0&&f[c.matched].combinator.value!==o?c=null:c.matched++,c&&(c.finished=c.matched===f.length,c.finished&&!e.allowAfter&&(i+1i&&s>0&&(o[o.length-1].elements=o[o.length-1].elements.concat(n[i].elements.slice(s)),s=0,i++),o=o.concat(n.slice(i,l.pathIndex)),o.push(new e.Selector(a.elements.slice(s,l.index).concat([f]).concat(r.elements.slice(1)))),i=l.endPathIndex,s=l.endPathElementIndex,s>=a.elements.length&&(s=0,i++);return i0&&(o[o.length-1].elements=o[o.length-1].elements.concat(n[i].elements.slice(s)),s=0,i++),o=o.concat(n.slice(i,n.length)),o},visitRulesetOut:function(e){},visitMedia:function(e,t){var n=e.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length-1]);n=n.concat(this.doExtendChaining(n,e.allExtends)),this.allExtendsStack.push(n)},visitMediaOut:function(e){this.allExtendsStack.length=this.allExtendsStack.length-1},visitDirective:function(e,t){var n=e.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length-1]);n=n.concat(this.doExtendChaining(n,e.allExtends)),this.allExtendsStack.push(n)},visitDirectiveOut:function(e){this.allExtendsStack.length=this.allExtendsStack.length-1}}}(n("./tree"));var o=/^(file|chrome(-extension)?|resource|qrc|app):/.test(location.protocol);r.env=r.env||(location.hostname=="127.0.0.1"||location.hostname=="0.0.0.0"||location.hostname=="localhost"||location.port.length>0||o?"development":"production"),r.async=r.async||!1,r.fileAsync=r.fileAsync||!1,r.poll=r.poll||(o?1e3:1500);if(r.functions)for(var u in r.functions)r.tree.functions[u]=r.functions[u];var a=/!dumpLineNumbers:(comments|mediaquery|all)/.exec(location.hash);a&&(r.dumpLineNumbers=a[1]),r.watch=function(){return r.watchMode||(r.env="development",f()),this.watchMode=!0},r.unwatch=function(){return clearInterval(r.watchTimer),this.watchMode=!1},/!watch/.test(location.hash)&&r.watch();var l=null;if(r.env!="development")try{l=typeof e.localStorage=="undefined"?null:e.localStorage}catch(c){}var h=document.getElementsByTagName("link"),p=/^text\/(x-)?less$/;r.sheets=[];for(var d=0;d>> 0; for (var i = 0; i < len; i++) { if (i in this) { block.call(thisObject, this[i], i, this); } } }; } if (!Array.prototype.map) { Array.prototype.map = function(fun /*, thisp*/) { var len = this.length >>> 0; var res = new Array(len); var thisp = arguments[1]; for (var i = 0; i < len; i++) { if (i in this) { res[i] = fun.call(thisp, this[i], i, this); } } return res; }; } if (!Array.prototype.filter) { Array.prototype.filter = function (block /*, thisp */) { var values = []; var thisp = arguments[1]; for (var i = 0; i < this.length; i++) { if (block.call(thisp, this[i])) { values.push(this[i]); } } return values; }; } if (!Array.prototype.reduce) { Array.prototype.reduce = function(fun /*, initial*/) { var len = this.length >>> 0; var i = 0; // no value to return if no initial value and an empty array if (len === 0 && arguments.length === 1) throw new TypeError(); if (arguments.length >= 2) { var rv = arguments[1]; } else { do { if (i in this) { rv = this[i++]; break; } // if array contains no values, no initial value to return if (++i >= len) throw new TypeError(); } while (true); } for (; i < len; i++) { if (i in this) { rv = fun.call(null, rv, this[i], i, this); } } return rv; }; } if (!Array.prototype.indexOf) { Array.prototype.indexOf = function (value /*, fromIndex */ ) { var length = this.length; var i = arguments[1] || 0; if (!length) return -1; if (i >= length) return -1; if (i < 0) i += length; for (; i < length; i++) { if (!Object.prototype.hasOwnProperty.call(this, i)) { continue } if (value === this[i]) return i; } return -1; }; } // // Object // if (!Object.keys) { Object.keys = function (object) { var keys = []; for (var name in object) { if (Object.prototype.hasOwnProperty.call(object, name)) { keys.push(name); } } return keys; }; } // // String // if (!String.prototype.trim) { String.prototype.trim = function () { return String(this).replace(/^\s\s*/, '').replace(/\s\s*$/, ''); }; } var less, tree; if (typeof(window) === 'undefined') { if (typeof(exports) === 'undefined') { // Rhino less = {}; tree = less.tree = {}; } else { // Node.js less = exports, tree = require('less/tree'); } } else { // Browser if (typeof(window.less) === 'undefined') { window.less = {} } less = window.less, tree = window.less.tree = {}; } // // less.js - parser // // A relatively straight-forward predictive parser. // There is no tokenization/lexing stage, the input is parsed // in one sweep. // // To make the parser fast enough to run in the browser, several // optimization had to be made: // // - Matching and slicing on a huge input is often cause of slowdowns. // The solution is to chunkify the input into smaller strings. // The chunks are stored in the `chunks` var, // `j` holds the current chunk index, and `current` holds // the index of the current chunk in relation to `input`. // This gives us an almost 4x speed-up. // // - In many cases, we don't need to match individual tokens; // for example, if a value doesn't hold any variables, operations // or dynamic references, the parser can effectively 'skip' it, // treating it as a literal. // An example would be '1px solid #000' - which evaluates to itself, // we don't need to know what the individual components are. // The drawback, of course is that you don't get the benefits of // syntax-checking on the CSS. This gives us a 50% speed-up in the parser, // and a smaller speed-up in the code-gen. // // // Token matching is done with the `$` function, which either takes // a terminal string or regexp, or a non-terminal function to call. // It also takes care of moving all the indices forwards. // // less.Parser = function Parser(env) { var input, // LeSS input string i, // current index in `input` j, // current chunk temp, // temporarily holds a chunk's state, for backtracking memo, // temporarily holds `i`, when backtracking furthest, // furthest index the parser has gone to chunks, // chunkified input current, // index of current chunk, in `input` parser; var that = this; // This function is called after all files // have been imported through `@import`. var finish = function () {}; var imports = this.imports = { paths: env && env.paths || [], // Search paths, when importing queue: [], // Files which haven't been imported yet files: {}, // Holds the imported parse trees mime: env && env.mime, // MIME type of .less files push: function (path, callback) { var that = this; this.queue.push(path); // // Import a file asynchronously // less.Parser.importer(path, this.paths, function (root) { that.queue.splice(that.queue.indexOf(path), 1); // Remove the path from the queue that.files[path] = root; // Store the root callback(root); if (that.queue.length === 0) { finish() } // Call `finish` if we're done importing }, env); } }; function save() { temp = chunks[j], memo = i, current = i } function restore() { chunks[j] = temp, i = memo, current = i } function sync() { if (i > current) { chunks[j] = chunks[j].slice(i - current); current = i; } } // // Parse from a token, regexp or string, and move forward if match // function $(tok) { var match, args, length, c, index, endIndex, k, mem; // // Non-terminal // if (tok instanceof Function) { return tok.call(parser.parsers); // // Terminal // // Either match a single character in the input, // or match a regexp in the current chunk (chunk[j]). // } else if (typeof(tok) === 'string') { match = input.charAt(i) === tok ? tok : null; length = 1; sync (); } else { sync (); if (match = tok.exec(chunks[j])) { length = match[0].length; } else { return null; } } // The match is confirmed, add the match length to `i`, // and consume any extra white-space characters (' ' || '\n') // which come after that. The reason for this is that LeSS's // grammar is mostly white-space insensitive. // if (match) { mem = i += length; endIndex = i + chunks[j].length - length; while (i < endIndex) { c = input.charCodeAt(i); if (! (c === 32 || c === 10 || c === 9)) { break } i++; } chunks[j] = chunks[j].slice(length + (i - mem)); current = i; if (chunks[j].length === 0 && j < chunks.length - 1) { j++ } if(typeof(match) === 'string') { return match; } else { return match.length === 1 ? match[0] : match; } } } // Same as $(), but don't change the state of the parser, // just return the match. function peek(tok) { if (typeof(tok) === 'string') { return input.charAt(i) === tok; } else { if (tok.test(chunks[j])) { return true; } else { return false; } } } this.env = env = env || {}; // The optimization level dictates the thoroughness of the parser, // the lower the number, the less nodes it will create in the tree. // This could matter for debugging, or if you want to access // the individual nodes in the tree. this.optimization = ('optimization' in this.env) ? this.env.optimization : 1; this.env.filename = this.env.filename || null; // // The Parser // return parser = { imports: imports, // // Parse an input string into an abstract syntax tree, // call `callback` when done. // parse: function (str, callback) { var root, start, end, zone, line, lines, buff = [], c, error = null; i = j = current = furthest = 0; chunks = []; input = str.replace(/\r\n/g, '\n'); // Split the input into chunks. chunks = (function (chunks) { var j = 0, skip = /[^"'`\{\}\/\(\)]+/g, comment = /\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g, level = 0, match, chunk = chunks[0], inParam, inString; for (var i = 0, c, cc; i < input.length; i++) { skip.lastIndex = i; if (match = skip.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); } } c = input.charAt(i); comment.lastIndex = i; if (!inString && !inParam && c === '/') { cc = input.charAt(i + 1); if (cc === '/' || cc === '*') { if (match = comment.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); c = input.charAt(i); } } } } if (c === '{' && !inString && !inParam) { level ++; chunk.push(c); } else if (c === '}' && !inString && !inParam) { level --; chunk.push(c); chunks[++j] = chunk = []; } else if (c === '(' && !inString && !inParam) { chunk.push(c); inParam = true; } else if (c === ')' && !inString && inParam) { chunk.push(c); inParam = false; } else { if (c === '"' || c === "'" || c === '`') { if (! inString) { inString = c; } else { inString = inString === c ? false : inString; } } chunk.push(c); } } if (level > 0) { throw { type: 'Syntax', message: "Missing closing `}`", filename: env.filename }; } return chunks.map(function (c) { return c.join('') });; })([[]]); // Start with the primary rule. // The whole syntax tree is held under a Ruleset node, // with the `root` property set to true, so no `{}` are // output. The callback is called when the input is parsed. root = new(tree.Ruleset)([], $(this.parsers.primary)); root.root = true; root.toCSS = (function (evaluate) { var line, lines, column; return function (options, variables) { var frames = []; options = options || {}; // // Allows setting variables with a hash, so: // // `{ color: new(tree.Color)('#f01') }` will become: // // new(tree.Rule)('@color', // new(tree.Value)([ // new(tree.Expression)([ // new(tree.Color)('#f01') // ]) // ]) // ) // if (typeof(variables) === 'object' && !Array.isArray(variables)) { variables = Object.keys(variables).map(function (k) { var value = variables[k]; if (! (value instanceof tree.Value)) { if (! (value instanceof tree.Expression)) { value = new(tree.Expression)([value]); } value = new(tree.Value)([value]); } return new(tree.Rule)('@' + k, value, false, 0); }); frames = [new(tree.Ruleset)(null, variables)]; } try { var css = evaluate.call(this, { frames: frames }) .toCSS([], { compress: options.compress || false }); } catch (e) { lines = input.split('\n'); line = getLine(e.index); for (var n = e.index, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } throw { type: e.type, message: e.message, filename: env.filename, index: e.index, line: typeof(line) === 'number' ? line + 1 : null, callLine: e.call && (getLine(e.call) + 1), callExtract: lines[getLine(e.call)], stack: e.stack, column: column, extract: [ lines[line - 1], lines[line], lines[line + 1] ] }; } if (options.compress) { return css.replace(/(\s)+/g, "$1"); } else { return css; } function getLine(index) { return index ? (input.slice(0, index).match(/\n/g) || "").length : null; } }; })(root.eval); // If `i` is smaller than the `input.length - 1`, // it means the parser wasn't able to parse the whole // string, so we've got a parsing error. // // We try to extract a \n delimited string, // showing the line where the parse error occured. // We split it up into two parts (the part which parsed, // and the part which didn't), so we can color them differently. if (i < input.length - 1) { i = furthest; lines = input.split('\n'); line = (input.slice(0, i).match(/\n/g) || "").length + 1; for (var n = i, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } error = { name: "ParseError", message: "Syntax Error on line " + line, index: i, filename: env.filename, line: line, column: column, extract: [ lines[line - 2], lines[line - 1], lines[line] ] }; } if (this.imports.queue.length > 0) { finish = function () { callback(error, root) }; } else { callback(error, root); } }, // // Here in, the parsing rules/functions // // The basic structure of the syntax tree generated is as follows: // // Ruleset -> Rule -> Value -> Expression -> Entity // // Here's some LESS code: // // .class { // color: #fff; // border: 1px solid #000; // width: @w + 4px; // > .child {...} // } // // And here's what the parse tree might look like: // // Ruleset (Selector '.class', [ // Rule ("color", Value ([Expression [Color #fff]])) // Rule ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]])) // Rule ("width", Value ([Expression [Operation "+" [Variable "@w"][Dimension 4px]]])) // Ruleset (Selector [Element '>', '.child'], [...]) // ]) // // In general, most rules will try to parse a token with the `$()` function, and if the return // value is truly, will return a new node, of the relevant type. Sometimes, we need to check // first, before parsing, that's when we use `peek()`. // parsers: { // // The `primary` rule is the *entry* and *exit* point of the parser. // The rules here can appear at any level of the parse tree. // // The recursive nature of the grammar is an interplay between the `block` // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule, // as represented by this simplified grammar: // // primary → (ruleset | rule)+ // ruleset → selector+ block // block → '{' primary '}' // // Only at one point is the primary rule not called from the // block rule: at the root level. // primary: function () { var node, root = []; while ((node = $(this.mixin.definition) || $(this.rule) || $(this.ruleset) || $(this.mixin.call) || $(this.comment) || $(this.directive)) || $(/^[\s\n]+/)) { node && root.push(node); } return root; }, // We create a Comment node for CSS comments `/* */`, // but keep the LeSS comments `//` silent, by just skipping // over them. comment: function () { var comment; if (input.charAt(i) !== '/') return; if (input.charAt(i + 1) === '/') { return new(tree.Comment)($(/^\/\/.*/), true); } else if (comment = $(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/)) { return new(tree.Comment)(comment); } }, // // Entities are tokens which can be found inside an Expression // entities: { // // A string, which supports escaping " and ' // // "milky way" 'he\'s the one!' // quoted: function () { var str, j = i, e; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '"' && input.charAt(j) !== "'") return; e && $('~'); if (str = $(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/)) { return new(tree.Quoted)(str[0], str[1] || str[2], e); } }, // // A catch-all word, such as: // // black border-collapse // keyword: function () { var k; if (k = $(/^[A-Za-z-]+/)) { return new(tree.Keyword)(k) } }, // // A function call // // rgb(255, 0, 255) // // We also try to catch IE's `alpha()`, but let the `alpha` parser // deal with the details. // // The arguments are parsed with the `entities.arguments` parser. // call: function () { var name, args, index = i; if (! (name = /^([\w-]+|%)\(/.exec(chunks[j]))) return; name = name[1].toLowerCase(); if (name === 'url') { return null } else { i += name.length } if (name === 'alpha') { return $(this.alpha) } $('('); // Parse the '(' and consume whitespace. args = $(this.entities.arguments); if (! $(')')) return; if (name) { return new(tree.Call)(name, args, index) } }, arguments: function () { var args = [], arg; while (arg = $(this.expression)) { args.push(arg); if (! $(',')) { break } } return args; }, literal: function () { return $(this.entities.dimension) || $(this.entities.color) || $(this.entities.quoted); }, // // Parse url() tokens // // We use a specific rule for urls, because they don't really behave like // standard function calls. The difference is that the argument doesn't have // to be enclosed within a string, so it can't be parsed as an Expression. // url: function () { var value; if (input.charAt(i) !== 'u' || !$(/^url\(/)) return; value = $(this.entities.quoted) || $(this.entities.variable) || $(this.entities.dataURI) || $(/^[-\w%@$\/.&=:;#+?~]+/) || ""; if (! $(')')) throw new(Error)("missing closing ) for url()"); return new(tree.URL)((value.value || value.data || value instanceof tree.Variable) ? value : new(tree.Anonymous)(value), imports.paths); }, dataURI: function () { var obj; if ($(/^data:/)) { obj = {}; obj.mime = $(/^[^\/]+\/[^,;)]+/) || ''; obj.charset = $(/^;\s*charset=[^,;)]+/) || ''; obj.base64 = $(/^;\s*base64/) || ''; obj.data = $(/^,\s*[^)]+/); if (obj.data) { return obj } } }, // // A Variable entity, such as `@fink`, in // // width: @fink + 2px // // We use a different parser for variable definitions, // see `parsers.variable`. // variable: function () { var name, index = i; if (input.charAt(i) === '@' && (name = $(/^@@?[\w-]+/))) { return new(tree.Variable)(name, index); } }, // // A Hexadecimal color // // #4F3C2F // // `rgb` and `hsl` colors are parsed through the `entities.call` parser. // color: function () { var rgb; if (input.charAt(i) === '#' && (rgb = $(/^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})/))) { return new(tree.Color)(rgb[1]); } }, // // A Dimension, that is, a number and a unit // // 0.5em 95% // dimension: function () { var value, c = input.charCodeAt(i); if ((c > 57 || c < 45) || c === 47) return; if (value = $(/^(-?\d*\.?\d+)(px|%|em|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn)?/)) { return new(tree.Dimension)(value[1], value[2]); } }, // // JavaScript code to be evaluated // // `window.location.href` // javascript: function () { var str, j = i, e; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '`') { return } e && $('~'); if (str = $(/^`([^`]*)`/)) { return new(tree.JavaScript)(str[1], i, e); } } }, // // The variable part of a variable definition. Used in the `rule` parser // // @fink: // variable: function () { var name; if (input.charAt(i) === '@' && (name = $(/^(@[\w-]+)\s*:/))) { return name[1] } }, // // A font size/line-height shorthand // // small/12px // // We need to peek first, or we'll match on keywords and dimensions // shorthand: function () { var a, b; if (! peek(/^[@\w.%-]+\/[@\w.-]+/)) return; if ((a = $(this.entity)) && $('/') && (b = $(this.entity))) { return new(tree.Shorthand)(a, b); } }, // // Mixins // mixin: { // // A Mixin call, with an optional argument list // // #mixins > .square(#fff); // .rounded(4px, black); // .button; // // The `while` loop is there because mixins can be // namespaced, but we only support the child and descendant // selector for now. // call: function () { var elements = [], e, c, args, index = i, s = input.charAt(i); if (s !== '.' && s !== '#') { return } while (e = $(/^[#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/)) { elements.push(new(tree.Element)(c, e)); c = $('>'); } $('(') && (args = $(this.entities.arguments)) && $(')'); if (elements.length > 0 && ($(';') || peek('}'))) { return new(tree.mixin.Call)(elements, args, index); } }, // // A Mixin definition, with a list of parameters // // .rounded (@radius: 2px, @color) { // ... // } // // Until we have a finer grained state-machine, we have to // do a look-ahead, to make sure we don't have a mixin call. // See the `rule` function for more information. // // We start by matching `.rounded (`, and then proceed on to // the argument list, which has optional default values. // We store the parameters in `params`, with a `value` key, // if there is a value, such as in the case of `@radius`. // // Once we've got our params list, and a closing `)`, we parse // the `{...}` block. // definition: function () { var name, params = [], match, ruleset, param, value; if ((input.charAt(i) !== '.' && input.charAt(i) !== '#') || peek(/^[^{]*(;|})/)) return; if (match = $(/^([#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+)\s*\(/)) { name = match[1]; while (param = $(this.entities.variable) || $(this.entities.literal) || $(this.entities.keyword)) { // Variable if (param instanceof tree.Variable) { if ($(':')) { if (value = $(this.expression)) { params.push({ name: param.name, value: value }); } else { throw new(Error)("Expected value"); } } else { params.push({ name: param.name }); } } else { params.push({ value: param }); } if (! $(',')) { break } } if (! $(')')) throw new(Error)("Expected )"); ruleset = $(this.block); if (ruleset) { return new(tree.mixin.Definition)(name, params, ruleset); } } } }, // // Entities are the smallest recognized token, // and can be found inside a rule's value. // entity: function () { return $(this.entities.literal) || $(this.entities.variable) || $(this.entities.url) || $(this.entities.call) || $(this.entities.keyword) || $(this.entities.javascript) || $(this.comment); }, // // A Rule terminator. Note that we use `peek()` to check for '}', // because the `block` rule will be expecting it, but we still need to make sure // it's there, if ';' was ommitted. // end: function () { return $(';') || peek('}'); }, // // IE's alpha function // // alpha(opacity=88) // alpha: function () { var value; if (! $(/^\(opacity=/i)) return; if (value = $(/^\d+/) || $(this.entities.variable)) { if (! $(')')) throw new(Error)("missing closing ) for alpha()"); return new(tree.Alpha)(value); } }, // // A Selector Element // // div // + h1 // #socks // input[type="text"] // // Elements are the building blocks for Selectors, // they are made out of a `Combinator` (see combinator rule), // and an element name, such as a tag a class, or `*`. // element: function () { var e, t, c; c = $(this.combinator); e = $(/^(?:[.#]?|:*)(?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/) || $('*') || $(this.attribute) || $(/^\([^)@]+\)/); if (e) { return new(tree.Element)(c, e) } if (c.value && c.value[0] === '&') { return new(tree.Element)(c, null); } }, // // Combinators combine elements together, in a Selector. // // Because our parser isn't white-space sensitive, special care // has to be taken, when parsing the descendant combinator, ` `, // as it's an empty space. We have to check the previous character // in the input, to see if it's a ` ` character. More info on how // we deal with this in *combinator.js*. // combinator: function () { var match, c = input.charAt(i); if (c === '>' || c === '+' || c === '~') { i++; while (input.charAt(i) === ' ') { i++ } return new(tree.Combinator)(c); } else if (c === '&') { match = '&'; i++; if(input.charAt(i) === ' ') { match = '& '; } while (input.charAt(i) === ' ') { i++ } return new(tree.Combinator)(match); } else if (c === ':' && input.charAt(i + 1) === ':') { i += 2; while (input.charAt(i) === ' ') { i++ } return new(tree.Combinator)('::'); } else if (input.charAt(i - 1) === ' ') { return new(tree.Combinator)(" "); } else { return new(tree.Combinator)(null); } }, // // A CSS Selector // // .class > div + h1 // li a:hover // // Selectors are made out of one or more Elements, see above. // selector: function () { var sel, e, elements = [], c, match; while (e = $(this.element)) { c = input.charAt(i); elements.push(e) if (c === '{' || c === '}' || c === ';' || c === ',') { break } } if (elements.length > 0) { return new(tree.Selector)(elements) } }, tag: function () { return $(/^[a-zA-Z][a-zA-Z-]*[0-9]?/) || $('*'); }, attribute: function () { var attr = '', key, val, op; if (! $('[')) return; if (key = $(/^[a-zA-Z-]+/) || $(this.entities.quoted)) { if ((op = $(/^[|~*$^]?=/)) && (val = $(this.entities.quoted) || $(/^[\w-]+/))) { attr = [key, op, val.toCSS ? val.toCSS() : val].join(''); } else { attr = key } } if (! $(']')) return; if (attr) { return "[" + attr + "]" } }, // // The `block` rule is used by `ruleset` and `mixin.definition`. // It's a wrapper around the `primary` rule, with added `{}`. // block: function () { var content; if ($('{') && (content = $(this.primary)) && $('}')) { return content; } }, // // div, .class, body > p {...} // ruleset: function () { var selectors = [], s, rules, match; save(); if (match = /^([.#: \w-]+)[\s\n]*\{/.exec(chunks[j])) { i += match[0].length - 1; selectors = [new(tree.Selector)([new(tree.Element)(null, match[1])])]; } else { while (s = $(this.selector)) { selectors.push(s); $(this.comment); if (! $(',')) { break } $(this.comment); } } if (selectors.length > 0 && (rules = $(this.block))) { return new(tree.Ruleset)(selectors, rules); } else { // Backtrack furthest = i; restore(); } }, rule: function () { var name, value, c = input.charAt(i), important, match; save(); if (c === '.' || c === '#' || c === '&') { return } if (name = $(this.variable) || $(this.property)) { if ((name.charAt(0) != '@') && (match = /^([^@+\/'"*`(;{}-]*);/.exec(chunks[j]))) { i += match[0].length - 1; value = new(tree.Anonymous)(match[1]); } else if (name === "font") { value = $(this.font); } else { value = $(this.value); } important = $(this.important); if (value && $(this.end)) { return new(tree.Rule)(name, value, important, memo); } else { furthest = i; restore(); } } }, // // An @import directive // // @import "lib"; // // Depending on our environemnt, importing is done differently: // In the browser, it's an XHR request, in Node, it would be a // file-system operation. The function used for importing is // stored in `import`, which we pass to the Import constructor. // "import": function () { var path; if ($(/^@import\s+/) && (path = $(this.entities.quoted) || $(this.entities.url)) && $(';')) { return new(tree.Import)(path, imports); } }, // // A CSS Directive // // @charset "utf-8"; // directive: function () { var name, value, rules, types; if (input.charAt(i) !== '@') return; if (value = $(this['import'])) { return value; } else if (name = $(/^@media|@page|@-[-a-z]+/)) { types = ($(/^[^{]+/) || '').trim(); if (rules = $(this.block)) { return new(tree.Directive)(name + " " + types, rules); } } else if (name = $(/^@[-a-z]+/)) { if (name === '@font-face') { if (rules = $(this.block)) { return new(tree.Directive)(name, rules); } } else if ((value = $(this.entity)) && $(';')) { return new(tree.Directive)(name, value); } } }, font: function () { var value = [], expression = [], weight, shorthand, font, e; while (e = $(this.shorthand) || $(this.entity)) { expression.push(e); } value.push(new(tree.Expression)(expression)); if ($(',')) { while (e = $(this.expression)) { value.push(e); if (! $(',')) { break } } } return new(tree.Value)(value); }, // // A Value is a comma-delimited list of Expressions // // font-family: Baskerville, Georgia, serif; // // In a Rule, a Value represents everything after the `:`, // and before the `;`. // value: function () { var e, expressions = [], important; while (e = $(this.expression)) { expressions.push(e); if (! $(',')) { break } } if (expressions.length > 0) { return new(tree.Value)(expressions); } }, important: function () { if (input.charAt(i) === '!') { return $(/^! *important/); } }, sub: function () { var e; if ($('(') && (e = $(this.expression)) && $(')')) { return e; } }, multiplication: function () { var m, a, op, operation; if (m = $(this.operand)) { while ((op = ($('/') || $('*'))) && (a = $(this.operand))) { operation = new(tree.Operation)(op, [operation || m, a]); } return operation || m; } }, addition: function () { var m, a, op, operation; if (m = $(this.multiplication)) { while ((op = $(/^[-+]\s+/) || (input.charAt(i - 1) != ' ' && ($('+') || $('-')))) && (a = $(this.multiplication))) { operation = new(tree.Operation)(op, [operation || m, a]); } return operation || m; } }, // // An operand is anything that can be part of an operation, // such as a Color, or a Variable // operand: function () { var negate, p = input.charAt(i + 1); if (input.charAt(i) === '-' && (p === '@' || p === '(')) { negate = $('-') } var o = $(this.sub) || $(this.entities.dimension) || $(this.entities.color) || $(this.entities.variable) || $(this.entities.call); return negate ? new(tree.Operation)('*', [new(tree.Dimension)(-1), o]) : o; }, // // Expressions either represent mathematical operations, // or white-space delimited Entities. // // 1px solid black // @var * 2 // expression: function () { var e, delim, entities = [], d; while (e = $(this.addition) || $(this.entity)) { entities.push(e); } if (entities.length > 0) { return new(tree.Expression)(entities); } }, property: function () { var name; if (name = $(/^(\*?-?[-a-z_0-9]+)\s*:/)) { return name[1]; } } } }; }; if (typeof(window) !== 'undefined' /* browser */ || typeof(exports) === 'undefined' /* rhino */) { // // Used by `@import` directives // less.Parser.importer = function (path, paths, callback, env) { if (path.charAt(0) !== '/' && paths.length > 0) { path = paths[0] + path; } // We pass `true` as 3rd argument, to force the reload of the import. // This is so we can get the syntax tree as opposed to just the CSS output, // as we need this to evaluate the current stylesheet. loadStyleSheet({ href: path, title: path, type: env.mime }, callback, true); }; } (function (tree) { tree.functions = { rgb: function (r, g, b) { return this.rgba(r, g, b, 1.0); }, rgba: function (r, g, b, a) { var rgb = [r, g, b].map(function (c) { return number(c) }), a = number(a); return new(tree.Color)(rgb, a); }, hsl: function (h, s, l) { return this.hsla(h, s, l, 1.0); }, hsla: function (h, s, l, a) { h = (number(h) % 360) / 360; s = number(s); l = number(l); a = number(a); var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s; var m1 = l * 2 - m2; return this.rgba(hue(h + 1/3) * 255, hue(h) * 255, hue(h - 1/3) * 255, a); function hue(h) { h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h); if (h * 6 < 1) return m1 + (m2 - m1) * h * 6; else if (h * 2 < 1) return m2; else if (h * 3 < 2) return m1 + (m2 - m1) * (2/3 - h) * 6; else return m1; } }, hue: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().h)); }, saturation: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().s * 100), '%'); }, lightness: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().l * 100), '%'); }, alpha: function (color) { return new(tree.Dimension)(color.toHSL().a); }, saturate: function (color, amount) { var hsl = color.toHSL(); hsl.s += amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, desaturate: function (color, amount) { var hsl = color.toHSL(); hsl.s -= amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, lighten: function (color, amount) { var hsl = color.toHSL(); hsl.l += amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, darken: function (color, amount) { var hsl = color.toHSL(); hsl.l -= amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, fadein: function (color, amount) { var hsl = color.toHSL(); hsl.a += amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, fadeout: function (color, amount) { var hsl = color.toHSL(); hsl.a -= amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, spin: function (color, amount) { var hsl = color.toHSL(); var hue = (hsl.h + amount.value) % 360; hsl.h = hue < 0 ? 360 + hue : hue; return hsla(hsl); }, // // Copyright (c) 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein // http://sass-lang.com // mix: function (color1, color2, weight) { var p = weight.value / 100.0; var w = p * 2 - 1; var a = color1.toHSL().a - color2.toHSL().a; var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0; var w2 = 1 - w1; var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2, color1.rgb[1] * w1 + color2.rgb[1] * w2, color1.rgb[2] * w1 + color2.rgb[2] * w2]; var alpha = color1.alpha * p + color2.alpha * (1 - p); return new(tree.Color)(rgb, alpha); }, greyscale: function (color) { return this.desaturate(color, new(tree.Dimension)(100)); }, e: function (str) { return new(tree.Anonymous)(str instanceof tree.JavaScript ? str.evaluated : str); }, escape: function (str) { return new(tree.Anonymous)(encodeURI(str.value).replace(/=/g, "%3D").replace(/:/g, "%3A").replace(/#/g, "%23").replace(/;/g, "%3B").replace(/\(/g, "%28").replace(/\)/g, "%29")); }, '%': function (quoted /* arg, arg, ...*/) { var args = Array.prototype.slice.call(arguments, 1), str = quoted.value; for (var i = 0; i < args.length; i++) { str = str.replace(/%[sda]/i, function(token) { var value = token.match(/s/i) ? args[i].value : args[i].toCSS(); return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value; }); } str = str.replace(/%%/g, '%'); return new(tree.Quoted)('"' + str + '"', str); }, round: function (n) { if (n instanceof tree.Dimension) { return new(tree.Dimension)(Math.round(number(n)), n.unit); } else if (typeof(n) === 'number') { return Math.round(n); } else { throw { error: "RuntimeError", message: "math functions take numbers as parameters" }; } } }; function hsla(hsla) { return tree.functions.hsla(hsla.h, hsla.s, hsla.l, hsla.a); } function number(n) { if (n instanceof tree.Dimension) { return parseFloat(n.unit == '%' ? n.value / 100 : n.value); } else if (typeof(n) === 'number') { return n; } else { throw { error: "RuntimeError", message: "color functions take numbers as parameters" }; } } function clamp(val) { return Math.min(1, Math.max(0, val)); } })(require('less/tree')); (function (tree) { tree.Alpha = function (val) { this.value = val; }; tree.Alpha.prototype = { toCSS: function () { return "alpha(opacity=" + (this.value.toCSS ? this.value.toCSS() : this.value) + ")"; }, eval: function (env) { if (this.value.eval) { this.value = this.value.eval(env) } return this; } }; })(require('less/tree')); (function (tree) { tree.Anonymous = function (string) { this.value = string.value || string; }; tree.Anonymous.prototype = { toCSS: function () { return this.value; }, eval: function () { return this } }; })(require('less/tree')); (function (tree) { // // A function call node. // tree.Call = function (name, args, index) { this.name = name; this.args = args; this.index = index; }; tree.Call.prototype = { // // When evaluating a function call, // we either find the function in `tree.functions` [1], // in which case we call it, passing the evaluated arguments, // or we simply print it out as it appeared originally [2]. // // The *functions.js* file contains the built-in functions. // // The reason why we evaluate the arguments, is in the case where // we try to pass a variable to a function, like: `saturate(@color)`. // The function should receive the value, not the variable. // eval: function (env) { var args = this.args.map(function (a) { return a.eval(env) }); if (this.name in tree.functions) { // 1. try { return tree.functions[this.name].apply(tree.functions, args); } catch (e) { throw { message: "error evaluating function `" + this.name + "`", index: this.index }; } } else { // 2. return new(tree.Anonymous)(this.name + "(" + args.map(function (a) { return a.toCSS() }).join(', ') + ")"); } }, toCSS: function (env) { return this.eval(env).toCSS(); } }; })(require('less/tree')); (function (tree) { // // RGB Colors - #ff0014, #eee // tree.Color = function (rgb, a) { // // The end goal here, is to parse the arguments // into an integer triplet, such as `128, 255, 0` // // This facilitates operations and conversions. // if (Array.isArray(rgb)) { this.rgb = rgb; } else if (rgb.length == 6) { this.rgb = rgb.match(/.{2}/g).map(function (c) { return parseInt(c, 16); }); } else if (rgb.length == 8) { this.alpha = parseInt(rgb.substring(0,2), 16) / 255.0; this.rgb = rgb.substr(2).match(/.{2}/g).map(function (c) { return parseInt(c, 16); }); } else { this.rgb = rgb.split('').map(function (c) { return parseInt(c + c, 16); }); } this.alpha = typeof(a) === 'number' ? a : 1; }; tree.Color.prototype = { eval: function () { return this }, // // If we have some transparency, the only way to represent it // is via `rgba`. Otherwise, we use the hex representation, // which has better compatibility with older browsers. // Values are capped between `0` and `255`, rounded and zero-padded. // toCSS: function () { if (this.alpha < 1.0) { return "rgba(" + this.rgb.map(function (c) { return Math.round(c); }).concat(this.alpha).join(', ') + ")"; } else { return '#' + this.rgb.map(function (i) { i = Math.round(i); i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16); return i.length === 1 ? '0' + i : i; }).join(''); } }, // // Operations have to be done per-channel, if not, // channels will spill onto each other. Once we have // our result, in the form of an integer triplet, // we create a new Color node to hold the result. // operate: function (op, other) { var result = []; if (! (other instanceof tree.Color)) { other = other.toColor(); } for (var c = 0; c < 3; c++) { result[c] = tree.operate(op, this.rgb[c], other.rgb[c]); } return new(tree.Color)(result, this.alpha + other.alpha); }, toHSL: function () { var r = this.rgb[0] / 255, g = this.rgb[1] / 255, b = this.rgb[2] / 255, a = this.alpha; var max = Math.max(r, g, b), min = Math.min(r, g, b); var h, s, l = (max + min) / 2, d = max - min; if (max === min) { h = s = 0; } else { s = l > 0.5 ? d / (2 - max - min) : d / (max + min); switch (max) { case r: h = (g - b) / d + (g < b ? 6 : 0); break; case g: h = (b - r) / d + 2; break; case b: h = (r - g) / d + 4; break; } h /= 6; } return { h: h * 360, s: s, l: l, a: a }; } }; })(require('less/tree')); (function (tree) { tree.Comment = function (value, silent) { this.value = value; this.silent = !!silent; }; tree.Comment.prototype = { toCSS: function (env) { return env.compress ? '' : this.value; }, eval: function () { return this } }; })(require('less/tree')); (function (tree) { // // A number with a unit // tree.Dimension = function (value, unit) { this.value = parseFloat(value); this.unit = unit || null; }; tree.Dimension.prototype = { eval: function () { return this }, toColor: function () { return new(tree.Color)([this.value, this.value, this.value]); }, toCSS: function () { var css = this.value + this.unit; return css; }, // In an operation between two Dimensions, // we default to the first Dimension's unit, // so `1px + 2em` will yield `3px`. // In the future, we could implement some unit // conversions such that `100cm + 10mm` would yield // `101cm`. operate: function (op, other) { return new(tree.Dimension) (tree.operate(op, this.value, other.value), this.unit || other.unit); } }; })(require('less/tree')); (function (tree) { tree.Directive = function (name, value) { this.name = name; if (Array.isArray(value)) { this.ruleset = new(tree.Ruleset)([], value); } else { this.value = value; } }; tree.Directive.prototype = { toCSS: function (ctx, env) { if (this.ruleset) { this.ruleset.root = true; return this.name + (env.compress ? '{' : ' {\n ') + this.ruleset.toCSS(ctx, env).trim().replace(/\n/g, '\n ') + (env.compress ? '}': '\n}\n'); } else { return this.name + ' ' + this.value.toCSS() + ';\n'; } }, eval: function (env) { env.frames.unshift(this); this.ruleset = this.ruleset && this.ruleset.eval(env); env.frames.shift(); return this; }, variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) }, find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) }, rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) } }; })(require('less/tree')); (function (tree) { tree.Element = function (combinator, value) { this.combinator = combinator instanceof tree.Combinator ? combinator : new(tree.Combinator)(combinator); this.value = value ? value.trim() : ""; }; tree.Element.prototype.toCSS = function (env) { return this.combinator.toCSS(env || {}) + this.value; }; tree.Combinator = function (value) { if (value === ' ') { this.value = ' '; } else if (value === '& ') { this.value = '& '; } else { this.value = value ? value.trim() : ""; } }; tree.Combinator.prototype.toCSS = function (env) { return { '' : '', ' ' : ' ', '&' : '', '& ' : ' ', ':' : ' :', '::': '::', '+' : env.compress ? '+' : ' + ', '~' : env.compress ? '~' : ' ~ ', '>' : env.compress ? '>' : ' > ' }[this.value]; }; })(require('less/tree')); (function (tree) { tree.Expression = function (value) { this.value = value }; tree.Expression.prototype = { eval: function (env) { if (this.value.length > 1) { return new(tree.Expression)(this.value.map(function (e) { return e.eval(env); })); } else if (this.value.length === 1) { return this.value[0].eval(env); } else { return this; } }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS(env); }).join(' '); } }; })(require('less/tree')); (function (tree) { // // CSS @import node // // The general strategy here is that we don't want to wait // for the parsing to be completed, before we start importing // the file. That's because in the context of a browser, // most of the time will be spent waiting for the server to respond. // // On creation, we push the import path to our import queue, though // `import,push`, we also pass it a callback, which it'll call once // the file has been fetched, and parsed. // tree.Import = function (path, imports) { var that = this; this._path = path; // The '.less' extension is optional if (path instanceof tree.Quoted) { this.path = /\.(le?|c)ss$/.test(path.value) ? path.value : path.value + '.less'; } else { this.path = path.value.value || path.value; } this.css = /css$/.test(this.path); // Only pre-compile .less files if (! this.css) { imports.push(this.path, function (root) { if (! root) { throw new(Error)("Error parsing " + that.path); } that.root = root; }); } }; // // The actual import node doesn't return anything, when converted to CSS. // The reason is that it's used at the evaluation stage, so that the rules // it imports can be treated like any other rules. // // In `eval`, we make sure all Import nodes get evaluated, recursively, so // we end up with a flat structure, which can easily be imported in the parent // ruleset. // tree.Import.prototype = { toCSS: function () { if (this.css) { return "@import " + this._path.toCSS() + ';\n'; } else { return ""; } }, eval: function (env) { var ruleset; if (this.css) { return this; } else { ruleset = new(tree.Ruleset)(null, this.root.rules.slice(0)); for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.Import) { Array.prototype .splice .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env))); } } return ruleset.rules; } } }; })(require('less/tree')); (function (tree) { tree.JavaScript = function (string, index, escaped) { this.escaped = escaped; this.expression = string; this.index = index; }; tree.JavaScript.prototype = { eval: function (env) { var result, that = this, context = {}; var expression = this.expression.replace(/@\{([\w-]+)\}/g, function (_, name) { return tree.jsify(new(tree.Variable)('@' + name, that.index).eval(env)); }); try { expression = new(Function)('return (' + expression + ')'); } catch (e) { throw { message: "JavaScript evaluation error: `" + expression + "`" , index: this.index }; } for (var k in env.frames[0].variables()) { context[k.slice(1)] = { value: env.frames[0].variables()[k].value, toJS: function () { return this.value.eval(env).toCSS(); } }; } try { result = expression.call(context); } catch (e) { throw { message: "JavaScript evaluation error: '" + e.name + ': ' + e.message + "'" , index: this.index }; } if (typeof(result) === 'string') { return new(tree.Quoted)('"' + result + '"', result, this.escaped, this.index); } else if (Array.isArray(result)) { return new(tree.Anonymous)(result.join(', ')); } else { return new(tree.Anonymous)(result); } } }; })(require('less/tree')); (function (tree) { tree.Keyword = function (value) { this.value = value }; tree.Keyword.prototype = { eval: function () { return this }, toCSS: function () { return this.value } }; })(require('less/tree')); (function (tree) { tree.mixin = {}; tree.mixin.Call = function (elements, args, index) { this.selector = new(tree.Selector)(elements); this.arguments = args; this.index = index; }; tree.mixin.Call.prototype = { eval: function (env) { var mixins, args, rules = [], match = false; for (var i = 0; i < env.frames.length; i++) { if ((mixins = env.frames[i].find(this.selector)).length > 0) { args = this.arguments && this.arguments.map(function (a) { return a.eval(env) }); for (var m = 0; m < mixins.length; m++) { if (mixins[m].match(args, env)) { try { Array.prototype.push.apply( rules, mixins[m].eval(env, this.arguments).rules); match = true; } catch (e) { throw { message: e.message, index: e.index, stack: e.stack, call: this.index }; } } } if (match) { return rules; } else { throw { message: 'No matching definition was found for `' + this.selector.toCSS().trim() + '(' + this.arguments.map(function (a) { return a.toCSS(); }).join(', ') + ")`", index: this.index }; } } } throw { message: this.selector.toCSS().trim() + " is undefined", index: this.index }; } }; tree.mixin.Definition = function (name, params, rules) { this.name = name; this.selectors = [new(tree.Selector)([new(tree.Element)(null, name)])]; this.params = params; this.arity = params.length; this.rules = rules; this._lookups = {}; this.required = params.reduce(function (count, p) { if (!p.name || (p.name && !p.value)) { return count + 1 } else { return count } }, 0); this.parent = tree.Ruleset.prototype; this.frames = []; }; tree.mixin.Definition.prototype = { toCSS: function () { return "" }, variable: function (name) { return this.parent.variable.call(this, name) }, variables: function () { return this.parent.variables.call(this) }, find: function () { return this.parent.find.apply(this, arguments) }, rulesets: function () { return this.parent.rulesets.apply(this) }, eval: function (env, args) { var frame = new(tree.Ruleset)(null, []), context, _arguments = []; for (var i = 0, val; i < this.params.length; i++) { if (this.params[i].name) { if (val = (args && args[i]) || this.params[i].value) { frame.rules.unshift(new(tree.Rule)(this.params[i].name, val.eval(env))); } else { throw { message: "wrong number of arguments for " + this.name + ' (' + args.length + ' for ' + this.arity + ')' }; } } } for (var i = 0; i < Math.max(this.params.length, args && args.length); i++) { _arguments.push(args[i] || this.params[i].value); } frame.rules.unshift(new(tree.Rule)('@arguments', new(tree.Expression)(_arguments).eval(env))); return new(tree.Ruleset)(null, this.rules.slice(0)).eval({ frames: [this, frame].concat(this.frames, env.frames) }); }, match: function (args, env) { var argsLength = (args && args.length) || 0, len; if (argsLength < this.required) { return false } if ((this.required > 0) && (argsLength > this.params.length)) { return false } len = Math.min(argsLength, this.arity); for (var i = 0; i < len; i++) { if (!this.params[i].name) { if (args[i].eval(env).toCSS() != this.params[i].value.eval(env).toCSS()) { return false; } } } return true; } }; })(require('less/tree')); (function (tree) { tree.Operation = function (op, operands) { this.op = op.trim(); this.operands = operands; }; tree.Operation.prototype.eval = function (env) { var a = this.operands[0].eval(env), b = this.operands[1].eval(env), temp; if (a instanceof tree.Dimension && b instanceof tree.Color) { if (this.op === '*' || this.op === '+') { temp = b, b = a, a = temp; } else { throw { name: "OperationError", message: "Can't substract or divide a color from a number" }; } } return a.operate(this.op, b); }; tree.operate = function (op, a, b) { switch (op) { case '+': return a + b; case '-': return a - b; case '*': return a * b; case '/': return a / b; } }; })(require('less/tree')); (function (tree) { tree.Quoted = function (str, content, escaped, i) { this.escaped = escaped; this.value = content || ''; this.quote = str.charAt(0); this.index = i; }; tree.Quoted.prototype = { toCSS: function () { if (this.escaped) { return this.value; } else { return this.quote + this.value + this.quote; } }, eval: function (env) { var that = this; var value = this.value.replace(/`([^`]+)`/g, function (_, exp) { return new(tree.JavaScript)(exp, that.index, true).eval(env).value; }).replace(/@\{([\w-]+)\}/g, function (_, name) { var v = new(tree.Variable)('@' + name, that.index).eval(env); return v.value || v.toCSS(); }); return new(tree.Quoted)(this.quote + value + this.quote, value, this.escaped, this.index); } }; })(require('less/tree')); (function (tree) { tree.Rule = function (name, value, important, index) { this.name = name; this.value = (value instanceof tree.Value) ? value : new(tree.Value)([value]); this.important = important ? ' ' + important.trim() : ''; this.index = index; if (name.charAt(0) === '@') { this.variable = true; } else { this.variable = false } }; tree.Rule.prototype.toCSS = function (env) { if (this.variable) { return "" } else { return this.name + (env.compress ? ':' : ': ') + this.value.toCSS(env) + this.important + ";"; } }; tree.Rule.prototype.eval = function (context) { return new(tree.Rule)(this.name, this.value.eval(context), this.important, this.index); }; tree.Shorthand = function (a, b) { this.a = a; this.b = b; }; tree.Shorthand.prototype = { toCSS: function (env) { return this.a.toCSS(env) + "/" + this.b.toCSS(env); }, eval: function () { return this } }; })(require('less/tree')); (function (tree) { tree.Ruleset = function (selectors, rules) { this.selectors = selectors; this.rules = rules; this._lookups = {}; }; tree.Ruleset.prototype = { eval: function (env) { var ruleset = new(tree.Ruleset)(this.selectors, this.rules.slice(0)); ruleset.root = this.root; // push the current ruleset to the frames stack env.frames.unshift(ruleset); // Evaluate imports if (ruleset.root) { for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.Import) { Array.prototype.splice .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env))); } } } // Store the frames around mixin definitions, // so they can be evaluated like closures when the time comes. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Definition) { ruleset.rules[i].frames = env.frames.slice(0); } } // Evaluate mixin calls. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Call) { Array.prototype.splice .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env))); } } // Evaluate everything else for (var i = 0, rule; i < ruleset.rules.length; i++) { rule = ruleset.rules[i]; if (! (rule instanceof tree.mixin.Definition)) { ruleset.rules[i] = rule.eval ? rule.eval(env) : rule; } } // Pop the stack env.frames.shift(); return ruleset; }, match: function (args) { return !args || args.length === 0; }, variables: function () { if (this._variables) { return this._variables } else { return this._variables = this.rules.reduce(function (hash, r) { if (r instanceof tree.Rule && r.variable === true) { hash[r.name] = r; } return hash; }, {}); } }, variable: function (name) { return this.variables()[name]; }, rulesets: function () { if (this._rulesets) { return this._rulesets } else { return this._rulesets = this.rules.filter(function (r) { return (r instanceof tree.Ruleset) || (r instanceof tree.mixin.Definition); }); } }, find: function (selector, self) { self = self || this; var rules = [], rule, match, key = selector.toCSS(); if (key in this._lookups) { return this._lookups[key] } this.rulesets().forEach(function (rule) { if (rule !== self) { for (var j = 0; j < rule.selectors.length; j++) { if (match = selector.match(rule.selectors[j])) { if (selector.elements.length > 1) { Array.prototype.push.apply(rules, rule.find( new(tree.Selector)(selector.elements.slice(1)), self)); } else { rules.push(rule); } break; } } } }); return this._lookups[key] = rules; }, // // Entry point for code generation // // `context` holds an array of arrays. // toCSS: function (context, env) { var css = [], // The CSS output rules = [], // node.Rule instances rulesets = [], // node.Ruleset instances paths = [], // Current selectors selector, // The fully rendered selector rule; if (! this.root) { if (context.length === 0) { paths = this.selectors.map(function (s) { return [s] }); } else { this.joinSelectors( paths, context, this.selectors ); } } // Compile rules and rulesets for (var i = 0; i < this.rules.length; i++) { rule = this.rules[i]; if (rule.rules || (rule instanceof tree.Directive)) { rulesets.push(rule.toCSS(paths, env)); } else if (rule instanceof tree.Comment) { if (!rule.silent) { if (this.root) { rulesets.push(rule.toCSS(env)); } else { rules.push(rule.toCSS(env)); } } } else { if (rule.toCSS && !rule.variable) { rules.push(rule.toCSS(env)); } else if (rule.value && !rule.variable) { rules.push(rule.value.toString()); } } } rulesets = rulesets.join(''); // If this is the root node, we don't render // a selector, or {}. // Otherwise, only output if this ruleset has rules. if (this.root) { css.push(rules.join(env.compress ? '' : '\n')); } else { if (rules.length > 0) { selector = paths.map(function (p) { return p.map(function (s) { return s.toCSS(env); }).join('').trim(); }).join(env.compress ? ',' : (paths.length > 3 ? ',\n' : ', ')); css.push(selector, (env.compress ? '{' : ' {\n ') + rules.join(env.compress ? '' : '\n ') + (env.compress ? '}' : '\n}\n')); } } css.push(rulesets); return css.join('') + (env.compress ? '\n' : ''); }, joinSelectors: function( paths, context, selectors ) { for (var s = 0; s < selectors.length; s++) { this.joinSelector(paths, context, selectors[s]); } }, joinSelector: function( paths, context, selector ) { var before = [], after = [], beforeElements = [], afterElements = [], hasParentSelector = false, el; for (var i = 0; i < selector.elements.length; i++) { el = selector.elements[i]; if (el.combinator.value[0] === '&') { hasParentSelector = true; } if(!hasParentSelector) { beforeElements.push(el); } else { afterElements.push(el); } } if(!hasParentSelector) { afterElements = beforeElements; beforeElements = []; } if(beforeElements.length > 0) { before.push(new (tree.Selector)(beforeElements)); } if(afterElements.length > 0) { after.push(new (tree.Selector)(afterElements)); } for (var c = 0; c < context.length; c++) { paths.push(before.concat(context[c]).concat(after)); } } }; })(require('less/tree')); (function (tree) { tree.Selector = function (elements) { this.elements = elements; if (this.elements[0].combinator.value === "") { this.elements[0].combinator.value = ' '; } }; tree.Selector.prototype.match = function (other) { if (this.elements[0].value === other.elements[0].value) { return true; } else { return false; } }; tree.Selector.prototype.toCSS = function (env) { if (this._css) { return this._css } return this._css = this.elements.map(function (e) { if (typeof(e) === 'string') { return ' ' + e.trim(); } else { return e.toCSS(env); } }).join(''); }; })(require('less/tree')); (function (tree) { tree.URL = function (val, paths) { if (val.data) { this.attrs = val; } else { // Add the base path if the URL is relative and we are in the browser if (!/^(?:https?:\/|file:\/|data:\/)?\//.test(val.value) && paths.length > 0 && typeof(window) !== 'undefined') { val.value = paths[0] + (val.value.charAt(0) === '/' ? val.value.slice(1) : val.value); } this.value = val; this.paths = paths; } }; tree.URL.prototype = { toCSS: function () { return "url(" + (this.attrs ? 'data:' + this.attrs.mime + this.attrs.charset + this.attrs.base64 + this.attrs.data : this.value.toCSS()) + ")"; }, eval: function (ctx) { return this.attrs ? this : new(tree.URL)(this.value.eval(ctx), this.paths); } }; })(require('less/tree')); (function (tree) { tree.Value = function (value) { this.value = value; this.is = 'value'; }; tree.Value.prototype = { eval: function (env) { if (this.value.length === 1) { return this.value[0].eval(env); } else { return new(tree.Value)(this.value.map(function (v) { return v.eval(env); })); } }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS(env); }).join(env.compress ? ',' : ', '); } }; })(require('less/tree')); (function (tree) { tree.Variable = function (name, index) { this.name = name, this.index = index }; tree.Variable.prototype = { eval: function (env) { var variable, v, name = this.name; if (name.indexOf('@@') == 0) { name = '@' + new(tree.Variable)(name.slice(1)).eval(env).value; } if (variable = tree.find(env.frames, function (frame) { if (v = frame.variable(name)) { return v.value.eval(env); } })) { return variable } else { throw { message: "variable " + name + " is undefined", index: this.index }; } } }; })(require('less/tree')); require('less/tree').find = function (obj, fun) { for (var i = 0, r; i < obj.length; i++) { if (r = fun.call(obj, obj[i])) { return r } } return null; }; require('less/tree').jsify = function (obj) { if (Array.isArray(obj.value) && (obj.value.length > 1)) { return '[' + obj.value.map(function (v) { return v.toCSS(false) }).join(', ') + ']'; } else { return obj.toCSS(false); } }; var name; function loadStyleSheet(sheet, callback, reload, remaining) { var sheetName = name.slice(0, name.lastIndexOf('/') + 1) + sheet.href; var input = readFile(sheetName); var parser = new less.Parser(); parser.parse(input, function (e, root) { if (e) { print("Error: " + e); quit(1); } callback(root, sheet, { local: false, lastModified: 0, remaining: remaining }); }); // callback({}, sheet, { local: true, remaining: remaining }); } function writeFile(filename, content) { var fstream = new java.io.FileWriter(filename); var out = new java.io.BufferedWriter(fstream); out.write(content); out.close(); } // Command line integration via Rhino (function (args) { name = args[0]; var output = args[1]; if (!name) { print('No files present in the fileset; Check your pattern match in build.xml'); quit(1); } path = name.split("/");path.pop();path=path.join("/") var input = readFile(name); if (!input) { print('lesscss: couldn\'t open file ' + name); quit(1); } var result; var parser = new less.Parser(); parser.parse(input, function (e, root) { if (e) { quit(1); } else { result = root.toCSS(); if (output) { writeFile(output, result); print("Written to " + output); } else { print(result); } quit(0); } }); print("done"); }(arguments)); less.js-1.4.2/dist/less-rhino-1.1.5.js000066400000000000000000002424331217256642200171420ustar00rootroot00000000000000// // Stub out `require` in rhino // function require(arg) { return less[arg.split('/')[1]]; }; // ecma-5.js // // -- kriskowal Kris Kowal Copyright (C) 2009-2010 MIT License // -- tlrobinson Tom Robinson // dantman Daniel Friesen // // Array // if (!Array.isArray) { Array.isArray = function(obj) { return Object.prototype.toString.call(obj) === "[object Array]" || (obj instanceof Array); }; } if (!Array.prototype.forEach) { Array.prototype.forEach = function(block, thisObject) { var len = this.length >>> 0; for (var i = 0; i < len; i++) { if (i in this) { block.call(thisObject, this[i], i, this); } } }; } if (!Array.prototype.map) { Array.prototype.map = function(fun /*, thisp*/) { var len = this.length >>> 0; var res = new Array(len); var thisp = arguments[1]; for (var i = 0; i < len; i++) { if (i in this) { res[i] = fun.call(thisp, this[i], i, this); } } return res; }; } if (!Array.prototype.filter) { Array.prototype.filter = function (block /*, thisp */) { var values = []; var thisp = arguments[1]; for (var i = 0; i < this.length; i++) { if (block.call(thisp, this[i])) { values.push(this[i]); } } return values; }; } if (!Array.prototype.reduce) { Array.prototype.reduce = function(fun /*, initial*/) { var len = this.length >>> 0; var i = 0; // no value to return if no initial value and an empty array if (len === 0 && arguments.length === 1) throw new TypeError(); if (arguments.length >= 2) { var rv = arguments[1]; } else { do { if (i in this) { rv = this[i++]; break; } // if array contains no values, no initial value to return if (++i >= len) throw new TypeError(); } while (true); } for (; i < len; i++) { if (i in this) { rv = fun.call(null, rv, this[i], i, this); } } return rv; }; } if (!Array.prototype.indexOf) { Array.prototype.indexOf = function (value /*, fromIndex */ ) { var length = this.length; var i = arguments[1] || 0; if (!length) return -1; if (i >= length) return -1; if (i < 0) i += length; for (; i < length; i++) { if (!Object.prototype.hasOwnProperty.call(this, i)) { continue } if (value === this[i]) return i; } return -1; }; } // // Object // if (!Object.keys) { Object.keys = function (object) { var keys = []; for (var name in object) { if (Object.prototype.hasOwnProperty.call(object, name)) { keys.push(name); } } return keys; }; } // // String // if (!String.prototype.trim) { String.prototype.trim = function () { return String(this).replace(/^\s\s*/, '').replace(/\s\s*$/, ''); }; } var less, tree; if (typeof environment === "object" && ({}).toString.call(environment) === "[object Environment]") { // Rhino // Details on how to detect Rhino: https://github.com/ringo/ringojs/issues/88 less = {}; tree = less.tree = {}; less.mode = 'rhino'; } else if (typeof(window) === 'undefined') { // Node.js less = exports, tree = require('./tree'); less.mode = 'rhino'; } else { // Browser if (typeof(window.less) === 'undefined') { window.less = {} } less = window.less, tree = window.less.tree = {}; less.mode = 'browser'; } // // less.js - parser // // A relatively straight-forward predictive parser. // There is no tokenization/lexing stage, the input is parsed // in one sweep. // // To make the parser fast enough to run in the browser, several // optimization had to be made: // // - Matching and slicing on a huge input is often cause of slowdowns. // The solution is to chunkify the input into smaller strings. // The chunks are stored in the `chunks` var, // `j` holds the current chunk index, and `current` holds // the index of the current chunk in relation to `input`. // This gives us an almost 4x speed-up. // // - In many cases, we don't need to match individual tokens; // for example, if a value doesn't hold any variables, operations // or dynamic references, the parser can effectively 'skip' it, // treating it as a literal. // An example would be '1px solid #000' - which evaluates to itself, // we don't need to know what the individual components are. // The drawback, of course is that you don't get the benefits of // syntax-checking on the CSS. This gives us a 50% speed-up in the parser, // and a smaller speed-up in the code-gen. // // // Token matching is done with the `$` function, which either takes // a terminal string or regexp, or a non-terminal function to call. // It also takes care of moving all the indices forwards. // // less.Parser = function Parser(env) { var input, // LeSS input string i, // current index in `input` j, // current chunk temp, // temporarily holds a chunk's state, for backtracking memo, // temporarily holds `i`, when backtracking furthest, // furthest index the parser has gone to chunks, // chunkified input current, // index of current chunk, in `input` parser; var that = this; // This function is called after all files // have been imported through `@import`. var finish = function () {}; var imports = this.imports = { paths: env && env.paths || [], // Search paths, when importing queue: [], // Files which haven't been imported yet files: {}, // Holds the imported parse trees mime: env && env.mime, // MIME type of .less files push: function (path, callback) { var that = this; this.queue.push(path); // // Import a file asynchronously // less.Parser.importer(path, this.paths, function (root) { that.queue.splice(that.queue.indexOf(path), 1); // Remove the path from the queue that.files[path] = root; // Store the root callback(root); if (that.queue.length === 0) { finish() } // Call `finish` if we're done importing }, env); } }; function save() { temp = chunks[j], memo = i, current = i } function restore() { chunks[j] = temp, i = memo, current = i } function sync() { if (i > current) { chunks[j] = chunks[j].slice(i - current); current = i; } } // // Parse from a token, regexp or string, and move forward if match // function $(tok) { var match, args, length, c, index, endIndex, k, mem; // // Non-terminal // if (tok instanceof Function) { return tok.call(parser.parsers); // // Terminal // // Either match a single character in the input, // or match a regexp in the current chunk (chunk[j]). // } else if (typeof(tok) === 'string') { match = input.charAt(i) === tok ? tok : null; length = 1; sync (); } else { sync (); if (match = tok.exec(chunks[j])) { length = match[0].length; } else { return null; } } // The match is confirmed, add the match length to `i`, // and consume any extra white-space characters (' ' || '\n') // which come after that. The reason for this is that LeSS's // grammar is mostly white-space insensitive. // if (match) { mem = i += length; endIndex = i + chunks[j].length - length; while (i < endIndex) { c = input.charCodeAt(i); if (! (c === 32 || c === 10 || c === 9)) { break } i++; } chunks[j] = chunks[j].slice(length + (i - mem)); current = i; if (chunks[j].length === 0 && j < chunks.length - 1) { j++ } if(typeof(match) === 'string') { return match; } else { return match.length === 1 ? match[0] : match; } } } // Same as $(), but don't change the state of the parser, // just return the match. function peek(tok) { if (typeof(tok) === 'string') { return input.charAt(i) === tok; } else { if (tok.test(chunks[j])) { return true; } else { return false; } } } this.env = env = env || {}; // The optimization level dictates the thoroughness of the parser, // the lower the number, the less nodes it will create in the tree. // This could matter for debugging, or if you want to access // the individual nodes in the tree. this.optimization = ('optimization' in this.env) ? this.env.optimization : 1; this.env.filename = this.env.filename || null; // // The Parser // return parser = { imports: imports, // // Parse an input string into an abstract syntax tree, // call `callback` when done. // parse: function (str, callback) { var root, start, end, zone, line, lines, buff = [], c, error = null; i = j = current = furthest = 0; chunks = []; input = str.replace(/\r\n/g, '\n'); // Split the input into chunks. chunks = (function (chunks) { var j = 0, skip = /[^"'`\{\}\/\(\)]+/g, comment = /\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g, level = 0, match, chunk = chunks[0], inParam, inString; for (var i = 0, c, cc; i < input.length; i++) { skip.lastIndex = i; if (match = skip.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); } } c = input.charAt(i); comment.lastIndex = i; if (!inString && !inParam && c === '/') { cc = input.charAt(i + 1); if (cc === '/' || cc === '*') { if (match = comment.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); c = input.charAt(i); } } } } if (c === '{' && !inString && !inParam) { level ++; chunk.push(c); } else if (c === '}' && !inString && !inParam) { level --; chunk.push(c); chunks[++j] = chunk = []; } else if (c === '(' && !inString && !inParam) { chunk.push(c); inParam = true; } else if (c === ')' && !inString && inParam) { chunk.push(c); inParam = false; } else { if (c === '"' || c === "'" || c === '`') { if (! inString) { inString = c; } else { inString = inString === c ? false : inString; } } chunk.push(c); } } if (level > 0) { throw { type: 'Syntax', message: "Missing closing `}`", filename: env.filename }; } return chunks.map(function (c) { return c.join('') });; })([[]]); // Start with the primary rule. // The whole syntax tree is held under a Ruleset node, // with the `root` property set to true, so no `{}` are // output. The callback is called when the input is parsed. root = new(tree.Ruleset)([], $(this.parsers.primary)); root.root = true; root.toCSS = (function (evaluate) { var line, lines, column; return function (options, variables) { var frames = []; options = options || {}; // // Allows setting variables with a hash, so: // // `{ color: new(tree.Color)('#f01') }` will become: // // new(tree.Rule)('@color', // new(tree.Value)([ // new(tree.Expression)([ // new(tree.Color)('#f01') // ]) // ]) // ) // if (typeof(variables) === 'object' && !Array.isArray(variables)) { variables = Object.keys(variables).map(function (k) { var value = variables[k]; if (! (value instanceof tree.Value)) { if (! (value instanceof tree.Expression)) { value = new(tree.Expression)([value]); } value = new(tree.Value)([value]); } return new(tree.Rule)('@' + k, value, false, 0); }); frames = [new(tree.Ruleset)(null, variables)]; } try { var css = evaluate.call(this, { frames: frames }) .toCSS([], { compress: options.compress || false }); } catch (e) { lines = input.split('\n'); line = getLine(e.index); for (var n = e.index, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } throw { type: e.type, message: e.message, filename: env.filename, index: e.index, line: typeof(line) === 'number' ? line + 1 : null, callLine: e.call && (getLine(e.call) + 1), callExtract: lines[getLine(e.call)], stack: e.stack, column: column, extract: [ lines[line - 1], lines[line], lines[line + 1] ] }; } if (options.compress) { return css.replace(/(\s)+/g, "$1"); } else { return css; } function getLine(index) { return index ? (input.slice(0, index).match(/\n/g) || "").length : null; } }; })(root.eval); // If `i` is smaller than the `input.length - 1`, // it means the parser wasn't able to parse the whole // string, so we've got a parsing error. // // We try to extract a \n delimited string, // showing the line where the parse error occured. // We split it up into two parts (the part which parsed, // and the part which didn't), so we can color them differently. if (i < input.length - 1) { i = furthest; lines = input.split('\n'); line = (input.slice(0, i).match(/\n/g) || "").length + 1; for (var n = i, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } error = { name: "ParseError", message: "Syntax Error on line " + line, index: i, filename: env.filename, line: line, column: column, extract: [ lines[line - 2], lines[line - 1], lines[line] ] }; } if (this.imports.queue.length > 0) { finish = function () { callback(error, root) }; } else { callback(error, root); } }, // // Here in, the parsing rules/functions // // The basic structure of the syntax tree generated is as follows: // // Ruleset -> Rule -> Value -> Expression -> Entity // // Here's some LESS code: // // .class { // color: #fff; // border: 1px solid #000; // width: @w + 4px; // > .child {...} // } // // And here's what the parse tree might look like: // // Ruleset (Selector '.class', [ // Rule ("color", Value ([Expression [Color #fff]])) // Rule ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]])) // Rule ("width", Value ([Expression [Operation "+" [Variable "@w"][Dimension 4px]]])) // Ruleset (Selector [Element '>', '.child'], [...]) // ]) // // In general, most rules will try to parse a token with the `$()` function, and if the return // value is truly, will return a new node, of the relevant type. Sometimes, we need to check // first, before parsing, that's when we use `peek()`. // parsers: { // // The `primary` rule is the *entry* and *exit* point of the parser. // The rules here can appear at any level of the parse tree. // // The recursive nature of the grammar is an interplay between the `block` // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule, // as represented by this simplified grammar: // // primary → (ruleset | rule)+ // ruleset → selector+ block // block → '{' primary '}' // // Only at one point is the primary rule not called from the // block rule: at the root level. // primary: function () { var node, root = []; while ((node = $(this.mixin.definition) || $(this.rule) || $(this.ruleset) || $(this.mixin.call) || $(this.comment) || $(this.directive)) || $(/^[\s\n]+/)) { node && root.push(node); } return root; }, // We create a Comment node for CSS comments `/* */`, // but keep the LeSS comments `//` silent, by just skipping // over them. comment: function () { var comment; if (input.charAt(i) !== '/') return; if (input.charAt(i + 1) === '/') { return new(tree.Comment)($(/^\/\/.*/), true); } else if (comment = $(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/)) { return new(tree.Comment)(comment); } }, // // Entities are tokens which can be found inside an Expression // entities: { // // A string, which supports escaping " and ' // // "milky way" 'he\'s the one!' // quoted: function () { var str, j = i, e; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '"' && input.charAt(j) !== "'") return; e && $('~'); if (str = $(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/)) { return new(tree.Quoted)(str[0], str[1] || str[2], e); } }, // // A catch-all word, such as: // // black border-collapse // keyword: function () { var k; if (k = $(/^[_A-Za-z-][_A-Za-z0-9-]*/)) { return new(tree.Keyword)(k) } }, // // A function call // // rgb(255, 0, 255) // // We also try to catch IE's `alpha()`, but let the `alpha` parser // deal with the details. // // The arguments are parsed with the `entities.arguments` parser. // call: function () { var name, args, index = i; if (! (name = /^([\w-]+|%)\(/.exec(chunks[j]))) return; name = name[1].toLowerCase(); if (name === 'url') { return null } else { i += name.length } if (name === 'alpha') { return $(this.alpha) } $('('); // Parse the '(' and consume whitespace. args = $(this.entities.arguments); if (! $(')')) return; if (name) { return new(tree.Call)(name, args, index) } }, arguments: function () { var args = [], arg; while (arg = $(this.expression)) { args.push(arg); if (! $(',')) { break } } return args; }, literal: function () { return $(this.entities.dimension) || $(this.entities.color) || $(this.entities.quoted); }, // // Parse url() tokens // // We use a specific rule for urls, because they don't really behave like // standard function calls. The difference is that the argument doesn't have // to be enclosed within a string, so it can't be parsed as an Expression. // url: function () { var value; if (input.charAt(i) !== 'u' || !$(/^url\(/)) return; value = $(this.entities.quoted) || $(this.entities.variable) || $(this.entities.dataURI) || $(/^[-\w%@$\/.&=:;#+?~]+/) || ""; if (! $(')')) throw new(Error)("missing closing ) for url()"); return new(tree.URL)((value.value || value.data || value instanceof tree.Variable) ? value : new(tree.Anonymous)(value), imports.paths); }, dataURI: function () { var obj; if ($(/^data:/)) { obj = {}; obj.mime = $(/^[^\/]+\/[^,;)]+/) || ''; obj.charset = $(/^;\s*charset=[^,;)]+/) || ''; obj.base64 = $(/^;\s*base64/) || ''; obj.data = $(/^,\s*[^)]+/); if (obj.data) { return obj } } }, // // A Variable entity, such as `@fink`, in // // width: @fink + 2px // // We use a different parser for variable definitions, // see `parsers.variable`. // variable: function () { var name, index = i; if (input.charAt(i) === '@' && (name = $(/^@@?[\w-]+/))) { return new(tree.Variable)(name, index); } }, // // A Hexadecimal color // // #4F3C2F // // `rgb` and `hsl` colors are parsed through the `entities.call` parser. // color: function () { var rgb; if (input.charAt(i) === '#' && (rgb = $(/^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})/))) { return new(tree.Color)(rgb[1]); } }, // // A Dimension, that is, a number and a unit // // 0.5em 95% // dimension: function () { var value, c = input.charCodeAt(i); if ((c > 57 || c < 45) || c === 47) return; if (value = $(/^(-?\d*\.?\d+)(px|%|em|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn)?/)) { return new(tree.Dimension)(value[1], value[2]); } }, // // JavaScript code to be evaluated // // `window.location.href` // javascript: function () { var str, j = i, e; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '`') { return } e && $('~'); if (str = $(/^`([^`]*)`/)) { return new(tree.JavaScript)(str[1], i, e); } } }, // // The variable part of a variable definition. Used in the `rule` parser // // @fink: // variable: function () { var name; if (input.charAt(i) === '@' && (name = $(/^(@[\w-]+)\s*:/))) { return name[1] } }, // // A font size/line-height shorthand // // small/12px // // We need to peek first, or we'll match on keywords and dimensions // shorthand: function () { var a, b; if (! peek(/^[@\w.%-]+\/[@\w.-]+/)) return; if ((a = $(this.entity)) && $('/') && (b = $(this.entity))) { return new(tree.Shorthand)(a, b); } }, // // Mixins // mixin: { // // A Mixin call, with an optional argument list // // #mixins > .square(#fff); // .rounded(4px, black); // .button; // // The `while` loop is there because mixins can be // namespaced, but we only support the child and descendant // selector for now. // call: function () { var elements = [], e, c, args, index = i, s = input.charAt(i); if (s !== '.' && s !== '#') { return } while (e = $(/^[#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/)) { elements.push(new(tree.Element)(c, e, i)); c = $('>'); } $('(') && (args = $(this.entities.arguments)) && $(')'); if (elements.length > 0 && ($(';') || peek('}'))) { return new(tree.mixin.Call)(elements, args, index); } }, // // A Mixin definition, with a list of parameters // // .rounded (@radius: 2px, @color) { // ... // } // // Until we have a finer grained state-machine, we have to // do a look-ahead, to make sure we don't have a mixin call. // See the `rule` function for more information. // // We start by matching `.rounded (`, and then proceed on to // the argument list, which has optional default values. // We store the parameters in `params`, with a `value` key, // if there is a value, such as in the case of `@radius`. // // Once we've got our params list, and a closing `)`, we parse // the `{...}` block. // definition: function () { var name, params = [], match, ruleset, param, value; if ((input.charAt(i) !== '.' && input.charAt(i) !== '#') || peek(/^[^{]*(;|})/)) return; if (match = $(/^([#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+)\s*\(/)) { name = match[1]; while (param = $(this.entities.variable) || $(this.entities.literal) || $(this.entities.keyword)) { // Variable if (param instanceof tree.Variable) { if ($(':')) { if (value = $(this.expression)) { params.push({ name: param.name, value: value }); } else { throw new(Error)("Expected value"); } } else { params.push({ name: param.name }); } } else { params.push({ value: param }); } if (! $(',')) { break } } if (! $(')')) throw new(Error)("Expected )"); ruleset = $(this.block); if (ruleset) { return new(tree.mixin.Definition)(name, params, ruleset); } } } }, // // Entities are the smallest recognized token, // and can be found inside a rule's value. // entity: function () { return $(this.entities.literal) || $(this.entities.variable) || $(this.entities.url) || $(this.entities.call) || $(this.entities.keyword) || $(this.entities.javascript) || $(this.comment); }, // // A Rule terminator. Note that we use `peek()` to check for '}', // because the `block` rule will be expecting it, but we still need to make sure // it's there, if ';' was ommitted. // end: function () { return $(';') || peek('}'); }, // // IE's alpha function // // alpha(opacity=88) // alpha: function () { var value; if (! $(/^\(opacity=/i)) return; if (value = $(/^\d+/) || $(this.entities.variable)) { if (! $(')')) throw new(Error)("missing closing ) for alpha()"); return new(tree.Alpha)(value); } }, // // A Selector Element // // div // + h1 // #socks // input[type="text"] // // Elements are the building blocks for Selectors, // they are made out of a `Combinator` (see combinator rule), // and an element name, such as a tag a class, or `*`. // element: function () { var e, t, c; c = $(this.combinator); e = $(/^(?:\d+\.\d+|\d+)%/) || $(/^(?:[.#]?|:*)(?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/) || $('*') || $(this.attribute) || $(/^\([^)@]+\)/); if (e) { return new(tree.Element)(c, e, i) } if (c.value && c.value.charAt(0) === '&') { return new(tree.Element)(c, null, i); } }, // // Combinators combine elements together, in a Selector. // // Because our parser isn't white-space sensitive, special care // has to be taken, when parsing the descendant combinator, ` `, // as it's an empty space. We have to check the previous character // in the input, to see if it's a ` ` character. More info on how // we deal with this in *combinator.js*. // combinator: function () { var match, c = input.charAt(i); if (c === '>' || c === '+' || c === '~') { i++; while (input.charAt(i) === ' ') { i++ } return new(tree.Combinator)(c); } else if (c === '&') { match = '&'; i++; if(input.charAt(i) === ' ') { match = '& '; } while (input.charAt(i) === ' ') { i++ } return new(tree.Combinator)(match); } else if (c === ':' && input.charAt(i + 1) === ':') { i += 2; while (input.charAt(i) === ' ') { i++ } return new(tree.Combinator)('::'); } else if (input.charAt(i - 1) === ' ') { return new(tree.Combinator)(" "); } else { return new(tree.Combinator)(null); } }, // // A CSS Selector // // .class > div + h1 // li a:hover // // Selectors are made out of one or more Elements, see above. // selector: function () { var sel, e, elements = [], c, match; while (e = $(this.element)) { c = input.charAt(i); elements.push(e) if (c === '{' || c === '}' || c === ';' || c === ',') { break } } if (elements.length > 0) { return new(tree.Selector)(elements) } }, tag: function () { return $(/^[a-zA-Z][a-zA-Z-]*[0-9]?/) || $('*'); }, attribute: function () { var attr = '', key, val, op; if (! $('[')) return; if (key = $(/^[a-zA-Z-]+/) || $(this.entities.quoted)) { if ((op = $(/^[|~*$^]?=/)) && (val = $(this.entities.quoted) || $(/^[\w-]+/))) { attr = [key, op, val.toCSS ? val.toCSS() : val].join(''); } else { attr = key } } if (! $(']')) return; if (attr) { return "[" + attr + "]" } }, // // The `block` rule is used by `ruleset` and `mixin.definition`. // It's a wrapper around the `primary` rule, with added `{}`. // block: function () { var content; if ($('{') && (content = $(this.primary)) && $('}')) { return content; } }, // // div, .class, body > p {...} // ruleset: function () { var selectors = [], s, rules, match; save(); while (s = $(this.selector)) { selectors.push(s); $(this.comment); if (! $(',')) { break } $(this.comment); } if (selectors.length > 0 && (rules = $(this.block))) { return new(tree.Ruleset)(selectors, rules); } else { // Backtrack furthest = i; restore(); } }, rule: function () { var name, value, c = input.charAt(i), important, match; save(); if (c === '.' || c === '#' || c === '&') { return } if (name = $(this.variable) || $(this.property)) { if ((name.charAt(0) != '@') && (match = /^([^@+\/'"*`(;{}-]*);/.exec(chunks[j]))) { i += match[0].length - 1; value = new(tree.Anonymous)(match[1]); } else if (name === "font") { value = $(this.font); } else { value = $(this.value); } important = $(this.important); if (value && $(this.end)) { return new(tree.Rule)(name, value, important, memo); } else { furthest = i; restore(); } } }, // // An @import directive // // @import "lib"; // // Depending on our environemnt, importing is done differently: // In the browser, it's an XHR request, in Node, it would be a // file-system operation. The function used for importing is // stored in `import`, which we pass to the Import constructor. // "import": function () { var path; if ($(/^@import\s+/) && (path = $(this.entities.quoted) || $(this.entities.url)) && $(';')) { return new(tree.Import)(path, imports); } }, // // A CSS Directive // // @charset "utf-8"; // directive: function () { var name, value, rules, types; if (input.charAt(i) !== '@') return; if (value = $(this['import'])) { return value; } else if (name = $(/^@media|@page/) || $(/^@(?:-webkit-|-moz-)?keyframes/)) { types = ($(/^[^{]+/) || '').trim(); if (rules = $(this.block)) { return new(tree.Directive)(name + " " + types, rules); } } else if (name = $(/^@[-a-z]+/)) { if (name === '@font-face') { if (rules = $(this.block)) { return new(tree.Directive)(name, rules); } } else if ((value = $(this.entity)) && $(';')) { return new(tree.Directive)(name, value); } } }, font: function () { var value = [], expression = [], weight, shorthand, font, e; while (e = $(this.shorthand) || $(this.entity)) { expression.push(e); } value.push(new(tree.Expression)(expression)); if ($(',')) { while (e = $(this.expression)) { value.push(e); if (! $(',')) { break } } } return new(tree.Value)(value); }, // // A Value is a comma-delimited list of Expressions // // font-family: Baskerville, Georgia, serif; // // In a Rule, a Value represents everything after the `:`, // and before the `;`. // value: function () { var e, expressions = [], important; while (e = $(this.expression)) { expressions.push(e); if (! $(',')) { break } } if (expressions.length > 0) { return new(tree.Value)(expressions); } }, important: function () { if (input.charAt(i) === '!') { return $(/^! *important/); } }, sub: function () { var e; if ($('(') && (e = $(this.expression)) && $(')')) { return e; } }, multiplication: function () { var m, a, op, operation; if (m = $(this.operand)) { while ((op = ($('/') || $('*'))) && (a = $(this.operand))) { operation = new(tree.Operation)(op, [operation || m, a]); } return operation || m; } }, addition: function () { var m, a, op, operation; if (m = $(this.multiplication)) { while ((op = $(/^[-+]\s+/) || (input.charAt(i - 1) != ' ' && ($('+') || $('-')))) && (a = $(this.multiplication))) { operation = new(tree.Operation)(op, [operation || m, a]); } return operation || m; } }, // // An operand is anything that can be part of an operation, // such as a Color, or a Variable // operand: function () { var negate, p = input.charAt(i + 1); if (input.charAt(i) === '-' && (p === '@' || p === '(')) { negate = $('-') } var o = $(this.sub) || $(this.entities.dimension) || $(this.entities.color) || $(this.entities.variable) || $(this.entities.call); return negate ? new(tree.Operation)('*', [new(tree.Dimension)(-1), o]) : o; }, // // Expressions either represent mathematical operations, // or white-space delimited Entities. // // 1px solid black // @var * 2 // expression: function () { var e, delim, entities = [], d; while (e = $(this.addition) || $(this.entity)) { entities.push(e); } if (entities.length > 0) { return new(tree.Expression)(entities); } }, property: function () { var name; if (name = $(/^(\*?-?[-a-z_0-9]+)\s*:/)) { return name[1]; } } } }; }; if (less.mode === 'browser' || less.mode === 'rhino') { // // Used by `@import` directives // less.Parser.importer = function (path, paths, callback, env) { if (path.charAt(0) !== '/' && paths.length > 0) { path = paths[0] + path; } // We pass `true` as 3rd argument, to force the reload of the import. // This is so we can get the syntax tree as opposed to just the CSS output, // as we need this to evaluate the current stylesheet. loadStyleSheet({ href: path, title: path, type: env.mime }, callback, true); }; } (function (tree) { tree.functions = { rgb: function (r, g, b) { return this.rgba(r, g, b, 1.0); }, rgba: function (r, g, b, a) { var rgb = [r, g, b].map(function (c) { return number(c) }), a = number(a); return new(tree.Color)(rgb, a); }, hsl: function (h, s, l) { return this.hsla(h, s, l, 1.0); }, hsla: function (h, s, l, a) { h = (number(h) % 360) / 360; s = number(s); l = number(l); a = number(a); var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s; var m1 = l * 2 - m2; return this.rgba(hue(h + 1/3) * 255, hue(h) * 255, hue(h - 1/3) * 255, a); function hue(h) { h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h); if (h * 6 < 1) return m1 + (m2 - m1) * h * 6; else if (h * 2 < 1) return m2; else if (h * 3 < 2) return m1 + (m2 - m1) * (2/3 - h) * 6; else return m1; } }, hue: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().h)); }, saturation: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().s * 100), '%'); }, lightness: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().l * 100), '%'); }, alpha: function (color) { return new(tree.Dimension)(color.toHSL().a); }, saturate: function (color, amount) { var hsl = color.toHSL(); hsl.s += amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, desaturate: function (color, amount) { var hsl = color.toHSL(); hsl.s -= amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, lighten: function (color, amount) { var hsl = color.toHSL(); hsl.l += amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, darken: function (color, amount) { var hsl = color.toHSL(); hsl.l -= amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, fadein: function (color, amount) { var hsl = color.toHSL(); hsl.a += amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, fadeout: function (color, amount) { var hsl = color.toHSL(); hsl.a -= amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, fade: function (color, amount) { var hsl = color.toHSL(); hsl.a = amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, spin: function (color, amount) { var hsl = color.toHSL(); var hue = (hsl.h + amount.value) % 360; hsl.h = hue < 0 ? 360 + hue : hue; return hsla(hsl); }, // // Copyright (c) 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein // http://sass-lang.com // mix: function (color1, color2, weight) { var p = weight.value / 100.0; var w = p * 2 - 1; var a = color1.toHSL().a - color2.toHSL().a; var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0; var w2 = 1 - w1; var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2, color1.rgb[1] * w1 + color2.rgb[1] * w2, color1.rgb[2] * w1 + color2.rgb[2] * w2]; var alpha = color1.alpha * p + color2.alpha * (1 - p); return new(tree.Color)(rgb, alpha); }, greyscale: function (color) { return this.desaturate(color, new(tree.Dimension)(100)); }, e: function (str) { return new(tree.Anonymous)(str instanceof tree.JavaScript ? str.evaluated : str); }, escape: function (str) { return new(tree.Anonymous)(encodeURI(str.value).replace(/=/g, "%3D").replace(/:/g, "%3A").replace(/#/g, "%23").replace(/;/g, "%3B").replace(/\(/g, "%28").replace(/\)/g, "%29")); }, '%': function (quoted /* arg, arg, ...*/) { var args = Array.prototype.slice.call(arguments, 1), str = quoted.value; for (var i = 0; i < args.length; i++) { str = str.replace(/%[sda]/i, function(token) { var value = token.match(/s/i) ? args[i].value : args[i].toCSS(); return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value; }); } str = str.replace(/%%/g, '%'); return new(tree.Quoted)('"' + str + '"', str); }, round: function (n) { if (n instanceof tree.Dimension) { return new(tree.Dimension)(Math.round(number(n)), n.unit); } else if (typeof(n) === 'number') { return Math.round(n); } else { throw { error: "RuntimeError", message: "math functions take numbers as parameters" }; } }, argb: function (color) { return new(tree.Anonymous)(color.toARGB()); } }; function hsla(hsla) { return tree.functions.hsla(hsla.h, hsla.s, hsla.l, hsla.a); } function number(n) { if (n instanceof tree.Dimension) { return parseFloat(n.unit == '%' ? n.value / 100 : n.value); } else if (typeof(n) === 'number') { return n; } else { throw { error: "RuntimeError", message: "color functions take numbers as parameters" }; } } function clamp(val) { return Math.min(1, Math.max(0, val)); } })(require('./tree')); (function (tree) { tree.Alpha = function (val) { this.value = val; }; tree.Alpha.prototype = { toCSS: function () { return "alpha(opacity=" + (this.value.toCSS ? this.value.toCSS() : this.value) + ")"; }, eval: function (env) { if (this.value.eval) { this.value = this.value.eval(env) } return this; } }; })(require('../tree')); (function (tree) { tree.Anonymous = function (string) { this.value = string.value || string; }; tree.Anonymous.prototype = { toCSS: function () { return this.value; }, eval: function () { return this } }; })(require('../tree')); (function (tree) { // // A function call node. // tree.Call = function (name, args, index) { this.name = name; this.args = args; this.index = index; }; tree.Call.prototype = { // // When evaluating a function call, // we either find the function in `tree.functions` [1], // in which case we call it, passing the evaluated arguments, // or we simply print it out as it appeared originally [2]. // // The *functions.js* file contains the built-in functions. // // The reason why we evaluate the arguments, is in the case where // we try to pass a variable to a function, like: `saturate(@color)`. // The function should receive the value, not the variable. // eval: function (env) { var args = this.args.map(function (a) { return a.eval(env) }); if (this.name in tree.functions) { // 1. try { return tree.functions[this.name].apply(tree.functions, args); } catch (e) { throw { message: "error evaluating function `" + this.name + "`", index: this.index }; } } else { // 2. return new(tree.Anonymous)(this.name + "(" + args.map(function (a) { return a.toCSS() }).join(', ') + ")"); } }, toCSS: function (env) { return this.eval(env).toCSS(); } }; })(require('../tree')); (function (tree) { // // RGB Colors - #ff0014, #eee // tree.Color = function (rgb, a) { // // The end goal here, is to parse the arguments // into an integer triplet, such as `128, 255, 0` // // This facilitates operations and conversions. // if (Array.isArray(rgb)) { this.rgb = rgb; } else if (rgb.length == 6) { this.rgb = rgb.match(/.{2}/g).map(function (c) { return parseInt(c, 16); }); } else { this.rgb = rgb.split('').map(function (c) { return parseInt(c + c, 16); }); } this.alpha = typeof(a) === 'number' ? a : 1; }; tree.Color.prototype = { eval: function () { return this }, // // If we have some transparency, the only way to represent it // is via `rgba`. Otherwise, we use the hex representation, // which has better compatibility with older browsers. // Values are capped between `0` and `255`, rounded and zero-padded. // toCSS: function () { if (this.alpha < 1.0) { return "rgba(" + this.rgb.map(function (c) { return Math.round(c); }).concat(this.alpha).join(', ') + ")"; } else { return '#' + this.rgb.map(function (i) { i = Math.round(i); i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16); return i.length === 1 ? '0' + i : i; }).join(''); } }, // // Operations have to be done per-channel, if not, // channels will spill onto each other. Once we have // our result, in the form of an integer triplet, // we create a new Color node to hold the result. // operate: function (op, other) { var result = []; if (! (other instanceof tree.Color)) { other = other.toColor(); } for (var c = 0; c < 3; c++) { result[c] = tree.operate(op, this.rgb[c], other.rgb[c]); } return new(tree.Color)(result, this.alpha + other.alpha); }, toHSL: function () { var r = this.rgb[0] / 255, g = this.rgb[1] / 255, b = this.rgb[2] / 255, a = this.alpha; var max = Math.max(r, g, b), min = Math.min(r, g, b); var h, s, l = (max + min) / 2, d = max - min; if (max === min) { h = s = 0; } else { s = l > 0.5 ? d / (2 - max - min) : d / (max + min); switch (max) { case r: h = (g - b) / d + (g < b ? 6 : 0); break; case g: h = (b - r) / d + 2; break; case b: h = (r - g) / d + 4; break; } h /= 6; } return { h: h * 360, s: s, l: l, a: a }; }, toARGB: function () { var argb = [Math.round(this.alpha * 255)].concat(this.rgb); return '#' + argb.map(function (i) { i = Math.round(i); i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16); return i.length === 1 ? '0' + i : i; }).join(''); } }; })(require('../tree')); (function (tree) { tree.Comment = function (value, silent) { this.value = value; this.silent = !!silent; }; tree.Comment.prototype = { toCSS: function (env) { return env.compress ? '' : this.value; }, eval: function () { return this } }; })(require('../tree')); (function (tree) { // // A number with a unit // tree.Dimension = function (value, unit) { this.value = parseFloat(value); this.unit = unit || null; }; tree.Dimension.prototype = { eval: function () { return this }, toColor: function () { return new(tree.Color)([this.value, this.value, this.value]); }, toCSS: function () { var css = this.value + this.unit; return css; }, // In an operation between two Dimensions, // we default to the first Dimension's unit, // so `1px + 2em` will yield `3px`. // In the future, we could implement some unit // conversions such that `100cm + 10mm` would yield // `101cm`. operate: function (op, other) { return new(tree.Dimension) (tree.operate(op, this.value, other.value), this.unit || other.unit); } }; })(require('../tree')); (function (tree) { tree.Directive = function (name, value) { this.name = name; if (Array.isArray(value)) { this.ruleset = new(tree.Ruleset)([], value); } else { this.value = value; } }; tree.Directive.prototype = { toCSS: function (ctx, env) { if (this.ruleset) { this.ruleset.root = true; return this.name + (env.compress ? '{' : ' {\n ') + this.ruleset.toCSS(ctx, env).trim().replace(/\n/g, '\n ') + (env.compress ? '}': '\n}\n'); } else { return this.name + ' ' + this.value.toCSS() + ';\n'; } }, eval: function (env) { env.frames.unshift(this); this.ruleset = this.ruleset && this.ruleset.eval(env); env.frames.shift(); return this; }, variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) }, find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) }, rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) } }; })(require('../tree')); (function (tree) { tree.Element = function (combinator, value, index) { this.combinator = combinator instanceof tree.Combinator ? combinator : new(tree.Combinator)(combinator); this.value = value ? value.trim() : ""; this.index = index; }; tree.Element.prototype.toCSS = function (env) { return this.combinator.toCSS(env || {}) + this.value; }; tree.Combinator = function (value) { if (value === ' ') { this.value = ' '; } else if (value === '& ') { this.value = '& '; } else { this.value = value ? value.trim() : ""; } }; tree.Combinator.prototype.toCSS = function (env) { return { '' : '', ' ' : ' ', '&' : '', '& ' : ' ', ':' : ' :', '::': '::', '+' : env.compress ? '+' : ' + ', '~' : env.compress ? '~' : ' ~ ', '>' : env.compress ? '>' : ' > ' }[this.value]; }; })(require('../tree')); (function (tree) { tree.Expression = function (value) { this.value = value }; tree.Expression.prototype = { eval: function (env) { if (this.value.length > 1) { return new(tree.Expression)(this.value.map(function (e) { return e.eval(env); })); } else if (this.value.length === 1) { return this.value[0].eval(env); } else { return this; } }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS(env); }).join(' '); } }; })(require('../tree')); (function (tree) { // // CSS @import node // // The general strategy here is that we don't want to wait // for the parsing to be completed, before we start importing // the file. That's because in the context of a browser, // most of the time will be spent waiting for the server to respond. // // On creation, we push the import path to our import queue, though // `import,push`, we also pass it a callback, which it'll call once // the file has been fetched, and parsed. // tree.Import = function (path, imports) { var that = this; this._path = path; // The '.less' extension is optional if (path instanceof tree.Quoted) { this.path = /\.(le?|c)ss(\?.*)?$/.test(path.value) ? path.value : path.value + '.less'; } else { this.path = path.value.value || path.value; } this.css = /css(\?.*)?$/.test(this.path); // Only pre-compile .less files if (! this.css) { imports.push(this.path, function (root) { if (! root) { throw new(Error)("Error parsing " + that.path); } that.root = root; }); } }; // // The actual import node doesn't return anything, when converted to CSS. // The reason is that it's used at the evaluation stage, so that the rules // it imports can be treated like any other rules. // // In `eval`, we make sure all Import nodes get evaluated, recursively, so // we end up with a flat structure, which can easily be imported in the parent // ruleset. // tree.Import.prototype = { toCSS: function () { if (this.css) { return "@import " + this._path.toCSS() + ';\n'; } else { return ""; } }, eval: function (env) { var ruleset; if (this.css) { return this; } else { ruleset = new(tree.Ruleset)(null, this.root.rules.slice(0)); for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.Import) { Array.prototype .splice .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env))); } } return ruleset.rules; } } }; })(require('../tree')); (function (tree) { tree.JavaScript = function (string, index, escaped) { this.escaped = escaped; this.expression = string; this.index = index; }; tree.JavaScript.prototype = { eval: function (env) { var result, that = this, context = {}; var expression = this.expression.replace(/@\{([\w-]+)\}/g, function (_, name) { return tree.jsify(new(tree.Variable)('@' + name, that.index).eval(env)); }); try { expression = new(Function)('return (' + expression + ')'); } catch (e) { throw { message: "JavaScript evaluation error: `" + expression + "`" , index: this.index }; } for (var k in env.frames[0].variables()) { context[k.slice(1)] = { value: env.frames[0].variables()[k].value, toJS: function () { return this.value.eval(env).toCSS(); } }; } try { result = expression.call(context); } catch (e) { throw { message: "JavaScript evaluation error: '" + e.name + ': ' + e.message + "'" , index: this.index }; } if (typeof(result) === 'string') { return new(tree.Quoted)('"' + result + '"', result, this.escaped, this.index); } else if (Array.isArray(result)) { return new(tree.Anonymous)(result.join(', ')); } else { return new(tree.Anonymous)(result); } } }; })(require('../tree')); (function (tree) { tree.Keyword = function (value) { this.value = value }; tree.Keyword.prototype = { eval: function () { return this }, toCSS: function () { return this.value } }; })(require('../tree')); (function (tree) { tree.mixin = {}; tree.mixin.Call = function (elements, args, index) { this.selector = new(tree.Selector)(elements); this.arguments = args; this.index = index; }; tree.mixin.Call.prototype = { eval: function (env) { var mixins, args, rules = [], match = false; for (var i = 0; i < env.frames.length; i++) { if ((mixins = env.frames[i].find(this.selector)).length > 0) { args = this.arguments && this.arguments.map(function (a) { return a.eval(env) }); for (var m = 0; m < mixins.length; m++) { if (mixins[m].match(args, env)) { try { Array.prototype.push.apply( rules, mixins[m].eval(env, this.arguments).rules); match = true; } catch (e) { throw { message: e.message, index: e.index, stack: e.stack, call: this.index }; } } } if (match) { return rules; } else { throw { message: 'No matching definition was found for `' + this.selector.toCSS().trim() + '(' + this.arguments.map(function (a) { return a.toCSS(); }).join(', ') + ")`", index: this.index }; } } } throw { message: this.selector.toCSS().trim() + " is undefined", index: this.index }; } }; tree.mixin.Definition = function (name, params, rules) { this.name = name; this.selectors = [new(tree.Selector)([new(tree.Element)(null, name)])]; this.params = params; this.arity = params.length; this.rules = rules; this._lookups = {}; this.required = params.reduce(function (count, p) { if (!p.name || (p.name && !p.value)) { return count + 1 } else { return count } }, 0); this.parent = tree.Ruleset.prototype; this.frames = []; }; tree.mixin.Definition.prototype = { toCSS: function () { return "" }, variable: function (name) { return this.parent.variable.call(this, name) }, variables: function () { return this.parent.variables.call(this) }, find: function () { return this.parent.find.apply(this, arguments) }, rulesets: function () { return this.parent.rulesets.apply(this) }, eval: function (env, args) { var frame = new(tree.Ruleset)(null, []), context, _arguments = []; for (var i = 0, val; i < this.params.length; i++) { if (this.params[i].name) { if (val = (args && args[i]) || this.params[i].value) { frame.rules.unshift(new(tree.Rule)(this.params[i].name, val.eval(env))); } else { throw { message: "wrong number of arguments for " + this.name + ' (' + args.length + ' for ' + this.arity + ')' }; } } } for (var i = 0; i < Math.max(this.params.length, args && args.length); i++) { _arguments.push(args[i] || this.params[i].value); } frame.rules.unshift(new(tree.Rule)('@arguments', new(tree.Expression)(_arguments).eval(env))); return new(tree.Ruleset)(null, this.rules.slice(0)).eval({ frames: [this, frame].concat(this.frames, env.frames) }); }, match: function (args, env) { var argsLength = (args && args.length) || 0, len; if (argsLength < this.required) { return false } if ((this.required > 0) && (argsLength > this.params.length)) { return false } len = Math.min(argsLength, this.arity); for (var i = 0; i < len; i++) { if (!this.params[i].name) { if (args[i].eval(env).toCSS() != this.params[i].value.eval(env).toCSS()) { return false; } } } return true; } }; })(require('../tree')); (function (tree) { tree.Operation = function (op, operands) { this.op = op.trim(); this.operands = operands; }; tree.Operation.prototype.eval = function (env) { var a = this.operands[0].eval(env), b = this.operands[1].eval(env), temp; if (a instanceof tree.Dimension && b instanceof tree.Color) { if (this.op === '*' || this.op === '+') { temp = b, b = a, a = temp; } else { throw { name: "OperationError", message: "Can't substract or divide a color from a number" }; } } return a.operate(this.op, b); }; tree.operate = function (op, a, b) { switch (op) { case '+': return a + b; case '-': return a - b; case '*': return a * b; case '/': return a / b; } }; })(require('../tree')); (function (tree) { tree.Quoted = function (str, content, escaped, i) { this.escaped = escaped; this.value = content || ''; this.quote = str.charAt(0); this.index = i; }; tree.Quoted.prototype = { toCSS: function () { if (this.escaped) { return this.value; } else { return this.quote + this.value + this.quote; } }, eval: function (env) { var that = this; var value = this.value.replace(/`([^`]+)`/g, function (_, exp) { return new(tree.JavaScript)(exp, that.index, true).eval(env).value; }).replace(/@\{([\w-]+)\}/g, function (_, name) { var v = new(tree.Variable)('@' + name, that.index).eval(env); return v.value || v.toCSS(); }); return new(tree.Quoted)(this.quote + value + this.quote, value, this.escaped, this.index); } }; })(require('../tree')); (function (tree) { tree.Rule = function (name, value, important, index) { this.name = name; this.value = (value instanceof tree.Value) ? value : new(tree.Value)([value]); this.important = important ? ' ' + important.trim() : ''; this.index = index; if (name.charAt(0) === '@') { this.variable = true; } else { this.variable = false } }; tree.Rule.prototype.toCSS = function (env) { if (this.variable) { return "" } else { return this.name + (env.compress ? ':' : ': ') + this.value.toCSS(env) + this.important + ";"; } }; tree.Rule.prototype.eval = function (context) { return new(tree.Rule)(this.name, this.value.eval(context), this.important, this.index); }; tree.Shorthand = function (a, b) { this.a = a; this.b = b; }; tree.Shorthand.prototype = { toCSS: function (env) { return this.a.toCSS(env) + "/" + this.b.toCSS(env); }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.Ruleset = function (selectors, rules) { this.selectors = selectors; this.rules = rules; this._lookups = {}; }; tree.Ruleset.prototype = { eval: function (env) { var ruleset = new(tree.Ruleset)(this.selectors, this.rules.slice(0)); ruleset.root = this.root; // push the current ruleset to the frames stack env.frames.unshift(ruleset); // Evaluate imports if (ruleset.root) { for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.Import) { Array.prototype.splice .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env))); } } } // Store the frames around mixin definitions, // so they can be evaluated like closures when the time comes. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Definition) { ruleset.rules[i].frames = env.frames.slice(0); } } // Evaluate mixin calls. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Call) { Array.prototype.splice .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env))); } } // Evaluate everything else for (var i = 0, rule; i < ruleset.rules.length; i++) { rule = ruleset.rules[i]; if (! (rule instanceof tree.mixin.Definition)) { ruleset.rules[i] = rule.eval ? rule.eval(env) : rule; } } // Pop the stack env.frames.shift(); return ruleset; }, match: function (args) { return !args || args.length === 0; }, variables: function () { if (this._variables) { return this._variables } else { return this._variables = this.rules.reduce(function (hash, r) { if (r instanceof tree.Rule && r.variable === true) { hash[r.name] = r; } return hash; }, {}); } }, variable: function (name) { return this.variables()[name]; }, rulesets: function () { if (this._rulesets) { return this._rulesets } else { return this._rulesets = this.rules.filter(function (r) { return (r instanceof tree.Ruleset) || (r instanceof tree.mixin.Definition); }); } }, find: function (selector, self) { self = self || this; var rules = [], rule, match, key = selector.toCSS(); if (key in this._lookups) { return this._lookups[key] } this.rulesets().forEach(function (rule) { if (rule !== self) { for (var j = 0; j < rule.selectors.length; j++) { if (match = selector.match(rule.selectors[j])) { if (selector.elements.length > rule.selectors[j].elements.length) { Array.prototype.push.apply(rules, rule.find( new(tree.Selector)(selector.elements.slice(1)), self)); } else { rules.push(rule); } break; } } } }); return this._lookups[key] = rules; }, // // Entry point for code generation // // `context` holds an array of arrays. // toCSS: function (context, env) { var css = [], // The CSS output rules = [], // node.Rule instances rulesets = [], // node.Ruleset instances paths = [], // Current selectors selector, // The fully rendered selector rule; if (! this.root) { if (context.length === 0) { paths = this.selectors.map(function (s) { return [s] }); } else { this.joinSelectors( paths, context, this.selectors ); } } // Compile rules and rulesets for (var i = 0; i < this.rules.length; i++) { rule = this.rules[i]; if (rule.rules || (rule instanceof tree.Directive)) { rulesets.push(rule.toCSS(paths, env)); } else if (rule instanceof tree.Comment) { if (!rule.silent) { if (this.root) { rulesets.push(rule.toCSS(env)); } else { rules.push(rule.toCSS(env)); } } } else { if (rule.toCSS && !rule.variable) { rules.push(rule.toCSS(env)); } else if (rule.value && !rule.variable) { rules.push(rule.value.toString()); } } } rulesets = rulesets.join(''); // If this is the root node, we don't render // a selector, or {}. // Otherwise, only output if this ruleset has rules. if (this.root) { css.push(rules.join(env.compress ? '' : '\n')); } else { if (rules.length > 0) { selector = paths.map(function (p) { return p.map(function (s) { return s.toCSS(env); }).join('').trim(); }).join(env.compress ? ',' : (paths.length > 3 ? ',\n' : ', ')); css.push(selector, (env.compress ? '{' : ' {\n ') + rules.join(env.compress ? '' : '\n ') + (env.compress ? '}' : '\n}\n')); } } css.push(rulesets); return css.join('') + (env.compress ? '\n' : ''); }, joinSelectors: function (paths, context, selectors) { for (var s = 0; s < selectors.length; s++) { this.joinSelector(paths, context, selectors[s]); } }, joinSelector: function (paths, context, selector) { var before = [], after = [], beforeElements = [], afterElements = [], hasParentSelector = false, el; for (var i = 0; i < selector.elements.length; i++) { el = selector.elements[i]; if (el.combinator.value.charAt(0) === '&') { hasParentSelector = true; } if (hasParentSelector) afterElements.push(el); else beforeElements.push(el); } if (! hasParentSelector) { afterElements = beforeElements; beforeElements = []; } if (beforeElements.length > 0) { before.push(new(tree.Selector)(beforeElements)); } if (afterElements.length > 0) { after.push(new(tree.Selector)(afterElements)); } for (var c = 0; c < context.length; c++) { paths.push(before.concat(context[c]).concat(after)); } } }; })(require('../tree')); (function (tree) { tree.Selector = function (elements) { this.elements = elements; if (this.elements[0].combinator.value === "") { this.elements[0].combinator.value = ' '; } }; tree.Selector.prototype.match = function (other) { var len = this.elements.length, olen = other.elements.length, max = Math.min(len, olen); if (len < olen) { return false; } else { for (var i = 0; i < max; i++) { if (this.elements[i].value !== other.elements[i].value) { return false; } } } return true; }; tree.Selector.prototype.toCSS = function (env) { if (this._css) { return this._css } return this._css = this.elements.map(function (e) { if (typeof(e) === 'string') { return ' ' + e.trim(); } else { return e.toCSS(env); } }).join(''); }; })(require('../tree')); (function (tree) { tree.URL = function (val, paths) { if (val.data) { this.attrs = val; } else { // Add the base path if the URL is relative and we are in the browser if (!/^(?:https?:\/\/|file:\/\/|data:)?/.test(val.value) && paths.length > 0 && typeof(window) !== 'undefined') { val.value = paths[0] + (val.value.charAt(0) === '/' ? val.value.slice(1) : val.value); } this.value = val; this.paths = paths; } }; tree.URL.prototype = { toCSS: function () { return "url(" + (this.attrs ? 'data:' + this.attrs.mime + this.attrs.charset + this.attrs.base64 + this.attrs.data : this.value.toCSS()) + ")"; }, eval: function (ctx) { return this.attrs ? this : new(tree.URL)(this.value.eval(ctx), this.paths); } }; })(require('../tree')); (function (tree) { tree.Value = function (value) { this.value = value; this.is = 'value'; }; tree.Value.prototype = { eval: function (env) { if (this.value.length === 1) { return this.value[0].eval(env); } else { return new(tree.Value)(this.value.map(function (v) { return v.eval(env); })); } }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS(env); }).join(env.compress ? ',' : ', '); } }; })(require('../tree')); (function (tree) { tree.Variable = function (name, index) { this.name = name, this.index = index }; tree.Variable.prototype = { eval: function (env) { var variable, v, name = this.name; if (name.indexOf('@@') == 0) { name = '@' + new(tree.Variable)(name.slice(1)).eval(env).value; } if (variable = tree.find(env.frames, function (frame) { if (v = frame.variable(name)) { return v.value.eval(env); } })) { return variable } else { throw { message: "variable " + name + " is undefined", index: this.index }; } } }; })(require('../tree')); require('./tree').find = function (obj, fun) { for (var i = 0, r; i < obj.length; i++) { if (r = fun.call(obj, obj[i])) { return r } } return null; }; require('./tree').jsify = function (obj) { if (Array.isArray(obj.value) && (obj.value.length > 1)) { return '[' + obj.value.map(function (v) { return v.toCSS(false) }).join(', ') + ']'; } else { return obj.toCSS(false); } }; var name; function loadStyleSheet(sheet, callback, reload, remaining) { var sheetName = name.slice(0, name.lastIndexOf('/') + 1) + sheet.href; var input = readFile(sheetName); var parser = new less.Parser(); parser.parse(input, function (e, root) { if (e) { print("Error: " + e); quit(1); } callback(root, sheet, { local: false, lastModified: 0, remaining: remaining }); }); // callback({}, sheet, { local: true, remaining: remaining }); } function writeFile(filename, content) { var fstream = new java.io.FileWriter(filename); var out = new java.io.BufferedWriter(fstream); out.write(content); out.close(); } // Command line integration via Rhino (function (args) { name = args[0]; var output = args[1]; if (!name) { print('No files present in the fileset; Check your pattern match in build.xml'); quit(1); } path = name.split("/");path.pop();path=path.join("/") var input = readFile(name); if (!input) { print('lesscss: couldn\'t open file ' + name); quit(1); } var result; var parser = new less.Parser(); parser.parse(input, function (e, root) { if (e) { quit(1); } else { result = root.toCSS(); if (output) { writeFile(output, result); print("Written to " + output); } else { print(result); } quit(0); } }); print("done"); }(arguments)); less.js-1.4.2/dist/less-rhino-1.3.1.js000066400000000000000000003677411217256642200171520ustar00rootroot00000000000000// // Stub out `require` in rhino // function require(arg) { return less[arg.split('/')[1]]; }; // ecma-5.js // // -- kriskowal Kris Kowal Copyright (C) 2009-2010 MIT License // -- tlrobinson Tom Robinson // dantman Daniel Friesen // // Array // if (!Array.isArray) { Array.isArray = function(obj) { return Object.prototype.toString.call(obj) === "[object Array]" || (obj instanceof Array); }; } if (!Array.prototype.forEach) { Array.prototype.forEach = function(block, thisObject) { var len = this.length >>> 0; for (var i = 0; i < len; i++) { if (i in this) { block.call(thisObject, this[i], i, this); } } }; } if (!Array.prototype.map) { Array.prototype.map = function(fun /*, thisp*/) { var len = this.length >>> 0; var res = new Array(len); var thisp = arguments[1]; for (var i = 0; i < len; i++) { if (i in this) { res[i] = fun.call(thisp, this[i], i, this); } } return res; }; } if (!Array.prototype.filter) { Array.prototype.filter = function (block /*, thisp */) { var values = []; var thisp = arguments[1]; for (var i = 0; i < this.length; i++) { if (block.call(thisp, this[i])) { values.push(this[i]); } } return values; }; } if (!Array.prototype.reduce) { Array.prototype.reduce = function(fun /*, initial*/) { var len = this.length >>> 0; var i = 0; // no value to return if no initial value and an empty array if (len === 0 && arguments.length === 1) throw new TypeError(); if (arguments.length >= 2) { var rv = arguments[1]; } else { do { if (i in this) { rv = this[i++]; break; } // if array contains no values, no initial value to return if (++i >= len) throw new TypeError(); } while (true); } for (; i < len; i++) { if (i in this) { rv = fun.call(null, rv, this[i], i, this); } } return rv; }; } if (!Array.prototype.indexOf) { Array.prototype.indexOf = function (value /*, fromIndex */ ) { var length = this.length; var i = arguments[1] || 0; if (!length) return -1; if (i >= length) return -1; if (i < 0) i += length; for (; i < length; i++) { if (!Object.prototype.hasOwnProperty.call(this, i)) { continue } if (value === this[i]) return i; } return -1; }; } // // Object // if (!Object.keys) { Object.keys = function (object) { var keys = []; for (var name in object) { if (Object.prototype.hasOwnProperty.call(object, name)) { keys.push(name); } } return keys; }; } // // String // if (!String.prototype.trim) { String.prototype.trim = function () { return String(this).replace(/^\s\s*/, '').replace(/\s\s*$/, ''); }; } var less, tree; if (typeof environment === "object" && ({}).toString.call(environment) === "[object Environment]") { // Rhino // Details on how to detect Rhino: https://github.com/ringo/ringojs/issues/88 if (typeof(window) === 'undefined') { less = {} } else { less = window.less = {} } tree = less.tree = {}; less.mode = 'rhino'; } else if (typeof(window) === 'undefined') { // Node.js less = exports, tree = require('./tree'); less.mode = 'node'; } else { // Browser if (typeof(window.less) === 'undefined') { window.less = {} } less = window.less, tree = window.less.tree = {}; less.mode = 'browser'; } // // less.js - parser // // A relatively straight-forward predictive parser. // There is no tokenization/lexing stage, the input is parsed // in one sweep. // // To make the parser fast enough to run in the browser, several // optimization had to be made: // // - Matching and slicing on a huge input is often cause of slowdowns. // The solution is to chunkify the input into smaller strings. // The chunks are stored in the `chunks` var, // `j` holds the current chunk index, and `current` holds // the index of the current chunk in relation to `input`. // This gives us an almost 4x speed-up. // // - In many cases, we don't need to match individual tokens; // for example, if a value doesn't hold any variables, operations // or dynamic references, the parser can effectively 'skip' it, // treating it as a literal. // An example would be '1px solid #000' - which evaluates to itself, // we don't need to know what the individual components are. // The drawback, of course is that you don't get the benefits of // syntax-checking on the CSS. This gives us a 50% speed-up in the parser, // and a smaller speed-up in the code-gen. // // // Token matching is done with the `$` function, which either takes // a terminal string or regexp, or a non-terminal function to call. // It also takes care of moving all the indices forwards. // // less.Parser = function Parser(env) { var input, // LeSS input string i, // current index in `input` j, // current chunk temp, // temporarily holds a chunk's state, for backtracking memo, // temporarily holds `i`, when backtracking furthest, // furthest index the parser has gone to chunks, // chunkified input current, // index of current chunk, in `input` parser; var that = this; // Top parser on an import tree must be sure there is one "env" // which will then be passed arround by reference. var env = env || { }; if (!env.contents) { env.contents={}; } // env.contents must be passed arround with top env // This function is called after all files // have been imported through `@import`. var finish = function () {}; var imports = this.imports = { paths: env && env.paths || [], // Search paths, when importing queue: [], // Files which haven't been imported yet files: {}, // Holds the imported parse trees contents: env.contents, // Holds the imported file contents mime: env && env.mime, // MIME type of .less files error: null, // Error in parsing/evaluating an import push: function (path, callback) { var that = this; this.queue.push(path); // // Import a file asynchronously // less.Parser.importer(path, this.paths, function (e, root) { that.queue.splice(that.queue.indexOf(path), 1); // Remove the path from the queue var imported = path in that.files; that.files[path] = root; // Store the root if (e && !that.error) { that.error = e } callback(e, root, imported); if (that.queue.length === 0) { finish(e) } // Call `finish` if we're done importing }, env); } }; function save() { temp = chunks[j], memo = i, current = i } function restore() { chunks[j] = temp, i = memo, current = i } function sync() { if (i > current) { chunks[j] = chunks[j].slice(i - current); current = i; } } function isWhitespace(c) { // Could change to \s? var code = c.charCodeAt(0); return code === 32 || code === 10 || code === 9; } // // Parse from a token, regexp or string, and move forward if match // function $(tok) { var match, args, length, index, k; // // Non-terminal // if (tok instanceof Function) { return tok.call(parser.parsers); // // Terminal // // Either match a single character in the input, // or match a regexp in the current chunk (chunk[j]). // } else if (typeof(tok) === 'string') { match = input.charAt(i) === tok ? tok : null; length = 1; sync (); } else { sync (); if (match = tok.exec(chunks[j])) { length = match[0].length; } else { return null; } } // The match is confirmed, add the match length to `i`, // and consume any extra white-space characters (' ' || '\n') // which come after that. The reason for this is that LeSS's // grammar is mostly white-space insensitive. // if (match) { skipWhitespace(length); if(typeof(match) === 'string') { return match; } else { return match.length === 1 ? match[0] : match; } } } function skipWhitespace(length) { var oldi = i, oldj = j, endIndex = i + chunks[j].length, mem = i += length; while (i < endIndex) { if (! isWhitespace(input.charAt(i))) { break } i++; } chunks[j] = chunks[j].slice(length + (i - mem)); current = i; if (chunks[j].length === 0 && j < chunks.length - 1) { j++ } return oldi !== i || oldj !== j; } function expect(arg, msg) { var result = $(arg); if (! result) { error(msg || (typeof(arg) === 'string' ? "expected '" + arg + "' got '" + input.charAt(i) + "'" : "unexpected token")); } else { return result; } } function error(msg, type) { throw { index: i, type: type || 'Syntax', message: msg }; } // Same as $(), but don't change the state of the parser, // just return the match. function peek(tok) { if (typeof(tok) === 'string') { return input.charAt(i) === tok; } else { if (tok.test(chunks[j])) { return true; } else { return false; } } } function getInput(e, env) { if (e.filename && env.filename && (e.filename !== env.filename)) { return parser.imports.contents[e.filename]; } else { return input; } } function getLocation(index, input) { for (var n = index, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } return { line: typeof(index) === 'number' ? (input.slice(0, index).match(/\n/g) || "").length : null, column: column }; } function getFileName(e) { if(less.mode === 'browser' || less.mode === 'rhino') return e.filename; else return require('path').resolve(e.filename); } function getDebugInfo(index, inputStream, e) { return { lineNumber: getLocation(index, inputStream).line + 1, fileName: getFileName(e) }; } function LessError(e, env) { var input = getInput(e, env), loc = getLocation(e.index, input), line = loc.line, col = loc.column, lines = input.split('\n'); this.type = e.type || 'Syntax'; this.message = e.message; this.filename = e.filename || env.filename; this.index = e.index; this.line = typeof(line) === 'number' ? line + 1 : null; this.callLine = e.call && (getLocation(e.call, input).line + 1); this.callExtract = lines[getLocation(e.call, input).line]; this.stack = e.stack; this.column = col; this.extract = [ lines[line - 1], lines[line], lines[line + 1] ]; } this.env = env = env || {}; // The optimization level dictates the thoroughness of the parser, // the lower the number, the less nodes it will create in the tree. // This could matter for debugging, or if you want to access // the individual nodes in the tree. this.optimization = ('optimization' in this.env) ? this.env.optimization : 1; this.env.filename = this.env.filename || null; // // The Parser // return parser = { imports: imports, // // Parse an input string into an abstract syntax tree, // call `callback` when done. // parse: function (str, callback) { var root, start, end, zone, line, lines, buff = [], c, error = null; i = j = current = furthest = 0; input = str.replace(/\r\n/g, '\n'); // Remove potential UTF Byte Order Mark input = input.replace(/^\uFEFF/, ''); // Split the input into chunks. chunks = (function (chunks) { var j = 0, skip = /(?:@\{[\w-]+\}|[^"'`\{\}\/\(\)\\])+/g, comment = /\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g, string = /"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'|`((?:[^`]|\\.)*)`/g, level = 0, match, chunk = chunks[0], inParam; for (var i = 0, c, cc; i < input.length; i++) { skip.lastIndex = i; if (match = skip.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); } } c = input.charAt(i); comment.lastIndex = string.lastIndex = i; if (match = string.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); c = input.charAt(i); } } if (!inParam && c === '/') { cc = input.charAt(i + 1); if (cc === '/' || cc === '*') { if (match = comment.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); c = input.charAt(i); } } } } switch (c) { case '{': if (! inParam) { level ++; chunk.push(c); break } case '}': if (! inParam) { level --; chunk.push(c); chunks[++j] = chunk = []; break } case '(': if (! inParam) { inParam = true; chunk.push(c); break } case ')': if ( inParam) { inParam = false; chunk.push(c); break } default: chunk.push(c); } } if (level > 0) { error = new(LessError)({ index: i, type: 'Parse', message: "missing closing `}`", filename: env.filename }, env); } return chunks.map(function (c) { return c.join('') });; })([[]]); if (error) { return callback(error); } // Start with the primary rule. // The whole syntax tree is held under a Ruleset node, // with the `root` property set to true, so no `{}` are // output. The callback is called when the input is parsed. try { root = new(tree.Ruleset)([], $(this.parsers.primary)); root.root = true; } catch (e) { return callback(new(LessError)(e, env)); } root.toCSS = (function (evaluate) { var line, lines, column; return function (options, variables) { var frames = [], importError; options = options || {}; // // Allows setting variables with a hash, so: // // `{ color: new(tree.Color)('#f01') }` will become: // // new(tree.Rule)('@color', // new(tree.Value)([ // new(tree.Expression)([ // new(tree.Color)('#f01') // ]) // ]) // ) // if (typeof(variables) === 'object' && !Array.isArray(variables)) { variables = Object.keys(variables).map(function (k) { var value = variables[k]; if (! (value instanceof tree.Value)) { if (! (value instanceof tree.Expression)) { value = new(tree.Expression)([value]); } value = new(tree.Value)([value]); } return new(tree.Rule)('@' + k, value, false, 0); }); frames = [new(tree.Ruleset)(null, variables)]; } try { var css = evaluate.call(this, { frames: frames }) .toCSS([], { compress: options.compress || false, dumpLineNumbers: env.dumpLineNumbers }); } catch (e) { throw new(LessError)(e, env); } if ((importError = parser.imports.error)) { // Check if there was an error during importing if (importError instanceof LessError) throw importError; else throw new(LessError)(importError, env); } if (options.yuicompress && less.mode === 'node') { return require('./cssmin').compressor.cssmin(css); } else if (options.compress) { return css.replace(/(\s)+/g, "$1"); } else { return css; } }; })(root.eval); // If `i` is smaller than the `input.length - 1`, // it means the parser wasn't able to parse the whole // string, so we've got a parsing error. // // We try to extract a \n delimited string, // showing the line where the parse error occured. // We split it up into two parts (the part which parsed, // and the part which didn't), so we can color them differently. if (i < input.length - 1) { i = furthest; lines = input.split('\n'); line = (input.slice(0, i).match(/\n/g) || "").length + 1; for (var n = i, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } error = { type: "Parse", message: "Syntax Error on line " + line, index: i, filename: env.filename, line: line, column: column, extract: [ lines[line - 2], lines[line - 1], lines[line] ] }; } if (this.imports.queue.length > 0) { finish = function (e) { if (e) callback(e); else callback(null, root); }; } else { callback(error, root); } }, // // Here in, the parsing rules/functions // // The basic structure of the syntax tree generated is as follows: // // Ruleset -> Rule -> Value -> Expression -> Entity // // Here's some LESS code: // // .class { // color: #fff; // border: 1px solid #000; // width: @w + 4px; // > .child {...} // } // // And here's what the parse tree might look like: // // Ruleset (Selector '.class', [ // Rule ("color", Value ([Expression [Color #fff]])) // Rule ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]])) // Rule ("width", Value ([Expression [Operation "+" [Variable "@w"][Dimension 4px]]])) // Ruleset (Selector [Element '>', '.child'], [...]) // ]) // // In general, most rules will try to parse a token with the `$()` function, and if the return // value is truly, will return a new node, of the relevant type. Sometimes, we need to check // first, before parsing, that's when we use `peek()`. // parsers: { // // The `primary` rule is the *entry* and *exit* point of the parser. // The rules here can appear at any level of the parse tree. // // The recursive nature of the grammar is an interplay between the `block` // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule, // as represented by this simplified grammar: // // primary → (ruleset | rule)+ // ruleset → selector+ block // block → '{' primary '}' // // Only at one point is the primary rule not called from the // block rule: at the root level. // primary: function () { var node, root = []; while ((node = $(this.mixin.definition) || $(this.rule) || $(this.ruleset) || $(this.mixin.call) || $(this.comment) || $(this.directive)) || $(/^[\s\n]+/)) { node && root.push(node); } return root; }, // We create a Comment node for CSS comments `/* */`, // but keep the LeSS comments `//` silent, by just skipping // over them. comment: function () { var comment; if (input.charAt(i) !== '/') return; if (input.charAt(i + 1) === '/') { return new(tree.Comment)($(/^\/\/.*/), true); } else if (comment = $(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/)) { return new(tree.Comment)(comment); } }, // // Entities are tokens which can be found inside an Expression // entities: { // // A string, which supports escaping " and ' // // "milky way" 'he\'s the one!' // quoted: function () { var str, j = i, e; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '"' && input.charAt(j) !== "'") return; e && $('~'); if (str = $(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/)) { return new(tree.Quoted)(str[0], str[1] || str[2], e); } }, // // A catch-all word, such as: // // black border-collapse // keyword: function () { var k; if (k = $(/^[_A-Za-z-][_A-Za-z0-9-]*/)) { if (tree.colors.hasOwnProperty(k)) { // detect named color return new(tree.Color)(tree.colors[k].slice(1)); } else { return new(tree.Keyword)(k); } } }, // // A function call // // rgb(255, 0, 255) // // We also try to catch IE's `alpha()`, but let the `alpha` parser // deal with the details. // // The arguments are parsed with the `entities.arguments` parser. // call: function () { var name, nameLC, args, alpha_ret, index = i; if (! (name = /^([\w-]+|%|progid:[\w\.]+)\(/.exec(chunks[j]))) return; name = name[1]; nameLC = name.toLowerCase(); if (nameLC === 'url') { return null } else { i += name.length } if (nameLC === 'alpha') { alpha_ret = $(this.alpha); if(typeof alpha_ret !== 'undefined') { return alpha_ret; } } $('('); // Parse the '(' and consume whitespace. args = $(this.entities.arguments); if (! $(')')) return; if (name) { return new(tree.Call)(name, args, index, env.filename) } }, arguments: function () { var args = [], arg; while (arg = $(this.entities.assignment) || $(this.expression)) { args.push(arg); if (! $(',')) { break } } return args; }, literal: function () { return $(this.entities.ratio) || $(this.entities.dimension) || $(this.entities.color) || $(this.entities.quoted); }, // Assignments are argument entities for calls. // They are present in ie filter properties as shown below. // // filter: progid:DXImageTransform.Microsoft.Alpha( *opacity=50* ) // assignment: function () { var key, value; if ((key = $(/^\w+(?=\s?=)/i)) && $('=') && (value = $(this.entity))) { return new(tree.Assignment)(key, value); } }, // // Parse url() tokens // // We use a specific rule for urls, because they don't really behave like // standard function calls. The difference is that the argument doesn't have // to be enclosed within a string, so it can't be parsed as an Expression. // url: function () { var value; if (input.charAt(i) !== 'u' || !$(/^url\(/)) return; value = $(this.entities.quoted) || $(this.entities.variable) || $(/^(?:(?:\\[\(\)'"])|[^\(\)'"])+/) || ""; expect(')'); return new(tree.URL)((value.value != null || value instanceof tree.Variable) ? value : new(tree.Anonymous)(value), imports.paths); }, // // A Variable entity, such as `@fink`, in // // width: @fink + 2px // // We use a different parser for variable definitions, // see `parsers.variable`. // variable: function () { var name, index = i; if (input.charAt(i) === '@' && (name = $(/^@@?[\w-]+/))) { return new(tree.Variable)(name, index, env.filename); } }, // A variable entity useing the protective {} e.g. @{var} variableCurly: function () { var name, curly, index = i; if (input.charAt(i) === '@' && (curly = $(/^@\{([\w-]+)\}/))) { return new(tree.Variable)("@" + curly[1], index, env.filename); } }, // // A Hexadecimal color // // #4F3C2F // // `rgb` and `hsl` colors are parsed through the `entities.call` parser. // color: function () { var rgb; if (input.charAt(i) === '#' && (rgb = $(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/))) { return new(tree.Color)(rgb[1]); } }, // // A Dimension, that is, a number and a unit // // 0.5em 95% // dimension: function () { var value, c = input.charCodeAt(i); if ((c > 57 || c < 45) || c === 47) return; if (value = $(/^(-?\d*\.?\d+)(px|%|em|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn|dpi|dpcm|dppx|rem|vw|vh|vmin|vm|ch)?/)) { return new(tree.Dimension)(value[1], value[2]); } }, // // A Ratio // // 16/9 // ratio: function () { var value, c = input.charCodeAt(i); if (c > 57 || c < 48) return; if (value = $(/^(\d+\/\d+)/)) { return new(tree.Ratio)(value[1]); } }, // // JavaScript code to be evaluated // // `window.location.href` // javascript: function () { var str, j = i, e; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '`') { return } e && $('~'); if (str = $(/^`([^`]*)`/)) { return new(tree.JavaScript)(str[1], i, e); } } }, // // The variable part of a variable definition. Used in the `rule` parser // // @fink: // variable: function () { var name; if (input.charAt(i) === '@' && (name = $(/^(@[\w-]+)\s*:/))) { return name[1] } }, // // A font size/line-height shorthand // // small/12px // // We need to peek first, or we'll match on keywords and dimensions // shorthand: function () { var a, b; if (! peek(/^[@\w.%-]+\/[@\w.-]+/)) return; save(); if ((a = $(this.entity)) && $('/') && (b = $(this.entity))) { return new(tree.Shorthand)(a, b); } restore(); }, // // Mixins // mixin: { // // A Mixin call, with an optional argument list // // #mixins > .square(#fff); // .rounded(4px, black); // .button; // // The `while` loop is there because mixins can be // namespaced, but we only support the child and descendant // selector for now. // call: function () { var elements = [], e, c, args = [], arg, index = i, s = input.charAt(i), name, value, important = false; if (s !== '.' && s !== '#') { return } save(); // stop us absorbing part of an invalid selector while (e = $(/^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/)) { elements.push(new(tree.Element)(c, e, i)); c = $('>'); } if ($('(')) { while (arg = $(this.expression)) { value = arg; name = null; // Variable if (arg.value.length == 1) { var val = arg.value[0]; if (val instanceof tree.Variable) { if ($(':')) { if (value = $(this.expression)) { name = val.name; } else { throw new(Error)("Expected value"); } } } } args.push({ name: name, value: value }); if (! $(',')) { break } } if (! $(')')) throw new(Error)("Expected )"); } if ($(this.important)) { important = true; } if (elements.length > 0 && ($(';') || peek('}'))) { return new(tree.mixin.Call)(elements, args, index, env.filename, important); } restore(); }, // // A Mixin definition, with a list of parameters // // .rounded (@radius: 2px, @color) { // ... // } // // Until we have a finer grained state-machine, we have to // do a look-ahead, to make sure we don't have a mixin call. // See the `rule` function for more information. // // We start by matching `.rounded (`, and then proceed on to // the argument list, which has optional default values. // We store the parameters in `params`, with a `value` key, // if there is a value, such as in the case of `@radius`. // // Once we've got our params list, and a closing `)`, we parse // the `{...}` block. // definition: function () { var name, params = [], match, ruleset, param, value, cond, variadic = false; if ((input.charAt(i) !== '.' && input.charAt(i) !== '#') || peek(/^[^{]*(;|})/)) return; save(); if (match = $(/^([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/)) { name = match[1]; do { if (input.charAt(i) === '.' && $(/^\.{3}/)) { variadic = true; break; } else if (param = $(this.entities.variable) || $(this.entities.literal) || $(this.entities.keyword)) { // Variable if (param instanceof tree.Variable) { if ($(':')) { value = expect(this.expression, 'expected expression'); params.push({ name: param.name, value: value }); } else if ($(/^\.{3}/)) { params.push({ name: param.name, variadic: true }); variadic = true; break; } else { params.push({ name: param.name }); } } else { params.push({ value: param }); } } else { break; } } while ($(',')) // .mixincall("@{a}"); // looks a bit like a mixin definition.. so we have to be nice and restore if (!$(')')) { furthest = i; restore(); } if ($(/^when/)) { // Guard cond = expect(this.conditions, 'expected condition'); } ruleset = $(this.block); if (ruleset) { return new(tree.mixin.Definition)(name, params, ruleset, cond, variadic); } else { restore(); } } } }, // // Entities are the smallest recognized token, // and can be found inside a rule's value. // entity: function () { return $(this.entities.literal) || $(this.entities.variable) || $(this.entities.url) || $(this.entities.call) || $(this.entities.keyword) || $(this.entities.javascript) || $(this.comment); }, // // A Rule terminator. Note that we use `peek()` to check for '}', // because the `block` rule will be expecting it, but we still need to make sure // it's there, if ';' was ommitted. // end: function () { return $(';') || peek('}'); }, // // IE's alpha function // // alpha(opacity=88) // alpha: function () { var value; if (! $(/^\(opacity=/i)) return; if (value = $(/^\d+/) || $(this.entities.variable)) { expect(')'); return new(tree.Alpha)(value); } }, // // A Selector Element // // div // + h1 // #socks // input[type="text"] // // Elements are the building blocks for Selectors, // they are made out of a `Combinator` (see combinator rule), // and an element name, such as a tag a class, or `*`. // element: function () { var e, t, c, v; c = $(this.combinator); e = $(/^(?:\d+\.\d+|\d+)%/) || $(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/) || $('*') || $('&') || $(this.attribute) || $(/^\([^)@]+\)/) || $(/^[\.#](?=@)/) || $(this.entities.variableCurly); if (! e) { if ($('(') && (v = ($(this.entities.variableCurly) || $(this.entities.variable))) && $(')')) { e = new(tree.Paren)(v); } } if (e) { return new(tree.Element)(c, e, i) } }, // // Combinators combine elements together, in a Selector. // // Because our parser isn't white-space sensitive, special care // has to be taken, when parsing the descendant combinator, ` `, // as it's an empty space. We have to check the previous character // in the input, to see if it's a ` ` character. More info on how // we deal with this in *combinator.js*. // combinator: function () { var match, c = input.charAt(i); if (c === '>' || c === '+' || c === '~') { i++; while (input.charAt(i).match(/\s/)) { i++ } return new(tree.Combinator)(c); } else if (input.charAt(i - 1).match(/\s/)) { return new(tree.Combinator)(" "); } else { return new(tree.Combinator)(null); } }, // // A CSS Selector // // .class > div + h1 // li a:hover // // Selectors are made out of one or more Elements, see above. // selector: function () { var sel, e, elements = [], c, match; // depreciated, will be removed soon if ($('(')) { sel = $(this.entity); expect(')'); return new(tree.Selector)([new(tree.Element)('', sel, i)]); } while (e = $(this.element)) { c = input.charAt(i); elements.push(e) if (c === '{' || c === '}' || c === ';' || c === ',') { break } } if (elements.length > 0) { return new(tree.Selector)(elements) } }, tag: function () { return $(/^[A-Za-z][A-Za-z-]*[0-9]?/) || $('*'); }, attribute: function () { var attr = '', key, val, op; if (! $('[')) return; if (key = $(/^(?:[_A-Za-z0-9-]|\\.)+/) || $(this.entities.quoted)) { if ((op = $(/^[|~*$^]?=/)) && (val = $(this.entities.quoted) || $(/^[\w-]+/))) { attr = [key, op, val.toCSS ? val.toCSS() : val].join(''); } else { attr = key } } if (! $(']')) return; if (attr) { return "[" + attr + "]" } }, // // The `block` rule is used by `ruleset` and `mixin.definition`. // It's a wrapper around the `primary` rule, with added `{}`. // block: function () { var content; if ($('{') && (content = $(this.primary)) && $('}')) { return content; } }, // // div, .class, body > p {...} // ruleset: function () { var selectors = [], s, rules, match, debugInfo; save(); if (env.dumpLineNumbers) debugInfo = getDebugInfo(i, input, env); while (s = $(this.selector)) { selectors.push(s); $(this.comment); if (! $(',')) { break } $(this.comment); } if (selectors.length > 0 && (rules = $(this.block))) { var ruleset = new(tree.Ruleset)(selectors, rules, env.strictImports); if (env.dumpLineNumbers) ruleset.debugInfo = debugInfo; return ruleset; } else { // Backtrack furthest = i; restore(); } }, rule: function () { var name, value, c = input.charAt(i), important, match; save(); if (c === '.' || c === '#' || c === '&') { return } if (name = $(this.variable) || $(this.property)) { if ((name.charAt(0) != '@') && (match = /^([^@+\/'"*`(;{}-]*);/.exec(chunks[j]))) { i += match[0].length - 1; value = new(tree.Anonymous)(match[1]); } else if (name === "font") { value = $(this.font); } else { value = $(this.value); } important = $(this.important); if (value && $(this.end)) { return new(tree.Rule)(name, value, important, memo); } else { furthest = i; restore(); } } }, // // An @import directive // // @import "lib"; // // Depending on our environemnt, importing is done differently: // In the browser, it's an XHR request, in Node, it would be a // file-system operation. The function used for importing is // stored in `import`, which we pass to the Import constructor. // "import": function () { var path, features, index = i; save(); var dir = $(/^@import(?:-(once))?\s+/); if (dir && (path = $(this.entities.quoted) || $(this.entities.url))) { features = $(this.mediaFeatures); if ($(';')) { return new(tree.Import)(path, imports, features, (dir[1] === 'once'), index); } } restore(); }, mediaFeature: function () { var e, p, nodes = []; do { if (e = $(this.entities.keyword)) { nodes.push(e); } else if ($('(')) { p = $(this.property); e = $(this.entity); if ($(')')) { if (p && e) { nodes.push(new(tree.Paren)(new(tree.Rule)(p, e, null, i, true))); } else if (e) { nodes.push(new(tree.Paren)(e)); } else { return null; } } else { return null } } } while (e); if (nodes.length > 0) { return new(tree.Expression)(nodes); } }, mediaFeatures: function () { var e, features = []; do { if (e = $(this.mediaFeature)) { features.push(e); if (! $(',')) { break } } else if (e = $(this.entities.variable)) { features.push(e); if (! $(',')) { break } } } while (e); return features.length > 0 ? features : null; }, media: function () { var features, rules, media, debugInfo; if (env.dumpLineNumbers) debugInfo = getDebugInfo(i, input, env); if ($(/^@media/)) { features = $(this.mediaFeatures); if (rules = $(this.block)) { media = new(tree.Media)(rules, features); if(env.dumpLineNumbers) media.debugInfo = debugInfo; return media; } } }, // // A CSS Directive // // @charset "utf-8"; // directive: function () { var name, value, rules, identifier, e, nodes, nonVendorSpecificName, hasBlock, hasIdentifier; if (input.charAt(i) !== '@') return; if (value = $(this['import']) || $(this.media)) { return value; } save(); name = $(/^@[a-z-]+/); nonVendorSpecificName = name; if (name.charAt(1) == '-' && name.indexOf('-', 2) > 0) { nonVendorSpecificName = "@" + name.slice(name.indexOf('-', 2) + 1); } switch(nonVendorSpecificName) { case "@font-face": hasBlock = true; break; case "@viewport": case "@top-left": case "@top-left-corner": case "@top-center": case "@top-right": case "@top-right-corner": case "@bottom-left": case "@bottom-left-corner": case "@bottom-center": case "@bottom-right": case "@bottom-right-corner": case "@left-top": case "@left-middle": case "@left-bottom": case "@right-top": case "@right-middle": case "@right-bottom": hasBlock = true; break; case "@page": case "@document": case "@supports": case "@keyframes": hasBlock = true; hasIdentifier = true; break; } if (hasIdentifier) { name += " " + ($(/^[^{]+/) || '').trim(); } if (hasBlock) { if (rules = $(this.block)) { return new(tree.Directive)(name, rules); } } else { if ((value = $(this.entity)) && $(';')) { return new(tree.Directive)(name, value); } } restore(); }, font: function () { var value = [], expression = [], weight, shorthand, font, e; while (e = $(this.shorthand) || $(this.entity)) { expression.push(e); } value.push(new(tree.Expression)(expression)); if ($(',')) { while (e = $(this.expression)) { value.push(e); if (! $(',')) { break } } } return new(tree.Value)(value); }, // // A Value is a comma-delimited list of Expressions // // font-family: Baskerville, Georgia, serif; // // In a Rule, a Value represents everything after the `:`, // and before the `;`. // value: function () { var e, expressions = [], important; while (e = $(this.expression)) { expressions.push(e); if (! $(',')) { break } } if (expressions.length > 0) { return new(tree.Value)(expressions); } }, important: function () { if (input.charAt(i) === '!') { return $(/^! *important/); } }, sub: function () { var e; if ($('(') && (e = $(this.expression)) && $(')')) { return e; } }, multiplication: function () { var m, a, op, operation; if (m = $(this.operand)) { while (!peek(/^\/\*/) && (op = ($('/') || $('*'))) && (a = $(this.operand))) { operation = new(tree.Operation)(op, [operation || m, a]); } return operation || m; } }, addition: function () { var m, a, op, operation; if (m = $(this.multiplication)) { while ((op = $(/^[-+]\s+/) || (!isWhitespace(input.charAt(i - 1)) && ($('+') || $('-')))) && (a = $(this.multiplication))) { operation = new(tree.Operation)(op, [operation || m, a]); } return operation || m; } }, conditions: function () { var a, b, index = i, condition; if (a = $(this.condition)) { while ($(',') && (b = $(this.condition))) { condition = new(tree.Condition)('or', condition || a, b, index); } return condition || a; } }, condition: function () { var a, b, c, op, index = i, negate = false; if ($(/^not/)) { negate = true } expect('('); if (a = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) { if (op = $(/^(?:>=|=<|[<=>])/)) { if (b = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) { c = new(tree.Condition)(op, a, b, index, negate); } else { error('expected expression'); } } else { c = new(tree.Condition)('=', a, new(tree.Keyword)('true'), index, negate); } expect(')'); return $(/^and/) ? new(tree.Condition)('and', c, $(this.condition)) : c; } }, // // An operand is anything that can be part of an operation, // such as a Color, or a Variable // operand: function () { var negate, p = input.charAt(i + 1); if (input.charAt(i) === '-' && (p === '@' || p === '(')) { negate = $('-') } var o = $(this.sub) || $(this.entities.dimension) || $(this.entities.color) || $(this.entities.variable) || $(this.entities.call); return negate ? new(tree.Operation)('*', [new(tree.Dimension)(-1), o]) : o; }, // // Expressions either represent mathematical operations, // or white-space delimited Entities. // // 1px solid black // @var * 2 // expression: function () { var e, delim, entities = [], d; while (e = $(this.addition) || $(this.entity)) { entities.push(e); } if (entities.length > 0) { return new(tree.Expression)(entities); } }, property: function () { var name; if (name = $(/^(\*?-?[_a-z0-9-]+)\s*:/)) { return name[1]; } } } }; }; if (less.mode === 'browser' || less.mode === 'rhino') { // // Used by `@import` directives // less.Parser.importer = function (path, paths, callback, env) { if (!/^([a-z-]+:)?\//.test(path) && paths.length > 0) { path = paths[0] + path; } // We pass `true` as 3rd argument, to force the reload of the import. // This is so we can get the syntax tree as opposed to just the CSS output, // as we need this to evaluate the current stylesheet. // __ Now using the hack of passing a ref to top parser's content cache in the 1st arg. __ loadStyleSheet({ href: path, title: path, type: env.mime, contents: env.contents }, function (e) { if (e && typeof(env.errback) === "function") { env.errback.call(null, path, paths, callback, env); } else { callback.apply(null, arguments); } }, true); }; } (function (tree) { tree.functions = { rgb: function (r, g, b) { return this.rgba(r, g, b, 1.0); }, rgba: function (r, g, b, a) { var rgb = [r, g, b].map(function (c) { return number(c) }), a = number(a); return new(tree.Color)(rgb, a); }, hsl: function (h, s, l) { return this.hsla(h, s, l, 1.0); }, hsla: function (h, s, l, a) { h = (number(h) % 360) / 360; s = number(s); l = number(l); a = number(a); var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s; var m1 = l * 2 - m2; return this.rgba(hue(h + 1/3) * 255, hue(h) * 255, hue(h - 1/3) * 255, a); function hue(h) { h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h); if (h * 6 < 1) return m1 + (m2 - m1) * h * 6; else if (h * 2 < 1) return m2; else if (h * 3 < 2) return m1 + (m2 - m1) * (2/3 - h) * 6; else return m1; } }, hue: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().h)); }, saturation: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().s * 100), '%'); }, lightness: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().l * 100), '%'); }, red: function (color) { return new(tree.Dimension)(color.rgb[0]); }, green: function (color) { return new(tree.Dimension)(color.rgb[1]); }, blue: function (color) { return new(tree.Dimension)(color.rgb[2]); }, alpha: function (color) { return new(tree.Dimension)(color.toHSL().a); }, luma: function (color) { return new(tree.Dimension)(Math.round((0.2126 * (color.rgb[0]/255) + 0.7152 * (color.rgb[1]/255) + 0.0722 * (color.rgb[2]/255)) * color.alpha * 100), '%'); }, saturate: function (color, amount) { var hsl = color.toHSL(); hsl.s += amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, desaturate: function (color, amount) { var hsl = color.toHSL(); hsl.s -= amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, lighten: function (color, amount) { var hsl = color.toHSL(); hsl.l += amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, darken: function (color, amount) { var hsl = color.toHSL(); hsl.l -= amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, fadein: function (color, amount) { var hsl = color.toHSL(); hsl.a += amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, fadeout: function (color, amount) { var hsl = color.toHSL(); hsl.a -= amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, fade: function (color, amount) { var hsl = color.toHSL(); hsl.a = amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, spin: function (color, amount) { var hsl = color.toHSL(); var hue = (hsl.h + amount.value) % 360; hsl.h = hue < 0 ? 360 + hue : hue; return hsla(hsl); }, // // Copyright (c) 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein // http://sass-lang.com // mix: function (color1, color2, weight) { if (!weight) { weight = new(tree.Dimension)(50); } var p = weight.value / 100.0; var w = p * 2 - 1; var a = color1.toHSL().a - color2.toHSL().a; var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0; var w2 = 1 - w1; var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2, color1.rgb[1] * w1 + color2.rgb[1] * w2, color1.rgb[2] * w1 + color2.rgb[2] * w2]; var alpha = color1.alpha * p + color2.alpha * (1 - p); return new(tree.Color)(rgb, alpha); }, greyscale: function (color) { return this.desaturate(color, new(tree.Dimension)(100)); }, contrast: function (color, dark, light, threshold) { if (typeof light === 'undefined') { light = this.rgba(255, 255, 255, 1.0); } if (typeof dark === 'undefined') { dark = this.rgba(0, 0, 0, 1.0); } if (typeof threshold === 'undefined') { threshold = 0.43; } else { threshold = threshold.value; } if (((0.2126 * (color.rgb[0]/255) + 0.7152 * (color.rgb[1]/255) + 0.0722 * (color.rgb[2]/255)) * color.alpha) < threshold) { return light; } else { return dark; } }, e: function (str) { return new(tree.Anonymous)(str instanceof tree.JavaScript ? str.evaluated : str); }, escape: function (str) { return new(tree.Anonymous)(encodeURI(str.value).replace(/=/g, "%3D").replace(/:/g, "%3A").replace(/#/g, "%23").replace(/;/g, "%3B").replace(/\(/g, "%28").replace(/\)/g, "%29")); }, '%': function (quoted /* arg, arg, ...*/) { var args = Array.prototype.slice.call(arguments, 1), str = quoted.value; for (var i = 0; i < args.length; i++) { str = str.replace(/%[sda]/i, function(token) { var value = token.match(/s/i) ? args[i].value : args[i].toCSS(); return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value; }); } str = str.replace(/%%/g, '%'); return new(tree.Quoted)('"' + str + '"', str); }, round: function (n, f) { var fraction = typeof(f) === "undefined" ? 0 : f.value; if (n instanceof tree.Dimension) { return new(tree.Dimension)(number(n).toFixed(fraction), n.unit); } else if (typeof(n) === 'number') { return n.toFixed(fraction); } else { throw { type: "Argument", message: "argument must be a number" }; } }, ceil: function (n) { return this._math('ceil', n); }, floor: function (n) { return this._math('floor', n); }, _math: function (fn, n) { if (n instanceof tree.Dimension) { return new(tree.Dimension)(Math[fn](number(n)), n.unit); } else if (typeof(n) === 'number') { return Math[fn](n); } else { throw { type: "Argument", message: "argument must be a number" }; } }, argb: function (color) { return new(tree.Anonymous)(color.toARGB()); }, percentage: function (n) { return new(tree.Dimension)(n.value * 100, '%'); }, color: function (n) { if (n instanceof tree.Quoted) { return new(tree.Color)(n.value.slice(1)); } else { throw { type: "Argument", message: "argument must be a string" }; } }, iscolor: function (n) { return this._isa(n, tree.Color); }, isnumber: function (n) { return this._isa(n, tree.Dimension); }, isstring: function (n) { return this._isa(n, tree.Quoted); }, iskeyword: function (n) { return this._isa(n, tree.Keyword); }, isurl: function (n) { return this._isa(n, tree.URL); }, ispixel: function (n) { return (n instanceof tree.Dimension) && n.unit === 'px' ? tree.True : tree.False; }, ispercentage: function (n) { return (n instanceof tree.Dimension) && n.unit === '%' ? tree.True : tree.False; }, isem: function (n) { return (n instanceof tree.Dimension) && n.unit === 'em' ? tree.True : tree.False; }, _isa: function (n, Type) { return (n instanceof Type) ? tree.True : tree.False; }, /* Blending modes */ multiply: function(color1, color2) { var r = color1.rgb[0] * color2.rgb[0] / 255; var g = color1.rgb[1] * color2.rgb[1] / 255; var b = color1.rgb[2] * color2.rgb[2] / 255; return this.rgb(r, g, b); }, screen: function(color1, color2) { var r = 255 - (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255; var g = 255 - (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255; var b = 255 - (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255; return this.rgb(r, g, b); }, overlay: function(color1, color2) { var r = color1.rgb[0] < 128 ? 2 * color1.rgb[0] * color2.rgb[0] / 255 : 255 - 2 * (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255; var g = color1.rgb[1] < 128 ? 2 * color1.rgb[1] * color2.rgb[1] / 255 : 255 - 2 * (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255; var b = color1.rgb[2] < 128 ? 2 * color1.rgb[2] * color2.rgb[2] / 255 : 255 - 2 * (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255; return this.rgb(r, g, b); }, softlight: function(color1, color2) { var t = color2.rgb[0] * color1.rgb[0] / 255; var r = t + color1.rgb[0] * (255 - (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255 - t) / 255; t = color2.rgb[1] * color1.rgb[1] / 255; var g = t + color1.rgb[1] * (255 - (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255 - t) / 255; t = color2.rgb[2] * color1.rgb[2] / 255; var b = t + color1.rgb[2] * (255 - (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255 - t) / 255; return this.rgb(r, g, b); }, hardlight: function(color1, color2) { var r = color2.rgb[0] < 128 ? 2 * color2.rgb[0] * color1.rgb[0] / 255 : 255 - 2 * (255 - color2.rgb[0]) * (255 - color1.rgb[0]) / 255; var g = color2.rgb[1] < 128 ? 2 * color2.rgb[1] * color1.rgb[1] / 255 : 255 - 2 * (255 - color2.rgb[1]) * (255 - color1.rgb[1]) / 255; var b = color2.rgb[2] < 128 ? 2 * color2.rgb[2] * color1.rgb[2] / 255 : 255 - 2 * (255 - color2.rgb[2]) * (255 - color1.rgb[2]) / 255; return this.rgb(r, g, b); }, difference: function(color1, color2) { var r = Math.abs(color1.rgb[0] - color2.rgb[0]); var g = Math.abs(color1.rgb[1] - color2.rgb[1]); var b = Math.abs(color1.rgb[2] - color2.rgb[2]); return this.rgb(r, g, b); }, exclusion: function(color1, color2) { var r = color1.rgb[0] + color2.rgb[0] * (255 - color1.rgb[0] - color1.rgb[0]) / 255; var g = color1.rgb[1] + color2.rgb[1] * (255 - color1.rgb[1] - color1.rgb[1]) / 255; var b = color1.rgb[2] + color2.rgb[2] * (255 - color1.rgb[2] - color1.rgb[2]) / 255; return this.rgb(r, g, b); }, average: function(color1, color2) { var r = (color1.rgb[0] + color2.rgb[0]) / 2; var g = (color1.rgb[1] + color2.rgb[1]) / 2; var b = (color1.rgb[2] + color2.rgb[2]) / 2; return this.rgb(r, g, b); }, negation: function(color1, color2) { var r = 255 - Math.abs(255 - color2.rgb[0] - color1.rgb[0]); var g = 255 - Math.abs(255 - color2.rgb[1] - color1.rgb[1]); var b = 255 - Math.abs(255 - color2.rgb[2] - color1.rgb[2]); return this.rgb(r, g, b); }, tint: function(color, amount) { return this.mix(this.rgb(255,255,255), color, amount); }, shade: function(color, amount) { return this.mix(this.rgb(0, 0, 0), color, amount); } }; function hsla(hsla) { return tree.functions.hsla(hsla.h, hsla.s, hsla.l, hsla.a); } function number(n) { if (n instanceof tree.Dimension) { return parseFloat(n.unit == '%' ? n.value / 100 : n.value); } else if (typeof(n) === 'number') { return n; } else { throw { error: "RuntimeError", message: "color functions take numbers as parameters" }; } } function clamp(val) { return Math.min(1, Math.max(0, val)); } })(require('./tree')); (function (tree) { tree.colors = { 'aliceblue':'#f0f8ff', 'antiquewhite':'#faebd7', 'aqua':'#00ffff', 'aquamarine':'#7fffd4', 'azure':'#f0ffff', 'beige':'#f5f5dc', 'bisque':'#ffe4c4', 'black':'#000000', 'blanchedalmond':'#ffebcd', 'blue':'#0000ff', 'blueviolet':'#8a2be2', 'brown':'#a52a2a', 'burlywood':'#deb887', 'cadetblue':'#5f9ea0', 'chartreuse':'#7fff00', 'chocolate':'#d2691e', 'coral':'#ff7f50', 'cornflowerblue':'#6495ed', 'cornsilk':'#fff8dc', 'crimson':'#dc143c', 'cyan':'#00ffff', 'darkblue':'#00008b', 'darkcyan':'#008b8b', 'darkgoldenrod':'#b8860b', 'darkgray':'#a9a9a9', 'darkgrey':'#a9a9a9', 'darkgreen':'#006400', 'darkkhaki':'#bdb76b', 'darkmagenta':'#8b008b', 'darkolivegreen':'#556b2f', 'darkorange':'#ff8c00', 'darkorchid':'#9932cc', 'darkred':'#8b0000', 'darksalmon':'#e9967a', 'darkseagreen':'#8fbc8f', 'darkslateblue':'#483d8b', 'darkslategray':'#2f4f4f', 'darkslategrey':'#2f4f4f', 'darkturquoise':'#00ced1', 'darkviolet':'#9400d3', 'deeppink':'#ff1493', 'deepskyblue':'#00bfff', 'dimgray':'#696969', 'dimgrey':'#696969', 'dodgerblue':'#1e90ff', 'firebrick':'#b22222', 'floralwhite':'#fffaf0', 'forestgreen':'#228b22', 'fuchsia':'#ff00ff', 'gainsboro':'#dcdcdc', 'ghostwhite':'#f8f8ff', 'gold':'#ffd700', 'goldenrod':'#daa520', 'gray':'#808080', 'grey':'#808080', 'green':'#008000', 'greenyellow':'#adff2f', 'honeydew':'#f0fff0', 'hotpink':'#ff69b4', 'indianred':'#cd5c5c', 'indigo':'#4b0082', 'ivory':'#fffff0', 'khaki':'#f0e68c', 'lavender':'#e6e6fa', 'lavenderblush':'#fff0f5', 'lawngreen':'#7cfc00', 'lemonchiffon':'#fffacd', 'lightblue':'#add8e6', 'lightcoral':'#f08080', 'lightcyan':'#e0ffff', 'lightgoldenrodyellow':'#fafad2', 'lightgray':'#d3d3d3', 'lightgrey':'#d3d3d3', 'lightgreen':'#90ee90', 'lightpink':'#ffb6c1', 'lightsalmon':'#ffa07a', 'lightseagreen':'#20b2aa', 'lightskyblue':'#87cefa', 'lightslategray':'#778899', 'lightslategrey':'#778899', 'lightsteelblue':'#b0c4de', 'lightyellow':'#ffffe0', 'lime':'#00ff00', 'limegreen':'#32cd32', 'linen':'#faf0e6', 'magenta':'#ff00ff', 'maroon':'#800000', 'mediumaquamarine':'#66cdaa', 'mediumblue':'#0000cd', 'mediumorchid':'#ba55d3', 'mediumpurple':'#9370d8', 'mediumseagreen':'#3cb371', 'mediumslateblue':'#7b68ee', 'mediumspringgreen':'#00fa9a', 'mediumturquoise':'#48d1cc', 'mediumvioletred':'#c71585', 'midnightblue':'#191970', 'mintcream':'#f5fffa', 'mistyrose':'#ffe4e1', 'moccasin':'#ffe4b5', 'navajowhite':'#ffdead', 'navy':'#000080', 'oldlace':'#fdf5e6', 'olive':'#808000', 'olivedrab':'#6b8e23', 'orange':'#ffa500', 'orangered':'#ff4500', 'orchid':'#da70d6', 'palegoldenrod':'#eee8aa', 'palegreen':'#98fb98', 'paleturquoise':'#afeeee', 'palevioletred':'#d87093', 'papayawhip':'#ffefd5', 'peachpuff':'#ffdab9', 'peru':'#cd853f', 'pink':'#ffc0cb', 'plum':'#dda0dd', 'powderblue':'#b0e0e6', 'purple':'#800080', 'red':'#ff0000', 'rosybrown':'#bc8f8f', 'royalblue':'#4169e1', 'saddlebrown':'#8b4513', 'salmon':'#fa8072', 'sandybrown':'#f4a460', 'seagreen':'#2e8b57', 'seashell':'#fff5ee', 'sienna':'#a0522d', 'silver':'#c0c0c0', 'skyblue':'#87ceeb', 'slateblue':'#6a5acd', 'slategray':'#708090', 'slategrey':'#708090', 'snow':'#fffafa', 'springgreen':'#00ff7f', 'steelblue':'#4682b4', 'tan':'#d2b48c', 'teal':'#008080', 'thistle':'#d8bfd8', 'tomato':'#ff6347', // 'transparent':'rgba(0,0,0,0)', 'turquoise':'#40e0d0', 'violet':'#ee82ee', 'wheat':'#f5deb3', 'white':'#ffffff', 'whitesmoke':'#f5f5f5', 'yellow':'#ffff00', 'yellowgreen':'#9acd32' }; })(require('./tree')); (function (tree) { tree.Alpha = function (val) { this.value = val; }; tree.Alpha.prototype = { toCSS: function () { return "alpha(opacity=" + (this.value.toCSS ? this.value.toCSS() : this.value) + ")"; }, eval: function (env) { if (this.value.eval) { this.value = this.value.eval(env) } return this; } }; })(require('../tree')); (function (tree) { tree.Anonymous = function (string) { this.value = string.value || string; }; tree.Anonymous.prototype = { toCSS: function () { return this.value; }, eval: function () { return this }, compare: function (x) { if (!x.toCSS) { return -1; } var left = this.toCSS(), right = x.toCSS(); if (left === right) { return 0; } return left < right ? -1 : 1; } }; })(require('../tree')); (function (tree) { tree.Assignment = function (key, val) { this.key = key; this.value = val; }; tree.Assignment.prototype = { toCSS: function () { return this.key + '=' + (this.value.toCSS ? this.value.toCSS() : this.value); }, eval: function (env) { if (this.value.eval) { return new(tree.Assignment)(this.key, this.value.eval(env)); } return this; } }; })(require('../tree'));(function (tree) { // // A function call node. // tree.Call = function (name, args, index, filename) { this.name = name; this.args = args; this.index = index; this.filename = filename; }; tree.Call.prototype = { // // When evaluating a function call, // we either find the function in `tree.functions` [1], // in which case we call it, passing the evaluated arguments, // or we simply print it out as it appeared originally [2]. // // The *functions.js* file contains the built-in functions. // // The reason why we evaluate the arguments, is in the case where // we try to pass a variable to a function, like: `saturate(@color)`. // The function should receive the value, not the variable. // eval: function (env) { var args = this.args.map(function (a) { return a.eval(env) }); if (this.name in tree.functions) { // 1. try { return tree.functions[this.name].apply(tree.functions, args); } catch (e) { throw { type: e.type || "Runtime", message: "error evaluating function `" + this.name + "`" + (e.message ? ': ' + e.message : ''), index: this.index, filename: this.filename }; } } else { // 2. return new(tree.Anonymous)(this.name + "(" + args.map(function (a) { return a.toCSS(env) }).join(', ') + ")"); } }, toCSS: function (env) { return this.eval(env).toCSS(); } }; })(require('../tree')); (function (tree) { // // RGB Colors - #ff0014, #eee // tree.Color = function (rgb, a) { // // The end goal here, is to parse the arguments // into an integer triplet, such as `128, 255, 0` // // This facilitates operations and conversions. // if (Array.isArray(rgb)) { this.rgb = rgb; } else if (rgb.length == 6) { this.rgb = rgb.match(/.{2}/g).map(function (c) { return parseInt(c, 16); }); } else { this.rgb = rgb.split('').map(function (c) { return parseInt(c + c, 16); }); } this.alpha = typeof(a) === 'number' ? a : 1; }; tree.Color.prototype = { eval: function () { return this }, // // If we have some transparency, the only way to represent it // is via `rgba`. Otherwise, we use the hex representation, // which has better compatibility with older browsers. // Values are capped between `0` and `255`, rounded and zero-padded. // toCSS: function () { if (this.alpha < 1.0) { return "rgba(" + this.rgb.map(function (c) { return Math.round(c); }).concat(this.alpha).join(', ') + ")"; } else { return '#' + this.rgb.map(function (i) { i = Math.round(i); i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16); return i.length === 1 ? '0' + i : i; }).join(''); } }, // // Operations have to be done per-channel, if not, // channels will spill onto each other. Once we have // our result, in the form of an integer triplet, // we create a new Color node to hold the result. // operate: function (op, other) { var result = []; if (! (other instanceof tree.Color)) { other = other.toColor(); } for (var c = 0; c < 3; c++) { result[c] = tree.operate(op, this.rgb[c], other.rgb[c]); } return new(tree.Color)(result, this.alpha + other.alpha); }, toHSL: function () { var r = this.rgb[0] / 255, g = this.rgb[1] / 255, b = this.rgb[2] / 255, a = this.alpha; var max = Math.max(r, g, b), min = Math.min(r, g, b); var h, s, l = (max + min) / 2, d = max - min; if (max === min) { h = s = 0; } else { s = l > 0.5 ? d / (2 - max - min) : d / (max + min); switch (max) { case r: h = (g - b) / d + (g < b ? 6 : 0); break; case g: h = (b - r) / d + 2; break; case b: h = (r - g) / d + 4; break; } h /= 6; } return { h: h * 360, s: s, l: l, a: a }; }, toARGB: function () { var argb = [Math.round(this.alpha * 255)].concat(this.rgb); return '#' + argb.map(function (i) { i = Math.round(i); i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16); return i.length === 1 ? '0' + i : i; }).join(''); }, compare: function (x) { if (!x.rgb) { return -1; } return (x.rgb[0] === this.rgb[0] && x.rgb[1] === this.rgb[1] && x.rgb[2] === this.rgb[2] && x.alpha === this.alpha) ? 0 : -1; } }; })(require('../tree')); (function (tree) { tree.Comment = function (value, silent) { this.value = value; this.silent = !!silent; }; tree.Comment.prototype = { toCSS: function (env) { return env.compress ? '' : this.value; }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.Condition = function (op, l, r, i, negate) { this.op = op.trim(); this.lvalue = l; this.rvalue = r; this.index = i; this.negate = negate; }; tree.Condition.prototype.eval = function (env) { var a = this.lvalue.eval(env), b = this.rvalue.eval(env); var i = this.index, result; var result = (function (op) { switch (op) { case 'and': return a && b; case 'or': return a || b; default: if (a.compare) { result = a.compare(b); } else if (b.compare) { result = b.compare(a); } else { throw { type: "Type", message: "Unable to perform comparison", index: i }; } switch (result) { case -1: return op === '<' || op === '=<'; case 0: return op === '=' || op === '>=' || op === '=<'; case 1: return op === '>' || op === '>='; } } })(this.op); return this.negate ? !result : result; }; })(require('../tree')); (function (tree) { // // A number with a unit // tree.Dimension = function (value, unit) { this.value = parseFloat(value); this.unit = unit || null; }; tree.Dimension.prototype = { eval: function () { return this }, toColor: function () { return new(tree.Color)([this.value, this.value, this.value]); }, toCSS: function () { var css = this.value + this.unit; return css; }, // In an operation between two Dimensions, // we default to the first Dimension's unit, // so `1px + 2em` will yield `3px`. // In the future, we could implement some unit // conversions such that `100cm + 10mm` would yield // `101cm`. operate: function (op, other) { return new(tree.Dimension) (tree.operate(op, this.value, other.value), this.unit || other.unit); }, // TODO: Perform unit conversion before comparing compare: function (other) { if (other instanceof tree.Dimension) { if (other.value > this.value) { return -1; } else if (other.value < this.value) { return 1; } else { return 0; } } else { return -1; } } }; })(require('../tree')); (function (tree) { tree.Directive = function (name, value) { this.name = name; if (Array.isArray(value)) { this.ruleset = new(tree.Ruleset)([], value); this.ruleset.allowImports = true; } else { this.value = value; } }; tree.Directive.prototype = { toCSS: function (ctx, env) { if (this.ruleset) { this.ruleset.root = true; return this.name + (env.compress ? '{' : ' {\n ') + this.ruleset.toCSS(ctx, env).trim().replace(/\n/g, '\n ') + (env.compress ? '}': '\n}\n'); } else { return this.name + ' ' + this.value.toCSS() + ';\n'; } }, eval: function (env) { var evaldDirective = this; if (this.ruleset) { env.frames.unshift(this); evaldDirective = new(tree.Directive)(this.name); evaldDirective.ruleset = this.ruleset.eval(env); env.frames.shift(); } return evaldDirective; }, variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) }, find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) }, rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) } }; })(require('../tree')); (function (tree) { tree.Element = function (combinator, value, index) { this.combinator = combinator instanceof tree.Combinator ? combinator : new(tree.Combinator)(combinator); if (typeof(value) === 'string') { this.value = value.trim(); } else if (value) { this.value = value; } else { this.value = ""; } this.index = index; }; tree.Element.prototype.eval = function (env) { return new(tree.Element)(this.combinator, this.value.eval ? this.value.eval(env) : this.value, this.index); }; tree.Element.prototype.toCSS = function (env) { var value = (this.value.toCSS ? this.value.toCSS(env) : this.value); if (value == '' && this.combinator.value.charAt(0) == '&') { return ''; } else { return this.combinator.toCSS(env || {}) + value; } }; tree.Combinator = function (value) { if (value === ' ') { this.value = ' '; } else { this.value = value ? value.trim() : ""; } }; tree.Combinator.prototype.toCSS = function (env) { return { '' : '', ' ' : ' ', ':' : ' :', '+' : env.compress ? '+' : ' + ', '~' : env.compress ? '~' : ' ~ ', '>' : env.compress ? '>' : ' > ' }[this.value]; }; })(require('../tree')); (function (tree) { tree.Expression = function (value) { this.value = value }; tree.Expression.prototype = { eval: function (env) { if (this.value.length > 1) { return new(tree.Expression)(this.value.map(function (e) { return e.eval(env); })); } else if (this.value.length === 1) { return this.value[0].eval(env); } else { return this; } }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS ? e.toCSS(env) : ''; }).join(' '); } }; })(require('../tree')); (function (tree) { // // CSS @import node // // The general strategy here is that we don't want to wait // for the parsing to be completed, before we start importing // the file. That's because in the context of a browser, // most of the time will be spent waiting for the server to respond. // // On creation, we push the import path to our import queue, though // `import,push`, we also pass it a callback, which it'll call once // the file has been fetched, and parsed. // tree.Import = function (path, imports, features, once, index) { var that = this; this.once = once; this.index = index; this._path = path; this.features = features && new(tree.Value)(features); // The '.less' extension is optional if (path instanceof tree.Quoted) { this.path = /\.(le?|c)ss(\?.*)?$/.test(path.value) ? path.value : path.value + '.less'; } else { this.path = path.value.value || path.value; } this.css = /css(\?.*)?$/.test(this.path); // Only pre-compile .less files if (! this.css) { imports.push(this.path, function (e, root, imported) { if (e) { e.index = index } if (imported && that.once) that.skip = imported; that.root = root || new(tree.Ruleset)([], []); }); } }; // // The actual import node doesn't return anything, when converted to CSS. // The reason is that it's used at the evaluation stage, so that the rules // it imports can be treated like any other rules. // // In `eval`, we make sure all Import nodes get evaluated, recursively, so // we end up with a flat structure, which can easily be imported in the parent // ruleset. // tree.Import.prototype = { toCSS: function (env) { var features = this.features ? ' ' + this.features.toCSS(env) : ''; if (this.css) { return "@import " + this._path.toCSS() + features + ';\n'; } else { return ""; } }, eval: function (env) { var ruleset, features = this.features && this.features.eval(env); if (this.skip) return []; if (this.css) { return this; } else { ruleset = new(tree.Ruleset)([], this.root.rules.slice(0)); for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.Import) { Array.prototype .splice .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env))); } } return this.features ? new(tree.Media)(ruleset.rules, this.features.value) : ruleset.rules; } } }; })(require('../tree')); (function (tree) { tree.JavaScript = function (string, index, escaped) { this.escaped = escaped; this.expression = string; this.index = index; }; tree.JavaScript.prototype = { eval: function (env) { var result, that = this, context = {}; var expression = this.expression.replace(/@\{([\w-]+)\}/g, function (_, name) { return tree.jsify(new(tree.Variable)('@' + name, that.index).eval(env)); }); try { expression = new(Function)('return (' + expression + ')'); } catch (e) { throw { message: "JavaScript evaluation error: `" + expression + "`" , index: this.index }; } for (var k in env.frames[0].variables()) { context[k.slice(1)] = { value: env.frames[0].variables()[k].value, toJS: function () { return this.value.eval(env).toCSS(); } }; } try { result = expression.call(context); } catch (e) { throw { message: "JavaScript evaluation error: '" + e.name + ': ' + e.message + "'" , index: this.index }; } if (typeof(result) === 'string') { return new(tree.Quoted)('"' + result + '"', result, this.escaped, this.index); } else if (Array.isArray(result)) { return new(tree.Anonymous)(result.join(', ')); } else { return new(tree.Anonymous)(result); } } }; })(require('../tree')); (function (tree) { tree.Keyword = function (value) { this.value = value }; tree.Keyword.prototype = { eval: function () { return this }, toCSS: function () { return this.value }, compare: function (other) { if (other instanceof tree.Keyword) { return other.value === this.value ? 0 : 1; } else { return -1; } } }; tree.True = new(tree.Keyword)('true'); tree.False = new(tree.Keyword)('false'); })(require('../tree')); (function (tree) { tree.Media = function (value, features) { var selectors = this.emptySelectors(); this.features = new(tree.Value)(features); this.ruleset = new(tree.Ruleset)(selectors, value); this.ruleset.allowImports = true; }; tree.Media.prototype = { toCSS: function (ctx, env) { var features = this.features.toCSS(env); this.ruleset.root = (ctx.length === 0 || ctx[0].multiMedia); return '@media ' + features + (env.compress ? '{' : ' {\n ') + this.ruleset.toCSS(ctx, env).trim().replace(/\n/g, '\n ') + (env.compress ? '}': '\n}\n'); }, eval: function (env) { if (!env.mediaBlocks) { env.mediaBlocks = []; env.mediaPath = []; } var blockIndex = env.mediaBlocks.length; env.mediaPath.push(this); env.mediaBlocks.push(this); var media = new(tree.Media)([], []); if(this.debugInfo) { this.ruleset.debugInfo = this.debugInfo; media.debugInfo = this.debugInfo; } media.features = this.features.eval(env); env.frames.unshift(this.ruleset); media.ruleset = this.ruleset.eval(env); env.frames.shift(); env.mediaBlocks[blockIndex] = media; env.mediaPath.pop(); return env.mediaPath.length === 0 ? media.evalTop(env) : media.evalNested(env) }, variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) }, find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) }, rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) }, emptySelectors: function() { var el = new(tree.Element)('', '&', 0); return [new(tree.Selector)([el])]; }, evalTop: function (env) { var result = this; // Render all dependent Media blocks. if (env.mediaBlocks.length > 1) { var selectors = this.emptySelectors(); result = new(tree.Ruleset)(selectors, env.mediaBlocks); result.multiMedia = true; } delete env.mediaBlocks; delete env.mediaPath; return result; }, evalNested: function (env) { var i, value, path = env.mediaPath.concat([this]); // Extract the media-query conditions separated with `,` (OR). for (i = 0; i < path.length; i++) { value = path[i].features instanceof tree.Value ? path[i].features.value : path[i].features; path[i] = Array.isArray(value) ? value : [value]; } // Trace all permutations to generate the resulting media-query. // // (a, b and c) with nested (d, e) -> // a and d // a and e // b and c and d // b and c and e this.features = new(tree.Value)(this.permute(path).map(function (path) { path = path.map(function (fragment) { return fragment.toCSS ? fragment : new(tree.Anonymous)(fragment); }); for(i = path.length - 1; i > 0; i--) { path.splice(i, 0, new(tree.Anonymous)("and")); } return new(tree.Expression)(path); })); // Fake a tree-node that doesn't output anything. return new(tree.Ruleset)([], []); }, permute: function (arr) { if (arr.length === 0) { return []; } else if (arr.length === 1) { return arr[0]; } else { var result = []; var rest = this.permute(arr.slice(1)); for (var i = 0; i < rest.length; i++) { for (var j = 0; j < arr[0].length; j++) { result.push([arr[0][j]].concat(rest[i])); } } return result; } }, bubbleSelectors: function (selectors) { this.ruleset = new(tree.Ruleset)(selectors.slice(0), [this.ruleset]); } }; })(require('../tree')); (function (tree) { tree.mixin = {}; tree.mixin.Call = function (elements, args, index, filename, important) { this.selector = new(tree.Selector)(elements); this.arguments = args; this.index = index; this.filename = filename; this.important = important; }; tree.mixin.Call.prototype = { eval: function (env) { var mixins, args, rules = [], match = false; for (var i = 0; i < env.frames.length; i++) { if ((mixins = env.frames[i].find(this.selector)).length > 0) { args = this.arguments && this.arguments.map(function (a) { return { name: a.name, value: a.value.eval(env) }; }); for (var m = 0; m < mixins.length; m++) { if (mixins[m].match(args, env)) { try { Array.prototype.push.apply( rules, mixins[m].eval(env, this.arguments, this.important).rules); match = true; } catch (e) { throw { message: e.message, index: this.index, filename: this.filename, stack: e.stack }; } } } if (match) { return rules; } else { throw { type: 'Runtime', message: 'No matching definition was found for `' + this.selector.toCSS().trim() + '(' + this.arguments.map(function (a) { return a.toCSS(); }).join(', ') + ")`", index: this.index, filename: this.filename }; } } } throw { type: 'Name', message: this.selector.toCSS().trim() + " is undefined", index: this.index, filename: this.filename }; } }; tree.mixin.Definition = function (name, params, rules, condition, variadic) { this.name = name; this.selectors = [new(tree.Selector)([new(tree.Element)(null, name)])]; this.params = params; this.condition = condition; this.variadic = variadic; this.arity = params.length; this.rules = rules; this._lookups = {}; this.required = params.reduce(function (count, p) { if (!p.name || (p.name && !p.value)) { return count + 1 } else { return count } }, 0); this.parent = tree.Ruleset.prototype; this.frames = []; }; tree.mixin.Definition.prototype = { toCSS: function () { return "" }, variable: function (name) { return this.parent.variable.call(this, name) }, variables: function () { return this.parent.variables.call(this) }, find: function () { return this.parent.find.apply(this, arguments) }, rulesets: function () { return this.parent.rulesets.apply(this) }, evalParams: function (env, args) { var frame = new(tree.Ruleset)(null, []), varargs, arg; for (var i = 0, val, name; i < this.params.length; i++) { arg = args && args[i] if (arg && arg.name) { frame.rules.unshift(new(tree.Rule)(arg.name, arg.value.eval(env))); args.splice(i, 1); i--; continue; } if (name = this.params[i].name) { if (this.params[i].variadic && args) { varargs = []; for (var j = i; j < args.length; j++) { varargs.push(args[j].value.eval(env)); } frame.rules.unshift(new(tree.Rule)(name, new(tree.Expression)(varargs).eval(env))); } else if (val = (arg && arg.value) || this.params[i].value) { frame.rules.unshift(new(tree.Rule)(name, val.eval(env))); } else { throw { type: 'Runtime', message: "wrong number of arguments for " + this.name + ' (' + args.length + ' for ' + this.arity + ')' }; } } } return frame; }, eval: function (env, args, important) { var frame = this.evalParams(env, args), context, _arguments = [], rules, start; for (var i = 0; i < Math.max(this.params.length, args && args.length); i++) { _arguments.push((args[i] && args[i].value) || this.params[i].value); } frame.rules.unshift(new(tree.Rule)('@arguments', new(tree.Expression)(_arguments).eval(env))); rules = important ? this.rules.map(function (r) { return new(tree.Rule)(r.name, r.value, '!important', r.index); }) : this.rules.slice(0); return new(tree.Ruleset)(null, rules).eval({ frames: [this, frame].concat(this.frames, env.frames) }); }, match: function (args, env) { var argsLength = (args && args.length) || 0, len, frame; if (! this.variadic) { if (argsLength < this.required) { return false } if (argsLength > this.params.length) { return false } if ((this.required > 0) && (argsLength > this.params.length)) { return false } } if (this.condition && !this.condition.eval({ frames: [this.evalParams(env, args)].concat(env.frames) })) { return false } len = Math.min(argsLength, this.arity); for (var i = 0; i < len; i++) { if (!this.params[i].name) { if (args[i].value.eval(env).toCSS() != this.params[i].value.eval(env).toCSS()) { return false; } } } return true; } }; })(require('../tree')); (function (tree) { tree.Operation = function (op, operands) { this.op = op.trim(); this.operands = operands; }; tree.Operation.prototype.eval = function (env) { var a = this.operands[0].eval(env), b = this.operands[1].eval(env), temp; if (a instanceof tree.Dimension && b instanceof tree.Color) { if (this.op === '*' || this.op === '+') { temp = b, b = a, a = temp; } else { throw { name: "OperationError", message: "Can't substract or divide a color from a number" }; } } return a.operate(this.op, b); }; tree.operate = function (op, a, b) { switch (op) { case '+': return a + b; case '-': return a - b; case '*': return a * b; case '/': return a / b; } }; })(require('../tree')); (function (tree) { tree.Paren = function (node) { this.value = node; }; tree.Paren.prototype = { toCSS: function (env) { return '(' + this.value.toCSS(env) + ')'; }, eval: function (env) { return new(tree.Paren)(this.value.eval(env)); } }; })(require('../tree')); (function (tree) { tree.Quoted = function (str, content, escaped, i) { this.escaped = escaped; this.value = content || ''; this.quote = str.charAt(0); this.index = i; }; tree.Quoted.prototype = { toCSS: function () { if (this.escaped) { return this.value; } else { return this.quote + this.value + this.quote; } }, eval: function (env) { var that = this; var value = this.value.replace(/`([^`]+)`/g, function (_, exp) { return new(tree.JavaScript)(exp, that.index, true).eval(env).value; }).replace(/@\{([\w-]+)\}/g, function (_, name) { var v = new(tree.Variable)('@' + name, that.index).eval(env); return ('value' in v) ? v.value : v.toCSS(); }); return new(tree.Quoted)(this.quote + value + this.quote, value, this.escaped, this.index); }, compare: function (x) { if (!x.toCSS) { return -1; } var left = this.toCSS(), right = x.toCSS(); if (left === right) { return 0; } return left < right ? -1 : 1; } }; })(require('../tree')); (function (tree) { tree.Ratio = function (value) { this.value = value; }; tree.Ratio.prototype = { toCSS: function (env) { return this.value; }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.Rule = function (name, value, important, index, inline) { this.name = name; this.value = (value instanceof tree.Value) ? value : new(tree.Value)([value]); this.important = important ? ' ' + important.trim() : ''; this.index = index; this.inline = inline || false; if (name.charAt(0) === '@') { this.variable = true; } else { this.variable = false } }; tree.Rule.prototype.toCSS = function (env) { if (this.variable) { return "" } else { return this.name + (env.compress ? ':' : ': ') + this.value.toCSS(env) + this.important + (this.inline ? "" : ";"); } }; tree.Rule.prototype.eval = function (context) { return new(tree.Rule)(this.name, this.value.eval(context), this.important, this.index, this.inline); }; tree.Shorthand = function (a, b) { this.a = a; this.b = b; }; tree.Shorthand.prototype = { toCSS: function (env) { return this.a.toCSS(env) + "/" + this.b.toCSS(env); }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.Ruleset = function (selectors, rules, strictImports) { this.selectors = selectors; this.rules = rules; this._lookups = {}; this.strictImports = strictImports; }; tree.Ruleset.prototype = { eval: function (env) { var selectors = this.selectors && this.selectors.map(function (s) { return s.eval(env) }); var ruleset = new(tree.Ruleset)(selectors, this.rules.slice(0), this.strictImports); var rules = []; ruleset.root = this.root; ruleset.allowImports = this.allowImports; if(this.debugInfo) { ruleset.debugInfo = this.debugInfo; } // push the current ruleset to the frames stack env.frames.unshift(ruleset); // Evaluate imports if (ruleset.root || ruleset.allowImports || !ruleset.strictImports) { for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.Import) { rules = rules.concat(ruleset.rules[i].eval(env)); } else { rules.push(ruleset.rules[i]); } } ruleset.rules = rules; rules = []; } // Store the frames around mixin definitions, // so they can be evaluated like closures when the time comes. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Definition) { ruleset.rules[i].frames = env.frames.slice(0); } } var mediaBlockCount = (env.mediaBlocks && env.mediaBlocks.length) || 0; // Evaluate mixin calls. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Call) { rules = rules.concat(ruleset.rules[i].eval(env)); } else { rules.push(ruleset.rules[i]); } } ruleset.rules = rules; // Evaluate everything else for (var i = 0, rule; i < ruleset.rules.length; i++) { rule = ruleset.rules[i]; if (! (rule instanceof tree.mixin.Definition)) { ruleset.rules[i] = rule.eval ? rule.eval(env) : rule; } } // Pop the stack env.frames.shift(); if (env.mediaBlocks) { for(var i = mediaBlockCount; i < env.mediaBlocks.length; i++) { env.mediaBlocks[i].bubbleSelectors(selectors); } } return ruleset; }, match: function (args) { return !args || args.length === 0; }, variables: function () { if (this._variables) { return this._variables } else { return this._variables = this.rules.reduce(function (hash, r) { if (r instanceof tree.Rule && r.variable === true) { hash[r.name] = r; } return hash; }, {}); } }, variable: function (name) { return this.variables()[name]; }, rulesets: function () { if (this._rulesets) { return this._rulesets } else { return this._rulesets = this.rules.filter(function (r) { return (r instanceof tree.Ruleset) || (r instanceof tree.mixin.Definition); }); } }, find: function (selector, self) { self = self || this; var rules = [], rule, match, key = selector.toCSS(); if (key in this._lookups) { return this._lookups[key] } this.rulesets().forEach(function (rule) { if (rule !== self) { for (var j = 0; j < rule.selectors.length; j++) { if (match = selector.match(rule.selectors[j])) { if (selector.elements.length > rule.selectors[j].elements.length) { Array.prototype.push.apply(rules, rule.find( new(tree.Selector)(selector.elements.slice(1)), self)); } else { rules.push(rule); } break; } } } }); return this._lookups[key] = rules; }, // // Entry point for code generation // // `context` holds an array of arrays. // toCSS: function (context, env) { var css = [], // The CSS output rules = [], // node.Rule instances _rules = [], // rulesets = [], // node.Ruleset instances paths = [], // Current selectors selector, // The fully rendered selector debugInfo, // Line number debugging rule; if (! this.root) { this.joinSelectors(paths, context, this.selectors); } // Compile rules and rulesets for (var i = 0; i < this.rules.length; i++) { rule = this.rules[i]; if (rule.rules || (rule instanceof tree.Directive) || (rule instanceof tree.Media)) { rulesets.push(rule.toCSS(paths, env)); } else if (rule instanceof tree.Comment) { if (!rule.silent) { if (this.root) { rulesets.push(rule.toCSS(env)); } else { rules.push(rule.toCSS(env)); } } } else { if (rule.toCSS && !rule.variable) { rules.push(rule.toCSS(env)); } else if (rule.value && !rule.variable) { rules.push(rule.value.toString()); } } } rulesets = rulesets.join(''); // If this is the root node, we don't render // a selector, or {}. // Otherwise, only output if this ruleset has rules. if (this.root) { css.push(rules.join(env.compress ? '' : '\n')); } else { if (rules.length > 0) { debugInfo = tree.debugInfo(env, this); selector = paths.map(function (p) { return p.map(function (s) { return s.toCSS(env); }).join('').trim(); }).join(env.compress ? ',' : ',\n'); // Remove duplicates for (var i = rules.length - 1; i >= 0; i--) { if (_rules.indexOf(rules[i]) === -1) { _rules.unshift(rules[i]); } } rules = _rules; css.push(debugInfo + selector + (env.compress ? '{' : ' {\n ') + rules.join(env.compress ? '' : '\n ') + (env.compress ? '}' : '\n}\n')); } } css.push(rulesets); return css.join('') + (env.compress ? '\n' : ''); }, joinSelectors: function (paths, context, selectors) { for (var s = 0; s < selectors.length; s++) { this.joinSelector(paths, context, selectors[s]); } }, joinSelector: function (paths, context, selector) { var i, j, k, hasParentSelector, newSelectors, el, sel, parentSel, newSelectorPath, afterParentJoin, newJoinedSelector, newJoinedSelectorEmpty, lastSelector, currentElements, selectorsMultiplied; for (i = 0; i < selector.elements.length; i++) { el = selector.elements[i]; if (el.value === '&') { hasParentSelector = true; } } if (!hasParentSelector) { if (context.length > 0) { for(i = 0; i < context.length; i++) { paths.push(context[i].concat(selector)); } } else { paths.push([selector]); } return; } // The paths are [[Selector]] // The first list is a list of comma seperated selectors // The inner list is a list of inheritance seperated selectors // e.g. // .a, .b { // .c { // } // } // == [[.a] [.c]] [[.b] [.c]] // // the elements from the current selector so far currentElements = []; // the current list of new selectors to add to the path. // We will build it up. We initiate it with one empty selector as we "multiply" the new selectors // by the parents newSelectors = [[]]; for (i = 0; i < selector.elements.length; i++) { el = selector.elements[i]; // non parent reference elements just get added if (el.value !== "&") { currentElements.push(el); } else { // the new list of selectors to add selectorsMultiplied = []; // merge the current list of non parent selector elements // on to the current list of selectors to add if (currentElements.length > 0) { this.mergeElementsOnToSelectors(currentElements, newSelectors); } // loop through our current selectors for(j = 0; j < newSelectors.length; j++) { sel = newSelectors[j]; // if we don't have any parent paths, the & might be in a mixin so that it can be used // whether there are parents or not if (context.length == 0) { // the combinator used on el should now be applied to the next element instead so that // it is not lost if (sel.length > 0) { sel[0].elements = sel[0].elements.slice(0); sel[0].elements.push(new(tree.Element)(el.combinator, '', 0)); //new Element(el.Combinator, "")); } selectorsMultiplied.push(sel); } else { // and the parent selectors for(k = 0; k < context.length; k++) { parentSel = context[k]; // We need to put the current selectors // then join the last selector's elements on to the parents selectors // our new selector path newSelectorPath = []; // selectors from the parent after the join afterParentJoin = []; newJoinedSelectorEmpty = true; //construct the joined selector - if & is the first thing this will be empty, // if not newJoinedSelector will be the last set of elements in the selector if (sel.length > 0) { newSelectorPath = sel.slice(0); lastSelector = newSelectorPath.pop(); newJoinedSelector = new(tree.Selector)(lastSelector.elements.slice(0)); newJoinedSelectorEmpty = false; } else { newJoinedSelector = new(tree.Selector)([]); } //put together the parent selectors after the join if (parentSel.length > 1) { afterParentJoin = afterParentJoin.concat(parentSel.slice(1)); } if (parentSel.length > 0) { newJoinedSelectorEmpty = false; // join the elements so far with the first part of the parent newJoinedSelector.elements.push(new(tree.Element)(el.combinator, parentSel[0].elements[0].value, 0)); newJoinedSelector.elements = newJoinedSelector.elements.concat(parentSel[0].elements.slice(1)); } if (!newJoinedSelectorEmpty) { // now add the joined selector newSelectorPath.push(newJoinedSelector); } // and the rest of the parent newSelectorPath = newSelectorPath.concat(afterParentJoin); // add that to our new set of selectors selectorsMultiplied.push(newSelectorPath); } } } // our new selectors has been multiplied, so reset the state newSelectors = selectorsMultiplied; currentElements = []; } } // if we have any elements left over (e.g. .a& .b == .b) // add them on to all the current selectors if (currentElements.length > 0) { this.mergeElementsOnToSelectors(currentElements, newSelectors); } for(i = 0; i < newSelectors.length; i++) { paths.push(newSelectors[i]); } }, mergeElementsOnToSelectors: function(elements, selectors) { var i, sel; if (selectors.length == 0) { selectors.push([ new(tree.Selector)(elements) ]); return; } for(i = 0; i < selectors.length; i++) { sel = selectors[i]; // if the previous thing in sel is a parent this needs to join on to it if (sel.length > 0) { sel[sel.length - 1] = new(tree.Selector)(sel[sel.length - 1].elements.concat(elements)); } else { sel.push(new(tree.Selector)(elements)); } } } }; })(require('../tree')); (function (tree) { tree.Selector = function (elements) { this.elements = elements; }; tree.Selector.prototype.match = function (other) { var len = this.elements.length, olen = other.elements.length, max = Math.min(len, olen); if (len < olen) { return false; } else { for (var i = 0; i < max; i++) { if (this.elements[i].value !== other.elements[i].value) { return false; } } } return true; }; tree.Selector.prototype.eval = function (env) { return new(tree.Selector)(this.elements.map(function (e) { return e.eval(env); })); }; tree.Selector.prototype.toCSS = function (env) { if (this._css) { return this._css } if (this.elements[0].combinator.value === "") { this._css = ' '; } else { this._css = ''; } this._css += this.elements.map(function (e) { if (typeof(e) === 'string') { return ' ' + e.trim(); } else { return e.toCSS(env); } }).join(''); return this._css; }; })(require('../tree')); (function (tree) { tree.URL = function (val, paths) { this.value = val; this.paths = paths; }; tree.URL.prototype = { toCSS: function () { return "url(" + this.value.toCSS() + ")"; }, eval: function (ctx) { var val = this.value.eval(ctx); // Add the base path if the URL is relative and we are in the browser if (typeof window !== 'undefined' && typeof val.value === "string" && !/^(?:[a-z-]+:|\/)/.test(val.value) && this.paths.length > 0) { val.value = this.paths[0] + (val.value.charAt(0) === '/' ? val.value.slice(1) : val.value); } return new(tree.URL)(val, this.paths); } }; })(require('../tree')); (function (tree) { tree.Value = function (value) { this.value = value; this.is = 'value'; }; tree.Value.prototype = { eval: function (env) { if (this.value.length === 1) { return this.value[0].eval(env); } else { return new(tree.Value)(this.value.map(function (v) { return v.eval(env); })); } }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS(env); }).join(env.compress ? ',' : ', '); } }; })(require('../tree')); (function (tree) { tree.Variable = function (name, index, file) { this.name = name, this.index = index, this.file = file }; tree.Variable.prototype = { eval: function (env) { var variable, v, name = this.name; if (name.indexOf('@@') == 0) { name = '@' + new(tree.Variable)(name.slice(1)).eval(env).value; } if (variable = tree.find(env.frames, function (frame) { if (v = frame.variable(name)) { return v.value.eval(env); } })) { return variable } else { throw { type: 'Name', message: "variable " + name + " is undefined", filename: this.file, index: this.index }; } } }; })(require('../tree')); (function (tree) { tree.debugInfo = function(env, ctx) { var result=""; if (env.dumpLineNumbers && !env.compress) { switch(env.dumpLineNumbers) { case 'comments': result = tree.debugInfo.asComment(ctx); break; case 'mediaquery': result = tree.debugInfo.asMediaQuery(ctx); break; case 'all': result = tree.debugInfo.asComment(ctx)+tree.debugInfo.asMediaQuery(ctx); break; } } return result; }; tree.debugInfo.asComment = function(ctx) { return '/* line ' + ctx.debugInfo.lineNumber + ', ' + ctx.debugInfo.fileName + ' */\n'; }; tree.debugInfo.asMediaQuery = function(ctx) { return '@media -sass-debug-info{filename{font-family:"' + ctx.debugInfo.fileName + '";}line{font-family:"' + ctx.debugInfo.lineNumber + '";}}\n'; }; tree.find = function (obj, fun) { for (var i = 0, r; i < obj.length; i++) { if (r = fun.call(obj, obj[i])) { return r } } return null; }; tree.jsify = function (obj) { if (Array.isArray(obj.value) && (obj.value.length > 1)) { return '[' + obj.value.map(function (v) { return v.toCSS(false) }).join(', ') + ']'; } else { return obj.toCSS(false); } }; })(require('./tree')); var name; function loadStyleSheet(sheet, callback, reload, remaining) { var endOfPath = Math.max(name.lastIndexOf('/'), name.lastIndexOf('\\')), sheetName = name.slice(0, endOfPath + 1) + sheet.href, contents = sheet.contents || {}, input = readFile(sheetName); contents[sheetName] = input; var parser = new less.Parser({ paths: [sheet.href.replace(/[\w\.-]+$/, '')], contents: contents }); parser.parse(input, function (e, root) { if (e) { return error(e, sheetName); } try { callback(e, root, sheet, { local: false, lastModified: 0, remaining: remaining }); } catch(e) { error(e, sheetName); } }); } function writeFile(filename, content) { var fstream = new java.io.FileWriter(filename); var out = new java.io.BufferedWriter(fstream); out.write(content); out.close(); } // Command line integration via Rhino (function (args) { var output, compress = false, i; for(i = 0; i < args.length; i++) { switch(args[i]) { case "-x": compress = true; break; default: if (!name) { name = args[i]; } else if (!output) { output = args[i]; } else { print("unrecognised parameters"); print("input_file [output_file] [-x]"); } } } if (!name) { print('No files present in the fileset; Check your pattern match in build.xml'); quit(1); } path = name.split("/");path.pop();path=path.join("/") var input = readFile(name); if (!input) { print('lesscss: couldn\'t open file ' + name); quit(1); } var result; try { var parser = new less.Parser(); parser.parse(input, function (e, root) { if (e) { error(e, name); quit(1); } else { result = root.toCSS({compress: compress || false}); if (output) { writeFile(output, result); print("Written to " + output); } else { print(result); } quit(0); } }); } catch(e) { error(e, name); quit(1); } print("done"); }(arguments)); function error(e, filename) { var content = "Error : " + filename + "\n"; filename = e.filename || filename; if (e.message) { content += e.message + "\n"; } var errorline = function (e, i, classname) { if (e.extract[i]) { content += String(parseInt(e.line) + (i - 1)) + ":" + e.extract[i] + "\n"; } }; if (e.stack) { content += e.stack; } else if (e.extract) { content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':\n'; errorline(e, 0); errorline(e, 1); errorline(e, 2); } print(content); }less.js-1.4.2/dist/less-rhino-1.3.2.js000066400000000000000000004132271217256642200171420ustar00rootroot00000000000000// // Stub out `require` in rhino // function require(arg) { return less[arg.split('/')[1]]; }; // ecma-5.js // // -- kriskowal Kris Kowal Copyright (C) 2009-2010 MIT License // -- tlrobinson Tom Robinson // dantman Daniel Friesen // // Array // if (!Array.isArray) { Array.isArray = function(obj) { return Object.prototype.toString.call(obj) === "[object Array]" || (obj instanceof Array); }; } if (!Array.prototype.forEach) { Array.prototype.forEach = function(block, thisObject) { var len = this.length >>> 0; for (var i = 0; i < len; i++) { if (i in this) { block.call(thisObject, this[i], i, this); } } }; } if (!Array.prototype.map) { Array.prototype.map = function(fun /*, thisp*/) { var len = this.length >>> 0; var res = new Array(len); var thisp = arguments[1]; for (var i = 0; i < len; i++) { if (i in this) { res[i] = fun.call(thisp, this[i], i, this); } } return res; }; } if (!Array.prototype.filter) { Array.prototype.filter = function (block /*, thisp */) { var values = []; var thisp = arguments[1]; for (var i = 0; i < this.length; i++) { if (block.call(thisp, this[i])) { values.push(this[i]); } } return values; }; } if (!Array.prototype.reduce) { Array.prototype.reduce = function(fun /*, initial*/) { var len = this.length >>> 0; var i = 0; // no value to return if no initial value and an empty array if (len === 0 && arguments.length === 1) throw new TypeError(); if (arguments.length >= 2) { var rv = arguments[1]; } else { do { if (i in this) { rv = this[i++]; break; } // if array contains no values, no initial value to return if (++i >= len) throw new TypeError(); } while (true); } for (; i < len; i++) { if (i in this) { rv = fun.call(null, rv, this[i], i, this); } } return rv; }; } if (!Array.prototype.indexOf) { Array.prototype.indexOf = function (value /*, fromIndex */ ) { var length = this.length; var i = arguments[1] || 0; if (!length) return -1; if (i >= length) return -1; if (i < 0) i += length; for (; i < length; i++) { if (!Object.prototype.hasOwnProperty.call(this, i)) { continue } if (value === this[i]) return i; } return -1; }; } // // Object // if (!Object.keys) { Object.keys = function (object) { var keys = []; for (var name in object) { if (Object.prototype.hasOwnProperty.call(object, name)) { keys.push(name); } } return keys; }; } // // String // if (!String.prototype.trim) { String.prototype.trim = function () { return String(this).replace(/^\s\s*/, '').replace(/\s\s*$/, ''); }; } var less, tree, charset; if (typeof environment === "object" && ({}).toString.call(environment) === "[object Environment]") { // Rhino // Details on how to detect Rhino: https://github.com/ringo/ringojs/issues/88 if (typeof(window) === 'undefined') { less = {} } else { less = window.less = {} } tree = less.tree = {}; less.mode = 'rhino'; } else if (typeof(window) === 'undefined') { // Node.js less = exports, tree = require('./tree'); less.mode = 'node'; } else { // Browser if (typeof(window.less) === 'undefined') { window.less = {} } less = window.less, tree = window.less.tree = {}; less.mode = 'browser'; } // // less.js - parser // // A relatively straight-forward predictive parser. // There is no tokenization/lexing stage, the input is parsed // in one sweep. // // To make the parser fast enough to run in the browser, several // optimization had to be made: // // - Matching and slicing on a huge input is often cause of slowdowns. // The solution is to chunkify the input into smaller strings. // The chunks are stored in the `chunks` var, // `j` holds the current chunk index, and `current` holds // the index of the current chunk in relation to `input`. // This gives us an almost 4x speed-up. // // - In many cases, we don't need to match individual tokens; // for example, if a value doesn't hold any variables, operations // or dynamic references, the parser can effectively 'skip' it, // treating it as a literal. // An example would be '1px solid #000' - which evaluates to itself, // we don't need to know what the individual components are. // The drawback, of course is that you don't get the benefits of // syntax-checking on the CSS. This gives us a 50% speed-up in the parser, // and a smaller speed-up in the code-gen. // // // Token matching is done with the `$` function, which either takes // a terminal string or regexp, or a non-terminal function to call. // It also takes care of moving all the indices forwards. // // less.Parser = function Parser(env) { var input, // LeSS input string i, // current index in `input` j, // current chunk temp, // temporarily holds a chunk's state, for backtracking memo, // temporarily holds `i`, when backtracking furthest, // furthest index the parser has gone to chunks, // chunkified input current, // index of current chunk, in `input` parser; var that = this; // Top parser on an import tree must be sure there is one "env" // which will then be passed arround by reference. var env = env || { }; // env.contents and files must be passed arround with top env if (!env.contents) { env.contents = {}; } env.rootpath = env.rootpath || ''; // env.rootpath must be initialized to '' if not provided if (!env.files) { env.files = {}; } // This function is called after all files // have been imported through `@import`. var finish = function () {}; var imports = this.imports = { paths: env.paths || [], // Search paths, when importing queue: [], // Files which haven't been imported yet files: env.files, // Holds the imported parse trees contents: env.contents, // Holds the imported file contents mime: env.mime, // MIME type of .less files error: null, // Error in parsing/evaluating an import push: function (path, callback) { var that = this; this.queue.push(path); // // Import a file asynchronously // less.Parser.importer(path, this.paths, function (e, root, fullPath) { that.queue.splice(that.queue.indexOf(path), 1); // Remove the path from the queue var imported = fullPath in that.files; that.files[fullPath] = root; // Store the root if (e && !that.error) { that.error = e } callback(e, root, imported); if (that.queue.length === 0) { finish(that.error) } // Call `finish` if we're done importing }, env); } }; function save() { temp = chunks[j], memo = i, current = i } function restore() { chunks[j] = temp, i = memo, current = i } function sync() { if (i > current) { chunks[j] = chunks[j].slice(i - current); current = i; } } function isWhitespace(c) { // Could change to \s? var code = c.charCodeAt(0); return code === 32 || code === 10 || code === 9; } // // Parse from a token, regexp or string, and move forward if match // function $(tok) { var match, args, length, index, k; // // Non-terminal // if (tok instanceof Function) { return tok.call(parser.parsers); // // Terminal // // Either match a single character in the input, // or match a regexp in the current chunk (chunk[j]). // } else if (typeof(tok) === 'string') { match = input.charAt(i) === tok ? tok : null; length = 1; sync (); } else { sync (); if (match = tok.exec(chunks[j])) { length = match[0].length; } else { return null; } } // The match is confirmed, add the match length to `i`, // and consume any extra white-space characters (' ' || '\n') // which come after that. The reason for this is that LeSS's // grammar is mostly white-space insensitive. // if (match) { skipWhitespace(length); if(typeof(match) === 'string') { return match; } else { return match.length === 1 ? match[0] : match; } } } function skipWhitespace(length) { var oldi = i, oldj = j, endIndex = i + chunks[j].length, mem = i += length; while (i < endIndex) { if (! isWhitespace(input.charAt(i))) { break } i++; } chunks[j] = chunks[j].slice(length + (i - mem)); current = i; if (chunks[j].length === 0 && j < chunks.length - 1) { j++ } return oldi !== i || oldj !== j; } function expect(arg, msg) { var result = $(arg); if (! result) { error(msg || (typeof(arg) === 'string' ? "expected '" + arg + "' got '" + input.charAt(i) + "'" : "unexpected token")); } else { return result; } } function error(msg, type) { var e = new Error(msg); e.index = i; e.type = type || 'Syntax'; throw e; } // Same as $(), but don't change the state of the parser, // just return the match. function peek(tok) { if (typeof(tok) === 'string') { return input.charAt(i) === tok; } else { if (tok.test(chunks[j])) { return true; } else { return false; } } } function getInput(e, env) { if (e.filename && env.filename && (e.filename !== env.filename)) { return parser.imports.contents[e.filename]; } else { return input; } } function getLocation(index, input) { for (var n = index, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } return { line: typeof(index) === 'number' ? (input.slice(0, index).match(/\n/g) || "").length : null, column: column }; } function getFileName(e) { if(less.mode === 'browser' || less.mode === 'rhino') return e.filename; else return require('path').resolve(e.filename); } function getDebugInfo(index, inputStream, e) { return { lineNumber: getLocation(index, inputStream).line + 1, fileName: getFileName(e) }; } function LessError(e, env) { var input = getInput(e, env), loc = getLocation(e.index, input), line = loc.line, col = loc.column, lines = input.split('\n'); this.type = e.type || 'Syntax'; this.message = e.message; this.filename = e.filename || env.filename; this.index = e.index; this.line = typeof(line) === 'number' ? line + 1 : null; this.callLine = e.call && (getLocation(e.call, input).line + 1); this.callExtract = lines[getLocation(e.call, input).line]; this.stack = e.stack; this.column = col; this.extract = [ lines[line - 1], lines[line], lines[line + 1] ]; } this.env = env = env || {}; // The optimization level dictates the thoroughness of the parser, // the lower the number, the less nodes it will create in the tree. // This could matter for debugging, or if you want to access // the individual nodes in the tree. this.optimization = ('optimization' in this.env) ? this.env.optimization : 1; this.env.filename = this.env.filename || null; // // The Parser // return parser = { imports: imports, // // Parse an input string into an abstract syntax tree, // call `callback` when done. // parse: function (str, callback) { var root, start, end, zone, line, lines, buff = [], c, error = null; i = j = current = furthest = 0; input = str.replace(/\r\n/g, '\n'); // Remove potential UTF Byte Order Mark input = input.replace(/^\uFEFF/, ''); // Split the input into chunks. chunks = (function (chunks) { var j = 0, skip = /(?:@\{[\w-]+\}|[^"'`\{\}\/\(\)\\])+/g, comment = /\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g, string = /"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'|`((?:[^`]|\\.)*)`/g, level = 0, match, chunk = chunks[0], inParam; for (var i = 0, c, cc; i < input.length;) { skip.lastIndex = i; if (match = skip.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); } } c = input.charAt(i); comment.lastIndex = string.lastIndex = i; if (match = string.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); continue; } } if (!inParam && c === '/') { cc = input.charAt(i + 1); if (cc === '/' || cc === '*') { if (match = comment.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); continue; } } } } switch (c) { case '{': if (! inParam) { level ++; chunk.push(c); break } case '}': if (! inParam) { level --; chunk.push(c); chunks[++j] = chunk = []; break } case '(': if (! inParam) { inParam = true; chunk.push(c); break } case ')': if ( inParam) { inParam = false; chunk.push(c); break } default: chunk.push(c); } i++; } if (level != 0) { error = new(LessError)({ index: i-1, type: 'Parse', message: (level > 0) ? "missing closing `}`" : "missing opening `{`", filename: env.filename }, env); } return chunks.map(function (c) { return c.join('') });; })([[]]); if (error) { return callback(error, env); } // Start with the primary rule. // The whole syntax tree is held under a Ruleset node, // with the `root` property set to true, so no `{}` are // output. The callback is called when the input is parsed. try { root = new(tree.Ruleset)([], $(this.parsers.primary)); root.root = true; } catch (e) { return callback(new(LessError)(e, env)); } root.toCSS = (function (evaluate) { var line, lines, column; return function (options, variables) { var frames = [], importError; options = options || {}; // // Allows setting variables with a hash, so: // // `{ color: new(tree.Color)('#f01') }` will become: // // new(tree.Rule)('@color', // new(tree.Value)([ // new(tree.Expression)([ // new(tree.Color)('#f01') // ]) // ]) // ) // if (typeof(variables) === 'object' && !Array.isArray(variables)) { variables = Object.keys(variables).map(function (k) { var value = variables[k]; if (! (value instanceof tree.Value)) { if (! (value instanceof tree.Expression)) { value = new(tree.Expression)([value]); } value = new(tree.Value)([value]); } return new(tree.Rule)('@' + k, value, false, 0); }); frames = [new(tree.Ruleset)(null, variables)]; } try { var css = evaluate.call(this, { frames: frames }) .toCSS([], { compress: options.compress || false, dumpLineNumbers: env.dumpLineNumbers }); } catch (e) { throw new(LessError)(e, env); } if ((importError = parser.imports.error)) { // Check if there was an error during importing if (importError instanceof LessError) throw importError; else throw new(LessError)(importError, env); } if (options.yuicompress && less.mode === 'node') { return require('ycssmin').cssmin(css); } else if (options.compress) { return css.replace(/(\s)+/g, "$1"); } else { return css; } }; })(root.eval); // If `i` is smaller than the `input.length - 1`, // it means the parser wasn't able to parse the whole // string, so we've got a parsing error. // // We try to extract a \n delimited string, // showing the line where the parse error occured. // We split it up into two parts (the part which parsed, // and the part which didn't), so we can color them differently. if (i < input.length - 1) { i = furthest; lines = input.split('\n'); line = (input.slice(0, i).match(/\n/g) || "").length + 1; for (var n = i, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } error = { type: "Parse", message: "Syntax Error on line " + line, index: i, filename: env.filename, line: line, column: column, extract: [ lines[line - 2], lines[line - 1], lines[line] ] }; } if (this.imports.queue.length > 0) { finish = function (e) { e = error || e; if (e) callback(e); else callback(null, root); }; } else { callback(error, root); } }, // // Here in, the parsing rules/functions // // The basic structure of the syntax tree generated is as follows: // // Ruleset -> Rule -> Value -> Expression -> Entity // // Here's some LESS code: // // .class { // color: #fff; // border: 1px solid #000; // width: @w + 4px; // > .child {...} // } // // And here's what the parse tree might look like: // // Ruleset (Selector '.class', [ // Rule ("color", Value ([Expression [Color #fff]])) // Rule ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]])) // Rule ("width", Value ([Expression [Operation "+" [Variable "@w"][Dimension 4px]]])) // Ruleset (Selector [Element '>', '.child'], [...]) // ]) // // In general, most rules will try to parse a token with the `$()` function, and if the return // value is truly, will return a new node, of the relevant type. Sometimes, we need to check // first, before parsing, that's when we use `peek()`. // parsers: { // // The `primary` rule is the *entry* and *exit* point of the parser. // The rules here can appear at any level of the parse tree. // // The recursive nature of the grammar is an interplay between the `block` // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule, // as represented by this simplified grammar: // // primary → (ruleset | rule)+ // ruleset → selector+ block // block → '{' primary '}' // // Only at one point is the primary rule not called from the // block rule: at the root level. // primary: function () { var node, root = []; while ((node = $(this.mixin.definition) || $(this.rule) || $(this.ruleset) || $(this.mixin.call) || $(this.comment) || $(this.directive)) || $(/^[\s\n]+/) || $(/^;+/)) { node && root.push(node); } return root; }, // We create a Comment node for CSS comments `/* */`, // but keep the LeSS comments `//` silent, by just skipping // over them. comment: function () { var comment; if (input.charAt(i) !== '/') return; if (input.charAt(i + 1) === '/') { return new(tree.Comment)($(/^\/\/.*/), true); } else if (comment = $(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/)) { return new(tree.Comment)(comment); } }, // // Entities are tokens which can be found inside an Expression // entities: { // // A string, which supports escaping " and ' // // "milky way" 'he\'s the one!' // quoted: function () { var str, j = i, e; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '"' && input.charAt(j) !== "'") return; e && $('~'); if (str = $(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/)) { return new(tree.Quoted)(str[0], str[1] || str[2], e); } }, // // A catch-all word, such as: // // black border-collapse // keyword: function () { var k; if (k = $(/^[_A-Za-z-][_A-Za-z0-9-]*/)) { if (tree.colors.hasOwnProperty(k)) { // detect named color return new(tree.Color)(tree.colors[k].slice(1)); } else { return new(tree.Keyword)(k); } } }, // // A function call // // rgb(255, 0, 255) // // We also try to catch IE's `alpha()`, but let the `alpha` parser // deal with the details. // // The arguments are parsed with the `entities.arguments` parser. // call: function () { var name, nameLC, args, alpha_ret, index = i; if (! (name = /^([\w-]+|%|progid:[\w\.]+)\(/.exec(chunks[j]))) return; name = name[1]; nameLC = name.toLowerCase(); if (nameLC === 'url') { return null } else { i += name.length } if (nameLC === 'alpha') { alpha_ret = $(this.alpha); if(typeof alpha_ret !== 'undefined') { return alpha_ret; } } $('('); // Parse the '(' and consume whitespace. args = $(this.entities.arguments); if (! $(')')) return; if (name) { return new(tree.Call)(name, args, index, env.filename) } }, arguments: function () { var args = [], arg; while (arg = $(this.entities.assignment) || $(this.expression)) { args.push(arg); if (! $(',')) { break } } return args; }, literal: function () { return $(this.entities.ratio) || $(this.entities.dimension) || $(this.entities.color) || $(this.entities.quoted) || $(this.entities.unicodeDescriptor); }, // Assignments are argument entities for calls. // They are present in ie filter properties as shown below. // // filter: progid:DXImageTransform.Microsoft.Alpha( *opacity=50* ) // assignment: function () { var key, value; if ((key = $(/^\w+(?=\s?=)/i)) && $('=') && (value = $(this.entity))) { return new(tree.Assignment)(key, value); } }, // // Parse url() tokens // // We use a specific rule for urls, because they don't really behave like // standard function calls. The difference is that the argument doesn't have // to be enclosed within a string, so it can't be parsed as an Expression. // url: function () { var value; if (input.charAt(i) !== 'u' || !$(/^url\(/)) return; value = $(this.entities.quoted) || $(this.entities.variable) || $(/^(?:(?:\\[\(\)'"])|[^\(\)'"])+/) || ""; expect(')'); return new(tree.URL)((value.value != null || value instanceof tree.Variable) ? value : new(tree.Anonymous)(value), env.rootpath); }, // // A Variable entity, such as `@fink`, in // // width: @fink + 2px // // We use a different parser for variable definitions, // see `parsers.variable`. // variable: function () { var name, index = i; if (input.charAt(i) === '@' && (name = $(/^@@?[\w-]+/))) { return new(tree.Variable)(name, index, env.filename); } }, // A variable entity useing the protective {} e.g. @{var} variableCurly: function () { var name, curly, index = i; if (input.charAt(i) === '@' && (curly = $(/^@\{([\w-]+)\}/))) { return new(tree.Variable)("@" + curly[1], index, env.filename); } }, // // A Hexadecimal color // // #4F3C2F // // `rgb` and `hsl` colors are parsed through the `entities.call` parser. // color: function () { var rgb; if (input.charAt(i) === '#' && (rgb = $(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/))) { return new(tree.Color)(rgb[1]); } }, // // A Dimension, that is, a number and a unit // // 0.5em 95% // dimension: function () { var value, c = input.charCodeAt(i); //Is the first char of the dimension 0-9, '.', '+' or '-' if ((c > 57 || c < 43) || c === 47 || c == 44) return; if (value = $(/^([+-]?\d*\.?\d+)(px|%|em|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn|dpi|dpcm|dppx|rem|vw|vh|vmin|vm|ch)?/)) { return new(tree.Dimension)(value[1], value[2]); } }, // // A Ratio // // 16/9 // ratio: function () { var value, c = input.charCodeAt(i); if (c > 57 || c < 48) return; if (value = $(/^(\d+\/\d+)/)) { return new(tree.Ratio)(value[1]); } }, // // A unicode descriptor, as is used in unicode-range // // U+0?? or U+00A1-00A9 // unicodeDescriptor: function () { var ud; if (ud = $(/^U\+[0-9a-fA-F?]+(\-[0-9a-fA-F?]+)?/)) { return new(tree.UnicodeDescriptor)(ud[0]); } }, // // JavaScript code to be evaluated // // `window.location.href` // javascript: function () { var str, j = i, e; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '`') { return } e && $('~'); if (str = $(/^`([^`]*)`/)) { return new(tree.JavaScript)(str[1], i, e); } } }, // // The variable part of a variable definition. Used in the `rule` parser // // @fink: // variable: function () { var name; if (input.charAt(i) === '@' && (name = $(/^(@[\w-]+)\s*:/))) { return name[1] } }, // // A font size/line-height shorthand // // small/12px // // We need to peek first, or we'll match on keywords and dimensions // shorthand: function () { var a, b; if (! peek(/^[@\w.%-]+\/[@\w.-]+/)) return; save(); if ((a = $(this.entity)) && $('/') && (b = $(this.entity))) { return new(tree.Shorthand)(a, b); } restore(); }, // // Mixins // mixin: { // // A Mixin call, with an optional argument list // // #mixins > .square(#fff); // .rounded(4px, black); // .button; // // The `while` loop is there because mixins can be // namespaced, but we only support the child and descendant // selector for now. // call: function () { var elements = [], e, c, argsSemiColon = [], argsComma = [], args, delim, arg, nameLoop, expressions, isSemiColonSeperated, expressionContainsNamed, index = i, s = input.charAt(i), name, value, important = false; if (s !== '.' && s !== '#') { return } save(); // stop us absorbing part of an invalid selector while (e = $(/^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/)) { elements.push(new(tree.Element)(c, e, i)); c = $('>'); } if ($('(')) { expressions = []; while (arg = $(this.expression)) { nameLoop = null; value = arg; // Variable if (arg.value.length == 1) { var val = arg.value[0]; if (val instanceof tree.Variable) { if ($(':')) { if (expressions.length > 0) { if (isSemiColonSeperated) { error("Cannot mix ; and , as delimiter types"); } expressionContainsNamed = true; } value = expect(this.expression); nameLoop = (name = val.name); } } } expressions.push(value); argsComma.push({ name: nameLoop, value: value }); if ($(',')) { continue; } if ($(';') || isSemiColonSeperated) { if (expressionContainsNamed) { error("Cannot mix ; and , as delimiter types"); } isSemiColonSeperated = true; if (expressions.length > 1) { value = new(tree.Value)(expressions); } argsSemiColon.push({ name: name, value: value }); name = null; expressions = []; expressionContainsNamed = false; } } expect(')'); } args = isSemiColonSeperated ? argsSemiColon : argsComma; if ($(this.important)) { important = true; } if (elements.length > 0 && ($(';') || peek('}'))) { return new(tree.mixin.Call)(elements, args, index, env.filename, important); } restore(); }, // // A Mixin definition, with a list of parameters // // .rounded (@radius: 2px, @color) { // ... // } // // Until we have a finer grained state-machine, we have to // do a look-ahead, to make sure we don't have a mixin call. // See the `rule` function for more information. // // We start by matching `.rounded (`, and then proceed on to // the argument list, which has optional default values. // We store the parameters in `params`, with a `value` key, // if there is a value, such as in the case of `@radius`. // // Once we've got our params list, and a closing `)`, we parse // the `{...}` block. // definition: function () { var name, params = [], match, ruleset, param, value, cond, variadic = false; if ((input.charAt(i) !== '.' && input.charAt(i) !== '#') || peek(/^[^{]*\}/)) return; save(); if (match = $(/^([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/)) { name = match[1]; do { $(this.comment); if (input.charAt(i) === '.' && $(/^\.{3}/)) { variadic = true; params.push({ variadic: true }); break; } else if (param = $(this.entities.variable) || $(this.entities.literal) || $(this.entities.keyword)) { // Variable if (param instanceof tree.Variable) { if ($(':')) { value = expect(this.expression, 'expected expression'); params.push({ name: param.name, value: value }); } else if ($(/^\.{3}/)) { params.push({ name: param.name, variadic: true }); variadic = true; break; } else { params.push({ name: param.name }); } } else { params.push({ value: param }); } } else { break; } } while ($(',') || $(';')) // .mixincall("@{a}"); // looks a bit like a mixin definition.. so we have to be nice and restore if (!$(')')) { furthest = i; restore(); } $(this.comment); if ($(/^when/)) { // Guard cond = expect(this.conditions, 'expected condition'); } ruleset = $(this.block); if (ruleset) { return new(tree.mixin.Definition)(name, params, ruleset, cond, variadic); } else { restore(); } } } }, // // Entities are the smallest recognized token, // and can be found inside a rule's value. // entity: function () { return $(this.entities.literal) || $(this.entities.variable) || $(this.entities.url) || $(this.entities.call) || $(this.entities.keyword) ||$(this.entities.javascript) || $(this.comment); }, // // A Rule terminator. Note that we use `peek()` to check for '}', // because the `block` rule will be expecting it, but we still need to make sure // it's there, if ';' was ommitted. // end: function () { return $(';') || peek('}'); }, // // IE's alpha function // // alpha(opacity=88) // alpha: function () { var value; if (! $(/^\(opacity=/i)) return; if (value = $(/^\d+/) || $(this.entities.variable)) { expect(')'); return new(tree.Alpha)(value); } }, // // A Selector Element // // div // + h1 // #socks // input[type="text"] // // Elements are the building blocks for Selectors, // they are made out of a `Combinator` (see combinator rule), // and an element name, such as a tag a class, or `*`. // element: function () { var e, t, c, v; c = $(this.combinator); e = $(/^(?:\d+\.\d+|\d+)%/) || $(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/) || $('*') || $('&') || $(this.attribute) || $(/^\([^()@]+\)/) || $(/^[\.#](?=@)/) || $(this.entities.variableCurly); if (! e) { if ($('(')) { if ((v = ($(this.entities.variableCurly) || $(this.entities.variable) || $(this.selector))) && $(')')) { e = new(tree.Paren)(v); } } } if (e) { return new(tree.Element)(c, e, i) } }, // // Combinators combine elements together, in a Selector. // // Because our parser isn't white-space sensitive, special care // has to be taken, when parsing the descendant combinator, ` `, // as it's an empty space. We have to check the previous character // in the input, to see if it's a ` ` character. More info on how // we deal with this in *combinator.js*. // combinator: function () { var match, c = input.charAt(i); if (c === '>' || c === '+' || c === '~' || c === '|') { i++; while (input.charAt(i).match(/\s/)) { i++ } return new(tree.Combinator)(c); } else if (input.charAt(i - 1).match(/\s/)) { return new(tree.Combinator)(" "); } else { return new(tree.Combinator)(null); } }, // // A CSS Selector // // .class > div + h1 // li a:hover // // Selectors are made out of one or more Elements, see above. // selector: function () { var sel, e, elements = [], c, match; // depreciated, will be removed soon if ($('(')) { sel = $(this.entity); expect(')'); return new(tree.Selector)([new(tree.Element)('', sel, i)]); } while (e = $(this.element)) { c = input.charAt(i); elements.push(e) if (c === '{' || c === '}' || c === ';' || c === ',' || c === ')') { break } } if (elements.length > 0) { return new(tree.Selector)(elements) } }, attribute: function () { var attr = '', key, val, op; if (! $('[')) return; if (key = $(/^(?:[_A-Za-z0-9-]|\\.)+/) || $(this.entities.quoted)) { if ((op = $(/^[|~*$^]?=/)) && (val = $(this.entities.quoted) || $(/^[\w-]+/))) { attr = [key, op, val.toCSS ? val.toCSS() : val].join(''); } else { attr = key } } if (! $(']')) return; if (attr) { return "[" + attr + "]" } }, // // The `block` rule is used by `ruleset` and `mixin.definition`. // It's a wrapper around the `primary` rule, with added `{}`. // block: function () { var content; if ($('{') && (content = $(this.primary)) && $('}')) { return content; } }, // // div, .class, body > p {...} // ruleset: function () { var selectors = [], s, rules, match, debugInfo; save(); if (env.dumpLineNumbers) debugInfo = getDebugInfo(i, input, env); while (s = $(this.selector)) { selectors.push(s); $(this.comment); if (! $(',')) { break } $(this.comment); } if (selectors.length > 0 && (rules = $(this.block))) { var ruleset = new(tree.Ruleset)(selectors, rules, env.strictImports); if (env.dumpLineNumbers) ruleset.debugInfo = debugInfo; return ruleset; } else { // Backtrack furthest = i; restore(); } }, rule: function () { var name, value, c = input.charAt(i), important, match; save(); if (c === '.' || c === '#' || c === '&') { return } if (name = $(this.variable) || $(this.property)) { if ((name.charAt(0) != '@') && (match = /^([^@+\/'"*`(;{}-]*);/.exec(chunks[j]))) { i += match[0].length - 1; value = new(tree.Anonymous)(match[1]); } else if (name === "font") { value = $(this.font); } else { value = $(this.value); } important = $(this.important); if (value && $(this.end)) { return new(tree.Rule)(name, value, important, memo); } else { furthest = i; restore(); } } }, // // An @import directive // // @import "lib"; // // Depending on our environemnt, importing is done differently: // In the browser, it's an XHR request, in Node, it would be a // file-system operation. The function used for importing is // stored in `import`, which we pass to the Import constructor. // "import": function () { var path, features, index = i; save(); var dir = $(/^@import(?:-(once))?\s+/); if (dir && (path = $(this.entities.quoted) || $(this.entities.url))) { features = $(this.mediaFeatures); if ($(';')) { return new(tree.Import)(path, imports, features, (dir[1] === 'once'), index, env.rootpath); } } restore(); }, mediaFeature: function () { var e, p, nodes = []; do { if (e = $(this.entities.keyword)) { nodes.push(e); } else if ($('(')) { p = $(this.property); e = $(this.entity); if ($(')')) { if (p && e) { nodes.push(new(tree.Paren)(new(tree.Rule)(p, e, null, i, true))); } else if (e) { nodes.push(new(tree.Paren)(e)); } else { return null; } } else { return null } } } while (e); if (nodes.length > 0) { return new(tree.Expression)(nodes); } }, mediaFeatures: function () { var e, features = []; do { if (e = $(this.mediaFeature)) { features.push(e); if (! $(',')) { break } } else if (e = $(this.entities.variable)) { features.push(e); if (! $(',')) { break } } } while (e); return features.length > 0 ? features : null; }, media: function () { var features, rules, media, debugInfo; if (env.dumpLineNumbers) debugInfo = getDebugInfo(i, input, env); if ($(/^@media/)) { features = $(this.mediaFeatures); if (rules = $(this.block)) { media = new(tree.Media)(rules, features); if(env.dumpLineNumbers) media.debugInfo = debugInfo; return media; } } }, // // A CSS Directive // // @charset "utf-8"; // directive: function () { var name, value, rules, identifier, e, nodes, nonVendorSpecificName, hasBlock, hasIdentifier, hasExpression; if (input.charAt(i) !== '@') return; if (value = $(this['import']) || $(this.media)) { return value; } save(); name = $(/^@[a-z-]+/); if (!name) return; nonVendorSpecificName = name; if (name.charAt(1) == '-' && name.indexOf('-', 2) > 0) { nonVendorSpecificName = "@" + name.slice(name.indexOf('-', 2) + 1); } switch(nonVendorSpecificName) { case "@font-face": hasBlock = true; break; case "@viewport": case "@top-left": case "@top-left-corner": case "@top-center": case "@top-right": case "@top-right-corner": case "@bottom-left": case "@bottom-left-corner": case "@bottom-center": case "@bottom-right": case "@bottom-right-corner": case "@left-top": case "@left-middle": case "@left-bottom": case "@right-top": case "@right-middle": case "@right-bottom": hasBlock = true; break; case "@page": case "@document": case "@supports": case "@keyframes": hasBlock = true; hasIdentifier = true; break; case "@namespace": hasExpression = true; break; } if (hasIdentifier) { name += " " + ($(/^[^{]+/) || '').trim(); } if (hasBlock) { if (rules = $(this.block)) { return new(tree.Directive)(name, rules); } } else { if ((value = hasExpression ? $(this.expression) : $(this.entity)) && $(';')) { var directive = new(tree.Directive)(name, value); if (env.dumpLineNumbers) { directive.debugInfo = getDebugInfo(i, input, env); } return directive; } } restore(); }, font: function () { var value = [], expression = [], weight, shorthand, font, e; while (e = $(this.shorthand) || $(this.entity)) { expression.push(e); } value.push(new(tree.Expression)(expression)); if ($(',')) { while (e = $(this.expression)) { value.push(e); if (! $(',')) { break } } } return new(tree.Value)(value); }, // // A Value is a comma-delimited list of Expressions // // font-family: Baskerville, Georgia, serif; // // In a Rule, a Value represents everything after the `:`, // and before the `;`. // value: function () { var e, expressions = [], important; while (e = $(this.expression)) { expressions.push(e); if (! $(',')) { break } } if (expressions.length > 0) { return new(tree.Value)(expressions); } }, important: function () { if (input.charAt(i) === '!') { return $(/^! *important/); } }, sub: function () { var e; if ($('(') && (e = $(this.expression)) && $(')')) { return e; } }, multiplication: function () { var m, a, op, operation; if (m = $(this.operand)) { while (!peek(/^\/[*\/]/) && (op = ($('/') || $('*'))) && (a = $(this.operand))) { operation = new(tree.Operation)(op, [operation || m, a]); } return operation || m; } }, addition: function () { var m, a, op, operation; if (m = $(this.multiplication)) { while ((op = $(/^[-+]\s+/) || (!isWhitespace(input.charAt(i - 1)) && ($('+') || $('-')))) && (a = $(this.multiplication))) { operation = new(tree.Operation)(op, [operation || m, a]); } return operation || m; } }, conditions: function () { var a, b, index = i, condition; if (a = $(this.condition)) { while ($(',') && (b = $(this.condition))) { condition = new(tree.Condition)('or', condition || a, b, index); } return condition || a; } }, condition: function () { var a, b, c, op, index = i, negate = false; if ($(/^not/)) { negate = true } expect('('); if (a = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) { if (op = $(/^(?:>=|=<|[<=>])/)) { if (b = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) { c = new(tree.Condition)(op, a, b, index, negate); } else { error('expected expression'); } } else { c = new(tree.Condition)('=', a, new(tree.Keyword)('true'), index, negate); } expect(')'); return $(/^and/) ? new(tree.Condition)('and', c, $(this.condition)) : c; } }, // // An operand is anything that can be part of an operation, // such as a Color, or a Variable // operand: function () { var negate, p = input.charAt(i + 1); if (input.charAt(i) === '-' && (p === '@' || p === '(')) { negate = $('-') } var o = $(this.sub) || $(this.entities.dimension) || $(this.entities.color) || $(this.entities.variable) || $(this.entities.call); return negate ? new(tree.Operation)('*', [new(tree.Dimension)(-1), o]) : o; }, // // Expressions either represent mathematical operations, // or white-space delimited Entities. // // 1px solid black // @var * 2 // expression: function () { var e, delim, entities = [], d; while (e = $(this.addition) || $(this.entity)) { entities.push(e); } if (entities.length > 0) { return new(tree.Expression)(entities); } }, property: function () { var name; if (name = $(/^(\*?-?[_a-z0-9-]+)\s*:/)) { return name[1]; } } } }; }; if (less.mode === 'browser' || less.mode === 'rhino') { // // Used by `@import` directives // less.Parser.importer = function (path, paths, callback, env) { if (!/^([a-z-]+:)?\//.test(path) && paths.length > 0) { path = paths[0] + path; } // We pass `true` as 3rd argument, to force the reload of the import. // This is so we can get the syntax tree as opposed to just the CSS output, // as we need this to evaluate the current stylesheet. loadStyleSheet({ href: path, title: path, type: env.mime, contents: env.contents, files: env.files, rootpath: env.rootpath, entryPath: env.entryPath, relativeUrls: env.relativeUrls }, function (e, root, data, sheet, _, path) { if (e && typeof(env.errback) === "function") { env.errback.call(null, path, paths, callback, env); } else { callback.call(null, e, root, path); } }, true); }; } (function (tree) { tree.functions = { rgb: function (r, g, b) { return this.rgba(r, g, b, 1.0); }, rgba: function (r, g, b, a) { var rgb = [r, g, b].map(function (c) { return scaled(c, 256); }); a = number(a); return new(tree.Color)(rgb, a); }, hsl: function (h, s, l) { return this.hsla(h, s, l, 1.0); }, hsla: function (h, s, l, a) { h = (number(h) % 360) / 360; s = number(s); l = number(l); a = number(a); var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s; var m1 = l * 2 - m2; return this.rgba(hue(h + 1/3) * 255, hue(h) * 255, hue(h - 1/3) * 255, a); function hue(h) { h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h); if (h * 6 < 1) return m1 + (m2 - m1) * h * 6; else if (h * 2 < 1) return m2; else if (h * 3 < 2) return m1 + (m2 - m1) * (2/3 - h) * 6; else return m1; } }, hsv: function(h, s, v) { return this.hsva(h, s, v, 1.0); }, hsva: function(h, s, v, a) { h = ((number(h) % 360) / 360) * 360; s = number(s); v = number(v); a = number(a); var i, f; i = Math.floor((h / 60) % 6); f = (h / 60) - i; var vs = [v, v * (1 - s), v * (1 - f * s), v * (1 - (1 - f) * s)]; var perm = [[0, 3, 1], [2, 0, 1], [1, 0, 3], [1, 2, 0], [3, 1, 0], [0, 1, 2]]; return this.rgba(vs[perm[i][0]] * 255, vs[perm[i][1]] * 255, vs[perm[i][2]] * 255, a); }, hue: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().h)); }, saturation: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().s * 100), '%'); }, lightness: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().l * 100), '%'); }, red: function (color) { return new(tree.Dimension)(color.rgb[0]); }, green: function (color) { return new(tree.Dimension)(color.rgb[1]); }, blue: function (color) { return new(tree.Dimension)(color.rgb[2]); }, alpha: function (color) { return new(tree.Dimension)(color.toHSL().a); }, luma: function (color) { return new(tree.Dimension)(Math.round((0.2126 * (color.rgb[0]/255) + 0.7152 * (color.rgb[1]/255) + 0.0722 * (color.rgb[2]/255)) * color.alpha * 100), '%'); }, saturate: function (color, amount) { var hsl = color.toHSL(); hsl.s += amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, desaturate: function (color, amount) { var hsl = color.toHSL(); hsl.s -= amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, lighten: function (color, amount) { var hsl = color.toHSL(); hsl.l += amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, darken: function (color, amount) { var hsl = color.toHSL(); hsl.l -= amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, fadein: function (color, amount) { var hsl = color.toHSL(); hsl.a += amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, fadeout: function (color, amount) { var hsl = color.toHSL(); hsl.a -= amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, fade: function (color, amount) { var hsl = color.toHSL(); hsl.a = amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, spin: function (color, amount) { var hsl = color.toHSL(); var hue = (hsl.h + amount.value) % 360; hsl.h = hue < 0 ? 360 + hue : hue; return hsla(hsl); }, // // Copyright (c) 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein // http://sass-lang.com // mix: function (color1, color2, weight) { if (!weight) { weight = new(tree.Dimension)(50); } var p = weight.value / 100.0; var w = p * 2 - 1; var a = color1.toHSL().a - color2.toHSL().a; var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0; var w2 = 1 - w1; var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2, color1.rgb[1] * w1 + color2.rgb[1] * w2, color1.rgb[2] * w1 + color2.rgb[2] * w2]; var alpha = color1.alpha * p + color2.alpha * (1 - p); return new(tree.Color)(rgb, alpha); }, greyscale: function (color) { return this.desaturate(color, new(tree.Dimension)(100)); }, contrast: function (color, dark, light, threshold) { if (typeof light === 'undefined') { light = this.rgba(255, 255, 255, 1.0); } if (typeof dark === 'undefined') { dark = this.rgba(0, 0, 0, 1.0); } if (typeof threshold === 'undefined') { threshold = 0.43; } else { threshold = threshold.value; } if (((0.2126 * (color.rgb[0]/255) + 0.7152 * (color.rgb[1]/255) + 0.0722 * (color.rgb[2]/255)) * color.alpha) < threshold) { return light; } else { return dark; } }, e: function (str) { return new(tree.Anonymous)(str instanceof tree.JavaScript ? str.evaluated : str); }, escape: function (str) { return new(tree.Anonymous)(encodeURI(str.value).replace(/=/g, "%3D").replace(/:/g, "%3A").replace(/#/g, "%23").replace(/;/g, "%3B").replace(/\(/g, "%28").replace(/\)/g, "%29")); }, '%': function (quoted /* arg, arg, ...*/) { var args = Array.prototype.slice.call(arguments, 1), str = quoted.value; for (var i = 0; i < args.length; i++) { str = str.replace(/%[sda]/i, function(token) { var value = token.match(/s/i) ? args[i].value : args[i].toCSS(); return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value; }); } str = str.replace(/%%/g, '%'); return new(tree.Quoted)('"' + str + '"', str); }, unit: function (val, unit) { return new(tree.Dimension)(val.value, unit ? unit.toCSS() : ""); }, round: function (n, f) { var fraction = typeof(f) === "undefined" ? 0 : f.value; return this._math(function(num) { return num.toFixed(fraction); }, n); }, ceil: function (n) { return this._math(Math.ceil, n); }, floor: function (n) { return this._math(Math.floor, n); }, _math: function (fn, n) { if (n instanceof tree.Dimension) { return new(tree.Dimension)(fn(parseFloat(n.value)), n.unit); } else if (typeof(n) === 'number') { return fn(n); } else { throw { type: "Argument", message: "argument must be a number" }; } }, argb: function (color) { return new(tree.Anonymous)(color.toARGB()); }, percentage: function (n) { return new(tree.Dimension)(n.value * 100, '%'); }, color: function (n) { if (n instanceof tree.Quoted) { return new(tree.Color)(n.value.slice(1)); } else { throw { type: "Argument", message: "argument must be a string" }; } }, iscolor: function (n) { return this._isa(n, tree.Color); }, isnumber: function (n) { return this._isa(n, tree.Dimension); }, isstring: function (n) { return this._isa(n, tree.Quoted); }, iskeyword: function (n) { return this._isa(n, tree.Keyword); }, isurl: function (n) { return this._isa(n, tree.URL); }, ispixel: function (n) { return (n instanceof tree.Dimension) && n.unit === 'px' ? tree.True : tree.False; }, ispercentage: function (n) { return (n instanceof tree.Dimension) && n.unit === '%' ? tree.True : tree.False; }, isem: function (n) { return (n instanceof tree.Dimension) && n.unit === 'em' ? tree.True : tree.False; }, _isa: function (n, Type) { return (n instanceof Type) ? tree.True : tree.False; }, /* Blending modes */ multiply: function(color1, color2) { var r = color1.rgb[0] * color2.rgb[0] / 255; var g = color1.rgb[1] * color2.rgb[1] / 255; var b = color1.rgb[2] * color2.rgb[2] / 255; return this.rgb(r, g, b); }, screen: function(color1, color2) { var r = 255 - (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255; var g = 255 - (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255; var b = 255 - (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255; return this.rgb(r, g, b); }, overlay: function(color1, color2) { var r = color1.rgb[0] < 128 ? 2 * color1.rgb[0] * color2.rgb[0] / 255 : 255 - 2 * (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255; var g = color1.rgb[1] < 128 ? 2 * color1.rgb[1] * color2.rgb[1] / 255 : 255 - 2 * (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255; var b = color1.rgb[2] < 128 ? 2 * color1.rgb[2] * color2.rgb[2] / 255 : 255 - 2 * (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255; return this.rgb(r, g, b); }, softlight: function(color1, color2) { var t = color2.rgb[0] * color1.rgb[0] / 255; var r = t + color1.rgb[0] * (255 - (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255 - t) / 255; t = color2.rgb[1] * color1.rgb[1] / 255; var g = t + color1.rgb[1] * (255 - (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255 - t) / 255; t = color2.rgb[2] * color1.rgb[2] / 255; var b = t + color1.rgb[2] * (255 - (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255 - t) / 255; return this.rgb(r, g, b); }, hardlight: function(color1, color2) { var r = color2.rgb[0] < 128 ? 2 * color2.rgb[0] * color1.rgb[0] / 255 : 255 - 2 * (255 - color2.rgb[0]) * (255 - color1.rgb[0]) / 255; var g = color2.rgb[1] < 128 ? 2 * color2.rgb[1] * color1.rgb[1] / 255 : 255 - 2 * (255 - color2.rgb[1]) * (255 - color1.rgb[1]) / 255; var b = color2.rgb[2] < 128 ? 2 * color2.rgb[2] * color1.rgb[2] / 255 : 255 - 2 * (255 - color2.rgb[2]) * (255 - color1.rgb[2]) / 255; return this.rgb(r, g, b); }, difference: function(color1, color2) { var r = Math.abs(color1.rgb[0] - color2.rgb[0]); var g = Math.abs(color1.rgb[1] - color2.rgb[1]); var b = Math.abs(color1.rgb[2] - color2.rgb[2]); return this.rgb(r, g, b); }, exclusion: function(color1, color2) { var r = color1.rgb[0] + color2.rgb[0] * (255 - color1.rgb[0] - color1.rgb[0]) / 255; var g = color1.rgb[1] + color2.rgb[1] * (255 - color1.rgb[1] - color1.rgb[1]) / 255; var b = color1.rgb[2] + color2.rgb[2] * (255 - color1.rgb[2] - color1.rgb[2]) / 255; return this.rgb(r, g, b); }, average: function(color1, color2) { var r = (color1.rgb[0] + color2.rgb[0]) / 2; var g = (color1.rgb[1] + color2.rgb[1]) / 2; var b = (color1.rgb[2] + color2.rgb[2]) / 2; return this.rgb(r, g, b); }, negation: function(color1, color2) { var r = 255 - Math.abs(255 - color2.rgb[0] - color1.rgb[0]); var g = 255 - Math.abs(255 - color2.rgb[1] - color1.rgb[1]); var b = 255 - Math.abs(255 - color2.rgb[2] - color1.rgb[2]); return this.rgb(r, g, b); }, tint: function(color, amount) { return this.mix(this.rgb(255,255,255), color, amount); }, shade: function(color, amount) { return this.mix(this.rgb(0, 0, 0), color, amount); } }; function hsla(color) { return tree.functions.hsla(color.h, color.s, color.l, color.a); } function scaled(n, size) { if (n instanceof tree.Dimension && n.unit == '%') { return parseFloat(n.value * size / 100); } else { return number(n); } } function number(n) { if (n instanceof tree.Dimension) { return parseFloat(n.unit == '%' ? n.value / 100 : n.value); } else if (typeof(n) === 'number') { return n; } else { throw { error: "RuntimeError", message: "color functions take numbers as parameters" }; } } function clamp(val) { return Math.min(1, Math.max(0, val)); } })(require('./tree')); (function (tree) { tree.colors = { 'aliceblue':'#f0f8ff', 'antiquewhite':'#faebd7', 'aqua':'#00ffff', 'aquamarine':'#7fffd4', 'azure':'#f0ffff', 'beige':'#f5f5dc', 'bisque':'#ffe4c4', 'black':'#000000', 'blanchedalmond':'#ffebcd', 'blue':'#0000ff', 'blueviolet':'#8a2be2', 'brown':'#a52a2a', 'burlywood':'#deb887', 'cadetblue':'#5f9ea0', 'chartreuse':'#7fff00', 'chocolate':'#d2691e', 'coral':'#ff7f50', 'cornflowerblue':'#6495ed', 'cornsilk':'#fff8dc', 'crimson':'#dc143c', 'cyan':'#00ffff', 'darkblue':'#00008b', 'darkcyan':'#008b8b', 'darkgoldenrod':'#b8860b', 'darkgray':'#a9a9a9', 'darkgrey':'#a9a9a9', 'darkgreen':'#006400', 'darkkhaki':'#bdb76b', 'darkmagenta':'#8b008b', 'darkolivegreen':'#556b2f', 'darkorange':'#ff8c00', 'darkorchid':'#9932cc', 'darkred':'#8b0000', 'darksalmon':'#e9967a', 'darkseagreen':'#8fbc8f', 'darkslateblue':'#483d8b', 'darkslategray':'#2f4f4f', 'darkslategrey':'#2f4f4f', 'darkturquoise':'#00ced1', 'darkviolet':'#9400d3', 'deeppink':'#ff1493', 'deepskyblue':'#00bfff', 'dimgray':'#696969', 'dimgrey':'#696969', 'dodgerblue':'#1e90ff', 'firebrick':'#b22222', 'floralwhite':'#fffaf0', 'forestgreen':'#228b22', 'fuchsia':'#ff00ff', 'gainsboro':'#dcdcdc', 'ghostwhite':'#f8f8ff', 'gold':'#ffd700', 'goldenrod':'#daa520', 'gray':'#808080', 'grey':'#808080', 'green':'#008000', 'greenyellow':'#adff2f', 'honeydew':'#f0fff0', 'hotpink':'#ff69b4', 'indianred':'#cd5c5c', 'indigo':'#4b0082', 'ivory':'#fffff0', 'khaki':'#f0e68c', 'lavender':'#e6e6fa', 'lavenderblush':'#fff0f5', 'lawngreen':'#7cfc00', 'lemonchiffon':'#fffacd', 'lightblue':'#add8e6', 'lightcoral':'#f08080', 'lightcyan':'#e0ffff', 'lightgoldenrodyellow':'#fafad2', 'lightgray':'#d3d3d3', 'lightgrey':'#d3d3d3', 'lightgreen':'#90ee90', 'lightpink':'#ffb6c1', 'lightsalmon':'#ffa07a', 'lightseagreen':'#20b2aa', 'lightskyblue':'#87cefa', 'lightslategray':'#778899', 'lightslategrey':'#778899', 'lightsteelblue':'#b0c4de', 'lightyellow':'#ffffe0', 'lime':'#00ff00', 'limegreen':'#32cd32', 'linen':'#faf0e6', 'magenta':'#ff00ff', 'maroon':'#800000', 'mediumaquamarine':'#66cdaa', 'mediumblue':'#0000cd', 'mediumorchid':'#ba55d3', 'mediumpurple':'#9370d8', 'mediumseagreen':'#3cb371', 'mediumslateblue':'#7b68ee', 'mediumspringgreen':'#00fa9a', 'mediumturquoise':'#48d1cc', 'mediumvioletred':'#c71585', 'midnightblue':'#191970', 'mintcream':'#f5fffa', 'mistyrose':'#ffe4e1', 'moccasin':'#ffe4b5', 'navajowhite':'#ffdead', 'navy':'#000080', 'oldlace':'#fdf5e6', 'olive':'#808000', 'olivedrab':'#6b8e23', 'orange':'#ffa500', 'orangered':'#ff4500', 'orchid':'#da70d6', 'palegoldenrod':'#eee8aa', 'palegreen':'#98fb98', 'paleturquoise':'#afeeee', 'palevioletred':'#d87093', 'papayawhip':'#ffefd5', 'peachpuff':'#ffdab9', 'peru':'#cd853f', 'pink':'#ffc0cb', 'plum':'#dda0dd', 'powderblue':'#b0e0e6', 'purple':'#800080', 'red':'#ff0000', 'rosybrown':'#bc8f8f', 'royalblue':'#4169e1', 'saddlebrown':'#8b4513', 'salmon':'#fa8072', 'sandybrown':'#f4a460', 'seagreen':'#2e8b57', 'seashell':'#fff5ee', 'sienna':'#a0522d', 'silver':'#c0c0c0', 'skyblue':'#87ceeb', 'slateblue':'#6a5acd', 'slategray':'#708090', 'slategrey':'#708090', 'snow':'#fffafa', 'springgreen':'#00ff7f', 'steelblue':'#4682b4', 'tan':'#d2b48c', 'teal':'#008080', 'thistle':'#d8bfd8', 'tomato':'#ff6347', // 'transparent':'rgba(0,0,0,0)', 'turquoise':'#40e0d0', 'violet':'#ee82ee', 'wheat':'#f5deb3', 'white':'#ffffff', 'whitesmoke':'#f5f5f5', 'yellow':'#ffff00', 'yellowgreen':'#9acd32' }; })(require('./tree')); (function (tree) { tree.Alpha = function (val) { this.value = val; }; tree.Alpha.prototype = { toCSS: function () { return "alpha(opacity=" + (this.value.toCSS ? this.value.toCSS() : this.value) + ")"; }, eval: function (env) { if (this.value.eval) { this.value = this.value.eval(env) } return this; } }; })(require('../tree')); (function (tree) { tree.Anonymous = function (string) { this.value = string.value || string; }; tree.Anonymous.prototype = { toCSS: function () { return this.value; }, eval: function () { return this }, compare: function (x) { if (!x.toCSS) { return -1; } var left = this.toCSS(), right = x.toCSS(); if (left === right) { return 0; } return left < right ? -1 : 1; } }; })(require('../tree')); (function (tree) { tree.Assignment = function (key, val) { this.key = key; this.value = val; }; tree.Assignment.prototype = { toCSS: function () { return this.key + '=' + (this.value.toCSS ? this.value.toCSS() : this.value); }, eval: function (env) { if (this.value.eval) { return new(tree.Assignment)(this.key, this.value.eval(env)); } return this; } }; })(require('../tree'));(function (tree) { // // A function call node. // tree.Call = function (name, args, index, filename) { this.name = name; this.args = args; this.index = index; this.filename = filename; }; tree.Call.prototype = { // // When evaluating a function call, // we either find the function in `tree.functions` [1], // in which case we call it, passing the evaluated arguments, // or we simply print it out as it appeared originally [2]. // // The *functions.js* file contains the built-in functions. // // The reason why we evaluate the arguments, is in the case where // we try to pass a variable to a function, like: `saturate(@color)`. // The function should receive the value, not the variable. // eval: function (env) { var args = this.args.map(function (a) { return a.eval(env) }); if (this.name in tree.functions) { // 1. try { return tree.functions[this.name].apply(tree.functions, args); } catch (e) { throw { type: e.type || "Runtime", message: "error evaluating function `" + this.name + "`" + (e.message ? ': ' + e.message : ''), index: this.index, filename: this.filename }; } } else { // 2. return new(tree.Anonymous)(this.name + "(" + args.map(function (a) { return a.toCSS(env) }).join(', ') + ")"); } }, toCSS: function (env) { return this.eval(env).toCSS(); } }; })(require('../tree')); (function (tree) { // // RGB Colors - #ff0014, #eee // tree.Color = function (rgb, a) { // // The end goal here, is to parse the arguments // into an integer triplet, such as `128, 255, 0` // // This facilitates operations and conversions. // if (Array.isArray(rgb)) { this.rgb = rgb; } else if (rgb.length == 6) { this.rgb = rgb.match(/.{2}/g).map(function (c) { return parseInt(c, 16); }); } else { this.rgb = rgb.split('').map(function (c) { return parseInt(c + c, 16); }); } this.alpha = typeof(a) === 'number' ? a : 1; }; tree.Color.prototype = { eval: function () { return this }, // // If we have some transparency, the only way to represent it // is via `rgba`. Otherwise, we use the hex representation, // which has better compatibility with older browsers. // Values are capped between `0` and `255`, rounded and zero-padded. // toCSS: function () { if (this.alpha < 1.0) { return "rgba(" + this.rgb.map(function (c) { return Math.round(c); }).concat(this.alpha).join(', ') + ")"; } else { return '#' + this.rgb.map(function (i) { i = Math.round(i); i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16); return i.length === 1 ? '0' + i : i; }).join(''); } }, // // Operations have to be done per-channel, if not, // channels will spill onto each other. Once we have // our result, in the form of an integer triplet, // we create a new Color node to hold the result. // operate: function (op, other) { var result = []; if (! (other instanceof tree.Color)) { other = other.toColor(); } for (var c = 0; c < 3; c++) { result[c] = tree.operate(op, this.rgb[c], other.rgb[c]); } return new(tree.Color)(result, this.alpha + other.alpha); }, toHSL: function () { var r = this.rgb[0] / 255, g = this.rgb[1] / 255, b = this.rgb[2] / 255, a = this.alpha; var max = Math.max(r, g, b), min = Math.min(r, g, b); var h, s, l = (max + min) / 2, d = max - min; if (max === min) { h = s = 0; } else { s = l > 0.5 ? d / (2 - max - min) : d / (max + min); switch (max) { case r: h = (g - b) / d + (g < b ? 6 : 0); break; case g: h = (b - r) / d + 2; break; case b: h = (r - g) / d + 4; break; } h /= 6; } return { h: h * 360, s: s, l: l, a: a }; }, toARGB: function () { var argb = [Math.round(this.alpha * 255)].concat(this.rgb); return '#' + argb.map(function (i) { i = Math.round(i); i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16); return i.length === 1 ? '0' + i : i; }).join(''); }, compare: function (x) { if (!x.rgb) { return -1; } return (x.rgb[0] === this.rgb[0] && x.rgb[1] === this.rgb[1] && x.rgb[2] === this.rgb[2] && x.alpha === this.alpha) ? 0 : -1; } }; })(require('../tree')); (function (tree) { tree.Comment = function (value, silent) { this.value = value; this.silent = !!silent; }; tree.Comment.prototype = { toCSS: function (env) { return env.compress ? '' : this.value; }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.Condition = function (op, l, r, i, negate) { this.op = op.trim(); this.lvalue = l; this.rvalue = r; this.index = i; this.negate = negate; }; tree.Condition.prototype.eval = function (env) { var a = this.lvalue.eval(env), b = this.rvalue.eval(env); var i = this.index, result; var result = (function (op) { switch (op) { case 'and': return a && b; case 'or': return a || b; default: if (a.compare) { result = a.compare(b); } else if (b.compare) { result = b.compare(a); } else { throw { type: "Type", message: "Unable to perform comparison", index: i }; } switch (result) { case -1: return op === '<' || op === '=<'; case 0: return op === '=' || op === '>=' || op === '=<'; case 1: return op === '>' || op === '>='; } } })(this.op); return this.negate ? !result : result; }; })(require('../tree')); (function (tree) { // // A number with a unit // tree.Dimension = function (value, unit) { this.value = parseFloat(value); this.unit = unit || null; }; tree.Dimension.prototype = { eval: function () { return this }, toColor: function () { return new(tree.Color)([this.value, this.value, this.value]); }, toCSS: function () { var css = this.value + this.unit; return css; }, // In an operation between two Dimensions, // we default to the first Dimension's unit, // so `1px + 2em` will yield `3px`. // In the future, we could implement some unit // conversions such that `100cm + 10mm` would yield // `101cm`. operate: function (op, other) { return new(tree.Dimension) (tree.operate(op, this.value, other.value), this.unit || other.unit); }, compare: function (other) { if (other instanceof tree.Dimension) { if (other.value > this.value) { return -1; } else if (other.value < this.value) { return 1; } else { if (other.unit && this.unit !== other.unit) { return -1; } return 0; } } else { return -1; } } }; })(require('../tree')); (function (tree) { tree.Directive = function (name, value) { this.name = name; if (Array.isArray(value)) { this.ruleset = new(tree.Ruleset)([], value); this.ruleset.allowImports = true; } else { this.value = value; } }; tree.Directive.prototype = { toCSS: function (ctx, env) { if (this.ruleset) { this.ruleset.root = true; return this.name + (env.compress ? '{' : ' {\n ') + this.ruleset.toCSS(ctx, env).trim().replace(/\n/g, '\n ') + (env.compress ? '}': '\n}\n'); } else { return this.name + ' ' + this.value.toCSS() + ';\n'; } }, eval: function (env) { var evaldDirective = this; if (this.ruleset) { env.frames.unshift(this); evaldDirective = new(tree.Directive)(this.name); evaldDirective.ruleset = this.ruleset.eval(env); env.frames.shift(); } return evaldDirective; }, variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) }, find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) }, rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) } }; })(require('../tree')); (function (tree) { tree.Element = function (combinator, value, index) { this.combinator = combinator instanceof tree.Combinator ? combinator : new(tree.Combinator)(combinator); if (typeof(value) === 'string') { this.value = value.trim(); } else if (value) { this.value = value; } else { this.value = ""; } this.index = index; }; tree.Element.prototype.eval = function (env) { return new(tree.Element)(this.combinator, this.value.eval ? this.value.eval(env) : this.value, this.index); }; tree.Element.prototype.toCSS = function (env) { var value = (this.value.toCSS ? this.value.toCSS(env) : this.value); if (value == '' && this.combinator.value.charAt(0) == '&') { return ''; } else { return this.combinator.toCSS(env || {}) + value; } }; tree.Combinator = function (value) { if (value === ' ') { this.value = ' '; } else { this.value = value ? value.trim() : ""; } }; tree.Combinator.prototype.toCSS = function (env) { return { '' : '', ' ' : ' ', ':' : ' :', '+' : env.compress ? '+' : ' + ', '~' : env.compress ? '~' : ' ~ ', '>' : env.compress ? '>' : ' > ', '|' : env.compress ? '|' : ' | ' }[this.value]; }; })(require('../tree')); (function (tree) { tree.Expression = function (value) { this.value = value }; tree.Expression.prototype = { eval: function (env) { if (this.value.length > 1) { return new(tree.Expression)(this.value.map(function (e) { return e.eval(env); })); } else if (this.value.length === 1) { return this.value[0].eval(env); } else { return this; } }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS ? e.toCSS(env) : ''; }).join(' '); } }; })(require('../tree')); (function (tree) { // // CSS @import node // // The general strategy here is that we don't want to wait // for the parsing to be completed, before we start importing // the file. That's because in the context of a browser, // most of the time will be spent waiting for the server to respond. // // On creation, we push the import path to our import queue, though // `import,push`, we also pass it a callback, which it'll call once // the file has been fetched, and parsed. // tree.Import = function (path, imports, features, once, index, rootpath) { var that = this; this.once = once; this.index = index; this._path = path; this.features = features && new(tree.Value)(features); this.rootpath = rootpath; // The '.less' extension is optional if (path instanceof tree.Quoted) { this.path = /(\.[a-z]*$)|([\?;].*)$/.test(path.value) ? path.value : path.value + '.less'; } else { this.path = path.value.value || path.value; } this.css = /css([\?;].*)?$/.test(this.path); // Only pre-compile .less files if (! this.css) { imports.push(this.path, function (e, root, imported) { if (e) { e.index = index } if (imported && that.once) that.skip = imported; that.root = root || new(tree.Ruleset)([], []); }); } }; // // The actual import node doesn't return anything, when converted to CSS. // The reason is that it's used at the evaluation stage, so that the rules // it imports can be treated like any other rules. // // In `eval`, we make sure all Import nodes get evaluated, recursively, so // we end up with a flat structure, which can easily be imported in the parent // ruleset. // tree.Import.prototype = { toCSS: function (env) { var features = this.features ? ' ' + this.features.toCSS(env) : ''; if (this.css) { // Add the base path if the import is relative if (typeof this._path.value === "string" && !/^(?:[a-z-]+:|\/)/.test(this._path.value)) { this._path.value = this.rootpath + this._path.value; } return "@import " + this._path.toCSS() + features + ';\n'; } else { return ""; } }, eval: function (env) { var ruleset, features = this.features && this.features.eval(env); if (this.skip) return []; if (this.css) { return this; } else { ruleset = new(tree.Ruleset)([], this.root.rules.slice(0)); ruleset.evalImports(env); return this.features ? new(tree.Media)(ruleset.rules, this.features.value) : ruleset.rules; } } }; })(require('../tree')); (function (tree) { tree.JavaScript = function (string, index, escaped) { this.escaped = escaped; this.expression = string; this.index = index; }; tree.JavaScript.prototype = { eval: function (env) { var result, that = this, context = {}; var expression = this.expression.replace(/@\{([\w-]+)\}/g, function (_, name) { return tree.jsify(new(tree.Variable)('@' + name, that.index).eval(env)); }); try { expression = new(Function)('return (' + expression + ')'); } catch (e) { throw { message: "JavaScript evaluation error: `" + expression + "`" , index: this.index }; } for (var k in env.frames[0].variables()) { context[k.slice(1)] = { value: env.frames[0].variables()[k].value, toJS: function () { return this.value.eval(env).toCSS(); } }; } try { result = expression.call(context); } catch (e) { throw { message: "JavaScript evaluation error: '" + e.name + ': ' + e.message + "'" , index: this.index }; } if (typeof(result) === 'string') { return new(tree.Quoted)('"' + result + '"', result, this.escaped, this.index); } else if (Array.isArray(result)) { return new(tree.Anonymous)(result.join(', ')); } else { return new(tree.Anonymous)(result); } } }; })(require('../tree')); (function (tree) { tree.Keyword = function (value) { this.value = value }; tree.Keyword.prototype = { eval: function () { return this }, toCSS: function () { return this.value }, compare: function (other) { if (other instanceof tree.Keyword) { return other.value === this.value ? 0 : 1; } else { return -1; } } }; tree.True = new(tree.Keyword)('true'); tree.False = new(tree.Keyword)('false'); })(require('../tree')); (function (tree) { tree.Media = function (value, features) { var selectors = this.emptySelectors(); this.features = new(tree.Value)(features); this.ruleset = new(tree.Ruleset)(selectors, value); this.ruleset.allowImports = true; }; tree.Media.prototype = { toCSS: function (ctx, env) { var features = this.features.toCSS(env); this.ruleset.root = (ctx.length === 0 || ctx[0].multiMedia); return '@media ' + features + (env.compress ? '{' : ' {\n ') + this.ruleset.toCSS(ctx, env).trim().replace(/\n/g, '\n ') + (env.compress ? '}': '\n}\n'); }, eval: function (env) { if (!env.mediaBlocks) { env.mediaBlocks = []; env.mediaPath = []; } var media = new(tree.Media)([], []); if(this.debugInfo) { this.ruleset.debugInfo = this.debugInfo; media.debugInfo = this.debugInfo; } media.features = this.features.eval(env); env.mediaPath.push(media); env.mediaBlocks.push(media); env.frames.unshift(this.ruleset); media.ruleset = this.ruleset.eval(env); env.frames.shift(); env.mediaPath.pop(); return env.mediaPath.length === 0 ? media.evalTop(env) : media.evalNested(env) }, variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) }, find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) }, rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) }, emptySelectors: function() { var el = new(tree.Element)('', '&', 0); return [new(tree.Selector)([el])]; }, evalTop: function (env) { var result = this; // Render all dependent Media blocks. if (env.mediaBlocks.length > 1) { var selectors = this.emptySelectors(); result = new(tree.Ruleset)(selectors, env.mediaBlocks); result.multiMedia = true; } delete env.mediaBlocks; delete env.mediaPath; return result; }, evalNested: function (env) { var i, value, path = env.mediaPath.concat([this]); // Extract the media-query conditions separated with `,` (OR). for (i = 0; i < path.length; i++) { value = path[i].features instanceof tree.Value ? path[i].features.value : path[i].features; path[i] = Array.isArray(value) ? value : [value]; } // Trace all permutations to generate the resulting media-query. // // (a, b and c) with nested (d, e) -> // a and d // a and e // b and c and d // b and c and e this.features = new(tree.Value)(this.permute(path).map(function (path) { path = path.map(function (fragment) { return fragment.toCSS ? fragment : new(tree.Anonymous)(fragment); }); for(i = path.length - 1; i > 0; i--) { path.splice(i, 0, new(tree.Anonymous)("and")); } return new(tree.Expression)(path); })); // Fake a tree-node that doesn't output anything. return new(tree.Ruleset)([], []); }, permute: function (arr) { if (arr.length === 0) { return []; } else if (arr.length === 1) { return arr[0]; } else { var result = []; var rest = this.permute(arr.slice(1)); for (var i = 0; i < rest.length; i++) { for (var j = 0; j < arr[0].length; j++) { result.push([arr[0][j]].concat(rest[i])); } } return result; } }, bubbleSelectors: function (selectors) { this.ruleset = new(tree.Ruleset)(selectors.slice(0), [this.ruleset]); } }; })(require('../tree')); (function (tree) { tree.mixin = {}; tree.mixin.Call = function (elements, args, index, filename, important) { this.selector = new(tree.Selector)(elements); this.arguments = args; this.index = index; this.filename = filename; this.important = important; }; tree.mixin.Call.prototype = { eval: function (env) { var mixins, mixin, args, rules = [], match = false, i, m, f, isRecursive, isOneFound; args = this.arguments && this.arguments.map(function (a) { return { name: a.name, value: a.value.eval(env) }; }); for (i = 0; i < env.frames.length; i++) { if ((mixins = env.frames[i].find(this.selector)).length > 0) { isOneFound = true; for (m = 0; m < mixins.length; m++) { mixin = mixins[m]; isRecursive = false; for(f = 0; f < env.frames.length; f++) { if ((!(mixin instanceof tree.mixin.Definition)) && mixin === (env.frames[f].originalRuleset || env.frames[f])) { isRecursive = true; break; } } if (isRecursive) { continue; } if (mixin.matchArgs(args, env)) { if (!mixin.matchCondition || mixin.matchCondition(args, env)) { try { Array.prototype.push.apply( rules, mixin.eval(env, args, this.important).rules); } catch (e) { throw { message: e.message, index: this.index, filename: this.filename, stack: e.stack }; } } match = true; } } if (match) { return rules; } } } if (isOneFound) { throw { type: 'Runtime', message: 'No matching definition was found for `' + this.selector.toCSS().trim() + '(' + (args ? args.map(function (a) { var argValue = ""; if (a.name) { argValue += a.name + ":"; } if (a.value.toCSS) { argValue += a.value.toCSS(); } else { argValue += "???"; } return argValue; }).join(', ') : "") + ")`", index: this.index, filename: this.filename }; } else { throw { type: 'Name', message: this.selector.toCSS().trim() + " is undefined", index: this.index, filename: this.filename }; } } }; tree.mixin.Definition = function (name, params, rules, condition, variadic) { this.name = name; this.selectors = [new(tree.Selector)([new(tree.Element)(null, name)])]; this.params = params; this.condition = condition; this.variadic = variadic; this.arity = params.length; this.rules = rules; this._lookups = {}; this.required = params.reduce(function (count, p) { if (!p.name || (p.name && !p.value)) { return count + 1 } else { return count } }, 0); this.parent = tree.Ruleset.prototype; this.frames = []; }; tree.mixin.Definition.prototype = { toCSS: function () { return "" }, variable: function (name) { return this.parent.variable.call(this, name) }, variables: function () { return this.parent.variables.call(this) }, find: function () { return this.parent.find.apply(this, arguments) }, rulesets: function () { return this.parent.rulesets.apply(this) }, evalParams: function (env, mixinEnv, args, evaldArguments) { var frame = new(tree.Ruleset)(null, []), varargs, arg, params = this.params.slice(0), i, j, val, name, isNamedFound, argIndex; if (args) { args = args.slice(0); for(i = 0; i < args.length; i++) { arg = args[i]; if (name = (arg && arg.name)) { isNamedFound = false; for(j = 0; j < params.length; j++) { if (!evaldArguments[j] && name === params[j].name) { evaldArguments[j] = arg.value.eval(env); frame.rules.unshift(new(tree.Rule)(name, arg.value.eval(env))); isNamedFound = true; break; } } if (isNamedFound) { args.splice(i, 1); i--; continue; } else { throw { type: 'Runtime', message: "Named argument for " + this.name + ' ' + args[i].name + ' not found' }; } } } } argIndex = 0; for (i = 0; i < params.length; i++) { if (evaldArguments[i]) continue; arg = args && args[argIndex]; if (name = params[i].name) { if (params[i].variadic && args) { varargs = []; for (j = argIndex; j < args.length; j++) { varargs.push(args[j].value.eval(env)); } frame.rules.unshift(new(tree.Rule)(name, new(tree.Expression)(varargs).eval(env))); } else { val = arg && arg.value; if (val) { val = val.eval(env); } else if (params[i].value) { val = params[i].value.eval(mixinEnv); } else { throw { type: 'Runtime', message: "wrong number of arguments for " + this.name + ' (' + args.length + ' for ' + this.arity + ')' }; } frame.rules.unshift(new(tree.Rule)(name, val)); evaldArguments[i] = val; } } if (params[i].variadic && args) { for (j = argIndex; j < args.length; j++) { evaldArguments[j] = args[j].value.eval(env); } } argIndex++; } return frame; }, eval: function (env, args, important) { var _arguments = [], mixinFrames = this.frames.concat(env.frames), frame = this.evalParams(env, {frames: mixinFrames}, args, _arguments), context, rules, start, ruleset; frame.rules.unshift(new(tree.Rule)('@arguments', new(tree.Expression)(_arguments).eval(env))); rules = important ? this.parent.makeImportant.apply(this).rules : this.rules.slice(0); ruleset = new(tree.Ruleset)(null, rules).eval({ frames: [this, frame].concat(mixinFrames) }); ruleset.originalRuleset = this; return ruleset; }, matchCondition: function (args, env) { if (this.condition && !this.condition.eval({ frames: [this.evalParams(env, {frames: this.frames.concat(env.frames)}, args, [])].concat(env.frames) })) { return false } return true; }, matchArgs: function (args, env) { var argsLength = (args && args.length) || 0, len, frame; if (! this.variadic) { if (argsLength < this.required) { return false } if (argsLength > this.params.length) { return false } if ((this.required > 0) && (argsLength > this.params.length)) { return false } } len = Math.min(argsLength, this.arity); for (var i = 0; i < len; i++) { if (!this.params[i].name && !this.params[i].variadic) { if (args[i].value.eval(env).toCSS() != this.params[i].value.eval(env).toCSS()) { return false; } } } return true; } }; })(require('../tree')); (function (tree) { tree.Operation = function (op, operands) { this.op = op.trim(); this.operands = operands; }; tree.Operation.prototype.eval = function (env) { var a = this.operands[0].eval(env), b = this.operands[1].eval(env), temp; if (a instanceof tree.Dimension && b instanceof tree.Color) { if (this.op === '*' || this.op === '+') { temp = b, b = a, a = temp; } else { throw { name: "OperationError", message: "Can't substract or divide a color from a number" }; } } if (!a.operate) { throw { name: "OperationError", message: "Operation on an invalid type" }; } return a.operate(this.op, b); }; tree.operate = function (op, a, b) { switch (op) { case '+': return a + b; case '-': return a - b; case '*': return a * b; case '/': return a / b; } }; })(require('../tree')); (function (tree) { tree.Paren = function (node) { this.value = node; }; tree.Paren.prototype = { toCSS: function (env) { return '(' + this.value.toCSS(env) + ')'; }, eval: function (env) { return new(tree.Paren)(this.value.eval(env)); } }; })(require('../tree')); (function (tree) { tree.Quoted = function (str, content, escaped, i) { this.escaped = escaped; this.value = content || ''; this.quote = str.charAt(0); this.index = i; }; tree.Quoted.prototype = { toCSS: function () { if (this.escaped) { return this.value; } else { return this.quote + this.value + this.quote; } }, eval: function (env) { var that = this; var value = this.value.replace(/`([^`]+)`/g, function (_, exp) { return new(tree.JavaScript)(exp, that.index, true).eval(env).value; }).replace(/@\{([\w-]+)\}/g, function (_, name) { var v = new(tree.Variable)('@' + name, that.index).eval(env); return (v instanceof tree.Quoted) ? v.value : v.toCSS(); }); return new(tree.Quoted)(this.quote + value + this.quote, value, this.escaped, this.index); }, compare: function (x) { if (!x.toCSS) { return -1; } var left = this.toCSS(), right = x.toCSS(); if (left === right) { return 0; } return left < right ? -1 : 1; } }; })(require('../tree')); (function (tree) { tree.Ratio = function (value) { this.value = value; }; tree.Ratio.prototype = { toCSS: function (env) { return this.value; }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.Rule = function (name, value, important, index, inline) { this.name = name; this.value = (value instanceof tree.Value) ? value : new(tree.Value)([value]); this.important = important ? ' ' + important.trim() : ''; this.index = index; this.inline = inline || false; if (name.charAt(0) === '@') { this.variable = true; } else { this.variable = false } }; tree.Rule.prototype.toCSS = function (env) { if (this.variable) { return "" } else { return this.name + (env.compress ? ':' : ': ') + this.value.toCSS(env) + this.important + (this.inline ? "" : ";"); } }; tree.Rule.prototype.eval = function (context) { return new(tree.Rule)(this.name, this.value.eval(context), this.important, this.index, this.inline); }; tree.Rule.prototype.makeImportant = function () { return new(tree.Rule)(this.name, this.value, "!important", this.index, this.inline); }; tree.Shorthand = function (a, b) { this.a = a; this.b = b; }; tree.Shorthand.prototype = { toCSS: function (env) { return this.a.toCSS(env) + "/" + this.b.toCSS(env); }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.Ruleset = function (selectors, rules, strictImports) { this.selectors = selectors; this.rules = rules; this._lookups = {}; this.strictImports = strictImports; }; tree.Ruleset.prototype = { eval: function (env) { var selectors = this.selectors && this.selectors.map(function (s) { return s.eval(env) }); var ruleset = new(tree.Ruleset)(selectors, this.rules.slice(0), this.strictImports); var rules; ruleset.originalRuleset = this; ruleset.root = this.root; ruleset.allowImports = this.allowImports; if(this.debugInfo) { ruleset.debugInfo = this.debugInfo; } // push the current ruleset to the frames stack env.frames.unshift(ruleset); // Evaluate imports if (ruleset.root || ruleset.allowImports || !ruleset.strictImports) { ruleset.evalImports(env); } // Store the frames around mixin definitions, // so they can be evaluated like closures when the time comes. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Definition) { ruleset.rules[i].frames = env.frames.slice(0); } } var mediaBlockCount = (env.mediaBlocks && env.mediaBlocks.length) || 0; // Evaluate mixin calls. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Call) { rules = ruleset.rules[i].eval(env); ruleset.rules.splice.apply(ruleset.rules, [i, 1].concat(rules)); i += rules.length-1; ruleset.resetCache(); } } // Evaluate everything else for (var i = 0, rule; i < ruleset.rules.length; i++) { rule = ruleset.rules[i]; if (! (rule instanceof tree.mixin.Definition)) { ruleset.rules[i] = rule.eval ? rule.eval(env) : rule; } } // Pop the stack env.frames.shift(); if (env.mediaBlocks) { for(var i = mediaBlockCount; i < env.mediaBlocks.length; i++) { env.mediaBlocks[i].bubbleSelectors(selectors); } } return ruleset; }, evalImports: function(env) { var i, rules; for (i = 0; i < this.rules.length; i++) { if (this.rules[i] instanceof tree.Import) { rules = this.rules[i].eval(env); if (typeof rules.length === "number") { this.rules.splice.apply(this.rules, [i, 1].concat(rules)); i+= rules.length-1; } else { this.rules.splice(i, 1, rules); } this.resetCache(); } } }, makeImportant: function() { return new tree.Ruleset(this.selectors, this.rules.map(function (r) { if (r.makeImportant) { return r.makeImportant(); } else { return r; } }), this.strictImports); }, matchArgs: function (args) { return !args || args.length === 0; }, resetCache: function () { this._rulesets = null; this._variables = null; this._lookups = {}; }, variables: function () { if (this._variables) { return this._variables } else { return this._variables = this.rules.reduce(function (hash, r) { if (r instanceof tree.Rule && r.variable === true) { hash[r.name] = r; } return hash; }, {}); } }, variable: function (name) { return this.variables()[name]; }, rulesets: function () { if (this._rulesets) { return this._rulesets } else { return this._rulesets = this.rules.filter(function (r) { return (r instanceof tree.Ruleset) || (r instanceof tree.mixin.Definition); }); } }, find: function (selector, self) { self = self || this; var rules = [], rule, match, key = selector.toCSS(); if (key in this._lookups) { return this._lookups[key] } this.rulesets().forEach(function (rule) { if (rule !== self) { for (var j = 0; j < rule.selectors.length; j++) { if (match = selector.match(rule.selectors[j])) { if (selector.elements.length > rule.selectors[j].elements.length) { Array.prototype.push.apply(rules, rule.find( new(tree.Selector)(selector.elements.slice(1)), self)); } else { rules.push(rule); } break; } } } }); return this._lookups[key] = rules; }, // // Entry point for code generation // // `context` holds an array of arrays. // toCSS: function (context, env) { var css = [], // The CSS output rules = [], // node.Rule instances _rules = [], // rulesets = [], // node.Ruleset instances paths = [], // Current selectors selector, // The fully rendered selector debugInfo, // Line number debugging rule; if (! this.root) { this.joinSelectors(paths, context, this.selectors); } // Compile rules and rulesets for (var i = 0; i < this.rules.length; i++) { rule = this.rules[i]; if (rule.rules || (rule instanceof tree.Media)) { rulesets.push(rule.toCSS(paths, env)); } else if (rule instanceof tree.Directive) { var cssValue = rule.toCSS(paths, env); // Output only the first @charset definition as such - convert the others // to comments in case debug is enabled if (rule.name === "@charset") { // Only output the debug info together with subsequent @charset definitions // a comment (or @media statement) before the actual @charset directive would // be considered illegal css as it has to be on the first line if (env.charset) { if (rule.debugInfo) { rulesets.push(tree.debugInfo(env, rule)); rulesets.push(new tree.Comment("/* "+cssValue.replace(/\n/g, "")+" */\n").toCSS(env)); } continue; } env.charset = true; } rulesets.push(cssValue); } else if (rule instanceof tree.Comment) { if (!rule.silent) { if (this.root) { rulesets.push(rule.toCSS(env)); } else { rules.push(rule.toCSS(env)); } } } else { if (rule.toCSS && !rule.variable) { rules.push(rule.toCSS(env)); } else if (rule.value && !rule.variable) { rules.push(rule.value.toString()); } } } rulesets = rulesets.join(''); // If this is the root node, we don't render // a selector, or {}. // Otherwise, only output if this ruleset has rules. if (this.root) { css.push(rules.join(env.compress ? '' : '\n')); } else { if (rules.length > 0) { debugInfo = tree.debugInfo(env, this); selector = paths.map(function (p) { return p.map(function (s) { return s.toCSS(env); }).join('').trim(); }).join(env.compress ? ',' : ',\n'); // Remove duplicates for (var i = rules.length - 1; i >= 0; i--) { if (_rules.indexOf(rules[i]) === -1) { _rules.unshift(rules[i]); } } rules = _rules; css.push(debugInfo + selector + (env.compress ? '{' : ' {\n ') + rules.join(env.compress ? '' : '\n ') + (env.compress ? '}' : '\n}\n')); } } css.push(rulesets); return css.join('') + (env.compress ? '\n' : ''); }, joinSelectors: function (paths, context, selectors) { for (var s = 0; s < selectors.length; s++) { this.joinSelector(paths, context, selectors[s]); } }, joinSelector: function (paths, context, selector) { var i, j, k, hasParentSelector, newSelectors, el, sel, parentSel, newSelectorPath, afterParentJoin, newJoinedSelector, newJoinedSelectorEmpty, lastSelector, currentElements, selectorsMultiplied; for (i = 0; i < selector.elements.length; i++) { el = selector.elements[i]; if (el.value === '&') { hasParentSelector = true; } } if (!hasParentSelector) { if (context.length > 0) { for(i = 0; i < context.length; i++) { paths.push(context[i].concat(selector)); } } else { paths.push([selector]); } return; } // The paths are [[Selector]] // The first list is a list of comma seperated selectors // The inner list is a list of inheritance seperated selectors // e.g. // .a, .b { // .c { // } // } // == [[.a] [.c]] [[.b] [.c]] // // the elements from the current selector so far currentElements = []; // the current list of new selectors to add to the path. // We will build it up. We initiate it with one empty selector as we "multiply" the new selectors // by the parents newSelectors = [[]]; for (i = 0; i < selector.elements.length; i++) { el = selector.elements[i]; // non parent reference elements just get added if (el.value !== "&") { currentElements.push(el); } else { // the new list of selectors to add selectorsMultiplied = []; // merge the current list of non parent selector elements // on to the current list of selectors to add if (currentElements.length > 0) { this.mergeElementsOnToSelectors(currentElements, newSelectors); } // loop through our current selectors for(j = 0; j < newSelectors.length; j++) { sel = newSelectors[j]; // if we don't have any parent paths, the & might be in a mixin so that it can be used // whether there are parents or not if (context.length == 0) { // the combinator used on el should now be applied to the next element instead so that // it is not lost if (sel.length > 0) { sel[0].elements = sel[0].elements.slice(0); sel[0].elements.push(new(tree.Element)(el.combinator, '', 0)); //new Element(el.Combinator, "")); } selectorsMultiplied.push(sel); } else { // and the parent selectors for(k = 0; k < context.length; k++) { parentSel = context[k]; // We need to put the current selectors // then join the last selector's elements on to the parents selectors // our new selector path newSelectorPath = []; // selectors from the parent after the join afterParentJoin = []; newJoinedSelectorEmpty = true; //construct the joined selector - if & is the first thing this will be empty, // if not newJoinedSelector will be the last set of elements in the selector if (sel.length > 0) { newSelectorPath = sel.slice(0); lastSelector = newSelectorPath.pop(); newJoinedSelector = new(tree.Selector)(lastSelector.elements.slice(0)); newJoinedSelectorEmpty = false; } else { newJoinedSelector = new(tree.Selector)([]); } //put together the parent selectors after the join if (parentSel.length > 1) { afterParentJoin = afterParentJoin.concat(parentSel.slice(1)); } if (parentSel.length > 0) { newJoinedSelectorEmpty = false; // join the elements so far with the first part of the parent newJoinedSelector.elements.push(new(tree.Element)(el.combinator, parentSel[0].elements[0].value, 0)); newJoinedSelector.elements = newJoinedSelector.elements.concat(parentSel[0].elements.slice(1)); } if (!newJoinedSelectorEmpty) { // now add the joined selector newSelectorPath.push(newJoinedSelector); } // and the rest of the parent newSelectorPath = newSelectorPath.concat(afterParentJoin); // add that to our new set of selectors selectorsMultiplied.push(newSelectorPath); } } } // our new selectors has been multiplied, so reset the state newSelectors = selectorsMultiplied; currentElements = []; } } // if we have any elements left over (e.g. .a& .b == .b) // add them on to all the current selectors if (currentElements.length > 0) { this.mergeElementsOnToSelectors(currentElements, newSelectors); } for(i = 0; i < newSelectors.length; i++) { paths.push(newSelectors[i]); } }, mergeElementsOnToSelectors: function(elements, selectors) { var i, sel; if (selectors.length == 0) { selectors.push([ new(tree.Selector)(elements) ]); return; } for(i = 0; i < selectors.length; i++) { sel = selectors[i]; // if the previous thing in sel is a parent this needs to join on to it if (sel.length > 0) { sel[sel.length - 1] = new(tree.Selector)(sel[sel.length - 1].elements.concat(elements)); } else { sel.push(new(tree.Selector)(elements)); } } } }; })(require('../tree')); (function (tree) { tree.Selector = function (elements) { this.elements = elements; }; tree.Selector.prototype.match = function (other) { var elements = this.elements, len = elements.length, oelements, olen, max, i; oelements = other.elements.slice( (other.elements.length && other.elements[0].value === "&") ? 1 : 0); olen = oelements.length; max = Math.min(len, olen) if (olen === 0 || len < olen) { return false; } else { for (i = 0; i < max; i++) { if (elements[i].value !== oelements[i].value) { return false; } } } return true; }; tree.Selector.prototype.eval = function (env) { return new(tree.Selector)(this.elements.map(function (e) { return e.eval(env); })); }; tree.Selector.prototype.toCSS = function (env) { if (this._css) { return this._css } if (this.elements[0].combinator.value === "") { this._css = ' '; } else { this._css = ''; } this._css += this.elements.map(function (e) { if (typeof(e) === 'string') { return ' ' + e.trim(); } else { return e.toCSS(env); } }).join(''); return this._css; }; })(require('../tree')); (function (tree) { tree.UnicodeDescriptor = function (value) { this.value = value; }; tree.UnicodeDescriptor.prototype = { toCSS: function (env) { return this.value; }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.URL = function (val, rootpath) { this.value = val; this.rootpath = rootpath; }; tree.URL.prototype = { toCSS: function () { return "url(" + this.value.toCSS() + ")"; }, eval: function (ctx) { var val = this.value.eval(ctx), rootpath; // Add the base path if the URL is relative if (typeof val.value === "string" && !/^(?:[a-z-]+:|\/)/.test(val.value)) { rootpath = this.rootpath; if (!val.quote) { rootpath = rootpath.replace(/[\(\)'"\s]/g, function(match) { return "\\"+match; }); } val.value = rootpath + val.value; } return new(tree.URL)(val, this.rootpath); } }; })(require('../tree')); (function (tree) { tree.Value = function (value) { this.value = value; this.is = 'value'; }; tree.Value.prototype = { eval: function (env) { if (this.value.length === 1) { return this.value[0].eval(env); } else { return new(tree.Value)(this.value.map(function (v) { return v.eval(env); })); } }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS(env); }).join(env.compress ? ',' : ', '); } }; })(require('../tree')); (function (tree) { tree.Variable = function (name, index, file) { this.name = name, this.index = index, this.file = file }; tree.Variable.prototype = { eval: function (env) { var variable, v, name = this.name; if (name.indexOf('@@') == 0) { name = '@' + new(tree.Variable)(name.slice(1)).eval(env).value; } if (this.evaluating) { throw { type: 'Name', message: "Recursive variable definition for " + name, filename: this.file, index: this.index }; } this.evaluating = true; if (variable = tree.find(env.frames, function (frame) { if (v = frame.variable(name)) { return v.value.eval(env); } })) { this.evaluating = false; return variable; } else { throw { type: 'Name', message: "variable " + name + " is undefined", filename: this.file, index: this.index }; } } }; })(require('../tree')); (function (tree) { tree.debugInfo = function(env, ctx) { var result=""; if (env.dumpLineNumbers && !env.compress) { switch(env.dumpLineNumbers) { case 'comments': result = tree.debugInfo.asComment(ctx); break; case 'mediaquery': result = tree.debugInfo.asMediaQuery(ctx); break; case 'all': result = tree.debugInfo.asComment(ctx)+tree.debugInfo.asMediaQuery(ctx); break; } } return result; }; tree.debugInfo.asComment = function(ctx) { return '/* line ' + ctx.debugInfo.lineNumber + ', ' + ctx.debugInfo.fileName + ' */\n'; }; tree.debugInfo.asMediaQuery = function(ctx) { return '@media -sass-debug-info{filename{font-family:' + ('file://' + ctx.debugInfo.fileName).replace(/[\/:.]/g, '\\$&') + '}line{font-family:\\00003' + ctx.debugInfo.lineNumber + '}}\n'; }; tree.find = function (obj, fun) { for (var i = 0, r; i < obj.length; i++) { if (r = fun.call(obj, obj[i])) { return r } } return null; }; tree.jsify = function (obj) { if (Array.isArray(obj.value) && (obj.value.length > 1)) { return '[' + obj.value.map(function (v) { return v.toCSS(false) }).join(', ') + ']'; } else { return obj.toCSS(false); } }; })(require('./tree')); var name; function loadStyleSheet(sheet, callback, reload, remaining) { var endOfPath = Math.max(name.lastIndexOf('/'), name.lastIndexOf('\\')), sheetName = name.slice(0, endOfPath + 1) + sheet.href, contents = sheet.contents || {}, input = readFile(sheetName); contents[sheetName] = input; var parser = new less.Parser({ paths: [sheet.href.replace(/[\w\.-]+$/, '')], contents: contents }); parser.parse(input, function (e, root) { if (e) { return error(e, sheetName); } try { callback(e, root, input, sheet, { local: false, lastModified: 0, remaining: remaining }, sheetName); } catch(e) { error(e, sheetName); } }); } function writeFile(filename, content) { var fstream = new java.io.FileWriter(filename); var out = new java.io.BufferedWriter(fstream); out.write(content); out.close(); } // Command line integration via Rhino (function (args) { var output, compress = false, i; for(i = 0; i < args.length; i++) { switch(args[i]) { case "-x": compress = true; break; default: if (!name) { name = args[i]; } else if (!output) { output = args[i]; } else { print("unrecognised parameters"); print("input_file [output_file] [-x]"); } } } if (!name) { print('No files present in the fileset; Check your pattern match in build.xml'); quit(1); } path = name.split("/");path.pop();path=path.join("/") var input = readFile(name); if (!input) { print('lesscss: couldn\'t open file ' + name); quit(1); } var result; try { var parser = new less.Parser(); parser.parse(input, function (e, root) { if (e) { error(e, name); quit(1); } else { result = root.toCSS({compress: compress || false}); if (output) { writeFile(output, result); print("Written to " + output); } else { print(result); } quit(0); } }); } catch(e) { error(e, name); quit(1); } print("done"); }(arguments)); function error(e, filename) { var content = "Error : " + filename + "\n"; filename = e.filename || filename; if (e.message) { content += e.message + "\n"; } var errorline = function (e, i, classname) { if (e.extract[i]) { content += String(parseInt(e.line) + (i - 1)) + ":" + e.extract[i] + "\n"; } }; if (e.stack) { content += e.stack; } else if (e.extract) { content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':\n'; errorline(e, 0); errorline(e, 1); errorline(e, 2); } print(content); }less.js-1.4.2/dist/less-rhino-1.3.3.js000066400000000000000000004137541217256642200171500ustar00rootroot00000000000000// // Stub out `require` in rhino // function require(arg) { return less[arg.split('/')[1]]; }; // ecma-5.js // // -- kriskowal Kris Kowal Copyright (C) 2009-2010 MIT License // -- tlrobinson Tom Robinson // dantman Daniel Friesen // // Array // if (!Array.isArray) { Array.isArray = function(obj) { return Object.prototype.toString.call(obj) === "[object Array]" || (obj instanceof Array); }; } if (!Array.prototype.forEach) { Array.prototype.forEach = function(block, thisObject) { var len = this.length >>> 0; for (var i = 0; i < len; i++) { if (i in this) { block.call(thisObject, this[i], i, this); } } }; } if (!Array.prototype.map) { Array.prototype.map = function(fun /*, thisp*/) { var len = this.length >>> 0; var res = new Array(len); var thisp = arguments[1]; for (var i = 0; i < len; i++) { if (i in this) { res[i] = fun.call(thisp, this[i], i, this); } } return res; }; } if (!Array.prototype.filter) { Array.prototype.filter = function (block /*, thisp */) { var values = []; var thisp = arguments[1]; for (var i = 0; i < this.length; i++) { if (block.call(thisp, this[i])) { values.push(this[i]); } } return values; }; } if (!Array.prototype.reduce) { Array.prototype.reduce = function(fun /*, initial*/) { var len = this.length >>> 0; var i = 0; // no value to return if no initial value and an empty array if (len === 0 && arguments.length === 1) throw new TypeError(); if (arguments.length >= 2) { var rv = arguments[1]; } else { do { if (i in this) { rv = this[i++]; break; } // if array contains no values, no initial value to return if (++i >= len) throw new TypeError(); } while (true); } for (; i < len; i++) { if (i in this) { rv = fun.call(null, rv, this[i], i, this); } } return rv; }; } if (!Array.prototype.indexOf) { Array.prototype.indexOf = function (value /*, fromIndex */ ) { var length = this.length; var i = arguments[1] || 0; if (!length) return -1; if (i >= length) return -1; if (i < 0) i += length; for (; i < length; i++) { if (!Object.prototype.hasOwnProperty.call(this, i)) { continue } if (value === this[i]) return i; } return -1; }; } // // Object // if (!Object.keys) { Object.keys = function (object) { var keys = []; for (var name in object) { if (Object.prototype.hasOwnProperty.call(object, name)) { keys.push(name); } } return keys; }; } // // String // if (!String.prototype.trim) { String.prototype.trim = function () { return String(this).replace(/^\s\s*/, '').replace(/\s\s*$/, ''); }; } var less, tree, charset; if (typeof environment === "object" && ({}).toString.call(environment) === "[object Environment]") { // Rhino // Details on how to detect Rhino: https://github.com/ringo/ringojs/issues/88 if (typeof(window) === 'undefined') { less = {} } else { less = window.less = {} } tree = less.tree = {}; less.mode = 'rhino'; } else if (typeof(window) === 'undefined') { // Node.js less = exports, tree = require('./tree'); less.mode = 'node'; } else { // Browser if (typeof(window.less) === 'undefined') { window.less = {} } less = window.less, tree = window.less.tree = {}; less.mode = 'browser'; } // // less.js - parser // // A relatively straight-forward predictive parser. // There is no tokenization/lexing stage, the input is parsed // in one sweep. // // To make the parser fast enough to run in the browser, several // optimization had to be made: // // - Matching and slicing on a huge input is often cause of slowdowns. // The solution is to chunkify the input into smaller strings. // The chunks are stored in the `chunks` var, // `j` holds the current chunk index, and `current` holds // the index of the current chunk in relation to `input`. // This gives us an almost 4x speed-up. // // - In many cases, we don't need to match individual tokens; // for example, if a value doesn't hold any variables, operations // or dynamic references, the parser can effectively 'skip' it, // treating it as a literal. // An example would be '1px solid #000' - which evaluates to itself, // we don't need to know what the individual components are. // The drawback, of course is that you don't get the benefits of // syntax-checking on the CSS. This gives us a 50% speed-up in the parser, // and a smaller speed-up in the code-gen. // // // Token matching is done with the `$` function, which either takes // a terminal string or regexp, or a non-terminal function to call. // It also takes care of moving all the indices forwards. // // less.Parser = function Parser(env) { var input, // LeSS input string i, // current index in `input` j, // current chunk temp, // temporarily holds a chunk's state, for backtracking memo, // temporarily holds `i`, when backtracking furthest, // furthest index the parser has gone to chunks, // chunkified input current, // index of current chunk, in `input` parser; var that = this; // Top parser on an import tree must be sure there is one "env" // which will then be passed arround by reference. var env = env || { }; // env.contents and files must be passed arround with top env if (!env.contents) { env.contents = {}; } env.rootpath = env.rootpath || ''; // env.rootpath must be initialized to '' if not provided if (!env.files) { env.files = {}; } // This function is called after all files // have been imported through `@import`. var finish = function () {}; var imports = this.imports = { paths: env.paths || [], // Search paths, when importing queue: [], // Files which haven't been imported yet files: env.files, // Holds the imported parse trees contents: env.contents, // Holds the imported file contents mime: env.mime, // MIME type of .less files error: null, // Error in parsing/evaluating an import push: function (path, callback) { var that = this; this.queue.push(path); // // Import a file asynchronously // less.Parser.importer(path, this.paths, function (e, root, fullPath) { that.queue.splice(that.queue.indexOf(path), 1); // Remove the path from the queue var imported = fullPath in that.files; that.files[fullPath] = root; // Store the root if (e && !that.error) { that.error = e } callback(e, root, imported); if (that.queue.length === 0) { finish(that.error) } // Call `finish` if we're done importing }, env); } }; function save() { temp = chunks[j], memo = i, current = i } function restore() { chunks[j] = temp, i = memo, current = i } function sync() { if (i > current) { chunks[j] = chunks[j].slice(i - current); current = i; } } function isWhitespace(c) { // Could change to \s? var code = c.charCodeAt(0); return code === 32 || code === 10 || code === 9; } // // Parse from a token, regexp or string, and move forward if match // function $(tok) { var match, args, length, index, k; // // Non-terminal // if (tok instanceof Function) { return tok.call(parser.parsers); // // Terminal // // Either match a single character in the input, // or match a regexp in the current chunk (chunk[j]). // } else if (typeof(tok) === 'string') { match = input.charAt(i) === tok ? tok : null; length = 1; sync (); } else { sync (); if (match = tok.exec(chunks[j])) { length = match[0].length; } else { return null; } } // The match is confirmed, add the match length to `i`, // and consume any extra white-space characters (' ' || '\n') // which come after that. The reason for this is that LeSS's // grammar is mostly white-space insensitive. // if (match) { skipWhitespace(length); if(typeof(match) === 'string') { return match; } else { return match.length === 1 ? match[0] : match; } } } function skipWhitespace(length) { var oldi = i, oldj = j, endIndex = i + chunks[j].length, mem = i += length; while (i < endIndex) { if (! isWhitespace(input.charAt(i))) { break } i++; } chunks[j] = chunks[j].slice(length + (i - mem)); current = i; if (chunks[j].length === 0 && j < chunks.length - 1) { j++ } return oldi !== i || oldj !== j; } function expect(arg, msg) { var result = $(arg); if (! result) { error(msg || (typeof(arg) === 'string' ? "expected '" + arg + "' got '" + input.charAt(i) + "'" : "unexpected token")); } else { return result; } } function error(msg, type) { var e = new Error(msg); e.index = i; e.type = type || 'Syntax'; throw e; } // Same as $(), but don't change the state of the parser, // just return the match. function peek(tok) { if (typeof(tok) === 'string') { return input.charAt(i) === tok; } else { if (tok.test(chunks[j])) { return true; } else { return false; } } } function getInput(e, env) { if (e.filename && env.filename && (e.filename !== env.filename)) { return parser.imports.contents[e.filename]; } else { return input; } } function getLocation(index, input) { for (var n = index, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } return { line: typeof(index) === 'number' ? (input.slice(0, index).match(/\n/g) || "").length : null, column: column }; } function getFileName(e) { if(less.mode === 'browser' || less.mode === 'rhino') return e.filename; else return require('path').resolve(e.filename); } function getDebugInfo(index, inputStream, e) { return { lineNumber: getLocation(index, inputStream).line + 1, fileName: getFileName(e) }; } function LessError(e, env) { var input = getInput(e, env), loc = getLocation(e.index, input), line = loc.line, col = loc.column, lines = input.split('\n'); this.type = e.type || 'Syntax'; this.message = e.message; this.filename = e.filename || env.filename; this.index = e.index; this.line = typeof(line) === 'number' ? line + 1 : null; this.callLine = e.call && (getLocation(e.call, input).line + 1); this.callExtract = lines[getLocation(e.call, input).line]; this.stack = e.stack; this.column = col; this.extract = [ lines[line - 1], lines[line], lines[line + 1] ]; } this.env = env = env || {}; // The optimization level dictates the thoroughness of the parser, // the lower the number, the less nodes it will create in the tree. // This could matter for debugging, or if you want to access // the individual nodes in the tree. this.optimization = ('optimization' in this.env) ? this.env.optimization : 1; this.env.filename = this.env.filename || null; // // The Parser // return parser = { imports: imports, // // Parse an input string into an abstract syntax tree, // call `callback` when done. // parse: function (str, callback) { var root, start, end, zone, line, lines, buff = [], c, error = null; i = j = current = furthest = 0; input = str.replace(/\r\n/g, '\n'); // Remove potential UTF Byte Order Mark input = input.replace(/^\uFEFF/, ''); // Split the input into chunks. chunks = (function (chunks) { var j = 0, skip = /(?:@\{[\w-]+\}|[^"'`\{\}\/\(\)\\])+/g, comment = /\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g, string = /"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'|`((?:[^`]|\\.)*)`/g, level = 0, match, chunk = chunks[0], inParam; for (var i = 0, c, cc; i < input.length;) { skip.lastIndex = i; if (match = skip.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); } } c = input.charAt(i); comment.lastIndex = string.lastIndex = i; if (match = string.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); continue; } } if (!inParam && c === '/') { cc = input.charAt(i + 1); if (cc === '/' || cc === '*') { if (match = comment.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); continue; } } } } switch (c) { case '{': if (! inParam) { level ++; chunk.push(c); break } case '}': if (! inParam) { level --; chunk.push(c); chunks[++j] = chunk = []; break } case '(': if (! inParam) { inParam = true; chunk.push(c); break } case ')': if ( inParam) { inParam = false; chunk.push(c); break } default: chunk.push(c); } i++; } if (level != 0) { error = new(LessError)({ index: i-1, type: 'Parse', message: (level > 0) ? "missing closing `}`" : "missing opening `{`", filename: env.filename }, env); } return chunks.map(function (c) { return c.join('') });; })([[]]); if (error) { return callback(error, env); } // Start with the primary rule. // The whole syntax tree is held under a Ruleset node, // with the `root` property set to true, so no `{}` are // output. The callback is called when the input is parsed. try { root = new(tree.Ruleset)([], $(this.parsers.primary)); root.root = true; } catch (e) { return callback(new(LessError)(e, env)); } root.toCSS = (function (evaluate) { var line, lines, column; return function (options, variables) { var frames = [], importError; options = options || {}; // // Allows setting variables with a hash, so: // // `{ color: new(tree.Color)('#f01') }` will become: // // new(tree.Rule)('@color', // new(tree.Value)([ // new(tree.Expression)([ // new(tree.Color)('#f01') // ]) // ]) // ) // if (typeof(variables) === 'object' && !Array.isArray(variables)) { variables = Object.keys(variables).map(function (k) { var value = variables[k]; if (! (value instanceof tree.Value)) { if (! (value instanceof tree.Expression)) { value = new(tree.Expression)([value]); } value = new(tree.Value)([value]); } return new(tree.Rule)('@' + k, value, false, 0); }); frames = [new(tree.Ruleset)(null, variables)]; } try { var css = evaluate.call(this, { frames: frames }) .toCSS([], { compress: options.compress || false, dumpLineNumbers: env.dumpLineNumbers }); } catch (e) { throw new(LessError)(e, env); } if ((importError = parser.imports.error)) { // Check if there was an error during importing if (importError instanceof LessError) throw importError; else throw new(LessError)(importError, env); } if (options.yuicompress && less.mode === 'node') { return require('ycssmin').cssmin(css); } else if (options.compress) { return css.replace(/(\s)+/g, "$1"); } else { return css; } }; })(root.eval); // If `i` is smaller than the `input.length - 1`, // it means the parser wasn't able to parse the whole // string, so we've got a parsing error. // // We try to extract a \n delimited string, // showing the line where the parse error occured. // We split it up into two parts (the part which parsed, // and the part which didn't), so we can color them differently. if (i < input.length - 1) { i = furthest; lines = input.split('\n'); line = (input.slice(0, i).match(/\n/g) || "").length + 1; for (var n = i, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } error = { type: "Parse", message: "Syntax Error on line " + line, index: i, filename: env.filename, line: line, column: column, extract: [ lines[line - 2], lines[line - 1], lines[line] ] }; } if (this.imports.queue.length > 0) { finish = function (e) { e = error || e; if (e) callback(e); else callback(null, root); }; } else { callback(error, root); } }, // // Here in, the parsing rules/functions // // The basic structure of the syntax tree generated is as follows: // // Ruleset -> Rule -> Value -> Expression -> Entity // // Here's some LESS code: // // .class { // color: #fff; // border: 1px solid #000; // width: @w + 4px; // > .child {...} // } // // And here's what the parse tree might look like: // // Ruleset (Selector '.class', [ // Rule ("color", Value ([Expression [Color #fff]])) // Rule ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]])) // Rule ("width", Value ([Expression [Operation "+" [Variable "@w"][Dimension 4px]]])) // Ruleset (Selector [Element '>', '.child'], [...]) // ]) // // In general, most rules will try to parse a token with the `$()` function, and if the return // value is truly, will return a new node, of the relevant type. Sometimes, we need to check // first, before parsing, that's when we use `peek()`. // parsers: { // // The `primary` rule is the *entry* and *exit* point of the parser. // The rules here can appear at any level of the parse tree. // // The recursive nature of the grammar is an interplay between the `block` // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule, // as represented by this simplified grammar: // // primary → (ruleset | rule)+ // ruleset → selector+ block // block → '{' primary '}' // // Only at one point is the primary rule not called from the // block rule: at the root level. // primary: function () { var node, root = []; while ((node = $(this.mixin.definition) || $(this.rule) || $(this.ruleset) || $(this.mixin.call) || $(this.comment) || $(this.directive)) || $(/^[\s\n]+/) || $(/^;+/)) { node && root.push(node); } return root; }, // We create a Comment node for CSS comments `/* */`, // but keep the LeSS comments `//` silent, by just skipping // over them. comment: function () { var comment; if (input.charAt(i) !== '/') return; if (input.charAt(i + 1) === '/') { return new(tree.Comment)($(/^\/\/.*/), true); } else if (comment = $(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/)) { return new(tree.Comment)(comment); } }, // // Entities are tokens which can be found inside an Expression // entities: { // // A string, which supports escaping " and ' // // "milky way" 'he\'s the one!' // quoted: function () { var str, j = i, e; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '"' && input.charAt(j) !== "'") return; e && $('~'); if (str = $(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/)) { return new(tree.Quoted)(str[0], str[1] || str[2], e); } }, // // A catch-all word, such as: // // black border-collapse // keyword: function () { var k; if (k = $(/^[_A-Za-z-][_A-Za-z0-9-]*/)) { if (tree.colors.hasOwnProperty(k)) { // detect named color return new(tree.Color)(tree.colors[k].slice(1)); } else { return new(tree.Keyword)(k); } } }, // // A function call // // rgb(255, 0, 255) // // We also try to catch IE's `alpha()`, but let the `alpha` parser // deal with the details. // // The arguments are parsed with the `entities.arguments` parser. // call: function () { var name, nameLC, args, alpha_ret, index = i; if (! (name = /^([\w-]+|%|progid:[\w\.]+)\(/.exec(chunks[j]))) return; name = name[1]; nameLC = name.toLowerCase(); if (nameLC === 'url') { return null } else { i += name.length } if (nameLC === 'alpha') { alpha_ret = $(this.alpha); if(typeof alpha_ret !== 'undefined') { return alpha_ret; } } $('('); // Parse the '(' and consume whitespace. args = $(this.entities.arguments); if (! $(')')) return; if (name) { return new(tree.Call)(name, args, index, env.filename) } }, arguments: function () { var args = [], arg; while (arg = $(this.entities.assignment) || $(this.expression)) { args.push(arg); if (! $(',')) { break } } return args; }, literal: function () { return $(this.entities.ratio) || $(this.entities.dimension) || $(this.entities.color) || $(this.entities.quoted) || $(this.entities.unicodeDescriptor); }, // Assignments are argument entities for calls. // They are present in ie filter properties as shown below. // // filter: progid:DXImageTransform.Microsoft.Alpha( *opacity=50* ) // assignment: function () { var key, value; if ((key = $(/^\w+(?=\s?=)/i)) && $('=') && (value = $(this.entity))) { return new(tree.Assignment)(key, value); } }, // // Parse url() tokens // // We use a specific rule for urls, because they don't really behave like // standard function calls. The difference is that the argument doesn't have // to be enclosed within a string, so it can't be parsed as an Expression. // url: function () { var value; if (input.charAt(i) !== 'u' || !$(/^url\(/)) return; value = $(this.entities.quoted) || $(this.entities.variable) || $(/^(?:(?:\\[\(\)'"])|[^\(\)'"])+/) || ""; expect(')'); return new(tree.URL)((value.value != null || value instanceof tree.Variable) ? value : new(tree.Anonymous)(value), env.rootpath); }, // // A Variable entity, such as `@fink`, in // // width: @fink + 2px // // We use a different parser for variable definitions, // see `parsers.variable`. // variable: function () { var name, index = i; if (input.charAt(i) === '@' && (name = $(/^@@?[\w-]+/))) { return new(tree.Variable)(name, index, env.filename); } }, // A variable entity useing the protective {} e.g. @{var} variableCurly: function () { var name, curly, index = i; if (input.charAt(i) === '@' && (curly = $(/^@\{([\w-]+)\}/))) { return new(tree.Variable)("@" + curly[1], index, env.filename); } }, // // A Hexadecimal color // // #4F3C2F // // `rgb` and `hsl` colors are parsed through the `entities.call` parser. // color: function () { var rgb; if (input.charAt(i) === '#' && (rgb = $(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/))) { return new(tree.Color)(rgb[1]); } }, // // A Dimension, that is, a number and a unit // // 0.5em 95% // dimension: function () { var value, c = input.charCodeAt(i); //Is the first char of the dimension 0-9, '.', '+' or '-' if ((c > 57 || c < 43) || c === 47 || c == 44) return; if (value = $(/^([+-]?\d*\.?\d+)(px|%|em|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn|dpi|dpcm|dppx|rem|vw|vh|vmin|vm|ch)?/)) { return new(tree.Dimension)(value[1], value[2]); } }, // // A Ratio // // 16/9 // ratio: function () { var value, c = input.charCodeAt(i); if (c > 57 || c < 48) return; if (value = $(/^(\d+\/\d+)/)) { return new(tree.Ratio)(value[1]); } }, // // A unicode descriptor, as is used in unicode-range // // U+0?? or U+00A1-00A9 // unicodeDescriptor: function () { var ud; if (ud = $(/^U\+[0-9a-fA-F?]+(\-[0-9a-fA-F?]+)?/)) { return new(tree.UnicodeDescriptor)(ud[0]); } }, // // JavaScript code to be evaluated // // `window.location.href` // javascript: function () { var str, j = i, e; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '`') { return } e && $('~'); if (str = $(/^`([^`]*)`/)) { return new(tree.JavaScript)(str[1], i, e); } } }, // // The variable part of a variable definition. Used in the `rule` parser // // @fink: // variable: function () { var name; if (input.charAt(i) === '@' && (name = $(/^(@[\w-]+)\s*:/))) { return name[1] } }, // // A font size/line-height shorthand // // small/12px // // We need to peek first, or we'll match on keywords and dimensions // shorthand: function () { var a, b; if (! peek(/^[@\w.%-]+\/[@\w.-]+/)) return; save(); if ((a = $(this.entity)) && $('/') && (b = $(this.entity))) { return new(tree.Shorthand)(a, b); } restore(); }, // // Mixins // mixin: { // // A Mixin call, with an optional argument list // // #mixins > .square(#fff); // .rounded(4px, black); // .button; // // The `while` loop is there because mixins can be // namespaced, but we only support the child and descendant // selector for now. // call: function () { var elements = [], e, c, argsSemiColon = [], argsComma = [], args, delim, arg, nameLoop, expressions, isSemiColonSeperated, expressionContainsNamed, index = i, s = input.charAt(i), name, value, important = false; if (s !== '.' && s !== '#') { return } save(); // stop us absorbing part of an invalid selector while (e = $(/^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/)) { elements.push(new(tree.Element)(c, e, i)); c = $('>'); } if ($('(')) { expressions = []; while (arg = $(this.expression)) { nameLoop = null; value = arg; // Variable if (arg.value.length == 1) { var val = arg.value[0]; if (val instanceof tree.Variable) { if ($(':')) { if (expressions.length > 0) { if (isSemiColonSeperated) { error("Cannot mix ; and , as delimiter types"); } expressionContainsNamed = true; } value = expect(this.expression); nameLoop = (name = val.name); } } } expressions.push(value); argsComma.push({ name: nameLoop, value: value }); if ($(',')) { continue; } if ($(';') || isSemiColonSeperated) { if (expressionContainsNamed) { error("Cannot mix ; and , as delimiter types"); } isSemiColonSeperated = true; if (expressions.length > 1) { value = new(tree.Value)(expressions); } argsSemiColon.push({ name: name, value: value }); name = null; expressions = []; expressionContainsNamed = false; } } expect(')'); } args = isSemiColonSeperated ? argsSemiColon : argsComma; if ($(this.important)) { important = true; } if (elements.length > 0 && ($(';') || peek('}'))) { return new(tree.mixin.Call)(elements, args, index, env.filename, important); } restore(); }, // // A Mixin definition, with a list of parameters // // .rounded (@radius: 2px, @color) { // ... // } // // Until we have a finer grained state-machine, we have to // do a look-ahead, to make sure we don't have a mixin call. // See the `rule` function for more information. // // We start by matching `.rounded (`, and then proceed on to // the argument list, which has optional default values. // We store the parameters in `params`, with a `value` key, // if there is a value, such as in the case of `@radius`. // // Once we've got our params list, and a closing `)`, we parse // the `{...}` block. // definition: function () { var name, params = [], match, ruleset, param, value, cond, variadic = false; if ((input.charAt(i) !== '.' && input.charAt(i) !== '#') || peek(/^[^{]*\}/)) return; save(); if (match = $(/^([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/)) { name = match[1]; do { $(this.comment); if (input.charAt(i) === '.' && $(/^\.{3}/)) { variadic = true; params.push({ variadic: true }); break; } else if (param = $(this.entities.variable) || $(this.entities.literal) || $(this.entities.keyword)) { // Variable if (param instanceof tree.Variable) { if ($(':')) { value = expect(this.expression, 'expected expression'); params.push({ name: param.name, value: value }); } else if ($(/^\.{3}/)) { params.push({ name: param.name, variadic: true }); variadic = true; break; } else { params.push({ name: param.name }); } } else { params.push({ value: param }); } } else { break; } } while ($(',') || $(';')) // .mixincall("@{a}"); // looks a bit like a mixin definition.. so we have to be nice and restore if (!$(')')) { furthest = i; restore(); } $(this.comment); if ($(/^when/)) { // Guard cond = expect(this.conditions, 'expected condition'); } ruleset = $(this.block); if (ruleset) { return new(tree.mixin.Definition)(name, params, ruleset, cond, variadic); } else { restore(); } } } }, // // Entities are the smallest recognized token, // and can be found inside a rule's value. // entity: function () { return $(this.entities.literal) || $(this.entities.variable) || $(this.entities.url) || $(this.entities.call) || $(this.entities.keyword) ||$(this.entities.javascript) || $(this.comment); }, // // A Rule terminator. Note that we use `peek()` to check for '}', // because the `block` rule will be expecting it, but we still need to make sure // it's there, if ';' was ommitted. // end: function () { return $(';') || peek('}'); }, // // IE's alpha function // // alpha(opacity=88) // alpha: function () { var value; if (! $(/^\(opacity=/i)) return; if (value = $(/^\d+/) || $(this.entities.variable)) { expect(')'); return new(tree.Alpha)(value); } }, // // A Selector Element // // div // + h1 // #socks // input[type="text"] // // Elements are the building blocks for Selectors, // they are made out of a `Combinator` (see combinator rule), // and an element name, such as a tag a class, or `*`. // element: function () { var e, t, c, v; c = $(this.combinator); e = $(/^(?:\d+\.\d+|\d+)%/) || $(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/) || $('*') || $('&') || $(this.attribute) || $(/^\([^()@]+\)/) || $(/^[\.#](?=@)/) || $(this.entities.variableCurly); if (! e) { if ($('(')) { if ((v = ($(this.entities.variableCurly) || $(this.entities.variable) || $(this.selector))) && $(')')) { e = new(tree.Paren)(v); } } } if (e) { return new(tree.Element)(c, e, i) } }, // // Combinators combine elements together, in a Selector. // // Because our parser isn't white-space sensitive, special care // has to be taken, when parsing the descendant combinator, ` `, // as it's an empty space. We have to check the previous character // in the input, to see if it's a ` ` character. More info on how // we deal with this in *combinator.js*. // combinator: function () { var match, c = input.charAt(i); if (c === '>' || c === '+' || c === '~' || c === '|') { i++; while (input.charAt(i).match(/\s/)) { i++ } return new(tree.Combinator)(c); } else if (input.charAt(i - 1).match(/\s/)) { return new(tree.Combinator)(" "); } else { return new(tree.Combinator)(null); } }, // // A CSS Selector // // .class > div + h1 // li a:hover // // Selectors are made out of one or more Elements, see above. // selector: function () { var sel, e, elements = [], c, match; // depreciated, will be removed soon if ($('(')) { sel = $(this.entity); if (!$(')')) { return null; } return new(tree.Selector)([new(tree.Element)('', sel, i)]); } while (e = $(this.element)) { c = input.charAt(i); elements.push(e) if (c === '{' || c === '}' || c === ';' || c === ',' || c === ')') { break } } if (elements.length > 0) { return new(tree.Selector)(elements) } }, attribute: function () { var attr = '', key, val, op; if (! $('[')) return; if (key = $(/^(?:[_A-Za-z0-9-]|\\.)+/) || $(this.entities.quoted)) { if ((op = $(/^[|~*$^]?=/)) && (val = $(this.entities.quoted) || $(/^[\w-]+/))) { attr = [key, op, val.toCSS ? val.toCSS() : val].join(''); } else { attr = key } } if (! $(']')) return; if (attr) { return "[" + attr + "]" } }, // // The `block` rule is used by `ruleset` and `mixin.definition`. // It's a wrapper around the `primary` rule, with added `{}`. // block: function () { var content; if ($('{') && (content = $(this.primary)) && $('}')) { return content; } }, // // div, .class, body > p {...} // ruleset: function () { var selectors = [], s, rules, match, debugInfo; save(); if (env.dumpLineNumbers) debugInfo = getDebugInfo(i, input, env); while (s = $(this.selector)) { selectors.push(s); $(this.comment); if (! $(',')) { break } $(this.comment); } if (selectors.length > 0 && (rules = $(this.block))) { var ruleset = new(tree.Ruleset)(selectors, rules, env.strictImports); if (env.dumpLineNumbers) ruleset.debugInfo = debugInfo; return ruleset; } else { // Backtrack furthest = i; restore(); } }, rule: function () { var name, value, c = input.charAt(i), important, match; save(); if (c === '.' || c === '#' || c === '&') { return } if (name = $(this.variable) || $(this.property)) { if ((name.charAt(0) != '@') && (match = /^([^@+\/'"*`(;{}-]*);/.exec(chunks[j]))) { i += match[0].length - 1; value = new(tree.Anonymous)(match[1]); } else if (name === "font") { value = $(this.font); } else { value = $(this.value); } important = $(this.important); if (value && $(this.end)) { return new(tree.Rule)(name, value, important, memo); } else { furthest = i; restore(); } } }, // // An @import directive // // @import "lib"; // // Depending on our environemnt, importing is done differently: // In the browser, it's an XHR request, in Node, it would be a // file-system operation. The function used for importing is // stored in `import`, which we pass to the Import constructor. // "import": function () { var path, features, index = i; save(); var dir = $(/^@import(?:-(once))?\s+/); if (dir && (path = $(this.entities.quoted) || $(this.entities.url))) { features = $(this.mediaFeatures); if ($(';')) { return new(tree.Import)(path, imports, features, (dir[1] === 'once'), index, env.rootpath); } } restore(); }, mediaFeature: function () { var e, p, nodes = []; do { if (e = $(this.entities.keyword)) { nodes.push(e); } else if ($('(')) { p = $(this.property); e = $(this.entity); if ($(')')) { if (p && e) { nodes.push(new(tree.Paren)(new(tree.Rule)(p, e, null, i, true))); } else if (e) { nodes.push(new(tree.Paren)(e)); } else { return null; } } else { return null } } } while (e); if (nodes.length > 0) { return new(tree.Expression)(nodes); } }, mediaFeatures: function () { var e, features = []; do { if (e = $(this.mediaFeature)) { features.push(e); if (! $(',')) { break } } else if (e = $(this.entities.variable)) { features.push(e); if (! $(',')) { break } } } while (e); return features.length > 0 ? features : null; }, media: function () { var features, rules, media, debugInfo; if (env.dumpLineNumbers) debugInfo = getDebugInfo(i, input, env); if ($(/^@media/)) { features = $(this.mediaFeatures); if (rules = $(this.block)) { media = new(tree.Media)(rules, features); if(env.dumpLineNumbers) media.debugInfo = debugInfo; return media; } } }, // // A CSS Directive // // @charset "utf-8"; // directive: function () { var name, value, rules, identifier, e, nodes, nonVendorSpecificName, hasBlock, hasIdentifier, hasExpression; if (input.charAt(i) !== '@') return; if (value = $(this['import']) || $(this.media)) { return value; } save(); name = $(/^@[a-z-]+/); if (!name) return; nonVendorSpecificName = name; if (name.charAt(1) == '-' && name.indexOf('-', 2) > 0) { nonVendorSpecificName = "@" + name.slice(name.indexOf('-', 2) + 1); } switch(nonVendorSpecificName) { case "@font-face": hasBlock = true; break; case "@viewport": case "@top-left": case "@top-left-corner": case "@top-center": case "@top-right": case "@top-right-corner": case "@bottom-left": case "@bottom-left-corner": case "@bottom-center": case "@bottom-right": case "@bottom-right-corner": case "@left-top": case "@left-middle": case "@left-bottom": case "@right-top": case "@right-middle": case "@right-bottom": hasBlock = true; break; case "@page": case "@document": case "@supports": case "@keyframes": hasBlock = true; hasIdentifier = true; break; case "@namespace": hasExpression = true; break; } if (hasIdentifier) { name += " " + ($(/^[^{]+/) || '').trim(); } if (hasBlock) { if (rules = $(this.block)) { return new(tree.Directive)(name, rules); } } else { if ((value = hasExpression ? $(this.expression) : $(this.entity)) && $(';')) { var directive = new(tree.Directive)(name, value); if (env.dumpLineNumbers) { directive.debugInfo = getDebugInfo(i, input, env); } return directive; } } restore(); }, font: function () { var value = [], expression = [], weight, shorthand, font, e; while (e = $(this.shorthand) || $(this.entity)) { expression.push(e); } value.push(new(tree.Expression)(expression)); if ($(',')) { while (e = $(this.expression)) { value.push(e); if (! $(',')) { break } } } return new(tree.Value)(value); }, // // A Value is a comma-delimited list of Expressions // // font-family: Baskerville, Georgia, serif; // // In a Rule, a Value represents everything after the `:`, // and before the `;`. // value: function () { var e, expressions = [], important; while (e = $(this.expression)) { expressions.push(e); if (! $(',')) { break } } if (expressions.length > 0) { return new(tree.Value)(expressions); } }, important: function () { if (input.charAt(i) === '!') { return $(/^! *important/); } }, sub: function () { var e; if ($('(') && (e = $(this.expression)) && $(')')) { return e; } }, multiplication: function () { var m, a, op, operation; if (m = $(this.operand)) { while (!peek(/^\/[*\/]/) && (op = ($('/') || $('*'))) && (a = $(this.operand))) { operation = new(tree.Operation)(op, [operation || m, a]); } return operation || m; } }, addition: function () { var m, a, op, operation; if (m = $(this.multiplication)) { while ((op = $(/^[-+]\s+/) || (!isWhitespace(input.charAt(i - 1)) && ($('+') || $('-')))) && (a = $(this.multiplication))) { operation = new(tree.Operation)(op, [operation || m, a]); } return operation || m; } }, conditions: function () { var a, b, index = i, condition; if (a = $(this.condition)) { while ($(',') && (b = $(this.condition))) { condition = new(tree.Condition)('or', condition || a, b, index); } return condition || a; } }, condition: function () { var a, b, c, op, index = i, negate = false; if ($(/^not/)) { negate = true } expect('('); if (a = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) { if (op = $(/^(?:>=|=<|[<=>])/)) { if (b = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) { c = new(tree.Condition)(op, a, b, index, negate); } else { error('expected expression'); } } else { c = new(tree.Condition)('=', a, new(tree.Keyword)('true'), index, negate); } expect(')'); return $(/^and/) ? new(tree.Condition)('and', c, $(this.condition)) : c; } }, // // An operand is anything that can be part of an operation, // such as a Color, or a Variable // operand: function () { var negate, p = input.charAt(i + 1); if (input.charAt(i) === '-' && (p === '@' || p === '(')) { negate = $('-') } var o = $(this.sub) || $(this.entities.dimension) || $(this.entities.color) || $(this.entities.variable) || $(this.entities.call); return negate ? new(tree.Operation)('*', [new(tree.Dimension)(-1), o]) : o; }, // // Expressions either represent mathematical operations, // or white-space delimited Entities. // // 1px solid black // @var * 2 // expression: function () { var e, delim, entities = [], d; while (e = $(this.addition) || $(this.entity)) { entities.push(e); } if (entities.length > 0) { return new(tree.Expression)(entities); } }, property: function () { var name; if (name = $(/^(\*?-?[_a-z0-9-]+)\s*:/)) { return name[1]; } } } }; }; if (less.mode === 'browser' || less.mode === 'rhino') { // // Used by `@import` directives // less.Parser.importer = function (path, paths, callback, env) { if (!/^([a-z-]+:)?\//.test(path) && paths.length > 0) { path = paths[0] + path; } // We pass `true` as 3rd argument, to force the reload of the import. // This is so we can get the syntax tree as opposed to just the CSS output, // as we need this to evaluate the current stylesheet. loadStyleSheet({ href: path, title: path, type: env.mime, contents: env.contents, files: env.files, rootpath: env.rootpath, entryPath: env.entryPath, relativeUrls: env.relativeUrls }, function (e, root, data, sheet, _, path) { if (e && typeof(env.errback) === "function") { env.errback.call(null, path, paths, callback, env); } else { callback.call(null, e, root, path); } }, true); }; } (function (tree) { tree.functions = { rgb: function (r, g, b) { return this.rgba(r, g, b, 1.0); }, rgba: function (r, g, b, a) { var rgb = [r, g, b].map(function (c) { return scaled(c, 256); }); a = number(a); return new(tree.Color)(rgb, a); }, hsl: function (h, s, l) { return this.hsla(h, s, l, 1.0); }, hsla: function (h, s, l, a) { h = (number(h) % 360) / 360; s = number(s); l = number(l); a = number(a); var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s; var m1 = l * 2 - m2; return this.rgba(hue(h + 1/3) * 255, hue(h) * 255, hue(h - 1/3) * 255, a); function hue(h) { h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h); if (h * 6 < 1) return m1 + (m2 - m1) * h * 6; else if (h * 2 < 1) return m2; else if (h * 3 < 2) return m1 + (m2 - m1) * (2/3 - h) * 6; else return m1; } }, hsv: function(h, s, v) { return this.hsva(h, s, v, 1.0); }, hsva: function(h, s, v, a) { h = ((number(h) % 360) / 360) * 360; s = number(s); v = number(v); a = number(a); var i, f; i = Math.floor((h / 60) % 6); f = (h / 60) - i; var vs = [v, v * (1 - s), v * (1 - f * s), v * (1 - (1 - f) * s)]; var perm = [[0, 3, 1], [2, 0, 1], [1, 0, 3], [1, 2, 0], [3, 1, 0], [0, 1, 2]]; return this.rgba(vs[perm[i][0]] * 255, vs[perm[i][1]] * 255, vs[perm[i][2]] * 255, a); }, hue: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().h)); }, saturation: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().s * 100), '%'); }, lightness: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().l * 100), '%'); }, red: function (color) { return new(tree.Dimension)(color.rgb[0]); }, green: function (color) { return new(tree.Dimension)(color.rgb[1]); }, blue: function (color) { return new(tree.Dimension)(color.rgb[2]); }, alpha: function (color) { return new(tree.Dimension)(color.toHSL().a); }, luma: function (color) { return new(tree.Dimension)(Math.round((0.2126 * (color.rgb[0]/255) + 0.7152 * (color.rgb[1]/255) + 0.0722 * (color.rgb[2]/255)) * color.alpha * 100), '%'); }, saturate: function (color, amount) { var hsl = color.toHSL(); hsl.s += amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, desaturate: function (color, amount) { var hsl = color.toHSL(); hsl.s -= amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, lighten: function (color, amount) { var hsl = color.toHSL(); hsl.l += amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, darken: function (color, amount) { var hsl = color.toHSL(); hsl.l -= amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, fadein: function (color, amount) { var hsl = color.toHSL(); hsl.a += amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, fadeout: function (color, amount) { var hsl = color.toHSL(); hsl.a -= amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, fade: function (color, amount) { var hsl = color.toHSL(); hsl.a = amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, spin: function (color, amount) { var hsl = color.toHSL(); var hue = (hsl.h + amount.value) % 360; hsl.h = hue < 0 ? 360 + hue : hue; return hsla(hsl); }, // // Copyright (c) 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein // http://sass-lang.com // mix: function (color1, color2, weight) { if (!weight) { weight = new(tree.Dimension)(50); } var p = weight.value / 100.0; var w = p * 2 - 1; var a = color1.toHSL().a - color2.toHSL().a; var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0; var w2 = 1 - w1; var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2, color1.rgb[1] * w1 + color2.rgb[1] * w2, color1.rgb[2] * w1 + color2.rgb[2] * w2]; var alpha = color1.alpha * p + color2.alpha * (1 - p); return new(tree.Color)(rgb, alpha); }, greyscale: function (color) { return this.desaturate(color, new(tree.Dimension)(100)); }, contrast: function (color, dark, light, threshold) { // filter: contrast(3.2); // should be kept as is, so check for color if (!color.rgb) { return null; } if (typeof light === 'undefined') { light = this.rgba(255, 255, 255, 1.0); } if (typeof dark === 'undefined') { dark = this.rgba(0, 0, 0, 1.0); } if (typeof threshold === 'undefined') { threshold = 0.43; } else { threshold = threshold.value; } if (((0.2126 * (color.rgb[0]/255) + 0.7152 * (color.rgb[1]/255) + 0.0722 * (color.rgb[2]/255)) * color.alpha) < threshold) { return light; } else { return dark; } }, e: function (str) { return new(tree.Anonymous)(str instanceof tree.JavaScript ? str.evaluated : str); }, escape: function (str) { return new(tree.Anonymous)(encodeURI(str.value).replace(/=/g, "%3D").replace(/:/g, "%3A").replace(/#/g, "%23").replace(/;/g, "%3B").replace(/\(/g, "%28").replace(/\)/g, "%29")); }, '%': function (quoted /* arg, arg, ...*/) { var args = Array.prototype.slice.call(arguments, 1), str = quoted.value; for (var i = 0; i < args.length; i++) { str = str.replace(/%[sda]/i, function(token) { var value = token.match(/s/i) ? args[i].value : args[i].toCSS(); return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value; }); } str = str.replace(/%%/g, '%'); return new(tree.Quoted)('"' + str + '"', str); }, unit: function (val, unit) { return new(tree.Dimension)(val.value, unit ? unit.toCSS() : ""); }, round: function (n, f) { var fraction = typeof(f) === "undefined" ? 0 : f.value; return this._math(function(num) { return num.toFixed(fraction); }, n); }, ceil: function (n) { return this._math(Math.ceil, n); }, floor: function (n) { return this._math(Math.floor, n); }, _math: function (fn, n) { if (n instanceof tree.Dimension) { return new(tree.Dimension)(fn(parseFloat(n.value)), n.unit); } else if (typeof(n) === 'number') { return fn(n); } else { throw { type: "Argument", message: "argument must be a number" }; } }, argb: function (color) { return new(tree.Anonymous)(color.toARGB()); }, percentage: function (n) { return new(tree.Dimension)(n.value * 100, '%'); }, color: function (n) { if (n instanceof tree.Quoted) { return new(tree.Color)(n.value.slice(1)); } else { throw { type: "Argument", message: "argument must be a string" }; } }, iscolor: function (n) { return this._isa(n, tree.Color); }, isnumber: function (n) { return this._isa(n, tree.Dimension); }, isstring: function (n) { return this._isa(n, tree.Quoted); }, iskeyword: function (n) { return this._isa(n, tree.Keyword); }, isurl: function (n) { return this._isa(n, tree.URL); }, ispixel: function (n) { return (n instanceof tree.Dimension) && n.unit === 'px' ? tree.True : tree.False; }, ispercentage: function (n) { return (n instanceof tree.Dimension) && n.unit === '%' ? tree.True : tree.False; }, isem: function (n) { return (n instanceof tree.Dimension) && n.unit === 'em' ? tree.True : tree.False; }, _isa: function (n, Type) { return (n instanceof Type) ? tree.True : tree.False; }, /* Blending modes */ multiply: function(color1, color2) { var r = color1.rgb[0] * color2.rgb[0] / 255; var g = color1.rgb[1] * color2.rgb[1] / 255; var b = color1.rgb[2] * color2.rgb[2] / 255; return this.rgb(r, g, b); }, screen: function(color1, color2) { var r = 255 - (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255; var g = 255 - (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255; var b = 255 - (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255; return this.rgb(r, g, b); }, overlay: function(color1, color2) { var r = color1.rgb[0] < 128 ? 2 * color1.rgb[0] * color2.rgb[0] / 255 : 255 - 2 * (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255; var g = color1.rgb[1] < 128 ? 2 * color1.rgb[1] * color2.rgb[1] / 255 : 255 - 2 * (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255; var b = color1.rgb[2] < 128 ? 2 * color1.rgb[2] * color2.rgb[2] / 255 : 255 - 2 * (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255; return this.rgb(r, g, b); }, softlight: function(color1, color2) { var t = color2.rgb[0] * color1.rgb[0] / 255; var r = t + color1.rgb[0] * (255 - (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255 - t) / 255; t = color2.rgb[1] * color1.rgb[1] / 255; var g = t + color1.rgb[1] * (255 - (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255 - t) / 255; t = color2.rgb[2] * color1.rgb[2] / 255; var b = t + color1.rgb[2] * (255 - (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255 - t) / 255; return this.rgb(r, g, b); }, hardlight: function(color1, color2) { var r = color2.rgb[0] < 128 ? 2 * color2.rgb[0] * color1.rgb[0] / 255 : 255 - 2 * (255 - color2.rgb[0]) * (255 - color1.rgb[0]) / 255; var g = color2.rgb[1] < 128 ? 2 * color2.rgb[1] * color1.rgb[1] / 255 : 255 - 2 * (255 - color2.rgb[1]) * (255 - color1.rgb[1]) / 255; var b = color2.rgb[2] < 128 ? 2 * color2.rgb[2] * color1.rgb[2] / 255 : 255 - 2 * (255 - color2.rgb[2]) * (255 - color1.rgb[2]) / 255; return this.rgb(r, g, b); }, difference: function(color1, color2) { var r = Math.abs(color1.rgb[0] - color2.rgb[0]); var g = Math.abs(color1.rgb[1] - color2.rgb[1]); var b = Math.abs(color1.rgb[2] - color2.rgb[2]); return this.rgb(r, g, b); }, exclusion: function(color1, color2) { var r = color1.rgb[0] + color2.rgb[0] * (255 - color1.rgb[0] - color1.rgb[0]) / 255; var g = color1.rgb[1] + color2.rgb[1] * (255 - color1.rgb[1] - color1.rgb[1]) / 255; var b = color1.rgb[2] + color2.rgb[2] * (255 - color1.rgb[2] - color1.rgb[2]) / 255; return this.rgb(r, g, b); }, average: function(color1, color2) { var r = (color1.rgb[0] + color2.rgb[0]) / 2; var g = (color1.rgb[1] + color2.rgb[1]) / 2; var b = (color1.rgb[2] + color2.rgb[2]) / 2; return this.rgb(r, g, b); }, negation: function(color1, color2) { var r = 255 - Math.abs(255 - color2.rgb[0] - color1.rgb[0]); var g = 255 - Math.abs(255 - color2.rgb[1] - color1.rgb[1]); var b = 255 - Math.abs(255 - color2.rgb[2] - color1.rgb[2]); return this.rgb(r, g, b); }, tint: function(color, amount) { return this.mix(this.rgb(255,255,255), color, amount); }, shade: function(color, amount) { return this.mix(this.rgb(0, 0, 0), color, amount); } }; function hsla(color) { return tree.functions.hsla(color.h, color.s, color.l, color.a); } function scaled(n, size) { if (n instanceof tree.Dimension && n.unit == '%') { return parseFloat(n.value * size / 100); } else { return number(n); } } function number(n) { if (n instanceof tree.Dimension) { return parseFloat(n.unit == '%' ? n.value / 100 : n.value); } else if (typeof(n) === 'number') { return n; } else { throw { error: "RuntimeError", message: "color functions take numbers as parameters" }; } } function clamp(val) { return Math.min(1, Math.max(0, val)); } })(require('./tree')); (function (tree) { tree.colors = { 'aliceblue':'#f0f8ff', 'antiquewhite':'#faebd7', 'aqua':'#00ffff', 'aquamarine':'#7fffd4', 'azure':'#f0ffff', 'beige':'#f5f5dc', 'bisque':'#ffe4c4', 'black':'#000000', 'blanchedalmond':'#ffebcd', 'blue':'#0000ff', 'blueviolet':'#8a2be2', 'brown':'#a52a2a', 'burlywood':'#deb887', 'cadetblue':'#5f9ea0', 'chartreuse':'#7fff00', 'chocolate':'#d2691e', 'coral':'#ff7f50', 'cornflowerblue':'#6495ed', 'cornsilk':'#fff8dc', 'crimson':'#dc143c', 'cyan':'#00ffff', 'darkblue':'#00008b', 'darkcyan':'#008b8b', 'darkgoldenrod':'#b8860b', 'darkgray':'#a9a9a9', 'darkgrey':'#a9a9a9', 'darkgreen':'#006400', 'darkkhaki':'#bdb76b', 'darkmagenta':'#8b008b', 'darkolivegreen':'#556b2f', 'darkorange':'#ff8c00', 'darkorchid':'#9932cc', 'darkred':'#8b0000', 'darksalmon':'#e9967a', 'darkseagreen':'#8fbc8f', 'darkslateblue':'#483d8b', 'darkslategray':'#2f4f4f', 'darkslategrey':'#2f4f4f', 'darkturquoise':'#00ced1', 'darkviolet':'#9400d3', 'deeppink':'#ff1493', 'deepskyblue':'#00bfff', 'dimgray':'#696969', 'dimgrey':'#696969', 'dodgerblue':'#1e90ff', 'firebrick':'#b22222', 'floralwhite':'#fffaf0', 'forestgreen':'#228b22', 'fuchsia':'#ff00ff', 'gainsboro':'#dcdcdc', 'ghostwhite':'#f8f8ff', 'gold':'#ffd700', 'goldenrod':'#daa520', 'gray':'#808080', 'grey':'#808080', 'green':'#008000', 'greenyellow':'#adff2f', 'honeydew':'#f0fff0', 'hotpink':'#ff69b4', 'indianred':'#cd5c5c', 'indigo':'#4b0082', 'ivory':'#fffff0', 'khaki':'#f0e68c', 'lavender':'#e6e6fa', 'lavenderblush':'#fff0f5', 'lawngreen':'#7cfc00', 'lemonchiffon':'#fffacd', 'lightblue':'#add8e6', 'lightcoral':'#f08080', 'lightcyan':'#e0ffff', 'lightgoldenrodyellow':'#fafad2', 'lightgray':'#d3d3d3', 'lightgrey':'#d3d3d3', 'lightgreen':'#90ee90', 'lightpink':'#ffb6c1', 'lightsalmon':'#ffa07a', 'lightseagreen':'#20b2aa', 'lightskyblue':'#87cefa', 'lightslategray':'#778899', 'lightslategrey':'#778899', 'lightsteelblue':'#b0c4de', 'lightyellow':'#ffffe0', 'lime':'#00ff00', 'limegreen':'#32cd32', 'linen':'#faf0e6', 'magenta':'#ff00ff', 'maroon':'#800000', 'mediumaquamarine':'#66cdaa', 'mediumblue':'#0000cd', 'mediumorchid':'#ba55d3', 'mediumpurple':'#9370d8', 'mediumseagreen':'#3cb371', 'mediumslateblue':'#7b68ee', 'mediumspringgreen':'#00fa9a', 'mediumturquoise':'#48d1cc', 'mediumvioletred':'#c71585', 'midnightblue':'#191970', 'mintcream':'#f5fffa', 'mistyrose':'#ffe4e1', 'moccasin':'#ffe4b5', 'navajowhite':'#ffdead', 'navy':'#000080', 'oldlace':'#fdf5e6', 'olive':'#808000', 'olivedrab':'#6b8e23', 'orange':'#ffa500', 'orangered':'#ff4500', 'orchid':'#da70d6', 'palegoldenrod':'#eee8aa', 'palegreen':'#98fb98', 'paleturquoise':'#afeeee', 'palevioletred':'#d87093', 'papayawhip':'#ffefd5', 'peachpuff':'#ffdab9', 'peru':'#cd853f', 'pink':'#ffc0cb', 'plum':'#dda0dd', 'powderblue':'#b0e0e6', 'purple':'#800080', 'red':'#ff0000', 'rosybrown':'#bc8f8f', 'royalblue':'#4169e1', 'saddlebrown':'#8b4513', 'salmon':'#fa8072', 'sandybrown':'#f4a460', 'seagreen':'#2e8b57', 'seashell':'#fff5ee', 'sienna':'#a0522d', 'silver':'#c0c0c0', 'skyblue':'#87ceeb', 'slateblue':'#6a5acd', 'slategray':'#708090', 'slategrey':'#708090', 'snow':'#fffafa', 'springgreen':'#00ff7f', 'steelblue':'#4682b4', 'tan':'#d2b48c', 'teal':'#008080', 'thistle':'#d8bfd8', 'tomato':'#ff6347', // 'transparent':'rgba(0,0,0,0)', 'turquoise':'#40e0d0', 'violet':'#ee82ee', 'wheat':'#f5deb3', 'white':'#ffffff', 'whitesmoke':'#f5f5f5', 'yellow':'#ffff00', 'yellowgreen':'#9acd32' }; })(require('./tree')); (function (tree) { tree.Alpha = function (val) { this.value = val; }; tree.Alpha.prototype = { toCSS: function () { return "alpha(opacity=" + (this.value.toCSS ? this.value.toCSS() : this.value) + ")"; }, eval: function (env) { if (this.value.eval) { this.value = this.value.eval(env) } return this; } }; })(require('../tree')); (function (tree) { tree.Anonymous = function (string) { this.value = string.value || string; }; tree.Anonymous.prototype = { toCSS: function () { return this.value; }, eval: function () { return this }, compare: function (x) { if (!x.toCSS) { return -1; } var left = this.toCSS(), right = x.toCSS(); if (left === right) { return 0; } return left < right ? -1 : 1; } }; })(require('../tree')); (function (tree) { tree.Assignment = function (key, val) { this.key = key; this.value = val; }; tree.Assignment.prototype = { toCSS: function () { return this.key + '=' + (this.value.toCSS ? this.value.toCSS() : this.value); }, eval: function (env) { if (this.value.eval) { return new(tree.Assignment)(this.key, this.value.eval(env)); } return this; } }; })(require('../tree'));(function (tree) { // // A function call node. // tree.Call = function (name, args, index, filename) { this.name = name; this.args = args; this.index = index; this.filename = filename; }; tree.Call.prototype = { // // When evaluating a function call, // we either find the function in `tree.functions` [1], // in which case we call it, passing the evaluated arguments, // if this returns null or we cannot find the function, we // simply print it out as it appeared originally [2]. // // The *functions.js* file contains the built-in functions. // // The reason why we evaluate the arguments, is in the case where // we try to pass a variable to a function, like: `saturate(@color)`. // The function should receive the value, not the variable. // eval: function (env) { var args = this.args.map(function (a) { return a.eval(env) }), result; if (this.name in tree.functions) { // 1. try { result = tree.functions[this.name].apply(tree.functions, args); if (result != null) { return result; } } catch (e) { throw { type: e.type || "Runtime", message: "error evaluating function `" + this.name + "`" + (e.message ? ': ' + e.message : ''), index: this.index, filename: this.filename }; } } // 2. return new(tree.Anonymous)(this.name + "(" + args.map(function (a) { return a.toCSS(env) }).join(', ') + ")"); }, toCSS: function (env) { return this.eval(env).toCSS(); } }; })(require('../tree')); (function (tree) { // // RGB Colors - #ff0014, #eee // tree.Color = function (rgb, a) { // // The end goal here, is to parse the arguments // into an integer triplet, such as `128, 255, 0` // // This facilitates operations and conversions. // if (Array.isArray(rgb)) { this.rgb = rgb; } else if (rgb.length == 6) { this.rgb = rgb.match(/.{2}/g).map(function (c) { return parseInt(c, 16); }); } else { this.rgb = rgb.split('').map(function (c) { return parseInt(c + c, 16); }); } this.alpha = typeof(a) === 'number' ? a : 1; }; tree.Color.prototype = { eval: function () { return this }, // // If we have some transparency, the only way to represent it // is via `rgba`. Otherwise, we use the hex representation, // which has better compatibility with older browsers. // Values are capped between `0` and `255`, rounded and zero-padded. // toCSS: function () { if (this.alpha < 1.0) { return "rgba(" + this.rgb.map(function (c) { return Math.round(c); }).concat(this.alpha).join(', ') + ")"; } else { return '#' + this.rgb.map(function (i) { i = Math.round(i); i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16); return i.length === 1 ? '0' + i : i; }).join(''); } }, // // Operations have to be done per-channel, if not, // channels will spill onto each other. Once we have // our result, in the form of an integer triplet, // we create a new Color node to hold the result. // operate: function (op, other) { var result = []; if (! (other instanceof tree.Color)) { other = other.toColor(); } for (var c = 0; c < 3; c++) { result[c] = tree.operate(op, this.rgb[c], other.rgb[c]); } return new(tree.Color)(result, this.alpha + other.alpha); }, toHSL: function () { var r = this.rgb[0] / 255, g = this.rgb[1] / 255, b = this.rgb[2] / 255, a = this.alpha; var max = Math.max(r, g, b), min = Math.min(r, g, b); var h, s, l = (max + min) / 2, d = max - min; if (max === min) { h = s = 0; } else { s = l > 0.5 ? d / (2 - max - min) : d / (max + min); switch (max) { case r: h = (g - b) / d + (g < b ? 6 : 0); break; case g: h = (b - r) / d + 2; break; case b: h = (r - g) / d + 4; break; } h /= 6; } return { h: h * 360, s: s, l: l, a: a }; }, toARGB: function () { var argb = [Math.round(this.alpha * 255)].concat(this.rgb); return '#' + argb.map(function (i) { i = Math.round(i); i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16); return i.length === 1 ? '0' + i : i; }).join(''); }, compare: function (x) { if (!x.rgb) { return -1; } return (x.rgb[0] === this.rgb[0] && x.rgb[1] === this.rgb[1] && x.rgb[2] === this.rgb[2] && x.alpha === this.alpha) ? 0 : -1; } }; })(require('../tree')); (function (tree) { tree.Comment = function (value, silent) { this.value = value; this.silent = !!silent; }; tree.Comment.prototype = { toCSS: function (env) { return env.compress ? '' : this.value; }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.Condition = function (op, l, r, i, negate) { this.op = op.trim(); this.lvalue = l; this.rvalue = r; this.index = i; this.negate = negate; }; tree.Condition.prototype.eval = function (env) { var a = this.lvalue.eval(env), b = this.rvalue.eval(env); var i = this.index, result; var result = (function (op) { switch (op) { case 'and': return a && b; case 'or': return a || b; default: if (a.compare) { result = a.compare(b); } else if (b.compare) { result = b.compare(a); } else { throw { type: "Type", message: "Unable to perform comparison", index: i }; } switch (result) { case -1: return op === '<' || op === '=<'; case 0: return op === '=' || op === '>=' || op === '=<'; case 1: return op === '>' || op === '>='; } } })(this.op); return this.negate ? !result : result; }; })(require('../tree')); (function (tree) { // // A number with a unit // tree.Dimension = function (value, unit) { this.value = parseFloat(value); this.unit = unit || null; }; tree.Dimension.prototype = { eval: function () { return this }, toColor: function () { return new(tree.Color)([this.value, this.value, this.value]); }, toCSS: function () { var css = this.value + this.unit; return css; }, // In an operation between two Dimensions, // we default to the first Dimension's unit, // so `1px + 2em` will yield `3px`. // In the future, we could implement some unit // conversions such that `100cm + 10mm` would yield // `101cm`. operate: function (op, other) { return new(tree.Dimension) (tree.operate(op, this.value, other.value), this.unit || other.unit); }, compare: function (other) { if (other instanceof tree.Dimension) { if (other.value > this.value) { return -1; } else if (other.value < this.value) { return 1; } else { if (other.unit && this.unit !== other.unit) { return -1; } return 0; } } else { return -1; } } }; })(require('../tree')); (function (tree) { tree.Directive = function (name, value) { this.name = name; if (Array.isArray(value)) { this.ruleset = new(tree.Ruleset)([], value); this.ruleset.allowImports = true; } else { this.value = value; } }; tree.Directive.prototype = { toCSS: function (ctx, env) { if (this.ruleset) { this.ruleset.root = true; return this.name + (env.compress ? '{' : ' {\n ') + this.ruleset.toCSS(ctx, env).trim().replace(/\n/g, '\n ') + (env.compress ? '}': '\n}\n'); } else { return this.name + ' ' + this.value.toCSS() + ';\n'; } }, eval: function (env) { var evaldDirective = this; if (this.ruleset) { env.frames.unshift(this); evaldDirective = new(tree.Directive)(this.name); evaldDirective.ruleset = this.ruleset.eval(env); env.frames.shift(); } return evaldDirective; }, variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) }, find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) }, rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) } }; })(require('../tree')); (function (tree) { tree.Element = function (combinator, value, index) { this.combinator = combinator instanceof tree.Combinator ? combinator : new(tree.Combinator)(combinator); if (typeof(value) === 'string') { this.value = value.trim(); } else if (value) { this.value = value; } else { this.value = ""; } this.index = index; }; tree.Element.prototype.eval = function (env) { return new(tree.Element)(this.combinator, this.value.eval ? this.value.eval(env) : this.value, this.index); }; tree.Element.prototype.toCSS = function (env) { var value = (this.value.toCSS ? this.value.toCSS(env) : this.value); if (value == '' && this.combinator.value.charAt(0) == '&') { return ''; } else { return this.combinator.toCSS(env || {}) + value; } }; tree.Combinator = function (value) { if (value === ' ') { this.value = ' '; } else { this.value = value ? value.trim() : ""; } }; tree.Combinator.prototype.toCSS = function (env) { return { '' : '', ' ' : ' ', ':' : ' :', '+' : env.compress ? '+' : ' + ', '~' : env.compress ? '~' : ' ~ ', '>' : env.compress ? '>' : ' > ', '|' : env.compress ? '|' : ' | ' }[this.value]; }; })(require('../tree')); (function (tree) { tree.Expression = function (value) { this.value = value }; tree.Expression.prototype = { eval: function (env) { if (this.value.length > 1) { return new(tree.Expression)(this.value.map(function (e) { return e.eval(env); })); } else if (this.value.length === 1) { return this.value[0].eval(env); } else { return this; } }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS ? e.toCSS(env) : ''; }).join(' '); } }; })(require('../tree')); (function (tree) { // // CSS @import node // // The general strategy here is that we don't want to wait // for the parsing to be completed, before we start importing // the file. That's because in the context of a browser, // most of the time will be spent waiting for the server to respond. // // On creation, we push the import path to our import queue, though // `import,push`, we also pass it a callback, which it'll call once // the file has been fetched, and parsed. // tree.Import = function (path, imports, features, once, index, rootpath) { var that = this; this.once = once; this.index = index; this._path = path; this.features = features && new(tree.Value)(features); this.rootpath = rootpath; // The '.less' extension is optional if (path instanceof tree.Quoted) { this.path = /(\.[a-z]*$)|([\?;].*)$/.test(path.value) ? path.value : path.value + '.less'; } else { this.path = path.value.value || path.value; } this.css = /css([\?;].*)?$/.test(this.path); // Only pre-compile .less files if (! this.css) { imports.push(this.path, function (e, root, imported) { if (e) { e.index = index } if (imported && that.once) that.skip = imported; that.root = root || new(tree.Ruleset)([], []); }); } }; // // The actual import node doesn't return anything, when converted to CSS. // The reason is that it's used at the evaluation stage, so that the rules // it imports can be treated like any other rules. // // In `eval`, we make sure all Import nodes get evaluated, recursively, so // we end up with a flat structure, which can easily be imported in the parent // ruleset. // tree.Import.prototype = { toCSS: function (env) { var features = this.features ? ' ' + this.features.toCSS(env) : ''; if (this.css) { // Add the base path if the import is relative if (typeof this._path.value === "string" && !/^(?:[a-z-]+:|\/)/.test(this._path.value)) { this._path.value = this.rootpath + this._path.value; } return "@import " + this._path.toCSS() + features + ';\n'; } else { return ""; } }, eval: function (env) { var ruleset, features = this.features && this.features.eval(env); if (this.skip) return []; if (this.css) { return this; } else { ruleset = new(tree.Ruleset)([], this.root.rules.slice(0)); ruleset.evalImports(env); return this.features ? new(tree.Media)(ruleset.rules, this.features.value) : ruleset.rules; } } }; })(require('../tree')); (function (tree) { tree.JavaScript = function (string, index, escaped) { this.escaped = escaped; this.expression = string; this.index = index; }; tree.JavaScript.prototype = { eval: function (env) { var result, that = this, context = {}; var expression = this.expression.replace(/@\{([\w-]+)\}/g, function (_, name) { return tree.jsify(new(tree.Variable)('@' + name, that.index).eval(env)); }); try { expression = new(Function)('return (' + expression + ')'); } catch (e) { throw { message: "JavaScript evaluation error: `" + expression + "`" , index: this.index }; } for (var k in env.frames[0].variables()) { context[k.slice(1)] = { value: env.frames[0].variables()[k].value, toJS: function () { return this.value.eval(env).toCSS(); } }; } try { result = expression.call(context); } catch (e) { throw { message: "JavaScript evaluation error: '" + e.name + ': ' + e.message + "'" , index: this.index }; } if (typeof(result) === 'string') { return new(tree.Quoted)('"' + result + '"', result, this.escaped, this.index); } else if (Array.isArray(result)) { return new(tree.Anonymous)(result.join(', ')); } else { return new(tree.Anonymous)(result); } } }; })(require('../tree')); (function (tree) { tree.Keyword = function (value) { this.value = value }; tree.Keyword.prototype = { eval: function () { return this }, toCSS: function () { return this.value }, compare: function (other) { if (other instanceof tree.Keyword) { return other.value === this.value ? 0 : 1; } else { return -1; } } }; tree.True = new(tree.Keyword)('true'); tree.False = new(tree.Keyword)('false'); })(require('../tree')); (function (tree) { tree.Media = function (value, features) { var selectors = this.emptySelectors(); this.features = new(tree.Value)(features); this.ruleset = new(tree.Ruleset)(selectors, value); this.ruleset.allowImports = true; }; tree.Media.prototype = { toCSS: function (ctx, env) { var features = this.features.toCSS(env); this.ruleset.root = (ctx.length === 0 || ctx[0].multiMedia); return '@media ' + features + (env.compress ? '{' : ' {\n ') + this.ruleset.toCSS(ctx, env).trim().replace(/\n/g, '\n ') + (env.compress ? '}': '\n}\n'); }, eval: function (env) { if (!env.mediaBlocks) { env.mediaBlocks = []; env.mediaPath = []; } var media = new(tree.Media)([], []); if(this.debugInfo) { this.ruleset.debugInfo = this.debugInfo; media.debugInfo = this.debugInfo; } media.features = this.features.eval(env); env.mediaPath.push(media); env.mediaBlocks.push(media); env.frames.unshift(this.ruleset); media.ruleset = this.ruleset.eval(env); env.frames.shift(); env.mediaPath.pop(); return env.mediaPath.length === 0 ? media.evalTop(env) : media.evalNested(env) }, variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) }, find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) }, rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) }, emptySelectors: function() { var el = new(tree.Element)('', '&', 0); return [new(tree.Selector)([el])]; }, evalTop: function (env) { var result = this; // Render all dependent Media blocks. if (env.mediaBlocks.length > 1) { var selectors = this.emptySelectors(); result = new(tree.Ruleset)(selectors, env.mediaBlocks); result.multiMedia = true; } delete env.mediaBlocks; delete env.mediaPath; return result; }, evalNested: function (env) { var i, value, path = env.mediaPath.concat([this]); // Extract the media-query conditions separated with `,` (OR). for (i = 0; i < path.length; i++) { value = path[i].features instanceof tree.Value ? path[i].features.value : path[i].features; path[i] = Array.isArray(value) ? value : [value]; } // Trace all permutations to generate the resulting media-query. // // (a, b and c) with nested (d, e) -> // a and d // a and e // b and c and d // b and c and e this.features = new(tree.Value)(this.permute(path).map(function (path) { path = path.map(function (fragment) { return fragment.toCSS ? fragment : new(tree.Anonymous)(fragment); }); for(i = path.length - 1; i > 0; i--) { path.splice(i, 0, new(tree.Anonymous)("and")); } return new(tree.Expression)(path); })); // Fake a tree-node that doesn't output anything. return new(tree.Ruleset)([], []); }, permute: function (arr) { if (arr.length === 0) { return []; } else if (arr.length === 1) { return arr[0]; } else { var result = []; var rest = this.permute(arr.slice(1)); for (var i = 0; i < rest.length; i++) { for (var j = 0; j < arr[0].length; j++) { result.push([arr[0][j]].concat(rest[i])); } } return result; } }, bubbleSelectors: function (selectors) { this.ruleset = new(tree.Ruleset)(selectors.slice(0), [this.ruleset]); } }; })(require('../tree')); (function (tree) { tree.mixin = {}; tree.mixin.Call = function (elements, args, index, filename, important) { this.selector = new(tree.Selector)(elements); this.arguments = args; this.index = index; this.filename = filename; this.important = important; }; tree.mixin.Call.prototype = { eval: function (env) { var mixins, mixin, args, rules = [], match = false, i, m, f, isRecursive, isOneFound; args = this.arguments && this.arguments.map(function (a) { return { name: a.name, value: a.value.eval(env) }; }); for (i = 0; i < env.frames.length; i++) { if ((mixins = env.frames[i].find(this.selector)).length > 0) { isOneFound = true; for (m = 0; m < mixins.length; m++) { mixin = mixins[m]; isRecursive = false; for(f = 0; f < env.frames.length; f++) { if ((!(mixin instanceof tree.mixin.Definition)) && mixin === (env.frames[f].originalRuleset || env.frames[f])) { isRecursive = true; break; } } if (isRecursive) { continue; } if (mixin.matchArgs(args, env)) { if (!mixin.matchCondition || mixin.matchCondition(args, env)) { try { Array.prototype.push.apply( rules, mixin.eval(env, args, this.important).rules); } catch (e) { throw { message: e.message, index: this.index, filename: this.filename, stack: e.stack }; } } match = true; } } if (match) { return rules; } } } if (isOneFound) { throw { type: 'Runtime', message: 'No matching definition was found for `' + this.selector.toCSS().trim() + '(' + (args ? args.map(function (a) { var argValue = ""; if (a.name) { argValue += a.name + ":"; } if (a.value.toCSS) { argValue += a.value.toCSS(); } else { argValue += "???"; } return argValue; }).join(', ') : "") + ")`", index: this.index, filename: this.filename }; } else { throw { type: 'Name', message: this.selector.toCSS().trim() + " is undefined", index: this.index, filename: this.filename }; } } }; tree.mixin.Definition = function (name, params, rules, condition, variadic) { this.name = name; this.selectors = [new(tree.Selector)([new(tree.Element)(null, name)])]; this.params = params; this.condition = condition; this.variadic = variadic; this.arity = params.length; this.rules = rules; this._lookups = {}; this.required = params.reduce(function (count, p) { if (!p.name || (p.name && !p.value)) { return count + 1 } else { return count } }, 0); this.parent = tree.Ruleset.prototype; this.frames = []; }; tree.mixin.Definition.prototype = { toCSS: function () { return "" }, variable: function (name) { return this.parent.variable.call(this, name) }, variables: function () { return this.parent.variables.call(this) }, find: function () { return this.parent.find.apply(this, arguments) }, rulesets: function () { return this.parent.rulesets.apply(this) }, evalParams: function (env, mixinEnv, args, evaldArguments) { var frame = new(tree.Ruleset)(null, []), varargs, arg, params = this.params.slice(0), i, j, val, name, isNamedFound, argIndex; if (args) { args = args.slice(0); for(i = 0; i < args.length; i++) { arg = args[i]; if (name = (arg && arg.name)) { isNamedFound = false; for(j = 0; j < params.length; j++) { if (!evaldArguments[j] && name === params[j].name) { evaldArguments[j] = arg.value.eval(env); frame.rules.unshift(new(tree.Rule)(name, arg.value.eval(env))); isNamedFound = true; break; } } if (isNamedFound) { args.splice(i, 1); i--; continue; } else { throw { type: 'Runtime', message: "Named argument for " + this.name + ' ' + args[i].name + ' not found' }; } } } } argIndex = 0; for (i = 0; i < params.length; i++) { if (evaldArguments[i]) continue; arg = args && args[argIndex]; if (name = params[i].name) { if (params[i].variadic && args) { varargs = []; for (j = argIndex; j < args.length; j++) { varargs.push(args[j].value.eval(env)); } frame.rules.unshift(new(tree.Rule)(name, new(tree.Expression)(varargs).eval(env))); } else { val = arg && arg.value; if (val) { val = val.eval(env); } else if (params[i].value) { val = params[i].value.eval(mixinEnv); } else { throw { type: 'Runtime', message: "wrong number of arguments for " + this.name + ' (' + args.length + ' for ' + this.arity + ')' }; } frame.rules.unshift(new(tree.Rule)(name, val)); evaldArguments[i] = val; } } if (params[i].variadic && args) { for (j = argIndex; j < args.length; j++) { evaldArguments[j] = args[j].value.eval(env); } } argIndex++; } return frame; }, eval: function (env, args, important) { var _arguments = [], mixinFrames = this.frames.concat(env.frames), frame = this.evalParams(env, {frames: mixinFrames}, args, _arguments), context, rules, start, ruleset; frame.rules.unshift(new(tree.Rule)('@arguments', new(tree.Expression)(_arguments).eval(env))); rules = important ? this.parent.makeImportant.apply(this).rules : this.rules.slice(0); ruleset = new(tree.Ruleset)(null, rules).eval({ frames: [this, frame].concat(mixinFrames) }); ruleset.originalRuleset = this; return ruleset; }, matchCondition: function (args, env) { if (this.condition && !this.condition.eval({ frames: [this.evalParams(env, {frames: this.frames.concat(env.frames)}, args, [])].concat(env.frames) })) { return false } return true; }, matchArgs: function (args, env) { var argsLength = (args && args.length) || 0, len, frame; if (! this.variadic) { if (argsLength < this.required) { return false } if (argsLength > this.params.length) { return false } if ((this.required > 0) && (argsLength > this.params.length)) { return false } } len = Math.min(argsLength, this.arity); for (var i = 0; i < len; i++) { if (!this.params[i].name && !this.params[i].variadic) { if (args[i].value.eval(env).toCSS() != this.params[i].value.eval(env).toCSS()) { return false; } } } return true; } }; })(require('../tree')); (function (tree) { tree.Operation = function (op, operands) { this.op = op.trim(); this.operands = operands; }; tree.Operation.prototype.eval = function (env) { var a = this.operands[0].eval(env), b = this.operands[1].eval(env), temp; if (a instanceof tree.Dimension && b instanceof tree.Color) { if (this.op === '*' || this.op === '+') { temp = b, b = a, a = temp; } else { throw { name: "OperationError", message: "Can't substract or divide a color from a number" }; } } if (!a.operate) { throw { name: "OperationError", message: "Operation on an invalid type" }; } return a.operate(this.op, b); }; tree.operate = function (op, a, b) { switch (op) { case '+': return a + b; case '-': return a - b; case '*': return a * b; case '/': return a / b; } }; })(require('../tree')); (function (tree) { tree.Paren = function (node) { this.value = node; }; tree.Paren.prototype = { toCSS: function (env) { return '(' + this.value.toCSS(env) + ')'; }, eval: function (env) { return new(tree.Paren)(this.value.eval(env)); } }; })(require('../tree')); (function (tree) { tree.Quoted = function (str, content, escaped, i) { this.escaped = escaped; this.value = content || ''; this.quote = str.charAt(0); this.index = i; }; tree.Quoted.prototype = { toCSS: function () { if (this.escaped) { return this.value; } else { return this.quote + this.value + this.quote; } }, eval: function (env) { var that = this; var value = this.value.replace(/`([^`]+)`/g, function (_, exp) { return new(tree.JavaScript)(exp, that.index, true).eval(env).value; }).replace(/@\{([\w-]+)\}/g, function (_, name) { var v = new(tree.Variable)('@' + name, that.index).eval(env); return (v instanceof tree.Quoted) ? v.value : v.toCSS(); }); return new(tree.Quoted)(this.quote + value + this.quote, value, this.escaped, this.index); }, compare: function (x) { if (!x.toCSS) { return -1; } var left = this.toCSS(), right = x.toCSS(); if (left === right) { return 0; } return left < right ? -1 : 1; } }; })(require('../tree')); (function (tree) { tree.Ratio = function (value) { this.value = value; }; tree.Ratio.prototype = { toCSS: function (env) { return this.value; }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.Rule = function (name, value, important, index, inline) { this.name = name; this.value = (value instanceof tree.Value) ? value : new(tree.Value)([value]); this.important = important ? ' ' + important.trim() : ''; this.index = index; this.inline = inline || false; if (name.charAt(0) === '@') { this.variable = true; } else { this.variable = false } }; tree.Rule.prototype.toCSS = function (env) { if (this.variable) { return "" } else { return this.name + (env.compress ? ':' : ': ') + this.value.toCSS(env) + this.important + (this.inline ? "" : ";"); } }; tree.Rule.prototype.eval = function (context) { return new(tree.Rule)(this.name, this.value.eval(context), this.important, this.index, this.inline); }; tree.Rule.prototype.makeImportant = function () { return new(tree.Rule)(this.name, this.value, "!important", this.index, this.inline); }; tree.Shorthand = function (a, b) { this.a = a; this.b = b; }; tree.Shorthand.prototype = { toCSS: function (env) { return this.a.toCSS(env) + "/" + this.b.toCSS(env); }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.Ruleset = function (selectors, rules, strictImports) { this.selectors = selectors; this.rules = rules; this._lookups = {}; this.strictImports = strictImports; }; tree.Ruleset.prototype = { eval: function (env) { var selectors = this.selectors && this.selectors.map(function (s) { return s.eval(env) }); var ruleset = new(tree.Ruleset)(selectors, this.rules.slice(0), this.strictImports); var rules; ruleset.originalRuleset = this; ruleset.root = this.root; ruleset.allowImports = this.allowImports; if(this.debugInfo) { ruleset.debugInfo = this.debugInfo; } // push the current ruleset to the frames stack env.frames.unshift(ruleset); // Evaluate imports if (ruleset.root || ruleset.allowImports || !ruleset.strictImports) { ruleset.evalImports(env); } // Store the frames around mixin definitions, // so they can be evaluated like closures when the time comes. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Definition) { ruleset.rules[i].frames = env.frames.slice(0); } } var mediaBlockCount = (env.mediaBlocks && env.mediaBlocks.length) || 0; // Evaluate mixin calls. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Call) { rules = ruleset.rules[i].eval(env); ruleset.rules.splice.apply(ruleset.rules, [i, 1].concat(rules)); i += rules.length-1; ruleset.resetCache(); } } // Evaluate everything else for (var i = 0, rule; i < ruleset.rules.length; i++) { rule = ruleset.rules[i]; if (! (rule instanceof tree.mixin.Definition)) { ruleset.rules[i] = rule.eval ? rule.eval(env) : rule; } } // Pop the stack env.frames.shift(); if (env.mediaBlocks) { for(var i = mediaBlockCount; i < env.mediaBlocks.length; i++) { env.mediaBlocks[i].bubbleSelectors(selectors); } } return ruleset; }, evalImports: function(env) { var i, rules; for (i = 0; i < this.rules.length; i++) { if (this.rules[i] instanceof tree.Import) { rules = this.rules[i].eval(env); if (typeof rules.length === "number") { this.rules.splice.apply(this.rules, [i, 1].concat(rules)); i+= rules.length-1; } else { this.rules.splice(i, 1, rules); } this.resetCache(); } } }, makeImportant: function() { return new tree.Ruleset(this.selectors, this.rules.map(function (r) { if (r.makeImportant) { return r.makeImportant(); } else { return r; } }), this.strictImports); }, matchArgs: function (args) { return !args || args.length === 0; }, resetCache: function () { this._rulesets = null; this._variables = null; this._lookups = {}; }, variables: function () { if (this._variables) { return this._variables } else { return this._variables = this.rules.reduce(function (hash, r) { if (r instanceof tree.Rule && r.variable === true) { hash[r.name] = r; } return hash; }, {}); } }, variable: function (name) { return this.variables()[name]; }, rulesets: function () { if (this._rulesets) { return this._rulesets } else { return this._rulesets = this.rules.filter(function (r) { return (r instanceof tree.Ruleset) || (r instanceof tree.mixin.Definition); }); } }, find: function (selector, self) { self = self || this; var rules = [], rule, match, key = selector.toCSS(); if (key in this._lookups) { return this._lookups[key] } this.rulesets().forEach(function (rule) { if (rule !== self) { for (var j = 0; j < rule.selectors.length; j++) { if (match = selector.match(rule.selectors[j])) { if (selector.elements.length > rule.selectors[j].elements.length) { Array.prototype.push.apply(rules, rule.find( new(tree.Selector)(selector.elements.slice(1)), self)); } else { rules.push(rule); } break; } } } }); return this._lookups[key] = rules; }, // // Entry point for code generation // // `context` holds an array of arrays. // toCSS: function (context, env) { var css = [], // The CSS output rules = [], // node.Rule instances _rules = [], // rulesets = [], // node.Ruleset instances paths = [], // Current selectors selector, // The fully rendered selector debugInfo, // Line number debugging rule; if (! this.root) { this.joinSelectors(paths, context, this.selectors); } // Compile rules and rulesets for (var i = 0; i < this.rules.length; i++) { rule = this.rules[i]; if (rule.rules || (rule instanceof tree.Media)) { rulesets.push(rule.toCSS(paths, env)); } else if (rule instanceof tree.Directive) { var cssValue = rule.toCSS(paths, env); // Output only the first @charset definition as such - convert the others // to comments in case debug is enabled if (rule.name === "@charset") { // Only output the debug info together with subsequent @charset definitions // a comment (or @media statement) before the actual @charset directive would // be considered illegal css as it has to be on the first line if (env.charset) { if (rule.debugInfo) { rulesets.push(tree.debugInfo(env, rule)); rulesets.push(new tree.Comment("/* "+cssValue.replace(/\n/g, "")+" */\n").toCSS(env)); } continue; } env.charset = true; } rulesets.push(cssValue); } else if (rule instanceof tree.Comment) { if (!rule.silent) { if (this.root) { rulesets.push(rule.toCSS(env)); } else { rules.push(rule.toCSS(env)); } } } else { if (rule.toCSS && !rule.variable) { rules.push(rule.toCSS(env)); } else if (rule.value && !rule.variable) { rules.push(rule.value.toString()); } } } rulesets = rulesets.join(''); // If this is the root node, we don't render // a selector, or {}. // Otherwise, only output if this ruleset has rules. if (this.root) { css.push(rules.join(env.compress ? '' : '\n')); } else { if (rules.length > 0) { debugInfo = tree.debugInfo(env, this); selector = paths.map(function (p) { return p.map(function (s) { return s.toCSS(env); }).join('').trim(); }).join(env.compress ? ',' : ',\n'); // Remove duplicates for (var i = rules.length - 1; i >= 0; i--) { if (_rules.indexOf(rules[i]) === -1) { _rules.unshift(rules[i]); } } rules = _rules; css.push(debugInfo + selector + (env.compress ? '{' : ' {\n ') + rules.join(env.compress ? '' : '\n ') + (env.compress ? '}' : '\n}\n')); } } css.push(rulesets); return css.join('') + (env.compress ? '\n' : ''); }, joinSelectors: function (paths, context, selectors) { for (var s = 0; s < selectors.length; s++) { this.joinSelector(paths, context, selectors[s]); } }, joinSelector: function (paths, context, selector) { var i, j, k, hasParentSelector, newSelectors, el, sel, parentSel, newSelectorPath, afterParentJoin, newJoinedSelector, newJoinedSelectorEmpty, lastSelector, currentElements, selectorsMultiplied; for (i = 0; i < selector.elements.length; i++) { el = selector.elements[i]; if (el.value === '&') { hasParentSelector = true; } } if (!hasParentSelector) { if (context.length > 0) { for(i = 0; i < context.length; i++) { paths.push(context[i].concat(selector)); } } else { paths.push([selector]); } return; } // The paths are [[Selector]] // The first list is a list of comma seperated selectors // The inner list is a list of inheritance seperated selectors // e.g. // .a, .b { // .c { // } // } // == [[.a] [.c]] [[.b] [.c]] // // the elements from the current selector so far currentElements = []; // the current list of new selectors to add to the path. // We will build it up. We initiate it with one empty selector as we "multiply" the new selectors // by the parents newSelectors = [[]]; for (i = 0; i < selector.elements.length; i++) { el = selector.elements[i]; // non parent reference elements just get added if (el.value !== "&") { currentElements.push(el); } else { // the new list of selectors to add selectorsMultiplied = []; // merge the current list of non parent selector elements // on to the current list of selectors to add if (currentElements.length > 0) { this.mergeElementsOnToSelectors(currentElements, newSelectors); } // loop through our current selectors for(j = 0; j < newSelectors.length; j++) { sel = newSelectors[j]; // if we don't have any parent paths, the & might be in a mixin so that it can be used // whether there are parents or not if (context.length == 0) { // the combinator used on el should now be applied to the next element instead so that // it is not lost if (sel.length > 0) { sel[0].elements = sel[0].elements.slice(0); sel[0].elements.push(new(tree.Element)(el.combinator, '', 0)); //new Element(el.Combinator, "")); } selectorsMultiplied.push(sel); } else { // and the parent selectors for(k = 0; k < context.length; k++) { parentSel = context[k]; // We need to put the current selectors // then join the last selector's elements on to the parents selectors // our new selector path newSelectorPath = []; // selectors from the parent after the join afterParentJoin = []; newJoinedSelectorEmpty = true; //construct the joined selector - if & is the first thing this will be empty, // if not newJoinedSelector will be the last set of elements in the selector if (sel.length > 0) { newSelectorPath = sel.slice(0); lastSelector = newSelectorPath.pop(); newJoinedSelector = new(tree.Selector)(lastSelector.elements.slice(0)); newJoinedSelectorEmpty = false; } else { newJoinedSelector = new(tree.Selector)([]); } //put together the parent selectors after the join if (parentSel.length > 1) { afterParentJoin = afterParentJoin.concat(parentSel.slice(1)); } if (parentSel.length > 0) { newJoinedSelectorEmpty = false; // join the elements so far with the first part of the parent newJoinedSelector.elements.push(new(tree.Element)(el.combinator, parentSel[0].elements[0].value, 0)); newJoinedSelector.elements = newJoinedSelector.elements.concat(parentSel[0].elements.slice(1)); } if (!newJoinedSelectorEmpty) { // now add the joined selector newSelectorPath.push(newJoinedSelector); } // and the rest of the parent newSelectorPath = newSelectorPath.concat(afterParentJoin); // add that to our new set of selectors selectorsMultiplied.push(newSelectorPath); } } } // our new selectors has been multiplied, so reset the state newSelectors = selectorsMultiplied; currentElements = []; } } // if we have any elements left over (e.g. .a& .b == .b) // add them on to all the current selectors if (currentElements.length > 0) { this.mergeElementsOnToSelectors(currentElements, newSelectors); } for(i = 0; i < newSelectors.length; i++) { paths.push(newSelectors[i]); } }, mergeElementsOnToSelectors: function(elements, selectors) { var i, sel; if (selectors.length == 0) { selectors.push([ new(tree.Selector)(elements) ]); return; } for(i = 0; i < selectors.length; i++) { sel = selectors[i]; // if the previous thing in sel is a parent this needs to join on to it if (sel.length > 0) { sel[sel.length - 1] = new(tree.Selector)(sel[sel.length - 1].elements.concat(elements)); } else { sel.push(new(tree.Selector)(elements)); } } } }; })(require('../tree')); (function (tree) { tree.Selector = function (elements) { this.elements = elements; }; tree.Selector.prototype.match = function (other) { var elements = this.elements, len = elements.length, oelements, olen, max, i; oelements = other.elements.slice( (other.elements.length && other.elements[0].value === "&") ? 1 : 0); olen = oelements.length; max = Math.min(len, olen) if (olen === 0 || len < olen) { return false; } else { for (i = 0; i < max; i++) { if (elements[i].value !== oelements[i].value) { return false; } } } return true; }; tree.Selector.prototype.eval = function (env) { return new(tree.Selector)(this.elements.map(function (e) { return e.eval(env); })); }; tree.Selector.prototype.toCSS = function (env) { if (this._css) { return this._css } if (this.elements[0].combinator.value === "") { this._css = ' '; } else { this._css = ''; } this._css += this.elements.map(function (e) { if (typeof(e) === 'string') { return ' ' + e.trim(); } else { return e.toCSS(env); } }).join(''); return this._css; }; })(require('../tree')); (function (tree) { tree.UnicodeDescriptor = function (value) { this.value = value; }; tree.UnicodeDescriptor.prototype = { toCSS: function (env) { return this.value; }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.URL = function (val, rootpath) { this.value = val; this.rootpath = rootpath; }; tree.URL.prototype = { toCSS: function () { return "url(" + this.value.toCSS() + ")"; }, eval: function (ctx) { var val = this.value.eval(ctx), rootpath; // Add the base path if the URL is relative if (typeof val.value === "string" && !/^(?:[a-z-]+:|\/)/.test(val.value)) { rootpath = this.rootpath; if (!val.quote) { rootpath = rootpath.replace(/[\(\)'"\s]/g, function(match) { return "\\"+match; }); } val.value = rootpath + val.value; } return new(tree.URL)(val, this.rootpath); } }; })(require('../tree')); (function (tree) { tree.Value = function (value) { this.value = value; this.is = 'value'; }; tree.Value.prototype = { eval: function (env) { if (this.value.length === 1) { return this.value[0].eval(env); } else { return new(tree.Value)(this.value.map(function (v) { return v.eval(env); })); } }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS(env); }).join(env.compress ? ',' : ', '); } }; })(require('../tree')); (function (tree) { tree.Variable = function (name, index, file) { this.name = name, this.index = index, this.file = file }; tree.Variable.prototype = { eval: function (env) { var variable, v, name = this.name; if (name.indexOf('@@') == 0) { name = '@' + new(tree.Variable)(name.slice(1)).eval(env).value; } if (this.evaluating) { throw { type: 'Name', message: "Recursive variable definition for " + name, filename: this.file, index: this.index }; } this.evaluating = true; if (variable = tree.find(env.frames, function (frame) { if (v = frame.variable(name)) { return v.value.eval(env); } })) { this.evaluating = false; return variable; } else { throw { type: 'Name', message: "variable " + name + " is undefined", filename: this.file, index: this.index }; } } }; })(require('../tree')); (function (tree) { tree.debugInfo = function(env, ctx) { var result=""; if (env.dumpLineNumbers && !env.compress) { switch(env.dumpLineNumbers) { case 'comments': result = tree.debugInfo.asComment(ctx); break; case 'mediaquery': result = tree.debugInfo.asMediaQuery(ctx); break; case 'all': result = tree.debugInfo.asComment(ctx)+tree.debugInfo.asMediaQuery(ctx); break; } } return result; }; tree.debugInfo.asComment = function(ctx) { return '/* line ' + ctx.debugInfo.lineNumber + ', ' + ctx.debugInfo.fileName + ' */\n'; }; tree.debugInfo.asMediaQuery = function(ctx) { return '@media -sass-debug-info{filename{font-family:' + ('file://' + ctx.debugInfo.fileName).replace(/[\/:.]/g, '\\$&') + '}line{font-family:\\00003' + ctx.debugInfo.lineNumber + '}}\n'; }; tree.find = function (obj, fun) { for (var i = 0, r; i < obj.length; i++) { if (r = fun.call(obj, obj[i])) { return r } } return null; }; tree.jsify = function (obj) { if (Array.isArray(obj.value) && (obj.value.length > 1)) { return '[' + obj.value.map(function (v) { return v.toCSS(false) }).join(', ') + ']'; } else { return obj.toCSS(false); } }; })(require('./tree')); var name; function loadStyleSheet(sheet, callback, reload, remaining) { var endOfPath = Math.max(name.lastIndexOf('/'), name.lastIndexOf('\\')), sheetName = name.slice(0, endOfPath + 1) + sheet.href, contents = sheet.contents || {}, input = readFile(sheetName); contents[sheetName] = input; var parser = new less.Parser({ paths: [sheet.href.replace(/[\w\.-]+$/, '')], contents: contents }); parser.parse(input, function (e, root) { if (e) { return error(e, sheetName); } try { callback(e, root, input, sheet, { local: false, lastModified: 0, remaining: remaining }, sheetName); } catch(e) { error(e, sheetName); } }); } function writeFile(filename, content) { var fstream = new java.io.FileWriter(filename); var out = new java.io.BufferedWriter(fstream); out.write(content); out.close(); } // Command line integration via Rhino (function (args) { var output, compress = false, i; for(i = 0; i < args.length; i++) { switch(args[i]) { case "-x": compress = true; break; default: if (!name) { name = args[i]; } else if (!output) { output = args[i]; } else { print("unrecognised parameters"); print("input_file [output_file] [-x]"); } } } if (!name) { print('No files present in the fileset; Check your pattern match in build.xml'); quit(1); } path = name.split("/");path.pop();path=path.join("/") var input = readFile(name); if (!input) { print('lesscss: couldn\'t open file ' + name); quit(1); } var result; try { var parser = new less.Parser(); parser.parse(input, function (e, root) { if (e) { error(e, name); quit(1); } else { result = root.toCSS({compress: compress || false}); if (output) { writeFile(output, result); print("Written to " + output); } else { print(result); } quit(0); } }); } catch(e) { error(e, name); quit(1); } print("done"); }(arguments)); function error(e, filename) { var content = "Error : " + filename + "\n"; filename = e.filename || filename; if (e.message) { content += e.message + "\n"; } var errorline = function (e, i, classname) { if (e.extract[i]) { content += String(parseInt(e.line) + (i - 1)) + ":" + e.extract[i] + "\n"; } }; if (e.stack) { content += e.stack; } else if (e.extract) { content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':\n'; errorline(e, 0); errorline(e, 1); errorline(e, 2); } print(content); }less.js-1.4.2/dist/less-rhino-1.4.0.js000066400000000000000000004334001217256642200171340ustar00rootroot00000000000000// // Stub out `require` in rhino // function require(arg) { return less[arg.split('/')[1]]; }; // ecma-5.js // // -- kriskowal Kris Kowal Copyright (C) 2009-2010 MIT License // -- tlrobinson Tom Robinson // dantman Daniel Friesen // // Array // if (!Array.isArray) { Array.isArray = function(obj) { return Object.prototype.toString.call(obj) === "[object Array]" || (obj instanceof Array); }; } if (!Array.prototype.forEach) { Array.prototype.forEach = function(block, thisObject) { var len = this.length >>> 0; for (var i = 0; i < len; i++) { if (i in this) { block.call(thisObject, this[i], i, this); } } }; } if (!Array.prototype.map) { Array.prototype.map = function(fun /*, thisp*/) { var len = this.length >>> 0; var res = new Array(len); var thisp = arguments[1]; for (var i = 0; i < len; i++) { if (i in this) { res[i] = fun.call(thisp, this[i], i, this); } } return res; }; } if (!Array.prototype.filter) { Array.prototype.filter = function (block /*, thisp */) { var values = []; var thisp = arguments[1]; for (var i = 0; i < this.length; i++) { if (block.call(thisp, this[i])) { values.push(this[i]); } } return values; }; } if (!Array.prototype.reduce) { Array.prototype.reduce = function(fun /*, initial*/) { var len = this.length >>> 0; var i = 0; // no value to return if no initial value and an empty array if (len === 0 && arguments.length === 1) throw new TypeError(); if (arguments.length >= 2) { var rv = arguments[1]; } else { do { if (i in this) { rv = this[i++]; break; } // if array contains no values, no initial value to return if (++i >= len) throw new TypeError(); } while (true); } for (; i < len; i++) { if (i in this) { rv = fun.call(null, rv, this[i], i, this); } } return rv; }; } if (!Array.prototype.indexOf) { Array.prototype.indexOf = function (value /*, fromIndex */ ) { var length = this.length; var i = arguments[1] || 0; if (!length) return -1; if (i >= length) return -1; if (i < 0) i += length; for (; i < length; i++) { if (!Object.prototype.hasOwnProperty.call(this, i)) { continue } if (value === this[i]) return i; } return -1; }; } // // Object // if (!Object.keys) { Object.keys = function (object) { var keys = []; for (var name in object) { if (Object.prototype.hasOwnProperty.call(object, name)) { keys.push(name); } } return keys; }; } // // String // if (!String.prototype.trim) { String.prototype.trim = function () { return String(this).replace(/^\s\s*/, '').replace(/\s\s*$/, ''); }; } var less, tree, charset; if (typeof environment === "object" && ({}).toString.call(environment) === "[object Environment]") { // Rhino // Details on how to detect Rhino: https://github.com/ringo/ringojs/issues/88 if (typeof(window) === 'undefined') { less = {} } else { less = window.less = {} } tree = less.tree = {}; less.mode = 'rhino'; } else if (typeof(window) === 'undefined') { // Node.js less = exports, tree = require('./tree'); less.mode = 'node'; } else { // Browser if (typeof(window.less) === 'undefined') { window.less = {} } less = window.less, tree = window.less.tree = {}; less.mode = 'browser'; } // // less.js - parser // // A relatively straight-forward predictive parser. // There is no tokenization/lexing stage, the input is parsed // in one sweep. // // To make the parser fast enough to run in the browser, several // optimization had to be made: // // - Matching and slicing on a huge input is often cause of slowdowns. // The solution is to chunkify the input into smaller strings. // The chunks are stored in the `chunks` var, // `j` holds the current chunk index, and `current` holds // the index of the current chunk in relation to `input`. // This gives us an almost 4x speed-up. // // - In many cases, we don't need to match individual tokens; // for example, if a value doesn't hold any variables, operations // or dynamic references, the parser can effectively 'skip' it, // treating it as a literal. // An example would be '1px solid #000' - which evaluates to itself, // we don't need to know what the individual components are. // The drawback, of course is that you don't get the benefits of // syntax-checking on the CSS. This gives us a 50% speed-up in the parser, // and a smaller speed-up in the code-gen. // // // Token matching is done with the `$` function, which either takes // a terminal string or regexp, or a non-terminal function to call. // It also takes care of moving all the indices forwards. // // less.Parser = function Parser(env) { var input, // LeSS input string i, // current index in `input` j, // current chunk temp, // temporarily holds a chunk's state, for backtracking memo, // temporarily holds `i`, when backtracking furthest, // furthest index the parser has gone to chunks, // chunkified input current, // index of current chunk, in `input` parser; var that = this; // Top parser on an import tree must be sure there is one "env" // which will then be passed arround by reference. var env = env || { }; // env.contents and files must be passed arround with top env if (!env.contents) { env.contents = {}; } env.rootpath = env.rootpath || ''; // env.rootpath must be initialized to '' if not provided if (!env.files) { env.files = {}; } // This function is called after all files // have been imported through `@import`. var finish = function () {}; var imports = this.imports = { paths: env.paths || [], // Search paths, when importing queue: [], // Files which haven't been imported yet files: env.files, // Holds the imported parse trees contents: env.contents, // Holds the imported file contents mime: env.mime, // MIME type of .less files error: null, // Error in parsing/evaluating an import push: function (path, callback) { var that = this; this.queue.push(path); // // Import a file asynchronously // less.Parser.importer(path, this.paths, function (e, root, fullPath) { that.queue.splice(that.queue.indexOf(path), 1); // Remove the path from the queue var imported = fullPath in that.files; that.files[fullPath] = root; // Store the root if (e && !that.error) { that.error = e } callback(e, root, imported); if (that.queue.length === 0) { finish(that.error) } // Call `finish` if we're done importing }, env); } }; function save() { temp = chunks[j], memo = i, current = i } function restore() { chunks[j] = temp, i = memo, current = i } function sync() { if (i > current) { chunks[j] = chunks[j].slice(i - current); current = i; } } function isWhitespace(c) { // Could change to \s? var code = c.charCodeAt(0); return code === 32 || code === 10 || code === 9; } // // Parse from a token, regexp or string, and move forward if match // function $(tok) { var match, args, length, index, k; // // Non-terminal // if (tok instanceof Function) { return tok.call(parser.parsers); // // Terminal // // Either match a single character in the input, // or match a regexp in the current chunk (chunk[j]). // } else if (typeof(tok) === 'string') { match = input.charAt(i) === tok ? tok : null; length = 1; sync (); } else { sync (); if (match = tok.exec(chunks[j])) { length = match[0].length; } else { return null; } } // The match is confirmed, add the match length to `i`, // and consume any extra white-space characters (' ' || '\n') // which come after that. The reason for this is that LeSS's // grammar is mostly white-space insensitive. // if (match) { skipWhitespace(length); if(typeof(match) === 'string') { return match; } else { return match.length === 1 ? match[0] : match; } } } function skipWhitespace(length) { var oldi = i, oldj = j, endIndex = i + chunks[j].length, mem = i += length; while (i < endIndex) { if (! isWhitespace(input.charAt(i))) { break } i++; } chunks[j] = chunks[j].slice(length + (i - mem)); current = i; if (chunks[j].length === 0 && j < chunks.length - 1) { j++ } return oldi !== i || oldj !== j; } function expect(arg, msg) { var result = $(arg); if (! result) { error(msg || (typeof(arg) === 'string' ? "expected '" + arg + "' got '" + input.charAt(i) + "'" : "unexpected token")); } else { return result; } } function error(msg, type) { var e = new Error(msg); e.index = i; e.type = type || 'Syntax'; throw e; } // Same as $(), but don't change the state of the parser, // just return the match. function peek(tok) { if (typeof(tok) === 'string') { return input.charAt(i) === tok; } else { if (tok.test(chunks[j])) { return true; } else { return false; } } } function getInput(e, env) { if (e.filename && env.filename && (e.filename !== env.filename)) { return parser.imports.contents[e.filename]; } else { return input; } } function getLocation(index, input) { for (var n = index, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } return { line: typeof(index) === 'number' ? (input.slice(0, index).match(/\n/g) || "").length : null, column: column }; } function getFileName(e) { if(less.mode === 'browser' || less.mode === 'rhino') return e.filename; else return require('path').resolve(e.filename); } function getDebugInfo(index, inputStream, e) { return { lineNumber: getLocation(index, inputStream).line + 1, fileName: getFileName(e) }; } function LessError(e, env) { var input = getInput(e, env), loc = getLocation(e.index, input), line = loc.line, col = loc.column, lines = input.split('\n'); this.type = e.type || 'Syntax'; this.message = e.message; this.filename = e.filename || env.filename; this.index = e.index; this.line = typeof(line) === 'number' ? line + 1 : null; this.callLine = e.call && (getLocation(e.call, input).line + 1); this.callExtract = lines[getLocation(e.call, input).line]; this.stack = e.stack; this.column = col; this.extract = [ lines[line - 1], lines[line], lines[line + 1] ]; } this.env = env = env || {}; // The optimization level dictates the thoroughness of the parser, // the lower the number, the less nodes it will create in the tree. // This could matter for debugging, or if you want to access // the individual nodes in the tree. this.optimization = ('optimization' in this.env) ? this.env.optimization : 1; this.env.filename = this.env.filename || null; // // The Parser // return parser = { imports: imports, // // Parse an input string into an abstract syntax tree, // call `callback` when done. // parse: function (str, callback) { var root, start, end, zone, line, lines, buff = [], c, error = null; i = j = current = furthest = 0; input = str.replace(/\r\n/g, '\n'); // Remove potential UTF Byte Order Mark input = input.replace(/^\uFEFF/, ''); // Split the input into chunks. chunks = (function (chunks) { var j = 0, skip = /(?:@\{[\w-]+\}|[^"'`\{\}\/\(\)\\])+/g, comment = /\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g, string = /"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'|`((?:[^`]|\\.)*)`/g, level = 0, match, chunk = chunks[0], inParam; for (var i = 0, c, cc; i < input.length;) { skip.lastIndex = i; if (match = skip.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); } } c = input.charAt(i); comment.lastIndex = string.lastIndex = i; if (match = string.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); continue; } } if (!inParam && c === '/') { cc = input.charAt(i + 1); if (cc === '/' || cc === '*') { if (match = comment.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); continue; } } } } switch (c) { case '{': if (! inParam) { level ++; chunk.push(c); break } case '}': if (! inParam) { level --; chunk.push(c); chunks[++j] = chunk = []; break } case '(': if (! inParam) { inParam = true; chunk.push(c); break } case ')': if ( inParam) { inParam = false; chunk.push(c); break } default: chunk.push(c); } i++; } if (level != 0) { error = new(LessError)({ index: i-1, type: 'Parse', message: (level > 0) ? "missing closing `}`" : "missing opening `{`", filename: env.filename }, env); } return chunks.map(function (c) { return c.join('') });; })([[]]); if (error) { return callback(error, env); } // Start with the primary rule. // The whole syntax tree is held under a Ruleset node, // with the `root` property set to true, so no `{}` are // output. The callback is called when the input is parsed. try { root = new(tree.Ruleset)([], $(this.parsers.primary)); root.root = true; } catch (e) { return callback(new(LessError)(e, env)); } root.toCSS = (function (evaluate) { var line, lines, column; return function (options, variables) { var frames = [], importError; options = options || {}; // // Allows setting variables with a hash, so: // // `{ color: new(tree.Color)('#f01') }` will become: // // new(tree.Rule)('@color', // new(tree.Value)([ // new(tree.Expression)([ // new(tree.Color)('#f01') // ]) // ]) // ) // if (typeof(variables) === 'object' && !Array.isArray(variables)) { variables = Object.keys(variables).map(function (k) { var value = variables[k]; if (! (value instanceof tree.Value)) { if (! (value instanceof tree.Expression)) { value = new(tree.Expression)([value]); } value = new(tree.Value)([value]); } return new(tree.Rule)('@' + k, value, false, 0); }); frames = [new(tree.Ruleset)(null, variables)]; } try { var css = evaluate.call(this, { frames: frames }) .toCSS([], { compress: options.compress || false, dumpLineNumbers: env.dumpLineNumbers }); } catch (e) { throw new(LessError)(e, env); } if ((importError = parser.imports.error)) { // Check if there was an error during importing if (importError instanceof LessError) throw importError; else throw new(LessError)(importError, env); } if (options.yuicompress && less.mode === 'node') { return require('ycssmin').cssmin(css); } else if (options.compress) { return css.replace(/(\s)+/g, "$1"); } else { return css; } }; })(root.eval); // If `i` is smaller than the `input.length - 1`, // it means the parser wasn't able to parse the whole // string, so we've got a parsing error. // // We try to extract a \n delimited string, // showing the line where the parse error occured. // We split it up into two parts (the part which parsed, // and the part which didn't), so we can color them differently. if (i < input.length - 1) { i = furthest; lines = input.split('\n'); line = (input.slice(0, i).match(/\n/g) || "").length + 1; for (var n = i, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } error = { type: "Parse", message: "Syntax Error on line " + line, index: i, filename: env.filename, line: line, column: column, extract: [ lines[line - 2], lines[line - 1], lines[line] ] }; } if (this.imports.queue.length > 0) { finish = function (e) { e = error || e; if (e) callback(e); else callback(null, root); }; } else { callback(error, root); } }, // // Here in, the parsing rules/functions // // The basic structure of the syntax tree generated is as follows: // // Ruleset -> Rule -> Value -> Expression -> Entity // // Here's some LESS code: // // .class { // color: #fff; // border: 1px solid #000; // width: @w + 4px; // > .child {...} // } // // And here's what the parse tree might look like: // // Ruleset (Selector '.class', [ // Rule ("color", Value ([Expression [Color #fff]])) // Rule ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]])) // Rule ("width", Value ([Expression [Operation "+" [Variable "@w"][Dimension 4px]]])) // Ruleset (Selector [Element '>', '.child'], [...]) // ]) // // In general, most rules will try to parse a token with the `$()` function, and if the return // value is truly, will return a new node, of the relevant type. Sometimes, we need to check // first, before parsing, that's when we use `peek()`. // parsers: { // // The `primary` rule is the *entry* and *exit* point of the parser. // The rules here can appear at any level of the parse tree. // // The recursive nature of the grammar is an interplay between the `block` // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule, // as represented by this simplified grammar: // // primary → (ruleset | rule)+ // ruleset → selector+ block // block → '{' primary '}' // // Only at one point is the primary rule not called from the // block rule: at the root level. // primary: function () { var node, root = []; while ((node = $(this.extendRule) || $(this.mixin.definition) || $(this.rule) || $(this.ruleset) || $(this.mixin.call) || $(this.comment) || $(this.directive)) || $(/^[\s\n]+/) || $(/^;+/)) { node && root.push(node); } return root; }, // We create a Comment node for CSS comments `/* */`, // but keep the LeSS comments `//` silent, by just skipping // over them. comment: function () { var comment; if (input.charAt(i) !== '/') return; if (input.charAt(i + 1) === '/') { return new(tree.Comment)($(/^\/\/.*/), true); } else if (comment = $(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/)) { return new(tree.Comment)(comment); } }, // // Entities are tokens which can be found inside an Expression // entities: { // // A string, which supports escaping " and ' // // "milky way" 'he\'s the one!' // quoted: function () { var str, j = i, e; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '"' && input.charAt(j) !== "'") return; e && $('~'); if (str = $(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/)) { return new(tree.Quoted)(str[0], str[1] || str[2], e); } }, // // A catch-all word, such as: // // black border-collapse // keyword: function () { var k; if (k = $(/^[_A-Za-z-][_A-Za-z0-9-]*/)) { if (tree.colors.hasOwnProperty(k)) { // detect named color return new(tree.Color)(tree.colors[k].slice(1)); } else { return new(tree.Keyword)(k); } } }, // // A function call // // rgb(255, 0, 255) // // We also try to catch IE's `alpha()`, but let the `alpha` parser // deal with the details. // // The arguments are parsed with the `entities.arguments` parser. // call: function () { var name, nameLC, args, alpha_ret, index = i; if (! (name = /^([\w-]+|%|progid:[\w\.]+)\(/.exec(chunks[j]))) return; name = name[1]; nameLC = name.toLowerCase(); if (nameLC === 'url') { return null } else { i += name.length } if (nameLC === 'alpha') { alpha_ret = $(this.alpha); if(typeof alpha_ret !== 'undefined') { return alpha_ret; } } $('('); // Parse the '(' and consume whitespace. args = $(this.entities.arguments); if (! $(')')) return; if (name) { return new(tree.Call)(name, args, index, env.filename) } }, arguments: function () { var args = [], arg; while (arg = $(this.entities.assignment) || $(this.expression)) { args.push(arg); if (! $(',')) { break } } return args; }, literal: function () { return $(this.entities.ratio) || $(this.entities.dimension) || $(this.entities.color) || $(this.entities.quoted) || $(this.entities.unicodeDescriptor); }, // Assignments are argument entities for calls. // They are present in ie filter properties as shown below. // // filter: progid:DXImageTransform.Microsoft.Alpha( *opacity=50* ) // assignment: function () { var key, value; if ((key = $(/^\w+(?=\s?=)/i)) && $('=') && (value = $(this.entity))) { return new(tree.Assignment)(key, value); } }, // // Parse url() tokens // // We use a specific rule for urls, because they don't really behave like // standard function calls. The difference is that the argument doesn't have // to be enclosed within a string, so it can't be parsed as an Expression. // url: function () { var value; if (input.charAt(i) !== 'u' || !$(/^url\(/)) return; value = $(this.entities.quoted) || $(this.entities.variable) || $(/^(?:(?:\\[\(\)'"])|[^\(\)'"])+/) || ""; expect(')'); return new(tree.URL)((value.value != null || value instanceof tree.Variable) ? value : new(tree.Anonymous)(value), env.rootpath); }, // // A Variable entity, such as `@fink`, in // // width: @fink + 2px // // We use a different parser for variable definitions, // see `parsers.variable`. // variable: function () { var name, index = i; if (input.charAt(i) === '@' && (name = $(/^@@?[\w-]+/))) { return new(tree.Variable)(name, index, env.filename); } }, // A variable entity useing the protective {} e.g. @{var} variableCurly: function () { var name, curly, index = i; if (input.charAt(i) === '@' && (curly = $(/^@\{([\w-]+)\}/))) { return new(tree.Variable)("@" + curly[1], index, env.filename); } }, // // A Hexadecimal color // // #4F3C2F // // `rgb` and `hsl` colors are parsed through the `entities.call` parser. // color: function () { var rgb; if (input.charAt(i) === '#' && (rgb = $(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/))) { return new(tree.Color)(rgb[1]); } }, // // A Dimension, that is, a number and a unit // // 0.5em 95% // dimension: function () { var value, c = input.charCodeAt(i); //Is the first char of the dimension 0-9, '.', '+' or '-' if ((c > 57 || c < 43) || c === 47 || c == 44) return; if (value = $(/^([+-]?\d*\.?\d+)(%|[a-z]+)?/)) { return new(tree.Dimension)(value[1], value[2]); } }, // // A Ratio // // 16/9 // ratio: function () { var value, c = input.charCodeAt(i); if (c > 57 || c < 48) return; if (value = $(/^(\d+\/\d+)/)) { return new(tree.Ratio)(value[1]); } }, // // A unicode descriptor, as is used in unicode-range // // U+0?? or U+00A1-00A9 // unicodeDescriptor: function () { var ud; if (ud = $(/^U\+[0-9a-fA-F?]+(\-[0-9a-fA-F?]+)?/)) { return new(tree.UnicodeDescriptor)(ud[0]); } }, // // JavaScript code to be evaluated // // `window.location.href` // javascript: function () { var str, j = i, e; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '`') { return } e && $('~'); if (str = $(/^`([^`]*)`/)) { return new(tree.JavaScript)(str[1], i, e); } } }, // // The variable part of a variable definition. Used in the `rule` parser // // @fink: // variable: function () { var name; if (input.charAt(i) === '@' && (name = $(/^(@[\w-]+)\s*:/))) { return name[1] } }, // // A font size/line-height shorthand // // small/12px // // We need to peek first, or we'll match on keywords and dimensions // shorthand: function () { var a, b; if (! peek(/^[@\w.%-]+\/[@\w.-]+/)) return; save(); if ((a = $(this.entity)) && $('/') && (b = $(this.entity))) { return new(tree.Shorthand)(a, b); } restore(); }, // // extend syntax - used to extend selectors // extend: function(isRule) { var elements = [], e, args, index = i; if (!$(isRule ? /^&:extend\(/ : /^:extend\(/)) { return; } while (e = $(/^[#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/)) { elements.push(new(tree.Element)(null, e, i)); } expect(/^\)/); if (isRule) { expect(/^;/); } return new(tree.Extend)(elements, index); }, // // extendRule - used in a rule to extend all the parent selectors // extendRule: function() { return this.extend(true); }, // // Mixins // mixin: { // // A Mixin call, with an optional argument list // // #mixins > .square(#fff); // .rounded(4px, black); // .button; // // The `while` loop is there because mixins can be // namespaced, but we only support the child and descendant // selector for now. // call: function () { var elements = [], e, c, argsSemiColon = [], argsComma = [], args, delim, arg, nameLoop, expressions, isSemiColonSeperated, expressionContainsNamed, index = i, s = input.charAt(i), name, value, important = false; if (s !== '.' && s !== '#') { return } save(); // stop us absorbing part of an invalid selector while (e = $(/^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/)) { elements.push(new(tree.Element)(c, e, i)); c = $('>'); } if ($('(')) { expressions = []; while (arg = $(this.expression)) { nameLoop = null; value = arg; // Variable if (arg.value.length == 1) { var val = arg.value[0]; if (val instanceof tree.Variable) { if ($(':')) { if (expressions.length > 0) { if (isSemiColonSeperated) { error("Cannot mix ; and , as delimiter types"); } expressionContainsNamed = true; } value = expect(this.expression); nameLoop = (name = val.name); } } } expressions.push(value); argsComma.push({ name: nameLoop, value: value }); if ($(',')) { continue; } if ($(';') || isSemiColonSeperated) { if (expressionContainsNamed) { error("Cannot mix ; and , as delimiter types"); } isSemiColonSeperated = true; if (expressions.length > 1) { value = new(tree.Value)(expressions); } argsSemiColon.push({ name: name, value: value }); name = null; expressions = []; expressionContainsNamed = false; } } expect(')'); } args = isSemiColonSeperated ? argsSemiColon : argsComma; if ($(this.important)) { important = true; } if (elements.length > 0 && ($(';') || peek('}'))) { return new(tree.mixin.Call)(elements, args, index, env.filename, important); } restore(); }, // // A Mixin definition, with a list of parameters // // .rounded (@radius: 2px, @color) { // ... // } // // Until we have a finer grained state-machine, we have to // do a look-ahead, to make sure we don't have a mixin call. // See the `rule` function for more information. // // We start by matching `.rounded (`, and then proceed on to // the argument list, which has optional default values. // We store the parameters in `params`, with a `value` key, // if there is a value, such as in the case of `@radius`. // // Once we've got our params list, and a closing `)`, we parse // the `{...}` block. // definition: function () { var name, params = [], match, ruleset, param, value, cond, variadic = false; if ((input.charAt(i) !== '.' && input.charAt(i) !== '#') || peek(/^[^{]*\}/)) return; save(); if (match = $(/^([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/)) { name = match[1]; do { $(this.comment); if (input.charAt(i) === '.' && $(/^\.{3}/)) { variadic = true; params.push({ variadic: true }); break; } else if (param = $(this.entities.variable) || $(this.entities.literal) || $(this.entities.keyword)) { // Variable if (param instanceof tree.Variable) { if ($(':')) { value = expect(this.expression, 'expected expression'); params.push({ name: param.name, value: value }); } else if ($(/^\.{3}/)) { params.push({ name: param.name, variadic: true }); variadic = true; break; } else { params.push({ name: param.name }); } } else { params.push({ value: param }); } } else { break; } } while ($(',') || $(';')) // .mixincall("@{a}"); // looks a bit like a mixin definition.. so we have to be nice and restore if (!$(')')) { furthest = i; restore(); } $(this.comment); if ($(/^when/)) { // Guard cond = expect(this.conditions, 'expected condition'); } ruleset = $(this.block); if (ruleset) { return new(tree.mixin.Definition)(name, params, ruleset, cond, variadic); } else { restore(); } } } }, // // Entities are the smallest recognized token, // and can be found inside a rule's value. // entity: function () { return $(this.entities.literal) || $(this.entities.variable) || $(this.entities.url) || $(this.entities.call) || $(this.entities.keyword) ||$(this.entities.javascript) || $(this.comment); }, // // A Rule terminator. Note that we use `peek()` to check for '}', // because the `block` rule will be expecting it, but we still need to make sure // it's there, if ';' was ommitted. // end: function () { return $(';') || peek('}'); }, // // IE's alpha function // // alpha(opacity=88) // alpha: function () { var value; if (! $(/^\(opacity=/i)) return; if (value = $(/^\d+/) || $(this.entities.variable)) { expect(')'); return new(tree.Alpha)(value); } }, // // A Selector Element // // div // + h1 // #socks // input[type="text"] // // Elements are the building blocks for Selectors, // they are made out of a `Combinator` (see combinator rule), // and an element name, such as a tag a class, or `*`. // element: function () { var e, t, c, v; c = $(this.combinator); e = $(/^(?:\d+\.\d+|\d+)%/) || $(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/) || $('*') || $('&') || $(this.attribute) || $(/^\([^()@]+\)/) || $(/^[\.#](?=@)/) || $(this.entities.variableCurly); if (! e) { if ($('(')) { if ((v = (//$(this.entities.variableCurly) || $(this.selector))) && $(')')) { e = new(tree.Paren)(v); } } } if (e) { return new(tree.Element)(c, e, i) } }, // // Combinators combine elements together, in a Selector. // // Because our parser isn't white-space sensitive, special care // has to be taken, when parsing the descendant combinator, ` `, // as it's an empty space. We have to check the previous character // in the input, to see if it's a ` ` character. More info on how // we deal with this in *combinator.js*. // combinator: function () { var match, c = input.charAt(i); if (c === '>' || c === '+' || c === '~' || c === '|') { i++; while (input.charAt(i).match(/\s/)) { i++ } return new(tree.Combinator)(c); } else if (input.charAt(i - 1).match(/\s/)) { return new(tree.Combinator)(" "); } else { return new(tree.Combinator)(null); } }, // // A CSS Selector // // .class > div + h1 // li a:hover // // Selectors are made out of one or more Elements, see above. // selector: function () { var sel, e, elements = [], c, match, extend; while ((extend = $(this.extend)) || (e = $(this.element))) { if (!e) { break; } c = input.charAt(i); elements.push(e) e = null; if (c === '{' || c === '}' || c === ';' || c === ',' || c === ')') { break } } if (elements.length > 0) { return new(tree.Selector)(elements, extend) } if (extend) { error("Extend must be used to extend a selector"); } }, attribute: function () { var attr = '', key, val, op; if (! $('[')) return; if (key = $(/^(?:[_A-Za-z0-9-]|\\.)+/) || $(this.entities.quoted)) { if ((op = $(/^[|~*$^]?=/)) && (val = $(this.entities.quoted) || $(/^[\w-]+/))) { attr = [key, op, val.toCSS ? val.toCSS() : val].join(''); } else { attr = key } } if (! $(']')) return; if (attr) { return "[" + attr + "]" } }, // // The `block` rule is used by `ruleset` and `mixin.definition`. // It's a wrapper around the `primary` rule, with added `{}`. // block: function () { var content; if ($('{') && (content = $(this.primary)) && $('}')) { return content; } }, // // div, .class, body > p {...} // ruleset: function () { var selectors = [], s, rules, match, debugInfo; save(); if (env.dumpLineNumbers) debugInfo = getDebugInfo(i, input, env); while (s = $(this.selector)) { selectors.push(s); $(this.comment); if (! $(',')) { break } $(this.comment); } if (selectors.length > 0 && (rules = $(this.block))) { var ruleset = new(tree.Ruleset)(selectors, rules, env.strictImports); if (env.dumpLineNumbers) ruleset.debugInfo = debugInfo; return ruleset; } else { // Backtrack furthest = i; restore(); } }, rule: function () { var name, value, c = input.charAt(i), important, match; save(); if (c === '.' || c === '#' || c === '&') { return } if (name = $(this.variable) || $(this.property)) { if ((name.charAt(0) != '@') && (match = /^([^@+\/'"*`(;{}-]*);/.exec(chunks[j]))) { i += match[0].length - 1; value = new(tree.Anonymous)(match[1]); } else if (name === "font") { value = $(this.font); } else { value = $(this.value); } important = $(this.important); if (value && $(this.end)) { return new(tree.Rule)(name, value, important, memo); } else { furthest = i; restore(); } } }, // // An @import directive // // @import "lib"; // // Depending on our environemnt, importing is done differently: // In the browser, it's an XHR request, in Node, it would be a // file-system operation. The function used for importing is // stored in `import`, which we pass to the Import constructor. // "import": function () { var path, features, index = i; save(); var dir = $(/^@import(?:-(once|multiple))?\s+/); if (dir && (path = $(this.entities.quoted) || $(this.entities.url))) { features = $(this.mediaFeatures); if ($(';')) { var importOnce = dir[1] !== 'multiple'; return new(tree.Import)(path, imports, features, importOnce, index, env.rootpath); } } restore(); }, mediaFeature: function () { var e, p, nodes = []; do { if (e = $(this.entities.keyword)) { nodes.push(e); } else if ($('(')) { p = $(this.property); e = $(this.entity); if ($(')')) { if (p && e) { nodes.push(new(tree.Paren)(new(tree.Rule)(p, e, null, i, true))); } else if (e) { nodes.push(new(tree.Paren)(e)); } else { return null; } } else { return null } } } while (e); if (nodes.length > 0) { return new(tree.Expression)(nodes); } }, mediaFeatures: function () { var e, features = []; do { if (e = $(this.mediaFeature)) { features.push(e); if (! $(',')) { break } } else if (e = $(this.entities.variable)) { features.push(e); if (! $(',')) { break } } } while (e); return features.length > 0 ? features : null; }, media: function () { var features, rules, media, debugInfo; if (env.dumpLineNumbers) debugInfo = getDebugInfo(i, input, env); if ($(/^@media/)) { features = $(this.mediaFeatures); if (rules = $(this.block)) { media = new(tree.Media)(rules, features); if(env.dumpLineNumbers) media.debugInfo = debugInfo; return media; } } }, // // A CSS Directive // // @charset "utf-8"; // directive: function () { var name, value, rules, identifier, e, nodes, nonVendorSpecificName, hasBlock, hasIdentifier, hasExpression; if (input.charAt(i) !== '@') return; if (value = $(this['import']) || $(this.media)) { return value; } save(); name = $(/^@[a-z-]+/); if (!name) return; nonVendorSpecificName = name; if (name.charAt(1) == '-' && name.indexOf('-', 2) > 0) { nonVendorSpecificName = "@" + name.slice(name.indexOf('-', 2) + 1); } switch(nonVendorSpecificName) { case "@font-face": hasBlock = true; break; case "@viewport": case "@top-left": case "@top-left-corner": case "@top-center": case "@top-right": case "@top-right-corner": case "@bottom-left": case "@bottom-left-corner": case "@bottom-center": case "@bottom-right": case "@bottom-right-corner": case "@left-top": case "@left-middle": case "@left-bottom": case "@right-top": case "@right-middle": case "@right-bottom": hasBlock = true; break; case "@page": case "@document": case "@supports": case "@keyframes": hasBlock = true; hasIdentifier = true; break; case "@namespace": hasExpression = true; break; } if (hasIdentifier) { name += " " + ($(/^[^{]+/) || '').trim(); } if (hasBlock) { if (rules = $(this.block)) { return new(tree.Directive)(name, rules); } } else { if ((value = hasExpression ? $(this.expression) : $(this.entity)) && $(';')) { var directive = new(tree.Directive)(name, value); if (env.dumpLineNumbers) { directive.debugInfo = getDebugInfo(i, input, env); } return directive; } } restore(); }, font: function () { var value = [], expression = [], weight, shorthand, font, e; while (e = $(this.shorthand) || $(this.entity)) { expression.push(e); } value.push(new(tree.Expression)(expression)); if ($(',')) { while (e = $(this.expression)) { value.push(e); if (! $(',')) { break } } } return new(tree.Value)(value); }, // // A Value is a comma-delimited list of Expressions // // font-family: Baskerville, Georgia, serif; // // In a Rule, a Value represents everything after the `:`, // and before the `;`. // value: function () { var e, expressions = [], important; while (e = $(this.expression)) { expressions.push(e); if (! $(',')) { break } } if (expressions.length > 0) { return new(tree.Value)(expressions); } }, important: function () { if (input.charAt(i) === '!') { return $(/^! *important/); } }, sub: function () { var e; if ($('(') && (e = $(this.expression)) && $(')')) { return e; } }, multiplication: function () { var m, a, op, operation; if (m = $(this.operand)) { while (!peek(/^\/[*\/]/) && (op = ($('/') || $('*'))) && (a = $(this.operand))) { operation = new(tree.Operation)(op, [operation || m, a]); } return operation || m; } }, addition: function () { var m, a, op, operation; if (m = $(this.multiplication)) { while ((op = $(/^[-+]\s+/) || (!isWhitespace(input.charAt(i - 1)) && ($('+') || $('-')))) && (a = $(this.multiplication))) { operation = new(tree.Operation)(op, [operation || m, a]); } return operation || m; } }, conditions: function () { var a, b, index = i, condition; if (a = $(this.condition)) { while ($(',') && (b = $(this.condition))) { condition = new(tree.Condition)('or', condition || a, b, index); } return condition || a; } }, condition: function () { var a, b, c, op, index = i, negate = false; if ($(/^not/)) { negate = true } expect('('); if (a = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) { if (op = $(/^(?:>=|=<|[<=>])/)) { if (b = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) { c = new(tree.Condition)(op, a, b, index, negate); } else { error('expected expression'); } } else { c = new(tree.Condition)('=', a, new(tree.Keyword)('true'), index, negate); } expect(')'); return $(/^and/) ? new(tree.Condition)('and', c, $(this.condition)) : c; } }, // // An operand is anything that can be part of an operation, // such as a Color, or a Variable // operand: function () { var negate, p = input.charAt(i + 1); if (input.charAt(i) === '-' && (p === '@' || p === '(')) { negate = $('-') } var o = $(this.sub) || $(this.entities.dimension) || $(this.entities.color) || $(this.entities.variable) || $(this.entities.call); return negate ? new(tree.Operation)('*', [new(tree.Dimension)(-1), o]) : o; }, // // Expressions either represent mathematical operations, // or white-space delimited Entities. // // 1px solid black // @var * 2 // expression: function () { var e, delim, entities = [], d; while (e = $(this.addition) || $(this.entity)) { entities.push(e); } if (entities.length > 0) { return new(tree.Expression)(entities); } }, property: function () { var name; if (name = $(/^(\*?-?[_a-z0-9-]+)\s*:/)) { return name[1]; } } } }; }; if (less.mode === 'browser' || less.mode === 'rhino') { // // Used by `@import` directives // less.Parser.importer = function (path, paths, callback, env) { if (!/^([a-z-]+:)?\//.test(path) && paths.length > 0) { path = paths[0] + path; } // We pass `true` as 3rd argument, to force the reload of the import. // This is so we can get the syntax tree as opposed to just the CSS output, // as we need this to evaluate the current stylesheet. loadStyleSheet({ href: path, title: path, type: env.mime, contents: env.contents, files: env.files, rootpath: env.rootpath, entryPath: env.entryPath, relativeUrls: env.relativeUrls }, function (e, root, data, sheet, _, path) { if (e && typeof(env.errback) === "function") { env.errback.call(null, path, paths, callback, env); } else { callback.call(null, e, root, path); } }, true); }; } (function (tree) { tree.functions = { rgb: function (r, g, b) { return this.rgba(r, g, b, 1.0); }, rgba: function (r, g, b, a) { var rgb = [r, g, b].map(function (c) { return scaled(c, 256); }); a = number(a); return new(tree.Color)(rgb, a); }, hsl: function (h, s, l) { return this.hsla(h, s, l, 1.0); }, hsla: function (h, s, l, a) { h = (number(h) % 360) / 360; s = number(s); l = number(l); a = number(a); var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s; var m1 = l * 2 - m2; return this.rgba(hue(h + 1/3) * 255, hue(h) * 255, hue(h - 1/3) * 255, a); function hue(h) { h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h); if (h * 6 < 1) return m1 + (m2 - m1) * h * 6; else if (h * 2 < 1) return m2; else if (h * 3 < 2) return m1 + (m2 - m1) * (2/3 - h) * 6; else return m1; } }, hsv: function(h, s, v) { return this.hsva(h, s, v, 1.0); }, hsva: function(h, s, v, a) { h = ((number(h) % 360) / 360) * 360; s = number(s); v = number(v); a = number(a); var i, f; i = Math.floor((h / 60) % 6); f = (h / 60) - i; var vs = [v, v * (1 - s), v * (1 - f * s), v * (1 - (1 - f) * s)]; var perm = [[0, 3, 1], [2, 0, 1], [1, 0, 3], [1, 2, 0], [3, 1, 0], [0, 1, 2]]; return this.rgba(vs[perm[i][0]] * 255, vs[perm[i][1]] * 255, vs[perm[i][2]] * 255, a); }, hue: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().h)); }, saturation: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().s * 100), '%'); }, lightness: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().l * 100), '%'); }, red: function (color) { return new(tree.Dimension)(color.rgb[0]); }, green: function (color) { return new(tree.Dimension)(color.rgb[1]); }, blue: function (color) { return new(tree.Dimension)(color.rgb[2]); }, alpha: function (color) { return new(tree.Dimension)(color.toHSL().a); }, luma: function (color) { return new(tree.Dimension)(Math.round((0.2126 * (color.rgb[0]/255) + 0.7152 * (color.rgb[1]/255) + 0.0722 * (color.rgb[2]/255)) * color.alpha * 100), '%'); }, saturate: function (color, amount) { var hsl = color.toHSL(); hsl.s += amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, desaturate: function (color, amount) { var hsl = color.toHSL(); hsl.s -= amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, lighten: function (color, amount) { var hsl = color.toHSL(); hsl.l += amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, darken: function (color, amount) { var hsl = color.toHSL(); hsl.l -= amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, fadein: function (color, amount) { var hsl = color.toHSL(); hsl.a += amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, fadeout: function (color, amount) { var hsl = color.toHSL(); hsl.a -= amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, fade: function (color, amount) { var hsl = color.toHSL(); hsl.a = amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, spin: function (color, amount) { var hsl = color.toHSL(); var hue = (hsl.h + amount.value) % 360; hsl.h = hue < 0 ? 360 + hue : hue; return hsla(hsl); }, // // Copyright (c) 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein // http://sass-lang.com // mix: function (color1, color2, weight) { if (!weight) { weight = new(tree.Dimension)(50); } var p = weight.value / 100.0; var w = p * 2 - 1; var a = color1.toHSL().a - color2.toHSL().a; var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0; var w2 = 1 - w1; var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2, color1.rgb[1] * w1 + color2.rgb[1] * w2, color1.rgb[2] * w1 + color2.rgb[2] * w2]; var alpha = color1.alpha * p + color2.alpha * (1 - p); return new(tree.Color)(rgb, alpha); }, greyscale: function (color) { return this.desaturate(color, new(tree.Dimension)(100)); }, contrast: function (color, dark, light, threshold) { // filter: contrast(3.2); // should be kept as is, so check for color if (!color.rgb) { return null; } if (typeof light === 'undefined') { light = this.rgba(255, 255, 255, 1.0); } if (typeof dark === 'undefined') { dark = this.rgba(0, 0, 0, 1.0); } if (typeof threshold === 'undefined') { threshold = 0.43; } else { threshold = threshold.value; } if (((0.2126 * (color.rgb[0]/255) + 0.7152 * (color.rgb[1]/255) + 0.0722 * (color.rgb[2]/255)) * color.alpha) < threshold) { return light; } else { return dark; } }, e: function (str) { return new(tree.Anonymous)(str instanceof tree.JavaScript ? str.evaluated : str); }, escape: function (str) { return new(tree.Anonymous)(encodeURI(str.value).replace(/=/g, "%3D").replace(/:/g, "%3A").replace(/#/g, "%23").replace(/;/g, "%3B").replace(/\(/g, "%28").replace(/\)/g, "%29")); }, '%': function (quoted /* arg, arg, ...*/) { var args = Array.prototype.slice.call(arguments, 1), str = quoted.value; for (var i = 0; i < args.length; i++) { str = str.replace(/%[sda]/i, function(token) { var value = token.match(/s/i) ? args[i].value : args[i].toCSS(); return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value; }); } str = str.replace(/%%/g, '%'); return new(tree.Quoted)('"' + str + '"', str); }, unit: function (val, unit) { return new(tree.Dimension)(val.value, unit ? unit.toCSS() : ""); }, round: function (n, f) { var fraction = typeof(f) === "undefined" ? 0 : f.value; return this._math(function(num) { return num.toFixed(fraction); }, n); }, ceil: function (n) { return this._math(Math.ceil, n); }, floor: function (n) { return this._math(Math.floor, n); }, _math: function (fn, n) { if (n instanceof tree.Dimension) { return new(tree.Dimension)(fn(parseFloat(n.value)), n.unit); } else if (typeof(n) === 'number') { return fn(n); } else { throw { type: "Argument", message: "argument must be a number" }; } }, argb: function (color) { return new(tree.Anonymous)(color.toARGB()); }, percentage: function (n) { return new(tree.Dimension)(n.value * 100, '%'); }, color: function (n) { if (n instanceof tree.Quoted) { return new(tree.Color)(n.value.slice(1)); } else { throw { type: "Argument", message: "argument must be a string" }; } }, iscolor: function (n) { return this._isa(n, tree.Color); }, isnumber: function (n) { return this._isa(n, tree.Dimension); }, isstring: function (n) { return this._isa(n, tree.Quoted); }, iskeyword: function (n) { return this._isa(n, tree.Keyword); }, isurl: function (n) { return this._isa(n, tree.URL); }, ispixel: function (n) { return (n instanceof tree.Dimension) && n.unit.is('px') ? tree.True : tree.False; }, ispercentage: function (n) { return (n instanceof tree.Dimension) && n.unit.is('%') ? tree.True : tree.False; }, isem: function (n) { return (n instanceof tree.Dimension) && n.unit.is('em') ? tree.True : tree.False; }, _isa: function (n, Type) { return (n instanceof Type) ? tree.True : tree.False; }, /* Blending modes */ multiply: function(color1, color2) { var r = color1.rgb[0] * color2.rgb[0] / 255; var g = color1.rgb[1] * color2.rgb[1] / 255; var b = color1.rgb[2] * color2.rgb[2] / 255; return this.rgb(r, g, b); }, screen: function(color1, color2) { var r = 255 - (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255; var g = 255 - (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255; var b = 255 - (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255; return this.rgb(r, g, b); }, overlay: function(color1, color2) { var r = color1.rgb[0] < 128 ? 2 * color1.rgb[0] * color2.rgb[0] / 255 : 255 - 2 * (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255; var g = color1.rgb[1] < 128 ? 2 * color1.rgb[1] * color2.rgb[1] / 255 : 255 - 2 * (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255; var b = color1.rgb[2] < 128 ? 2 * color1.rgb[2] * color2.rgb[2] / 255 : 255 - 2 * (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255; return this.rgb(r, g, b); }, softlight: function(color1, color2) { var t = color2.rgb[0] * color1.rgb[0] / 255; var r = t + color1.rgb[0] * (255 - (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255 - t) / 255; t = color2.rgb[1] * color1.rgb[1] / 255; var g = t + color1.rgb[1] * (255 - (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255 - t) / 255; t = color2.rgb[2] * color1.rgb[2] / 255; var b = t + color1.rgb[2] * (255 - (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255 - t) / 255; return this.rgb(r, g, b); }, hardlight: function(color1, color2) { var r = color2.rgb[0] < 128 ? 2 * color2.rgb[0] * color1.rgb[0] / 255 : 255 - 2 * (255 - color2.rgb[0]) * (255 - color1.rgb[0]) / 255; var g = color2.rgb[1] < 128 ? 2 * color2.rgb[1] * color1.rgb[1] / 255 : 255 - 2 * (255 - color2.rgb[1]) * (255 - color1.rgb[1]) / 255; var b = color2.rgb[2] < 128 ? 2 * color2.rgb[2] * color1.rgb[2] / 255 : 255 - 2 * (255 - color2.rgb[2]) * (255 - color1.rgb[2]) / 255; return this.rgb(r, g, b); }, difference: function(color1, color2) { var r = Math.abs(color1.rgb[0] - color2.rgb[0]); var g = Math.abs(color1.rgb[1] - color2.rgb[1]); var b = Math.abs(color1.rgb[2] - color2.rgb[2]); return this.rgb(r, g, b); }, exclusion: function(color1, color2) { var r = color1.rgb[0] + color2.rgb[0] * (255 - color1.rgb[0] - color1.rgb[0]) / 255; var g = color1.rgb[1] + color2.rgb[1] * (255 - color1.rgb[1] - color1.rgb[1]) / 255; var b = color1.rgb[2] + color2.rgb[2] * (255 - color1.rgb[2] - color1.rgb[2]) / 255; return this.rgb(r, g, b); }, average: function(color1, color2) { var r = (color1.rgb[0] + color2.rgb[0]) / 2; var g = (color1.rgb[1] + color2.rgb[1]) / 2; var b = (color1.rgb[2] + color2.rgb[2]) / 2; return this.rgb(r, g, b); }, negation: function(color1, color2) { var r = 255 - Math.abs(255 - color2.rgb[0] - color1.rgb[0]); var g = 255 - Math.abs(255 - color2.rgb[1] - color1.rgb[1]); var b = 255 - Math.abs(255 - color2.rgb[2] - color1.rgb[2]); return this.rgb(r, g, b); }, tint: function(color, amount) { return this.mix(this.rgb(255,255,255), color, amount); }, shade: function(color, amount) { return this.mix(this.rgb(0, 0, 0), color, amount); } }; function hsla(color) { return tree.functions.hsla(color.h, color.s, color.l, color.a); } function scaled(n, size) { if (n instanceof tree.Dimension && n.unit.is('%')) { return parseFloat(n.value * size / 100); } else { return number(n); } } function number(n) { if (n instanceof tree.Dimension) { return parseFloat(n.unit.is('%') ? n.value / 100 : n.value); } else if (typeof(n) === 'number') { return n; } else { throw { error: "RuntimeError", message: "color functions take numbers as parameters" }; } } function clamp(val) { return Math.min(1, Math.max(0, val)); } })(require('./tree')); (function (tree) { tree.colors = { 'aliceblue':'#f0f8ff', 'antiquewhite':'#faebd7', 'aqua':'#00ffff', 'aquamarine':'#7fffd4', 'azure':'#f0ffff', 'beige':'#f5f5dc', 'bisque':'#ffe4c4', 'black':'#000000', 'blanchedalmond':'#ffebcd', 'blue':'#0000ff', 'blueviolet':'#8a2be2', 'brown':'#a52a2a', 'burlywood':'#deb887', 'cadetblue':'#5f9ea0', 'chartreuse':'#7fff00', 'chocolate':'#d2691e', 'coral':'#ff7f50', 'cornflowerblue':'#6495ed', 'cornsilk':'#fff8dc', 'crimson':'#dc143c', 'cyan':'#00ffff', 'darkblue':'#00008b', 'darkcyan':'#008b8b', 'darkgoldenrod':'#b8860b', 'darkgray':'#a9a9a9', 'darkgrey':'#a9a9a9', 'darkgreen':'#006400', 'darkkhaki':'#bdb76b', 'darkmagenta':'#8b008b', 'darkolivegreen':'#556b2f', 'darkorange':'#ff8c00', 'darkorchid':'#9932cc', 'darkred':'#8b0000', 'darksalmon':'#e9967a', 'darkseagreen':'#8fbc8f', 'darkslateblue':'#483d8b', 'darkslategray':'#2f4f4f', 'darkslategrey':'#2f4f4f', 'darkturquoise':'#00ced1', 'darkviolet':'#9400d3', 'deeppink':'#ff1493', 'deepskyblue':'#00bfff', 'dimgray':'#696969', 'dimgrey':'#696969', 'dodgerblue':'#1e90ff', 'firebrick':'#b22222', 'floralwhite':'#fffaf0', 'forestgreen':'#228b22', 'fuchsia':'#ff00ff', 'gainsboro':'#dcdcdc', 'ghostwhite':'#f8f8ff', 'gold':'#ffd700', 'goldenrod':'#daa520', 'gray':'#808080', 'grey':'#808080', 'green':'#008000', 'greenyellow':'#adff2f', 'honeydew':'#f0fff0', 'hotpink':'#ff69b4', 'indianred':'#cd5c5c', 'indigo':'#4b0082', 'ivory':'#fffff0', 'khaki':'#f0e68c', 'lavender':'#e6e6fa', 'lavenderblush':'#fff0f5', 'lawngreen':'#7cfc00', 'lemonchiffon':'#fffacd', 'lightblue':'#add8e6', 'lightcoral':'#f08080', 'lightcyan':'#e0ffff', 'lightgoldenrodyellow':'#fafad2', 'lightgray':'#d3d3d3', 'lightgrey':'#d3d3d3', 'lightgreen':'#90ee90', 'lightpink':'#ffb6c1', 'lightsalmon':'#ffa07a', 'lightseagreen':'#20b2aa', 'lightskyblue':'#87cefa', 'lightslategray':'#778899', 'lightslategrey':'#778899', 'lightsteelblue':'#b0c4de', 'lightyellow':'#ffffe0', 'lime':'#00ff00', 'limegreen':'#32cd32', 'linen':'#faf0e6', 'magenta':'#ff00ff', 'maroon':'#800000', 'mediumaquamarine':'#66cdaa', 'mediumblue':'#0000cd', 'mediumorchid':'#ba55d3', 'mediumpurple':'#9370d8', 'mediumseagreen':'#3cb371', 'mediumslateblue':'#7b68ee', 'mediumspringgreen':'#00fa9a', 'mediumturquoise':'#48d1cc', 'mediumvioletred':'#c71585', 'midnightblue':'#191970', 'mintcream':'#f5fffa', 'mistyrose':'#ffe4e1', 'moccasin':'#ffe4b5', 'navajowhite':'#ffdead', 'navy':'#000080', 'oldlace':'#fdf5e6', 'olive':'#808000', 'olivedrab':'#6b8e23', 'orange':'#ffa500', 'orangered':'#ff4500', 'orchid':'#da70d6', 'palegoldenrod':'#eee8aa', 'palegreen':'#98fb98', 'paleturquoise':'#afeeee', 'palevioletred':'#d87093', 'papayawhip':'#ffefd5', 'peachpuff':'#ffdab9', 'peru':'#cd853f', 'pink':'#ffc0cb', 'plum':'#dda0dd', 'powderblue':'#b0e0e6', 'purple':'#800080', 'red':'#ff0000', 'rosybrown':'#bc8f8f', 'royalblue':'#4169e1', 'saddlebrown':'#8b4513', 'salmon':'#fa8072', 'sandybrown':'#f4a460', 'seagreen':'#2e8b57', 'seashell':'#fff5ee', 'sienna':'#a0522d', 'silver':'#c0c0c0', 'skyblue':'#87ceeb', 'slateblue':'#6a5acd', 'slategray':'#708090', 'slategrey':'#708090', 'snow':'#fffafa', 'springgreen':'#00ff7f', 'steelblue':'#4682b4', 'tan':'#d2b48c', 'teal':'#008080', 'thistle':'#d8bfd8', 'tomato':'#ff6347', // 'transparent':'rgba(0,0,0,0)', 'turquoise':'#40e0d0', 'violet':'#ee82ee', 'wheat':'#f5deb3', 'white':'#ffffff', 'whitesmoke':'#f5f5f5', 'yellow':'#ffff00', 'yellowgreen':'#9acd32' }; })(require('./tree')); (function (tree) { tree.Alpha = function (val) { this.value = val; }; tree.Alpha.prototype = { toCSS: function () { return "alpha(opacity=" + (this.value.toCSS ? this.value.toCSS() : this.value) + ")"; }, eval: function (env) { if (this.value.eval) { this.value = this.value.eval(env) } return this; } }; })(require('../tree')); (function (tree) { tree.Anonymous = function (string) { this.value = string.value || string; }; tree.Anonymous.prototype = { toCSS: function () { return this.value; }, eval: function () { return this }, compare: function (x) { if (!x.toCSS) { return -1; } var left = this.toCSS(), right = x.toCSS(); if (left === right) { return 0; } return left < right ? -1 : 1; } }; })(require('../tree')); (function (tree) { tree.Assignment = function (key, val) { this.key = key; this.value = val; }; tree.Assignment.prototype = { toCSS: function () { return this.key + '=' + (this.value.toCSS ? this.value.toCSS() : this.value); }, eval: function (env) { if (this.value.eval) { return new(tree.Assignment)(this.key, this.value.eval(env)); } return this; } }; })(require('../tree'));(function (tree) { // // A function call node. // tree.Call = function (name, args, index, filename) { this.name = name; this.args = args; this.index = index; this.filename = filename; }; tree.Call.prototype = { // // When evaluating a function call, // we either find the function in `tree.functions` [1], // in which case we call it, passing the evaluated arguments, // if this returns null or we cannot find the function, we // simply print it out as it appeared originally [2]. // // The *functions.js* file contains the built-in functions. // // The reason why we evaluate the arguments, is in the case where // we try to pass a variable to a function, like: `saturate(@color)`. // The function should receive the value, not the variable. // eval: function (env) { var args = this.args.map(function (a) { return a.eval(env) }), result; if (this.name in tree.functions) { // 1. try { result = tree.functions[this.name].apply(tree.functions, args); if (result != null) { return result; } } catch (e) { throw { type: e.type || "Runtime", message: "error evaluating function `" + this.name + "`" + (e.message ? ': ' + e.message : ''), index: this.index, filename: this.filename }; } } // 2. return new(tree.Anonymous)(this.name + "(" + args.map(function (a) { return a.toCSS(env) }).join(', ') + ")"); }, toCSS: function (env) { return this.eval(env).toCSS(); } }; })(require('../tree')); (function (tree) { // // RGB Colors - #ff0014, #eee // tree.Color = function (rgb, a) { // // The end goal here, is to parse the arguments // into an integer triplet, such as `128, 255, 0` // // This facilitates operations and conversions. // if (Array.isArray(rgb)) { this.rgb = rgb; } else if (rgb.length == 6) { this.rgb = rgb.match(/.{2}/g).map(function (c) { return parseInt(c, 16); }); } else { this.rgb = rgb.split('').map(function (c) { return parseInt(c + c, 16); }); } this.alpha = typeof(a) === 'number' ? a : 1; }; tree.Color.prototype = { eval: function () { return this }, // // If we have some transparency, the only way to represent it // is via `rgba`. Otherwise, we use the hex representation, // which has better compatibility with older browsers. // Values are capped between `0` and `255`, rounded and zero-padded. // toCSS: function () { if (this.alpha < 1.0) { return "rgba(" + this.rgb.map(function (c) { return Math.round(c); }).concat(this.alpha).join(', ') + ")"; } else { return '#' + this.rgb.map(function (i) { i = Math.round(i); i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16); return i.length === 1 ? '0' + i : i; }).join(''); } }, // // Operations have to be done per-channel, if not, // channels will spill onto each other. Once we have // our result, in the form of an integer triplet, // we create a new Color node to hold the result. // operate: function (op, other) { var result = []; if (! (other instanceof tree.Color)) { other = other.toColor(); } for (var c = 0; c < 3; c++) { result[c] = tree.operate(op, this.rgb[c], other.rgb[c]); } return new(tree.Color)(result, this.alpha + other.alpha); }, toHSL: function () { var r = this.rgb[0] / 255, g = this.rgb[1] / 255, b = this.rgb[2] / 255, a = this.alpha; var max = Math.max(r, g, b), min = Math.min(r, g, b); var h, s, l = (max + min) / 2, d = max - min; if (max === min) { h = s = 0; } else { s = l > 0.5 ? d / (2 - max - min) : d / (max + min); switch (max) { case r: h = (g - b) / d + (g < b ? 6 : 0); break; case g: h = (b - r) / d + 2; break; case b: h = (r - g) / d + 4; break; } h /= 6; } return { h: h * 360, s: s, l: l, a: a }; }, toARGB: function () { var argb = [Math.round(this.alpha * 255)].concat(this.rgb); return '#' + argb.map(function (i) { i = Math.round(i); i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16); return i.length === 1 ? '0' + i : i; }).join(''); }, compare: function (x) { if (!x.rgb) { return -1; } return (x.rgb[0] === this.rgb[0] && x.rgb[1] === this.rgb[1] && x.rgb[2] === this.rgb[2] && x.alpha === this.alpha) ? 0 : -1; } }; })(require('../tree')); (function (tree) { tree.Comment = function (value, silent) { this.value = value; this.silent = !!silent; }; tree.Comment.prototype = { toCSS: function (env) { return env.compress ? '' : this.value; }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.Condition = function (op, l, r, i, negate) { this.op = op.trim(); this.lvalue = l; this.rvalue = r; this.index = i; this.negate = negate; }; tree.Condition.prototype.eval = function (env) { var a = this.lvalue.eval(env), b = this.rvalue.eval(env); var i = this.index, result; var result = (function (op) { switch (op) { case 'and': return a && b; case 'or': return a || b; default: if (a.compare) { result = a.compare(b); } else if (b.compare) { result = b.compare(a); } else { throw { type: "Type", message: "Unable to perform comparison", index: i }; } switch (result) { case -1: return op === '<' || op === '=<'; case 0: return op === '=' || op === '>=' || op === '=<'; case 1: return op === '>' || op === '>='; } } })(this.op); return this.negate ? !result : result; }; })(require('../tree')); (function (tree) { // // A number with a unit // tree.Dimension = function (value, unit) { this.value = parseFloat(value); this.unit = (unit && unit instanceof tree.Unit) ? unit : new(tree.Unit)(unit ? [unit] : undefined); }; tree.Dimension.prototype = { eval: function () { return this }, toColor: function () { return new(tree.Color)([this.value, this.value, this.value]); }, toCSS: function () { return this.unit.isEmpty() ? this.value : (String(this.value) + this.unit.toCSS()); }, // In an operation between two Dimensions, // we default to the first Dimension's unit, // so `1px + 2` will yield `3px`. operate: function (op, other) { var value = tree.operate(op, this.value, other.value), unit = this.unit.clone(); if (op === '+' || op === '-') { if (unit.numerator.length === 0 && unit.denominator.length === 0) { unit.numerator = other.unit.numerator.slice(0); unit.denominator = other.unit.denominator.slice(0); } else if (other.unit.numerator.length == 0 && unit.denominator.length == 0) { // do nothing } else { other = other.convertTo(this.unit.usedUnits()); if(other.unit.toCSS() !== unit.toCSS()) { throw new Error("Incompatible units: '" + unit.toCSS() + "' and '" + other.unit.toCSS() + "'."); } value = tree.operate(op, this.value, other.value); } } else if (op === '*') { unit.numerator = unit.numerator.concat(other.unit.numerator).sort(); unit.denominator = unit.denominator.concat(other.unit.denominator).sort(); unit.cancel(); } else if (op === '/') { unit.numerator = unit.numerator.concat(other.unit.denominator).sort(); unit.denominator = unit.denominator.concat(other.unit.numerator).sort(); unit.cancel(); } return new(tree.Dimension)(value, unit); }, compare: function (other) { if (other instanceof tree.Dimension) { var a = this.unify(), b = other.unify(), aValue = a.value, bValue = b.value; if (bValue > aValue) { return -1; } else if (bValue < aValue) { return 1; } else { if (!b.unit.isEmpty() && a.unit.compare(b) !== 0) { return -1; } return 0; } } else { return -1; } }, unify: function () { return this.convertTo({ length: 'm', duration: 's' }); }, convertTo: function (conversions) { var value = this.value, unit = this.unit.clone(), i, groupName, group, conversion, targetUnit; for (groupName in conversions) { if (conversions.hasOwnProperty(groupName)) { targetUnit = conversions[groupName]; group = tree.UnitConversions[groupName]; unit.map(function (atomicUnit, denominator) { if (group.hasOwnProperty(atomicUnit)) { if (denominator) { value = value / (group[atomicUnit] / group[targetUnit]); } else { value = value * (group[atomicUnit] / group[targetUnit]); } return targetUnit; } return atomicUnit; }); } } unit.cancel(); return new(tree.Dimension)(value, unit); } }; // http://www.w3.org/TR/css3-values/#absolute-lengths tree.UnitConversions = { length: { 'm': 1, 'cm': 0.01, 'mm': 0.001, 'in': 0.0254, 'pt': 0.0254 / 72, 'pc': 0.0254 / 72 * 12 }, duration: { 's': 1, 'ms': 0.001 } }; tree.Unit = function (numerator, denominator) { this.numerator = numerator ? numerator.slice(0).sort() : []; this.denominator = denominator ? denominator.slice(0).sort() : []; }; tree.Unit.prototype = { clone: function () { return new tree.Unit(this.numerator.slice(0), this.denominator.slice(0)); }, toCSS: function () { var i, css = this.numerator.join("*"); for (i = 0; i < this.denominator.length; i++) { css += "/" + this.denominator[i]; } return css; }, compare: function (other) { return this.is(other.toCSS()) ? 0 : -1; }, is: function (unitString) { return this.toCSS() === unitString; }, isEmpty: function () { return this.numerator.length == 0 && this.denominator.length == 0; }, map: function(callback) { var i; for (i = 0; i < this.numerator.length; i++) { this.numerator[i] = callback(this.numerator[i], false); } for (i = 0; i < this.denominator.length; i++) { this.denominator[i] = callback(this.denominator[i], true); } }, usedUnits: function() { var group, groupName, result = {}; for (groupName in tree.UnitConversions) { if (tree.UnitConversions.hasOwnProperty(groupName)) { group = tree.UnitConversions[groupName]; this.map(function (atomicUnit) { if (group.hasOwnProperty(atomicUnit) && !result[groupName]) { result[groupName] = atomicUnit; } return atomicUnit; }); } } return result; }, cancel: function () { var counter = {}, atomicUnit, i; for (i = 0; i < this.numerator.length; i++) { atomicUnit = this.numerator[i]; counter[atomicUnit] = (counter[atomicUnit] || 0) + 1; } for (i = 0; i < this.denominator.length; i++) { atomicUnit = this.denominator[i]; counter[atomicUnit] = (counter[atomicUnit] || 0) - 1; } this.numerator = []; this.denominator = []; for (atomicUnit in counter) { if (counter.hasOwnProperty(atomicUnit)) { var count = counter[atomicUnit]; if (count > 0) { for (i = 0; i < count; i++) { this.numerator.push(atomicUnit); } } else if (count < 0) { for (i = 0; i < -count; i++) { this.denominator.push(atomicUnit); } } } } this.numerator.sort(); this.denominator.sort(); } }; })(require('../tree')); (function (tree) { tree.Directive = function (name, value) { this.name = name; if (Array.isArray(value)) { this.ruleset = new(tree.Ruleset)([], value); this.ruleset.allowImports = true; } else { this.value = value; } }; tree.Directive.prototype = { toCSS: function (ctx, env) { if (this.ruleset) { this.ruleset.root = true; return this.name + (env.compress ? '{' : ' {\n ') + this.ruleset.toCSS(ctx, env).trim().replace(/\n/g, '\n ') + (env.compress ? '}': '\n}\n'); } else { return this.name + ' ' + this.value.toCSS() + ';\n'; } }, eval: function (env) { var evaldDirective = this; if (this.ruleset) { env.frames.unshift(this); evaldDirective = new(tree.Directive)(this.name); evaldDirective.ruleset = this.ruleset.eval(env); env.frames.shift(); } return evaldDirective; }, variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) }, find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) }, rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) } }; })(require('../tree')); (function (tree) { tree.Element = function (combinator, value, index) { this.combinator = combinator instanceof tree.Combinator ? combinator : new(tree.Combinator)(combinator); if (typeof(value) === 'string') { this.value = value.trim(); } else if (value) { this.value = value; } else { this.value = ""; } this.index = index; }; tree.Element.prototype.eval = function (env) { return new(tree.Element)(this.combinator, this.value.eval ? this.value.eval(env) : this.value, this.index); }; tree.Element.prototype.toCSS = function (env) { var value = (this.value.toCSS ? this.value.toCSS(env) : this.value); if (value == '' && this.combinator.value.charAt(0) == '&') { return ''; } else { return this.combinator.toCSS(env || {}) + value; } }; tree.Combinator = function (value) { if (value === ' ') { this.value = ' '; } else { this.value = value ? value.trim() : ""; } }; tree.Combinator.prototype.toCSS = function (env) { return { '' : '', ' ' : ' ', ':' : ' :', '+' : env.compress ? '+' : ' + ', '~' : env.compress ? '~' : ' ~ ', '>' : env.compress ? '>' : ' > ', '|' : env.compress ? '|' : ' | ' }[this.value]; }; })(require('../tree')); (function (tree) { tree.Expression = function (value) { this.value = value }; tree.Expression.prototype = { eval: function (env) { if (this.value.length > 1) { return new(tree.Expression)(this.value.map(function (e) { return e.eval(env); })); } else if (this.value.length === 1) { return this.value[0].eval(env); } else { return this; } }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS ? e.toCSS(env) : ''; }).join(' '); } }; })(require('../tree')); (function (tree) { tree.Extend = function Extend(elements, index) { this.selector = new(tree.Selector)(elements); this.index = index; }; tree.Extend.prototype.eval = function Extend_eval(env, selectors) { var selfSelectors = findSelfSelectors(selectors || env.selectors), targetValue = this.selector.elements[0].value; env.frames.forEach(function(frame) { frame.rulesets().forEach(function(rule) { rule.selectors.forEach(function(selector) { selector.elements.forEach(function(element, idx) { if (element.value === targetValue) { selfSelectors.forEach(function(_selector) { _selector.elements[0] = new tree.Element( element.combinator, _selector.elements[0].value, _selector.elements[0].index ); rule.selectors.push(new tree.Selector( selector.elements .slice(0, idx) .concat(_selector.elements) .concat(selector.elements.slice(idx + 1)) )); }); } }); }); }); }); return this; }; function findSelfSelectors(selectors) { var ret = []; (function loop(elem, i) { if (selectors[i] && selectors[i].length) { selectors[i].forEach(function(s) { loop(s.elements.concat(elem), i + 1); }); } else { ret.push({ elements: elem }); } })([], 0); return ret; } })(require('../tree')); (function (tree) { // // CSS @import node // // The general strategy here is that we don't want to wait // for the parsing to be completed, before we start importing // the file. That's because in the context of a browser, // most of the time will be spent waiting for the server to respond. // // On creation, we push the import path to our import queue, though // `import,push`, we also pass it a callback, which it'll call once // the file has been fetched, and parsed. // tree.Import = function (path, imports, features, once, index, rootpath) { var that = this; this.once = once; this.index = index; this._path = path; this.features = features && new(tree.Value)(features); this.rootpath = rootpath; // The '.less' extension is optional if (path instanceof tree.Quoted) { this.path = /(\.[a-z]*$)|([\?;].*)$/.test(path.value) ? path.value : path.value + '.less'; } else { this.path = path.value.value || path.value; } this.css = /css([\?;].*)?$/.test(this.path); // Only pre-compile .less files if (! this.css) { imports.push(this.path, function (e, root, imported) { if (e) { e.index = index } if (imported && that.once) that.skip = imported; that.root = root || new(tree.Ruleset)([], []); }); } }; // // The actual import node doesn't return anything, when converted to CSS. // The reason is that it's used at the evaluation stage, so that the rules // it imports can be treated like any other rules. // // In `eval`, we make sure all Import nodes get evaluated, recursively, so // we end up with a flat structure, which can easily be imported in the parent // ruleset. // tree.Import.prototype = { toCSS: function (env) { var features = this.features ? ' ' + this.features.toCSS(env) : ''; if (this.css) { // Add the base path if the import is relative if (typeof this._path.value === "string" && !/^(?:[a-z-]+:|\/)/.test(this._path.value)) { this._path.value = this.rootpath + this._path.value; } return "@import " + this._path.toCSS() + features + ';\n'; } else { return ""; } }, eval: function (env) { var ruleset, features = this.features && this.features.eval(env); if (this.skip) return []; if (this.css) { return this; } else { ruleset = new(tree.Ruleset)([], this.root.rules.slice(0)); ruleset.evalImports(env); return this.features ? new(tree.Media)(ruleset.rules, this.features.value) : ruleset.rules; } } }; })(require('../tree')); (function (tree) { tree.JavaScript = function (string, index, escaped) { this.escaped = escaped; this.expression = string; this.index = index; }; tree.JavaScript.prototype = { eval: function (env) { var result, that = this, context = {}; var expression = this.expression.replace(/@\{([\w-]+)\}/g, function (_, name) { return tree.jsify(new(tree.Variable)('@' + name, that.index).eval(env)); }); try { expression = new(Function)('return (' + expression + ')'); } catch (e) { throw { message: "JavaScript evaluation error: `" + expression + "`" , index: this.index }; } for (var k in env.frames[0].variables()) { context[k.slice(1)] = { value: env.frames[0].variables()[k].value, toJS: function () { return this.value.eval(env).toCSS(); } }; } try { result = expression.call(context); } catch (e) { throw { message: "JavaScript evaluation error: '" + e.name + ': ' + e.message + "'" , index: this.index }; } if (typeof(result) === 'string') { return new(tree.Quoted)('"' + result + '"', result, this.escaped, this.index); } else if (Array.isArray(result)) { return new(tree.Anonymous)(result.join(', ')); } else { return new(tree.Anonymous)(result); } } }; })(require('../tree')); (function (tree) { tree.Keyword = function (value) { this.value = value }; tree.Keyword.prototype = { eval: function () { return this }, toCSS: function () { return this.value }, compare: function (other) { if (other instanceof tree.Keyword) { return other.value === this.value ? 0 : 1; } else { return -1; } } }; tree.True = new(tree.Keyword)('true'); tree.False = new(tree.Keyword)('false'); })(require('../tree')); (function (tree) { tree.Media = function (value, features) { var selectors = this.emptySelectors(); this.features = new(tree.Value)(features); this.ruleset = new(tree.Ruleset)(selectors, value); this.ruleset.allowImports = true; }; tree.Media.prototype = { toCSS: function (ctx, env) { var features = this.features.toCSS(env); this.ruleset.root = (ctx.length === 0 || ctx[0].multiMedia); return '@media ' + features + (env.compress ? '{' : ' {\n ') + this.ruleset.toCSS(ctx, env).trim().replace(/\n/g, '\n ') + (env.compress ? '}': '\n}\n'); }, eval: function (env) { if (!env.mediaBlocks) { env.mediaBlocks = []; env.mediaPath = []; } var media = new(tree.Media)([], []); if(this.debugInfo) { this.ruleset.debugInfo = this.debugInfo; media.debugInfo = this.debugInfo; } media.features = this.features.eval(env); env.mediaPath.push(media); env.mediaBlocks.push(media); env.frames.unshift(this.ruleset); media.ruleset = this.ruleset.eval(env); env.frames.shift(); env.mediaPath.pop(); return env.mediaPath.length === 0 ? media.evalTop(env) : media.evalNested(env) }, variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) }, find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) }, rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) }, emptySelectors: function() { var el = new(tree.Element)('', '&', 0); return [new(tree.Selector)([el])]; }, evalTop: function (env) { var result = this; // Render all dependent Media blocks. if (env.mediaBlocks.length > 1) { var selectors = this.emptySelectors(); result = new(tree.Ruleset)(selectors, env.mediaBlocks); result.multiMedia = true; } delete env.mediaBlocks; delete env.mediaPath; return result; }, evalNested: function (env) { var i, value, path = env.mediaPath.concat([this]); // Extract the media-query conditions separated with `,` (OR). for (i = 0; i < path.length; i++) { value = path[i].features instanceof tree.Value ? path[i].features.value : path[i].features; path[i] = Array.isArray(value) ? value : [value]; } // Trace all permutations to generate the resulting media-query. // // (a, b and c) with nested (d, e) -> // a and d // a and e // b and c and d // b and c and e this.features = new(tree.Value)(this.permute(path).map(function (path) { path = path.map(function (fragment) { return fragment.toCSS ? fragment : new(tree.Anonymous)(fragment); }); for(i = path.length - 1; i > 0; i--) { path.splice(i, 0, new(tree.Anonymous)("and")); } return new(tree.Expression)(path); })); // Fake a tree-node that doesn't output anything. return new(tree.Ruleset)([], []); }, permute: function (arr) { if (arr.length === 0) { return []; } else if (arr.length === 1) { return arr[0]; } else { var result = []; var rest = this.permute(arr.slice(1)); for (var i = 0; i < rest.length; i++) { for (var j = 0; j < arr[0].length; j++) { result.push([arr[0][j]].concat(rest[i])); } } return result; } }, bubbleSelectors: function (selectors) { this.ruleset = new(tree.Ruleset)(selectors.slice(0), [this.ruleset]); } }; })(require('../tree')); (function (tree) { tree.mixin = {}; tree.mixin.Call = function (elements, args, index, filename, important) { this.selector = new(tree.Selector)(elements); this.arguments = args; this.index = index; this.filename = filename; this.important = important; }; tree.mixin.Call.prototype = { eval: function (env) { var mixins, mixin, args, rules = [], match = false, i, m, f, isRecursive, isOneFound; args = this.arguments && this.arguments.map(function (a) { return { name: a.name, value: a.value.eval(env) }; }); for (i = 0; i < env.frames.length; i++) { if ((mixins = env.frames[i].find(this.selector)).length > 0) { isOneFound = true; for (m = 0; m < mixins.length; m++) { mixin = mixins[m]; isRecursive = false; for(f = 0; f < env.frames.length; f++) { if ((!(mixin instanceof tree.mixin.Definition)) && mixin === (env.frames[f].originalRuleset || env.frames[f])) { isRecursive = true; break; } } if (isRecursive) { continue; } if (mixin.matchArgs(args, env)) { if (!mixin.matchCondition || mixin.matchCondition(args, env)) { try { Array.prototype.push.apply( rules, mixin.eval(env, args, this.important).rules); } catch (e) { throw { message: e.message, index: this.index, filename: this.filename, stack: e.stack }; } } match = true; } } if (match) { return rules; } } } if (isOneFound) { throw { type: 'Runtime', message: 'No matching definition was found for `' + this.selector.toCSS().trim() + '(' + (args ? args.map(function (a) { var argValue = ""; if (a.name) { argValue += a.name + ":"; } if (a.value.toCSS) { argValue += a.value.toCSS(); } else { argValue += "???"; } return argValue; }).join(', ') : "") + ")`", index: this.index, filename: this.filename }; } else { throw { type: 'Name', message: this.selector.toCSS().trim() + " is undefined", index: this.index, filename: this.filename }; } } }; tree.mixin.Definition = function (name, params, rules, condition, variadic) { this.name = name; this.selectors = [new(tree.Selector)([new(tree.Element)(null, name)])]; this.params = params; this.condition = condition; this.variadic = variadic; this.arity = params.length; this.rules = rules; this._lookups = {}; this.required = params.reduce(function (count, p) { if (!p.name || (p.name && !p.value)) { return count + 1 } else { return count } }, 0); this.parent = tree.Ruleset.prototype; this.frames = []; }; tree.mixin.Definition.prototype = { toCSS: function () { return "" }, variable: function (name) { return this.parent.variable.call(this, name) }, variables: function () { return this.parent.variables.call(this) }, find: function () { return this.parent.find.apply(this, arguments) }, rulesets: function () { return this.parent.rulesets.apply(this) }, evalParams: function (env, mixinEnv, args, evaldArguments) { var frame = new(tree.Ruleset)(null, []), varargs, arg, params = this.params.slice(0), i, j, val, name, isNamedFound, argIndex; if (args) { args = args.slice(0); for(i = 0; i < args.length; i++) { arg = args[i]; if (name = (arg && arg.name)) { isNamedFound = false; for(j = 0; j < params.length; j++) { if (!evaldArguments[j] && name === params[j].name) { evaldArguments[j] = arg.value.eval(env); frame.rules.unshift(new(tree.Rule)(name, arg.value.eval(env))); isNamedFound = true; break; } } if (isNamedFound) { args.splice(i, 1); i--; continue; } else { throw { type: 'Runtime', message: "Named argument for " + this.name + ' ' + args[i].name + ' not found' }; } } } } argIndex = 0; for (i = 0; i < params.length; i++) { if (evaldArguments[i]) continue; arg = args && args[argIndex]; if (name = params[i].name) { if (params[i].variadic && args) { varargs = []; for (j = argIndex; j < args.length; j++) { varargs.push(args[j].value.eval(env)); } frame.rules.unshift(new(tree.Rule)(name, new(tree.Expression)(varargs).eval(env))); } else { val = arg && arg.value; if (val) { val = val.eval(env); } else if (params[i].value) { val = params[i].value.eval(mixinEnv); } else { throw { type: 'Runtime', message: "wrong number of arguments for " + this.name + ' (' + args.length + ' for ' + this.arity + ')' }; } frame.rules.unshift(new(tree.Rule)(name, val)); evaldArguments[i] = val; } } if (params[i].variadic && args) { for (j = argIndex; j < args.length; j++) { evaldArguments[j] = args[j].value.eval(env); } } argIndex++; } return frame; }, eval: function (env, args, important) { var _arguments = [], mixinFrames = this.frames.concat(env.frames), frame = this.evalParams(env, {frames: mixinFrames}, args, _arguments), context, rules, start, ruleset; frame.rules.unshift(new(tree.Rule)('@arguments', new(tree.Expression)(_arguments).eval(env))); rules = important ? this.parent.makeImportant.apply(this).rules : this.rules.slice(0); ruleset = new(tree.Ruleset)(null, rules).eval({ frames: [this, frame].concat(mixinFrames) }); ruleset.originalRuleset = this; return ruleset; }, matchCondition: function (args, env) { if (this.condition && !this.condition.eval({ frames: [this.evalParams(env, {frames: this.frames.concat(env.frames)}, args, [])].concat(env.frames) })) { return false } return true; }, matchArgs: function (args, env) { var argsLength = (args && args.length) || 0, len, frame; if (! this.variadic) { if (argsLength < this.required) { return false } if (argsLength > this.params.length) { return false } if ((this.required > 0) && (argsLength > this.params.length)) { return false } } len = Math.min(argsLength, this.arity); for (var i = 0; i < len; i++) { if (!this.params[i].name && !this.params[i].variadic) { if (args[i].value.eval(env).toCSS() != this.params[i].value.eval(env).toCSS()) { return false; } } } return true; } }; })(require('../tree')); (function (tree) { tree.Operation = function (op, operands) { this.op = op.trim(); this.operands = operands; }; tree.Operation.prototype.eval = function (env) { var a = this.operands[0].eval(env), b = this.operands[1].eval(env), temp; if (a instanceof tree.Dimension && b instanceof tree.Color) { if (this.op === '*' || this.op === '+') { temp = b, b = a, a = temp; } else { throw { name: "OperationError", message: "Can't substract or divide a color from a number" }; } } if (!a.operate) { throw { name: "OperationError", message: "Operation on an invalid type" }; } return a.operate(this.op, b); }; tree.operate = function (op, a, b) { switch (op) { case '+': return a + b; case '-': return a - b; case '*': return a * b; case '/': return a / b; } }; })(require('../tree')); (function (tree) { tree.Paren = function (node) { this.value = node; }; tree.Paren.prototype = { toCSS: function (env) { return '(' + this.value.toCSS(env).trim() + ')'; }, eval: function (env) { return new(tree.Paren)(this.value.eval(env)); } }; })(require('../tree')); (function (tree) { tree.Quoted = function (str, content, escaped, i) { this.escaped = escaped; this.value = content || ''; this.quote = str.charAt(0); this.index = i; }; tree.Quoted.prototype = { toCSS: function () { if (this.escaped) { return this.value; } else { return this.quote + this.value + this.quote; } }, eval: function (env) { var that = this; var value = this.value.replace(/`([^`]+)`/g, function (_, exp) { return new(tree.JavaScript)(exp, that.index, true).eval(env).value; }).replace(/@\{([\w-]+)\}/g, function (_, name) { var v = new(tree.Variable)('@' + name, that.index).eval(env); return (v instanceof tree.Quoted) ? v.value : v.toCSS(); }); return new(tree.Quoted)(this.quote + value + this.quote, value, this.escaped, this.index); }, compare: function (x) { if (!x.toCSS) { return -1; } var left = this.toCSS(), right = x.toCSS(); if (left === right) { return 0; } return left < right ? -1 : 1; } }; })(require('../tree')); (function (tree) { tree.Ratio = function (value) { this.value = value; }; tree.Ratio.prototype = { toCSS: function (env) { return this.value; }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.Rule = function (name, value, important, index, inline) { this.name = name; this.value = (value instanceof tree.Value) ? value : new(tree.Value)([value]); this.important = important ? ' ' + important.trim() : ''; this.index = index; this.inline = inline || false; if (name.charAt(0) === '@') { this.variable = true; } else { this.variable = false } }; tree.Rule.prototype.toCSS = function (env) { if (this.variable) { return "" } else { return this.name + (env.compress ? ':' : ': ') + this.value.toCSS(env) + this.important + (this.inline ? "" : ";"); } }; tree.Rule.prototype.eval = function (context) { return new(tree.Rule)(this.name, this.value.eval(context), this.important, this.index, this.inline); }; tree.Rule.prototype.makeImportant = function () { return new(tree.Rule)(this.name, this.value, "!important", this.index, this.inline); }; tree.Shorthand = function (a, b) { this.a = a; this.b = b; }; tree.Shorthand.prototype = { toCSS: function (env) { return this.a.toCSS(env) + "/" + this.b.toCSS(env); }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.Ruleset = function (selectors, rules, strictImports) { this.selectors = selectors; this.rules = rules; this._lookups = {}; this.strictImports = strictImports; }; tree.Ruleset.prototype = { eval: function (env) { var selectors = this.selectors && this.selectors.map(function (s) { return s.eval(env) }); var ruleset = new(tree.Ruleset)(selectors, this.rules.slice(0), this.strictImports); var rules; ruleset.originalRuleset = this; ruleset.root = this.root; ruleset.allowImports = this.allowImports; if(this.debugInfo) { ruleset.debugInfo = this.debugInfo; } // push the current ruleset to the frames stack env.frames.unshift(ruleset); // currrent selectors if (!env.selectors) { env.selectors = []; } env.selectors.unshift(this.selectors); // Evaluate imports if (ruleset.root || ruleset.allowImports || !ruleset.strictImports) { ruleset.evalImports(env); } // Store the frames around mixin definitions, // so they can be evaluated like closures when the time comes. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Definition) { ruleset.rules[i].frames = env.frames.slice(0); } } var mediaBlockCount = (env.mediaBlocks && env.mediaBlocks.length) || 0; // Evaluate mixin calls. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Call) { rules = ruleset.rules[i].eval(env); ruleset.rules.splice.apply(ruleset.rules, [i, 1].concat(rules)); i += rules.length-1; ruleset.resetCache(); } } if (this.selectors) { for (var i = 0; i < this.selectors.length; i++) { if (this.selectors[i].extend) { this.selectors[i].extend.eval(env, [[this.selectors[i]]].concat(env.selectors.slice(1))); } } } // Evaluate everything else for (var i = 0, rule; i < ruleset.rules.length; i++) { rule = ruleset.rules[i]; if (! (rule instanceof tree.mixin.Definition)) { ruleset.rules[i] = rule.eval ? rule.eval(env) : rule; } } // Pop the stack env.frames.shift(); env.selectors.shift(); if (env.mediaBlocks) { for(var i = mediaBlockCount; i < env.mediaBlocks.length; i++) { env.mediaBlocks[i].bubbleSelectors(selectors); } } return ruleset; }, evalImports: function(env) { var i, rules; for (i = 0; i < this.rules.length; i++) { if (this.rules[i] instanceof tree.Import) { rules = this.rules[i].eval(env); if (typeof rules.length === "number") { this.rules.splice.apply(this.rules, [i, 1].concat(rules)); i+= rules.length-1; } else { this.rules.splice(i, 1, rules); } this.resetCache(); } } }, makeImportant: function() { return new tree.Ruleset(this.selectors, this.rules.map(function (r) { if (r.makeImportant) { return r.makeImportant(); } else { return r; } }), this.strictImports); }, matchArgs: function (args) { return !args || args.length === 0; }, resetCache: function () { this._rulesets = null; this._variables = null; this._lookups = {}; }, variables: function () { if (this._variables) { return this._variables } else { return this._variables = this.rules.reduce(function (hash, r) { if (r instanceof tree.Rule && r.variable === true) { hash[r.name] = r; } return hash; }, {}); } }, variable: function (name) { return this.variables()[name]; }, rulesets: function () { return this.rules.filter(function (r) { return (r instanceof tree.Ruleset) || (r instanceof tree.mixin.Definition); }); }, find: function (selector, self) { self = self || this; var rules = [], rule, match, key = selector.toCSS(); if (key in this._lookups) { return this._lookups[key] } this.rulesets().forEach(function (rule) { if (rule !== self) { for (var j = 0; j < rule.selectors.length; j++) { if (match = selector.match(rule.selectors[j])) { if (selector.elements.length > rule.selectors[j].elements.length) { Array.prototype.push.apply(rules, rule.find( new(tree.Selector)(selector.elements.slice(1)), self)); } else { rules.push(rule); } break; } } } }); return this._lookups[key] = rules; }, // // Entry point for code generation // // `context` holds an array of arrays. // toCSS: function (context, env) { var css = [], // The CSS output rules = [], // node.Rule instances _rules = [], // rulesets = [], // node.Ruleset instances paths = [], // Current selectors selector, // The fully rendered selector debugInfo, // Line number debugging rule; if (! this.root) { this.joinSelectors(paths, context, this.selectors); } // Compile rules and rulesets for (var i = 0; i < this.rules.length; i++) { rule = this.rules[i]; if (rule.rules || (rule instanceof tree.Media)) { rulesets.push(rule.toCSS(paths, env)); } else if (rule instanceof tree.Directive) { var cssValue = rule.toCSS(paths, env); // Output only the first @charset definition as such - convert the others // to comments in case debug is enabled if (rule.name === "@charset") { // Only output the debug info together with subsequent @charset definitions // a comment (or @media statement) before the actual @charset directive would // be considered illegal css as it has to be on the first line if (env.charset) { if (rule.debugInfo) { rulesets.push(tree.debugInfo(env, rule)); rulesets.push(new tree.Comment("/* "+cssValue.replace(/\n/g, "")+" */\n").toCSS(env)); } continue; } env.charset = true; } rulesets.push(cssValue); } else if (rule instanceof tree.Comment) { if (!rule.silent) { if (this.root) { rulesets.push(rule.toCSS(env)); } else { rules.push(rule.toCSS(env)); } } } else { if (rule.toCSS && !rule.variable) { rules.push(rule.toCSS(env)); } else if (rule.value && !rule.variable) { rules.push(rule.value.toString()); } } } rulesets = rulesets.join(''); // If this is the root node, we don't render // a selector, or {}. // Otherwise, only output if this ruleset has rules. if (this.root) { css.push(rules.join(env.compress ? '' : '\n')); } else { if (rules.length > 0) { debugInfo = tree.debugInfo(env, this); selector = paths.map(function (p) { return p.map(function (s) { return s.toCSS(env); }).join('').trim(); }).join(env.compress ? ',' : ',\n'); // Remove duplicates for (var i = rules.length - 1; i >= 0; i--) { if (_rules.indexOf(rules[i]) === -1) { _rules.unshift(rules[i]); } } rules = _rules; css.push(debugInfo + selector + (env.compress ? '{' : ' {\n ') + rules.join(env.compress ? '' : '\n ') + (env.compress ? '}' : '\n}\n')); } } css.push(rulesets); return css.join('') + (env.compress ? '\n' : ''); }, joinSelectors: function (paths, context, selectors) { for (var s = 0; s < selectors.length; s++) { this.joinSelector(paths, context, selectors[s]); } }, joinSelector: function (paths, context, selector) { var i, j, k, hasParentSelector, newSelectors, el, sel, parentSel, newSelectorPath, afterParentJoin, newJoinedSelector, newJoinedSelectorEmpty, lastSelector, currentElements, selectorsMultiplied; for (i = 0; i < selector.elements.length; i++) { el = selector.elements[i]; if (el.value === '&') { hasParentSelector = true; } } if (!hasParentSelector) { if (context.length > 0) { for(i = 0; i < context.length; i++) { paths.push(context[i].concat(selector)); } } else { paths.push([selector]); } return; } // The paths are [[Selector]] // The first list is a list of comma seperated selectors // The inner list is a list of inheritance seperated selectors // e.g. // .a, .b { // .c { // } // } // == [[.a] [.c]] [[.b] [.c]] // // the elements from the current selector so far currentElements = []; // the current list of new selectors to add to the path. // We will build it up. We initiate it with one empty selector as we "multiply" the new selectors // by the parents newSelectors = [[]]; for (i = 0; i < selector.elements.length; i++) { el = selector.elements[i]; // non parent reference elements just get added if (el.value !== "&") { currentElements.push(el); } else { // the new list of selectors to add selectorsMultiplied = []; // merge the current list of non parent selector elements // on to the current list of selectors to add if (currentElements.length > 0) { this.mergeElementsOnToSelectors(currentElements, newSelectors); } // loop through our current selectors for(j = 0; j < newSelectors.length; j++) { sel = newSelectors[j]; // if we don't have any parent paths, the & might be in a mixin so that it can be used // whether there are parents or not if (context.length == 0) { // the combinator used on el should now be applied to the next element instead so that // it is not lost if (sel.length > 0) { sel[0].elements = sel[0].elements.slice(0); sel[0].elements.push(new(tree.Element)(el.combinator, '', 0)); //new Element(el.Combinator, "")); } selectorsMultiplied.push(sel); } else { // and the parent selectors for(k = 0; k < context.length; k++) { parentSel = context[k]; // We need to put the current selectors // then join the last selector's elements on to the parents selectors // our new selector path newSelectorPath = []; // selectors from the parent after the join afterParentJoin = []; newJoinedSelectorEmpty = true; //construct the joined selector - if & is the first thing this will be empty, // if not newJoinedSelector will be the last set of elements in the selector if (sel.length > 0) { newSelectorPath = sel.slice(0); lastSelector = newSelectorPath.pop(); newJoinedSelector = new(tree.Selector)(lastSelector.elements.slice(0)); newJoinedSelectorEmpty = false; } else { newJoinedSelector = new(tree.Selector)([]); } //put together the parent selectors after the join if (parentSel.length > 1) { afterParentJoin = afterParentJoin.concat(parentSel.slice(1)); } if (parentSel.length > 0) { newJoinedSelectorEmpty = false; // join the elements so far with the first part of the parent newJoinedSelector.elements.push(new(tree.Element)(el.combinator, parentSel[0].elements[0].value, 0)); newJoinedSelector.elements = newJoinedSelector.elements.concat(parentSel[0].elements.slice(1)); } if (!newJoinedSelectorEmpty) { // now add the joined selector newSelectorPath.push(newJoinedSelector); } // and the rest of the parent newSelectorPath = newSelectorPath.concat(afterParentJoin); // add that to our new set of selectors selectorsMultiplied.push(newSelectorPath); } } } // our new selectors has been multiplied, so reset the state newSelectors = selectorsMultiplied; currentElements = []; } } // if we have any elements left over (e.g. .a& .b == .b) // add them on to all the current selectors if (currentElements.length > 0) { this.mergeElementsOnToSelectors(currentElements, newSelectors); } for(i = 0; i < newSelectors.length; i++) { paths.push(newSelectors[i]); } }, mergeElementsOnToSelectors: function(elements, selectors) { var i, sel; if (selectors.length == 0) { selectors.push([ new(tree.Selector)(elements) ]); return; } for(i = 0; i < selectors.length; i++) { sel = selectors[i]; // if the previous thing in sel is a parent this needs to join on to it if (sel.length > 0) { sel[sel.length - 1] = new(tree.Selector)(sel[sel.length - 1].elements.concat(elements)); } else { sel.push(new(tree.Selector)(elements)); } } } }; })(require('../tree')); (function (tree) { tree.Selector = function (elements, extend) { this.elements = elements; this.extend = extend; }; tree.Selector.prototype.match = function (other) { var elements = this.elements, len = elements.length, oelements, olen, max, i; oelements = other.elements.slice( (other.elements.length && other.elements[0].value === "&") ? 1 : 0); olen = oelements.length; max = Math.min(len, olen) if (olen === 0 || len < olen) { return false; } else { for (i = 0; i < max; i++) { if (elements[i].value !== oelements[i].value) { return false; } } } return true; }; tree.Selector.prototype.eval = function (env) { return new(tree.Selector)(this.elements.map(function (e) { return e.eval(env); }), this.extend); }; tree.Selector.prototype.toCSS = function (env) { if (this._css) { return this._css } if (this.elements[0].combinator.value === "") { this._css = ' '; } else { this._css = ''; } this._css += this.elements.map(function (e) { if (typeof(e) === 'string') { return ' ' + e.trim(); } else { return e.toCSS(env); } }).join(''); return this._css; }; })(require('../tree')); (function (tree) { tree.UnicodeDescriptor = function (value) { this.value = value; }; tree.UnicodeDescriptor.prototype = { toCSS: function (env) { return this.value; }, eval: function () { return this } }; })(require('../tree')); (function (tree) { tree.URL = function (val, rootpath) { this.value = val; this.rootpath = rootpath; }; tree.URL.prototype = { toCSS: function () { return "url(" + this.value.toCSS() + ")"; }, eval: function (ctx) { var val = this.value.eval(ctx), rootpath; // Add the base path if the URL is relative if (typeof val.value === "string" && !/^(?:[a-z-]+:|\/)/.test(val.value)) { rootpath = this.rootpath; if (!val.quote) { rootpath = rootpath.replace(/[\(\)'"\s]/g, function(match) { return "\\"+match; }); } val.value = rootpath + val.value; } return new(tree.URL)(val, this.rootpath); } }; })(require('../tree')); (function (tree) { tree.Value = function (value) { this.value = value; this.is = 'value'; }; tree.Value.prototype = { eval: function (env) { if (this.value.length === 1) { return this.value[0].eval(env); } else { return new(tree.Value)(this.value.map(function (v) { return v.eval(env); })); } }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS(env); }).join(env.compress ? ',' : ', '); } }; })(require('../tree')); (function (tree) { tree.Variable = function (name, index, file) { this.name = name, this.index = index, this.file = file }; tree.Variable.prototype = { eval: function (env) { var variable, v, name = this.name; if (name.indexOf('@@') == 0) { name = '@' + new(tree.Variable)(name.slice(1)).eval(env).value; } if (this.evaluating) { throw { type: 'Name', message: "Recursive variable definition for " + name, filename: this.file, index: this.index }; } this.evaluating = true; if (variable = tree.find(env.frames, function (frame) { if (v = frame.variable(name)) { return v.value.eval(env); } })) { this.evaluating = false; return variable; } else { throw { type: 'Name', message: "variable " + name + " is undefined", filename: this.file, index: this.index }; } } }; })(require('../tree')); (function (tree) { tree.debugInfo = function(env, ctx) { var result=""; if (env.dumpLineNumbers && !env.compress) { switch(env.dumpLineNumbers) { case 'comments': result = tree.debugInfo.asComment(ctx); break; case 'mediaquery': result = tree.debugInfo.asMediaQuery(ctx); break; case 'all': result = tree.debugInfo.asComment(ctx)+tree.debugInfo.asMediaQuery(ctx); break; } } return result; }; tree.debugInfo.asComment = function(ctx) { return '/* line ' + ctx.debugInfo.lineNumber + ', ' + ctx.debugInfo.fileName + ' */\n'; }; tree.debugInfo.asMediaQuery = function(ctx) { return '@media -sass-debug-info{filename{font-family:' + ('file://' + ctx.debugInfo.fileName).replace(/[\/:.]/g, '\\$&') + '}line{font-family:\\00003' + ctx.debugInfo.lineNumber + '}}\n'; }; tree.find = function (obj, fun) { for (var i = 0, r; i < obj.length; i++) { if (r = fun.call(obj, obj[i])) { return r } } return null; }; tree.jsify = function (obj) { if (Array.isArray(obj.value) && (obj.value.length > 1)) { return '[' + obj.value.map(function (v) { return v.toCSS(false) }).join(', ') + ']'; } else { return obj.toCSS(false); } }; })(require('./tree')); var name; function loadStyleSheet(sheet, callback, reload, remaining) { var endOfPath = Math.max(name.lastIndexOf('/'), name.lastIndexOf('\\')), sheetName = name.slice(0, endOfPath + 1) + sheet.href, contents = sheet.contents || {}, input = readFile(sheetName); contents[sheetName] = input; var parser = new less.Parser({ paths: [sheet.href.replace(/[\w\.-]+$/, '')], contents: contents }); parser.parse(input, function (e, root) { if (e) { return error(e, sheetName); } try { callback(e, root, input, sheet, { local: false, lastModified: 0, remaining: remaining }, sheetName); } catch(e) { error(e, sheetName); } }); } function writeFile(filename, content) { var fstream = new java.io.FileWriter(filename); var out = new java.io.BufferedWriter(fstream); out.write(content); out.close(); } // Command line integration via Rhino (function (args) { var output, compress = false, i; for(i = 0; i < args.length; i++) { switch(args[i]) { case "-x": compress = true; break; default: if (!name) { name = args[i]; } else if (!output) { output = args[i]; } else { print("unrecognised parameters"); print("input_file [output_file] [-x]"); } } } if (!name) { print('No files present in the fileset; Check your pattern match in build.xml'); quit(1); } path = name.split("/");path.pop();path=path.join("/") var input = readFile(name); if (!input) { print('lesscss: couldn\'t open file ' + name); quit(1); } var result; try { var parser = new less.Parser(); parser.parse(input, function (e, root) { if (e) { error(e, name); quit(1); } else { result = root.toCSS({compress: compress || false}); if (output) { writeFile(output, result); print("Written to " + output); } else { print(result); } quit(0); } }); } catch(e) { error(e, name); quit(1); } print("done"); }(arguments)); function error(e, filename) { var content = "Error : " + filename + "\n"; filename = e.filename || filename; if (e.message) { content += e.message + "\n"; } var errorline = function (e, i, classname) { if (e.extract[i]) { content += String(parseInt(e.line) + (i - 1)) + ":" + e.extract[i] + "\n"; } }; if (e.stack) { content += e.stack; } else if (e.extract) { content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':\n'; errorline(e, 0); errorline(e, 1); errorline(e, 2); } print(content); }less.js-1.4.2/lib/000077500000000000000000000000001217256642200136545ustar00rootroot00000000000000less.js-1.4.2/lib/less/000077500000000000000000000000001217256642200146225ustar00rootroot00000000000000less.js-1.4.2/lib/less/browser.js000066400000000000000000000445121217256642200166510ustar00rootroot00000000000000// // browser.js - client-side engine // var isFileProtocol = /^(file|chrome(-extension)?|resource|qrc|app):/.test(location.protocol); less.env = less.env || (location.hostname == '127.0.0.1' || location.hostname == '0.0.0.0' || location.hostname == 'localhost' || location.port.length > 0 || isFileProtocol ? 'development' : 'production'); // Load styles asynchronously (default: false) // // This is set to `false` by default, so that the body // doesn't start loading before the stylesheets are parsed. // Setting this to `true` can result in flickering. // less.async = less.async || false; less.fileAsync = less.fileAsync || false; // Interval between watch polls less.poll = less.poll || (isFileProtocol ? 1000 : 1500); //Setup user functions if (less.functions) { for(var func in less.functions) { less.tree.functions[func] = less.functions[func]; } } var dumpLineNumbers = /!dumpLineNumbers:(comments|mediaquery|all)/.exec(location.hash); if (dumpLineNumbers) { less.dumpLineNumbers = dumpLineNumbers[1]; } // // Watch mode // less.watch = function () { if (!less.watchMode ){ less.env = 'development'; initRunningMode(); } return this.watchMode = true }; less.unwatch = function () {clearInterval(less.watchTimer); return this.watchMode = false; }; function initRunningMode(){ if (less.env === 'development') { less.optimization = 0; less.watchTimer = setInterval(function () { if (less.watchMode) { loadStyleSheets(function (e, root, _, sheet, env) { if (e) { error(e, sheet.href); } else if (root) { createCSS(root.toCSS(less), sheet, env.lastModified); } }); } }, less.poll); } else { less.optimization = 3; } } if (/!watch/.test(location.hash)) { less.watch(); } var cache = null; if (less.env != 'development') { try { cache = (typeof(window.localStorage) === 'undefined') ? null : window.localStorage; } catch (_) {} } // // Get all tags with the 'rel' attribute set to "stylesheet/less" // var links = document.getElementsByTagName('link'); var typePattern = /^text\/(x-)?less$/; less.sheets = []; for (var i = 0; i < links.length; i++) { if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) && (links[i].type.match(typePattern)))) { less.sheets.push(links[i]); } } // // With this function, it's possible to alter variables and re-render // CSS without reloading less-files // var session_cache = ''; less.modifyVars = function(record) { var str = session_cache; for (var name in record) { str += ((name.slice(0,1) === '@')? '' : '@') + name +': '+ ((record[name].slice(-1) === ';')? record[name] : record[name] +';'); } new(less.Parser)(new less.tree.parseEnv(less)).parse(str, function (e, root) { if (e) { error(e, "session_cache"); } else { createCSS(root.toCSS(less), less.sheets[less.sheets.length - 1]); } }); }; less.refresh = function (reload) { var startTime, endTime; startTime = endTime = new(Date); loadStyleSheets(function (e, root, _, sheet, env) { if (e) { return error(e, sheet.href); } if (env.local) { log("loading " + sheet.href + " from cache."); } else { log("parsed " + sheet.href + " successfully."); createCSS(root.toCSS(less), sheet, env.lastModified); } log("css for " + sheet.href + " generated in " + (new(Date) - endTime) + 'ms'); (env.remaining === 0) && log("css generated in " + (new(Date) - startTime) + 'ms'); endTime = new(Date); }, reload); loadStyles(); }; less.refreshStyles = loadStyles; less.refresh(less.env === 'development'); function loadStyles() { var styles = document.getElementsByTagName('style'); for (var i = 0; i < styles.length; i++) { if (styles[i].type.match(typePattern)) { var env = new less.tree.parseEnv(less); env.filename = document.location.href.replace(/#.*$/, ''); new(less.Parser)(env).parse(styles[i].innerHTML || '', function (e, cssAST) { if (e) { return error(e, "inline"); } var css = cssAST.toCSS(less); var style = styles[i]; style.type = 'text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.innerHTML = css; } }); } } } function loadStyleSheets(callback, reload) { for (var i = 0; i < less.sheets.length; i++) { loadStyleSheet(less.sheets[i], callback, reload, less.sheets.length - (i + 1)); } } function pathDiff(url, baseUrl) { // diff between two paths to create a relative path var urlParts = extractUrlParts(url), baseUrlParts = extractUrlParts(baseUrl), i, max, urlDirectories, baseUrlDirectories, diff = ""; if (urlParts.hostPart !== baseUrlParts.hostPart) { return ""; } max = Math.max(baseUrlParts.directories.length, urlParts.directories.length); for(i = 0; i < max; i++) { if (baseUrlParts.directories[i] !== urlParts.directories[i]) { break; } } baseUrlDirectories = baseUrlParts.directories.slice(i); urlDirectories = urlParts.directories.slice(i); for(i = 0; i < baseUrlDirectories.length-1; i++) { diff += "../"; } for(i = 0; i < urlDirectories.length-1; i++) { diff += urlDirectories[i] + "/"; } return diff; } function extractUrlParts(url, baseUrl) { // urlParts[1] = protocol&hostname || / // urlParts[2] = / if path relative to host base // urlParts[3] = directories // urlParts[4] = filename // urlParts[5] = parameters var urlPartsRegex = /^((?:[a-z-]+:)?\/+?(?:[^\/\?#]*\/)|([\/\\]))?((?:[^\/\\\?#]*[\/\\])*)([^\/\\\?#]*)([#\?].*)?$/i, urlParts = url.match(urlPartsRegex), returner = {}, directories = [], i, baseUrlParts; if (!urlParts) { throw new Error("Could not parse sheet href - '"+url+"'"); } // Stylesheets in IE don't always return the full path if (!urlParts[1] || urlParts[2]) { baseUrlParts = baseUrl.match(urlPartsRegex); if (!baseUrlParts) { throw new Error("Could not parse page url - '"+baseUrl+"'"); } urlParts[1] = urlParts[1] || baseUrlParts[1] || ""; if (!urlParts[2]) { urlParts[3] = baseUrlParts[3] + urlParts[3]; } } if (urlParts[3]) { directories = urlParts[3].replace(/\\/g, "/").split("/"); // extract out . before .. so .. doesn't absorb a non-directory for(i = 0; i < directories.length; i++) { if (directories[i] === ".") { directories.splice(i, 1); i -= 1; } } for(i = 0; i < directories.length; i++) { if (directories[i] === ".." && i > 0) { directories.splice(i-1, 2); i -= 2; } } } returner.hostPart = urlParts[1]; returner.directories = directories; returner.path = urlParts[1] + directories.join("/"); returner.fileUrl = returner.path + (urlParts[4] || ""); returner.url = returner.fileUrl + (urlParts[5] || ""); return returner; } function loadStyleSheet(sheet, callback, reload, remaining) { // sheet may be set to the stylesheet for the initial load or a collection of properties including // some env variables for imports var hrefParts = extractUrlParts(sheet.href, window.location.href); var href = hrefParts.url; var css = cache && cache.getItem(href); var timestamp = cache && cache.getItem(href + ':timestamp'); var styles = { css: css, timestamp: timestamp }; var env; var newFileInfo = { relativeUrls: less.relativeUrls, currentDirectory: hrefParts.path, filename: href }; if (sheet instanceof less.tree.parseEnv) { env = new less.tree.parseEnv(sheet); newFileInfo.entryPath = env.currentFileInfo.entryPath; newFileInfo.rootpath = env.currentFileInfo.rootpath; newFileInfo.rootFilename = env.currentFileInfo.rootFilename; } else { env = new less.tree.parseEnv(less); env.mime = sheet.type; newFileInfo.entryPath = hrefParts.path; newFileInfo.rootpath = less.rootpath || hrefParts.path; newFileInfo.rootFilename = href; } if (env.relativeUrls) { //todo - this relies on option being set on less object rather than being passed in as an option // - need an originalRootpath if (less.rootpath) { newFileInfo.rootpath = extractUrlParts(less.rootpath + pathDiff(hrefParts.path, newFileInfo.entryPath)).path; } else { newFileInfo.rootpath = hrefParts.path; } } xhr(href, sheet.type, function (data, lastModified) { // Store data this session session_cache += data.replace(/@import .+?;/ig, ''); if (!reload && styles && lastModified && (new(Date)(lastModified).valueOf() === new(Date)(styles.timestamp).valueOf())) { // Use local copy createCSS(styles.css, sheet); callback(null, null, data, sheet, { local: true, remaining: remaining }, href); } else { // Use remote copy (re-parse) try { env.contents[href] = data; // Updating content cache env.paths = [hrefParts.path]; env.currentFileInfo = newFileInfo; new(less.Parser)(env).parse(data, function (e, root) { if (e) { return callback(e, null, null, sheet); } try { callback(e, root, data, sheet, { local: false, lastModified: lastModified, remaining: remaining }, href); //TODO - there must be a better way? A generic less-to-css function that can both call error //and removeNode where appropriate //should also add tests if (env.currentFileInfo.rootFilename === href) { removeNode(document.getElementById('less-error-message:' + extractId(href))); } } catch (e) { callback(e, null, null, sheet); } }); } catch (e) { callback(e, null, null, sheet); } } }, function (status, url) { callback({ type: 'File', message: "'" + url + "' wasn't found (" + status + ")" }, null, null, sheet); }); } function extractId(href) { return href.replace(/^[a-z-]+:\/+?[^\/]+/, '' ) // Remove protocol & domain .replace(/^\//, '' ) // Remove root / .replace(/\.[a-zA-Z]+$/, '' ) // Remove simple extension .replace(/[^\.\w-]+/g, '-') // Replace illegal characters .replace(/\./g, ':'); // Replace dots with colons(for valid id) } function createCSS(styles, sheet, lastModified) { // Strip the query-string var href = sheet.href || ''; // If there is no title set, use the filename, minus the extension var id = 'less:' + (sheet.title || extractId(href)); // If this has already been inserted into the DOM, we may need to replace it var oldCss = document.getElementById(id); var keepOldCss = false; // Create a new stylesheet node for insertion or (if necessary) replacement var css = document.createElement('style'); css.setAttribute('type', 'text/css'); if (sheet.media) { css.setAttribute('media', sheet.media); } css.id = id; if (css.styleSheet) { // IE try { css.styleSheet.cssText = styles; } catch (e) { throw new(Error)("Couldn't reassign styleSheet.cssText."); } } else { css.appendChild(document.createTextNode(styles)); // If new contents match contents of oldCss, don't replace oldCss keepOldCss = (oldCss !== null && oldCss.childNodes.length > 0 && css.childNodes.length > 0 && oldCss.firstChild.nodeValue === css.firstChild.nodeValue); } var head = document.getElementsByTagName('head')[0]; // If there is no oldCss, just append; otherwise, only append if we need // to replace oldCss with an updated stylesheet if (oldCss == null || keepOldCss === false) { var nextEl = sheet && sheet.nextSibling || null; (nextEl || document.getElementsByTagName('head')[0]).parentNode.insertBefore(css, nextEl); } if (oldCss && keepOldCss === false) { head.removeChild(oldCss); } // Don't update the local store if the file wasn't modified if (lastModified && cache) { log('saving ' + href + ' to cache.'); try { cache.setItem(href, styles); cache.setItem(href + ':timestamp', lastModified); } catch(e) { //TODO - could do with adding more robust error handling log('failed to save'); } } } function xhr(url, type, callback, errback) { var xhr = getXMLHttpRequest(); var async = isFileProtocol ? less.fileAsync : less.async; if (typeof(xhr.overrideMimeType) === 'function') { xhr.overrideMimeType('text/css'); } xhr.open('GET', url, async); xhr.setRequestHeader('Accept', type || 'text/x-less, text/css; q=0.9, */*; q=0.5'); xhr.send(null); if (isFileProtocol && !less.fileAsync) { if (xhr.status === 0 || (xhr.status >= 200 && xhr.status < 300)) { callback(xhr.responseText); } else { errback(xhr.status, url); } } else if (async) { xhr.onreadystatechange = function () { if (xhr.readyState == 4) { handleResponse(xhr, callback, errback); } }; } else { handleResponse(xhr, callback, errback); } function handleResponse(xhr, callback, errback) { if (xhr.status >= 200 && xhr.status < 300) { callback(xhr.responseText, xhr.getResponseHeader("Last-Modified")); } else if (typeof(errback) === 'function') { errback(xhr.status, url); } } } function getXMLHttpRequest() { if (window.XMLHttpRequest) { return new(XMLHttpRequest); } else { try { return new(ActiveXObject)("MSXML2.XMLHTTP.3.0"); } catch (e) { log("browser doesn't support AJAX."); return null; } } } function removeNode(node) { return node && node.parentNode.removeChild(node); } function log(str) { if (less.env == 'development' && typeof(console) !== "undefined") { console.log('less: ' + str) } } function error(e, rootHref) { var id = 'less-error-message:' + extractId(rootHref || ""); var template = '
  • {content}
  • '; var elem = document.createElement('div'), timer, content, error = []; var filename = e.filename || rootHref; var filenameNoPath = filename.match(/([^\/]+(\?.*)?)$/)[1]; elem.id = id; elem.className = "less-error-message"; content = '

    ' + (e.type || "Syntax") + "Error: " + (e.message || 'There is an error in your .less file') + '

    ' + '

    in ' + filenameNoPath + " "; var errorline = function (e, i, classname) { if (e.extract[i] != undefined) { error.push(template.replace(/\{line\}/, (parseInt(e.line) || 0) + (i - 1)) .replace(/\{class\}/, classname) .replace(/\{content\}/, e.extract[i])); } }; if (e.extract) { errorline(e, 0, ''); errorline(e, 1, 'line'); errorline(e, 2, ''); content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':

    ' + '
      ' + error.join('') + '
    '; } else if (e.stack) { content += '
    ' + e.stack.split('\n').slice(1).join('
    '); } elem.innerHTML = content; // CSS for error messages createCSS([ '.less-error-message ul, .less-error-message li {', 'list-style-type: none;', 'margin-right: 15px;', 'padding: 4px 0;', 'margin: 0;', '}', '.less-error-message label {', 'font-size: 12px;', 'margin-right: 15px;', 'padding: 4px 0;', 'color: #cc7777;', '}', '.less-error-message pre {', 'color: #dd6666;', 'padding: 4px 0;', 'margin: 0;', 'display: inline-block;', '}', '.less-error-message pre.line {', 'color: #ff0000;', '}', '.less-error-message h3 {', 'font-size: 20px;', 'font-weight: bold;', 'padding: 15px 0 5px 0;', 'margin: 0;', '}', '.less-error-message a {', 'color: #10a', '}', '.less-error-message .error {', 'color: red;', 'font-weight: bold;', 'padding-bottom: 2px;', 'border-bottom: 1px dashed red;', '}' ].join('\n'), { title: 'error-message' }); elem.style.cssText = [ "font-family: Arial, sans-serif", "border: 1px solid #e00", "background-color: #eee", "border-radius: 5px", "-webkit-border-radius: 5px", "-moz-border-radius: 5px", "color: #e00", "padding: 15px", "margin-bottom: 15px" ].join(';'); if (less.env == 'development') { timer = setInterval(function () { if (document.body) { if (document.getElementById(id)) { document.body.replaceChild(elem, document.getElementById(id)); } else { document.body.insertBefore(elem, document.body.firstChild); } clearInterval(timer); } }, 10); } } less.js-1.4.2/lib/less/colors.js000066400000000000000000000110551217256642200164630ustar00rootroot00000000000000(function (tree) { tree.colors = { 'aliceblue':'#f0f8ff', 'antiquewhite':'#faebd7', 'aqua':'#00ffff', 'aquamarine':'#7fffd4', 'azure':'#f0ffff', 'beige':'#f5f5dc', 'bisque':'#ffe4c4', 'black':'#000000', 'blanchedalmond':'#ffebcd', 'blue':'#0000ff', 'blueviolet':'#8a2be2', 'brown':'#a52a2a', 'burlywood':'#deb887', 'cadetblue':'#5f9ea0', 'chartreuse':'#7fff00', 'chocolate':'#d2691e', 'coral':'#ff7f50', 'cornflowerblue':'#6495ed', 'cornsilk':'#fff8dc', 'crimson':'#dc143c', 'cyan':'#00ffff', 'darkblue':'#00008b', 'darkcyan':'#008b8b', 'darkgoldenrod':'#b8860b', 'darkgray':'#a9a9a9', 'darkgrey':'#a9a9a9', 'darkgreen':'#006400', 'darkkhaki':'#bdb76b', 'darkmagenta':'#8b008b', 'darkolivegreen':'#556b2f', 'darkorange':'#ff8c00', 'darkorchid':'#9932cc', 'darkred':'#8b0000', 'darksalmon':'#e9967a', 'darkseagreen':'#8fbc8f', 'darkslateblue':'#483d8b', 'darkslategray':'#2f4f4f', 'darkslategrey':'#2f4f4f', 'darkturquoise':'#00ced1', 'darkviolet':'#9400d3', 'deeppink':'#ff1493', 'deepskyblue':'#00bfff', 'dimgray':'#696969', 'dimgrey':'#696969', 'dodgerblue':'#1e90ff', 'firebrick':'#b22222', 'floralwhite':'#fffaf0', 'forestgreen':'#228b22', 'fuchsia':'#ff00ff', 'gainsboro':'#dcdcdc', 'ghostwhite':'#f8f8ff', 'gold':'#ffd700', 'goldenrod':'#daa520', 'gray':'#808080', 'grey':'#808080', 'green':'#008000', 'greenyellow':'#adff2f', 'honeydew':'#f0fff0', 'hotpink':'#ff69b4', 'indianred':'#cd5c5c', 'indigo':'#4b0082', 'ivory':'#fffff0', 'khaki':'#f0e68c', 'lavender':'#e6e6fa', 'lavenderblush':'#fff0f5', 'lawngreen':'#7cfc00', 'lemonchiffon':'#fffacd', 'lightblue':'#add8e6', 'lightcoral':'#f08080', 'lightcyan':'#e0ffff', 'lightgoldenrodyellow':'#fafad2', 'lightgray':'#d3d3d3', 'lightgrey':'#d3d3d3', 'lightgreen':'#90ee90', 'lightpink':'#ffb6c1', 'lightsalmon':'#ffa07a', 'lightseagreen':'#20b2aa', 'lightskyblue':'#87cefa', 'lightslategray':'#778899', 'lightslategrey':'#778899', 'lightsteelblue':'#b0c4de', 'lightyellow':'#ffffe0', 'lime':'#00ff00', 'limegreen':'#32cd32', 'linen':'#faf0e6', 'magenta':'#ff00ff', 'maroon':'#800000', 'mediumaquamarine':'#66cdaa', 'mediumblue':'#0000cd', 'mediumorchid':'#ba55d3', 'mediumpurple':'#9370d8', 'mediumseagreen':'#3cb371', 'mediumslateblue':'#7b68ee', 'mediumspringgreen':'#00fa9a', 'mediumturquoise':'#48d1cc', 'mediumvioletred':'#c71585', 'midnightblue':'#191970', 'mintcream':'#f5fffa', 'mistyrose':'#ffe4e1', 'moccasin':'#ffe4b5', 'navajowhite':'#ffdead', 'navy':'#000080', 'oldlace':'#fdf5e6', 'olive':'#808000', 'olivedrab':'#6b8e23', 'orange':'#ffa500', 'orangered':'#ff4500', 'orchid':'#da70d6', 'palegoldenrod':'#eee8aa', 'palegreen':'#98fb98', 'paleturquoise':'#afeeee', 'palevioletred':'#d87093', 'papayawhip':'#ffefd5', 'peachpuff':'#ffdab9', 'peru':'#cd853f', 'pink':'#ffc0cb', 'plum':'#dda0dd', 'powderblue':'#b0e0e6', 'purple':'#800080', 'red':'#ff0000', 'rosybrown':'#bc8f8f', 'royalblue':'#4169e1', 'saddlebrown':'#8b4513', 'salmon':'#fa8072', 'sandybrown':'#f4a460', 'seagreen':'#2e8b57', 'seashell':'#fff5ee', 'sienna':'#a0522d', 'silver':'#c0c0c0', 'skyblue':'#87ceeb', 'slateblue':'#6a5acd', 'slategray':'#708090', 'slategrey':'#708090', 'snow':'#fffafa', 'springgreen':'#00ff7f', 'steelblue':'#4682b4', 'tan':'#d2b48c', 'teal':'#008080', 'thistle':'#d8bfd8', 'tomato':'#ff6347', // 'transparent':'rgba(0,0,0,0)', 'turquoise':'#40e0d0', 'violet':'#ee82ee', 'wheat':'#f5deb3', 'white':'#ffffff', 'whitesmoke':'#f5f5f5', 'yellow':'#ffff00', 'yellowgreen':'#9acd32' }; })(require('./tree')); less.js-1.4.2/lib/less/env.js000066400000000000000000000077651217256642200157670ustar00rootroot00000000000000(function (tree) { var parseCopyProperties = [ 'paths', // option - unmodified - paths to search for imports on 'optimization', // option - optimization level (for the chunker) 'files', // list of files that have been imported, used for import-once 'contents', // browser-only, contents of all the files 'relativeUrls', // option - whether to adjust URL's to be relative 'strictImports', // option - 'dumpLineNumbers', // option - whether to dump line numbers 'compress', // option - whether to compress 'processImports', // option - whether to process imports. if false then imports will not be imported 'syncImport', // option - whether to import synchronously 'mime', // browser only - mime type for sheet import 'currentFileInfo' // information about the current file - for error reporting and importing and making urls relative etc. ]; //currentFileInfo = { // 'relativeUrls' - option - whether to adjust URL's to be relative // 'filename' - full resolved filename of current file // 'rootpath' - path to append to normal URLs for this node // 'currentDirectory' - path to the current file, absolute // 'rootFilename' - filename of the base file // 'entryPath' = absolute path to the entry file tree.parseEnv = function(options) { copyFromOriginal(options, this, parseCopyProperties); if (!this.contents) { this.contents = {}; } if (!this.files) { this.files = {}; } if (!this.currentFileInfo) { var filename = (options && options.filename) || "input"; var entryPath = filename.replace(/[^\/\\]*$/, ""); if (options) { options.filename = null; } this.currentFileInfo = { filename: filename, relativeUrls: this.relativeUrls, rootpath: (options && options.rootpath) || "", currentDirectory: entryPath, entryPath: entryPath, rootFilename: filename }; } }; tree.parseEnv.prototype.toSheet = function (path) { var env = new tree.parseEnv(this); env.href = path; //env.title = path; env.type = this.mime; return env; }; var evalCopyProperties = [ 'silent', // whether to swallow errors and warnings 'verbose', // whether to log more activity 'compress', // whether to compress 'yuicompress', // whether to compress with the outside tool yui compressor 'ieCompat', // whether to enforce IE compatibility (IE8 data-uri) 'strictMath', // whether math has to be within parenthesis 'strictUnits' // whether units need to evaluate correctly ]; tree.evalEnv = function(options, frames) { copyFromOriginal(options, this, evalCopyProperties); this.frames = frames || []; }; tree.evalEnv.prototype.inParenthesis = function () { if (!this.parensStack) { this.parensStack = []; } this.parensStack.push(true); }; tree.evalEnv.prototype.outOfParenthesis = function () { this.parensStack.pop(); }; tree.evalEnv.prototype.isMathOn = function () { return this.strictMath ? (this.parensStack && this.parensStack.length) : true; }; tree.evalEnv.prototype.isPathRelative = function (path) { return !/^(?:[a-z-]+:|\/)/.test(path); }; //todo - do the same for the toCSS env //tree.toCSSEnv = function (options) { //}; var copyFromOriginal = function(original, destination, propertiesToCopy) { if (!original) { return; } for(var i = 0; i < propertiesToCopy.length; i++) { if (original.hasOwnProperty(propertiesToCopy[i])) { destination[propertiesToCopy[i]] = original[propertiesToCopy[i]]; } } } })(require('./tree'));less.js-1.4.2/lib/less/extend-visitor.js000066400000000000000000000465321217256642200201560ustar00rootroot00000000000000(function (tree) { tree.extendFinderVisitor = function() { this._visitor = new tree.visitor(this); this.contexts = []; this.allExtendsStack = [[]]; }; tree.extendFinderVisitor.prototype = { run: function (root) { root = this._visitor.visit(root); root.allExtends = this.allExtendsStack[0]; return root; }, visitRule: function (ruleNode, visitArgs) { visitArgs.visitDeeper = false; }, visitMixinDefinition: function (mixinDefinitionNode, visitArgs) { visitArgs.visitDeeper = false; }, visitRuleset: function (rulesetNode, visitArgs) { if (rulesetNode.root) { return; } var i, j, extend, allSelectorsExtendList = [], extendList; // get &:extend(.a); rules which apply to all selectors in this ruleset for(i = 0; i < rulesetNode.rules.length; i++) { if (rulesetNode.rules[i] instanceof tree.Extend) { allSelectorsExtendList.push(rulesetNode.rules[i]); } } // now find every selector and apply the extends that apply to all extends // and the ones which apply to an individual extend for(i = 0; i < rulesetNode.paths.length; i++) { var selectorPath = rulesetNode.paths[i], selector = selectorPath[selectorPath.length-1]; extendList = selector.extendList.slice(0).concat(allSelectorsExtendList).map(function(allSelectorsExtend) { return allSelectorsExtend.clone(); }); for(j = 0; j < extendList.length; j++) { this.foundExtends = true; extend = extendList[j]; extend.findSelfSelectors(selectorPath); extend.ruleset = rulesetNode; if (j === 0) { extend.firstExtendOnThisSelectorPath = true; } this.allExtendsStack[this.allExtendsStack.length-1].push(extend); } } this.contexts.push(rulesetNode.selectors); }, visitRulesetOut: function (rulesetNode) { if (!rulesetNode.root) { this.contexts.length = this.contexts.length - 1; } }, visitMedia: function (mediaNode, visitArgs) { mediaNode.allExtends = []; this.allExtendsStack.push(mediaNode.allExtends); }, visitMediaOut: function (mediaNode) { this.allExtendsStack.length = this.allExtendsStack.length - 1; }, visitDirective: function (directiveNode, visitArgs) { directiveNode.allExtends = []; this.allExtendsStack.push(directiveNode.allExtends); }, visitDirectiveOut: function (directiveNode) { this.allExtendsStack.length = this.allExtendsStack.length - 1; } }; tree.processExtendsVisitor = function() { this._visitor = new tree.visitor(this); }; tree.processExtendsVisitor.prototype = { run: function(root) { var extendFinder = new tree.extendFinderVisitor(); extendFinder.run(root); if (!extendFinder.foundExtends) { return root; } root.allExtends = root.allExtends.concat(this.doExtendChaining(root.allExtends, root.allExtends)); this.allExtendsStack = [root.allExtends]; return this._visitor.visit(root); }, doExtendChaining: function (extendsList, extendsListTarget, iterationCount) { // // chaining is different from normal extension.. if we extend an extend then we are not just copying, altering and pasting // the selector we would do normally, but we are also adding an extend with the same target selector // this means this new extend can then go and alter other extends // // this method deals with all the chaining work - without it, extend is flat and doesn't work on other extend selectors // this is also the most expensive.. and a match on one selector can cause an extension of a selector we had already processed if // we look at each selector at a time, as is done in visitRuleset var extendIndex, targetExtendIndex, matches, extendsToAdd = [], newSelector, extendVisitor = this, selectorPath, extend, targetExtend, newExtend; iterationCount = iterationCount || 0; //loop through comparing every extend with every target extend. // a target extend is the one on the ruleset we are looking at copy/edit/pasting in place // e.g. .a:extend(.b) {} and .b:extend(.c) {} then the first extend extends the second one // and the second is the target. // the seperation into two lists allows us to process a subset of chains with a bigger set, as is the // case when processing media queries for(extendIndex = 0; extendIndex < extendsList.length; extendIndex++){ for(targetExtendIndex = 0; targetExtendIndex < extendsListTarget.length; targetExtendIndex++){ extend = extendsList[extendIndex]; targetExtend = extendsListTarget[targetExtendIndex]; // look for circular references if (this.inInheritanceChain(targetExtend, extend)) { continue; } // find a match in the target extends self selector (the bit before :extend) selectorPath = [targetExtend.selfSelectors[0]]; matches = extendVisitor.findMatch(extend, selectorPath); if (matches.length) { // we found a match, so for each self selector.. extend.selfSelectors.forEach(function(selfSelector) { // process the extend as usual newSelector = extendVisitor.extendSelector(matches, selectorPath, selfSelector); // but now we create a new extend from it newExtend = new(tree.Extend)(targetExtend.selector, targetExtend.option, 0); newExtend.selfSelectors = newSelector; // add the extend onto the list of extends for that selector newSelector[newSelector.length-1].extendList = [newExtend]; // record that we need to add it. extendsToAdd.push(newExtend); newExtend.ruleset = targetExtend.ruleset; //remember its parents for circular references newExtend.parents = [targetExtend, extend]; // only process the selector once.. if we have :extend(.a,.b) then multiple // extends will look at the same selector path, so when extending // we know that any others will be duplicates in terms of what is added to the css if (targetExtend.firstExtendOnThisSelectorPath) { newExtend.firstExtendOnThisSelectorPath = true; targetExtend.ruleset.paths.push(newSelector); } }); } } } if (extendsToAdd.length) { // try to detect circular references to stop a stack overflow. // may no longer be needed. this.extendChainCount++; if (iterationCount > 100) { var selectorOne = "{unable to calculate}"; var selectorTwo = "{unable to calculate}"; try { selectorOne = extendsToAdd[0].selfSelectors[0].toCSS(); selectorTwo = extendsToAdd[0].selector.toCSS(); } catch(e) {} throw {message: "extend circular reference detected. One of the circular extends is currently:"+selectorOne+":extend(" + selectorTwo+")"}; } // now process the new extends on the existing rules so that we can handle a extending b extending c ectending d extending e... return extendsToAdd.concat(extendVisitor.doExtendChaining(extendsToAdd, extendsListTarget, iterationCount+1)); } else { return extendsToAdd; } }, inInheritanceChain: function (possibleParent, possibleChild) { if (possibleParent === possibleChild) { return true; } if (possibleChild.parents) { if (this.inInheritanceChain(possibleParent, possibleChild.parents[0])) { return true; } if (this.inInheritanceChain(possibleParent, possibleChild.parents[1])) { return true; } } return false; }, visitRule: function (ruleNode, visitArgs) { visitArgs.visitDeeper = false; }, visitMixinDefinition: function (mixinDefinitionNode, visitArgs) { visitArgs.visitDeeper = false; }, visitSelector: function (selectorNode, visitArgs) { visitArgs.visitDeeper = false; }, visitRuleset: function (rulesetNode, visitArgs) { if (rulesetNode.root) { return; } var matches, pathIndex, extendIndex, allExtends = this.allExtendsStack[this.allExtendsStack.length-1], selectorsToAdd = [], extendVisitor = this, selectorPath; // look at each selector path in the ruleset, find any extend matches and then copy, find and replace for(extendIndex = 0; extendIndex < allExtends.length; extendIndex++) { for(pathIndex = 0; pathIndex < rulesetNode.paths.length; pathIndex++) { selectorPath = rulesetNode.paths[pathIndex]; // extending extends happens initially, before the main pass if (selectorPath[selectorPath.length-1].extendList.length) { continue; } matches = this.findMatch(allExtends[extendIndex], selectorPath); if (matches.length) { allExtends[extendIndex].selfSelectors.forEach(function(selfSelector) { selectorsToAdd.push(extendVisitor.extendSelector(matches, selectorPath, selfSelector)); }); } } } rulesetNode.paths = rulesetNode.paths.concat(selectorsToAdd); }, findMatch: function (extend, haystackSelectorPath) { // // look through the haystack selector path to try and find the needle - extend.selector // returns an array of selector matches that can then be replaced // var haystackSelectorIndex, hackstackSelector, hackstackElementIndex, haystackElement, targetCombinator, i, extendVisitor = this, needleElements = extend.selector.elements, potentialMatches = [], potentialMatch, matches = []; // loop through the haystack elements for(haystackSelectorIndex = 0; haystackSelectorIndex < haystackSelectorPath.length; haystackSelectorIndex++) { hackstackSelector = haystackSelectorPath[haystackSelectorIndex]; for(hackstackElementIndex = 0; hackstackElementIndex < hackstackSelector.elements.length; hackstackElementIndex++) { haystackElement = hackstackSelector.elements[hackstackElementIndex]; // if we allow elements before our match we can add a potential match every time. otherwise only at the first element. if (extend.allowBefore || (haystackSelectorIndex == 0 && hackstackElementIndex == 0)) { potentialMatches.push({pathIndex: haystackSelectorIndex, index: hackstackElementIndex, matched: 0, initialCombinator: haystackElement.combinator}); } for(i = 0; i < potentialMatches.length; i++) { potentialMatch = potentialMatches[i]; // selectors add " " onto the first element. When we use & it joins the selectors together, but if we don't // then each selector in haystackSelectorPath has a space before it added in the toCSS phase. so we need to work out // what the resulting combinator will be targetCombinator = haystackElement.combinator.value; if (targetCombinator == '' && hackstackElementIndex === 0) { targetCombinator = ' '; } // if we don't match, null our match to indicate failure if (!extendVisitor.isElementValuesEqual(needleElements[potentialMatch.matched].value, haystackElement.value) || (potentialMatch.matched > 0 && needleElements[potentialMatch.matched].combinator.value !== targetCombinator)) { potentialMatch = null; } else { potentialMatch.matched++; } // if we are still valid and have finished, test whether we have elements after and whether these are allowed if (potentialMatch) { potentialMatch.finished = potentialMatch.matched === needleElements.length; if (potentialMatch.finished && (!extend.allowAfter && (hackstackElementIndex+1 < hackstackSelector.elements.length || haystackSelectorIndex+1 < haystackSelectorPath.length))) { potentialMatch = null; } } // if null we remove, if not, we are still valid, so either push as a valid match or continue if (potentialMatch) { if (potentialMatch.finished) { potentialMatch.length = needleElements.length; potentialMatch.endPathIndex = haystackSelectorIndex; potentialMatch.endPathElementIndex = hackstackElementIndex + 1; // index after end of match potentialMatches.length = 0; // we don't allow matches to overlap, so start matching again matches.push(potentialMatch); } } else { potentialMatches.splice(i, 1); i--; } } } } return matches; }, isElementValuesEqual: function(elementValue1, elementValue2) { if (typeof elementValue1 === "string" || typeof elementValue2 === "string") { return elementValue1 === elementValue2; } if (elementValue1 instanceof tree.Attribute) { if (elementValue1.op !== elementValue2.op || elementValue1.key !== elementValue2.key) { return false; } if (!elementValue1.value || !elementValue2.value) { if (elementValue1.value || elementValue2.value) { return false; } return true; } elementValue1 = elementValue1.value.value || elementValue1.value; elementValue2 = elementValue2.value.value || elementValue2.value; return elementValue1 === elementValue2; } return false; }, extendSelector:function (matches, selectorPath, replacementSelector) { //for a set of matches, replace each match with the replacement selector var currentSelectorPathIndex = 0, currentSelectorPathElementIndex = 0, path = [], matchIndex, selector, firstElement, match; for (matchIndex = 0; matchIndex < matches.length; matchIndex++) { match = matches[matchIndex]; selector = selectorPath[match.pathIndex]; firstElement = new tree.Element( match.initialCombinator, replacementSelector.elements[0].value, replacementSelector.elements[0].index ); if (match.pathIndex > currentSelectorPathIndex && currentSelectorPathElementIndex > 0) { path[path.length - 1].elements = path[path.length - 1].elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex)); currentSelectorPathElementIndex = 0; currentSelectorPathIndex++; } path = path.concat(selectorPath.slice(currentSelectorPathIndex, match.pathIndex)); path.push(new tree.Selector( selector.elements .slice(currentSelectorPathElementIndex, match.index) .concat([firstElement]) .concat(replacementSelector.elements.slice(1)) )); currentSelectorPathIndex = match.endPathIndex; currentSelectorPathElementIndex = match.endPathElementIndex; if (currentSelectorPathElementIndex >= selector.elements.length) { currentSelectorPathElementIndex = 0; currentSelectorPathIndex++; } } if (currentSelectorPathIndex < selectorPath.length && currentSelectorPathElementIndex > 0) { path[path.length - 1].elements = path[path.length - 1].elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex)); currentSelectorPathElementIndex = 0; currentSelectorPathIndex++; } path = path.concat(selectorPath.slice(currentSelectorPathIndex, selectorPath.length)); return path; }, visitRulesetOut: function (rulesetNode) { }, visitMedia: function (mediaNode, visitArgs) { var newAllExtends = mediaNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length-1]); newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, mediaNode.allExtends)); this.allExtendsStack.push(newAllExtends); }, visitMediaOut: function (mediaNode) { this.allExtendsStack.length = this.allExtendsStack.length - 1; }, visitDirective: function (directiveNode, visitArgs) { var newAllExtends = directiveNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length-1]); newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, directiveNode.allExtends)); this.allExtendsStack.push(newAllExtends); }, visitDirectiveOut: function (directiveNode) { this.allExtendsStack.length = this.allExtendsStack.length - 1; } }; })(require('./tree'));less.js-1.4.2/lib/less/functions.js000066400000000000000000000437001217256642200171740ustar00rootroot00000000000000(function (tree) { tree.functions = { rgb: function (r, g, b) { return this.rgba(r, g, b, 1.0); }, rgba: function (r, g, b, a) { var rgb = [r, g, b].map(function (c) { return scaled(c, 256); }); a = number(a); return new(tree.Color)(rgb, a); }, hsl: function (h, s, l) { return this.hsla(h, s, l, 1.0); }, hsla: function (h, s, l, a) { h = (number(h) % 360) / 360; s = clamp(number(s)); l = clamp(number(l)); a = clamp(number(a)); var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s; var m1 = l * 2 - m2; return this.rgba(hue(h + 1/3) * 255, hue(h) * 255, hue(h - 1/3) * 255, a); function hue(h) { h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h); if (h * 6 < 1) return m1 + (m2 - m1) * h * 6; else if (h * 2 < 1) return m2; else if (h * 3 < 2) return m1 + (m2 - m1) * (2/3 - h) * 6; else return m1; } }, hsv: function(h, s, v) { return this.hsva(h, s, v, 1.0); }, hsva: function(h, s, v, a) { h = ((number(h) % 360) / 360) * 360; s = number(s); v = number(v); a = number(a); var i, f; i = Math.floor((h / 60) % 6); f = (h / 60) - i; var vs = [v, v * (1 - s), v * (1 - f * s), v * (1 - (1 - f) * s)]; var perm = [[0, 3, 1], [2, 0, 1], [1, 0, 3], [1, 2, 0], [3, 1, 0], [0, 1, 2]]; return this.rgba(vs[perm[i][0]] * 255, vs[perm[i][1]] * 255, vs[perm[i][2]] * 255, a); }, hue: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().h)); }, saturation: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().s * 100), '%'); }, lightness: function (color) { return new(tree.Dimension)(Math.round(color.toHSL().l * 100), '%'); }, hsvhue: function(color) { return new(tree.Dimension)(Math.round(color.toHSV().h)); }, hsvsaturation: function (color) { return new(tree.Dimension)(Math.round(color.toHSV().s * 100), '%'); }, hsvvalue: function (color) { return new(tree.Dimension)(Math.round(color.toHSV().v * 100), '%'); }, red: function (color) { return new(tree.Dimension)(color.rgb[0]); }, green: function (color) { return new(tree.Dimension)(color.rgb[1]); }, blue: function (color) { return new(tree.Dimension)(color.rgb[2]); }, alpha: function (color) { return new(tree.Dimension)(color.toHSL().a); }, luma: function (color) { return new(tree.Dimension)(Math.round(color.luma() * color.alpha * 100), '%'); }, saturate: function (color, amount) { var hsl = color.toHSL(); hsl.s += amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, desaturate: function (color, amount) { var hsl = color.toHSL(); hsl.s -= amount.value / 100; hsl.s = clamp(hsl.s); return hsla(hsl); }, lighten: function (color, amount) { var hsl = color.toHSL(); hsl.l += amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, darken: function (color, amount) { var hsl = color.toHSL(); hsl.l -= amount.value / 100; hsl.l = clamp(hsl.l); return hsla(hsl); }, fadein: function (color, amount) { var hsl = color.toHSL(); hsl.a += amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, fadeout: function (color, amount) { var hsl = color.toHSL(); hsl.a -= amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, fade: function (color, amount) { var hsl = color.toHSL(); hsl.a = amount.value / 100; hsl.a = clamp(hsl.a); return hsla(hsl); }, spin: function (color, amount) { var hsl = color.toHSL(); var hue = (hsl.h + amount.value) % 360; hsl.h = hue < 0 ? 360 + hue : hue; return hsla(hsl); }, // // Copyright (c) 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein // http://sass-lang.com // mix: function (color1, color2, weight) { if (!weight) { weight = new(tree.Dimension)(50); } var p = weight.value / 100.0; var w = p * 2 - 1; var a = color1.toHSL().a - color2.toHSL().a; var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0; var w2 = 1 - w1; var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2, color1.rgb[1] * w1 + color2.rgb[1] * w2, color1.rgb[2] * w1 + color2.rgb[2] * w2]; var alpha = color1.alpha * p + color2.alpha * (1 - p); return new(tree.Color)(rgb, alpha); }, greyscale: function (color) { return this.desaturate(color, new(tree.Dimension)(100)); }, contrast: function (color, dark, light, threshold) { // filter: contrast(3.2); // should be kept as is, so check for color if (!color.rgb) { return null; } if (typeof light === 'undefined') { light = this.rgba(255, 255, 255, 1.0); } if (typeof dark === 'undefined') { dark = this.rgba(0, 0, 0, 1.0); } //Figure out which is actually light and dark! if (dark.luma() > light.luma()) { var t = light; light = dark; dark = t; } if (typeof threshold === 'undefined') { threshold = 0.43; } else { threshold = number(threshold); } if ((color.luma() * color.alpha) < threshold) { return light; } else { return dark; } }, e: function (str) { return new(tree.Anonymous)(str instanceof tree.JavaScript ? str.evaluated : str); }, escape: function (str) { return new(tree.Anonymous)(encodeURI(str.value).replace(/=/g, "%3D").replace(/:/g, "%3A").replace(/#/g, "%23").replace(/;/g, "%3B").replace(/\(/g, "%28").replace(/\)/g, "%29")); }, '%': function (quoted /* arg, arg, ...*/) { var args = Array.prototype.slice.call(arguments, 1), str = quoted.value; for (var i = 0; i < args.length; i++) { str = str.replace(/%[sda]/i, function(token) { var value = token.match(/s/i) ? args[i].value : args[i].toCSS(); return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value; }); } str = str.replace(/%%/g, '%'); return new(tree.Quoted)('"' + str + '"', str); }, unit: function (val, unit) { return new(tree.Dimension)(val.value, unit ? unit.toCSS() : ""); }, convert: function (val, unit) { return val.convertTo(unit.value); }, round: function (n, f) { var fraction = typeof(f) === "undefined" ? 0 : f.value; return this._math(function(num) { return num.toFixed(fraction); }, null, n); }, pi: function () { return new(tree.Dimension)(Math.PI); }, mod: function(a, b) { return new(tree.Dimension)(a.value % b.value, a.unit); }, pow: function(x, y) { if (typeof x === "number" && typeof y === "number") { x = new(tree.Dimension)(x); y = new(tree.Dimension)(y); } else if (!(x instanceof tree.Dimension) || !(y instanceof tree.Dimension)) { throw { type: "Argument", message: "arguments must be numbers" }; } return new(tree.Dimension)(Math.pow(x.value, y.value), x.unit); }, _math: function (fn, unit, n) { if (n instanceof tree.Dimension) { return new(tree.Dimension)(fn(parseFloat(n.value)), unit == null ? n.unit : unit); } else if (typeof(n) === 'number') { return fn(n); } else { throw { type: "Argument", message: "argument must be a number" }; } }, argb: function (color) { return new(tree.Anonymous)(color.toARGB()); }, percentage: function (n) { return new(tree.Dimension)(n.value * 100, '%'); }, color: function (n) { if (n instanceof tree.Quoted) { return new(tree.Color)(n.value.slice(1)); } else { throw { type: "Argument", message: "argument must be a string" }; } }, iscolor: function (n) { return this._isa(n, tree.Color); }, isnumber: function (n) { return this._isa(n, tree.Dimension); }, isstring: function (n) { return this._isa(n, tree.Quoted); }, iskeyword: function (n) { return this._isa(n, tree.Keyword); }, isurl: function (n) { return this._isa(n, tree.URL); }, ispixel: function (n) { return this.isunit(n, 'px'); }, ispercentage: function (n) { return this.isunit(n, '%'); }, isem: function (n) { return this.isunit(n, 'em'); }, isunit: function (n, unit) { return (n instanceof tree.Dimension) && n.unit.is(unit.value || unit) ? tree.True : tree.False; }, _isa: function (n, Type) { return (n instanceof Type) ? tree.True : tree.False; }, /* Blending modes */ multiply: function(color1, color2) { var r = color1.rgb[0] * color2.rgb[0] / 255; var g = color1.rgb[1] * color2.rgb[1] / 255; var b = color1.rgb[2] * color2.rgb[2] / 255; return this.rgb(r, g, b); }, screen: function(color1, color2) { var r = 255 - (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255; var g = 255 - (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255; var b = 255 - (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255; return this.rgb(r, g, b); }, overlay: function(color1, color2) { var r = color1.rgb[0] < 128 ? 2 * color1.rgb[0] * color2.rgb[0] / 255 : 255 - 2 * (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255; var g = color1.rgb[1] < 128 ? 2 * color1.rgb[1] * color2.rgb[1] / 255 : 255 - 2 * (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255; var b = color1.rgb[2] < 128 ? 2 * color1.rgb[2] * color2.rgb[2] / 255 : 255 - 2 * (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255; return this.rgb(r, g, b); }, softlight: function(color1, color2) { var t = color2.rgb[0] * color1.rgb[0] / 255; var r = t + color1.rgb[0] * (255 - (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255 - t) / 255; t = color2.rgb[1] * color1.rgb[1] / 255; var g = t + color1.rgb[1] * (255 - (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255 - t) / 255; t = color2.rgb[2] * color1.rgb[2] / 255; var b = t + color1.rgb[2] * (255 - (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255 - t) / 255; return this.rgb(r, g, b); }, hardlight: function(color1, color2) { var r = color2.rgb[0] < 128 ? 2 * color2.rgb[0] * color1.rgb[0] / 255 : 255 - 2 * (255 - color2.rgb[0]) * (255 - color1.rgb[0]) / 255; var g = color2.rgb[1] < 128 ? 2 * color2.rgb[1] * color1.rgb[1] / 255 : 255 - 2 * (255 - color2.rgb[1]) * (255 - color1.rgb[1]) / 255; var b = color2.rgb[2] < 128 ? 2 * color2.rgb[2] * color1.rgb[2] / 255 : 255 - 2 * (255 - color2.rgb[2]) * (255 - color1.rgb[2]) / 255; return this.rgb(r, g, b); }, difference: function(color1, color2) { var r = Math.abs(color1.rgb[0] - color2.rgb[0]); var g = Math.abs(color1.rgb[1] - color2.rgb[1]); var b = Math.abs(color1.rgb[2] - color2.rgb[2]); return this.rgb(r, g, b); }, exclusion: function(color1, color2) { var r = color1.rgb[0] + color2.rgb[0] * (255 - color1.rgb[0] - color1.rgb[0]) / 255; var g = color1.rgb[1] + color2.rgb[1] * (255 - color1.rgb[1] - color1.rgb[1]) / 255; var b = color1.rgb[2] + color2.rgb[2] * (255 - color1.rgb[2] - color1.rgb[2]) / 255; return this.rgb(r, g, b); }, average: function(color1, color2) { var r = (color1.rgb[0] + color2.rgb[0]) / 2; var g = (color1.rgb[1] + color2.rgb[1]) / 2; var b = (color1.rgb[2] + color2.rgb[2]) / 2; return this.rgb(r, g, b); }, negation: function(color1, color2) { var r = 255 - Math.abs(255 - color2.rgb[0] - color1.rgb[0]); var g = 255 - Math.abs(255 - color2.rgb[1] - color1.rgb[1]); var b = 255 - Math.abs(255 - color2.rgb[2] - color1.rgb[2]); return this.rgb(r, g, b); }, tint: function(color, amount) { return this.mix(this.rgb(255,255,255), color, amount); }, shade: function(color, amount) { return this.mix(this.rgb(0, 0, 0), color, amount); }, extract: function(values, index) { index = index.value - 1; // (1-based index) return values.value[index]; }, "data-uri": function(mimetypeNode, filePathNode) { if (typeof window !== 'undefined') { return new tree.URL(filePathNode || mimetypeNode, this.currentFileInfo).eval(this.env); } var mimetype = mimetypeNode.value; var filePath = (filePathNode && filePathNode.value); var fs = require("fs"), path = require("path"), useBase64 = false; if (arguments.length < 2) { filePath = mimetype; } if (this.env.isPathRelative(filePath)) { if (this.currentFileInfo.relativeUrls) { filePath = path.join(this.currentFileInfo.currentDirectory, filePath); } else { filePath = path.join(this.currentFileInfo.entryPath, filePath); } } // detect the mimetype if not given if (arguments.length < 2) { var mime; try { mime = require('mime'); } catch (ex) { mime = tree._mime; } mimetype = mime.lookup(filePath); // use base 64 unless it's an ASCII or UTF-8 format var charset = mime.charsets.lookup(mimetype); useBase64 = ['US-ASCII', 'UTF-8'].indexOf(charset) < 0; if (useBase64) mimetype += ';base64'; } else { useBase64 = /;base64$/.test(mimetype) } var buf = fs.readFileSync(filePath); // IE8 cannot handle a data-uri larger than 32KB. If this is exceeded // and the --ieCompat flag is enabled, return a normal url() instead. var DATA_URI_MAX_KB = 32, fileSizeInKB = parseInt((buf.length / 1024), 10); if (fileSizeInKB >= DATA_URI_MAX_KB) { if (this.env.ieCompat !== false) { if (!this.env.silent) { console.warn("Skipped data-uri embedding of %s because its size (%dKB) exceeds IE8-safe %dKB!", filePath, fileSizeInKB, DATA_URI_MAX_KB); } return new tree.URL(filePathNode || mimetypeNode, this.currentFileInfo).eval(this.env); } else if (!this.env.silent) { // if explicitly disabled (via --no-ie-compat on CLI, or env.ieCompat === false), merely warn console.warn("WARNING: Embedding %s (%dKB) exceeds IE8's data-uri size limit of %dKB!", filePath, fileSizeInKB, DATA_URI_MAX_KB); } } buf = useBase64 ? buf.toString('base64') : encodeURIComponent(buf); var uri = "'data:" + mimetype + ',' + buf + "'"; return new(tree.URL)(new(tree.Anonymous)(uri)); } }; // these static methods are used as a fallback when the optional 'mime' dependency is missing tree._mime = { // this map is intentionally incomplete // if you want more, install 'mime' dep _types: { '.htm' : 'text/html', '.html': 'text/html', '.gif' : 'image/gif', '.jpg' : 'image/jpeg', '.jpeg': 'image/jpeg', '.png' : 'image/png' }, lookup: function (filepath) { var ext = require('path').extname(filepath), type = tree._mime._types[ext]; if (type === undefined) { throw new Error('Optional dependency "mime" is required for ' + ext); } return type; }, charsets: { lookup: function (type) { // assumes all text types are UTF-8 return type && (/^text\//).test(type) ? 'UTF-8' : ''; } } }; var mathFunctions = [{name:"ceil"}, {name:"floor"}, {name: "sqrt"}, {name:"abs"}, {name:"tan", unit: ""}, {name:"sin", unit: ""}, {name:"cos", unit: ""}, {name:"atan", unit: "rad"}, {name:"asin", unit: "rad"}, {name:"acos", unit: "rad"}], createMathFunction = function(name, unit) { return function(n) { if (unit != null) { n = n.unify(); } return this._math(Math[name], unit, n); }; }; for(var i = 0; i < mathFunctions.length; i++) { tree.functions[mathFunctions[i].name] = createMathFunction(mathFunctions[i].name, mathFunctions[i].unit); } function hsla(color) { return tree.functions.hsla(color.h, color.s, color.l, color.a); } function scaled(n, size) { if (n instanceof tree.Dimension && n.unit.is('%')) { return parseFloat(n.value * size / 100); } else { return number(n); } } function number(n) { if (n instanceof tree.Dimension) { return parseFloat(n.unit.is('%') ? n.value / 100 : n.value); } else if (typeof(n) === 'number') { return n; } else { throw { error: "RuntimeError", message: "color functions take numbers as parameters" }; } } function clamp(val) { return Math.min(1, Math.max(0, val)); } tree.functionCall = function(env, currentFileInfo) { this.env = env; this.currentFileInfo = currentFileInfo; }; tree.functionCall.prototype = tree.functions; })(require('./tree')); less.js-1.4.2/lib/less/import-visitor.js000066400000000000000000000075651217256642200202040ustar00rootroot00000000000000(function (tree) { tree.importVisitor = function(importer, finish, evalEnv) { this._visitor = new tree.visitor(this); this._importer = importer; this._finish = finish; this.env = evalEnv || new tree.evalEnv(); this.importCount = 0; }; tree.importVisitor.prototype = { isReplacing: true, run: function (root) { var error; try { // process the contents this._visitor.visit(root); } catch(e) { error = e; } this.isFinished = true; if (this.importCount === 0) { this._finish(error); } }, visitImport: function (importNode, visitArgs) { var importVisitor = this, evaldImportNode; if (!importNode.css) { try { evaldImportNode = importNode.evalForImport(this.env); } catch(e){ if (!e.filename) { e.index = importNode.index; e.filename = importNode.currentFileInfo.filename; } // attempt to eval properly and treat as css importNode.css = true; // if that fails, this error will be thrown importNode.error = e; } if (evaldImportNode && !evaldImportNode.css) { importNode = evaldImportNode; this.importCount++; var env = new tree.evalEnv(this.env, this.env.frames.slice(0)); this._importer.push(importNode.getPath(), importNode.currentFileInfo, function (e, root, imported) { if (e && !e.filename) { e.index = importNode.index; e.filename = importNode.currentFileInfo.filename; } if (imported && !importNode.options.multiple) { importNode.skip = imported; } var subFinish = function(e) { importVisitor.importCount--; if (importVisitor.importCount === 0 && importVisitor.isFinished) { importVisitor._finish(e); } }; if (root) { importNode.root = root; new(tree.importVisitor)(importVisitor._importer, subFinish, env) .run(root); } else { subFinish(); } }); } } visitArgs.visitDeeper = false; return importNode; }, visitRule: function (ruleNode, visitArgs) { visitArgs.visitDeeper = false; return ruleNode; }, visitDirective: function (directiveNode, visitArgs) { this.env.frames.unshift(directiveNode); return directiveNode; }, visitDirectiveOut: function (directiveNode) { this.env.frames.shift(); }, visitMixinDefinition: function (mixinDefinitionNode, visitArgs) { this.env.frames.unshift(mixinDefinitionNode); return mixinDefinitionNode; }, visitMixinDefinitionOut: function (mixinDefinitionNode) { this.env.frames.shift(); }, visitRuleset: function (rulesetNode, visitArgs) { this.env.frames.unshift(rulesetNode); return rulesetNode; }, visitRulesetOut: function (rulesetNode) { this.env.frames.shift(); }, visitMedia: function (mediaNode, visitArgs) { this.env.frames.unshift(mediaNode.ruleset); return mediaNode; }, visitMediaOut: function (mediaNode) { this.env.frames.shift(); } }; })(require('./tree'));less.js-1.4.2/lib/less/index.js000066400000000000000000000170661217256642200163010ustar00rootroot00000000000000var path = require('path'), sys = require('util'), url = require('url'), request, fs = require('fs'); var less = { version: [1, 4, 2], Parser: require('./parser').Parser, importer: require('./parser').importer, tree: require('./tree'), render: function (input, options, callback) { options = options || {}; if (typeof(options) === 'function') { callback = options, options = {}; } var parser = new(less.Parser)(options), ee; if (callback) { parser.parse(input, function (e, root) { callback(e, root && root.toCSS && root.toCSS(options)); }); } else { ee = new(require('events').EventEmitter); process.nextTick(function () { parser.parse(input, function (e, root) { if (e) { ee.emit('error', e) } else { ee.emit('success', root.toCSS(options)) } }); }); return ee; } }, formatError: function(ctx, options) { options = options || {}; var message = ""; var extract = ctx.extract; var error = []; var stylize = options.color ? require('./lessc_helper').stylize : function (str) { return str }; // only output a stack if it isn't a less error if (ctx.stack && !ctx.type) { return stylize(ctx.stack, 'red') } if (!ctx.hasOwnProperty('index') || !extract) { return ctx.stack || ctx.message; } if (typeof(extract[0]) === 'string') { error.push(stylize((ctx.line - 1) + ' ' + extract[0], 'grey')); } if (typeof(extract[1]) === 'string') { var errorTxt = ctx.line + ' '; if (extract[1]) { errorTxt += extract[1].slice(0, ctx.column) + stylize(stylize(stylize(extract[1][ctx.column], 'bold') + extract[1].slice(ctx.column + 1), 'red'), 'inverse'); } error.push(errorTxt); } if (typeof(extract[2]) === 'string') { error.push(stylize((ctx.line + 1) + ' ' + extract[2], 'grey')); } error = error.join('\n') + stylize('', 'reset') + '\n'; message += stylize(ctx.type + 'Error: ' + ctx.message, 'red'); ctx.filename && (message += stylize(' in ', 'red') + ctx.filename + stylize(' on line ' + ctx.line + ', column ' + (ctx.column + 1) + ':', 'grey')); message += '\n' + error; if (ctx.callLine) { message += stylize('from ', 'red') + (ctx.filename || '') + '/n'; message += stylize(ctx.callLine, 'grey') + ' ' + ctx.callExtract + '/n'; } return message; }, writeError: function (ctx, options) { options = options || {}; if (options.silent) { return } sys.error(less.formatError(ctx, options)); } }; ['color', 'directive', 'operation', 'dimension', 'keyword', 'variable', 'ruleset', 'element', 'selector', 'quoted', 'expression', 'rule', 'call', 'url', 'alpha', 'import', 'mixin', 'comment', 'anonymous', 'value', 'javascript', 'assignment', 'condition', 'paren', 'media', 'unicode-descriptor', 'negative', 'extend' ].forEach(function (n) { require('./tree/' + n); }); var isUrlRe = /^(?:https?:)?\/\//i; less.Parser.importer = function (file, currentFileInfo, callback, env) { var pathname, dirname, data, newFileInfo = { relativeUrls: env.relativeUrls, entryPath: currentFileInfo.entryPath, rootpath: currentFileInfo.rootpath, rootFilename: currentFileInfo.rootFilename }; function parseFile(e, data) { if (e) { return callback(e); } env = new less.tree.parseEnv(env); env.processImports = false; var j = file.lastIndexOf('/'); // Pass on an updated rootpath if path of imported file is relative and file // is in a (sub|sup) directory // // Examples: // - If path of imported file is 'module/nav/nav.less' and rootpath is 'less/', // then rootpath should become 'less/module/nav/' // - If path of imported file is '../mixins.less' and rootpath is 'less/', // then rootpath should become 'less/../' if(newFileInfo.relativeUrls && !/^(?:[a-z-]+:|\/)/.test(file) && j != -1) { var relativeSubDirectory = file.slice(0, j+1); newFileInfo.rootpath = newFileInfo.rootpath + relativeSubDirectory; // append (sub|sup) directory path of imported file } newFileInfo.currentDirectory = pathname.replace(/[^\\\/]*$/, ""); newFileInfo.filename = pathname; env.contents[pathname] = data; // Updating top importing parser content cache. env.currentFileInfo = newFileInfo; new(less.Parser)(env).parse(data, function (e, root) { callback(e, root, pathname); }); }; var isUrl = isUrlRe.test( file ); if (isUrl || isUrlRe.test(currentFileInfo.currentDirectory)) { if (request === undefined) { try { request = require('request'); } catch(e) { request = null; } } if (!request) { callback({ type: 'File', message: "optional dependency 'request' required to import over http(s)\n" }); return; } var urlStr = isUrl ? file : url.resolve(currentFileInfo.currentDirectory, file), urlObj = url.parse(urlStr), req = { host: urlObj.hostname, port: urlObj.port || 80, path: urlObj.pathname + (urlObj.search||'') }; request.get(urlStr, function (error, res, body) { if (res.statusCode === 404) { callback({ type: 'File', message: "resource '" + urlStr + "' was not found\n" }); return; } if (!body) { sys.error( 'Warning: Empty body (HTTP '+ res.statusCode + ') returned by "' + urlStr +'"' ); } if (error) { callback({ type: 'File', message: "resource '" + urlStr + "' gave this Error:\n "+ error +"\n" }); } pathname = urlStr; dirname = urlObj.protocol +'//'+ urlObj.host + urlObj.pathname.replace(/[^\/]*$/, ''); parseFile(null, body); }); } else { var paths = [currentFileInfo.currentDirectory].concat(env.paths); paths.push('.'); for (var i = 0; i < paths.length; i++) { try { pathname = path.join(paths[i], file); fs.statSync(pathname); break; } catch (e) { pathname = null; } } if (!pathname) { callback({ type: 'File', message: "'" + file + "' wasn't found" }); return; } dirname = path.dirname(pathname); if (env.syncImport) { try { data = fs.readFileSync(pathname, 'utf-8'); parseFile(null, data); } catch (e) { parseFile(e); } } else { fs.readFile(pathname, 'utf-8', parseFile); } } } require('./env'); require('./functions'); require('./colors'); require('./visitor.js'); require('./import-visitor.js'); require('./extend-visitor.js'); require('./join-selector-visitor.js'); for (var k in less) { exports[k] = less[k]; } less.js-1.4.2/lib/less/join-selector-visitor.js000066400000000000000000000023611217256642200214340ustar00rootroot00000000000000(function (tree) { tree.joinSelectorVisitor = function() { this.contexts = [[]]; this._visitor = new tree.visitor(this); }; tree.joinSelectorVisitor.prototype = { run: function (root) { return this._visitor.visit(root); }, visitRule: function (ruleNode, visitArgs) { visitArgs.visitDeeper = false; }, visitMixinDefinition: function (mixinDefinitionNode, visitArgs) { visitArgs.visitDeeper = false; }, visitRuleset: function (rulesetNode, visitArgs) { var context = this.contexts[this.contexts.length - 1]; var paths = []; this.contexts.push(paths); if (! rulesetNode.root) { rulesetNode.joinSelectors(paths, context, rulesetNode.selectors); rulesetNode.paths = paths; } }, visitRulesetOut: function (rulesetNode) { this.contexts.length = this.contexts.length - 1; }, visitMedia: function (mediaNode, visitArgs) { var context = this.contexts[this.contexts.length - 1]; mediaNode.ruleset.root = (context.length === 0 || context[0].multiMedia); } }; })(require('./tree'));less.js-1.4.2/lib/less/lessc_helper.js000066400000000000000000000075101217256642200176330ustar00rootroot00000000000000// lessc_helper.js // // helper functions for lessc var sys = require('util'); var lessc_helper = { //Stylize a string stylize : function(str, style) { var styles = { 'reset' : [0, 0], 'bold' : [1, 22], 'inverse' : [7, 27], 'underline' : [4, 24], 'yellow' : [33, 39], 'green' : [32, 39], 'red' : [31, 39], 'grey' : [90, 39] }; return '\033[' + styles[style][0] + 'm' + str + '\033[' + styles[style][1] + 'm'; }, //Print command line options printUsage: function() { sys.puts("usage: lessc [option option=parameter ...] [destination]"); sys.puts(""); sys.puts("If source is set to `-' (dash or hyphen-minus), input is read from stdin."); sys.puts(""); sys.puts("options:"); sys.puts(" -h, --help Print help (this message) and exit."); sys.puts(" --include-path=PATHS Set include paths. Separated by `:'. Use `;' on Windows."); sys.puts(" -M, --depends Output a makefile import dependency list to stdout"); sys.puts(" --no-color Disable colorized output."); sys.puts(" --no-ie-compat Disable IE compatibility checks."); sys.puts(" -l, --lint Syntax check only (lint)."); sys.puts(" -s, --silent Suppress output of error messages."); sys.puts(" --strict-imports Force evaluation of imports."); sys.puts(" --verbose Be verbose."); sys.puts(" -v, --version Print version number and exit."); sys.puts(" -x, --compress Compress output by removing some whitespaces."); sys.puts(" --yui-compress Compress output using ycssmin"); sys.puts(" --max-line-len=LINELEN Max line length used by ycssmin"); sys.puts(" -O0, -O1, -O2 Set the parser's optimization level. The lower"); sys.puts(" the number, the less nodes it will create in the"); sys.puts(" tree. This could matter for debugging, or if you"); sys.puts(" want to access the individual nodes in the tree."); sys.puts(" --line-numbers=TYPE Outputs filename and line numbers."); sys.puts(" TYPE can be either 'comments', which will output"); sys.puts(" the debug info within comments, 'mediaquery'"); sys.puts(" that will output the information within a fake"); sys.puts(" media query which is compatible with the SASS"); sys.puts(" format, and 'all' which will do both."); sys.puts(" -rp, --rootpath=URL Set rootpath for url rewriting in relative imports and urls."); sys.puts(" Works with or without the relative-urls option."); sys.puts(" -ru, --relative-urls re-write relative urls to the base less file."); sys.puts(" -sm=on|off Turn on or off strict math, where in strict mode, math"); sys.puts(" --strict-math=on|off requires brackets. This option may default to on and then"); sys.puts(" be removed in the future."); sys.puts(" -su=on|off Allow mixed units, e.g. 1px+1em or 1px*1px which have units"); sys.puts(" --strict-units=on|off that cannot be represented."); sys.puts(""); sys.puts("Report bugs to: http://github.com/cloudhead/less.js/issues"); sys.puts("Home page: "); } } // Exports helper functions for (var h in lessc_helper) { exports[h] = lessc_helper[h] } less.js-1.4.2/lib/less/parser.js000066400000000000000000001662351217256642200164710ustar00rootroot00000000000000var less, tree, charset; if (typeof environment === "object" && ({}).toString.call(environment) === "[object Environment]") { // Rhino // Details on how to detect Rhino: https://github.com/ringo/ringojs/issues/88 if (typeof(window) === 'undefined') { less = {} } else { less = window.less = {} } tree = less.tree = {}; less.mode = 'rhino'; } else if (typeof(window) === 'undefined') { // Node.js less = exports, tree = require('./tree'); less.mode = 'node'; } else { // Browser if (typeof(window.less) === 'undefined') { window.less = {} } less = window.less, tree = window.less.tree = {}; less.mode = 'browser'; } // // less.js - parser // // A relatively straight-forward predictive parser. // There is no tokenization/lexing stage, the input is parsed // in one sweep. // // To make the parser fast enough to run in the browser, several // optimization had to be made: // // - Matching and slicing on a huge input is often cause of slowdowns. // The solution is to chunkify the input into smaller strings. // The chunks are stored in the `chunks` var, // `j` holds the current chunk index, and `current` holds // the index of the current chunk in relation to `input`. // This gives us an almost 4x speed-up. // // - In many cases, we don't need to match individual tokens; // for example, if a value doesn't hold any variables, operations // or dynamic references, the parser can effectively 'skip' it, // treating it as a literal. // An example would be '1px solid #000' - which evaluates to itself, // we don't need to know what the individual components are. // The drawback, of course is that you don't get the benefits of // syntax-checking on the CSS. This gives us a 50% speed-up in the parser, // and a smaller speed-up in the code-gen. // // // Token matching is done with the `$` function, which either takes // a terminal string or regexp, or a non-terminal function to call. // It also takes care of moving all the indices forwards. // // less.Parser = function Parser(env) { var input, // LeSS input string i, // current index in `input` j, // current chunk temp, // temporarily holds a chunk's state, for backtracking memo, // temporarily holds `i`, when backtracking furthest, // furthest index the parser has gone to chunks, // chunkified input current, // index of current chunk, in `input` parser; var that = this; // Top parser on an import tree must be sure there is one "env" // which will then be passed around by reference. if (!(env instanceof tree.parseEnv)) { env = new tree.parseEnv(env); } var imports = this.imports = { paths: env.paths || [], // Search paths, when importing queue: [], // Files which haven't been imported yet files: env.files, // Holds the imported parse trees contents: env.contents, // Holds the imported file contents mime: env.mime, // MIME type of .less files error: null, // Error in parsing/evaluating an import push: function (path, currentFileInfo, callback) { var parserImporter = this; this.queue.push(path); // // Import a file asynchronously // less.Parser.importer(path, currentFileInfo, function (e, root, fullPath) { parserImporter.queue.splice(parserImporter.queue.indexOf(path), 1); // Remove the path from the queue var imported = fullPath in parserImporter.files; parserImporter.files[fullPath] = root; // Store the root if (e && !parserImporter.error) { parserImporter.error = e; } callback(e, root, imported); }, env); } }; function save() { temp = chunks[j], memo = i, current = i; } function restore() { chunks[j] = temp, i = memo, current = i; } function sync() { if (i > current) { chunks[j] = chunks[j].slice(i - current); current = i; } } function isWhitespace(c) { // Could change to \s? var code = c.charCodeAt(0); return code === 32 || code === 10 || code === 9; } // // Parse from a token, regexp or string, and move forward if match // function $(tok) { var match, args, length, index, k; // // Non-terminal // if (tok instanceof Function) { return tok.call(parser.parsers); // // Terminal // // Either match a single character in the input, // or match a regexp in the current chunk (chunk[j]). // } else if (typeof(tok) === 'string') { match = input.charAt(i) === tok ? tok : null; length = 1; sync (); } else { sync (); if (match = tok.exec(chunks[j])) { length = match[0].length; } else { return null; } } // The match is confirmed, add the match length to `i`, // and consume any extra white-space characters (' ' || '\n') // which come after that. The reason for this is that LeSS's // grammar is mostly white-space insensitive. // if (match) { skipWhitespace(length); if(typeof(match) === 'string') { return match; } else { return match.length === 1 ? match[0] : match; } } } function skipWhitespace(length) { var oldi = i, oldj = j, endIndex = i + chunks[j].length, mem = i += length; while (i < endIndex) { if (! isWhitespace(input.charAt(i))) { break } i++; } chunks[j] = chunks[j].slice(length + (i - mem)); current = i; if (chunks[j].length === 0 && j < chunks.length - 1) { j++ } return oldi !== i || oldj !== j; } function expect(arg, msg) { var result = $(arg); if (! result) { error(msg || (typeof(arg) === 'string' ? "expected '" + arg + "' got '" + input.charAt(i) + "'" : "unexpected token")); } else { return result; } } function error(msg, type) { var e = new Error(msg); e.index = i; e.type = type || 'Syntax'; throw e; } // Same as $(), but don't change the state of the parser, // just return the match. function peek(tok) { if (typeof(tok) === 'string') { return input.charAt(i) === tok; } else { if (tok.test(chunks[j])) { return true; } else { return false; } } } function getInput(e, env) { if (e.filename && env.currentFileInfo.filename && (e.filename !== env.currentFileInfo.filename)) { return parser.imports.contents[e.filename]; } else { return input; } } function getLocation(index, input) { for (var n = index, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } return { line: typeof(index) === 'number' ? (input.slice(0, index).match(/\n/g) || "").length : null, column: column }; } function getDebugInfo(index, inputStream, env) { var filename = env.currentFileInfo.filename; if(less.mode !== 'browser' && less.mode !== 'rhino') { filename = require('path').resolve(filename); } return { lineNumber: getLocation(index, inputStream).line + 1, fileName: filename }; } function LessError(e, env) { var input = getInput(e, env), loc = getLocation(e.index, input), line = loc.line, col = loc.column, lines = input.split('\n'); this.type = e.type || 'Syntax'; this.message = e.message; this.filename = e.filename || env.currentFileInfo.filename; this.index = e.index; this.line = typeof(line) === 'number' ? line + 1 : null; this.callLine = e.call && (getLocation(e.call, input).line + 1); this.callExtract = lines[getLocation(e.call, input).line]; this.stack = e.stack; this.column = col; this.extract = [ lines[line - 1], lines[line], lines[line + 1] ]; } LessError.prototype = new Error(); LessError.prototype.constructor = LessError; this.env = env = env || {}; // The optimization level dictates the thoroughness of the parser, // the lower the number, the less nodes it will create in the tree. // This could matter for debugging, or if you want to access // the individual nodes in the tree. this.optimization = ('optimization' in this.env) ? this.env.optimization : 1; // // The Parser // return parser = { imports: imports, // // Parse an input string into an abstract syntax tree, // call `callback` when done. // parse: function (str, callback) { var root, start, end, zone, line, lines, buff = [], c, error = null; i = j = current = furthest = 0; input = str.replace(/\r\n/g, '\n'); // Remove potential UTF Byte Order Mark input = input.replace(/^\uFEFF/, ''); // Split the input into chunks. chunks = (function (chunks) { var j = 0, skip = /(?:@\{[\w-]+\}|[^"'`\{\}\/\(\)\\])+/g, comment = /\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g, string = /"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'|`((?:[^`]|\\.)*)`/g, level = 0, match, chunk = chunks[0], inParam; for (var i = 0, c, cc; i < input.length;) { skip.lastIndex = i; if (match = skip.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); } } c = input.charAt(i); comment.lastIndex = string.lastIndex = i; if (match = string.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); continue; } } if (!inParam && c === '/') { cc = input.charAt(i + 1); if (cc === '/' || cc === '*') { if (match = comment.exec(input)) { if (match.index === i) { i += match[0].length; chunk.push(match[0]); continue; } } } } switch (c) { case '{': if (! inParam) { level ++; chunk.push(c); break } case '}': if (! inParam) { level --; chunk.push(c); chunks[++j] = chunk = []; break } case '(': if (! inParam) { inParam = true; chunk.push(c); break } case ')': if ( inParam) { inParam = false; chunk.push(c); break } default: chunk.push(c); } i++; } if (level != 0) { error = new(LessError)({ index: i-1, type: 'Parse', message: (level > 0) ? "missing closing `}`" : "missing opening `{`", filename: env.currentFileInfo.filename }, env); } return chunks.map(function (c) { return c.join('') });; })([[]]); if (error) { return callback(new(LessError)(error, env)); } // Start with the primary rule. // The whole syntax tree is held under a Ruleset node, // with the `root` property set to true, so no `{}` are // output. The callback is called when the input is parsed. try { root = new(tree.Ruleset)([], $(this.parsers.primary)); root.root = true; root.firstRoot = true; } catch (e) { return callback(new(LessError)(e, env)); } root.toCSS = (function (evaluate) { var line, lines, column; return function (options, variables) { options = options || {}; var importError, evalEnv = new tree.evalEnv(options); // // Allows setting variables with a hash, so: // // `{ color: new(tree.Color)('#f01') }` will become: // // new(tree.Rule)('@color', // new(tree.Value)([ // new(tree.Expression)([ // new(tree.Color)('#f01') // ]) // ]) // ) // if (typeof(variables) === 'object' && !Array.isArray(variables)) { variables = Object.keys(variables).map(function (k) { var value = variables[k]; if (! (value instanceof tree.Value)) { if (! (value instanceof tree.Expression)) { value = new(tree.Expression)([value]); } value = new(tree.Value)([value]); } return new(tree.Rule)('@' + k, value, false, 0); }); evalEnv.frames = [new(tree.Ruleset)(null, variables)]; } try { var evaldRoot = evaluate.call(this, evalEnv); new(tree.joinSelectorVisitor)() .run(evaldRoot); new(tree.processExtendsVisitor)() .run(evaldRoot); var css = evaldRoot.toCSS({ compress: Boolean(options.compress), dumpLineNumbers: env.dumpLineNumbers, strictUnits: Boolean(options.strictUnits)}); } catch (e) { throw new(LessError)(e, env); } if (options.yuicompress && less.mode === 'node') { return require('ycssmin').cssmin(css, options.maxLineLen); } else if (options.compress) { return css.replace(/(\s)+/g, "$1"); } else { return css; } }; })(root.eval); // If `i` is smaller than the `input.length - 1`, // it means the parser wasn't able to parse the whole // string, so we've got a parsing error. // // We try to extract a \n delimited string, // showing the line where the parse error occured. // We split it up into two parts (the part which parsed, // and the part which didn't), so we can color them differently. if (i < input.length - 1) { i = furthest; lines = input.split('\n'); line = (input.slice(0, i).match(/\n/g) || "").length + 1; for (var n = i, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ } error = { type: "Parse", message: "Unrecognised input", index: i, filename: env.currentFileInfo.filename, line: line, column: column, extract: [ lines[line - 2], lines[line - 1], lines[line] ] }; } var finish = function (e) { e = error || e || parser.imports.error; if (e) { if (!(e instanceof LessError)) { e = new(LessError)(e, env); } callback(e); } else { callback(null, root); } }; if (env.processImports !== false) { new tree.importVisitor(this.imports, finish) .run(root); } else { finish(); } }, // // Here in, the parsing rules/functions // // The basic structure of the syntax tree generated is as follows: // // Ruleset -> Rule -> Value -> Expression -> Entity // // Here's some LESS code: // // .class { // color: #fff; // border: 1px solid #000; // width: @w + 4px; // > .child {...} // } // // And here's what the parse tree might look like: // // Ruleset (Selector '.class', [ // Rule ("color", Value ([Expression [Color #fff]])) // Rule ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]])) // Rule ("width", Value ([Expression [Operation "+" [Variable "@w"][Dimension 4px]]])) // Ruleset (Selector [Element '>', '.child'], [...]) // ]) // // In general, most rules will try to parse a token with the `$()` function, and if the return // value is truly, will return a new node, of the relevant type. Sometimes, we need to check // first, before parsing, that's when we use `peek()`. // parsers: { // // The `primary` rule is the *entry* and *exit* point of the parser. // The rules here can appear at any level of the parse tree. // // The recursive nature of the grammar is an interplay between the `block` // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule, // as represented by this simplified grammar: // // primary → (ruleset | rule)+ // ruleset → selector+ block // block → '{' primary '}' // // Only at one point is the primary rule not called from the // block rule: at the root level. // primary: function () { var node, root = []; while ((node = $(this.extendRule) || $(this.mixin.definition) || $(this.rule) || $(this.ruleset) || $(this.mixin.call) || $(this.comment) || $(this.directive)) || $(/^[\s\n]+/) || $(/^;+/)) { node && root.push(node); } return root; }, // We create a Comment node for CSS comments `/* */`, // but keep the LeSS comments `//` silent, by just skipping // over them. comment: function () { var comment; if (input.charAt(i) !== '/') return; if (input.charAt(i + 1) === '/') { return new(tree.Comment)($(/^\/\/.*/), true); } else if (comment = $(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/)) { return new(tree.Comment)(comment); } }, // // Entities are tokens which can be found inside an Expression // entities: { // // A string, which supports escaping " and ' // // "milky way" 'he\'s the one!' // quoted: function () { var str, j = i, e, index = i; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '"' && input.charAt(j) !== "'") return; e && $('~'); if (str = $(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/)) { return new(tree.Quoted)(str[0], str[1] || str[2], e, index, env.currentFileInfo); } }, // // A catch-all word, such as: // // black border-collapse // keyword: function () { var k; if (k = $(/^[_A-Za-z-][_A-Za-z0-9-]*/)) { if (tree.colors.hasOwnProperty(k)) { // detect named color return new(tree.Color)(tree.colors[k].slice(1)); } else { return new(tree.Keyword)(k); } } }, // // A function call // // rgb(255, 0, 255) // // We also try to catch IE's `alpha()`, but let the `alpha` parser // deal with the details. // // The arguments are parsed with the `entities.arguments` parser. // call: function () { var name, nameLC, args, alpha_ret, index = i; if (! (name = /^([\w-]+|%|progid:[\w\.]+)\(/.exec(chunks[j]))) return; name = name[1]; nameLC = name.toLowerCase(); if (nameLC === 'url') { return null } else { i += name.length } if (nameLC === 'alpha') { alpha_ret = $(this.alpha); if(typeof alpha_ret !== 'undefined') { return alpha_ret; } } $('('); // Parse the '(' and consume whitespace. args = $(this.entities.arguments); if (! $(')')) { return; } if (name) { return new(tree.Call)(name, args, index, env.currentFileInfo); } }, arguments: function () { var args = [], arg; while (arg = $(this.entities.assignment) || $(this.expression)) { args.push(arg); if (! $(',')) { break } } return args; }, literal: function () { return $(this.entities.dimension) || $(this.entities.color) || $(this.entities.quoted) || $(this.entities.unicodeDescriptor); }, // Assignments are argument entities for calls. // They are present in ie filter properties as shown below. // // filter: progid:DXImageTransform.Microsoft.Alpha( *opacity=50* ) // assignment: function () { var key, value; if ((key = $(/^\w+(?=\s?=)/i)) && $('=') && (value = $(this.entity))) { return new(tree.Assignment)(key, value); } }, // // Parse url() tokens // // We use a specific rule for urls, because they don't really behave like // standard function calls. The difference is that the argument doesn't have // to be enclosed within a string, so it can't be parsed as an Expression. // url: function () { var value; if (input.charAt(i) !== 'u' || !$(/^url\(/)) return; value = $(this.entities.quoted) || $(this.entities.variable) || $(/^(?:(?:\\[\(\)'"])|[^\(\)'"])+/) || ""; expect(')'); return new(tree.URL)((value.value != null || value instanceof tree.Variable) ? value : new(tree.Anonymous)(value), env.currentFileInfo); }, // // A Variable entity, such as `@fink`, in // // width: @fink + 2px // // We use a different parser for variable definitions, // see `parsers.variable`. // variable: function () { var name, index = i; if (input.charAt(i) === '@' && (name = $(/^@@?[\w-]+/))) { return new(tree.Variable)(name, index, env.currentFileInfo); } }, // A variable entity useing the protective {} e.g. @{var} variableCurly: function () { var name, curly, index = i; if (input.charAt(i) === '@' && (curly = $(/^@\{([\w-]+)\}/))) { return new(tree.Variable)("@" + curly[1], index, env.currentFileInfo); } }, // // A Hexadecimal color // // #4F3C2F // // `rgb` and `hsl` colors are parsed through the `entities.call` parser. // color: function () { var rgb; if (input.charAt(i) === '#' && (rgb = $(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/))) { return new(tree.Color)(rgb[1]); } }, // // A Dimension, that is, a number and a unit // // 0.5em 95% // dimension: function () { var value, c = input.charCodeAt(i); //Is the first char of the dimension 0-9, '.', '+' or '-' if ((c > 57 || c < 43) || c === 47 || c == 44) return; if (value = $(/^([+-]?\d*\.?\d+)(%|[a-z]+)?/)) { return new(tree.Dimension)(value[1], value[2]); } }, // // A unicode descriptor, as is used in unicode-range // // U+0?? or U+00A1-00A9 // unicodeDescriptor: function () { var ud; if (ud = $(/^U\+[0-9a-fA-F?]+(\-[0-9a-fA-F?]+)?/)) { return new(tree.UnicodeDescriptor)(ud[0]); } }, // // JavaScript code to be evaluated // // `window.location.href` // javascript: function () { var str, j = i, e; if (input.charAt(j) === '~') { j++, e = true } // Escaped strings if (input.charAt(j) !== '`') { return } e && $('~'); if (str = $(/^`([^`]*)`/)) { return new(tree.JavaScript)(str[1], i, e); } } }, // // The variable part of a variable definition. Used in the `rule` parser // // @fink: // variable: function () { var name; if (input.charAt(i) === '@' && (name = $(/^(@[\w-]+)\s*:/))) { return name[1] } }, // // extend syntax - used to extend selectors // extend: function(isRule) { var elements, e, index = i, option, extendList = []; if (!$(isRule ? /^&:extend\(/ : /^:extend\(/)) { return; } do { option = null; elements = []; while (true) { option = $(/^(all)(?=\s*(\)|,))/); if (option) { break; } e = $(this.element); if (!e) { break; } elements.push(e); } option = option && option[1]; extendList.push(new(tree.Extend)(new(tree.Selector)(elements), option, index)); } while($(",")) expect(/^\)/); if (isRule) { expect(/^;/); } return extendList; }, // // extendRule - used in a rule to extend all the parent selectors // extendRule: function() { return this.extend(true); }, // // Mixins // mixin: { // // A Mixin call, with an optional argument list // // #mixins > .square(#fff); // .rounded(4px, black); // .button; // // The `while` loop is there because mixins can be // namespaced, but we only support the child and descendant // selector for now. // call: function () { var elements = [], e, c, args, delim, arg, index = i, s = input.charAt(i), important = false; if (s !== '.' && s !== '#') { return } save(); // stop us absorbing part of an invalid selector while (e = $(/^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/)) { elements.push(new(tree.Element)(c, e, i)); c = $('>'); } if ($('(')) { args = this.mixin.args.call(this, true).args; expect(')'); } args = args || []; if ($(this.important)) { important = true; } if (elements.length > 0 && ($(';') || peek('}'))) { return new(tree.mixin.Call)(elements, args, index, env.currentFileInfo, important); } restore(); }, args: function (isCall) { var expressions = [], argsSemiColon = [], isSemiColonSeperated, argsComma = [], expressionContainsNamed, name, nameLoop, value, arg, returner = {args:null, variadic: false}; while (true) { if (isCall) { arg = $(this.expression); } else { $(this.comment); if (input.charAt(i) === '.' && $(/^\.{3}/)) { returner.variadic = true; if ($(";") && !isSemiColonSeperated) { isSemiColonSeperated = true; } (isSemiColonSeperated ? argsSemiColon : argsComma) .push({ variadic: true }); break; } arg = $(this.entities.variable) || $(this.entities.literal) || $(this.entities.keyword); } if (!arg) { break; } nameLoop = null; if (arg.throwAwayComments) { arg.throwAwayComments(); } value = arg; var val = null; if (isCall) { // Variable if (arg.value.length == 1) { var val = arg.value[0]; } } else { val = arg; } if (val && val instanceof tree.Variable) { if ($(':')) { if (expressions.length > 0) { if (isSemiColonSeperated) { error("Cannot mix ; and , as delimiter types"); } expressionContainsNamed = true; } value = expect(this.expression); nameLoop = (name = val.name); } else if (!isCall && $(/^\.{3}/)) { returner.variadic = true; if ($(";") && !isSemiColonSeperated) { isSemiColonSeperated = true; } (isSemiColonSeperated ? argsSemiColon : argsComma) .push({ name: arg.name, variadic: true }); break; } else if (!isCall) { name = nameLoop = val.name; value = null; } } if (value) { expressions.push(value); } argsComma.push({ name:nameLoop, value:value }); if ($(',')) { continue; } if ($(';') || isSemiColonSeperated) { if (expressionContainsNamed) { error("Cannot mix ; and , as delimiter types"); } isSemiColonSeperated = true; if (expressions.length > 1) { value = new (tree.Value)(expressions); } argsSemiColon.push({ name:name, value:value }); name = null; expressions = []; expressionContainsNamed = false; } } returner.args = isSemiColonSeperated ? argsSemiColon : argsComma; return returner; }, // // A Mixin definition, with a list of parameters // // .rounded (@radius: 2px, @color) { // ... // } // // Until we have a finer grained state-machine, we have to // do a look-ahead, to make sure we don't have a mixin call. // See the `rule` function for more information. // // We start by matching `.rounded (`, and then proceed on to // the argument list, which has optional default values. // We store the parameters in `params`, with a `value` key, // if there is a value, such as in the case of `@radius`. // // Once we've got our params list, and a closing `)`, we parse // the `{...}` block. // definition: function () { var name, params = [], match, ruleset, param, value, cond, variadic = false; if ((input.charAt(i) !== '.' && input.charAt(i) !== '#') || peek(/^[^{]*\}/)) return; save(); if (match = $(/^([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/)) { name = match[1]; var argInfo = this.mixin.args.call(this, false); params = argInfo.args; variadic = argInfo.variadic; // .mixincall("@{a}"); // looks a bit like a mixin definition.. so we have to be nice and restore if (!$(')')) { furthest = i; restore(); } $(this.comment); if ($(/^when/)) { // Guard cond = expect(this.conditions, 'expected condition'); } ruleset = $(this.block); if (ruleset) { return new(tree.mixin.Definition)(name, params, ruleset, cond, variadic); } else { restore(); } } } }, // // Entities are the smallest recognized token, // and can be found inside a rule's value. // entity: function () { return $(this.entities.literal) || $(this.entities.variable) || $(this.entities.url) || $(this.entities.call) || $(this.entities.keyword) ||$(this.entities.javascript) || $(this.comment); }, // // A Rule terminator. Note that we use `peek()` to check for '}', // because the `block` rule will be expecting it, but we still need to make sure // it's there, if ';' was ommitted. // end: function () { return $(';') || peek('}'); }, // // IE's alpha function // // alpha(opacity=88) // alpha: function () { var value; if (! $(/^\(opacity=/i)) return; if (value = $(/^\d+/) || $(this.entities.variable)) { expect(')'); return new(tree.Alpha)(value); } }, // // A Selector Element // // div // + h1 // #socks // input[type="text"] // // Elements are the building blocks for Selectors, // they are made out of a `Combinator` (see combinator rule), // and an element name, such as a tag a class, or `*`. // element: function () { var e, t, c, v; c = $(this.combinator); e = $(/^(?:\d+\.\d+|\d+)%/) || $(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/) || $('*') || $('&') || $(this.attribute) || $(/^\([^()@]+\)/) || $(/^[\.#](?=@)/) || $(this.entities.variableCurly); if (! e) { if ($('(')) { if ((v = ($(this.selector))) && $(')')) { e = new(tree.Paren)(v); } } } if (e) { return new(tree.Element)(c, e, i) } }, // // Combinators combine elements together, in a Selector. // // Because our parser isn't white-space sensitive, special care // has to be taken, when parsing the descendant combinator, ` `, // as it's an empty space. We have to check the previous character // in the input, to see if it's a ` ` character. More info on how // we deal with this in *combinator.js*. // combinator: function () { var c = input.charAt(i); if (c === '>' || c === '+' || c === '~' || c === '|') { i++; while (input.charAt(i).match(/\s/)) { i++ } return new(tree.Combinator)(c); } else if (input.charAt(i - 1).match(/\s/)) { return new(tree.Combinator)(" "); } else { return new(tree.Combinator)(null); } }, // // A CSS Selector // // .class > div + h1 // li a:hover // // Selectors are made out of one or more Elements, see above. // selector: function () { var sel, e, elements = [], c, extend, extendList = []; while ((extend = $(this.extend)) || (e = $(this.element))) { if (extend) { extendList.push.apply(extendList, extend); } else { if (extendList.length) { error("Extend can only be used at the end of selector"); } c = input.charAt(i); elements.push(e) e = null; } if (c === '{' || c === '}' || c === ';' || c === ',' || c === ')') { break } } if (elements.length > 0) { return new(tree.Selector)(elements, extendList); } if (extendList.length) { error("Extend must be used to extend a selector, it cannot be used on its own"); } }, attribute: function () { var attr = '', key, val, op; if (! $('[')) return; if (!(key = $(this.entities.variableCurly))) { key = expect(/^(?:[_A-Za-z0-9-\*]*\|)?(?:[_A-Za-z0-9-]|\\.)+/); } if ((op = $(/^[|~*$^]?=/))) { val = $(this.entities.quoted) || $(/^[\w-]+/) || $(this.entities.variableCurly); } expect(']'); return new(tree.Attribute)(key, op, val); }, // // The `block` rule is used by `ruleset` and `mixin.definition`. // It's a wrapper around the `primary` rule, with added `{}`. // block: function () { var content; if ($('{') && (content = $(this.primary)) && $('}')) { return content; } }, // // div, .class, body > p {...} // ruleset: function () { var selectors = [], s, rules, debugInfo; save(); if (env.dumpLineNumbers) debugInfo = getDebugInfo(i, input, env); while (s = $(this.selector)) { selectors.push(s); $(this.comment); if (! $(',')) { break } $(this.comment); } if (selectors.length > 0 && (rules = $(this.block))) { var ruleset = new(tree.Ruleset)(selectors, rules, env.strictImports); if (env.dumpLineNumbers) ruleset.debugInfo = debugInfo; return ruleset; } else { // Backtrack furthest = i; restore(); } }, rule: function (tryAnonymous) { var name, value, c = input.charAt(i), important; save(); if (c === '.' || c === '#' || c === '&') { return } if (name = $(this.variable) || $(this.property)) { // prefer to try to parse first if its a variable or we are compressing // but always fallback on the other one value = !tryAnonymous && (env.compress || (name.charAt(0) === '@')) ? ($(this.value) || $(this.anonymousValue)) : ($(this.anonymousValue) || $(this.value)); important = $(this.important); if (value && $(this.end)) { return new(tree.Rule)(name, value, important, memo, env.currentFileInfo); } else { furthest = i; restore(); if (value && !tryAnonymous) { return this.rule(true); } } } }, anonymousValue: function () { var match; if (match = /^([^@+\/'"*`(;{}-]*);/.exec(chunks[j])) { i += match[0].length - 1; return new(tree.Anonymous)(match[1]); } }, // // An @import directive // // @import "lib"; // // Depending on our environemnt, importing is done differently: // In the browser, it's an XHR request, in Node, it would be a // file-system operation. The function used for importing is // stored in `import`, which we pass to the Import constructor. // "import": function () { var path, features, index = i; save(); var dir = $(/^@import?\s+/); var options = (dir ? $(this.importOptions) : null) || {}; if (dir && (path = $(this.entities.quoted) || $(this.entities.url))) { features = $(this.mediaFeatures); if ($(';')) { features = features && new(tree.Value)(features); return new(tree.Import)(path, features, options, index, env.currentFileInfo); } } restore(); }, importOptions: function() { var o, options = {}, optionName, value; // list of options, surrounded by parens if (! $('(')) { return null; } do { if (o = $(this.importOption)) { optionName = o; value = true; switch(optionName) { case "css": optionName = "less"; value = false; break; case "once": optionName = "multiple"; value = false; break; } options[optionName] = value; if (! $(',')) { break } } } while (o); expect(')'); return options; }, importOption: function() { var opt = $(/^(less|css|multiple|once)/); if (opt) { return opt[1]; } }, mediaFeature: function () { var e, p, nodes = []; do { if (e = $(this.entities.keyword)) { nodes.push(e); } else if ($('(')) { p = $(this.property); e = $(this.value); if ($(')')) { if (p && e) { nodes.push(new(tree.Paren)(new(tree.Rule)(p, e, null, i, env.currentFileInfo, true))); } else if (e) { nodes.push(new(tree.Paren)(e)); } else { return null; } } else { return null } } } while (e); if (nodes.length > 0) { return new(tree.Expression)(nodes); } }, mediaFeatures: function () { var e, features = []; do { if (e = $(this.mediaFeature)) { features.push(e); if (! $(',')) { break } } else if (e = $(this.entities.variable)) { features.push(e); if (! $(',')) { break } } } while (e); return features.length > 0 ? features : null; }, media: function () { var features, rules, media, debugInfo; if (env.dumpLineNumbers) debugInfo = getDebugInfo(i, input, env); if ($(/^@media/)) { features = $(this.mediaFeatures); if (rules = $(this.block)) { media = new(tree.Media)(rules, features); if(env.dumpLineNumbers) media.debugInfo = debugInfo; return media; } } }, // // A CSS Directive // // @charset "utf-8"; // directive: function () { var name, value, rules, identifier, e, nodes, nonVendorSpecificName, hasBlock, hasIdentifier, hasExpression; if (input.charAt(i) !== '@') return; if (value = $(this['import']) || $(this.media)) { return value; } save(); name = $(/^@[a-z-]+/); if (!name) return; nonVendorSpecificName = name; if (name.charAt(1) == '-' && name.indexOf('-', 2) > 0) { nonVendorSpecificName = "@" + name.slice(name.indexOf('-', 2) + 1); } switch(nonVendorSpecificName) { case "@font-face": hasBlock = true; break; case "@viewport": case "@top-left": case "@top-left-corner": case "@top-center": case "@top-right": case "@top-right-corner": case "@bottom-left": case "@bottom-left-corner": case "@bottom-center": case "@bottom-right": case "@bottom-right-corner": case "@left-top": case "@left-middle": case "@left-bottom": case "@right-top": case "@right-middle": case "@right-bottom": hasBlock = true; break; case "@page": case "@document": case "@supports": case "@keyframes": hasBlock = true; hasIdentifier = true; break; case "@namespace": hasExpression = true; break; } if (hasIdentifier) { name += " " + ($(/^[^{]+/) || '').trim(); } if (hasBlock) { if (rules = $(this.block)) { return new(tree.Directive)(name, rules); } } else { if ((value = hasExpression ? $(this.expression) : $(this.entity)) && $(';')) { var directive = new(tree.Directive)(name, value); if (env.dumpLineNumbers) { directive.debugInfo = getDebugInfo(i, input, env); } return directive; } } restore(); }, // // A Value is a comma-delimited list of Expressions // // font-family: Baskerville, Georgia, serif; // // In a Rule, a Value represents everything after the `:`, // and before the `;`. // value: function () { var e, expressions = [], important; while (e = $(this.expression)) { expressions.push(e); if (! $(',')) { break } } if (expressions.length > 0) { return new(tree.Value)(expressions); } }, important: function () { if (input.charAt(i) === '!') { return $(/^! *important/); } }, sub: function () { var a, e; if ($('(')) { if (a = $(this.addition)) { e = new(tree.Expression)([a]); expect(')'); e.parens = true; return e; } } }, multiplication: function () { var m, a, op, operation, isSpaced, expression = []; if (m = $(this.operand)) { isSpaced = isWhitespace(input.charAt(i - 1)); while (!peek(/^\/[*\/]/) && (op = ($('/') || $('*')))) { if (a = $(this.operand)) { m.parensInOp = true; a.parensInOp = true; operation = new(tree.Operation)(op, [operation || m, a], isSpaced); isSpaced = isWhitespace(input.charAt(i - 1)); } else { break; } } return operation || m; } }, addition: function () { var m, a, op, operation, isSpaced; if (m = $(this.multiplication)) { isSpaced = isWhitespace(input.charAt(i - 1)); while ((op = $(/^[-+]\s+/) || (!isSpaced && ($('+') || $('-')))) && (a = $(this.multiplication))) { m.parensInOp = true; a.parensInOp = true; operation = new(tree.Operation)(op, [operation || m, a], isSpaced); isSpaced = isWhitespace(input.charAt(i - 1)); } return operation || m; } }, conditions: function () { var a, b, index = i, condition; if (a = $(this.condition)) { while ($(',') && (b = $(this.condition))) { condition = new(tree.Condition)('or', condition || a, b, index); } return condition || a; } }, condition: function () { var a, b, c, op, index = i, negate = false; if ($(/^not/)) { negate = true } expect('('); if (a = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) { if (op = $(/^(?:>=|=<|[<=>])/)) { if (b = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) { c = new(tree.Condition)(op, a, b, index, negate); } else { error('expected expression'); } } else { c = new(tree.Condition)('=', a, new(tree.Keyword)('true'), index, negate); } expect(')'); return $(/^and/) ? new(tree.Condition)('and', c, $(this.condition)) : c; } }, // // An operand is anything that can be part of an operation, // such as a Color, or a Variable // operand: function () { var negate, p = input.charAt(i + 1); if (input.charAt(i) === '-' && (p === '@' || p === '(')) { negate = $('-') } var o = $(this.sub) || $(this.entities.dimension) || $(this.entities.color) || $(this.entities.variable) || $(this.entities.call); if (negate) { o.parensInOp = true; o = new(tree.Negative)(o); } return o; }, // // Expressions either represent mathematical operations, // or white-space delimited Entities. // // 1px solid black // @var * 2 // expression: function () { var e, delim, entities = [], d; while (e = $(this.addition) || $(this.entity)) { entities.push(e); // operations do not allow keyword "/" dimension (e.g. small/20px) so we support that here if (!peek(/^\/[\/*]/) && (delim = $('/'))) { entities.push(new(tree.Anonymous)(delim)); } } if (entities.length > 0) { return new(tree.Expression)(entities); } }, property: function () { var name; if (name = $(/^(\*?-?[_a-zA-Z0-9-]+)\s*:/)) { return name[1]; } } } }; }; if (less.mode === 'browser' || less.mode === 'rhino') { // // Used by `@import` directives // less.Parser.importer = function (path, currentFileInfo, callback, env) { if (!/^([a-z-]+:)?\//.test(path) && currentFileInfo.currentDirectory) { path = currentFileInfo.currentDirectory + path; } var sheetEnv = env.toSheet(path); sheetEnv.processImports = false; sheetEnv.currentFileInfo = currentFileInfo; // We pass `true` as 3rd argument, to force the reload of the import. // This is so we can get the syntax tree as opposed to just the CSS output, // as we need this to evaluate the current stylesheet. loadStyleSheet(sheetEnv, function (e, root, data, sheet, _, path) { callback.call(null, e, root, path); }, true); }; } less.js-1.4.2/lib/less/rhino.js000066400000000000000000000062661217256642200163110ustar00rootroot00000000000000var name; function loadStyleSheet(sheet, callback, reload, remaining) { var endOfPath = Math.max(name.lastIndexOf('/'), name.lastIndexOf('\\')), sheetName = name.slice(0, endOfPath + 1) + sheet.href, contents = sheet.contents || {}, input = readFile(sheetName); input = input.replace(/^\xEF\xBB\xBF/, ''); contents[sheetName] = input; var parser = new less.Parser({ paths: [sheet.href.replace(/[\w\.-]+$/, '')], contents: contents }); parser.parse(input, function (e, root) { if (e) { return error(e, sheetName); } try { callback(e, root, input, sheet, { local: false, lastModified: 0, remaining: remaining }, sheetName); } catch(e) { error(e, sheetName); } }); } function writeFile(filename, content) { var fstream = new java.io.FileWriter(filename); var out = new java.io.BufferedWriter(fstream); out.write(content); out.close(); } // Command line integration via Rhino (function (args) { var output, compress = false, i, path; for(i = 0; i < args.length; i++) { switch(args[i]) { case "-x": compress = true; break; default: if (!name) { name = args[i]; } else if (!output) { output = args[i]; } else { print("unrecognised parameters"); print("input_file [output_file] [-x]"); } } } if (!name) { print('No files present in the fileset; Check your pattern match in build.xml'); quit(1); } path = name.split("/");path.pop();path=path.join("/") var input = readFile(name); if (!input) { print('lesscss: couldn\'t open file ' + name); quit(1); } var result; try { var parser = new less.Parser(); parser.parse(input, function (e, root) { if (e) { error(e, name); quit(1); } else { result = root.toCSS({compress: compress || false}); if (output) { writeFile(output, result); print("Written to " + output); } else { print(result); } quit(0); } }); } catch(e) { error(e, name); quit(1); } print("done"); }(arguments)); function error(e, filename) { var content = "Error : " + filename + "\n"; filename = e.filename || filename; if (e.message) { content += e.message + "\n"; } var errorline = function (e, i, classname) { if (e.extract[i]) { content += String(parseInt(e.line) + (i - 1)) + ":" + e.extract[i] + "\n"; } }; if (e.stack) { content += e.stack; } else if (e.extract) { content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':\n'; errorline(e, 0); errorline(e, 1); errorline(e, 2); } print(content); }less.js-1.4.2/lib/less/tree.js000066400000000000000000000026211217256642200161200ustar00rootroot00000000000000(function (tree) { tree.debugInfo = function(env, ctx) { var result=""; if (env.dumpLineNumbers && !env.compress) { switch(env.dumpLineNumbers) { case 'comments': result = tree.debugInfo.asComment(ctx); break; case 'mediaquery': result = tree.debugInfo.asMediaQuery(ctx); break; case 'all': result = tree.debugInfo.asComment(ctx)+tree.debugInfo.asMediaQuery(ctx); break; } } return result; }; tree.debugInfo.asComment = function(ctx) { return '/* line ' + ctx.debugInfo.lineNumber + ', ' + ctx.debugInfo.fileName + ' */\n'; }; tree.debugInfo.asMediaQuery = function(ctx) { return '@media -sass-debug-info{filename{font-family:' + ('file://' + ctx.debugInfo.fileName).replace(/([.:/\\])/g, function(a){if(a=='\\') a = '\/'; return '\\' + a}) + '}line{font-family:\\00003' + ctx.debugInfo.lineNumber + '}}\n'; }; tree.find = function (obj, fun) { for (var i = 0, r; i < obj.length; i++) { if (r = fun.call(obj, obj[i])) { return r } } return null; }; tree.jsify = function (obj) { if (Array.isArray(obj.value) && (obj.value.length > 1)) { return '[' + obj.value.map(function (v) { return v.toCSS(false) }).join(', ') + ']'; } else { return obj.toCSS(false); } }; })(require('./tree')); less.js-1.4.2/lib/less/tree/000077500000000000000000000000001217256642200155615ustar00rootroot00000000000000less.js-1.4.2/lib/less/tree/alpha.js000066400000000000000000000007611217256642200172100ustar00rootroot00000000000000(function (tree) { tree.Alpha = function (val) { this.value = val; }; tree.Alpha.prototype = { type: "Alpha", accept: function (visitor) { this.value = visitor.visit(this.value); }, eval: function (env) { if (this.value.eval) { this.value = this.value.eval(env) } return this; }, toCSS: function () { return "alpha(opacity=" + (this.value.toCSS ? this.value.toCSS() : this.value) + ")"; } }; })(require('../tree')); less.js-1.4.2/lib/less/tree/anonymous.js000066400000000000000000000010611217256642200201450ustar00rootroot00000000000000(function (tree) { tree.Anonymous = function (string) { this.value = string.value || string; }; tree.Anonymous.prototype = { type: "Anonymous", toCSS: function () { return this.value; }, eval: function () { return this }, compare: function (x) { if (!x.toCSS) { return -1; } var left = this.toCSS(), right = x.toCSS(); if (left === right) { return 0; } return left < right ? -1 : 1; } }; })(require('../tree')); less.js-1.4.2/lib/less/tree/assignment.js000066400000000000000000000010601217256642200202640ustar00rootroot00000000000000(function (tree) { tree.Assignment = function (key, val) { this.key = key; this.value = val; }; tree.Assignment.prototype = { type: "Assignment", accept: function (visitor) { this.value = visitor.visit(this.value); }, toCSS: function () { return this.key + '=' + (this.value.toCSS ? this.value.toCSS() : this.value); }, eval: function (env) { if (this.value.eval) { return new(tree.Assignment)(this.key, this.value.eval(env)); } return this; } }; })(require('../tree'));less.js-1.4.2/lib/less/tree/call.js000066400000000000000000000037241217256642200170400ustar00rootroot00000000000000(function (tree) { // // A function call node. // tree.Call = function (name, args, index, currentFileInfo) { this.name = name; this.args = args; this.index = index; this.currentFileInfo = currentFileInfo; }; tree.Call.prototype = { type: "Call", accept: function (visitor) { this.args = visitor.visit(this.args); }, // // When evaluating a function call, // we either find the function in `tree.functions` [1], // in which case we call it, passing the evaluated arguments, // if this returns null or we cannot find the function, we // simply print it out as it appeared originally [2]. // // The *functions.js* file contains the built-in functions. // // The reason why we evaluate the arguments, is in the case where // we try to pass a variable to a function, like: `saturate(@color)`. // The function should receive the value, not the variable. // eval: function (env) { var args = this.args.map(function (a) { return a.eval(env); }), nameLC = this.name.toLowerCase(), result, func; if (nameLC in tree.functions) { // 1. try { func = new tree.functionCall(env, this.currentFileInfo); result = func[nameLC].apply(func, args); if (result != null) { return result; } } catch (e) { throw { type: e.type || "Runtime", message: "error evaluating function `" + this.name + "`" + (e.message ? ': ' + e.message : ''), index: this.index, filename: this.currentFileInfo.filename }; } } // 2. return new(tree.Anonymous)(this.name + "(" + args.map(function (a) { return a.toCSS(env); }).join(', ') + ")"); }, toCSS: function (env) { return this.eval(env).toCSS(); } }; })(require('../tree')); less.js-1.4.2/lib/less/tree/color.js000066400000000000000000000114321217256642200172360ustar00rootroot00000000000000(function (tree) { // // RGB Colors - #ff0014, #eee // tree.Color = function (rgb, a) { // // The end goal here, is to parse the arguments // into an integer triplet, such as `128, 255, 0` // // This facilitates operations and conversions. // if (Array.isArray(rgb)) { this.rgb = rgb; } else if (rgb.length == 6) { this.rgb = rgb.match(/.{2}/g).map(function (c) { return parseInt(c, 16); }); } else { this.rgb = rgb.split('').map(function (c) { return parseInt(c + c, 16); }); } this.alpha = typeof(a) === 'number' ? a : 1; }; tree.Color.prototype = { type: "Color", eval: function () { return this }, luma: function () { return (0.2126 * this.rgb[0] / 255) + (0.7152 * this.rgb[1] / 255) + (0.0722 * this.rgb[2] / 255); }, // // If we have some transparency, the only way to represent it // is via `rgba`. Otherwise, we use the hex representation, // which has better compatibility with older browsers. // Values are capped between `0` and `255`, rounded and zero-padded. // toCSS: function (env, doNotCompress) { var compress = env && env.compress && !doNotCompress; if (this.alpha < 1.0) { return "rgba(" + this.rgb.map(function (c) { return Math.round(c); }).concat(this.alpha).join(',' + (compress ? '' : ' ')) + ")"; } else { var color = this.rgb.map(function (i) { i = Math.round(i); i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16); return i.length === 1 ? '0' + i : i; }).join(''); if (compress) { color = color.split(''); // Convert color to short format if (color[0] == color[1] && color[2] == color[3] && color[4] == color[5]) { color = color[0] + color[2] + color[4]; } else { color = color.join(''); } } return '#' + color; } }, // // Operations have to be done per-channel, if not, // channels will spill onto each other. Once we have // our result, in the form of an integer triplet, // we create a new Color node to hold the result. // operate: function (env, op, other) { var result = []; if (! (other instanceof tree.Color)) { other = other.toColor(); } for (var c = 0; c < 3; c++) { result[c] = tree.operate(env, op, this.rgb[c], other.rgb[c]); } return new(tree.Color)(result, this.alpha + other.alpha); }, toHSL: function () { var r = this.rgb[0] / 255, g = this.rgb[1] / 255, b = this.rgb[2] / 255, a = this.alpha; var max = Math.max(r, g, b), min = Math.min(r, g, b); var h, s, l = (max + min) / 2, d = max - min; if (max === min) { h = s = 0; } else { s = l > 0.5 ? d / (2 - max - min) : d / (max + min); switch (max) { case r: h = (g - b) / d + (g < b ? 6 : 0); break; case g: h = (b - r) / d + 2; break; case b: h = (r - g) / d + 4; break; } h /= 6; } return { h: h * 360, s: s, l: l, a: a }; }, //Adapted from http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript toHSV: function () { var r = this.rgb[0] / 255, g = this.rgb[1] / 255, b = this.rgb[2] / 255, a = this.alpha; var max = Math.max(r, g, b), min = Math.min(r, g, b); var h, s, v = max; var d = max - min; if (max === 0) { s = 0; } else { s = d / max; } if (max === min) { h = 0; } else { switch(max){ case r: h = (g - b) / d + (g < b ? 6 : 0); break; case g: h = (b - r) / d + 2; break; case b: h = (r - g) / d + 4; break; } h /= 6; } return { h: h * 360, s: s, v: v, a: a }; }, toARGB: function () { var argb = [Math.round(this.alpha * 255)].concat(this.rgb); return '#' + argb.map(function (i) { i = Math.round(i); i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16); return i.length === 1 ? '0' + i : i; }).join(''); }, compare: function (x) { if (!x.rgb) { return -1; } return (x.rgb[0] === this.rgb[0] && x.rgb[1] === this.rgb[1] && x.rgb[2] === this.rgb[2] && x.alpha === this.alpha) ? 0 : -1; } }; })(require('../tree')); less.js-1.4.2/lib/less/tree/comment.js000066400000000000000000000004711217256642200175630ustar00rootroot00000000000000(function (tree) { tree.Comment = function (value, silent) { this.value = value; this.silent = !!silent; }; tree.Comment.prototype = { type: "Comment", toCSS: function (env) { return env.compress ? '' : this.value; }, eval: function () { return this } }; })(require('../tree')); less.js-1.4.2/lib/less/tree/condition.js000066400000000000000000000027541217256642200201150ustar00rootroot00000000000000(function (tree) { tree.Condition = function (op, l, r, i, negate) { this.op = op.trim(); this.lvalue = l; this.rvalue = r; this.index = i; this.negate = negate; }; tree.Condition.prototype = { type: "Condition", accept: function (visitor) { this.lvalue = visitor.visit(this.lvalue); this.rvalue = visitor.visit(this.rvalue); }, eval: function (env) { var a = this.lvalue.eval(env), b = this.rvalue.eval(env); var i = this.index, result; var result = (function (op) { switch (op) { case 'and': return a && b; case 'or': return a || b; default: if (a.compare) { result = a.compare(b); } else if (b.compare) { result = b.compare(a); } else { throw { type: "Type", message: "Unable to perform comparison", index: i }; } switch (result) { case -1: return op === '<' || op === '=<'; case 0: return op === '=' || op === '>=' || op === '=<'; case 1: return op === '>' || op === '>='; } } })(this.op); return this.negate ? !result : result; } }; })(require('../tree')); less.js-1.4.2/lib/less/tree/dimension.js000066400000000000000000000207411217256642200201100ustar00rootroot00000000000000(function (tree) { // // A number with a unit // tree.Dimension = function (value, unit) { this.value = parseFloat(value); this.unit = (unit && unit instanceof tree.Unit) ? unit : new(tree.Unit)(unit ? [unit] : undefined); }; tree.Dimension.prototype = { type: "Dimension", accept: function (visitor) { this.unit = visitor.visit(this.unit); }, eval: function (env) { return this; }, toColor: function () { return new(tree.Color)([this.value, this.value, this.value]); }, toCSS: function (env) { if ((env && env.strictUnits) && !this.unit.isSingular()) { throw new Error("Multiple units in dimension. Correct the units or use the unit function. Bad unit: "+this.unit.toString()); } var value = this.value, strValue = String(value); if (value !== 0 && value < 0.000001 && value > -0.000001) { // would be output 1e-6 etc. strValue = value.toFixed(20).replace(/0+$/, ""); } if (env && env.compress) { // Zero values doesn't need a unit if (value === 0 && !this.unit.isAngle()) { return strValue; } // Float values doesn't need a leading zero if (value > 0 && value < 1) { strValue = (strValue).substr(1); } } return strValue + this.unit.toCSS(env); }, // In an operation between two Dimensions, // we default to the first Dimension's unit, // so `1px + 2` will yield `3px`. operate: function (env, op, other) { var value = tree.operate(env, op, this.value, other.value), unit = this.unit.clone(); if (op === '+' || op === '-') { if (unit.numerator.length === 0 && unit.denominator.length === 0) { unit.numerator = other.unit.numerator.slice(0); unit.denominator = other.unit.denominator.slice(0); } else if (other.unit.numerator.length == 0 && unit.denominator.length == 0) { // do nothing } else { other = other.convertTo(this.unit.usedUnits()); if(env.strictUnits && other.unit.toString() !== unit.toString()) { throw new Error("Incompatible units. Change the units or use the unit function. Bad units: '" + unit.toString() + "' and '" + other.unit.toString() + "'."); } value = tree.operate(env, op, this.value, other.value); } } else if (op === '*') { unit.numerator = unit.numerator.concat(other.unit.numerator).sort(); unit.denominator = unit.denominator.concat(other.unit.denominator).sort(); unit.cancel(); } else if (op === '/') { unit.numerator = unit.numerator.concat(other.unit.denominator).sort(); unit.denominator = unit.denominator.concat(other.unit.numerator).sort(); unit.cancel(); } return new(tree.Dimension)(value, unit); }, compare: function (other) { if (other instanceof tree.Dimension) { var a = this.unify(), b = other.unify(), aValue = a.value, bValue = b.value; if (bValue > aValue) { return -1; } else if (bValue < aValue) { return 1; } else { if (!b.unit.isEmpty() && a.unit.compare(b.unit) !== 0) { return -1; } return 0; } } else { return -1; } }, unify: function () { return this.convertTo({ length: 'm', duration: 's', angle: 'rad' }); }, convertTo: function (conversions) { var value = this.value, unit = this.unit.clone(), i, groupName, group, conversion, targetUnit, derivedConversions = {}; if (typeof conversions === 'string') { for(i in tree.UnitConversions) { if (tree.UnitConversions[i].hasOwnProperty(conversions)) { derivedConversions = {}; derivedConversions[i] = conversions; } } conversions = derivedConversions; } for (groupName in conversions) { if (conversions.hasOwnProperty(groupName)) { targetUnit = conversions[groupName]; group = tree.UnitConversions[groupName]; unit.map(function (atomicUnit, denominator) { if (group.hasOwnProperty(atomicUnit)) { if (denominator) { value = value / (group[atomicUnit] / group[targetUnit]); } else { value = value * (group[atomicUnit] / group[targetUnit]); } return targetUnit; } return atomicUnit; }); } } unit.cancel(); return new(tree.Dimension)(value, unit); } }; // http://www.w3.org/TR/css3-values/#absolute-lengths tree.UnitConversions = { length: { 'm': 1, 'cm': 0.01, 'mm': 0.001, 'in': 0.0254, 'pt': 0.0254 / 72, 'pc': 0.0254 / 72 * 12 }, duration: { 's': 1, 'ms': 0.001 }, angle: { 'rad': 1/(2*Math.PI), 'deg': 1/360, 'grad': 1/400, 'turn': 1 } }; tree.Unit = function (numerator, denominator, backupUnit) { this.numerator = numerator ? numerator.slice(0).sort() : []; this.denominator = denominator ? denominator.slice(0).sort() : []; this.backupUnit = backupUnit; }; tree.Unit.prototype = { type: "Unit", clone: function () { return new tree.Unit(this.numerator.slice(0), this.denominator.slice(0), this.backupUnit); }, toCSS: function (env) { if (this.numerator.length >= 1) { return this.numerator[0]; } if (this.denominator.length >= 1) { return this.denominator[0]; } if ((!env || !env.strictUnits) && this.backupUnit) { return this.backupUnit; } return ""; }, toString: function () { var i, returnStr = this.numerator.join("*"); for (i = 0; i < this.denominator.length; i++) { returnStr += "/" + this.denominator[i]; } return returnStr; }, compare: function (other) { return this.is(other.toString()) ? 0 : -1; }, is: function (unitString) { return this.toString() === unitString; }, isAngle: function () { return tree.UnitConversions.angle.hasOwnProperty(this.toCSS()); }, isEmpty: function () { return this.numerator.length == 0 && this.denominator.length == 0; }, isSingular: function() { return this.numerator.length <= 1 && this.denominator.length == 0; }, map: function(callback) { var i; for (i = 0; i < this.numerator.length; i++) { this.numerator[i] = callback(this.numerator[i], false); } for (i = 0; i < this.denominator.length; i++) { this.denominator[i] = callback(this.denominator[i], true); } }, usedUnits: function() { var group, groupName, result = {}; for (groupName in tree.UnitConversions) { if (tree.UnitConversions.hasOwnProperty(groupName)) { group = tree.UnitConversions[groupName]; this.map(function (atomicUnit) { if (group.hasOwnProperty(atomicUnit) && !result[groupName]) { result[groupName] = atomicUnit; } return atomicUnit; }); } } return result; }, cancel: function () { var counter = {}, atomicUnit, i, backup; for (i = 0; i < this.numerator.length; i++) { atomicUnit = this.numerator[i]; if (!backup) { backup = atomicUnit; } counter[atomicUnit] = (counter[atomicUnit] || 0) + 1; } for (i = 0; i < this.denominator.length; i++) { atomicUnit = this.denominator[i]; if (!backup) { backup = atomicUnit; } counter[atomicUnit] = (counter[atomicUnit] || 0) - 1; } this.numerator = []; this.denominator = []; for (atomicUnit in counter) { if (counter.hasOwnProperty(atomicUnit)) { var count = counter[atomicUnit]; if (count > 0) { for (i = 0; i < count; i++) { this.numerator.push(atomicUnit); } } else if (count < 0) { for (i = 0; i < -count; i++) { this.denominator.push(atomicUnit); } } } } if (this.numerator.length === 0 && this.denominator.length === 0 && backup) { this.backupUnit = backup; } this.numerator.sort(); this.denominator.sort(); } }; })(require('../tree')); less.js-1.4.2/lib/less/tree/directive.js000066400000000000000000000027201217256642200200760ustar00rootroot00000000000000(function (tree) { tree.Directive = function (name, value) { this.name = name; if (Array.isArray(value)) { this.ruleset = new(tree.Ruleset)([], value); this.ruleset.allowImports = true; } else { this.value = value; } }; tree.Directive.prototype = { type: "Directive", accept: function (visitor) { this.ruleset = visitor.visit(this.ruleset); this.value = visitor.visit(this.value); }, toCSS: function (env) { if (this.ruleset) { this.ruleset.root = true; return this.name + (env.compress ? '{' : ' {\n ') + this.ruleset.toCSS(env).trim().replace(/\n/g, '\n ') + (env.compress ? '}': '\n}\n'); } else { return this.name + ' ' + this.value.toCSS() + ';\n'; } }, eval: function (env) { var evaldDirective = this; if (this.ruleset) { env.frames.unshift(this); evaldDirective = new(tree.Directive)(this.name); evaldDirective.ruleset = this.ruleset.eval(env); env.frames.shift(); } return evaldDirective; }, variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) }, find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) }, rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) } }; })(require('../tree')); less.js-1.4.2/lib/less/tree/element.js000066400000000000000000000045551217256642200175610ustar00rootroot00000000000000(function (tree) { tree.Element = function (combinator, value, index) { this.combinator = combinator instanceof tree.Combinator ? combinator : new(tree.Combinator)(combinator); if (typeof(value) === 'string') { this.value = value.trim(); } else if (value) { this.value = value; } else { this.value = ""; } this.index = index; }; tree.Element.prototype = { type: "Element", accept: function (visitor) { this.combinator = visitor.visit(this.combinator); this.value = visitor.visit(this.value); }, eval: function (env) { return new(tree.Element)(this.combinator, this.value.eval ? this.value.eval(env) : this.value, this.index); }, toCSS: function (env) { var value = (this.value.toCSS ? this.value.toCSS(env) : this.value); if (value == '' && this.combinator.value.charAt(0) == '&') { return ''; } else { return this.combinator.toCSS(env || {}) + value; } } }; tree.Attribute = function (key, op, value) { this.key = key; this.op = op; this.value = value; }; tree.Attribute.prototype = { type: "Attribute", accept: function (visitor) { this.value = visitor.visit(this.value); }, eval: function (env) { return new(tree.Attribute)(this.key.eval ? this.key.eval(env) : this.key, this.op, (this.value && this.value.eval) ? this.value.eval(env) : this.value); }, toCSS: function (env) { var value = this.key.toCSS ? this.key.toCSS(env) : this.key; if (this.op) { value += this.op; value += (this.value.toCSS ? this.value.toCSS(env) : this.value); } return '[' + value + ']'; } }; tree.Combinator = function (value) { if (value === ' ') { this.value = ' '; } else { this.value = value ? value.trim() : ""; } }; tree.Combinator.prototype = { type: "Combinator", toCSS: function (env) { return { '' : '', ' ' : ' ', ':' : ' :', '+' : env.compress ? '+' : ' + ', '~' : env.compress ? '~' : ' ~ ', '>' : env.compress ? '>' : ' > ', '|' : env.compress ? '|' : ' | ' }[this.value]; } }; })(require('../tree')); less.js-1.4.2/lib/less/tree/expression.js000066400000000000000000000027041217256642200203210ustar00rootroot00000000000000(function (tree) { tree.Expression = function (value) { this.value = value; }; tree.Expression.prototype = { type: "Expression", accept: function (visitor) { this.value = visitor.visit(this.value); }, eval: function (env) { var returnValue, inParenthesis = this.parens && !this.parensInOp, doubleParen = false; if (inParenthesis) { env.inParenthesis(); } if (this.value.length > 1) { returnValue = new(tree.Expression)(this.value.map(function (e) { return e.eval(env); })); } else if (this.value.length === 1) { if (this.value[0].parens && !this.value[0].parensInOp) { doubleParen = true; } returnValue = this.value[0].eval(env); } else { returnValue = this; } if (inParenthesis) { env.outOfParenthesis(); } if (this.parens && this.parensInOp && !(env.isMathOn()) && !doubleParen) { returnValue = new(tree.Paren)(returnValue); } return returnValue; }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS ? e.toCSS(env) : ''; }).join(' '); }, throwAwayComments: function () { this.value = this.value.filter(function(v) { return !(v instanceof tree.Comment); }); } }; })(require('../tree')); less.js-1.4.2/lib/less/tree/extend.js000066400000000000000000000020751217256642200174120ustar00rootroot00000000000000(function (tree) { tree.Extend = function Extend(selector, option, index) { this.selector = selector; this.option = option; this.index = index; switch(option) { case "all": this.allowBefore = true; this.allowAfter = true; break; default: this.allowBefore = false; this.allowAfter = false; break; } }; tree.Extend.prototype = { type: "Extend", accept: function (visitor) { this.selector = visitor.visit(this.selector); }, eval: function (env) { return new(tree.Extend)(this.selector.eval(env), this.option, this.index); }, clone: function (env) { return new(tree.Extend)(this.selector, this.option, this.index); }, findSelfSelectors: function (selectors) { var selfElements = [], i; for(i = 0; i < selectors.length; i++) { selfElements = selfElements.concat(selectors[i].elements); } this.selfSelectors = [{ elements: selfElements }]; } }; })(require('../tree')); less.js-1.4.2/lib/less/tree/import.js000066400000000000000000000066331217256642200174410ustar00rootroot00000000000000(function (tree) { // // CSS @import node // // The general strategy here is that we don't want to wait // for the parsing to be completed, before we start importing // the file. That's because in the context of a browser, // most of the time will be spent waiting for the server to respond. // // On creation, we push the import path to our import queue, though // `import,push`, we also pass it a callback, which it'll call once // the file has been fetched, and parsed. // tree.Import = function (path, features, options, index, currentFileInfo) { var that = this; this.options = options; this.index = index; this.path = path; this.features = features; this.currentFileInfo = currentFileInfo; if (this.options.less !== undefined) { this.css = !this.options.less; } else { var pathValue = this.getPath(); if (pathValue && /css([\?;].*)?$/.test(pathValue)) { this.css = true; } } }; // // The actual import node doesn't return anything, when converted to CSS. // The reason is that it's used at the evaluation stage, so that the rules // it imports can be treated like any other rules. // // In `eval`, we make sure all Import nodes get evaluated, recursively, so // we end up with a flat structure, which can easily be imported in the parent // ruleset. // tree.Import.prototype = { type: "Import", accept: function (visitor) { this.features = visitor.visit(this.features); this.path = visitor.visit(this.path); this.root = visitor.visit(this.root); }, toCSS: function (env) { var features = this.features ? ' ' + this.features.toCSS(env) : ''; if (this.css) { return "@import " + this.path.toCSS() + features + ';\n'; } else { return ""; } }, getPath: function () { if (this.path instanceof tree.Quoted) { var path = this.path.value; return (this.css !== undefined || /(\.[a-z]*$)|([\?;].*)$/.test(path)) ? path : path + '.less'; } else if (this.path instanceof tree.URL) { return this.path.value.value; } return null; }, evalForImport: function (env) { return new(tree.Import)(this.path.eval(env), this.features, this.options, this.index, this.currentFileInfo); }, evalPath: function (env) { var path = this.path.eval(env); var rootpath = this.currentFileInfo && this.currentFileInfo.rootpath; if (rootpath && !(path instanceof tree.URL)) { var pathValue = path.value; // Add the base path if the import is relative if (pathValue && env.isPathRelative(pathValue)) { path.value = rootpath + pathValue; } } return path; }, eval: function (env) { var ruleset, features = this.features && this.features.eval(env); if (this.skip) { return []; } if (this.css) { var newImport = new(tree.Import)(this.evalPath(env), features, this.options, this.index); if (!newImport.css && this.error) { throw this.error; } return newImport; } else { ruleset = new(tree.Ruleset)([], this.root.rules.slice(0)); ruleset.evalImports(env); return this.features ? new(tree.Media)(ruleset.rules, this.features.value) : ruleset.rules; } } }; })(require('../tree')); less.js-1.4.2/lib/less/tree/javascript.js000066400000000000000000000031021217256642200202610ustar00rootroot00000000000000(function (tree) { tree.JavaScript = function (string, index, escaped) { this.escaped = escaped; this.expression = string; this.index = index; }; tree.JavaScript.prototype = { type: "JavaScript", eval: function (env) { var result, that = this, context = {}; var expression = this.expression.replace(/@\{([\w-]+)\}/g, function (_, name) { return tree.jsify(new(tree.Variable)('@' + name, that.index).eval(env)); }); try { expression = new(Function)('return (' + expression + ')'); } catch (e) { throw { message: "JavaScript evaluation error: `" + expression + "`" , index: this.index }; } for (var k in env.frames[0].variables()) { context[k.slice(1)] = { value: env.frames[0].variables()[k].value, toJS: function () { return this.value.eval(env).toCSS(); } }; } try { result = expression.call(context); } catch (e) { throw { message: "JavaScript evaluation error: '" + e.name + ': ' + e.message + "'" , index: this.index }; } if (typeof(result) === 'string') { return new(tree.Quoted)('"' + result + '"', result, this.escaped, this.index); } else if (Array.isArray(result)) { return new(tree.Anonymous)(result.join(', ')); } else { return new(tree.Anonymous)(result); } } }; })(require('../tree')); less.js-1.4.2/lib/less/tree/keyword.js000066400000000000000000000007741217256642200176130ustar00rootroot00000000000000(function (tree) { tree.Keyword = function (value) { this.value = value }; tree.Keyword.prototype = { type: "Keyword", eval: function () { return this; }, toCSS: function () { return this.value; }, compare: function (other) { if (other instanceof tree.Keyword) { return other.value === this.value ? 0 : 1; } else { return -1; } } }; tree.True = new(tree.Keyword)('true'); tree.False = new(tree.Keyword)('false'); })(require('../tree')); less.js-1.4.2/lib/less/tree/media.js000066400000000000000000000104371217256642200172030ustar00rootroot00000000000000(function (tree) { tree.Media = function (value, features) { var selectors = this.emptySelectors(); this.features = new(tree.Value)(features); this.ruleset = new(tree.Ruleset)(selectors, value); this.ruleset.allowImports = true; }; tree.Media.prototype = { type: "Media", accept: function (visitor) { this.features = visitor.visit(this.features); this.ruleset = visitor.visit(this.ruleset); }, toCSS: function (env) { var features = this.features.toCSS(env); return '@media ' + features + (env.compress ? '{' : ' {\n ') + this.ruleset.toCSS(env).trim().replace(/\n/g, '\n ') + (env.compress ? '}': '\n}\n'); }, eval: function (env) { if (!env.mediaBlocks) { env.mediaBlocks = []; env.mediaPath = []; } var media = new(tree.Media)([], []); if(this.debugInfo) { this.ruleset.debugInfo = this.debugInfo; media.debugInfo = this.debugInfo; } var strictMathBypass = false; if (!env.strictMath) { strictMathBypass = true; env.strictMath = true; } try { media.features = this.features.eval(env); } finally { if (strictMathBypass) { env.strictMath = false; } } env.mediaPath.push(media); env.mediaBlocks.push(media); env.frames.unshift(this.ruleset); media.ruleset = this.ruleset.eval(env); env.frames.shift(); env.mediaPath.pop(); return env.mediaPath.length === 0 ? media.evalTop(env) : media.evalNested(env) }, variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) }, find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) }, rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) }, emptySelectors: function() { var el = new(tree.Element)('', '&', 0); return [new(tree.Selector)([el])]; }, evalTop: function (env) { var result = this; // Render all dependent Media blocks. if (env.mediaBlocks.length > 1) { var selectors = this.emptySelectors(); result = new(tree.Ruleset)(selectors, env.mediaBlocks); result.multiMedia = true; } delete env.mediaBlocks; delete env.mediaPath; return result; }, evalNested: function (env) { var i, value, path = env.mediaPath.concat([this]); // Extract the media-query conditions separated with `,` (OR). for (i = 0; i < path.length; i++) { value = path[i].features instanceof tree.Value ? path[i].features.value : path[i].features; path[i] = Array.isArray(value) ? value : [value]; } // Trace all permutations to generate the resulting media-query. // // (a, b and c) with nested (d, e) -> // a and d // a and e // b and c and d // b and c and e this.features = new(tree.Value)(this.permute(path).map(function (path) { path = path.map(function (fragment) { return fragment.toCSS ? fragment : new(tree.Anonymous)(fragment); }); for(i = path.length - 1; i > 0; i--) { path.splice(i, 0, new(tree.Anonymous)("and")); } return new(tree.Expression)(path); })); // Fake a tree-node that doesn't output anything. return new(tree.Ruleset)([], []); }, permute: function (arr) { if (arr.length === 0) { return []; } else if (arr.length === 1) { return arr[0]; } else { var result = []; var rest = this.permute(arr.slice(1)); for (var i = 0; i < rest.length; i++) { for (var j = 0; j < arr[0].length; j++) { result.push([arr[0][j]].concat(rest[i])); } } return result; } }, bubbleSelectors: function (selectors) { this.ruleset = new(tree.Ruleset)(selectors.slice(0), [this.ruleset]); } }; })(require('../tree')); less.js-1.4.2/lib/less/tree/mixin.js000066400000000000000000000222451217256642200172500ustar00rootroot00000000000000(function (tree) { tree.mixin = {}; tree.mixin.Call = function (elements, args, index, currentFileInfo, important) { this.selector = new(tree.Selector)(elements); this.arguments = args; this.index = index; this.currentFileInfo = currentFileInfo; this.important = important; }; tree.mixin.Call.prototype = { type: "MixinCall", accept: function (visitor) { this.selector = visitor.visit(this.selector); this.arguments = visitor.visit(this.arguments); }, eval: function (env) { var mixins, mixin, args, rules = [], match = false, i, m, f, isRecursive, isOneFound; args = this.arguments && this.arguments.map(function (a) { return { name: a.name, value: a.value.eval(env) }; }); for (i = 0; i < env.frames.length; i++) { if ((mixins = env.frames[i].find(this.selector)).length > 0) { isOneFound = true; for (m = 0; m < mixins.length; m++) { mixin = mixins[m]; isRecursive = false; for(f = 0; f < env.frames.length; f++) { if ((!(mixin instanceof tree.mixin.Definition)) && mixin === (env.frames[f].originalRuleset || env.frames[f])) { isRecursive = true; break; } } if (isRecursive) { continue; } if (mixin.matchArgs(args, env)) { if (!mixin.matchCondition || mixin.matchCondition(args, env)) { try { Array.prototype.push.apply( rules, mixin.eval(env, args, this.important).rules); } catch (e) { throw { message: e.message, index: this.index, filename: this.currentFileInfo.filename, stack: e.stack }; } } match = true; } } if (match) { return rules; } } } if (isOneFound) { throw { type: 'Runtime', message: 'No matching definition was found for `' + this.selector.toCSS().trim() + '(' + (args ? args.map(function (a) { var argValue = ""; if (a.name) { argValue += a.name + ":"; } if (a.value.toCSS) { argValue += a.value.toCSS(); } else { argValue += "???"; } return argValue; }).join(', ') : "") + ")`", index: this.index, filename: this.currentFileInfo.filename }; } else { throw { type: 'Name', message: this.selector.toCSS().trim() + " is undefined", index: this.index, filename: this.currentFileInfo.filename }; } } }; tree.mixin.Definition = function (name, params, rules, condition, variadic) { this.name = name; this.selectors = [new(tree.Selector)([new(tree.Element)(null, name)])]; this.params = params; this.condition = condition; this.variadic = variadic; this.arity = params.length; this.rules = rules; this._lookups = {}; this.required = params.reduce(function (count, p) { if (!p.name || (p.name && !p.value)) { return count + 1 } else { return count } }, 0); this.parent = tree.Ruleset.prototype; this.frames = []; }; tree.mixin.Definition.prototype = { type: "MixinDefinition", accept: function (visitor) { this.params = visitor.visit(this.params); this.rules = visitor.visit(this.rules); this.condition = visitor.visit(this.condition); }, toCSS: function () { return ""; }, variable: function (name) { return this.parent.variable.call(this, name); }, variables: function () { return this.parent.variables.call(this); }, find: function () { return this.parent.find.apply(this, arguments); }, rulesets: function () { return this.parent.rulesets.apply(this); }, evalParams: function (env, mixinEnv, args, evaldArguments) { var frame = new(tree.Ruleset)(null, []), varargs, arg, params = this.params.slice(0), i, j, val, name, isNamedFound, argIndex; mixinEnv = new tree.evalEnv(mixinEnv, [frame].concat(mixinEnv.frames)); if (args) { args = args.slice(0); for(i = 0; i < args.length; i++) { arg = args[i]; if (name = (arg && arg.name)) { isNamedFound = false; for(j = 0; j < params.length; j++) { if (!evaldArguments[j] && name === params[j].name) { evaldArguments[j] = arg.value.eval(env); frame.rules.unshift(new(tree.Rule)(name, arg.value.eval(env))); isNamedFound = true; break; } } if (isNamedFound) { args.splice(i, 1); i--; continue; } else { throw { type: 'Runtime', message: "Named argument for " + this.name + ' ' + args[i].name + ' not found' }; } } } } argIndex = 0; for (i = 0; i < params.length; i++) { if (evaldArguments[i]) continue; arg = args && args[argIndex]; if (name = params[i].name) { if (params[i].variadic && args) { varargs = []; for (j = argIndex; j < args.length; j++) { varargs.push(args[j].value.eval(env)); } frame.rules.unshift(new(tree.Rule)(name, new(tree.Expression)(varargs).eval(env))); } else { val = arg && arg.value; if (val) { val = val.eval(env); } else if (params[i].value) { val = params[i].value.eval(mixinEnv); frame.resetCache(); } else { throw { type: 'Runtime', message: "wrong number of arguments for " + this.name + ' (' + args.length + ' for ' + this.arity + ')' }; } frame.rules.unshift(new(tree.Rule)(name, val)); evaldArguments[i] = val; } } if (params[i].variadic && args) { for (j = argIndex; j < args.length; j++) { evaldArguments[j] = args[j].value.eval(env); } } argIndex++; } return frame; }, eval: function (env, args, important) { var _arguments = [], mixinFrames = this.frames.concat(env.frames), frame = this.evalParams(env, new(tree.evalEnv)(env, mixinFrames), args, _arguments), context, rules, start, ruleset; frame.rules.unshift(new(tree.Rule)('@arguments', new(tree.Expression)(_arguments).eval(env))); rules = important ? this.parent.makeImportant.apply(this).rules : this.rules.slice(0); ruleset = new(tree.Ruleset)(null, rules).eval(new(tree.evalEnv)(env, [this, frame].concat(mixinFrames))); ruleset.originalRuleset = this; return ruleset; }, matchCondition: function (args, env) { if (this.condition && !this.condition.eval( new(tree.evalEnv)(env, [this.evalParams(env, new(tree.evalEnv)(env, this.frames.concat(env.frames)), args, [])] .concat(env.frames)))) { return false; } return true; }, matchArgs: function (args, env) { var argsLength = (args && args.length) || 0, len, frame; if (! this.variadic) { if (argsLength < this.required) { return false } if (argsLength > this.params.length) { return false } if ((this.required > 0) && (argsLength > this.params.length)) { return false } } len = Math.min(argsLength, this.arity); for (var i = 0; i < len; i++) { if (!this.params[i].name && !this.params[i].variadic) { if (args[i].value.eval(env).toCSS() != this.params[i].value.eval(env).toCSS()) { return false; } } } return true; } }; })(require('../tree')); less.js-1.4.2/lib/less/tree/negative.js000066400000000000000000000010471217256642200177230ustar00rootroot00000000000000(function (tree) { tree.Negative = function (node) { this.value = node; }; tree.Negative.prototype = { type: "Negative", accept: function (visitor) { this.value = visitor.visit(this.value); }, toCSS: function (env) { return '-' + this.value.toCSS(env); }, eval: function (env) { if (env.isMathOn()) { return (new(tree.Operation)('*', [new(tree.Dimension)(-1), this.value])).eval(env); } return new(tree.Negative)(this.value.eval(env)); } }; })(require('../tree')); less.js-1.4.2/lib/less/tree/operation.js000066400000000000000000000030341217256642200201170ustar00rootroot00000000000000(function (tree) { tree.Operation = function (op, operands, isSpaced) { this.op = op.trim(); this.operands = operands; this.isSpaced = isSpaced; }; tree.Operation.prototype = { type: "Operation", accept: function (visitor) { this.operands = visitor.visit(this.operands); }, eval: function (env) { var a = this.operands[0].eval(env), b = this.operands[1].eval(env), temp; if (env.isMathOn()) { if (a instanceof tree.Dimension && b instanceof tree.Color) { if (this.op === '*' || this.op === '+') { temp = b, b = a, a = temp; } else { throw { type: "Operation", message: "Can't substract or divide a color from a number" }; } } if (!a.operate) { throw { type: "Operation", message: "Operation on an invalid type" }; } return a.operate(env, this.op, b); } else { return new(tree.Operation)(this.op, [a, b], this.isSpaced); } }, toCSS: function (env) { var separator = this.isSpaced ? " " : ""; return this.operands[0].toCSS() + separator + this.op + separator + this.operands[1].toCSS(); } }; tree.operate = function (env, op, a, b) { switch (op) { case '+': return a + b; case '-': return a - b; case '*': return a * b; case '/': return a / b; } }; })(require('../tree')); less.js-1.4.2/lib/less/tree/paren.js000066400000000000000000000006411217256642200172250ustar00rootroot00000000000000 (function (tree) { tree.Paren = function (node) { this.value = node; }; tree.Paren.prototype = { type: "Paren", accept: function (visitor) { this.value = visitor.visit(this.value); }, toCSS: function (env) { return '(' + this.value.toCSS(env).trim() + ')'; }, eval: function (env) { return new(tree.Paren)(this.value.eval(env)); } }; })(require('../tree')); less.js-1.4.2/lib/less/tree/quoted.js000066400000000000000000000024731217256642200174260ustar00rootroot00000000000000(function (tree) { tree.Quoted = function (str, content, escaped, index, currentFileInfo) { this.escaped = escaped; this.value = content || ''; this.quote = str.charAt(0); this.index = index; this.currentFileInfo = currentFileInfo; }; tree.Quoted.prototype = { type: "Quoted", toCSS: function () { if (this.escaped) { return this.value; } else { return this.quote + this.value + this.quote; } }, eval: function (env) { var that = this; var value = this.value.replace(/`([^`]+)`/g, function (_, exp) { return new(tree.JavaScript)(exp, that.index, true).eval(env).value; }).replace(/@\{([\w-]+)\}/g, function (_, name) { var v = new(tree.Variable)('@' + name, that.index, that.currentFileInfo).eval(env, true); return (v instanceof tree.Quoted) ? v.value : v.toCSS(); }); return new(tree.Quoted)(this.quote + value + this.quote, value, this.escaped, this.index); }, compare: function (x) { if (!x.toCSS) { return -1; } var left = this.toCSS(), right = x.toCSS(); if (left === right) { return 0; } return left < right ? -1 : 1; } }; })(require('../tree')); less.js-1.4.2/lib/less/tree/rule.js000066400000000000000000000035711217256642200170740ustar00rootroot00000000000000(function (tree) { tree.Rule = function (name, value, important, index, currentFileInfo, inline) { this.name = name; this.value = (value instanceof tree.Value) ? value : new(tree.Value)([value]); this.important = important ? ' ' + important.trim() : ''; this.index = index; this.currentFileInfo = currentFileInfo; this.inline = inline || false; if (name.charAt(0) === '@') { this.variable = true; } else { this.variable = false } }; tree.Rule.prototype = { type: "Rule", accept: function (visitor) { this.value = visitor.visit(this.value); }, toCSS: function (env) { if (this.variable) { return "" } else { try { return this.name + (env.compress ? ':' : ': ') + this.value.toCSS(env) + this.important + (this.inline ? "" : ";"); } catch(e) { e.index = this.index; e.filename = this.currentFileInfo.filename; throw e; } } }, eval: function (env) { var strictMathBypass = false; if (this.name === "font" && !env.strictMath) { strictMathBypass = true; env.strictMath = true; } try { return new(tree.Rule)(this.name, this.value.eval(env), this.important, this.index, this.currentFileInfo, this.inline); } finally { if (strictMathBypass) { env.strictMath = false; } } }, makeImportant: function () { return new(tree.Rule)(this.name, this.value, "!important", this.index, this.currentFileInfo, this.inline); } }; })(require('../tree')); less.js-1.4.2/lib/less/tree/ruleset.js000066400000000000000000000415521217256642200176110ustar00rootroot00000000000000(function (tree) { tree.Ruleset = function (selectors, rules, strictImports) { this.selectors = selectors; this.rules = rules; this._lookups = {}; this.strictImports = strictImports; }; tree.Ruleset.prototype = { type: "Ruleset", accept: function (visitor) { this.selectors = visitor.visit(this.selectors); this.rules = visitor.visit(this.rules); }, eval: function (env) { var selectors = this.selectors && this.selectors.map(function (s) { return s.eval(env) }); var ruleset = new(tree.Ruleset)(selectors, this.rules.slice(0), this.strictImports); var rules; ruleset.originalRuleset = this; ruleset.root = this.root; ruleset.firstRoot = this.firstRoot; ruleset.allowImports = this.allowImports; if(this.debugInfo) { ruleset.debugInfo = this.debugInfo; } // push the current ruleset to the frames stack env.frames.unshift(ruleset); // currrent selectors if (!env.selectors) { env.selectors = []; } env.selectors.unshift(this.selectors); // Evaluate imports if (ruleset.root || ruleset.allowImports || !ruleset.strictImports) { ruleset.evalImports(env); } // Store the frames around mixin definitions, // so they can be evaluated like closures when the time comes. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Definition) { ruleset.rules[i].frames = env.frames.slice(0); } } var mediaBlockCount = (env.mediaBlocks && env.mediaBlocks.length) || 0; // Evaluate mixin calls. for (var i = 0; i < ruleset.rules.length; i++) { if (ruleset.rules[i] instanceof tree.mixin.Call) { rules = ruleset.rules[i].eval(env).filter(function(r) { if ((r instanceof tree.Rule) && r.variable) { // do not pollute the scope if the variable is // already there. consider returning false here // but we need a way to "return" variable from mixins return !(ruleset.variable(r.name)); } return true; }); ruleset.rules.splice.apply(ruleset.rules, [i, 1].concat(rules)); i += rules.length-1; ruleset.resetCache(); } } // Evaluate everything else for (var i = 0, rule; i < ruleset.rules.length; i++) { rule = ruleset.rules[i]; if (! (rule instanceof tree.mixin.Definition)) { ruleset.rules[i] = rule.eval ? rule.eval(env) : rule; } } // Pop the stack env.frames.shift(); env.selectors.shift(); if (env.mediaBlocks) { for(var i = mediaBlockCount; i < env.mediaBlocks.length; i++) { env.mediaBlocks[i].bubbleSelectors(selectors); } } return ruleset; }, evalImports: function(env) { var i, rules; for (i = 0; i < this.rules.length; i++) { if (this.rules[i] instanceof tree.Import) { rules = this.rules[i].eval(env); if (typeof rules.length === "number") { this.rules.splice.apply(this.rules, [i, 1].concat(rules)); i+= rules.length-1; } else { this.rules.splice(i, 1, rules); } this.resetCache(); } } }, makeImportant: function() { return new tree.Ruleset(this.selectors, this.rules.map(function (r) { if (r.makeImportant) { return r.makeImportant(); } else { return r; } }), this.strictImports); }, matchArgs: function (args) { return !args || args.length === 0; }, resetCache: function () { this._rulesets = null; this._variables = null; this._lookups = {}; }, variables: function () { if (this._variables) { return this._variables } else { return this._variables = this.rules.reduce(function (hash, r) { if (r instanceof tree.Rule && r.variable === true) { hash[r.name] = r; } return hash; }, {}); } }, variable: function (name) { return this.variables()[name]; }, rulesets: function () { return this.rules.filter(function (r) { return (r instanceof tree.Ruleset) || (r instanceof tree.mixin.Definition); }); }, find: function (selector, self) { self = self || this; var rules = [], rule, match, key = selector.toCSS(); if (key in this._lookups) { return this._lookups[key] } this.rulesets().forEach(function (rule) { if (rule !== self) { for (var j = 0; j < rule.selectors.length; j++) { if (match = selector.match(rule.selectors[j])) { if (selector.elements.length > rule.selectors[j].elements.length) { Array.prototype.push.apply(rules, rule.find( new(tree.Selector)(selector.elements.slice(1)), self)); } else { rules.push(rule); } break; } } } }); return this._lookups[key] = rules; }, // // Entry point for code generation // // `context` holds an array of arrays. // toCSS: function (env) { var css = [], // The CSS output rules = [], // node.Rule instances _rules = [], // rulesets = [], // node.Ruleset instances selector, // The fully rendered selector debugInfo, // Line number debugging rule; // Compile rules and rulesets for (var i = 0; i < this.rules.length; i++) { rule = this.rules[i]; if (rule.rules || (rule instanceof tree.Media)) { rulesets.push(rule.toCSS(env)); } else if (rule instanceof tree.Directive) { var cssValue = rule.toCSS(env); // Output only the first @charset definition as such - convert the others // to comments in case debug is enabled if (rule.name === "@charset") { // Only output the debug info together with subsequent @charset definitions // a comment (or @media statement) before the actual @charset directive would // be considered illegal css as it has to be on the first line if (env.charset) { if (rule.debugInfo) { rulesets.push(tree.debugInfo(env, rule)); rulesets.push(new tree.Comment("/* "+cssValue.replace(/\n/g, "")+" */\n").toCSS(env)); } continue; } env.charset = true; } rulesets.push(cssValue); } else if (rule instanceof tree.Comment) { if (!rule.silent) { if (this.root) { rulesets.push(rule.toCSS(env)); } else { rules.push(rule.toCSS(env)); } } } else { if (rule.toCSS && !rule.variable) { if (this.firstRoot && rule instanceof tree.Rule) { throw { message: "properties must be inside selector blocks, they cannot be in the root.", index: rule.index, filename: rule.currentFileInfo ? rule.currentFileInfo.filename : null}; } rules.push(rule.toCSS(env)); } else if (rule.value && !rule.variable) { rules.push(rule.value.toString()); } } } // Remove last semicolon if (env.compress && rules.length) { rule = rules[rules.length - 1]; if (rule.charAt(rule.length - 1) === ';') { rules[rules.length - 1] = rule.substring(0, rule.length - 1); } } rulesets = rulesets.join(''); // If this is the root node, we don't render // a selector, or {}. // Otherwise, only output if this ruleset has rules. if (this.root) { css.push(rules.join(env.compress ? '' : '\n')); } else { if (rules.length > 0) { debugInfo = tree.debugInfo(env, this); selector = this.paths.map(function (p) { return p.map(function (s) { return s.toCSS(env); }).join('').trim(); }).join(env.compress ? ',' : ',\n'); // Remove duplicates for (var i = rules.length - 1; i >= 0; i--) { if (rules[i].slice(0, 2) === "/*" || _rules.indexOf(rules[i]) === -1) { _rules.unshift(rules[i]); } } rules = _rules; css.push(debugInfo + selector + (env.compress ? '{' : ' {\n ') + rules.join(env.compress ? '' : '\n ') + (env.compress ? '}' : '\n}\n')); } } css.push(rulesets); return css.join('') + (env.compress ? '\n' : ''); }, joinSelectors: function (paths, context, selectors) { for (var s = 0; s < selectors.length; s++) { this.joinSelector(paths, context, selectors[s]); } }, joinSelector: function (paths, context, selector) { var i, j, k, hasParentSelector, newSelectors, el, sel, parentSel, newSelectorPath, afterParentJoin, newJoinedSelector, newJoinedSelectorEmpty, lastSelector, currentElements, selectorsMultiplied; for (i = 0; i < selector.elements.length; i++) { el = selector.elements[i]; if (el.value === '&') { hasParentSelector = true; } } if (!hasParentSelector) { if (context.length > 0) { for(i = 0; i < context.length; i++) { paths.push(context[i].concat(selector)); } } else { paths.push([selector]); } return; } // The paths are [[Selector]] // The first list is a list of comma seperated selectors // The inner list is a list of inheritance seperated selectors // e.g. // .a, .b { // .c { // } // } // == [[.a] [.c]] [[.b] [.c]] // // the elements from the current selector so far currentElements = []; // the current list of new selectors to add to the path. // We will build it up. We initiate it with one empty selector as we "multiply" the new selectors // by the parents newSelectors = [[]]; for (i = 0; i < selector.elements.length; i++) { el = selector.elements[i]; // non parent reference elements just get added if (el.value !== "&") { currentElements.push(el); } else { // the new list of selectors to add selectorsMultiplied = []; // merge the current list of non parent selector elements // on to the current list of selectors to add if (currentElements.length > 0) { this.mergeElementsOnToSelectors(currentElements, newSelectors); } // loop through our current selectors for(j = 0; j < newSelectors.length; j++) { sel = newSelectors[j]; // if we don't have any parent paths, the & might be in a mixin so that it can be used // whether there are parents or not if (context.length == 0) { // the combinator used on el should now be applied to the next element instead so that // it is not lost if (sel.length > 0) { sel[0].elements = sel[0].elements.slice(0); sel[0].elements.push(new(tree.Element)(el.combinator, '', 0)); //new Element(el.Combinator, "")); } selectorsMultiplied.push(sel); } else { // and the parent selectors for(k = 0; k < context.length; k++) { parentSel = context[k]; // We need to put the current selectors // then join the last selector's elements on to the parents selectors // our new selector path newSelectorPath = []; // selectors from the parent after the join afterParentJoin = []; newJoinedSelectorEmpty = true; //construct the joined selector - if & is the first thing this will be empty, // if not newJoinedSelector will be the last set of elements in the selector if (sel.length > 0) { newSelectorPath = sel.slice(0); lastSelector = newSelectorPath.pop(); newJoinedSelector = new(tree.Selector)(lastSelector.elements.slice(0), selector.extendList); newJoinedSelectorEmpty = false; } else { newJoinedSelector = new(tree.Selector)([], selector.extendList); } //put together the parent selectors after the join if (parentSel.length > 1) { afterParentJoin = afterParentJoin.concat(parentSel.slice(1)); } if (parentSel.length > 0) { newJoinedSelectorEmpty = false; // join the elements so far with the first part of the parent newJoinedSelector.elements.push(new(tree.Element)(el.combinator, parentSel[0].elements[0].value, 0)); newJoinedSelector.elements = newJoinedSelector.elements.concat(parentSel[0].elements.slice(1)); } if (!newJoinedSelectorEmpty) { // now add the joined selector newSelectorPath.push(newJoinedSelector); } // and the rest of the parent newSelectorPath = newSelectorPath.concat(afterParentJoin); // add that to our new set of selectors selectorsMultiplied.push(newSelectorPath); } } } // our new selectors has been multiplied, so reset the state newSelectors = selectorsMultiplied; currentElements = []; } } // if we have any elements left over (e.g. .a& .b == .b) // add them on to all the current selectors if (currentElements.length > 0) { this.mergeElementsOnToSelectors(currentElements, newSelectors); } for(i = 0; i < newSelectors.length; i++) { if (newSelectors[i].length > 0) { paths.push(newSelectors[i]); } } }, mergeElementsOnToSelectors: function(elements, selectors) { var i, sel, extendList; if (selectors.length == 0) { selectors.push([ new(tree.Selector)(elements) ]); return; } for(i = 0; i < selectors.length; i++) { sel = selectors[i]; // if the previous thing in sel is a parent this needs to join on to it if (sel.length > 0) { sel[sel.length - 1] = new(tree.Selector)(sel[sel.length - 1].elements.concat(elements), sel[sel.length - 1].extendList); } else { sel.push(new(tree.Selector)(elements)); } } } }; })(require('../tree')); less.js-1.4.2/lib/less/tree/selector.js000066400000000000000000000032511217256642200177400ustar00rootroot00000000000000(function (tree) { tree.Selector = function (elements, extendList) { this.elements = elements; this.extendList = extendList || []; }; tree.Selector.prototype = { type: "Selector", accept: function (visitor) { this.elements = visitor.visit(this.elements); this.extendList = visitor.visit(this.extendList) }, match: function (other) { var elements = this.elements, len = elements.length, oelements, olen, max, i; oelements = other.elements.slice( (other.elements.length && other.elements[0].value === "&") ? 1 : 0); olen = oelements.length; max = Math.min(len, olen); if (olen === 0 || len < olen) { return false; } else { for (i = 0; i < max; i++) { if (elements[i].value !== oelements[i].value) { return false; } } } return true; }, eval: function (env) { return new(tree.Selector)(this.elements.map(function (e) { return e.eval(env); }), this.extendList.map(function(extend) { return extend.eval(env); })); }, toCSS: function (env) { if (this._css) { return this._css } if (this.elements[0].combinator.value === "") { this._css = ' '; } else { this._css = ''; } this._css += this.elements.map(function (e) { if (typeof(e) === 'string') { return ' ' + e.trim(); } else { return e.toCSS(env); } }).join(''); return this._css; } }; })(require('../tree')); less.js-1.4.2/lib/less/tree/unicode-descriptor.js000066400000000000000000000004371217256642200217250ustar00rootroot00000000000000(function (tree) { tree.UnicodeDescriptor = function (value) { this.value = value; }; tree.UnicodeDescriptor.prototype = { type: "UnicodeDescriptor", toCSS: function (env) { return this.value; }, eval: function () { return this } }; })(require('../tree')); less.js-1.4.2/lib/less/tree/url.js000066400000000000000000000016221217256642200167220ustar00rootroot00000000000000(function (tree) { tree.URL = function (val, currentFileInfo) { this.value = val; this.currentFileInfo = currentFileInfo; }; tree.URL.prototype = { type: "Url", accept: function (visitor) { this.value = visitor.visit(this.value); }, toCSS: function () { return "url(" + this.value.toCSS() + ")"; }, eval: function (ctx) { var val = this.value.eval(ctx), rootpath; // Add the base path if the URL is relative rootpath = this.currentFileInfo && this.currentFileInfo.rootpath; if (rootpath && typeof val.value === "string" && ctx.isPathRelative(val.value)) { if (!val.quote) { rootpath = rootpath.replace(/[\(\)'"\s]/g, function(match) { return "\\"+match; }); } val.value = rootpath + val.value; } return new(tree.URL)(val, null); } }; })(require('../tree')); less.js-1.4.2/lib/less/tree/value.js000066400000000000000000000012211217256642200172270ustar00rootroot00000000000000(function (tree) { tree.Value = function (value) { this.value = value; }; tree.Value.prototype = { type: "Value", accept: function (visitor) { this.value = visitor.visit(this.value); }, eval: function (env) { if (this.value.length === 1) { return this.value[0].eval(env); } else { return new(tree.Value)(this.value.map(function (v) { return v.eval(env); })); } }, toCSS: function (env) { return this.value.map(function (e) { return e.toCSS(env); }).join(env.compress ? ',' : ', '); } }; })(require('../tree')); less.js-1.4.2/lib/less/tree/variable.js000066400000000000000000000023031217256642200177020ustar00rootroot00000000000000(function (tree) { tree.Variable = function (name, index, currentFileInfo) { this.name = name, this.index = index, this.currentFileInfo = currentFileInfo }; tree.Variable.prototype = { type: "Variable", eval: function (env) { var variable, v, name = this.name; if (name.indexOf('@@') == 0) { name = '@' + new(tree.Variable)(name.slice(1)).eval(env).value; } if (this.evaluating) { throw { type: 'Name', message: "Recursive variable definition for " + name, filename: this.currentFileInfo.file, index: this.index }; } this.evaluating = true; if (variable = tree.find(env.frames, function (frame) { if (v = frame.variable(name)) { return v.value.eval(env); } })) { this.evaluating = false; return variable; } else { throw { type: 'Name', message: "variable " + name + " is undefined", filename: this.currentFileInfo.filename, index: this.index }; } } }; })(require('../tree')); less.js-1.4.2/lib/less/visitor.js000066400000000000000000000031511217256642200166570ustar00rootroot00000000000000(function (tree) { tree.visitor = function(implementation) { this._implementation = implementation; }; tree.visitor.prototype = { visit: function(node) { if (node instanceof Array) { return this.visitArray(node); } if (!node || !node.type) { return node; } var funcName = "visit" + node.type, func = this._implementation[funcName], visitArgs, newNode; if (func) { visitArgs = {visitDeeper: true}; newNode = func.call(this._implementation, node, visitArgs); if (this._implementation.isReplacing) { node = newNode; } } if ((!visitArgs || visitArgs.visitDeeper) && node && node.accept) { node.accept(this); } funcName = funcName + "Out"; if (this._implementation[funcName]) { this._implementation[funcName](node); } return node; }, visitArray: function(nodes) { var i, newNodes = []; for(i = 0; i < nodes.length; i++) { var evald = this.visit(nodes[i]); if (evald instanceof Array) { newNodes = newNodes.concat(evald); } else { newNodes.push(evald); } } if (this._implementation.isReplacing) { return newNodes; } return nodes; } }; })(require('./tree'));less.js-1.4.2/package.json000066400000000000000000000025131217256642200153750ustar00rootroot00000000000000{ "name": "less", "version": "1.4.2", "description": "Leaner CSS", "homepage": "http://lesscss.org", "author": "Alexis Sellier ", "contributors": [ "The Core Less Team" ], "bugs": { "url": "https://github.com/less/less.js/issues" }, "repository": { "type": "git", "url": "https://github.com/less/less.js.git" }, "bin": { "lessc": "./bin/lessc" }, "main": "./lib/less/index", "directories": { "test": "./test" }, "jam": { "main": "./dist/less-1.4.1.js" }, "engines": { "node": ">=0.4.2" }, "scripts": { "test": "make test" }, "optionalDependencies": { "mime": "1.2.x", "request": ">=2.12.0", "mkdirp": "~0.3.4", "ycssmin": ">=1.0.1" }, "devDependencies": { "diff": "~1.0" }, "keywords": [ "compile less", "css nesting", "css variable", "css", "gradients css", "gradients css3", "less compiler", "less css", "less mixins", "less", "less.js", "lesscss", "mixins", "nested css", "parser", "preprocessor", "bootstrap css", "bootstrap less", "style", "styles", "stylesheet", "variables in css", "css less" ], "licenses": [ { "type": "Apache v2", "url": "https://github.com/less/less.js/blob/master/LICENSE" } ] } less.js-1.4.2/test/000077500000000000000000000000001217256642200140655ustar00rootroot00000000000000less.js-1.4.2/test/browser-test-prepare.js000066400000000000000000000037161217256642200205260ustar00rootroot00000000000000var path = require('path'), fs = require('fs'), sys = require('util'); var readDirFilesSync = function(dir, regex, callback) { fs.readdirSync(dir).forEach(function (file) { if (! regex.test(file)) { return; } callback(file); }); } var createTestRunnerPage = function(dir, exclude, testSuiteName, dir2) { var output = '\n'; readDirFilesSync(path.join("test", dir, 'less', dir2 || ""), /\.less$/, function (file) { var name = path.basename(file, '.less'), id = (dir ? dir + '-' : "") + 'less-' + (dir2 ? dir2 + "-" : "") + name; if (exclude && name.match(exclude)) { return; } output += '\n'; output += '\n'; }); output += String(fs.readFileSync(path.join('test/browser', 'template.htm'))).replace("{runner-name}", testSuiteName); fs.writeFileSync(path.join('test/browser', 'test-runner-'+testSuiteName+'.htm'), output); }; var removeFiles = function(dir, regex) { readDirFilesSync(dir, regex, function(file) { fs.unlinkSync(path.join(dir, file), function() { console.log("Failed to delete " + file); }); }); } removeFiles("test/browser", /test-runner-[a-zA-Z-]*\.htm$/); createTestRunnerPage("", /javascript|urls/, "main"); createTestRunnerPage("", null, "legacy", "legacy"); createTestRunnerPage("", /javascript/, "errors", "errors"); createTestRunnerPage("browser", null, "browser"); createTestRunnerPage("browser", null, "relative-urls", "relative-urls"); createTestRunnerPage("browser", null, "rootpath", "rootpath"); createTestRunnerPage("browser", null, "rootpath-relative", "rootpath-relative"); createTestRunnerPage("browser", null, "production");less.js-1.4.2/test/browser/000077500000000000000000000000001217256642200155505ustar00rootroot00000000000000less.js-1.4.2/test/browser/common.js000066400000000000000000000073651217256642200174110ustar00rootroot00000000000000/*if not async then phantomjs fails to run the webserver and the test concurrently*/ var less = { async: true, strictMath: true }; /* record log messages for testing */ var logMessages = [], realConsoleLog = console.log; console.log = function(msg) { logMessages.push(msg); realConsoleLog.call(console, msg); }; var testLessEqualsInDocument = function() { testLessInDocument(testSheet); }; var testLessErrorsInDocument = function() { testLessInDocument(testErrorSheet); }; var testLessInDocument = function(testFunc) { var links = document.getElementsByTagName('link'), typePattern = /^text\/(x-)?less$/; for (var i = 0; i < links.length; i++) { if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) && (links[i].type.match(typePattern)))) { testFunc(links[i]); } } }; var testSheet = function(sheet) { it(sheet.id + " should match the expected output", function() { var lessOutputId = sheet.id.replace("original-", ""), expectedOutputId = "expected-" + lessOutputId, lessOutput = document.getElementById(lessOutputId).innerText, expectedOutputHref = document.getElementById(expectedOutputId).href, expectedOutput = loadFile(expectedOutputHref); waitsFor(function() { return expectedOutput.loaded; }, "failed to load expected outout", 10000); runs(function() { // use sheet to do testing expect(lessOutput).toEqual(expectedOutput.text); }); }); }; var testErrorSheet = function(sheet) { it(sheet.id + " should match an error", function() { var lessHref = sheet.href, id = sheet.id.replace(/^original-less:/, "less-error-message:"), errorHref = lessHref.replace(/.less$/, ".txt"), errorFile = loadFile(errorHref), actualErrorElement = document.getElementById(id), actualErrorMsg; describe("the error", function() { expect(actualErrorElement).not.toBe(null); }); actualErrorMsg = actualErrorElement.innerText .replace(/\n\d+/g, function(lineNo) { return lineNo + " "; }) .replace(/\n\s*in /g, " in ") .replace("\n\n", "\n"); waitsFor(function() { return errorFile.loaded; }, "failed to load expected outout", 10000); runs(function() { var errorTxt = errorFile.text .replace("{path}", "") .replace("{pathrel}", "") .replace("{pathhref}", "http://localhost:8081/less/errors/") .replace("{404status}", " (404)"); expect(actualErrorMsg).toEqual(errorTxt); if (errorTxt == actualErrorMsg) { actualErrorElement.style.display = "none"; } }); }); }; var loadFile = function(href) { var request = new XMLHttpRequest(), response = { loaded: false, text: ""}; request.open('GET', href, true); request.onload = function(e) { response.text = request.response.replace(/\r/g, ""); response.loaded = true; } request.send(); return response; }; (function() { var jasmineEnv = jasmine.getEnv(); jasmineEnv.updateInterval = 1000; var htmlReporter = new jasmine.HtmlReporter(); jasmineEnv.addReporter(htmlReporter); jasmineEnv.specFilter = function(spec) { return htmlReporter.specFilter(spec); }; var currentWindowOnload = window.onload; window.onload = function() { if (currentWindowOnload) { currentWindowOnload(); } execJasmine(); }; function execJasmine() { setTimeout(function() { jasmineEnv.execute(); }, 3000); } })();less.js-1.4.2/test/browser/css/000077500000000000000000000000001217256642200163405ustar00rootroot00000000000000less.js-1.4.2/test/browser/css/relative-urls/000077500000000000000000000000001217256642200211365ustar00rootroot00000000000000less.js-1.4.2/test/browser/css/relative-urls/urls.css000066400000000000000000000027651217256642200226470ustar00rootroot00000000000000@import "http://localhost:8081/browser/less/imports/modify-this.css"; @import "http://localhost:8081/browser/less/imports/modify-again.css"; .modify { my-url: url("http://localhost:8081/browser/less/imports/a.png"); } .modify { my-url: url("http://localhost:8081/browser/less/imports/b.png"); } @font-face { src: url("/fonts/garamond-pro.ttf"); src: local(Futura-Medium), url(http://localhost:8081/browser/less/relative-urls/fonts.svg#MyGeometricModern) format("svg"); } #shorthands { background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px; } #misc { background-image: url(http://localhost:8081/browser/less/relative-urls/images/image.jpg); } #data-uri { background: url(data:image/png;charset=utf-8;base64, kiVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/ k//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U kg9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC); background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==); background-image: url(http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700); } #svg-data-uri { background: transparent url('data:image/svg+xml, '); } .comma-delimited { background: url(http://localhost:8081/browser/less/relative-urls/bg.jpg) no-repeat, url(http://localhost:8081/browser/less/relative-urls/bg.png) repeat-x top left, url(http://localhost:8081/browser/less/relative-urls/bg); } .values { url: url('http://localhost:8081/browser/less/relative-urls/Trebuchet'); } less.js-1.4.2/test/browser/css/rootpath-relative/000077500000000000000000000000001217256642200220115ustar00rootroot00000000000000less.js-1.4.2/test/browser/css/rootpath-relative/urls.css000066400000000000000000000026751217256642200235220ustar00rootroot00000000000000@import "https://www.github.com/cloudhead/imports/modify-this.css"; @import "https://www.github.com/cloudhead/imports/modify-again.css"; .modify { my-url: url("https://www.github.com/cloudhead/imports/a.png"); } .modify { my-url: url("https://www.github.com/cloudhead/imports/b.png"); } @font-face { src: url("/fonts/garamond-pro.ttf"); src: local(Futura-Medium), url(https://www.github.com/cloudhead/less.js/fonts.svg#MyGeometricModern) format("svg"); } #shorthands { background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px; } #misc { background-image: url(https://www.github.com/cloudhead/less.js/images/image.jpg); } #data-uri { background: url(data:image/png;charset=utf-8;base64, kiVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/ k//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U kg9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC); background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==); background-image: url(http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700); } #svg-data-uri { background: transparent url('data:image/svg+xml, '); } .comma-delimited { background: url(https://www.github.com/cloudhead/less.js/bg.jpg) no-repeat, url(https://www.github.com/cloudhead/less.js/bg.png) repeat-x top left, url(https://www.github.com/cloudhead/less.js/bg); } .values { url: url('https://www.github.com/cloudhead/less.js/Trebuchet'); } less.js-1.4.2/test/browser/css/rootpath/000077500000000000000000000000001217256642200202005ustar00rootroot00000000000000less.js-1.4.2/test/browser/css/rootpath/urls.css000066400000000000000000000024111217256642200216750ustar00rootroot00000000000000@import "https://www.github.com/modify-this.css"; @import "https://www.github.com/modify-again.css"; .modify { my-url: url("https://www.github.com/a.png"); } .modify { my-url: url("https://www.github.com/b.png"); } @font-face { src: url("/fonts/garamond-pro.ttf"); src: local(Futura-Medium), url(https://www.github.com/fonts.svg#MyGeometricModern) format("svg"); } #shorthands { background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px; } #misc { background-image: url(https://www.github.com/images/image.jpg); } #data-uri { background: url(data:image/png;charset=utf-8;base64, kiVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/ k//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U kg9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC); background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==); background-image: url(http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700); } #svg-data-uri { background: transparent url('data:image/svg+xml, '); } .comma-delimited { background: url(https://www.github.com/bg.jpg) no-repeat, url(https://www.github.com/bg.png) repeat-x top left, url(https://www.github.com/bg); } .values { url: url('https://www.github.com/Trebuchet'); } less.js-1.4.2/test/browser/css/urls.css000066400000000000000000000034731217256642200200460ustar00rootroot00000000000000@import "http://localhost:8081/browser/less/modify-this.css"; @import "http://localhost:8081/browser/less/modify-again.css"; .modify { my-url: url("http://localhost:8081/browser/less/a.png"); } .modify { my-url: url("http://localhost:8081/browser/less/b.png"); } @font-face { src: url("/fonts/garamond-pro.ttf"); src: local(Futura-Medium), url(http://localhost:8081/browser/less/fonts.svg#MyGeometricModern) format("svg"); } #shorthands { background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px; } #misc { background-image: url(http://localhost:8081/browser/less/images/image.jpg); } #data-uri { background: url(data:image/png;charset=utf-8;base64, kiVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/ k//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U kg9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC); background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==); background-image: url(http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700); } #svg-data-uri { background: transparent url('data:image/svg+xml, '); } .comma-delimited { background: url(http://localhost:8081/browser/less/bg.jpg) no-repeat, url(http://localhost:8081/browser/less/bg.png) repeat-x top left, url(http://localhost:8081/browser/less/bg); } .values { url: url('http://localhost:8081/browser/less/Trebuchet'); } #data-uri { uri: url('http://localhost:8081/browser/less/../../data/image.jpg'); } #data-uri-guess { uri: url('http://localhost:8081/browser/less/../../data/image.jpg'); } #data-uri-ascii { uri-1: url('http://localhost:8081/browser/less/../../data/page.html'); uri-2: url('http://localhost:8081/browser/less/../../data/page.html'); } #data-uri-toobig { uri: url('http://localhost:8081/browser/less/../../data/data-uri-fail.png'); } less.js-1.4.2/test/browser/jasmine-html.js000066400000000000000000000504351217256642200205050ustar00rootroot00000000000000jasmine.HtmlReporterHelpers = {}; jasmine.HtmlReporterHelpers.createDom = function(type, attrs, childrenVarArgs) { var el = document.createElement(type); for (var i = 2; i < arguments.length; i++) { var child = arguments[i]; if (typeof child === 'string') { el.appendChild(document.createTextNode(child)); } else { if (child) { el.appendChild(child); } } } for (var attr in attrs) { if (attr == "className") { el[attr] = attrs[attr]; } else { el.setAttribute(attr, attrs[attr]); } } return el; }; jasmine.HtmlReporterHelpers.getSpecStatus = function(child) { var results = child.results(); var status = results.passed() ? 'passed' : 'failed'; if (results.skipped) { status = 'skipped'; } return status; }; jasmine.HtmlReporterHelpers.appendToSummary = function(child, childElement) { var parentDiv = this.dom.summary; var parentSuite = (typeof child.parentSuite == 'undefined') ? 'suite' : 'parentSuite'; var parent = child[parentSuite]; if (parent) { if (typeof this.views.suites[parent.id] == 'undefined') { this.views.suites[parent.id] = new jasmine.HtmlReporter.SuiteView(parent, this.dom, this.views); } parentDiv = this.views.suites[parent.id].element; } parentDiv.appendChild(childElement); }; jasmine.HtmlReporterHelpers.addHelpers = function(ctor) { for(var fn in jasmine.HtmlReporterHelpers) { ctor.prototype[fn] = jasmine.HtmlReporterHelpers[fn]; } }; jasmine.HtmlReporter = function(_doc) { var self = this; var doc = _doc || window.document; var reporterView; var dom = {}; // Jasmine Reporter Public Interface self.logRunningSpecs = false; self.reportRunnerStarting = function(runner) { var specs = runner.specs() || []; if (specs.length == 0) { return; } createReporterDom(runner.env.versionString()); doc.body.appendChild(dom.reporter); setExceptionHandling(); reporterView = new jasmine.HtmlReporter.ReporterView(dom); reporterView.addSpecs(specs, self.specFilter); }; self.reportRunnerResults = function(runner) { reporterView && reporterView.complete(); }; self.reportSuiteResults = function(suite) { reporterView.suiteComplete(suite); }; self.reportSpecStarting = function(spec) { if (self.logRunningSpecs) { self.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...'); } }; self.reportSpecResults = function(spec) { reporterView.specComplete(spec); }; self.log = function() { var console = jasmine.getGlobal().console; if (console && console.log) { if (console.log.apply) { console.log.apply(console, arguments); } else { console.log(arguments); // ie fix: console.log.apply doesn't exist on ie } } }; self.specFilter = function(spec) { if (!focusedSpecName()) { return true; } return spec.getFullName().indexOf(focusedSpecName()) === 0; }; return self; function focusedSpecName() { var specName; (function memoizeFocusedSpec() { if (specName) { return; } var paramMap = []; var params = jasmine.HtmlReporter.parameters(doc); for (var i = 0; i < params.length; i++) { var p = params[i].split('='); paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]); } specName = paramMap.spec; })(); return specName; } function createReporterDom(version) { dom.reporter = self.createDom('div', { id: 'HTMLReporter', className: 'jasmine_reporter' }, dom.banner = self.createDom('div', { className: 'banner' }, self.createDom('span', { className: 'title' }, "Jasmine "), self.createDom('span', { className: 'version' }, version)), dom.symbolSummary = self.createDom('ul', {className: 'symbolSummary'}), dom.alert = self.createDom('div', {className: 'alert'}, self.createDom('span', { className: 'exceptions' }, self.createDom('label', { className: 'label', 'for': 'no_try_catch' }, 'No try/catch'), self.createDom('input', { id: 'no_try_catch', type: 'checkbox' }))), dom.results = self.createDom('div', {className: 'results'}, dom.summary = self.createDom('div', { className: 'summary' }), dom.details = self.createDom('div', { id: 'details' })) ); } function noTryCatch() { return window.location.search.match(/catch=false/); } function searchWithCatch() { var params = jasmine.HtmlReporter.parameters(window.document); var removed = false; var i = 0; while (!removed && i < params.length) { if (params[i].match(/catch=/)) { params.splice(i, 1); removed = true; } i++; } if (jasmine.CATCH_EXCEPTIONS) { params.push("catch=false"); } return params.join("&"); } function setExceptionHandling() { var chxCatch = document.getElementById('no_try_catch'); if (noTryCatch()) { chxCatch.setAttribute('checked', true); jasmine.CATCH_EXCEPTIONS = false; } chxCatch.onclick = function() { window.location.search = searchWithCatch(); }; } }; jasmine.HtmlReporter.parameters = function(doc) { var paramStr = doc.location.search.substring(1); var params = []; if (paramStr.length > 0) { params = paramStr.split('&'); } return params; } jasmine.HtmlReporter.sectionLink = function(sectionName) { var link = '?'; var params = []; if (sectionName) { params.push('spec=' + encodeURIComponent(sectionName)); } if (!jasmine.CATCH_EXCEPTIONS) { params.push("catch=false"); } if (params.length > 0) { link += params.join("&"); } return link; }; jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter); jasmine.HtmlReporter.ReporterView = function(dom) { this.startedAt = new Date(); this.runningSpecCount = 0; this.completeSpecCount = 0; this.passedCount = 0; this.failedCount = 0; this.skippedCount = 0; this.createResultsMenu = function() { this.resultsMenu = this.createDom('span', {className: 'resultsMenu bar'}, this.summaryMenuItem = this.createDom('a', {className: 'summaryMenuItem', href: "#"}, '0 specs'), ' | ', this.detailsMenuItem = this.createDom('a', {className: 'detailsMenuItem', href: "#"}, '0 failing')); this.summaryMenuItem.onclick = function() { dom.reporter.className = dom.reporter.className.replace(/ showDetails/g, ''); }; this.detailsMenuItem.onclick = function() { showDetails(); }; }; this.addSpecs = function(specs, specFilter) { this.totalSpecCount = specs.length; this.views = { specs: {}, suites: {} }; for (var i = 0; i < specs.length; i++) { var spec = specs[i]; this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom, this.views); if (specFilter(spec)) { this.runningSpecCount++; } } }; this.specComplete = function(spec) { this.completeSpecCount++; if (isUndefined(this.views.specs[spec.id])) { this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom); } var specView = this.views.specs[spec.id]; switch (specView.status()) { case 'passed': this.passedCount++; break; case 'failed': this.failedCount++; break; case 'skipped': this.skippedCount++; break; } specView.refresh(); this.refresh(); }; this.suiteComplete = function(suite) { var suiteView = this.views.suites[suite.id]; if (isUndefined(suiteView)) { return; } suiteView.refresh(); }; this.refresh = function() { if (isUndefined(this.resultsMenu)) { this.createResultsMenu(); } // currently running UI if (isUndefined(this.runningAlert)) { this.runningAlert = this.createDom('a', { href: jasmine.HtmlReporter.sectionLink(), className: "runningAlert bar" }); dom.alert.appendChild(this.runningAlert); } this.runningAlert.innerHTML = "Running " + this.completeSpecCount + " of " + specPluralizedFor(this.totalSpecCount); // skipped specs UI if (isUndefined(this.skippedAlert)) { this.skippedAlert = this.createDom('a', { href: jasmine.HtmlReporter.sectionLink(), className: "skippedAlert bar" }); } this.skippedAlert.innerHTML = "Skipping " + this.skippedCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all"; if (this.skippedCount === 1 && isDefined(dom.alert)) { dom.alert.appendChild(this.skippedAlert); } // passing specs UI if (isUndefined(this.passedAlert)) { this.passedAlert = this.createDom('span', { href: jasmine.HtmlReporter.sectionLink(), className: "passingAlert bar" }); } this.passedAlert.innerHTML = "Passing " + specPluralizedFor(this.passedCount); // failing specs UI if (isUndefined(this.failedAlert)) { this.failedAlert = this.createDom('span', {href: "?", className: "failingAlert bar"}); } this.failedAlert.innerHTML = "Failing " + specPluralizedFor(this.failedCount); if (this.failedCount === 1 && isDefined(dom.alert)) { dom.alert.appendChild(this.failedAlert); dom.alert.appendChild(this.resultsMenu); } // summary info this.summaryMenuItem.innerHTML = "" + specPluralizedFor(this.runningSpecCount); this.detailsMenuItem.innerHTML = "" + this.failedCount + " failing"; }; this.complete = function() { dom.alert.removeChild(this.runningAlert); this.skippedAlert.innerHTML = "Ran " + this.runningSpecCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all"; if (this.failedCount === 0) { dom.alert.appendChild(this.createDom('span', {className: 'passingAlert bar'}, "Passing " + specPluralizedFor(this.passedCount))); } else { showDetails(); } dom.banner.appendChild(this.createDom('span', {className: 'duration'}, "finished in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s")); }; return this; function showDetails() { if (dom.reporter.className.search(/showDetails/) === -1) { dom.reporter.className += " showDetails"; } } function isUndefined(obj) { return typeof obj === 'undefined'; } function isDefined(obj) { return !isUndefined(obj); } function specPluralizedFor(count) { var str = count + " spec"; if (count > 1) { str += "s" } return str; } }; jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.ReporterView); jasmine.HtmlReporter.SpecView = function(spec, dom, views) { this.spec = spec; this.dom = dom; this.views = views; this.symbol = this.createDom('li', { className: 'pending' }); this.dom.symbolSummary.appendChild(this.symbol); this.summary = this.createDom('div', { className: 'specSummary' }, this.createDom('a', { className: 'description', href: jasmine.HtmlReporter.sectionLink(this.spec.getFullName()), title: this.spec.getFullName() }, this.spec.description) ); this.detail = this.createDom('div', { className: 'specDetail' }, this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(this.spec.getFullName()), title: this.spec.getFullName() }, this.spec.getFullName()) ); }; jasmine.HtmlReporter.SpecView.prototype.status = function() { return this.getSpecStatus(this.spec); }; jasmine.HtmlReporter.SpecView.prototype.refresh = function() { this.symbol.className = this.status(); switch (this.status()) { case 'skipped': break; case 'passed': this.appendSummaryToSuiteDiv(); break; case 'failed': this.appendSummaryToSuiteDiv(); this.appendFailureDetail(); break; } }; jasmine.HtmlReporter.SpecView.prototype.appendSummaryToSuiteDiv = function() { this.summary.className += ' ' + this.status(); this.appendToSummary(this.spec, this.summary); }; jasmine.HtmlReporter.SpecView.prototype.appendFailureDetail = function() { this.detail.className += ' ' + this.status(); var resultItems = this.spec.results().getItems(); var messagesDiv = this.createDom('div', { className: 'messages' }); for (var i = 0; i < resultItems.length; i++) { var result = resultItems[i]; if (result.type == 'log') { messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString())); } else if (result.type == 'expect' && result.passed && !result.passed()) { messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message)); if (result.trace.stack) { messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack)); } } } if (messagesDiv.childNodes.length > 0) { this.detail.appendChild(messagesDiv); this.dom.details.appendChild(this.detail); } }; jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SpecView);jasmine.HtmlReporter.SuiteView = function(suite, dom, views) { this.suite = suite; this.dom = dom; this.views = views; this.element = this.createDom('div', { className: 'suite' }, this.createDom('a', { className: 'description', href: jasmine.HtmlReporter.sectionLink(this.suite.getFullName()) }, this.suite.description) ); this.appendToSummary(this.suite, this.element); }; jasmine.HtmlReporter.SuiteView.prototype.status = function() { return this.getSpecStatus(this.suite); }; jasmine.HtmlReporter.SuiteView.prototype.refresh = function() { this.element.className += " " + this.status(); }; jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SuiteView); /* @deprecated Use jasmine.HtmlReporter instead */ jasmine.TrivialReporter = function(doc) { this.document = doc || document; this.suiteDivs = {}; this.logRunningSpecs = false; }; jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) { var el = document.createElement(type); for (var i = 2; i < arguments.length; i++) { var child = arguments[i]; if (typeof child === 'string') { el.appendChild(document.createTextNode(child)); } else { if (child) { el.appendChild(child); } } } for (var attr in attrs) { if (attr == "className") { el[attr] = attrs[attr]; } else { el.setAttribute(attr, attrs[attr]); } } return el; }; jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) { var showPassed, showSkipped; this.outerDiv = this.createDom('div', { id: 'TrivialReporter', className: 'jasmine_reporter' }, this.createDom('div', { className: 'banner' }, this.createDom('div', { className: 'logo' }, this.createDom('span', { className: 'title' }, "Jasmine"), this.createDom('span', { className: 'version' }, runner.env.versionString())), this.createDom('div', { className: 'options' }, "Show ", showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }), this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "), showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }), this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped") ) ), this.runnerDiv = this.createDom('div', { className: 'runner running' }, this.createDom('a', { className: 'run_spec', href: '?' }, "run all"), this.runnerMessageSpan = this.createDom('span', {}, "Running..."), this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, "")) ); this.document.body.appendChild(this.outerDiv); var suites = runner.suites(); for (var i = 0; i < suites.length; i++) { var suite = suites[i]; var suiteDiv = this.createDom('div', { className: 'suite' }, this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"), this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description)); this.suiteDivs[suite.id] = suiteDiv; var parentDiv = this.outerDiv; if (suite.parentSuite) { parentDiv = this.suiteDivs[suite.parentSuite.id]; } parentDiv.appendChild(suiteDiv); } this.startedAt = new Date(); var self = this; showPassed.onclick = function(evt) { if (showPassed.checked) { self.outerDiv.className += ' show-passed'; } else { self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, ''); } }; showSkipped.onclick = function(evt) { if (showSkipped.checked) { self.outerDiv.className += ' show-skipped'; } else { self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, ''); } }; }; jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) { var results = runner.results(); var className = (results.failedCount > 0) ? "runner failed" : "runner passed"; this.runnerDiv.setAttribute("class", className); //do it twice for IE this.runnerDiv.setAttribute("className", className); var specs = runner.specs(); var specCount = 0; for (var i = 0; i < specs.length; i++) { if (this.specFilter(specs[i])) { specCount++; } } var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s"); message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s"; this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild); this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString())); }; jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) { var results = suite.results(); var status = results.passed() ? 'passed' : 'failed'; if (results.totalCount === 0) { // todo: change this to check results.skipped status = 'skipped'; } this.suiteDivs[suite.id].className += " " + status; }; jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) { if (this.logRunningSpecs) { this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...'); } }; jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) { var results = spec.results(); var status = results.passed() ? 'passed' : 'failed'; if (results.skipped) { status = 'skipped'; } var specDiv = this.createDom('div', { className: 'spec ' + status }, this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"), this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(spec.getFullName()), title: spec.getFullName() }, spec.description)); var resultItems = results.getItems(); var messagesDiv = this.createDom('div', { className: 'messages' }); for (var i = 0; i < resultItems.length; i++) { var result = resultItems[i]; if (result.type == 'log') { messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString())); } else if (result.type == 'expect' && result.passed && !result.passed()) { messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message)); if (result.trace.stack) { messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack)); } } } if (messagesDiv.childNodes.length > 0) { specDiv.appendChild(messagesDiv); } this.suiteDivs[spec.suite.id].appendChild(specDiv); }; jasmine.TrivialReporter.prototype.log = function() { var console = jasmine.getGlobal().console; if (console && console.log) { if (console.log.apply) { console.log.apply(console, arguments); } else { console.log(arguments); // ie fix: console.log.apply doesn't exist on ie } } }; jasmine.TrivialReporter.prototype.getLocation = function() { return this.document.location; }; jasmine.TrivialReporter.prototype.specFilter = function(spec) { var paramMap = {}; var params = this.getLocation().search.substring(1).split('&'); for (var i = 0; i < params.length; i++) { var p = params[i].split('='); paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]); } if (!paramMap.spec) { return true; } return spec.getFullName().indexOf(paramMap.spec) === 0; }; less.js-1.4.2/test/browser/jasmine.css000066400000000000000000000146111217256642200177130ustar00rootroot00000000000000body { background-color: #eeeeee; padding: 0; margin: 5px; overflow-y: scroll; } #HTMLReporter { font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333333; } #HTMLReporter a { text-decoration: none; } #HTMLReporter a:hover { text-decoration: underline; } #HTMLReporter p, #HTMLReporter h1, #HTMLReporter h2, #HTMLReporter h3, #HTMLReporter h4, #HTMLReporter h5, #HTMLReporter h6 { margin: 0; line-height: 14px; } #HTMLReporter .banner, #HTMLReporter .symbolSummary, #HTMLReporter .summary, #HTMLReporter .resultMessage, #HTMLReporter .specDetail .description, #HTMLReporter .alert .bar, #HTMLReporter .stackTrace { padding-left: 9px; padding-right: 9px; } #HTMLReporter #jasmine_content { position: fixed; right: 100%; } #HTMLReporter .version { color: #aaaaaa; } #HTMLReporter .banner { margin-top: 14px; } #HTMLReporter .duration { color: #aaaaaa; float: right; } #HTMLReporter .symbolSummary { overflow: hidden; *zoom: 1; margin: 14px 0; } #HTMLReporter .symbolSummary li { display: block; float: left; height: 7px; width: 14px; margin-bottom: 7px; font-size: 16px; } #HTMLReporter .symbolSummary li.passed { font-size: 14px; } #HTMLReporter .symbolSummary li.passed:before { color: #5e7d00; content: "\02022"; } #HTMLReporter .symbolSummary li.failed { line-height: 9px; } #HTMLReporter .symbolSummary li.failed:before { color: #b03911; content: "x"; font-weight: bold; margin-left: -1px; } #HTMLReporter .symbolSummary li.skipped { font-size: 14px; } #HTMLReporter .symbolSummary li.skipped:before { color: #bababa; content: "\02022"; } #HTMLReporter .symbolSummary li.pending { line-height: 11px; } #HTMLReporter .symbolSummary li.pending:before { color: #aaaaaa; content: "-"; } #HTMLReporter .exceptions { color: #fff; float: right; margin-top: 5px; margin-right: 5px; } #HTMLReporter .bar { line-height: 28px; font-size: 14px; display: block; color: #eee; } #HTMLReporter .runningAlert { background-color: #666666; } #HTMLReporter .skippedAlert { background-color: #aaaaaa; } #HTMLReporter .skippedAlert:first-child { background-color: #333333; } #HTMLReporter .skippedAlert:hover { text-decoration: none; color: white; text-decoration: underline; } #HTMLReporter .passingAlert { background-color: #a6b779; } #HTMLReporter .passingAlert:first-child { background-color: #5e7d00; } #HTMLReporter .failingAlert { background-color: #cf867e; } #HTMLReporter .failingAlert:first-child { background-color: #b03911; } #HTMLReporter .results { margin-top: 14px; } #HTMLReporter #details { display: none; } #HTMLReporter .resultsMenu, #HTMLReporter .resultsMenu a { background-color: #fff; color: #333333; } #HTMLReporter.showDetails .summaryMenuItem { font-weight: normal; text-decoration: inherit; } #HTMLReporter.showDetails .summaryMenuItem:hover { text-decoration: underline; } #HTMLReporter.showDetails .detailsMenuItem { font-weight: bold; text-decoration: underline; } #HTMLReporter.showDetails .summary { display: none; } #HTMLReporter.showDetails #details { display: block; } #HTMLReporter .summaryMenuItem { font-weight: bold; text-decoration: underline; } #HTMLReporter .summary { margin-top: 14px; } #HTMLReporter .summary .suite .suite, #HTMLReporter .summary .specSummary { margin-left: 14px; } #HTMLReporter .summary .specSummary.passed a { color: #5e7d00; } #HTMLReporter .summary .specSummary.failed a { color: #b03911; } #HTMLReporter .description + .suite { margin-top: 0; } #HTMLReporter .suite { margin-top: 14px; } #HTMLReporter .suite a { color: #333333; } #HTMLReporter #details .specDetail { margin-bottom: 28px; } #HTMLReporter #details .specDetail .description { display: block; color: white; background-color: #b03911; } #HTMLReporter .resultMessage { padding-top: 14px; color: #333333; } #HTMLReporter .resultMessage span.result { display: block; } #HTMLReporter .stackTrace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666666; border: 1px solid #ddd; background: white; white-space: pre; } #TrivialReporter { padding: 8px 13px; position: absolute; top: 0; bottom: 0; left: 0; right: 0; overflow-y: scroll; background-color: white; font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif; /*.resultMessage {*/ /*white-space: pre;*/ /*}*/ } #TrivialReporter a:visited, #TrivialReporter a { color: #303; } #TrivialReporter a:hover, #TrivialReporter a:active { color: blue; } #TrivialReporter .run_spec { float: right; padding-right: 5px; font-size: .8em; text-decoration: none; } #TrivialReporter .banner { color: #303; background-color: #fef; padding: 5px; } #TrivialReporter .logo { float: left; font-size: 1.1em; padding-left: 5px; } #TrivialReporter .logo .version { font-size: .6em; padding-left: 1em; } #TrivialReporter .runner.running { background-color: yellow; } #TrivialReporter .options { text-align: right; font-size: .8em; } #TrivialReporter .suite { border: 1px outset gray; margin: 5px 0; padding-left: 1em; } #TrivialReporter .suite .suite { margin: 5px; } #TrivialReporter .suite.passed { background-color: #dfd; } #TrivialReporter .suite.failed { background-color: #fdd; } #TrivialReporter .spec { margin: 5px; padding-left: 1em; clear: both; } #TrivialReporter .spec.failed, #TrivialReporter .spec.passed, #TrivialReporter .spec.skipped { padding-bottom: 5px; border: 1px solid gray; } #TrivialReporter .spec.failed { background-color: #fbb; border-color: red; } #TrivialReporter .spec.passed { background-color: #bfb; border-color: green; } #TrivialReporter .spec.skipped { background-color: #bbb; } #TrivialReporter .messages { border-left: 1px dashed gray; padding-left: 1em; padding-right: 1em; } #TrivialReporter .passed { background-color: #cfc; display: none; } #TrivialReporter .failed { background-color: #fbb; } #TrivialReporter .skipped { color: #777; background-color: #eee; display: none; } #TrivialReporter .resultMessage span.result { display: block; line-height: 2em; color: black; } #TrivialReporter .resultMessage .mismatch { color: black; } #TrivialReporter .stackTrace { white-space: pre; font-size: .8em; margin-left: 10px; max-height: 5em; overflow: auto; border: 1px inset red; padding: 1em; background: #eef; } #TrivialReporter .finished-at { padding-left: 1em; font-size: .6em; } #TrivialReporter.show-passed .passed, #TrivialReporter.show-skipped .skipped { display: block; } #TrivialReporter #jasmine_content { position: fixed; right: 100%; } #TrivialReporter .runner { border: 1px solid gray; display: block; margin: 5px 0; padding: 2px 0 2px 10px; } less.js-1.4.2/test/browser/jasmine.js000066400000000000000000002123541217256642200175430ustar00rootroot00000000000000var isCommonJS = typeof window == "undefined" && typeof exports == "object"; /** * Top level namespace for Jasmine, a lightweight JavaScript BDD/spec/testing framework. * * @namespace */ var jasmine = {}; if (isCommonJS) exports.jasmine = jasmine; /** * @private */ jasmine.unimplementedMethod_ = function() { throw new Error("unimplemented method"); }; /** * Use jasmine.undefined instead of undefined, since undefined is just * a plain old variable and may be redefined by somebody else. * * @private */ jasmine.undefined = jasmine.___undefined___; /** * Show diagnostic messages in the console if set to true * */ jasmine.VERBOSE = false; /** * Default interval in milliseconds for event loop yields (e.g. to allow network activity or to refresh the screen with the HTML-based runner). Small values here may result in slow test running. Zero means no updates until all tests have completed. * */ jasmine.DEFAULT_UPDATE_INTERVAL = 250; /** * Maximum levels of nesting that will be included when an object is pretty-printed */ jasmine.MAX_PRETTY_PRINT_DEPTH = 40; /** * Default timeout interval in milliseconds for waitsFor() blocks. */ jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000; /** * By default exceptions thrown in the context of a test are caught by jasmine so that it can run the remaining tests in the suite. * Set to false to let the exception bubble up in the browser. * */ jasmine.CATCH_EXCEPTIONS = true; jasmine.getGlobal = function() { function getGlobal() { return this; } return getGlobal(); }; /** * Allows for bound functions to be compared. Internal use only. * * @ignore * @private * @param base {Object} bound 'this' for the function * @param name {Function} function to find */ jasmine.bindOriginal_ = function(base, name) { var original = base[name]; if (original.apply) { return function() { return original.apply(base, arguments); }; } else { // IE support return jasmine.getGlobal()[name]; } }; jasmine.setTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'setTimeout'); jasmine.clearTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearTimeout'); jasmine.setInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'setInterval'); jasmine.clearInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearInterval'); jasmine.MessageResult = function(values) { this.type = 'log'; this.values = values; this.trace = new Error(); // todo: test better }; jasmine.MessageResult.prototype.toString = function() { var text = ""; for (var i = 0; i < this.values.length; i++) { if (i > 0) text += " "; if (jasmine.isString_(this.values[i])) { text += this.values[i]; } else { text += jasmine.pp(this.values[i]); } } return text; }; jasmine.ExpectationResult = function(params) { this.type = 'expect'; this.matcherName = params.matcherName; this.passed_ = params.passed; this.expected = params.expected; this.actual = params.actual; this.message = this.passed_ ? 'Passed.' : params.message; var trace = (params.trace || new Error(this.message)); this.trace = this.passed_ ? '' : trace; }; jasmine.ExpectationResult.prototype.toString = function () { return this.message; }; jasmine.ExpectationResult.prototype.passed = function () { return this.passed_; }; /** * Getter for the Jasmine environment. Ensures one gets created */ jasmine.getEnv = function() { var env = jasmine.currentEnv_ = jasmine.currentEnv_ || new jasmine.Env(); return env; }; /** * @ignore * @private * @param value * @returns {Boolean} */ jasmine.isArray_ = function(value) { return jasmine.isA_("Array", value); }; /** * @ignore * @private * @param value * @returns {Boolean} */ jasmine.isString_ = function(value) { return jasmine.isA_("String", value); }; /** * @ignore * @private * @param value * @returns {Boolean} */ jasmine.isNumber_ = function(value) { return jasmine.isA_("Number", value); }; /** * @ignore * @private * @param {String} typeName * @param value * @returns {Boolean} */ jasmine.isA_ = function(typeName, value) { return Object.prototype.toString.apply(value) === '[object ' + typeName + ']'; }; /** * Pretty printer for expecations. Takes any object and turns it into a human-readable string. * * @param value {Object} an object to be outputted * @returns {String} */ jasmine.pp = function(value) { var stringPrettyPrinter = new jasmine.StringPrettyPrinter(); stringPrettyPrinter.format(value); return stringPrettyPrinter.string; }; /** * Returns true if the object is a DOM Node. * * @param {Object} obj object to check * @returns {Boolean} */ jasmine.isDomNode = function(obj) { return obj.nodeType > 0; }; /** * Returns a matchable 'generic' object of the class type. For use in expecations of type when values don't matter. * * @example * // don't care about which function is passed in, as long as it's a function * expect(mySpy).toHaveBeenCalledWith(jasmine.any(Function)); * * @param {Class} clazz * @returns matchable object of the type clazz */ jasmine.any = function(clazz) { return new jasmine.Matchers.Any(clazz); }; /** * Returns a matchable subset of a JSON object. For use in expectations when you don't care about all of the * attributes on the object. * * @example * // don't care about any other attributes than foo. * expect(mySpy).toHaveBeenCalledWith(jasmine.objectContaining({foo: "bar"}); * * @param sample {Object} sample * @returns matchable object for the sample */ jasmine.objectContaining = function (sample) { return new jasmine.Matchers.ObjectContaining(sample); }; /** * Jasmine Spies are test doubles that can act as stubs, spies, fakes or when used in an expecation, mocks. * * Spies should be created in test setup, before expectations. They can then be checked, using the standard Jasmine * expectation syntax. Spies can be checked if they were called or not and what the calling params were. * * A Spy has the following fields: wasCalled, callCount, mostRecentCall, and argsForCall (see docs). * * Spies are torn down at the end of every spec. * * Note: Do not call new jasmine.Spy() directly - a spy must be created using spyOn, jasmine.createSpy or jasmine.createSpyObj. * * @example * // a stub * var myStub = jasmine.createSpy('myStub'); // can be used anywhere * * // spy example * var foo = { * not: function(bool) { return !bool; } * } * * // actual foo.not will not be called, execution stops * spyOn(foo, 'not'); // foo.not spied upon, execution will continue to implementation * spyOn(foo, 'not').andCallThrough(); * * // fake example * var foo = { * not: function(bool) { return !bool; } * } * * // foo.not(val) will return val * spyOn(foo, 'not').andCallFake(function(value) {return value;}); * * // mock example * foo.not(7 == 7); * expect(foo.not).toHaveBeenCalled(); * expect(foo.not).toHaveBeenCalledWith(true); * * @constructor * @see spyOn, jasmine.createSpy, jasmine.createSpyObj * @param {String} name */ jasmine.Spy = function(name) { /** * The name of the spy, if provided. */ this.identity = name || 'unknown'; /** * Is this Object a spy? */ this.isSpy = true; /** * The actual function this spy stubs. */ this.plan = function() { }; /** * Tracking of the most recent call to the spy. * @example * var mySpy = jasmine.createSpy('foo'); * mySpy(1, 2); * mySpy.mostRecentCall.args = [1, 2]; */ this.mostRecentCall = {}; /** * Holds arguments for each call to the spy, indexed by call count * @example * var mySpy = jasmine.createSpy('foo'); * mySpy(1, 2); * mySpy(7, 8); * mySpy.mostRecentCall.args = [7, 8]; * mySpy.argsForCall[0] = [1, 2]; * mySpy.argsForCall[1] = [7, 8]; */ this.argsForCall = []; this.calls = []; }; /** * Tells a spy to call through to the actual implemenatation. * * @example * var foo = { * bar: function() { // do some stuff } * } * * // defining a spy on an existing property: foo.bar * spyOn(foo, 'bar').andCallThrough(); */ jasmine.Spy.prototype.andCallThrough = function() { this.plan = this.originalValue; return this; }; /** * For setting the return value of a spy. * * @example * // defining a spy from scratch: foo() returns 'baz' * var foo = jasmine.createSpy('spy on foo').andReturn('baz'); * * // defining a spy on an existing property: foo.bar() returns 'baz' * spyOn(foo, 'bar').andReturn('baz'); * * @param {Object} value */ jasmine.Spy.prototype.andReturn = function(value) { this.plan = function() { return value; }; return this; }; /** * For throwing an exception when a spy is called. * * @example * // defining a spy from scratch: foo() throws an exception w/ message 'ouch' * var foo = jasmine.createSpy('spy on foo').andThrow('baz'); * * // defining a spy on an existing property: foo.bar() throws an exception w/ message 'ouch' * spyOn(foo, 'bar').andThrow('baz'); * * @param {String} exceptionMsg */ jasmine.Spy.prototype.andThrow = function(exceptionMsg) { this.plan = function() { throw exceptionMsg; }; return this; }; /** * Calls an alternate implementation when a spy is called. * * @example * var baz = function() { * // do some stuff, return something * } * // defining a spy from scratch: foo() calls the function baz * var foo = jasmine.createSpy('spy on foo').andCall(baz); * * // defining a spy on an existing property: foo.bar() calls an anonymnous function * spyOn(foo, 'bar').andCall(function() { return 'baz';} ); * * @param {Function} fakeFunc */ jasmine.Spy.prototype.andCallFake = function(fakeFunc) { this.plan = fakeFunc; return this; }; /** * Resets all of a spy's the tracking variables so that it can be used again. * * @example * spyOn(foo, 'bar'); * * foo.bar(); * * expect(foo.bar.callCount).toEqual(1); * * foo.bar.reset(); * * expect(foo.bar.callCount).toEqual(0); */ jasmine.Spy.prototype.reset = function() { this.wasCalled = false; this.callCount = 0; this.argsForCall = []; this.calls = []; this.mostRecentCall = {}; }; jasmine.createSpy = function(name) { var spyObj = function() { spyObj.wasCalled = true; spyObj.callCount++; var args = jasmine.util.argsToArray(arguments); spyObj.mostRecentCall.object = this; spyObj.mostRecentCall.args = args; spyObj.argsForCall.push(args); spyObj.calls.push({object: this, args: args}); return spyObj.plan.apply(this, arguments); }; var spy = new jasmine.Spy(name); for (var prop in spy) { spyObj[prop] = spy[prop]; } spyObj.reset(); return spyObj; }; /** * Determines whether an object is a spy. * * @param {jasmine.Spy|Object} putativeSpy * @returns {Boolean} */ jasmine.isSpy = function(putativeSpy) { return putativeSpy && putativeSpy.isSpy; }; /** * Creates a more complicated spy: an Object that has every property a function that is a spy. Used for stubbing something * large in one call. * * @param {String} baseName name of spy class * @param {Array} methodNames array of names of methods to make spies */ jasmine.createSpyObj = function(baseName, methodNames) { if (!jasmine.isArray_(methodNames) || methodNames.length === 0) { throw new Error('createSpyObj requires a non-empty array of method names to create spies for'); } var obj = {}; for (var i = 0; i < methodNames.length; i++) { obj[methodNames[i]] = jasmine.createSpy(baseName + '.' + methodNames[i]); } return obj; }; /** * All parameters are pretty-printed and concatenated together, then written to the current spec's output. * * Be careful not to leave calls to jasmine.log in production code. */ jasmine.log = function() { var spec = jasmine.getEnv().currentSpec; spec.log.apply(spec, arguments); }; /** * Function that installs a spy on an existing object's method name. Used within a Spec to create a spy. * * @example * // spy example * var foo = { * not: function(bool) { return !bool; } * } * spyOn(foo, 'not'); // actual foo.not will not be called, execution stops * * @see jasmine.createSpy * @param obj * @param methodName * @return {jasmine.Spy} a Jasmine spy that can be chained with all spy methods */ var spyOn = function(obj, methodName) { return jasmine.getEnv().currentSpec.spyOn(obj, methodName); }; if (isCommonJS) exports.spyOn = spyOn; /** * Creates a Jasmine spec that will be added to the current suite. * * // TODO: pending tests * * @example * it('should be true', function() { * expect(true).toEqual(true); * }); * * @param {String} desc description of this specification * @param {Function} func defines the preconditions and expectations of the spec */ var it = function(desc, func) { return jasmine.getEnv().it(desc, func); }; if (isCommonJS) exports.it = it; /** * Creates a disabled Jasmine spec. * * A convenience method that allows existing specs to be disabled temporarily during development. * * @param {String} desc description of this specification * @param {Function} func defines the preconditions and expectations of the spec */ var xit = function(desc, func) { return jasmine.getEnv().xit(desc, func); }; if (isCommonJS) exports.xit = xit; /** * Starts a chain for a Jasmine expectation. * * It is passed an Object that is the actual value and should chain to one of the many * jasmine.Matchers functions. * * @param {Object} actual Actual value to test against and expected value * @return {jasmine.Matchers} */ var expect = function(actual) { return jasmine.getEnv().currentSpec.expect(actual); }; if (isCommonJS) exports.expect = expect; /** * Defines part of a jasmine spec. Used in cominbination with waits or waitsFor in asynchrnous specs. * * @param {Function} func Function that defines part of a jasmine spec. */ var runs = function(func) { jasmine.getEnv().currentSpec.runs(func); }; if (isCommonJS) exports.runs = runs; /** * Waits a fixed time period before moving to the next block. * * @deprecated Use waitsFor() instead * @param {Number} timeout milliseconds to wait */ var waits = function(timeout) { jasmine.getEnv().currentSpec.waits(timeout); }; if (isCommonJS) exports.waits = waits; /** * Waits for the latchFunction to return true before proceeding to the next block. * * @param {Function} latchFunction * @param {String} optional_timeoutMessage * @param {Number} optional_timeout */ var waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) { jasmine.getEnv().currentSpec.waitsFor.apply(jasmine.getEnv().currentSpec, arguments); }; if (isCommonJS) exports.waitsFor = waitsFor; /** * A function that is called before each spec in a suite. * * Used for spec setup, including validating assumptions. * * @param {Function} beforeEachFunction */ var beforeEach = function(beforeEachFunction) { jasmine.getEnv().beforeEach(beforeEachFunction); }; if (isCommonJS) exports.beforeEach = beforeEach; /** * A function that is called after each spec in a suite. * * Used for restoring any state that is hijacked during spec execution. * * @param {Function} afterEachFunction */ var afterEach = function(afterEachFunction) { jasmine.getEnv().afterEach(afterEachFunction); }; if (isCommonJS) exports.afterEach = afterEach; /** * Defines a suite of specifications. * * Stores the description and all defined specs in the Jasmine environment as one suite of specs. Variables declared * are accessible by calls to beforeEach, it, and afterEach. Describe blocks can be nested, allowing for specialization * of setup in some tests. * * @example * // TODO: a simple suite * * // TODO: a simple suite with a nested describe block * * @param {String} description A string, usually the class under test. * @param {Function} specDefinitions function that defines several specs. */ var describe = function(description, specDefinitions) { return jasmine.getEnv().describe(description, specDefinitions); }; if (isCommonJS) exports.describe = describe; /** * Disables a suite of specifications. Used to disable some suites in a file, or files, temporarily during development. * * @param {String} description A string, usually the class under test. * @param {Function} specDefinitions function that defines several specs. */ var xdescribe = function(description, specDefinitions) { return jasmine.getEnv().xdescribe(description, specDefinitions); }; if (isCommonJS) exports.xdescribe = xdescribe; // Provide the XMLHttpRequest class for IE 5.x-6.x: jasmine.XmlHttpRequest = (typeof XMLHttpRequest == "undefined") ? function() { function tryIt(f) { try { return f(); } catch(e) { } return null; } var xhr = tryIt(function() { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); }) || tryIt(function() { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); }) || tryIt(function() { return new ActiveXObject("Msxml2.XMLHTTP"); }) || tryIt(function() { return new ActiveXObject("Microsoft.XMLHTTP"); }); if (!xhr) throw new Error("This browser does not support XMLHttpRequest."); return xhr; } : XMLHttpRequest; /** * @namespace */ jasmine.util = {}; /** * Declare that a child class inherit it's prototype from the parent class. * * @private * @param {Function} childClass * @param {Function} parentClass */ jasmine.util.inherit = function(childClass, parentClass) { /** * @private */ var subclass = function() { }; subclass.prototype = parentClass.prototype; childClass.prototype = new subclass(); }; jasmine.util.formatException = function(e) { var lineNumber; if (e.line) { lineNumber = e.line; } else if (e.lineNumber) { lineNumber = e.lineNumber; } var file; if (e.sourceURL) { file = e.sourceURL; } else if (e.fileName) { file = e.fileName; } var message = (e.name && e.message) ? (e.name + ': ' + e.message) : e.toString(); if (file && lineNumber) { message += ' in ' + file + ' (line ' + lineNumber + ')'; } return message; }; jasmine.util.htmlEscape = function(str) { if (!str) return str; return str.replace(/&/g, '&') .replace(//g, '>'); }; jasmine.util.argsToArray = function(args) { var arrayOfArgs = []; for (var i = 0; i < args.length; i++) arrayOfArgs.push(args[i]); return arrayOfArgs; }; jasmine.util.extend = function(destination, source) { for (var property in source) destination[property] = source[property]; return destination; }; /** * Environment for Jasmine * * @constructor */ jasmine.Env = function() { this.currentSpec = null; this.currentSuite = null; this.currentRunner_ = new jasmine.Runner(this); this.reporter = new jasmine.MultiReporter(); this.updateInterval = jasmine.DEFAULT_UPDATE_INTERVAL; this.defaultTimeoutInterval = jasmine.DEFAULT_TIMEOUT_INTERVAL; this.lastUpdate = 0; this.specFilter = function() { return true; }; this.nextSpecId_ = 0; this.nextSuiteId_ = 0; this.equalityTesters_ = []; // wrap matchers this.matchersClass = function() { jasmine.Matchers.apply(this, arguments); }; jasmine.util.inherit(this.matchersClass, jasmine.Matchers); jasmine.Matchers.wrapInto_(jasmine.Matchers.prototype, this.matchersClass); }; jasmine.Env.prototype.setTimeout = jasmine.setTimeout; jasmine.Env.prototype.clearTimeout = jasmine.clearTimeout; jasmine.Env.prototype.setInterval = jasmine.setInterval; jasmine.Env.prototype.clearInterval = jasmine.clearInterval; /** * @returns an object containing jasmine version build info, if set. */ jasmine.Env.prototype.version = function () { if (jasmine.version_) { return jasmine.version_; } else { throw new Error('Version not set'); } }; /** * @returns string containing jasmine version build info, if set. */ jasmine.Env.prototype.versionString = function() { if (!jasmine.version_) { return "version unknown"; } var version = this.version(); var versionString = version.major + "." + version.minor + "." + version.build; if (version.release_candidate) { versionString += ".rc" + version.release_candidate; } versionString += " revision " + version.revision; return versionString; }; /** * @returns a sequential integer starting at 0 */ jasmine.Env.prototype.nextSpecId = function () { return this.nextSpecId_++; }; /** * @returns a sequential integer starting at 0 */ jasmine.Env.prototype.nextSuiteId = function () { return this.nextSuiteId_++; }; /** * Register a reporter to receive status updates from Jasmine. * @param {jasmine.Reporter} reporter An object which will receive status updates. */ jasmine.Env.prototype.addReporter = function(reporter) { this.reporter.addReporter(reporter); }; jasmine.Env.prototype.execute = function() { this.currentRunner_.execute(); }; jasmine.Env.prototype.describe = function(description, specDefinitions) { var suite = new jasmine.Suite(this, description, specDefinitions, this.currentSuite); var parentSuite = this.currentSuite; if (parentSuite) { parentSuite.add(suite); } else { this.currentRunner_.add(suite); } this.currentSuite = suite; var declarationError = null; try { specDefinitions.call(suite); } catch(e) { declarationError = e; } if (declarationError) { this.it("encountered a declaration exception", function() { throw declarationError; }); } this.currentSuite = parentSuite; return suite; }; jasmine.Env.prototype.beforeEach = function(beforeEachFunction) { if (this.currentSuite) { this.currentSuite.beforeEach(beforeEachFunction); } else { this.currentRunner_.beforeEach(beforeEachFunction); } }; jasmine.Env.prototype.currentRunner = function () { return this.currentRunner_; }; jasmine.Env.prototype.afterEach = function(afterEachFunction) { if (this.currentSuite) { this.currentSuite.afterEach(afterEachFunction); } else { this.currentRunner_.afterEach(afterEachFunction); } }; jasmine.Env.prototype.xdescribe = function(desc, specDefinitions) { return { execute: function() { } }; }; jasmine.Env.prototype.it = function(description, func) { var spec = new jasmine.Spec(this, this.currentSuite, description); this.currentSuite.add(spec); this.currentSpec = spec; if (func) { spec.runs(func); } return spec; }; jasmine.Env.prototype.xit = function(desc, func) { return { id: this.nextSpecId(), runs: function() { } }; }; jasmine.Env.prototype.compareRegExps_ = function(a, b, mismatchKeys, mismatchValues) { if (a.source != b.source) mismatchValues.push("expected pattern /" + b.source + "/ is not equal to the pattern /" + a.source + "/"); if (a.ignoreCase != b.ignoreCase) mismatchValues.push("expected modifier i was" + (b.ignoreCase ? " " : " not ") + "set and does not equal the origin modifier"); if (a.global != b.global) mismatchValues.push("expected modifier g was" + (b.global ? " " : " not ") + "set and does not equal the origin modifier"); if (a.multiline != b.multiline) mismatchValues.push("expected modifier m was" + (b.multiline ? " " : " not ") + "set and does not equal the origin modifier"); if (a.sticky != b.sticky) mismatchValues.push("expected modifier y was" + (b.sticky ? " " : " not ") + "set and does not equal the origin modifier"); return (mismatchValues.length === 0); }; jasmine.Env.prototype.compareObjects_ = function(a, b, mismatchKeys, mismatchValues) { if (a.__Jasmine_been_here_before__ === b && b.__Jasmine_been_here_before__ === a) { return true; } a.__Jasmine_been_here_before__ = b; b.__Jasmine_been_here_before__ = a; var hasKey = function(obj, keyName) { return obj !== null && obj[keyName] !== jasmine.undefined; }; for (var property in b) { if (!hasKey(a, property) && hasKey(b, property)) { mismatchKeys.push("expected has key '" + property + "', but missing from actual."); } } for (property in a) { if (!hasKey(b, property) && hasKey(a, property)) { mismatchKeys.push("expected missing key '" + property + "', but present in actual."); } } for (property in b) { if (property == '__Jasmine_been_here_before__') continue; if (!this.equals_(a[property], b[property], mismatchKeys, mismatchValues)) { mismatchValues.push("'" + property + "' was '" + (b[property] ? jasmine.util.htmlEscape(b[property].toString()) : b[property]) + "' in expected, but was '" + (a[property] ? jasmine.util.htmlEscape(a[property].toString()) : a[property]) + "' in actual."); } } if (jasmine.isArray_(a) && jasmine.isArray_(b) && a.length != b.length) { mismatchValues.push("arrays were not the same length"); } delete a.__Jasmine_been_here_before__; delete b.__Jasmine_been_here_before__; return (mismatchKeys.length === 0 && mismatchValues.length === 0); }; jasmine.Env.prototype.equals_ = function(a, b, mismatchKeys, mismatchValues) { mismatchKeys = mismatchKeys || []; mismatchValues = mismatchValues || []; for (var i = 0; i < this.equalityTesters_.length; i++) { var equalityTester = this.equalityTesters_[i]; var result = equalityTester(a, b, this, mismatchKeys, mismatchValues); if (result !== jasmine.undefined) return result; } if (a === b) return true; if (a === jasmine.undefined || a === null || b === jasmine.undefined || b === null) { return (a == jasmine.undefined && b == jasmine.undefined); } if (jasmine.isDomNode(a) && jasmine.isDomNode(b)) { return a === b; } if (a instanceof Date && b instanceof Date) { return a.getTime() == b.getTime(); } if (a.jasmineMatches) { return a.jasmineMatches(b); } if (b.jasmineMatches) { return b.jasmineMatches(a); } if (a instanceof jasmine.Matchers.ObjectContaining) { return a.matches(b); } if (b instanceof jasmine.Matchers.ObjectContaining) { return b.matches(a); } if (jasmine.isString_(a) && jasmine.isString_(b)) { return (a == b); } if (jasmine.isNumber_(a) && jasmine.isNumber_(b)) { return (a == b); } if (a instanceof RegExp && b instanceof RegExp) { return this.compareRegExps_(a, b, mismatchKeys, mismatchValues); } if (typeof a === "object" && typeof b === "object") { return this.compareObjects_(a, b, mismatchKeys, mismatchValues); } //Straight check return (a === b); }; jasmine.Env.prototype.contains_ = function(haystack, needle) { if (jasmine.isArray_(haystack)) { for (var i = 0; i < haystack.length; i++) { if (this.equals_(haystack[i], needle)) return true; } return false; } return haystack.indexOf(needle) >= 0; }; jasmine.Env.prototype.addEqualityTester = function(equalityTester) { this.equalityTesters_.push(equalityTester); }; /** No-op base class for Jasmine reporters. * * @constructor */ jasmine.Reporter = function() { }; //noinspection JSUnusedLocalSymbols jasmine.Reporter.prototype.reportRunnerStarting = function(runner) { }; //noinspection JSUnusedLocalSymbols jasmine.Reporter.prototype.reportRunnerResults = function(runner) { }; //noinspection JSUnusedLocalSymbols jasmine.Reporter.prototype.reportSuiteResults = function(suite) { }; //noinspection JSUnusedLocalSymbols jasmine.Reporter.prototype.reportSpecStarting = function(spec) { }; //noinspection JSUnusedLocalSymbols jasmine.Reporter.prototype.reportSpecResults = function(spec) { }; //noinspection JSUnusedLocalSymbols jasmine.Reporter.prototype.log = function(str) { }; /** * Blocks are functions with executable code that make up a spec. * * @constructor * @param {jasmine.Env} env * @param {Function} func * @param {jasmine.Spec} spec */ jasmine.Block = function(env, func, spec) { this.env = env; this.func = func; this.spec = spec; }; jasmine.Block.prototype.execute = function(onComplete) { if (!jasmine.CATCH_EXCEPTIONS) { this.func.apply(this.spec); } else { try { this.func.apply(this.spec); } catch (e) { this.spec.fail(e); } } onComplete(); }; /** JavaScript API reporter. * * @constructor */ jasmine.JsApiReporter = function() { this.started = false; this.finished = false; this.suites_ = []; this.results_ = {}; }; jasmine.JsApiReporter.prototype.reportRunnerStarting = function(runner) { this.started = true; var suites = runner.topLevelSuites(); for (var i = 0; i < suites.length; i++) { var suite = suites[i]; this.suites_.push(this.summarize_(suite)); } }; jasmine.JsApiReporter.prototype.suites = function() { return this.suites_; }; jasmine.JsApiReporter.prototype.summarize_ = function(suiteOrSpec) { var isSuite = suiteOrSpec instanceof jasmine.Suite; var summary = { id: suiteOrSpec.id, name: suiteOrSpec.description, type: isSuite ? 'suite' : 'spec', children: [] }; if (isSuite) { var children = suiteOrSpec.children(); for (var i = 0; i < children.length; i++) { summary.children.push(this.summarize_(children[i])); } } return summary; }; jasmine.JsApiReporter.prototype.results = function() { return this.results_; }; jasmine.JsApiReporter.prototype.resultsForSpec = function(specId) { return this.results_[specId]; }; //noinspection JSUnusedLocalSymbols jasmine.JsApiReporter.prototype.reportRunnerResults = function(runner) { this.finished = true; }; //noinspection JSUnusedLocalSymbols jasmine.JsApiReporter.prototype.reportSuiteResults = function(suite) { }; //noinspection JSUnusedLocalSymbols jasmine.JsApiReporter.prototype.reportSpecResults = function(spec) { this.results_[spec.id] = { messages: spec.results().getItems(), result: spec.results().failedCount > 0 ? "failed" : "passed" }; }; //noinspection JSUnusedLocalSymbols jasmine.JsApiReporter.prototype.log = function(str) { }; jasmine.JsApiReporter.prototype.resultsForSpecs = function(specIds){ var results = {}; for (var i = 0; i < specIds.length; i++) { var specId = specIds[i]; results[specId] = this.summarizeResult_(this.results_[specId]); } return results; }; jasmine.JsApiReporter.prototype.summarizeResult_ = function(result){ var summaryMessages = []; var messagesLength = result.messages.length; for (var messageIndex = 0; messageIndex < messagesLength; messageIndex++) { var resultMessage = result.messages[messageIndex]; summaryMessages.push({ text: resultMessage.type == 'log' ? resultMessage.toString() : jasmine.undefined, passed: resultMessage.passed ? resultMessage.passed() : true, type: resultMessage.type, message: resultMessage.message, trace: { stack: resultMessage.passed && !resultMessage.passed() ? resultMessage.trace.stack : jasmine.undefined } }); } return { result : result.result, messages : summaryMessages }; }; /** * @constructor * @param {jasmine.Env} env * @param actual * @param {jasmine.Spec} spec */ jasmine.Matchers = function(env, actual, spec, opt_isNot) { this.env = env; this.actual = actual; this.spec = spec; this.isNot = opt_isNot || false; this.reportWasCalled_ = false; }; // todo: @deprecated as of Jasmine 0.11, remove soon [xw] jasmine.Matchers.pp = function(str) { throw new Error("jasmine.Matchers.pp() is no longer supported, please use jasmine.pp() instead!"); }; // todo: @deprecated Deprecated as of Jasmine 0.10. Rewrite your custom matchers to return true or false. [xw] jasmine.Matchers.prototype.report = function(result, failing_message, details) { throw new Error("As of jasmine 0.11, custom matchers must be implemented differently -- please see jasmine docs"); }; jasmine.Matchers.wrapInto_ = function(prototype, matchersClass) { for (var methodName in prototype) { if (methodName == 'report') continue; var orig = prototype[methodName]; matchersClass.prototype[methodName] = jasmine.Matchers.matcherFn_(methodName, orig); } }; jasmine.Matchers.matcherFn_ = function(matcherName, matcherFunction) { return function() { var matcherArgs = jasmine.util.argsToArray(arguments); var result = matcherFunction.apply(this, arguments); if (this.isNot) { result = !result; } if (this.reportWasCalled_) return result; var message; if (!result) { if (this.message) { message = this.message.apply(this, arguments); if (jasmine.isArray_(message)) { message = message[this.isNot ? 1 : 0]; } } else { var englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); }); message = "Expected " + jasmine.pp(this.actual) + (this.isNot ? " not " : " ") + englishyPredicate; if (matcherArgs.length > 0) { for (var i = 0; i < matcherArgs.length; i++) { if (i > 0) message += ","; message += " " + jasmine.pp(matcherArgs[i]); } } message += "."; } } var expectationResult = new jasmine.ExpectationResult({ matcherName: matcherName, passed: result, expected: matcherArgs.length > 1 ? matcherArgs : matcherArgs[0], actual: this.actual, message: message }); this.spec.addMatcherResult(expectationResult); return jasmine.undefined; }; }; /** * toBe: compares the actual to the expected using === * @param expected */ jasmine.Matchers.prototype.toBe = function(expected) { return this.actual === expected; }; /** * toNotBe: compares the actual to the expected using !== * @param expected * @deprecated as of 1.0. Use not.toBe() instead. */ jasmine.Matchers.prototype.toNotBe = function(expected) { return this.actual !== expected; }; /** * toEqual: compares the actual to the expected using common sense equality. Handles Objects, Arrays, etc. * * @param expected */ jasmine.Matchers.prototype.toEqual = function(expected) { return this.env.equals_(this.actual, expected); }; /** * toNotEqual: compares the actual to the expected using the ! of jasmine.Matchers.toEqual * @param expected * @deprecated as of 1.0. Use not.toEqual() instead. */ jasmine.Matchers.prototype.toNotEqual = function(expected) { return !this.env.equals_(this.actual, expected); }; /** * Matcher that compares the actual to the expected using a regular expression. Constructs a RegExp, so takes * a pattern or a String. * * @param expected */ jasmine.Matchers.prototype.toMatch = function(expected) { return new RegExp(expected).test(this.actual); }; /** * Matcher that compares the actual to the expected using the boolean inverse of jasmine.Matchers.toMatch * @param expected * @deprecated as of 1.0. Use not.toMatch() instead. */ jasmine.Matchers.prototype.toNotMatch = function(expected) { return !(new RegExp(expected).test(this.actual)); }; /** * Matcher that compares the actual to jasmine.undefined. */ jasmine.Matchers.prototype.toBeDefined = function() { return (this.actual !== jasmine.undefined); }; /** * Matcher that compares the actual to jasmine.undefined. */ jasmine.Matchers.prototype.toBeUndefined = function() { return (this.actual === jasmine.undefined); }; /** * Matcher that compares the actual to null. */ jasmine.Matchers.prototype.toBeNull = function() { return (this.actual === null); }; /** * Matcher that compares the actual to NaN. */ jasmine.Matchers.prototype.toBeNaN = function() { this.message = function() { return [ "Expected " + jasmine.pp(this.actual) + " to be NaN." ]; }; return (this.actual !== this.actual); }; /** * Matcher that boolean not-nots the actual. */ jasmine.Matchers.prototype.toBeTruthy = function() { return !!this.actual; }; /** * Matcher that boolean nots the actual. */ jasmine.Matchers.prototype.toBeFalsy = function() { return !this.actual; }; /** * Matcher that checks to see if the actual, a Jasmine spy, was called. */ jasmine.Matchers.prototype.toHaveBeenCalled = function() { if (arguments.length > 0) { throw new Error('toHaveBeenCalled does not take arguments, use toHaveBeenCalledWith'); } if (!jasmine.isSpy(this.actual)) { throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.'); } this.message = function() { return [ "Expected spy " + this.actual.identity + " to have been called.", "Expected spy " + this.actual.identity + " not to have been called." ]; }; return this.actual.wasCalled; }; /** @deprecated Use expect(xxx).toHaveBeenCalled() instead */ jasmine.Matchers.prototype.wasCalled = jasmine.Matchers.prototype.toHaveBeenCalled; /** * Matcher that checks to see if the actual, a Jasmine spy, was not called. * * @deprecated Use expect(xxx).not.toHaveBeenCalled() instead */ jasmine.Matchers.prototype.wasNotCalled = function() { if (arguments.length > 0) { throw new Error('wasNotCalled does not take arguments'); } if (!jasmine.isSpy(this.actual)) { throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.'); } this.message = function() { return [ "Expected spy " + this.actual.identity + " to not have been called.", "Expected spy " + this.actual.identity + " to have been called." ]; }; return !this.actual.wasCalled; }; /** * Matcher that checks to see if the actual, a Jasmine spy, was called with a set of parameters. * * @example * */ jasmine.Matchers.prototype.toHaveBeenCalledWith = function() { var expectedArgs = jasmine.util.argsToArray(arguments); if (!jasmine.isSpy(this.actual)) { throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.'); } this.message = function() { var invertedMessage = "Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but it was."; var positiveMessage = ""; if (this.actual.callCount === 0) { positiveMessage = "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but it was never called."; } else { positiveMessage = "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but actual calls were " + jasmine.pp(this.actual.argsForCall).replace(/^\[ | \]$/g, '') } return [positiveMessage, invertedMessage]; }; return this.env.contains_(this.actual.argsForCall, expectedArgs); }; /** @deprecated Use expect(xxx).toHaveBeenCalledWith() instead */ jasmine.Matchers.prototype.wasCalledWith = jasmine.Matchers.prototype.toHaveBeenCalledWith; /** @deprecated Use expect(xxx).not.toHaveBeenCalledWith() instead */ jasmine.Matchers.prototype.wasNotCalledWith = function() { var expectedArgs = jasmine.util.argsToArray(arguments); if (!jasmine.isSpy(this.actual)) { throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.'); } this.message = function() { return [ "Expected spy not to have been called with " + jasmine.pp(expectedArgs) + " but it was", "Expected spy to have been called with " + jasmine.pp(expectedArgs) + " but it was" ]; }; return !this.env.contains_(this.actual.argsForCall, expectedArgs); }; /** * Matcher that checks that the expected item is an element in the actual Array. * * @param {Object} expected */ jasmine.Matchers.prototype.toContain = function(expected) { return this.env.contains_(this.actual, expected); }; /** * Matcher that checks that the expected item is NOT an element in the actual Array. * * @param {Object} expected * @deprecated as of 1.0. Use not.toContain() instead. */ jasmine.Matchers.prototype.toNotContain = function(expected) { return !this.env.contains_(this.actual, expected); }; jasmine.Matchers.prototype.toBeLessThan = function(expected) { return this.actual < expected; }; jasmine.Matchers.prototype.toBeGreaterThan = function(expected) { return this.actual > expected; }; /** * Matcher that checks that the expected item is equal to the actual item * up to a given level of decimal precision (default 2). * * @param {Number} expected * @param {Number} precision, as number of decimal places */ jasmine.Matchers.prototype.toBeCloseTo = function(expected, precision) { if (!(precision === 0)) { precision = precision || 2; } return Math.abs(expected - this.actual) < (Math.pow(10, -precision) / 2); }; /** * Matcher that checks that the expected exception was thrown by the actual. * * @param {String} [expected] */ jasmine.Matchers.prototype.toThrow = function(expected) { var result = false; var exception; if (typeof this.actual != 'function') { throw new Error('Actual is not a function'); } try { this.actual(); } catch (e) { exception = e; } if (exception) { result = (expected === jasmine.undefined || this.env.equals_(exception.message || exception, expected.message || expected)); } var not = this.isNot ? "not " : ""; this.message = function() { if (exception && (expected === jasmine.undefined || !this.env.equals_(exception.message || exception, expected.message || expected))) { return ["Expected function " + not + "to throw", expected ? expected.message || expected : "an exception", ", but it threw", exception.message || exception].join(' '); } else { return "Expected function to throw an exception."; } }; return result; }; jasmine.Matchers.Any = function(expectedClass) { this.expectedClass = expectedClass; }; jasmine.Matchers.Any.prototype.jasmineMatches = function(other) { if (this.expectedClass == String) { return typeof other == 'string' || other instanceof String; } if (this.expectedClass == Number) { return typeof other == 'number' || other instanceof Number; } if (this.expectedClass == Function) { return typeof other == 'function' || other instanceof Function; } if (this.expectedClass == Object) { return typeof other == 'object'; } return other instanceof this.expectedClass; }; jasmine.Matchers.Any.prototype.jasmineToString = function() { return ''; }; jasmine.Matchers.ObjectContaining = function (sample) { this.sample = sample; }; jasmine.Matchers.ObjectContaining.prototype.jasmineMatches = function(other, mismatchKeys, mismatchValues) { mismatchKeys = mismatchKeys || []; mismatchValues = mismatchValues || []; var env = jasmine.getEnv(); var hasKey = function(obj, keyName) { return obj != null && obj[keyName] !== jasmine.undefined; }; for (var property in this.sample) { if (!hasKey(other, property) && hasKey(this.sample, property)) { mismatchKeys.push("expected has key '" + property + "', but missing from actual."); } else if (!env.equals_(this.sample[property], other[property], mismatchKeys, mismatchValues)) { mismatchValues.push("'" + property + "' was '" + (other[property] ? jasmine.util.htmlEscape(other[property].toString()) : other[property]) + "' in expected, but was '" + (this.sample[property] ? jasmine.util.htmlEscape(this.sample[property].toString()) : this.sample[property]) + "' in actual."); } } return (mismatchKeys.length === 0 && mismatchValues.length === 0); }; jasmine.Matchers.ObjectContaining.prototype.jasmineToString = function () { return ""; }; // Mock setTimeout, clearTimeout // Contributed by Pivotal Computer Systems, www.pivotalsf.com jasmine.FakeTimer = function() { this.reset(); var self = this; self.setTimeout = function(funcToCall, millis) { self.timeoutsMade++; self.scheduleFunction(self.timeoutsMade, funcToCall, millis, false); return self.timeoutsMade; }; self.setInterval = function(funcToCall, millis) { self.timeoutsMade++; self.scheduleFunction(self.timeoutsMade, funcToCall, millis, true); return self.timeoutsMade; }; self.clearTimeout = function(timeoutKey) { self.scheduledFunctions[timeoutKey] = jasmine.undefined; }; self.clearInterval = function(timeoutKey) { self.scheduledFunctions[timeoutKey] = jasmine.undefined; }; }; jasmine.FakeTimer.prototype.reset = function() { this.timeoutsMade = 0; this.scheduledFunctions = {}; this.nowMillis = 0; }; jasmine.FakeTimer.prototype.tick = function(millis) { var oldMillis = this.nowMillis; var newMillis = oldMillis + millis; this.runFunctionsWithinRange(oldMillis, newMillis); this.nowMillis = newMillis; }; jasmine.FakeTimer.prototype.runFunctionsWithinRange = function(oldMillis, nowMillis) { var scheduledFunc; var funcsToRun = []; for (var timeoutKey in this.scheduledFunctions) { scheduledFunc = this.scheduledFunctions[timeoutKey]; if (scheduledFunc != jasmine.undefined && scheduledFunc.runAtMillis >= oldMillis && scheduledFunc.runAtMillis <= nowMillis) { funcsToRun.push(scheduledFunc); this.scheduledFunctions[timeoutKey] = jasmine.undefined; } } if (funcsToRun.length > 0) { funcsToRun.sort(function(a, b) { return a.runAtMillis - b.runAtMillis; }); for (var i = 0; i < funcsToRun.length; ++i) { try { var funcToRun = funcsToRun[i]; this.nowMillis = funcToRun.runAtMillis; funcToRun.funcToCall(); if (funcToRun.recurring) { this.scheduleFunction(funcToRun.timeoutKey, funcToRun.funcToCall, funcToRun.millis, true); } } catch(e) { } } this.runFunctionsWithinRange(oldMillis, nowMillis); } }; jasmine.FakeTimer.prototype.scheduleFunction = function(timeoutKey, funcToCall, millis, recurring) { this.scheduledFunctions[timeoutKey] = { runAtMillis: this.nowMillis + millis, funcToCall: funcToCall, recurring: recurring, timeoutKey: timeoutKey, millis: millis }; }; /** * @namespace */ jasmine.Clock = { defaultFakeTimer: new jasmine.FakeTimer(), reset: function() { jasmine.Clock.assertInstalled(); jasmine.Clock.defaultFakeTimer.reset(); }, tick: function(millis) { jasmine.Clock.assertInstalled(); jasmine.Clock.defaultFakeTimer.tick(millis); }, runFunctionsWithinRange: function(oldMillis, nowMillis) { jasmine.Clock.defaultFakeTimer.runFunctionsWithinRange(oldMillis, nowMillis); }, scheduleFunction: function(timeoutKey, funcToCall, millis, recurring) { jasmine.Clock.defaultFakeTimer.scheduleFunction(timeoutKey, funcToCall, millis, recurring); }, useMock: function() { if (!jasmine.Clock.isInstalled()) { var spec = jasmine.getEnv().currentSpec; spec.after(jasmine.Clock.uninstallMock); jasmine.Clock.installMock(); } }, installMock: function() { jasmine.Clock.installed = jasmine.Clock.defaultFakeTimer; }, uninstallMock: function() { jasmine.Clock.assertInstalled(); jasmine.Clock.installed = jasmine.Clock.real; }, real: { setTimeout: jasmine.getGlobal().setTimeout, clearTimeout: jasmine.getGlobal().clearTimeout, setInterval: jasmine.getGlobal().setInterval, clearInterval: jasmine.getGlobal().clearInterval }, assertInstalled: function() { if (!jasmine.Clock.isInstalled()) { throw new Error("Mock clock is not installed, use jasmine.Clock.useMock()"); } }, isInstalled: function() { return jasmine.Clock.installed == jasmine.Clock.defaultFakeTimer; }, installed: null }; jasmine.Clock.installed = jasmine.Clock.real; //else for IE support jasmine.getGlobal().setTimeout = function(funcToCall, millis) { if (jasmine.Clock.installed.setTimeout.apply) { return jasmine.Clock.installed.setTimeout.apply(this, arguments); } else { return jasmine.Clock.installed.setTimeout(funcToCall, millis); } }; jasmine.getGlobal().setInterval = function(funcToCall, millis) { if (jasmine.Clock.installed.setInterval.apply) { return jasmine.Clock.installed.setInterval.apply(this, arguments); } else { return jasmine.Clock.installed.setInterval(funcToCall, millis); } }; jasmine.getGlobal().clearTimeout = function(timeoutKey) { if (jasmine.Clock.installed.clearTimeout.apply) { return jasmine.Clock.installed.clearTimeout.apply(this, arguments); } else { return jasmine.Clock.installed.clearTimeout(timeoutKey); } }; jasmine.getGlobal().clearInterval = function(timeoutKey) { if (jasmine.Clock.installed.clearTimeout.apply) { return jasmine.Clock.installed.clearInterval.apply(this, arguments); } else { return jasmine.Clock.installed.clearInterval(timeoutKey); } }; /** * @constructor */ jasmine.MultiReporter = function() { this.subReporters_ = []; }; jasmine.util.inherit(jasmine.MultiReporter, jasmine.Reporter); jasmine.MultiReporter.prototype.addReporter = function(reporter) { this.subReporters_.push(reporter); }; (function() { var functionNames = [ "reportRunnerStarting", "reportRunnerResults", "reportSuiteResults", "reportSpecStarting", "reportSpecResults", "log" ]; for (var i = 0; i < functionNames.length; i++) { var functionName = functionNames[i]; jasmine.MultiReporter.prototype[functionName] = (function(functionName) { return function() { for (var j = 0; j < this.subReporters_.length; j++) { var subReporter = this.subReporters_[j]; if (subReporter[functionName]) { subReporter[functionName].apply(subReporter, arguments); } } }; })(functionName); } })(); /** * Holds results for a set of Jasmine spec. Allows for the results array to hold another jasmine.NestedResults * * @constructor */ jasmine.NestedResults = function() { /** * The total count of results */ this.totalCount = 0; /** * Number of passed results */ this.passedCount = 0; /** * Number of failed results */ this.failedCount = 0; /** * Was this suite/spec skipped? */ this.skipped = false; /** * @ignore */ this.items_ = []; }; /** * Roll up the result counts. * * @param result */ jasmine.NestedResults.prototype.rollupCounts = function(result) { this.totalCount += result.totalCount; this.passedCount += result.passedCount; this.failedCount += result.failedCount; }; /** * Adds a log message. * @param values Array of message parts which will be concatenated later. */ jasmine.NestedResults.prototype.log = function(values) { this.items_.push(new jasmine.MessageResult(values)); }; /** * Getter for the results: message & results. */ jasmine.NestedResults.prototype.getItems = function() { return this.items_; }; /** * Adds a result, tracking counts (total, passed, & failed) * @param {jasmine.ExpectationResult|jasmine.NestedResults} result */ jasmine.NestedResults.prototype.addResult = function(result) { if (result.type != 'log') { if (result.items_) { this.rollupCounts(result); } else { this.totalCount++; if (result.passed()) { this.passedCount++; } else { this.failedCount++; } } } this.items_.push(result); }; /** * @returns {Boolean} True if everything below passed */ jasmine.NestedResults.prototype.passed = function() { return this.passedCount === this.totalCount; }; /** * Base class for pretty printing for expectation results. */ jasmine.PrettyPrinter = function() { this.ppNestLevel_ = 0; }; /** * Formats a value in a nice, human-readable string. * * @param value */ jasmine.PrettyPrinter.prototype.format = function(value) { this.ppNestLevel_++; try { if (value === jasmine.undefined) { this.emitScalar('undefined'); } else if (value === null) { this.emitScalar('null'); } else if (value === jasmine.getGlobal()) { this.emitScalar(''); } else if (value.jasmineToString) { this.emitScalar(value.jasmineToString()); } else if (typeof value === 'string') { this.emitString(value); } else if (jasmine.isSpy(value)) { this.emitScalar("spy on " + value.identity); } else if (value instanceof RegExp) { this.emitScalar(value.toString()); } else if (typeof value === 'function') { this.emitScalar('Function'); } else if (typeof value.nodeType === 'number') { this.emitScalar('HTMLNode'); } else if (value instanceof Date) { this.emitScalar('Date(' + value + ')'); } else if (value.__Jasmine_been_here_before__) { this.emitScalar(''); } else if (jasmine.isArray_(value) || typeof value == 'object') { value.__Jasmine_been_here_before__ = true; if (jasmine.isArray_(value)) { this.emitArray(value); } else { this.emitObject(value); } delete value.__Jasmine_been_here_before__; } else { this.emitScalar(value.toString()); } } finally { this.ppNestLevel_--; } }; jasmine.PrettyPrinter.prototype.iterateObject = function(obj, fn) { for (var property in obj) { if (!obj.hasOwnProperty(property)) continue; if (property == '__Jasmine_been_here_before__') continue; fn(property, obj.__lookupGetter__ ? (obj.__lookupGetter__(property) !== jasmine.undefined && obj.__lookupGetter__(property) !== null) : false); } }; jasmine.PrettyPrinter.prototype.emitArray = jasmine.unimplementedMethod_; jasmine.PrettyPrinter.prototype.emitObject = jasmine.unimplementedMethod_; jasmine.PrettyPrinter.prototype.emitScalar = jasmine.unimplementedMethod_; jasmine.PrettyPrinter.prototype.emitString = jasmine.unimplementedMethod_; jasmine.StringPrettyPrinter = function() { jasmine.PrettyPrinter.call(this); this.string = ''; }; jasmine.util.inherit(jasmine.StringPrettyPrinter, jasmine.PrettyPrinter); jasmine.StringPrettyPrinter.prototype.emitScalar = function(value) { this.append(value); }; jasmine.StringPrettyPrinter.prototype.emitString = function(value) { this.append("'" + value + "'"); }; jasmine.StringPrettyPrinter.prototype.emitArray = function(array) { if (this.ppNestLevel_ > jasmine.MAX_PRETTY_PRINT_DEPTH) { this.append("Array"); return; } this.append('[ '); for (var i = 0; i < array.length; i++) { if (i > 0) { this.append(', '); } this.format(array[i]); } this.append(' ]'); }; jasmine.StringPrettyPrinter.prototype.emitObject = function(obj) { if (this.ppNestLevel_ > jasmine.MAX_PRETTY_PRINT_DEPTH) { this.append("Object"); return; } var self = this; this.append('{ '); var first = true; this.iterateObject(obj, function(property, isGetter) { if (first) { first = false; } else { self.append(', '); } self.append(property); self.append(' : '); if (isGetter) { self.append(''); } else { self.format(obj[property]); } }); this.append(' }'); }; jasmine.StringPrettyPrinter.prototype.append = function(value) { this.string += value; }; jasmine.Queue = function(env) { this.env = env; // parallel to blocks. each true value in this array means the block will // get executed even if we abort this.ensured = []; this.blocks = []; this.running = false; this.index = 0; this.offset = 0; this.abort = false; }; jasmine.Queue.prototype.addBefore = function(block, ensure) { if (ensure === jasmine.undefined) { ensure = false; } this.blocks.unshift(block); this.ensured.unshift(ensure); }; jasmine.Queue.prototype.add = function(block, ensure) { if (ensure === jasmine.undefined) { ensure = false; } this.blocks.push(block); this.ensured.push(ensure); }; jasmine.Queue.prototype.insertNext = function(block, ensure) { if (ensure === jasmine.undefined) { ensure = false; } this.ensured.splice((this.index + this.offset + 1), 0, ensure); this.blocks.splice((this.index + this.offset + 1), 0, block); this.offset++; }; jasmine.Queue.prototype.start = function(onComplete) { this.running = true; this.onComplete = onComplete; this.next_(); }; jasmine.Queue.prototype.isRunning = function() { return this.running; }; jasmine.Queue.LOOP_DONT_RECURSE = true; jasmine.Queue.prototype.next_ = function() { var self = this; var goAgain = true; while (goAgain) { goAgain = false; if (self.index < self.blocks.length && !(this.abort && !this.ensured[self.index])) { var calledSynchronously = true; var completedSynchronously = false; var onComplete = function () { if (jasmine.Queue.LOOP_DONT_RECURSE && calledSynchronously) { completedSynchronously = true; return; } if (self.blocks[self.index].abort) { self.abort = true; } self.offset = 0; self.index++; var now = new Date().getTime(); if (self.env.updateInterval && now - self.env.lastUpdate > self.env.updateInterval) { self.env.lastUpdate = now; self.env.setTimeout(function() { self.next_(); }, 0); } else { if (jasmine.Queue.LOOP_DONT_RECURSE && completedSynchronously) { goAgain = true; } else { self.next_(); } } }; self.blocks[self.index].execute(onComplete); calledSynchronously = false; if (completedSynchronously) { onComplete(); } } else { self.running = false; if (self.onComplete) { self.onComplete(); } } } }; jasmine.Queue.prototype.results = function() { var results = new jasmine.NestedResults(); for (var i = 0; i < this.blocks.length; i++) { if (this.blocks[i].results) { results.addResult(this.blocks[i].results()); } } return results; }; /** * Runner * * @constructor * @param {jasmine.Env} env */ jasmine.Runner = function(env) { var self = this; self.env = env; self.queue = new jasmine.Queue(env); self.before_ = []; self.after_ = []; self.suites_ = []; }; jasmine.Runner.prototype.execute = function() { var self = this; if (self.env.reporter.reportRunnerStarting) { self.env.reporter.reportRunnerStarting(this); } self.queue.start(function () { self.finishCallback(); }); }; jasmine.Runner.prototype.beforeEach = function(beforeEachFunction) { beforeEachFunction.typeName = 'beforeEach'; this.before_.splice(0,0,beforeEachFunction); }; jasmine.Runner.prototype.afterEach = function(afterEachFunction) { afterEachFunction.typeName = 'afterEach'; this.after_.splice(0,0,afterEachFunction); }; jasmine.Runner.prototype.finishCallback = function() { this.env.reporter.reportRunnerResults(this); }; jasmine.Runner.prototype.addSuite = function(suite) { this.suites_.push(suite); }; jasmine.Runner.prototype.add = function(block) { if (block instanceof jasmine.Suite) { this.addSuite(block); } this.queue.add(block); }; jasmine.Runner.prototype.specs = function () { var suites = this.suites(); var specs = []; for (var i = 0; i < suites.length; i++) { specs = specs.concat(suites[i].specs()); } return specs; }; jasmine.Runner.prototype.suites = function() { return this.suites_; }; jasmine.Runner.prototype.topLevelSuites = function() { var topLevelSuites = []; for (var i = 0; i < this.suites_.length; i++) { if (!this.suites_[i].parentSuite) { topLevelSuites.push(this.suites_[i]); } } return topLevelSuites; }; jasmine.Runner.prototype.results = function() { return this.queue.results(); }; /** * Internal representation of a Jasmine specification, or test. * * @constructor * @param {jasmine.Env} env * @param {jasmine.Suite} suite * @param {String} description */ jasmine.Spec = function(env, suite, description) { if (!env) { throw new Error('jasmine.Env() required'); } if (!suite) { throw new Error('jasmine.Suite() required'); } var spec = this; spec.id = env.nextSpecId ? env.nextSpecId() : null; spec.env = env; spec.suite = suite; spec.description = description; spec.queue = new jasmine.Queue(env); spec.afterCallbacks = []; spec.spies_ = []; spec.results_ = new jasmine.NestedResults(); spec.results_.description = description; spec.matchersClass = null; }; jasmine.Spec.prototype.getFullName = function() { return this.suite.getFullName() + ' ' + this.description + '.'; }; jasmine.Spec.prototype.results = function() { return this.results_; }; /** * All parameters are pretty-printed and concatenated together, then written to the spec's output. * * Be careful not to leave calls to jasmine.log in production code. */ jasmine.Spec.prototype.log = function() { return this.results_.log(arguments); }; jasmine.Spec.prototype.runs = function (func) { var block = new jasmine.Block(this.env, func, this); this.addToQueue(block); return this; }; jasmine.Spec.prototype.addToQueue = function (block) { if (this.queue.isRunning()) { this.queue.insertNext(block); } else { this.queue.add(block); } }; /** * @param {jasmine.ExpectationResult} result */ jasmine.Spec.prototype.addMatcherResult = function(result) { this.results_.addResult(result); }; jasmine.Spec.prototype.expect = function(actual) { var positive = new (this.getMatchersClass_())(this.env, actual, this); positive.not = new (this.getMatchersClass_())(this.env, actual, this, true); return positive; }; /** * Waits a fixed time period before moving to the next block. * * @deprecated Use waitsFor() instead * @param {Number} timeout milliseconds to wait */ jasmine.Spec.prototype.waits = function(timeout) { var waitsFunc = new jasmine.WaitsBlock(this.env, timeout, this); this.addToQueue(waitsFunc); return this; }; /** * Waits for the latchFunction to return true before proceeding to the next block. * * @param {Function} latchFunction * @param {String} optional_timeoutMessage * @param {Number} optional_timeout */ jasmine.Spec.prototype.waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) { var latchFunction_ = null; var optional_timeoutMessage_ = null; var optional_timeout_ = null; for (var i = 0; i < arguments.length; i++) { var arg = arguments[i]; switch (typeof arg) { case 'function': latchFunction_ = arg; break; case 'string': optional_timeoutMessage_ = arg; break; case 'number': optional_timeout_ = arg; break; } } var waitsForFunc = new jasmine.WaitsForBlock(this.env, optional_timeout_, latchFunction_, optional_timeoutMessage_, this); this.addToQueue(waitsForFunc); return this; }; jasmine.Spec.prototype.fail = function (e) { var expectationResult = new jasmine.ExpectationResult({ passed: false, message: e ? jasmine.util.formatException(e) : 'Exception', trace: { stack: e.stack } }); this.results_.addResult(expectationResult); }; jasmine.Spec.prototype.getMatchersClass_ = function() { return this.matchersClass || this.env.matchersClass; }; jasmine.Spec.prototype.addMatchers = function(matchersPrototype) { var parent = this.getMatchersClass_(); var newMatchersClass = function() { parent.apply(this, arguments); }; jasmine.util.inherit(newMatchersClass, parent); jasmine.Matchers.wrapInto_(matchersPrototype, newMatchersClass); this.matchersClass = newMatchersClass; }; jasmine.Spec.prototype.finishCallback = function() { this.env.reporter.reportSpecResults(this); }; jasmine.Spec.prototype.finish = function(onComplete) { this.removeAllSpies(); this.finishCallback(); if (onComplete) { onComplete(); } }; jasmine.Spec.prototype.after = function(doAfter) { if (this.queue.isRunning()) { this.queue.add(new jasmine.Block(this.env, doAfter, this), true); } else { this.afterCallbacks.unshift(doAfter); } }; jasmine.Spec.prototype.execute = function(onComplete) { var spec = this; if (!spec.env.specFilter(spec)) { spec.results_.skipped = true; spec.finish(onComplete); return; } this.env.reporter.reportSpecStarting(this); spec.env.currentSpec = spec; spec.addBeforesAndAftersToQueue(); spec.queue.start(function () { spec.finish(onComplete); }); }; jasmine.Spec.prototype.addBeforesAndAftersToQueue = function() { var runner = this.env.currentRunner(); var i; for (var suite = this.suite; suite; suite = suite.parentSuite) { for (i = 0; i < suite.before_.length; i++) { this.queue.addBefore(new jasmine.Block(this.env, suite.before_[i], this)); } } for (i = 0; i < runner.before_.length; i++) { this.queue.addBefore(new jasmine.Block(this.env, runner.before_[i], this)); } for (i = 0; i < this.afterCallbacks.length; i++) { this.queue.add(new jasmine.Block(this.env, this.afterCallbacks[i], this), true); } for (suite = this.suite; suite; suite = suite.parentSuite) { for (i = 0; i < suite.after_.length; i++) { this.queue.add(new jasmine.Block(this.env, suite.after_[i], this), true); } } for (i = 0; i < runner.after_.length; i++) { this.queue.add(new jasmine.Block(this.env, runner.after_[i], this), true); } }; jasmine.Spec.prototype.explodes = function() { throw 'explodes function should not have been called'; }; jasmine.Spec.prototype.spyOn = function(obj, methodName, ignoreMethodDoesntExist) { if (obj == jasmine.undefined) { throw "spyOn could not find an object to spy upon for " + methodName + "()"; } if (!ignoreMethodDoesntExist && obj[methodName] === jasmine.undefined) { throw methodName + '() method does not exist'; } if (!ignoreMethodDoesntExist && obj[methodName] && obj[methodName].isSpy) { throw new Error(methodName + ' has already been spied upon'); } var spyObj = jasmine.createSpy(methodName); this.spies_.push(spyObj); spyObj.baseObj = obj; spyObj.methodName = methodName; spyObj.originalValue = obj[methodName]; obj[methodName] = spyObj; return spyObj; }; jasmine.Spec.prototype.removeAllSpies = function() { for (var i = 0; i < this.spies_.length; i++) { var spy = this.spies_[i]; spy.baseObj[spy.methodName] = spy.originalValue; } this.spies_ = []; }; /** * Internal representation of a Jasmine suite. * * @constructor * @param {jasmine.Env} env * @param {String} description * @param {Function} specDefinitions * @param {jasmine.Suite} parentSuite */ jasmine.Suite = function(env, description, specDefinitions, parentSuite) { var self = this; self.id = env.nextSuiteId ? env.nextSuiteId() : null; self.description = description; self.queue = new jasmine.Queue(env); self.parentSuite = parentSuite; self.env = env; self.before_ = []; self.after_ = []; self.children_ = []; self.suites_ = []; self.specs_ = []; }; jasmine.Suite.prototype.getFullName = function() { var fullName = this.description; for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) { fullName = parentSuite.description + ' ' + fullName; } return fullName; }; jasmine.Suite.prototype.finish = function(onComplete) { this.env.reporter.reportSuiteResults(this); this.finished = true; if (typeof(onComplete) == 'function') { onComplete(); } }; jasmine.Suite.prototype.beforeEach = function(beforeEachFunction) { beforeEachFunction.typeName = 'beforeEach'; this.before_.unshift(beforeEachFunction); }; jasmine.Suite.prototype.afterEach = function(afterEachFunction) { afterEachFunction.typeName = 'afterEach'; this.after_.unshift(afterEachFunction); }; jasmine.Suite.prototype.results = function() { return this.queue.results(); }; jasmine.Suite.prototype.add = function(suiteOrSpec) { this.children_.push(suiteOrSpec); if (suiteOrSpec instanceof jasmine.Suite) { this.suites_.push(suiteOrSpec); this.env.currentRunner().addSuite(suiteOrSpec); } else { this.specs_.push(suiteOrSpec); } this.queue.add(suiteOrSpec); }; jasmine.Suite.prototype.specs = function() { return this.specs_; }; jasmine.Suite.prototype.suites = function() { return this.suites_; }; jasmine.Suite.prototype.children = function() { return this.children_; }; jasmine.Suite.prototype.execute = function(onComplete) { var self = this; this.queue.start(function () { self.finish(onComplete); }); }; jasmine.WaitsBlock = function(env, timeout, spec) { this.timeout = timeout; jasmine.Block.call(this, env, null, spec); }; jasmine.util.inherit(jasmine.WaitsBlock, jasmine.Block); jasmine.WaitsBlock.prototype.execute = function (onComplete) { if (jasmine.VERBOSE) { this.env.reporter.log('>> Jasmine waiting for ' + this.timeout + ' ms...'); } this.env.setTimeout(function () { onComplete(); }, this.timeout); }; /** * A block which waits for some condition to become true, with timeout. * * @constructor * @extends jasmine.Block * @param {jasmine.Env} env The Jasmine environment. * @param {Number} timeout The maximum time in milliseconds to wait for the condition to become true. * @param {Function} latchFunction A function which returns true when the desired condition has been met. * @param {String} message The message to display if the desired condition hasn't been met within the given time period. * @param {jasmine.Spec} spec The Jasmine spec. */ jasmine.WaitsForBlock = function(env, timeout, latchFunction, message, spec) { this.timeout = timeout || env.defaultTimeoutInterval; this.latchFunction = latchFunction; this.message = message; this.totalTimeSpentWaitingForLatch = 0; jasmine.Block.call(this, env, null, spec); }; jasmine.util.inherit(jasmine.WaitsForBlock, jasmine.Block); jasmine.WaitsForBlock.TIMEOUT_INCREMENT = 10; jasmine.WaitsForBlock.prototype.execute = function(onComplete) { if (jasmine.VERBOSE) { this.env.reporter.log('>> Jasmine waiting for ' + (this.message || 'something to happen')); } var latchFunctionResult; try { latchFunctionResult = this.latchFunction.apply(this.spec); } catch (e) { this.spec.fail(e); onComplete(); return; } if (latchFunctionResult) { onComplete(); } else if (this.totalTimeSpentWaitingForLatch >= this.timeout) { var message = 'timed out after ' + this.timeout + ' msec waiting for ' + (this.message || 'something to happen'); this.spec.fail({ name: 'timeout', message: message }); this.abort = true; onComplete(); } else { this.totalTimeSpentWaitingForLatch += jasmine.WaitsForBlock.TIMEOUT_INCREMENT; var self = this; this.env.setTimeout(function() { self.execute(onComplete); }, jasmine.WaitsForBlock.TIMEOUT_INCREMENT); } }; jasmine.version_= { "major": 1, "minor": 3, "build": 1, "revision": 1354556913 }; less.js-1.4.2/test/browser/less/000077500000000000000000000000001217256642200165165ustar00rootroot00000000000000less.js-1.4.2/test/browser/less/imports/000077500000000000000000000000001217256642200202135ustar00rootroot00000000000000less.js-1.4.2/test/browser/less/imports/urls.less000066400000000000000000000000761217256642200220730ustar00rootroot00000000000000@import "modify-this.css"; .modify { my-url: url("a.png"); }less.js-1.4.2/test/browser/less/imports/urls2.less000066400000000000000000000000771217256642200221560ustar00rootroot00000000000000@import "modify-again.css"; .modify { my-url: url("b.png"); }less.js-1.4.2/test/browser/less/relative-urls/000077500000000000000000000000001217256642200213145ustar00rootroot00000000000000less.js-1.4.2/test/browser/less/relative-urls/urls.less000066400000000000000000000020351217256642200231710ustar00rootroot00000000000000@import ".././imports/urls.less"; @import "http://localhost:8081/browser/less/imports/urls2.less"; @font-face { src: url("/fonts/garamond-pro.ttf"); src: local(Futura-Medium), url(fonts.svg#MyGeometricModern) format("svg"); } #shorthands { background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px; } #misc { background-image: url(images/image.jpg); } #data-uri { background: url(data:image/png;charset=utf-8;base64, kiVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/ k//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U kg9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC); background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==); background-image: url(http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700); } #svg-data-uri { background: transparent url('data:image/svg+xml, '); } .comma-delimited { background: url(bg.jpg) no-repeat, url(bg.png) repeat-x top left, url(bg); } .values { @a: 'Trebuchet'; url: url(@a); } less.js-1.4.2/test/browser/less/rootpath-relative/000077500000000000000000000000001217256642200221675ustar00rootroot00000000000000less.js-1.4.2/test/browser/less/rootpath-relative/urls.less000066400000000000000000000020331217256642200240420ustar00rootroot00000000000000@import "../imports/urls.less"; @import "http://localhost:8081/browser/less/imports/urls2.less"; @font-face { src: url("/fonts/garamond-pro.ttf"); src: local(Futura-Medium), url(fonts.svg#MyGeometricModern) format("svg"); } #shorthands { background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px; } #misc { background-image: url(images/image.jpg); } #data-uri { background: url(data:image/png;charset=utf-8;base64, kiVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/ k//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U kg9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC); background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==); background-image: url(http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700); } #svg-data-uri { background: transparent url('data:image/svg+xml, '); } .comma-delimited { background: url(bg.jpg) no-repeat, url(bg.png) repeat-x top left, url(bg); } .values { @a: 'Trebuchet'; url: url(@a); } less.js-1.4.2/test/browser/less/rootpath/000077500000000000000000000000001217256642200203565ustar00rootroot00000000000000less.js-1.4.2/test/browser/less/rootpath/urls.less000066400000000000000000000020331217256642200222310ustar00rootroot00000000000000@import "../imports/urls.less"; @import "http://localhost:8081/browser/less/imports/urls2.less"; @font-face { src: url("/fonts/garamond-pro.ttf"); src: local(Futura-Medium), url(fonts.svg#MyGeometricModern) format("svg"); } #shorthands { background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px; } #misc { background-image: url(images/image.jpg); } #data-uri { background: url(data:image/png;charset=utf-8;base64, kiVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/ k//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U kg9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC); background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==); background-image: url(http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700); } #svg-data-uri { background: transparent url('data:image/svg+xml, '); } .comma-delimited { background: url(bg.jpg) no-repeat, url(bg.png) repeat-x top left, url(bg); } .values { @a: 'Trebuchet'; url: url(@a); } less.js-1.4.2/test/browser/less/urls.less000066400000000000000000000025411217256642200203750ustar00rootroot00000000000000@import "imports/urls.less"; @import "http://localhost:8081/browser/less/imports/urls2.less"; @font-face { src: url("/fonts/garamond-pro.ttf"); src: local(Futura-Medium), url(fonts.svg#MyGeometricModern) format("svg"); } #shorthands { background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px; } #misc { background-image: url(images/image.jpg); } #data-uri { background: url(data:image/png;charset=utf-8;base64, kiVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/ k//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U kg9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC); background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==); background-image: url(http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700); } #svg-data-uri { background: transparent url('data:image/svg+xml, '); } .comma-delimited { background: url(bg.jpg) no-repeat, url(bg.png) repeat-x top left, url(bg); } .values { @a: 'Trebuchet'; url: url(@a); } #data-uri { uri: data-uri('image/jpeg;base64', '../../data/image.jpg'); } #data-uri-guess { uri: data-uri('../../data/image.jpg'); } #data-uri-ascii { uri-1: data-uri('text/html', '../../data/page.html'); uri-2: data-uri('../../data/page.html'); } #data-uri-toobig { uri: data-uri('../../data/data-uri-fail.png'); } less.js-1.4.2/test/browser/phantom-runner.js000066400000000000000000000130171217256642200210650ustar00rootroot00000000000000var webpage = require('webpage'); var server = require('webserver').create(); var system = require('system'); var fs = require('fs'); var host, port = 8081; var listening = server.listen(port, function (request, response) { //console.log("Requested "+request.url); var filename = ("test/" + request.url.slice(1)).replace(/[\\\/]/g, fs.separator); if (!fs.exists(filename) || !fs.isFile(filename)) { response.statusCode = 404; response.write("

    File Not Found

    File:"+filename+"

    "); response.close(); return; } // we set the headers here response.statusCode = 200; response.headers = {"Cache": "no-cache", "Content-Type": "text/html"}; response.write(fs.read(filename)); response.close(); }); if (!listening) { console.log("could not create web server listening on port " + port); phantom.exit(); } /** * Wait until the test condition is true or a timeout occurs. Useful for waiting * on a server response or for a ui change (fadeIn, etc.) to occur. * * @param testFx javascript condition that evaluates to a boolean, * it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or * as a callback function. * @param onReady what to do when testFx condition is fulfilled, * it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or * as a callback function. * @param timeOutMillis the max amount of time to wait. If not specified, 3 sec is used. * @param timeOutErrorMessage the error message if time out occurs */ function waitFor(testFx, onReady, timeOutMillis, timeOutErrorMessage) { var maxtimeOutMillis = timeOutMillis ? timeOutMillis : 10001, //< Default Max Timeout is 10s start = new Date().getTime(), condition = false, interval = setInterval(function() { if ( (new Date().getTime() - start < maxtimeOutMillis) && !condition ) { // If not time-out yet and condition not yet fulfilled condition = (typeof(testFx) === "string" ? eval(testFx) : testFx()); //< defensive code } else { if(!condition) { // If condition still not fulfilled (timeout but condition is 'false') console.log(timeOutErrorMessage || "'waitFor()' timeout"); phantom.exit(1); } else { // Condition fulfilled (timeout and/or condition is 'true') typeof(onReady) === "string" ? eval(onReady) : onReady(); //< Do what it's supposed to do once the condition is fulfilled clearInterval(interval); //< Stop this interval } } }, 100); //< repeat check every 100ms }; function testPage(url) { var page = webpage.create(); page.open(url, function (status) { if (status !== "success") { console.log("Unable to access network - " + status); phantom.exit(); } else { waitFor(function(){ return page.evaluate(function(){ return document.body && document.body.querySelector && document.body.querySelector('.symbolSummary .pending') === null && document.body.querySelector('.results') !== null; }); }, function(){ page.onConsoleMessage = function (msg) { console.log(msg); }; var exitCode = page.evaluate(function(){ console.log(''); console.log(document.body.querySelector('.description').innerText); var list = document.body.querySelectorAll('.results > #details > .specDetail.failed'); if (list && list.length > 0) { console.log(''); console.log(list.length + ' test(s) FAILED:'); for (var i = 0; i < list.length; ++i) { var el = list[i], desc = el.querySelector('.description'), msg = el.querySelector('.resultMessage.fail'); console.log(''); console.log(desc.innerText); console.log(msg.innerText); console.log(''); } return 1; } else { console.log(document.body.querySelector('.alert > .passingAlert.bar').innerText); return 0; } }); testFinished(exitCode); }, 10000, // 10 second timeout "Test failed waiting for jasmine results on page: " + url); } }); } function scanDirectory(path, regex) { var files = []; fs.list(path).forEach(function (file) { if (file.match(regex)) { files.push(file); } }); return files; }; var totalTests = 0, totalFailed = 0, totalDone = 0; function testFinished(failed) { if (failed) { totalFailed++; } totalDone++; if (totalDone === totalTests) { phantom.exit(totalFailed > 0 ? 1 : 0); } } if (system.args.length != 2 && system.args[1] != "--no-tests") { var files = scanDirectory("test/browser/", /^test-runner-.+\.htm$/); totalTests = files.length; console.log("found " + files.length + " tests"); files.forEach(function(file) { testPage("http://localhost:8081/browser/" + file); }); }less.js-1.4.2/test/browser/runner-browser.js000066400000000000000000000003071217256642200211000ustar00rootroot00000000000000describe("less.js browser behaviour", function() { testLessEqualsInDocument(); it("has some log messages", function() { expect(logMessages.length).toBeGreaterThan(0); }); });less.js-1.4.2/test/browser/runner-errors.js000066400000000000000000000001521217256642200207270ustar00rootroot00000000000000less.strictUnits = true; describe("less.js error tests", function() { testLessErrorsInDocument(); });less.js-1.4.2/test/browser/runner-legacy.js000066400000000000000000000002051217256642200206560ustar00rootroot00000000000000less.strictMath = false; less.strictUnits = false; describe("less.js legacy tests", function() { testLessEqualsInDocument(); });less.js-1.4.2/test/browser/runner-main.js000066400000000000000000000006171217256642200203450ustar00rootroot00000000000000less.functions = { add: function (a, b) { return new(less.tree.Dimension)(a.value + b.value); }, increment: function (a) { return new(less.tree.Dimension)(a.value + 1); }, _color: function (str) { if (str.value === "evil red") { return new(less.tree.Color)("600") } } }; describe("less.js main tests", function() { testLessEqualsInDocument(); });less.js-1.4.2/test/browser/runner-production.js000066400000000000000000000002721217256642200216040ustar00rootroot00000000000000less.env = "production"; describe("less.js production behaviour", function() { it("doesn't log any messages", function() { expect(logMessages.length).toEqual(0); }); });less.js-1.4.2/test/browser/runner-relative-urls.js000066400000000000000000000001741217256642200222150ustar00rootroot00000000000000less.relativeUrls = true; describe("less.js browser test - relative url's", function() { testLessEqualsInDocument(); });less.js-1.4.2/test/browser/runner-rootpath-relative.js000066400000000000000000000003061217256642200230650ustar00rootroot00000000000000less.rootpath = "https://www.github.com/cloudhead/less.js/"; less.relativeUrls = true; describe("less.js browser test - rootpath and relative url's", function() { testLessEqualsInDocument(); });less.js-1.4.2/test/browser/runner-rootpath.js000066400000000000000000000002151217256642200212530ustar00rootroot00000000000000less.rootpath = "https://www.github.com/"; describe("less.js browser test - rootpath url's", function() { testLessEqualsInDocument(); });less.js-1.4.2/test/browser/template.htm000066400000000000000000000007071217256642200201010ustar00rootroot00000000000000 less.js-1.4.2/test/css/000077500000000000000000000000001217256642200146555ustar00rootroot00000000000000less.js-1.4.2/test/css/charsets.css000066400000000000000000000000221217256642200171750ustar00rootroot00000000000000@charset "UTF-8"; less.js-1.4.2/test/css/colors.css000066400000000000000000000017321217256642200166730ustar00rootroot00000000000000#yelow #short { color: #fea; } #yelow #long { color: #ffeeaa; } #yelow #rgba { color: rgba(255, 238, 170, 0.1); } #yelow #argb { color: #1affeeaa; } #blue #short { color: #00f; } #blue #long { color: #0000ff; } #blue #rgba { color: rgba(0, 0, 255, 0.1); } #blue #argb { color: #1a0000ff; } #alpha #hsla { color: rgba(61, 45, 41, 0.6); } #overflow .a { color: #000000; } #overflow .b { color: #ffffff; } #overflow .c { color: #ffffff; } #overflow .d { color: #00ff00; } #grey { color: #c8c8c8; } #333333 { color: #333333; } #808080 { color: #808080; } #00ff00 { color: #00ff00; } .lightenblue { color: #3333ff; } .darkenblue { color: #0000cc; } .unknowncolors { color: blue2; border: 2px solid superred; } .transparent { color: transparent; background-color: rgba(0, 0, 0, 0); } #alpha #fromvar { opacity: 0.7; } #alpha #short { opacity: 1; } #alpha #long { opacity: 1; } #alpha #rgba { opacity: 0.2; } #alpha #hsl { opacity: 1; } less.js-1.4.2/test/css/comments.css000066400000000000000000000020171217256642200172140ustar00rootroot00000000000000/******************\ * * * Comment Header * * * \******************/ /* Comment */ /* * Comment Test * * - cloudhead (http://cloudhead.net) * */ /* Colors * ------ * #EDF8FC (background blue) * #166C89 (darkest blue) * * Text: * #333 (standard text) // A comment within a comment! * #1F9EC9 (standard link) * */ /* @group Variables ------------------- */ #comments { /**/ color: red; /* A C-style comment */ /* A C-style comment */ background-color: orange; font-size: 12px; /* lost comment */ content: "content"; border: 1px solid black; padding: 0; margin: 2em; } /* commented out #more-comments { color: grey; } */ .selector, .lots, .comments { color: #808080, /* blue */ #ffa500; -webkit-border-radius: 2px /* webkit only */; -moz-border-radius: 8px /* moz only with operation */; } .test { color: 1px //put in @b - causes problems! --->; } #last { color: #0000ff; } /* *//* { *//* *//* *//* */#div { color: #A33; } /* } */ less.js-1.4.2/test/css/compression/000077500000000000000000000000001217256642200172165ustar00rootroot00000000000000less.js-1.4.2/test/css/compression/compression.css000066400000000000000000000002501217256642200222660ustar00rootroot00000000000000#colours{color1:#fea;color2:#fea;color3:rgba(255,238,170,0.1);string:"#ffeeaa"} dimensions{val:.1px;val:0;val:4cm;val:.2;val:5;angles-must-have-unit:0deg;width:auto\9} less.js-1.4.2/test/css/css-3.css000066400000000000000000000036421217256642200163240ustar00rootroot00000000000000.comma-delimited { text-shadow: -1px -1px 1px #ff0000, 6px 5px 5px #ffff00; -moz-box-shadow: 0pt 0pt 2px rgba(255, 255, 255, 0.4) inset, 0pt 4px 6px rgba(255, 255, 255, 0.4) inset; -webkit-transform: rotate(-0.0000000001deg); } @font-face { font-family: Headline; unicode-range: U+??????, U+0???, U+0-7F, U+A5; } .other { -moz-transform: translate(0, 11em) rotate(-90deg); transform: rotateX(45deg); } .item[data-cra_zy-attr1b-ut3=bold] { font-weight: bold; } p:not([class*="lead"]) { color: black; } input[type="text"].class#id[attr=32]:not(1) { color: white; } div#id.class[a=1][b=2].class:not(1) { color: white; } ul.comma > li:not(:only-child)::after { color: white; } ol.comma > li:nth-last-child(2)::after { color: white; } li:nth-child(4n+1), li:nth-child(-5n), li:nth-child(-n+2) { color: white; } a[href^="http://"] { color: black; } a[href$="http://"] { color: black; } form[data-disabled] { color: black; } p::before { color: black; } #issue322 { -webkit-animation: anim2 7s infinite ease-in-out; } @-webkit-keyframes frames { 0% { border: 1px; } 5.5% { border: 2px; } 100% { border: 3px; } } @keyframes fontbulger1 { to { font-size: 15px; } from, to { font-size: 12px; } 0%, 100% { font-size: 12px; } } .units { font: 1.2rem/2rem; font: 8vw/9vw; font: 10vh/12vh; font: 12vm/15vm; font: 12vmin/15vmin; font: 1.2ch/1.5ch; } @supports ( box-shadow: 2px 2px 2px black ) or ( -moz-box-shadow: 2px 2px 2px black ) { .outline { box-shadow: 2px 2px 2px black; -moz-box-shadow: 2px 2px 2px black; } } @-x-document url-prefix(""github.com"") { h1 { color: red; } } @viewport { font-size: 10px; } @namespace foo url(http://www.example.com); foo | h1 { color: blue; } foo | * { color: yellow; } | h1 { color: red; } * | h1 { color: green; } h1 { color: green; } .upper-test { UpperCaseProperties: allowed; } less.js-1.4.2/test/css/css-escapes.css000066400000000000000000000006431217256642200176030ustar00rootroot00000000000000.escape\|random\|char { color: red; } .mixin\!tUp { font-weight: bold; } .\34 04 { background: red; } .\34 04 strong { color: #ff00ff; font-weight: bold; } .trailingTest\+ { color: red; } /* This hideous test of hideousness checks for the selector "blockquote" with various permutations of hex escapes */ \62\6c\6f \63 \6B \0071 \000075o\74 e { color: silver; } [ng\:cloak], ng\:form { display: none; } less.js-1.4.2/test/css/css.css000066400000000000000000000024721217256642200161640ustar00rootroot00000000000000@charset "utf-8"; div { color: black; } div { width: 99%; } * { min-width: 45em; } h1, h2 > a > p, h3 { color: none; } div.class { color: blue; } div#id { color: green; } .class#id { color: purple; } .one.two.three { color: grey; } @media print { * { font-size: 3em; } } @media screen { * { font-size: 10px; } } @font-face { font-family: 'Garamond Pro'; } a:hover, a:link { color: #999; } p, p:first-child { text-transform: none; } q:lang(no) { quotes: none; } p + h1 { font-size: 2.2em; } #shorthands { border: 1px solid #000; font: 12px/16px Arial; font: 100%/16px Arial; margin: 1px 0; padding: 0 auto; } #more-shorthands { margin: 0; padding: 1px 0 2px 0; font: normal small / 20px 'Trebuchet MS', Verdana, sans-serif; font: 0/0 a; border-radius: 5px / 10px; } .misc { -moz-border-radius: 2px; display: -moz-inline-stack; width: .1em; background-color: #009998; background: -webkit-gradient(linear, left top, left bottom, from(#ff0000), to(#0000ff)); margin: ; filter: alpha(opacity=100); width: auto\9; } .misc .nested-multiple { multiple-semi-colons: yes; } #important { color: red !important; width: 100%!important; height: 20px ! important; } @font-face { font-family: font-a; } @font-face { font-family: font-b; } .æøå { margin: 0; } less.js-1.4.2/test/css/debug/000077500000000000000000000000001217256642200157435ustar00rootroot00000000000000less.js-1.4.2/test/css/debug/linenumbers-all.css000066400000000000000000000026661217256642200215600ustar00rootroot00000000000000@charset "UTF-8"; /* line 3, {pathimport}test.less */ @media -sass-debug-info{filename{font-family:file\:\/\/{pathimportesc}test\.less}line{font-family:\000033}} /* @charset "ISO-8859-1"; */ /* line 23, {pathimport}test.less */ @media -sass-debug-info{filename{font-family:file\:\/\/{pathimportesc}test\.less}line{font-family:\0000323}} .tst3 { color: grey; } /* line 15, {path}linenumbers.less */ @media -sass-debug-info{filename{font-family:file\:\/\/{pathesc}linenumbers\.less}line{font-family:\0000315}} .test1 { color: black; } /* line 6, {path}linenumbers.less */ @media -sass-debug-info{filename{font-family:file\:\/\/{pathesc}linenumbers\.less}line{font-family:\000036}} .test2 { color: red; } @media all { /* line 5, {pathimport}test.less */ @media -sass-debug-info{filename{font-family:file\:\/\/{pathimportesc}test\.less}line{font-family:\000035}} .tst { color: black; } } @media all and screen { /* line 7, {pathimport}test.less */ @media -sass-debug-info{filename{font-family:file\:\/\/{pathimportesc}test\.less}line{font-family:\000037}} .tst { color: red; } /* line 9, {pathimport}test.less */ @media -sass-debug-info{filename{font-family:file\:\/\/{pathimportesc}test\.less}line{font-family:\000039}} .tst .tst3 { color: white; } } /* line 18, {pathimport}test.less */ @media -sass-debug-info{filename{font-family:file\:\/\/{pathimportesc}test\.less}line{font-family:\0000318}} .tst2 { color: white; } less.js-1.4.2/test/css/debug/linenumbers-comments.css000066400000000000000000000011131217256642200226170ustar00rootroot00000000000000@charset "UTF-8"; /* line 3, {pathimport}test.less */ /* @charset "ISO-8859-1"; */ /* line 23, {pathimport}test.less */ .tst3 { color: grey; } /* line 15, {path}linenumbers.less */ .test1 { color: black; } /* line 6, {path}linenumbers.less */ .test2 { color: red; } @media all { /* line 5, {pathimport}test.less */ .tst { color: black; } } @media all and screen { /* line 7, {pathimport}test.less */ .tst { color: red; } /* line 9, {pathimport}test.less */ .tst .tst3 { color: white; } } /* line 18, {pathimport}test.less */ .tst2 { color: white; } less.js-1.4.2/test/css/debug/linenumbers-mediaquery.css000066400000000000000000000022131217256642200231410ustar00rootroot00000000000000@charset "UTF-8"; @media -sass-debug-info{filename{font-family:file\:\/\/{pathimportesc}test\.less}line{font-family:\000033}} /* @charset "ISO-8859-1"; */ @media -sass-debug-info{filename{font-family:file\:\/\/{pathimportesc}test\.less}line{font-family:\0000323}} .tst3 { color: grey; } @media -sass-debug-info{filename{font-family:file\:\/\/{pathesc}linenumbers\.less}line{font-family:\0000315}} .test1 { color: black; } @media -sass-debug-info{filename{font-family:file\:\/\/{pathesc}linenumbers\.less}line{font-family:\000036}} .test2 { color: red; } @media all { @media -sass-debug-info{filename{font-family:file\:\/\/{pathimportesc}test\.less}line{font-family:\000035}} .tst { color: black; } } @media all and screen { @media -sass-debug-info{filename{font-family:file\:\/\/{pathimportesc}test\.less}line{font-family:\000037}} .tst { color: red; } @media -sass-debug-info{filename{font-family:file\:\/\/{pathimportesc}test\.less}line{font-family:\000039}} .tst .tst3 { color: white; } } @media -sass-debug-info{filename{font-family:file\:\/\/{pathimportesc}test\.less}line{font-family:\0000318}} .tst2 { color: white; } less.js-1.4.2/test/css/extend-chaining.css000066400000000000000000000007721217256642200204420ustar00rootroot00000000000000.a, .b, .c { color: black; } .f, .e, .d { color: black; } .g.h, .i.j.h, .k.j.h { color: black; } .i.j, .k.j { color: white; } .l, .m, .n, .o, .p, .q, .r, .s, .t { color: black; } .u, .v.u.v { color: black; } .w, .v.w.v { color: black; } .x, .y, .z { color: x; } .y, .z, .x { color: y; } .z, .x, .y { color: z; } @media tv { .ma, .mb, .mc { color: black; } .md, .ma, .mb, .mc { color: white; } } @media tv and plasma { .me, .mf { background: red; } } less.js-1.4.2/test/css/extend-clearfix.css000066400000000000000000000002761217256642200204560ustar00rootroot00000000000000.clearfix, .foo, .bar { *zoom: 1; } .clearfix:after, .foo:after, .bar:after { content: ''; display: block; clear: both; height: 0; } .foo { color: red; } .bar { color: blue; } less.js-1.4.2/test/css/extend-exact.css000066400000000000000000000007241217256642200177630ustar00rootroot00000000000000.replace.replace .replace, .c.replace + .replace .replace, .replace.replace .c, .c.replace + .replace .c, .rep_ace { prop: copy-paste-replace; } .a .b .c { prop: not_effected; } .a, .effected { prop: is_effected; } .a .b { prop: not_effected; } .a .b.c { prop: not_effected; } .c .b .a, .a .b .a, .c .a .a, .a .a .a, .c .b .c, .a .b .c, .c .a .c, .a .a .c { prop: not_effected; } .e.e, .dbl { prop: extend-double; } .e.e:hover { hover: not-extended; } less.js-1.4.2/test/css/extend-media.css000066400000000000000000000004661217256642200177410ustar00rootroot00000000000000.ext1 .ext2, .all .ext2 { background: black; } @media tv { .ext1 .ext3, .tv-lowres .ext3, .all .ext3 { color: white; } .tv-lowres { background: blue; } } @media tv and hires { .ext1 .ext4, .tv-hires .ext4, .all .ext4 { color: green; } .tv-hires { background: red; } } less.js-1.4.2/test/css/extend-nest.css000066400000000000000000000053541217256642200176340ustar00rootroot00000000000000.sidebar, .sidebar2, .type1 .sidebar3, .type2.sidebar4 { width: 300px; background: red; } .sidebar .box, .sidebar2 .box, .type1 .sidebar3 .box, .type2.sidebar4 .box { background: #FFF; border: 1px solid #000; margin: 10px 0; } .sidebar2 { background: blue; } .type1 .sidebar3 { background: green; } .type2.sidebar4 { background: red; } .button, .submit { color: black; } .button:hover, .submit:hover { color: white; } .button2 :hover { nested: white; } .button2 :hover { notnested: black; } .amp-test-h, .amp-test-f.amp-test-c .amp-test-a.amp-test-d.amp-test-a.amp-test-e + .amp-test-c .amp-test-a.amp-test-d.amp-test-a.amp-test-e.amp-test-g, .amp-test-f.amp-test-c .amp-test-a.amp-test-d.amp-test-a.amp-test-e + .amp-test-c .amp-test-a.amp-test-d.amp-test-b.amp-test-e.amp-test-g, .amp-test-f.amp-test-c .amp-test-a.amp-test-d.amp-test-a.amp-test-e + .amp-test-c .amp-test-b.amp-test-d.amp-test-a.amp-test-e.amp-test-g, .amp-test-f.amp-test-c .amp-test-a.amp-test-d.amp-test-a.amp-test-e + .amp-test-c .amp-test-b.amp-test-d.amp-test-b.amp-test-e.amp-test-g, .amp-test-f.amp-test-c .amp-test-a.amp-test-d.amp-test-b.amp-test-e + .amp-test-c .amp-test-a.amp-test-d.amp-test-a.amp-test-e.amp-test-g, .amp-test-f.amp-test-c .amp-test-a.amp-test-d.amp-test-b.amp-test-e + .amp-test-c .amp-test-a.amp-test-d.amp-test-b.amp-test-e.amp-test-g, .amp-test-f.amp-test-c .amp-test-a.amp-test-d.amp-test-b.amp-test-e + .amp-test-c .amp-test-b.amp-test-d.amp-test-a.amp-test-e.amp-test-g, .amp-test-f.amp-test-c .amp-test-a.amp-test-d.amp-test-b.amp-test-e + .amp-test-c .amp-test-b.amp-test-d.amp-test-b.amp-test-e.amp-test-g, .amp-test-f.amp-test-c .amp-test-b.amp-test-d.amp-test-a.amp-test-e + .amp-test-c .amp-test-a.amp-test-d.amp-test-a.amp-test-e.amp-test-g, .amp-test-f.amp-test-c .amp-test-b.amp-test-d.amp-test-a.amp-test-e + .amp-test-c .amp-test-a.amp-test-d.amp-test-b.amp-test-e.amp-test-g, .amp-test-f.amp-test-c .amp-test-b.amp-test-d.amp-test-a.amp-test-e + .amp-test-c .amp-test-b.amp-test-d.amp-test-a.amp-test-e.amp-test-g, .amp-test-f.amp-test-c .amp-test-b.amp-test-d.amp-test-a.amp-test-e + .amp-test-c .amp-test-b.amp-test-d.amp-test-b.amp-test-e.amp-test-g, .amp-test-f.amp-test-c .amp-test-b.amp-test-d.amp-test-b.amp-test-e + .amp-test-c .amp-test-a.amp-test-d.amp-test-a.amp-test-e.amp-test-g, .amp-test-f.amp-test-c .amp-test-b.amp-test-d.amp-test-b.amp-test-e + .amp-test-c .amp-test-a.amp-test-d.amp-test-b.amp-test-e.amp-test-g, .amp-test-f.amp-test-c .amp-test-b.amp-test-d.amp-test-b.amp-test-e + .amp-test-c .amp-test-b.amp-test-d.amp-test-a.amp-test-e.amp-test-g, .amp-test-f.amp-test-c .amp-test-b.amp-test-d.amp-test-b.amp-test-e + .amp-test-c .amp-test-b.amp-test-d.amp-test-b.amp-test-e.amp-test-g { test: extended by masses of selectors; } less.js-1.4.2/test/css/extend-selector.css000066400000000000000000000020631217256642200204750ustar00rootroot00000000000000.error, .badError { border: 1px #f00; background: #fdd; } .error.intrusion, .badError.intrusion { font-size: 1.3em; font-weight: bold; } .intrusion .error, .intrusion .badError { display: none; } .badError { border-width: 3px; } .foo .bar, .foo .baz, .ext1 .ext2 .bar, .ext1 .ext2 .baz, .ext3 .bar, .ext3 .baz, .ext4 .bar, .ext4 .baz { display: none; } div.ext5, .ext6 > .ext5, div.ext7, .ext6 > .ext7 { width: 100px; } .ext, .a .c, .b .c { test: 1; } .a, .b { test: 2; } .a .c, .b .c { test: 3; } .a .c .d, .b .c .d { test: 4; } .replace.replace .replace, .c.replace + .replace .replace, .replace.replace .c, .c.replace + .replace .c, .rep_ace .rep_ace .rep_ace, .c.rep_ace + .rep_ace .rep_ace, .rep_ace .rep_ace .c, .c.rep_ace + .rep_ace .c { prop: copy-paste-replace; } .attributes [data="test"], .attributes .attributes .attribute-test { extend: attributes; } .attributes [data], .attributes .attributes .attribute-test2 { extend: attributes2; } .attributes [data="test3"], .attributes .attributes .attribute-test { extend: attributes2; } less.js-1.4.2/test/css/extend.css000066400000000000000000000015441217256642200166620ustar00rootroot00000000000000.error, .badError { border: 1px #f00; background: #fdd; } .error.intrusion, .badError.intrusion { font-size: 1.3em; font-weight: bold; } .intrusion .error, .intrusion .badError { display: none; } .badError { border-width: 3px; } .foo .bar, .foo .baz, .ext1 .ext2 .bar, .ext1 .ext2 .baz, .ext3 .bar, .ext3 .baz, .foo .ext3, .ext4 .bar, .ext4 .baz, .foo .ext4 { display: none; } div.ext5, .ext6 > .ext5, div.ext7, .ext6 > .ext7 { width: 100px; } .ext8.ext9, .fuu { result: add-foo; } .ext8 .ext9, .ext8 + .ext9, .ext8 > .ext9, .buu, .zap, .zoo { result: bar-matched; } .ext8.nomatch { result: none; } .ext8 .ext9, .buu { result: match-nested-bar; } .ext8.ext9, .fuu { result: match-nested-foo; } .aa, .cc { color: black; } .aa .dd, .aa .ee { background: red; } .bb, .cc, .ee, .ff { background: red; } .bb .bb, .ff .ff { color: black; } less.js-1.4.2/test/css/functions.css000066400000000000000000000052211217256642200173770ustar00rootroot00000000000000#functions { color: #660000; width: 16; height: undefined("self"); border-width: 5; variable: 11; background: linear-gradient(#000000, #ffffff); } #built-in { escaped: -Some::weird(#thing, y); lighten: #ffcccc; darken: #330000; saturate: #203c31; desaturate: #29332f; greyscale: #2e2e2e; hsl-clamp: #ffffff; spin-p: #bf6a40; spin-n: #bf4055; luma-white: 100%; luma-black: 0%; luma-black-alpha: 0%; luma-red: 21%; luma-green: 72%; luma-blue: 7%; luma-yellow: 93%; luma-cyan: 79%; luma-white-alpha: 50%; contrast-filter: contrast(30%); contrast-white: #000000; contrast-black: #ffffff; contrast-red: #ffffff; contrast-green: #000000; contrast-blue: #ffffff; contrast-yellow: #000000; contrast-cyan: #000000; contrast-light: #111111; contrast-dark: #eeeeee; contrast-wrongorder: #111111; contrast-light-thresh: #111111; contrast-dark-thresh: #eeeeee; contrast-high-thresh: #eeeeee; contrast-low-thresh: #111111; contrast-light-thresh-per: #111111; contrast-dark-thresh-per: #eeeeee; contrast-high-thresh-per: #eeeeee; contrast-low-thresh-per: #111111; format: "rgb(32, 128, 64)"; format-string: "hello world"; format-multiple: "hello earth 2"; format-url-encode: "red is %23ff0000"; eformat: rgb(32, 128, 64); unitless: 12; unit: 14em; hue: 98; saturation: 12%; lightness: 95%; hsvhue: 98; hsvsaturation: 12%; hsvvalue: 95%; red: 255; green: 255; blue: 255; rounded: 11; rounded-two: 10.67; roundedpx: 3px; roundedpx-three: 3.333px; rounded-percentage: 10%; ceil: 11px; floor: 12px; sqrt: 5px; pi: 3.141592653589793; mod: 2m; abs: 4%; tan: 0.9004040442978399; sin: 0.17364817766693033; cos: 0.8438539587324921; atan: 0.1rad; atan: 34.00000000000001deg; atan: 45.00000000000001deg; pow: 64px; pow: 64; pow: 27; percentage: 20%; color: #ff0011; tint: #898989; tint-full: #ffffff; tint-percent: #898989; shade: #686868; shade-full: #000000; shade-percent: #686868; fade-out: rgba(255, 0, 0, 0.95); fade-in: rgba(255, 0, 0, 0.9500000000000001); hsv: #4d2926; hsva: rgba(77, 40, 38, 0.2); mix: #ff3300; mix-0: #ffff00; mix-100: #ff0000; mix-weightless: #ff8000; } #built-in .is-a { color: true; color1: true; color2: true; keyword: true; number: true; string: true; pixel: true; percent: true; em: true; cat: true; } #alpha { alpha: rgba(153, 94, 51, 0.6); } #blendmodes { multiply: #ed0000; screen: #f600f6; overlay: #ed0000; softlight: #ff0000; hardlight: #0000ed; difference: #f600f6; exclusion: #f600f6; average: #7b007b; negation: #d73131; } #extract { result: 3 2 1 C B A; } less.js-1.4.2/test/css/ie-filters.css000066400000000000000000000006101217256642200174270ustar00rootroot00000000000000.nav { filter: progid:DXImageTransform.Microsoft.Alpha(opacity=20); filter: progid:DXImageTransform.Microsoft.Alpha(opacity=0); filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="#333333", endColorstr="#000000", GradientType=0); } .evalTest1 { filter: progid:DXImageTransform.Microsoft.Alpha(opacity=30); filter: progid:DXImageTransform.Microsoft.Alpha(opacity=5); } less.js-1.4.2/test/css/import-interpolation.css000066400000000000000000000000541217256642200215650ustar00rootroot00000000000000body { width: 100%; } .a { var: test; } less.js-1.4.2/test/css/import-once.css000066400000000000000000000000361217256642200176220ustar00rootroot00000000000000#import { color: #ff0000; } less.js-1.4.2/test/css/import.css000066400000000000000000000012021217256642200166740ustar00rootroot00000000000000@import url(http://fonts.googleapis.com/css?family=Open+Sans); @import url(/absolute/something.css) screen and (color) and (max-width: 600px); @import url("//ha.com/file.css") (min-width: 100px); #import-test { height: 10px; color: #ff0000; width: 10px; height: 30%; } @media screen and (max-width: 600px) { body { width: 100%; } } #import { color: #ff0000; } .mixin { height: 10px; color: #ff0000; } @media screen and (max-width: 601px) { #css { color: yellow; } } @media screen and (max-width: 602px) { body { width: 100%; } } @media screen and (max-width: 603px) { #css { color: yellow; } } less.js-1.4.2/test/css/javascript.css000066400000000000000000000004151217256642200175350ustar00rootroot00000000000000.eval { js: 42; js: 2; js: "hello world"; js: 1, 2, 3; title: "string"; ternary: true; multiline: 2; } .scope { var: 42; escaped: 7px; } .vars { width: 8; } .escape-interpol { width: hello world; } .arrays { ary: "1, 2, 3"; ary1: "1, 2, 3"; } less.js-1.4.2/test/css/lazy-eval.css000066400000000000000000000000361217256642200172720ustar00rootroot00000000000000.lazy-eval { width: 100%; } less.js-1.4.2/test/css/legacy/000077500000000000000000000000001217256642200161215ustar00rootroot00000000000000less.js-1.4.2/test/css/legacy/legacy.css000066400000000000000000000002171217256642200200770ustar00rootroot00000000000000@media (-o-min-device-pixel-ratio: 2/1) { .test-math-and-units { font: ignores 0/0 rules; test-division: 7em; simple: 2px; } } less.js-1.4.2/test/css/media.css000066400000000000000000000056671217256642200164640ustar00rootroot00000000000000@media print { .class { color: blue; } .class .sub { width: 42; } .top, header > h1 { color: #444444; } } @media screen { body { max-width: 480; } } @media all and (device-aspect-ratio: 16 / 9) { body { max-width: 800px; } } @media all and (orientation: portrait) { aside { float: none; } } @media handheld and (min-width: 42), screen and (min-width: 20em) { body { max-width: 480px; } } @media print { body { padding: 20px; } body header { background-color: red; } } @media print and (orientation: landscape) { body { margin-left: 20px; } } @media screen { .sidebar { width: 300px; } } @media screen and (orientation: landscape) { .sidebar { width: 500px; } } @media a { } @media a and b { .first .second .third { width: 300px; } .first .second .fourth { width: 3; } } @media a and b and c { .first .second .third { width: 500px; } } @media a, b and c { body { width: 95%; } } @media a and x, b and c and x, a and y, b and c and y { body { width: 100%; } } .a { background: black; } @media handheld { .a { background: white; } } @media handheld and (max-width: 100px) { .a { background: red; } } .b { background: black; } @media handheld { .b { background: white; } } @media handheld and (max-width: 200px) { .b { background: red; } } @media only screen and (max-width: 200px) { width: 480px; } @media print { @page :left { margin: 0.5cm; } @page :right { margin: 0.5cm; } @page Test:first { margin: 1cm; } @page :first { size: 8.5in 11in;@top-left { margin: 1cm; } @top-left-corner { margin: 1cm; } @top-center { margin: 1cm; } @top-right { margin: 1cm; } @top-right-corner { margin: 1cm; } @bottom-left { margin: 1cm; } @bottom-left-corner { margin: 1cm; } @bottom-center { margin: 1cm; } @bottom-right { margin: 1cm; } @bottom-right-corner { margin: 1cm; } @left-top { margin: 1cm; } @left-middle { margin: 1cm; } @left-bottom { margin: 1cm; } @right-top { margin: 1cm; } @right-middle { content: "Page " counter(page); } @right-bottom { margin: 1cm; } } } @media (-webkit-min-device-pixel-ratio: 2), (min--moz-device-pixel-ratio: 2), (-o-min-device-pixel-ratio: 2/1), (min-resolution: 2dppx), (min-resolution: 128dpcm) { .b { background: red; } } body { background: red; } @media (max-width: 500px) { body { background: green; } } @media (max-width: 1000px) { body { background: red; background: blue; } } @media (max-width: 1000px) and (max-width: 500px) { body { background: green; } } @media (max-width: 1200px) { /* a comment */ } @media (max-width: 1200px) and (max-width: 900px) { body { font-size: 11px; } } less.js-1.4.2/test/css/mixins-args.css000066400000000000000000000025571217256642200176410ustar00rootroot00000000000000#hidden { color: transparent; } #hidden1 { color: transparent; } .two-args { color: blue; width: 10px; height: 99%; border: 2px dotted #000000; } .one-arg { width: 15px; height: 49%; } .no-parens { width: 5px; height: 49%; } .no-args { width: 5px; height: 49%; } .var-args { width: 45; height: 17%; } .multi-mix { width: 10px; height: 29%; margin: 4; padding: 5; } body { padding: 30px; color: #ff0000; } .scope-mix { width: 8; } .content { width: 600px; } .content .column { margin: 600px; } #same-var-name { radius: 5px; } #var-inside { width: 10px; } .arguments { border: 1px solid #000000; width: 1px; } .arguments2 { border: 0px; width: 0px; } .arguments3 { border: 0px; width: 0px; } .arguments4 { border: 0 1 2 3 4; rest: 1 2 3 4; width: 0; } .edge-case { border: "{"; width: "{"; } .slash-vs-math { border-radius: 2px/5px; border-radius: 5px/10px; border-radius: 6px; } .comma-vs-semi-colon { one: a; two: b, c; one: d, e; two: f; one: g; one: h; one: i; one: j; one: k; two: l; one: m, n; one: o, p; two: q; one: r, s; two: t; } #named-conflict { four: a, 11, 12, 13; four: a, 21, 22, 23; } .test-mixin-default-arg { defaults: 1px 1px 1px; defaults: 2px 2px 2px; } .selector { margin: 2, 2, 2, 2; } .selector2 { margin: 2, 2, 2, 2; } .selector3 { margin: 4; } less.js-1.4.2/test/css/mixins-closure.css000066400000000000000000000001311217256642200203430ustar00rootroot00000000000000.class { width: 99px; } .overwrite { width: 99px; } .nested .class { width: 5px; } less.js-1.4.2/test/css/mixins-guards.css000066400000000000000000000021341217256642200201610ustar00rootroot00000000000000.light1 { color: white; margin: 1px; } .light2 { color: black; margin: 1px; } .max1 { width: 6; } .max2 { width: 8; } .glob1 { margin: auto auto; } .ops1 { height: gt-or-eq; height: lt-or-eq; } .ops2 { height: gt-or-eq; height: not-eq; } .ops3 { height: lt-or-eq; height: not-eq; } .default1 { content: default; } .test1 { content: "true."; } .test2 { content: "false."; } .test3 { content: "false."; } .test4 { content: "false."; } .test5 { content: "false."; } .bool1 { content: true and true; content: true; content: false, true; content: false and true and true, true; content: false, true and true; content: false, false, true; content: false, true and true and true, false; content: not false; content: not false and false, not false; } .equality-units { test: pass; } .colorguardtest { content: is #ff0000; content: is not #0000ff its #ff0000; content: is not #0000ff its #800080; } .stringguardtest { content: is theme1; content: is not theme2; content: is theme1 no quotes; } #tryNumberPx { catch: all; declare: 4; declare: 4px; } less.js-1.4.2/test/css/mixins-important.css000066400000000000000000000010001217256642200207000ustar00rootroot00000000000000.class { border: 1; boxer: 1; border: 2 !important; boxer: 2 !important; border: 3; boxer: 3; border: 4 !important; boxer: 4 !important; border: 5; boxer: 5; border: 0 !important; boxer: 0 !important; border: 9 !important; border: 9; boxer: 9; } .class .inner { test: 1; } .class .inner { test: 2 !important; } .class .inner { test: 3; } .class .inner { test: 4 !important; } .class .inner { test: 5; } .class .inner { test: 0 !important; } .class .inner { test: 9; } less.js-1.4.2/test/css/mixins-named-args.css000066400000000000000000000005441217256642200207150ustar00rootroot00000000000000.named-arg { color: blue; width: 5px; height: 99%; args: 1px 100%; text-align: center; } .class { width: 5px; height: 19%; args: 1px 20%; } .all-args-wrong-args { width: 10px; height: 9%; args: 2px 10%; } .named-args2 { width: 15px; height: 49%; color: #646464; } .named-args3 { width: 5px; height: 29%; color: #123456; } less.js-1.4.2/test/css/mixins-nested.css000066400000000000000000000002731217256642200201600ustar00rootroot00000000000000.class .inner { height: 300; } .class .inner .innest { width: 30; border-width: 60; } .class2 .inner { height: 600; } .class2 .inner .innest { width: 60; border-width: 120; } less.js-1.4.2/test/css/mixins-pattern.css000066400000000000000000000007471217256642200203610ustar00rootroot00000000000000.zero { variadic: true; zero: 0; one: 1; two: 2; three: 3; } .one { variadic: true; one: 1; one-req: 1; two: 2; three: 3; } .two { variadic: true; two: 2; three: 3; } .three { variadic: true; three-req: 3; three: 3; } .left { left: 1; } .right { right: 1; } .border-right { color: black; border-right: 4px; } .border-left { color: black; border-left: 4px; } .only-right { right: 33; } .only-left { left: 33; } .left-right { both: 330; } less.js-1.4.2/test/css/mixins.css000066400000000000000000000031051217256642200166750ustar00rootroot00000000000000.mixin { border: 1px solid black; } .mixout { border-color: orange; } .borders { border-style: dashed; } #namespace .borders { border-style: dotted; } #namespace .biohazard { content: "death"; } #namespace .biohazard .man { color: transparent; } #theme > .mixin { background-color: grey; } #container { color: black; border: 1px solid black; border-color: orange; background-color: grey; } #header .milk { color: white; border: 1px solid black; background-color: grey; } #header #cookie { border-style: dashed; } #header #cookie .chips { border-style: dotted; } #header #cookie .chips .calories { color: black; border: 1px solid black; border-color: orange; background-color: grey; } .secure-zone { color: transparent; } .direct { border-style: dotted; } .bo, .bar { width: 100%; } .bo { border: 1px; } .ar.bo.ca { color: black; } .jo.ki { background: none; } .amp.support { color: orange; } .extended { width: 100%; border: 1px; background: none; color: orange; } .foo .bar { width: 100%; } .underParents { color: red; } .parent .underParents { color: red; } * + h1 { margin-top: 25px; } legend + h1 { margin-top: 0; } h1 + * { margin-top: 10px; } * + h2 { margin-top: 20px; } legend + h2 { margin-top: 0; } h2 + * { margin-top: 8px; } * + h3 { margin-top: 15px; } legend + h3 { margin-top: 0; } h3 + * { margin-top: 5px; } .error { background-image: "/a.png"; background-position: center center; } .test-rec .recursion { color: black; } .button { padding-left: 44px; } .button.large { padding-left: 40em; } less.js-1.4.2/test/css/operations.css000066400000000000000000000012701217256642200175520ustar00rootroot00000000000000#operations { color: #111111; height: 9px; width: 3em; substraction: 0; division: 1; } #operations .spacing { height: 9px; width: 3em; } .with-variables { height: 16em; width: 24em; size: 1cm; } .with-functions { color: #646464; color: #ff8080; color: #c94a4a; } .negative { height: 0px; width: 4px; } .shorthands { padding: -1px 2px 0 -4px; } .rem-dimensions { font-size: 5.5rem; } .colors { color: #123; border-color: #334455; background-color: #000000; } .colors .other { color: #222222; border-color: #222222; } .negations { variable: -4px; variable1: 0px; variable2: 0px; variable3: 8px; variable4: 0px; paren: -4px; paren2: 16px; } less.js-1.4.2/test/css/parens.css000066400000000000000000000012721217256642200166610ustar00rootroot00000000000000.parens { border: 2px solid #000000; margin: 1px 3px 16 3; width: 36; padding: 2px 36px; } .more-parens { padding: 8 4 4 4px; width-all: 96; width-first: 16 * 6; width-keep: (4 * 4) * 6; height-keep: (7 * 7) + (8 * 8); height-all: 113; height-parts: 49 + 64; margin-keep: (4 * (5 + 5) / 2) - (4 * 2); margin-parts: 20 - 8; margin-all: 12; border-radius-keep: 4px * (1 + 1) / 4 + 3px; border-radius-parts: 8px / 7px; border-radius-all: 5px; } .negative { neg-var: -1; neg-var-paren: -(1); } .nested-parens { width: 2 * (4 * (2 + (1 + 6))) - 1; height: ((2 + 3) * (2 + 3) / (9 - 4)) + 1; } .mixed-units { margin: 2px 4em 1 5pc; padding: 6px 1em 2px 2; } less.js-1.4.2/test/css/rulesets.css000066400000000000000000000017731217256642200172450ustar00rootroot00000000000000#first > .one { font-size: 2em; } #first > .one > #second .two > #deux { width: 50%; } #first > .one > #second .two > #deux #third { height: 100%; } #first > .one > #second .two > #deux #third:focus { color: black; } #first > .one > #second .two > #deux #third:focus #fifth > #sixth .seventh #eighth + #ninth { color: purple; } #first > .one > #second .two > #deux #fourth, #first > .one > #second .two > #deux #five, #first > .one > #second .two > #deux #six { color: #110000; } #first > .one > #second .two > #deux #fourth .seven, #first > .one > #second .two > #deux #five .seven, #first > .one > #second .two > #deux #six .seven, #first > .one > #second .two > #deux #fourth .eight > #nine, #first > .one > #second .two > #deux #five .eight > #nine, #first > .one > #second .two > #deux #six .eight > #nine { border: 1px solid black; } #first > .one > #second .two > #deux #fourth #ten, #first > .one > #second .two > #deux #five #ten, #first > .one > #second .two > #deux #six #ten { color: red; } less.js-1.4.2/test/css/scope.css000066400000000000000000000007701217256642200165040ustar00rootroot00000000000000.tiny-scope { color: #998899; } .scope1 { color: #0000ff; border-color: #000000; } .scope1 .scope2 { color: #0000ff; } .scope1 .scope2 .scope3 { color: #ff0000; border-color: #000000; background-color: #ffffff; } .scope { scoped-val: #008000; } .heightIsSet { height: 1024px; } .useHeightInMixinCall { mixin-height: 1024px; } .imported { exists: true; } .testImported { exists: true; } #allAreUsedHere { default: 'top level'; scope: 'top level'; sub-scope-only: 'inside'; } less.js-1.4.2/test/css/selectors.css000066400000000000000000000031761217256642200174010ustar00rootroot00000000000000h1 a:hover, h2 a:hover, h3 a:hover, h1 p:hover, h2 p:hover, h3 p:hover { color: red; } #all { color: blue; } #the { color: blue; } #same { color: blue; } ul, li, div, q, blockquote, textarea { margin: 0; } td { margin: 0; padding: 0; } td, input { line-height: 1em; } a { color: red; } a:hover { color: blue; } div a { color: green; } p a span { color: yellow; } .foo .bar .qux, .foo .baz .qux { display: block; } .qux .foo .bar, .qux .foo .baz { display: inline; } .qux.foo .bar, .qux.foo .baz { display: inline-block; } .qux .foo .bar .biz, .qux .foo .baz .biz { display: none; } .a.b.c { color: red; } .c .b.a { color: red; } .foo .p.bar { color: red; } .foo.p.bar { color: red; } .foo + .foo { background: amber; } .foo + .foo { background: amber; } .foo + .foo, .foo + .bar, .bar + .foo, .bar + .bar { background: amber; } .foo a > .foo a, .foo a > .bar a, .foo a > .foo b, .foo a > .bar b, .bar a > .foo a, .bar a > .bar a, .bar a > .foo b, .bar a > .bar b, .foo b > .foo a, .foo b > .bar a, .foo b > .foo b, .foo b > .bar b, .bar b > .foo a, .bar b > .bar a, .bar b > .foo b, .bar b > .bar b { background: amber; } .other ::fnord { color: #ff0000; } .other::fnord { color: #ff0000; } .other ::bnord { color: #ff0000; } .other::bnord { color: #ff0000; } .blood { color: red; } .bloodred { color: green; } #blood.blood.red.black { color: black; } :nth-child(3) { selector: interpolated; } .test:nth-child(odd):not(:nth-child(3)) { color: #ff0000; } [prop], [prop="value3"], [prop*="val3"], [|prop~="val3"], [*|prop$="val3"], [ns|prop^="val3"], [3^="val3"], [3=3], [3] { attributes: yes; } less.js-1.4.2/test/css/static-urls/000077500000000000000000000000001217256642200171275ustar00rootroot00000000000000less.js-1.4.2/test/css/static-urls/urls.css000066400000000000000000000024541217256642200206330ustar00rootroot00000000000000@import "folder (1)/../css/background.css"; @import "folder (1)/import-test-d.css"; @font-face { src: url("/fonts/garamond-pro.ttf"); src: local(Futura-Medium), url(folder\ \(1\)/fonts.svg#MyGeometricModern) format("svg"); } #shorthands { background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px; } #misc { background-image: url(folder\ \(1\)/images/image.jpg); } #data-uri { background: url(data:image/png;charset=utf-8;base64, kiVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/ k//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U kg9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC); background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==); background-image: url(http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700); } #svg-data-uri { background: transparent url('data:image/svg+xml, '); } .comma-delimited { background: url(folder\ \(1\)/bg.jpg) no-repeat, url(folder\ \(1\)/bg.png) repeat-x top left, url(folder\ \(1\)/bg); } .values { url: url('folder (1)/Trebuchet'); } #logo { width: 100px; height: 100px; background: url('folder (1)/../assets/logo.png'); } @font-face { font-family: xecret; src: url('folder (1)/../assets/xecret.ttf'); } #secret { font-family: xecret, sans-serif; } less.js-1.4.2/test/css/strings.css000066400000000000000000000014671217256642200170700ustar00rootroot00000000000000#strings { background-image: url("http://son-of-a-banana.com"); quotes: "~" "~"; content: "#*%:&^,)!.(~*})"; empty: ""; brackets: "{" "}"; escapes: "\"hello\" \\world"; escapes2: "\"llo"; } #comments { content: "/* hello */ // not-so-secret"; } #single-quote { quotes: "'" "'"; content: '""#!&""'; empty: ''; semi-colon: ';'; } #escaped { filter: DX.Transform.MS.BS.filter(opacity=50); } #one-line { image: url(http://tooks.com); } #crazy { image: url(http://), "}", url("http://}"); } #interpolation { url: "http://lesscss.org/dev/image.jpg"; url2: "http://lesscss.org/image-256.jpg"; url3: "http://lesscss.org#445566"; url4: "http://lesscss.org/hello"; url5: "http://lesscss.org/54.4px"; } .mix-mul-class { color: #0000ff; color: #ff0000; color: #000000; color: #ffa500; } less.js-1.4.2/test/css/urls.css000066400000000000000000000034761217256642200163660ustar00rootroot00000000000000@import "import/../css/background.css"; @import "import/import-test-d.css"; @import "file.css"; @font-face { src: url("/fonts/garamond-pro.ttf"); src: local(Futura-Medium), url(fonts.svg#MyGeometricModern) format("svg"); } #shorthands { background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px; background: url("img.jpg") center / 100px; background: #ffffff url(image.png) center / 1px 100px repeat-x scroll content-box padding-box; } #misc { background-image: url(images/image.jpg); } #data-uri { background: url(data:image/png;charset=utf-8;base64, kiVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/ k//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U kg9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC); background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==); background-image: url(http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700); } #svg-data-uri { background: transparent url('data:image/svg+xml, '); } .comma-delimited { background: url(bg.jpg) no-repeat, url(bg.png) repeat-x top left, url(bg); } .values { url: url('Trebuchet'); } #logo { width: 100px; height: 100px; background: url('import/imports/../assets/logo.png'); } @font-face { font-family: xecret; src: url('import/imports/../assets/xecret.ttf'); } #secret { font-family: xecret, sans-serif; } #data-uri { uri: url('data:image/jpeg;base64,bm90IGFjdHVhbGx5IGEganBlZyBmaWxlCg=='); } #data-uri-guess { uri: url('data:image/jpeg;base64,bm90IGFjdHVhbGx5IGEganBlZyBmaWxlCg=='); } #data-uri-ascii { uri-1: url('data:text/html,%3Ch1%3EThis%20page%20is%20100%25%20Awesome.%3C%2Fh1%3E%0A'); uri-2: url('data:text/html,%3Ch1%3EThis%20page%20is%20100%25%20Awesome.%3C%2Fh1%3E%0A'); } #data-uri-toobig { uri: url('../data/data-uri-fail.png'); } less.js-1.4.2/test/css/variables.css000066400000000000000000000014411217256642200173370ustar00rootroot00000000000000.variables { width: 14cm; } .variables { height: 24px; color: #888888; font-family: "Trebuchet MS", Verdana, sans-serif; quotes: "~" "~"; } .redef { zero: 0; } .redef .inition { three: 3; } .values { minus-one: -1; font-family: 'Trebuchet', 'Trebuchet', 'Trebuchet'; color: #888888 !important; multi: something 'A', B, C, 'Trebuchet'; } .variable-names { name: 'hello'; } .alpha { filter: alpha(opacity=42); } .testPollution { a: 'no-pollution'; } .units { width: 1px; same-unit-as-previously: 1px; square-pixel-divided: 1px; odd-unit: 2; percentage: 500%; pixels: 500px; conversion-metric-a: 30mm; conversion-metric-b: 3cm; conversion-imperial: 3in; custom-unit: 420octocats; custom-unit-cancelling: 18dogs; mix-units: 2px; invalid-units: 1px; } less.js-1.4.2/test/css/whitespace.css000066400000000000000000000010401217256642200175160ustar00rootroot00000000000000.whitespace { color: white; } .whitespace { color: white; } .whitespace { color: white; } .whitespace { color: white; } .whitespace { color: white ; } .white, .space, .mania { color: white; } .no-semi-column { color: #ffffff; } .no-semi-column { color: white; white-space: pre; } .no-semi-column { border: 2px solid #ffffff; } .newlines { background: the, great, wall; border: 2px solid black; } .sel .newline_ws .tab_ws { color: white; background-position: 45 -23; } less.js-1.4.2/test/data/000077500000000000000000000000001217256642200147765ustar00rootroot00000000000000less.js-1.4.2/test/data/data-uri-fail.png000066400000000000000000001463041217256642200201330ustar00rootroot00000000000000‰PNG  IHDR€®á ¯ žiCCPicmxÚ­—wPÓÙÇïï—ÞhÐ!ôŽô*%ôÐ¥ƒ„J AÄ®,®ÀŠ¢"‚]i ®J‘µ l‹€½à‚,êºX•ýðÞ›Ù?ÞÌ;3'¿OΜùæžû»wæÈ­,¡0– C-Šð÷¢ÇÅ'Ðq}0ÀS@c±ÅBFxx0øÇøxéFâŽÅ´øßBžÃ³€ÂNâˆÙŸFr?[(Ê…ÔõWd §9aE²@„‹§™7˧9i–OÏôDEx#| <™Åñ ÝEêô6Ñ!}@ØJÀá ë#ìÎNaqF˜gddNó6„“þM‡÷šIRM‹'åÙYfïà ÓY+Áÿ;2Ò%s¿¡…$Yœ„< ‘=Ëe³|#ç8…Ë žca¶WÄó³™QÒI@ôKÒ¢sœ–$í$…†IõÅÞ sœ—;Ç®ï‹2#¤ýâœHßù~ïÐ9Ne†Ï1K43Ë sÓý#æ×.]§ =T:K²ÈOÚÃÏÏ› eäHûù~Lé¼¢€yýôp©¦H!Ý® ZªÉaùH÷D À\ I ¤ƒl@>€Ä@ˆ|cäugss³§òήñy)Ùtr+¸æt¦€miN·±²¶Ówlö¾§Í܈vc¾–Õ€s!RäÍ×Xzœyõã|MïÝì9=×Í–ˆrfkèé Y T‘¢Œ°Àx_ÂIâÁ2ÀFæÉ@&YVƒ  m`¨ÀaPŽƒ“ œÁUptƒ{à èCàÁ$A8ˆQ!UH2€Ì È r‡|¡`(Ї!$€$ÐjhT•BÐ!¨ú:]„®C=Ð#h…ÞA_`L†aMØ^;Á 8Ž‚—Â<8 ΃óá­p9\ƒ›á‹ðMøÜ¿‚ÇQEBÑP:( ”ʆJ@%£D¨µ¨BTª Õ€jCu¢î úQ¯QŸÑX4MG[ ]Ñèh4…^‹.FW kÐÍèËè;èôú;†‚ÑÀ˜a\0LL†‡Y)À”aŽbš0W0÷0C˜X,–†5Â:b°ñØTì*l1v¶ÛŽíÁbÇq8œ*Î ç† Ã±pÙ¸ÜÜ1Ü\/n÷ OÂkãmð~ø¼¿_†¯ÃŸÇ÷â‡ñ“9‚Á…FàVJGm„Û„!Â$QžhDt#FS‰ˆåÄââSâ{‰¤Kr&-"ñIëI夤k¤Òg²Ù”ìM^B–·’«ÉíäGä÷ ÅâII dS¶Rj)—(Ï(Ÿd¨2–2LŽÌ:™J™f™^™7²YY†ì2Ù<Ù2ÙS²·e_Ëä å¼åXrkå*åÎÈ=—§Ê[ˇÉgÈË×É_—QÀ)*ø*pò+\R¤¢¨zTo*›º‰z„z…:¤ˆU4Rd*¦*)WìRSRP²SŠQÊUªT:§ÔOCÑ iLZ:­„v’vŸöEYS™¡ÌUޢܠܫ<¡¢®â©ÂU)TiT¹§òE•®ê«š¦º]µEµO ­fª¶Hm…Ú~µ+j¯ÕÕ]ÕÙê…ê'ÕkÀ¦«4kÜÒ×ÔÒô×jîѼ¤ùZ‹¦å©•ªµSë¼Ö¨6UÛ]›¯½Sû‚öKºAO§—Ó/ÓÇt4tt$:‡tºt&ut£u7ê6êöéõœô’õvêuèékë‡è¯Ö¯×l@0p2H1ØmÐi0ahdk¸Ù°ÅpÄHňi”gToôÔ˜bìaœe\e|×kâd’f²Ï¤Û6µ7M1­4½m›9˜ñÍö™õ˜cÌÍæUæ,È ‹‹z‹Kše°åFËË7 ô$,ؾ sÁw+{«t«#VO¬¬­7Z·Y¿³1µaÛTÚܵ¥ØúÙ®³mµ}kgfǵÛo÷Оjb¿Ù¾Ãþ›ƒ£ƒÈ¡ÁaÔQß1Ñq¯ã'E§p§b§kÎg/çuÎg?»8¸d»œtùËÕÂ5͵Îud¡ÑBîÂ# ÝtÝXn‡ÜúÝéî‰îÝû=t<䨹ʰªì0öpÎáGbŽtþìôsíQµ£EG¿U ªûk"j.×:ÖÖÖiÔ•ÔÃõ’úÑcKŽu÷9ÞÚ`Ñp¨‘ÖXtœœxùKâ/÷Oì8åtªá´Áé½MÔ¦Âf¨yeóXKJKk|kÏ™À3m®mM¿ZþZ}Vçlå9¥s%ç‰çóÏO]È»0Þ.l}‘wq°cyÇ“Kq—î^^t¹ëJЕkWý®^êdt^¸ævíìu—ëgn8Ýh¹ép³ù–ý­¦ßìkêrèj¾íx»µÛ¹»­gaÏù^Þ‹w|î\½Ë¼{ó^轞ûÑ÷>Xò ÿ!çáÈ£ôGoç<ž|²þ)æiaŸ\_Ù3gU¿›üÞØïÐnÀgàÖóÈçOÙƒ¯þÿñu(ÿåEÙ°öpíˆÍÈÙQ¿Ñî—‹_½¾š|]ð§üŸ{ß¿9ý—ç_·ÆâƆފÞN½+~¯ú¾úƒÝ‡Žñðñg3>NN~RýTóÙésç—Ø/Ó+¾â¾–3ùÖö=èûÓ©Œ©)!KÄš±($áädÞU@‰G¼C7D™Y<ЬoŸ!ðO<ë“g€jO¢×Œx”ýH LFžÓv.ÊÀ¶¶ÒüWˆ“mmfµÈˆÓÃ|ššz¯ ® €o¢©©É}SSߎ ‹}@{Ö¬÷ž,ò¤Ôˆ¦Dy~³ïõÿíÿ|öÿTÂsÉbÁáIDATxÚìÝ…wWú7ð÷Ÿù•v»ÛvÛî¶c˜3'qÌÌLqâØ‰™™™™™™™e’™mó^Y±¢Ø’,˜ÍH3瞞ƖE–ç3ßçÒÿ»aLÓB®n&´-”Ún^ݾi¦W¶púÍìkú¦E\ÝÌi[$ÛÍ"ŠÚ„YmÑ ›%£Ãb±¢m±œ4ë8.Zü…&z¹Ù0o œ4ÛË-Ž&f—„–ÌiÃÌk„é·|Ö.}¢8ûd2ù¨_úÓ¡Ó8ýKäìoŸÜ¾ž@X?í0EÓœÞYáàÜZSºCn,°õ sW³øÿ8”M€¯6˜m€¹4øÛÏ·ã£Þ`¬1ÌŸ ÛôbA_væ@_Žæ ±p8›C¯ïKsnðM<ãóØ`œaœ^.èÅõ }Q¡XPB0Ú Ñ‚d0²Qg˜/Ü…6ø ”¾|X|⩾tÆC0…hÜ`>‰Â¸ÄüF¯Àé‹d×/Ÿ10¯BðM¬‡`”¢±k0Î0î.ª‚/®/ŠÏ<¿Œf×àPì…`Ü`D F´mÃq‰±à.ƒ/ßꋊâ3†ã/T£-óY![Ç¡ÏàÄNô¸©(srzùD_<þ¢A_&c$›â!†Î`TŒa†q‰Qà.âô²ZvŽçê/ ×òâ36 ÆC0‡ã£¶K ãóÂ]ô¢Bß8\_ÞŸQ›L†;‡òYÆ †Ç`8¢p/THÄÑÅfðåuÙmúZb[_(WÞ€`AÁ¼)D#ÜŒ"ƒyPŽFÃ|ì1oßOЋŒ¾¨ê÷EañÙ“Åg šÌÆ^æ÷B4ÿ,¨ cÚc”¼uðЋõN_n†=ómñ¶©G\Œ‡`¾+D£Éà8´Œz†Ñì1ÚÞ"xúz¡ ¾¸¾X,>#!ÑŒÌÁ±|a°1̘Ñÿ&ÀI/:ÊÎ|ª/ÅgNü…`¬‡`ÞŽÆ‚£3X æeÆ2ÃÜ0A/ßé‹–®_¾Š¿ÐŒ¢a Á¸Á¼d—§Ûú¢wàBÅgTL=b`4„`ŽÆÂX!»ã ãkw!£—Ãà KÙ×ýc¯ ‹¿ÀMèÆC0n0Ö Æ%Æéåaðå_}¹øÌ&À˜ ÁØ0X˜/'&!o0Î0î.”îrN/?ê‹ìÀ+LŸ!¿lŒÉÑX˜*DcÍ`”FaÄÆ%FÊ]äéE8øbR_uýòQüe0ÏB0^ˆŽÆÒä`TGaHÆ%æwù5øò½¾è,>CÙÁ¸ÁðŒîŠ4^šFÒ]^ÑË^ðå_}±Ýõ‹±WWÌ!˜¡ÁØî æ ƒïXF*™xÈ™za/ ³ˆqŒ9Bw¹¢ÝegL鋟¡X`Gcñ[g0‡e‰YŘéX¶ÈýU¦ &cêƒÉŠ4ãóÊ]˜èÅõ¼â3<ñ—)Àü‚Ñ_ˆÆ¦Á¬1üÒȵ[æ÷Y‰ÿ-Où¾Šñ'@2+£—aV%NÀÅEÄ]–éåIðÅõEQñ™—ñ—púBp(›Ã¶>%n0Ôß· +R¼=#ñ`ÐZåþ§kàðÀ2ŒÛ(Œ†c4  +½è ¾¼Ò7“ú¢rìkci]¢qƒiš…®Å”äT})mDêŸ.Zº’f~, E†_b[ßq‹œ»¨§†à‹B}¡x…µâ3£;óA!š²Ðh°˜UL‘ÒmMü¥6‚Ä÷ñ¯%_»ÝµŒà+†9ÇU*' Ýö~×Ö<ª9ó¾ìÌ }ù-þB¬/ óGæãÎ`4|‰aiSïq©Ÿ¨è.Þ_К“û'åŸ3ß5Ëýe«müÔ<ƒQÈ04ÃÁ3DOÆá+½¨ ¾¸¾X{ÅÀü‚a+DãCa°³–Þäyýy^åwRWíNI⚯٢у9é)_’ú9@MEÖÔ›õ¹Â2¸"ÐzŒl³áUý¸¾xñ™±¾¬ÌËŒÚB4n0''¿z1-ù=Ú5o£Ï§'ŸÁqz $^uÓœWùƒò­)ÉR^=S0ñdkÉÌ3Œ~’mxÞâ±D/®/úbrì]€ ÁØ/Dã³Ípƒüuêøçýæ@ïçóãdwk3ÖmAíå»Ó’?d©<’0ógwå,¨ŽG:¼€Ùm zQ|J_lŸácër »Uƒ¹eøŽEĨÔ?©ÀÇ«ÄÏß§ÇGÛÙa ê_ žü)èòmËH æs†¨Åc^ÓW×—S}/ Oæ§ÑX<aƒe=Ǥþñ¥øåŸ€ÛÏ—ŽÓ£C`ðœÒ¯gc²þ¯[æ75Ãwœ-"}5øĂá.¢ôÂSvÆŒ¾hxÅûâ3óÍh,Ì¢5Âr4 tüàe;¹Ïô&|°¿`y‚ŒV•áf/ØÆ%F‡»¨¢×9}ù!þÒõS’`,DãCf°¸ehŒ^4~Äàϧ§GÄé !ÊĤùëÜo©'Ã8Æ38@ÞˆzO¹eŸÌo,B ÙÙ%†q‰QŽ®ÍÕ¿AÌÒ‹ë Ÿ¾pŸá˜o¦$…]ñ+Á †Í`W íf¹¿´ ©?7õ£öƒv8ÑÏࣣ½º<ÊͤyiäF9͉[ÅH™ùª¹è8Rš–¡³œ©×=‹pv†_bcHÑE-½(*;s©/ö†=c=þB0 Ñx†szRÔkÙ ÉŸzdþ ~h"zöÅ.Ù?fÎÞLp§†ôÍq|´×Rvž€}f jûÌ<ÐBÏ2æµL¥‚h³Ü_”V'#ùåóšÚ@e´2,àÇóÚ]ôÓ‹ë‹Ââ3¼c¯Î[0#€c4–)::ƒ1e0‹ +Þ¦¬¹Ñ+󛻺º²ÑG1«˜ •Ç„ó…8ˆz·g$àÃÒdJp«Üÿ@ðU2þðF¥Oæ·Ë‹HSÆj•)ŠÙj36˜k†!“8G*wù‚^\_¬êË}ü%|!À蜒„òB4nð—Â.-™Ê¬uÌ‚ß(Òn…´õîdkýò ¬ãåùÕêg;4œ­­cš¦òÜÉ7îJÿ¸ðæh”5,Á-›äþ2Õ³â¸o˜óǾ!¸ '½pê 1½èÕe]¿¦¼Ñ—S€¡ Á((DãÃ`0-Àç‹<ÿ«DQœ ñ=õ+sò?o&yNôîïRè=Ù\%õ4lĸÎÉýL™ <.ùÓ°Ô¿.ÜøÁç×Û¹[Y¡+ï^S°ÌQyðÔ<ˆËQZ¼“+$Ãóª­š^ìéË»WüQ|þ 0¤#‚ù©3k3aø2ÀŒÚÊõ­ôÀ’Äâ„͸K/®ü‘-‘ƒÑnJ±šÔU;ÿêOÊ×;dÿ´Ô5‡d°4 Ë1¯`FäYcÄ]þÔ7ŠÇÞuä3¬óY!7˜CƒY˜ƒF4¸GÅtH!êÝ¡|}Lêq¯¤Ä­¢¡š³Ä‰ÄaŒå¥»‚I/®/æ‹Ïߌ¢çàÞІÞ`  Žà…7×vk²×—çAtžSü•ú­zùë/Ý8=ÕB-1Ž1ûè¢È]ˆép}#øQ_ìŒÂB4÷›ó‡Á0Ü$÷7uã#è›ô oD¼]±#Þ§ýÖ°ÔϪò÷-¸;ó ±5..$îb”^\_HõÅòÈgú L!šÕÎ`Ü`n ÎV~@;àÉÖ,÷·®¾#gaVIÅ=¶áðMA›»üL/†õE{ñÙ„}/ŒžÑXhè FÛ hlì£öšvÝ+¸HÛCÒ?·¨Þž´Ql4Qbs(dsŽ1æHæî•¢Ñ]\_tõûòyñù`à þ Á¸Áè04-}ÇAé#£ï¤äU Â>Ú¡ž½5U®ž‘’f~ðœ ã‘Ã=*CôBDÐì.ªéÅõ…U_ޟ錌 Ã÷ÌCªå…hgýÂÔ&$*Pº«¯o/û!%®ª7µ~ð¾c"§l^` ‡Ð°=1NZ_Ћë+0úB0ºB0::ƒQ<9ƒaˆÂnꚣ0W¡§$(WÓ2x{Û.Á"º¢ahV+°ñ38'ÒˆòcÁº|@/†ôEbàÆŠÏߌ¢Ù…ÌR{aâW¡ B]üŽ~ß6Ù?Mu-ÁYOÊ5=¡º/º¢û–OOèœ#$Pâòöw½h ¾ØÖ%]¿7aÓ¸I`Ü`~4˜åhsó6ÙÿÂ4iPúßžêj·,#Aü5‹,¯ì™RpÏúräùù;ŒQ¨2/'ŽÝ…–^è+$púò¸ø| `>+DÃÞŒøŽIˆ ]·ˆpÓк´˜3÷mLꉯ$ž™PâoRM\e/Ó"*$†ft7ô½ç0º‹,½È”q}á/>SÐòQF¸3X f•áGf¾o^öIÿažü1Wù>yÅ+«Ø[¶ñFá¥ÍÃsÌÎ’LOÐw,#%Mýž°º‘N2º¹å½˜ ¾¨ÑæWè+>Ó˜ÕÌ…hLÌízÑ<0ø¦nü OK~_+SGßr|þ>5¼´+£qH|õ“¾†z¶ñ¯$>ih>‘ʵ9w§×—ŸŠÏFÄ ÑXš˜ÁPu G³X‹6Ô³‰%9ÀÝäàiɪå…,tÍÅ-£ÀyPÔ:î_^ÝÁ0´„³'Í™ZÌ*FÛÀ©TQ¸Þ)ûG€ÚKySO,#ðÄòŒ^Èkθ¾H{æuñÙˆ>À¨5˜ëB4zdaÄ`袰”‰·½–aŠÊÓ™ÿpVyÎQ~` gGÑ´ŽI®iõ%ã÷99“ZÇÉšzƒË‚éó¡Úý2¿$½z¡§ïpÏ"œ4œ†„»ü|q}yÛõ 3ÀÐŒÌñÈ,9cw+³`UÅRE±^™ßX,;7Ê] z£üÚèí Qîcf~ëè‡ÔzÎΧbVÑÖ:f}ß>‡ ÉŸ*D]5µeL}pØpza£Múru‚F_þêúe)þ^M!7“òØ`ø‘Y †Á[ ±‡ºZü+‰B¥;m2vÈüI;ÍwPê_Ͳ¥«<ñTc¨gûÔ,öœH~Õ::/ù!³³êsSÿpUùËÞ$¾ë’ù=áµ$9 [âQXÝ彸¾(Ô×b}™ŒÖB4ª:ƒùÈ`DaJ»e!eâ­jèb¢keªcù^SÇE‹ÜÞkéÚê˜ëÙ(ºkvùÌøÔ9%¸¨=½aãs«šáûREñó-˜SüeNþgÚ(\­ üICC‚è.LôB|q}1\|¦ 0Ã| ѨÍçGsž¢wúûæü¨è‘]7@0‰(ãø k©kAÝ1‚¨#¶ãºS»hEÔ»='ý#åë½2¿%¾’Ô0|'žîŸ@¸KŸ^~ ¾˜ÔÞ®_$‹ÏŒæëB4n0T#Â0ƒó ùyÇ.Á.¾ºmlá¡S2g'Ù»á ÝRóæÑÜøéÑá‘°×T¼`5¯úå[ã’?+Ý2ÓµÂËÑ|.¬ô¢,øò·¾X(>³0?ÌJ‚§3e‹›…Þ6 È`ôGá˜çïSªû’kû9>Õ>1 |£L!vNáß›ñŸ)ÇÉñÑüävnø¢Écj¯p…‚ˆ¾˜U4N#?ºËSzq}ùX_öÆF!š÷Á¨1ø‰±ï[ @U¥—ï!®(|™aE¬–‘9ãðRŽO¸r&žÉ¯žS|]ÐÙ)Mþüíq²½¾×X´ì¨D)GOIþ¡òø¥‘ê—ºÄÑŽp–1£¯€uýž· Fã…hÌ|Ï4ÐIC·]öa©Ÿ“UžÒ5Xˆ/ ¦2|Ç.Þ.¾ª\N¼Ü7ÌbS1vËQ¾OxÑôÉ~KéçKÇéÁþ~sÉ’¥åfàöÐPhÂÁj—xCºpÓËûà õ+.õ@­¾7y¤/Ëó_!š_ 5 ×Óµ©‘¿I"G龑Žåm3ÄËÑ2üü}Jbu_rM?óQZ¬¼dñ‚ÔYý™Þq²»µSOÔ»E¹e¾ò½ s‘qŒ±†.:èÅXÙY õ5áN_îFs!½²6XÒÈ#ú•Ô”äÔÁD“’?ß«k=5öA«ÁÜ2,÷)³apÆ(¼„É(-ö°Ù“ýÖ²Ï Žãåùõ»99ò ¥vÙÿšéYq°ä..šÝå'zq}ÑßõKE“9ÀÈ¢‘ì æ7ƒ t¬Zeÿ{y‰N™ß#_ɼÖw5GÚ`˜·‰3 +éž$ÞwL¼r°ô×U;,#1˜¨-º[žÊàÏ'ǻՙD½Û”ÉÁoµ .Üù#ó`/yç¦þàÚc˜½oJ]ˆeôB^sÆõ CvàU(Âú² 0Š;ƒ:ƒšøû¼yIiÛ°ÔÏEŠ·lµ ÁÍø) ?tJ ÈoËiamÎÒ‰eM¼\4µu ©gd)SŸ˜×Ò_FAËý¼ëvztȈàÃÑîçW”ÐÔ9ŸÈ¦§ï¨¦œ©ò¨Hév±Ò­|å{*OüÕ^i8Ý£·x_©Œx~}bèÿF%ð ¸ÜeµÔ€»(¾‚¨/Ê^±0^ˆFƒÁôV4ø¥üà !Ò?.ÛÊmĺ®|PŸý?êÊ ª*Ê~âÁð0,ù!­°mÌ1±†åyÃä¦nø®\A´P鎑ž %¤>0ñVW¥™¬u47Áࣅ©U}ÊXèwZzàÇàÇ«„F¤~¾°ÕñÔ¿j„üÕ^J™úB^F>oêê½2¿·7Wùø=ÞµçGzÑ|y¨/Ÿwýr 0êöihƒõtmšeÿ¢Qw c×§†v«³Ãsòÿ¢|k@úßñ/_(¸@g0Ï'VUŸÜ²´k:[ó† ôíÀû0!ùc•‚ˆ“–Á#ó`1Ëhm£1©|™‰¤)¼SÇ(“Z–íÀÍz¤³Ó6~mô!öµTŸô¯3Œw8þ%ðò 3¤¡Âd×ìÕMÙøc¥‚eKipeÙ -LU\WݾXóA½ð_\_Ìuý²0b…h¬t#eðUåh-# åt¿â¢vH¦Nž9œèߌÿ´ %Bù.HiI/Ÿ‘ †l†L_Áð»xDŽꖑy1ëX¶¦›éYRÎÝ ÂvÈþ™ðJÂ@ÏÖPÏœÓÏׂþqÙI™ÔßB§ xgs+ÕoþõÏÒíÏ• ÂU ÂÃÒ?Ór;ÿê¿«ž›ÉÞà¿Ô DŸÌ¯&ºÖ·8ì³ÄÛ7Í[ýͤͅ‡¥~®Q UUPûÂ02îÂD/ªô$}yS|f ` ÑXë †mbLß1 þ¤ö†z2Z¶== Ñ qr¼J™xÑð>Õà¨WR2†Ÿ 5i†¿MŽ*ëŽ(íbwê°¹®%í¹{\ê§F¹kÅŠ·Úh†°Í)þ²â¢¾ßVyº¿ûµø¼Hú’G`I}OàF7õ®ZŽ÷l®ÍM¬ySˉ¯^÷rÀå®=0ÉW¾G8ß¶™¶v­ÂͰ3†o]bjzcø^\_äôe `”m,ð?2ñ TUü¿^þ±•L'ºm­ïÆPç°Jÿû½†Ö-Ó^ÌÃRÒ«z§LÂKÙ=o^ø|¸ø÷†°8Á%ËšÉvVÈvvèFÄÛ•w¯Þ\£èˤí'œQÞöÍ$¯ù—Rßs}};1ËhQnšªáûzùëLÞ2Ãò7Þ¨<7õµŠ†Á]˜èå³²³ëk̶¾\ŒºB´ÀüÄÄ7XUáKÿ¥Úõ‚ú3h6W·’}¨EÑ,åJ”B4=ƒQΰ¨u¬V@ÁðÜêCÇ$vÏžfôfÔæä~è‚6§øëìù¶HÌÛF„óñʹþHZ²¡ÝÖ0ôâs³Qnš¹®Eûy­b^ù÷íü轚ìÍ%™9¹Rßjp¹“¯tW_Ïî–E„`ÕœQÖé‹N}y×õ Àˆ¢…IƒY˜\D_uףܲKæ?Ú¦0ì¡wE:šÒì”XSÛOààÊÀ4 õzˆy7û›³’_ËÔ}2¿Úê˜Ü»bÈ.Þ˜gþ¨¡ÞÆ/Ë–ÙÈÍŽœl,NìÕ篸¨Q¯x¦%¾o’ûÛ\Ç ƒ£a£mÁ;úboàC}¯³0Ê;ƒùÖàÛ&AO ½ÄÉÕc*À>T€AÀÝÎ c¸ŽÄñÑNi2e@Ö´ä÷ï4´¯ÜÇQøñÛ¤¨òîÐâNN¦ õKÿ «ÁóÊÿYP¿9§ø ­¾”V tWÁا”ã¥3ß(I}éV_ °¢¾ 9<<oçF,h Ížw·Éþ—;ƒÑH/®/Jõ卸 À¬¢ù{@Kº{¾yí¬®M5˜à9™Ÿ6"ß}ÝMïò:c=+ï^YGBCóŸß#?9C7EC×ûfA¼‰Â¬1,ù!µ¦oÚ8¬„ƒSªº3óND8Ú„ä=ŠϽS«4y©dꉛÊñÒÁªJÃR_2îVfÈÉöÆ¥­«6H½KÖRsç]õr×$M¼EØ^ì;ô¢oÈFô E‰¾œÌY‚±-«ê½­n–ý‹jðmÓàjjÔsýÊõ£™QÆëHL¯z\ø¡±Ÿ•¦QªÊ“Já:ùÀ§ ‘,åo”_¼7CÃà,üÊ;{l~õ¾CËwÈ»g¨uN0YOµ×OÌù ]ÚyDA´gÑIÀTƒ÷Û+‰Ú¢”^€rE±‡fÁg²™(¹ÙjÛi™éX(¹aŒ^´”±¯/º~/À-Àh,Dó›Á&ÚæÓgý[à¿ÝÒÿ‰Wy®©kT®”:¯Bÿcõ“Îáä ÝóÒ^}þ¢Á=Ê ¬wêZ ø(Þ¡âM·õKÿòI]í‘©?o*Ò—~è˜RØWÙÃÙ ¢–ÑÆºÖpwSZ‰Ò-mǶ1±•½‰ÕýJÙbp.>uß<4_éî ô¿ ”î¼1|Ïè^ž¿ë¢¡Ý+óÛ—ç¡öÇ«DFך§ûoçþMÙ9ã©iõNtôRTžVË 5Ê]ë’ù½[æ÷Ù?Àÿç)ݵÕ6B½p_AÑ÷&ºõ¥ŒŒ ÁílªmF=¿ÏH|7*õ&Ù¿ n7ÈþýuòŒÒ¯ëVG³ã;€§‡W= ædÿAÙ¬¤^Àð…à;ÿú¯õ@«íÌàUWÍyåÿP¾Ø!󇎮øû„Æ`®~þ>¤I礎Ғ3öHSy·¾2Xêšß± ·Ž©(íœ0/ÙݽŠYo¢V±oµô(¿Í)IòàUEÔDáv£ß¬²PÞáå³QПƒm ª_–h¥쪡Õ,÷ׄ$IeࢶSö÷OꨦEeg\_n»~!êÎ`>ͽÁá̦2<)ùÃ…ʼÒo+®»•éÇãý¤þ–­T¿%K ðõ+¦±Æ|8Z˜:ÙÙ8š#OêøÒ‹ö]ðkEj!š· K»¦ Î,+ºgr¼ˆ‡¸E„™ŽÖQWÞg¥`¹e]¾¹-Oœ“™oÓÄe»gÚ"÷?šOyÆjᚈ3ÃYc¥AÕà}Ãùº9ùí·W2Ùº „àMaZ€¾=2ÿ¹°„Ù¼êß´ÿ ›N¶àëà‹ë ‹¾Á,ê ܤÀ§ÁØ0øÊ(|`f‹H¨ß êÞ"êß!ꈓ—d’úáÊŸÚ)Kù|rrvö:ÙŒÿ4¯òûùPÒë¯ ÞC=W˜mƒE­b4ýóGæVÅmbÙ=LÛž™úª*ÑA´\åû¯Œ>ˆZE‡ud7 «úäŠZ³+{ìëZ.- ¤þ¥ZAÈMCó1, ÇpÓ®äVÊÄÛ\ÇBÂćú•Ûæá¥Š·¨/pÍ×ìxyžá´»Å™µ”[ª8‡¨*\/è»]w89HêmXyÿ†ú¦µÉþùÄÔ]ô¢«ìŒQ}CÑ ïKú^å…häd¡È`Öæ¬m&ûœl­S6XõУ.ÿDÞ}OCû®iÔs…ÙcøŽmœSBuUïG+x|•XÔ"JÅÐ5Cùïa³Ü_&ºV·,"tƒ‹*{¦lb«Î‹Ï¶‹FªÊ2z>ç ;jéßa{(Ÿ6»sÆ^~ÈS¾—­ü@S߉:—7DU‘:k^é·ÝêìSÒ]€w+ÓæUþ N‘úçÌ·ïÌ¢éÓ/øNŽÛhjÑ?©*ò#½hèôÅ–¾!è À¨ì æ;ƒáxASh=Ôa§0vÍßbþõ_´ßª‘¿©Â`%( f‰á‰¡Å!…í\,¤õ¥‰[D¾1x—¥üÚ7ØðACë¾YÈmÛøŒÆÁ˜Š©ilíXÌYûº›“äwDƒ{ëA6K¶²ó ¿Ð¬wý]¯Ì¯¹Ê÷TÉã³bi\.Ae¬kÝ$÷÷¤äMrù¿y)k쮜4ôß‚/R_Qïö~{Õé!éâÆ‘½ ‹F˜W}–íä>Ÿ/Ü}L$Ð~«OúW=][$éE:øâúò\ßo6€Ø`#Ü`è Ö×±¢^þÃÒ$¿ŸWüuþõÿÈÃG¿Ýs„`¯7¯™øÁ³lK ?sN.ïš°Œ*çz=KŠÁÊFn±¯¤&%€ªë7XUá…‰ˆe´cbMQû˜AH1+&r¯2µœ>'ýãv^ÔÉúòñâÌáäÀvVÈ¢ÉcÚ_bƒü5m´YKç ‹¹¿(!|ì䮫*éZ§ª<=ß¿yVêû ¡­ò€¬3MÁ ßLö!êß•¾â×:'ÿïƒáÎϧ§'{Ûë!vÊÍrIy𽸾hxEËåe€!.DóÅ h. †`z’šžc½Ü5„r¢¶"Å[ò†nÌ—®„•a)—´áÙ9·t¨V–³ˆ|nê먥_/w{}CU奌½D-£^¼O-î÷Ímy䔼C¬ø÷Ù~ hÙÝÿÜŒÿH™C‰Â²~ÐÔA´ŒšŠ¡ë×d†âˆÔ?»eþ0¾Ðá=¯ò;Q[lÑðÞ¢á}¢®8y¿ä÷¬•|„É?¢—¼tè·ß+1/%á¦#Á×®â3 À‡`”vcØ`)ÃOñ*Ï‘D·J^ÈASOÙÀ%3£ :¹@Â)æ¤2,j£åŸ?»²%f áÊÒ"–QwÌC_º¼Qn¥Ù˜­Ö'ó«§Ú›&¾¢gÝÌÞ9-¹Í#ê~ù"V±ÈXE;øŽZVýÊðÖú~W-QGŒ*Y“ÜßÔZ4’¦²·l™‘{™¢òš‰ï‹•îÔÙëE8»`™^\_lè Ü<7}Ó2|Ë$ÈI]±3Q²ÊÓWúïn›†›G”vŒ»¤ÔÞµ¥ÿ§?÷lb­¢Ëkú¦áØãDáfÁ FmµŒÒUHÿÂâ[4)ùCŽò==ûûæ!”‡å>fTöL}Êh¸kŸ€˜UßLwNÎÑááDÿòÛ—Ô¼žªòµôRš¤±w1͘g¸4i»¦©ï(eŸWœU‡Yza);ãúB^|¦ I0Æ:ƒùÔ`ÆQøžcµüMdôU2ø Ô!¬¸#º¬ªU-é¦áÛæaÍd= ô¬½ÔU3”ÕË]”þ÷åÂJo¼QÑ4pzb nIe#¸¨#¥v@Ù3[A«®˜lðñi°šƒÛeÿ!Í‹YDe«’qMcõ,ÃO“ª{§tƒ 9\E‹ëQÓ¬¬vSÞÑ0¨ä‘…0T#磂çdÿq0ÚÃXàÓ㥹%pË1©D½’¡üø#³ uµVòdÙŸ'$š’üaFâ;‚Ä÷’?ŽHý³Vþ¦£–Ámóp_Ñ—7ÙQKŸºö$ÜÅçUqóˆóçñ¥ãï’k±M/®/Oõ½Áš¾ôæãÎ`ì,jj¦mÚ+ýLË(¾S׺cLû·\Óç•ÕôØ1½3¤K¹¤Î®l=vLäj1KX$ަÆ_p‰à”XÃúÔ#¨Z…üùhaé·’½™„à“íuÊ”›qÉŸâ^J‚Ÿ}nêŸøòÅ(yŠï Jj–ûÛ^Ëti›¬±{™¢(Kþó¹±õSq×.®qhF?¸#5gT•y«o(Jõ5b¨/+óWg0Æ íŽI ƒ†‡¿–}aìuáÏ»¶oÚ2ªL˜ƒ³DQXÔ*ZÃ/oba<Ð ’e¥a8©ø«­ï jùMé;ðò×…8tÄOö¶¼±îDø™©ÒËçöäXxó÷zˆíz å¢Á]ªÁå ¢o Þ!€.mµˆŒT•£Îú…­y½QùòA"¢ÀÍC³:X ×Ûú27U_Ú¹á®I€†~¤› d*=P6p&ÿ ýóVü”QÖ9®TÀù ‚k†oÙÄXE—WõLA¼»tkøçUø›âo ³ÕÒ•)Ý‘2öùºK3íTàüh†+$¯-.Ÿ• §$h•ýo£Üµ‹úªßØ)Œ9ÝÛÔ]O5Däˆ×²P¢Ù{cõõlažûÞ-óŸ;f¡´Ÿ%.Æ ½W•q}¡xÅÀ¼ì 0ƒ9Ù=IÜ4DC×¾@šþàjù›Úº¶"ä®ßo6(M¯xí•ÍíÉ‚ †ïÛÇG”tF•vÁµÏ× ÓÄßhŽ·Jd±å*Ý›”ü¡CæwgM=ÊÜ'q‹Èn™¯åù—î5ÓéÞßÝΞ;_â› ñÝå²ó¢Ñƒƒ±^Êíæ'×<õ¿–¿n¤k +·t, VU€u8-ãËŸ·±ùµW^Ù(¦A}M±¦¯ –ôe 0n0Ç#RŽ1 }bäí¬®ÙÎ].UÕÔ³ý¢o­ÁžY U½òÓ¡9kpÄðC‡„äš>ÿ¼x·;äcrüí™z›T#já.&Sì—ú©N¶é}³àw:4¿Ðïæ_ýw·2ã}÷¶7ÜçäÿÅü“@ÔÛk.ù²‡ôXï¢éÚÎॻLEGÃÑ^˜xç+Ý™fmq+v[…¼ð-ó° ž »$1«hA£¡²3æõ…`àg£f@n0M3 ‘0t«®Î&ìî²nõRRÎÀMä}¿2]ÞåžÙðØ)Ê3› ?¸õMë ´ñ0›‡µ§Ôö³!€™0uø.`ÄBÅ;ßþf¿›SøeÑâùf¢ÇvFàZ 5ÑàÞœìÕSzæd~Z²x¾S’¸[—¿ì¨|a?ðiIxùâ¡i LÖÒiÑ"QšzŽ 0¢G$ÿ¡hèzù3ÞÚ;@%½Ø/;£E_Þwý²0j;ƒÙàK ›…†o›)é¿÷xó $Ú+«và™Êõt¬ïš S÷\ºôç]Ó;å”PÒô§–~ñ.ejqC‡àöÃ,b,ÿ1£ u”»øË^ËUº{y÷_Oéü–¥¾Ÿ“ý¹Éü4+ù«2Ÿ’ûçœÜÏtwª•¿©«g7º"54Ôµ®‘»1-e6Öµµˆà`Ä鄎^”tú Ž¾Ü M!:ÙB´À,t>QH|Ë4ø±Ÿ²þ{G Ýà×réJKåE(-[ñ^Ä++M£†â¦!äà{á/“æ/ü‰SBmß´YD Œç–tI!®ïˆZF #¸ý0‹Í'§9·yXÝ/±P˜¢ò„O=–É"uò×Sß;W½ù”"J^ù ^qé,oø1Mùñ˜$4ƒ¢ßkh‹›‡Óro­åŸ?¾°†jzy_vÆõ…F_ÖæûÎ`ÔÌá %Ú¿+aò¤aàq(hÀÚóFþ'pW˜ù_éÙ¹²GFvÓV@Þ…ŽaÄMÌ*Æ0¤¨ozIº…-¡’Xâ}JaÛ¨WVÓm›8¦Óožêo¦ ÚB‘•6*õÏøW/L| ƒ »Ôàèݱˆ7pÔÒo–ý‹›(Ü-ó =ºúRæ¼™F”6 Π†^ƒ/®/Ïõå `Ü`Ô fm/aΚ}\ebu/`øòà,ķޱŒ.¯ì™„`0vNªÍjÖ ,Dd¹/ÍP×z’Íž~n²oÒmicð¸¯}r’júìâ*‘D—N¶ˆ|hh«eT¤xk\ò'v;}ƒUŸûC<ãIçf¥õ–ÜE˜^Xƒ/r¾¸¾Œ,x{e5F”tȸ¦^œ…Ãwíã#˺"J;…`˜‰ïØÄD^Òqß>Éu?$Œ½Ø…‡ãÖ"÷?]KÊã*{fE•uÙÇW!É-“4,fùÂØÛ^Ó æ•TÓá‡=2¿å)Þ}«©óÌØWÌ<‚ùg\ð}L¯/éç#zy|ù]ß\ëËÀpt£mP4¿ ÃQ¥]îéõâé¯4‹Ã÷ÎöËkc“%n$6‹(K¯4 -F~ JaF+GBZ|þG¤ª¬yÕ­3ø]Rƒ ÚÂK:¶–ù޼"‘ ‰’[hªï´õhÛóгo‘oÆÒª/Ö1à:#¤¨wô«ïM^êÊÏúq¢/àkþ¼4ØHÀ ÆN.isI®¹mCw€4ìŸ1üÈ)±~€`^ ß^‡œaœPÕ›XÕ+ñ>!rhÌ{§©; 7p‚¢‘•اo“¼²š"À«¨2Fc¤‘aø‘cBÝA3 ŸI"A^bMÿü¶Q‡øjžPtÏ4¸WêWXõ’ú9PU‰öAïÚÆJo(håKw©Õfq›Ø”Úþ Â6ŒÓËgeg¾Õ÷+À187ƒUÜ3²µ| ÆH#ÃðsçäåÍÝ{vqÌK#È0¹yg7¬äžÉ«8è®®6 çd¤ I#Ï ê_UÞ=É7âÒíå½m×4<«T€”»¼ ×5úr0n0/ †ª}ÃÁ™ ê¾9̧*ÁÍð‹wÉK;,ÎYBFbI—Ô¼–Ÿœæ[Ö1°,ñÁZFÂÔÜ%󻣦þåG´¯ªîºgut™Œ®ºmÛL˜Wô¢%ø¢rÈ• ›'pÔëû À<î ƒC±b°C|edi§âÇô+§ Ãǰ¨e´AHQßÔ"»³‡aeØ9©:³añn9¬`èÖ#ýë ô{Bÿ”¬òìlƒ ‹~ ƒÊä%ɰ'.KsŠ,¢îØÆL/iùçáÁ×}/ŒÌƒa-GsʰWVcxq»Ì‡Ô«ÿòa3XÌ*Ú2ª¬¢g’³E<àø®]\rM_HQû}ûxÞ,IÇ`Èr0¸+ºÅg*À™œÅÛvåç„òqºg·³€5zQ¨/<Ã¥ï ô¥0âÁ¸ÁhŒÂä9H ä9H,ž``ø¶MŒGfcNó0—ËiA(±V@~fã mlJVÄ7Êý ÉÚX‰ïä¯këÙ3z,ý࢜¦a ¿ü ÉvÃ’Æ^Q¯d†¤ÿ(e]â‰ï&%ì–ùOÄ+F•gêsP9[ ë à(¬ºËt`³ˆE”IXqÃà êGZ¡ øâúBŒÎ`¬Ìãr4]†Ÿ:%TtO˜G”puŽàšá‡ñõnGİv^fåün[‘Õ8dD^ý ¥=4 tÖÐMVy: ýËÔÏ£Rÿ—úiBòG@2mHIýcXêçvÙ?ƒ_+’Ü`áÎÑ °×îÒlQ>rØ¢£úÞÀõe0n°À¬âžžÙ0 ˜ÏíÉ‚»aÒ‡f4¡’ÊÄbV11åݱåÝQ ð×MÌ# \-µM>ª«û«*e(?¤¶•'Þo^9kêª~¸cÂú}*{dF–v9&Tñ™»4£î£>e4¶âô"|Tß3€õýqƒ¹3U]Â0¬é—“Ý8¨íŸËõ)ƒ9ÃWH ¨›_Uø˜ŽäˆŒ0~í•×<ü!µŽ>c‹HqópQÖV!F“xŸB^º¸íèrº€†˜Utdigpaúèe­æŒë‹5}ÏÖ‡`Ü`LFa Ãöqå‘¥JŸÒ¹ßÓ†Ÿ¾MZÙÚE~Dº;'ÕÄUö¼öÎa]ßg&¾&:–òFí>‹­~ÞÙM 7º¿b¶ý!N/o‚/2¾¦/pó €qƒ‘Íû‘Y 9%TF”´+|LƒjkaÎêÒ r-^X‹Gß³O©í.ïÿÃb‡ñcÿ¸—’cRÿ¨P1Ò±z`$‚ñ(ŒÀBȺKm·¬cZFæÌ"J!p¥ôò2øâú^Ö—`Ü` Æh9:¼¤Ý/¯ùÙÛ!èvf—aò2XÁE½Œ–ÁBcÍ€ü´úÛ¸JûŒµÎ:]2¿SJýËGíˆÂwÍB°Ë0| ñÝ ·Í“×?ç=½¨©9ãúB¦oàe}¿7ÍòŒÂ‘%™õã9XD*†Å¬¢-"K«z§xð·‹XF{d5&Öô)¸g²ØmüÐ4 _éîÅýíeÿç®®¦`ôñžY0†`!ÎÌ¿ëÛ613Ë› 3xWmFYðEo§/Ÿè{ `t Èpƒy…ÏN®éóÈlx`Ëxº0ì ‹YEÙÄ”—wOð`rWtbzý@hQ»¸u ‹TëX6ÉýMwêm³ìÿ>1|Û,[ s°ZÑ¥mwlbwI‡¼‹¼|H/ÒúaL_zC2 7u]Âl0\Ñ5a[Ϊ02|Û&:(¿%±ºî-‡¯lÁ…iu–Qe¬÷{¨©öKÿò]©æä~ž•úþÃvZ’Æ^ŸÅ"ÀB\6Þý¢;%lì죚^\_žé q×/'ó¨Í?£ }µÁ"æd€cÊ‘†—ás‰ïØÄD~Y‡ö]‡™/Îà“ÓœZÛ/Ïd6ÔÅ*td¢Êói‰/âõë-YKµEçU~SÎSº««k{Ï4üˆê~ì”è™ÕSÞ ™µ(@÷ë:”QÆaÅÝD–Ü,zù Ó—M}Ò—À¸Á¨–…\~ê”PÚ1fQÂ|ªÜ ß±‰-ïöËmF`×a¦õ礄ª^¶–àæ(ß§*»•x²µþùóçÃÉ­4ÿ%KÉ3†¿§n¾ë¬¡ýÈÄŸb0o·:fžeE­b\RëJ;Çù€[ºWZ–QeµýÓHE^˜FZa$øâú^0ÊdáÃ…?¦gÔ÷ëæ³2c>†ïÙÆ´Ž¼Kªæx¨êÏ`Xÿ9Ã¥Šb_çd~Úï¨þLs¯Ìo¥ø.=ߢÜf\ò'uÍû¦BfJxšcB5'£RÜËË`ä·¤Õ÷óŠ^_Œ–1®/S€qƒ¡4ª.aØ£°ŠGFFý€N@>‹«vÀÄð»¸úòBÐW¯ã—Ä"–Q>ÙM‰U½R.©œLÔ;hý|é u×/;(ÍÉÿköl7_`°‘Ž¥¸yæÆ‚µt{yÀ±ÝA­0»‹zq}‘Ð÷*€1e𠬌š(ü à ó¥Öö©ûä°µxä _˜ ?sNНìaw;&Z€AÒ=îüLï8š›Xu×;3˜|ËbEq #/Öçâ1ÀX…–áè*1«¨âޱ)5¤ÁžN_ŒêÈ¢¾€ý83˜‹AѸÁè5Ø6¦<²„¼%kXBÈðû¸¶Ñy5ïlö¶Œ€°þœXÝk^Â9À÷†:>38€ÁËö ”Z4Ášºö¢àí¢]Â4䱉ß3cj»k;ÒŒ_šcB`>r—ÚÄ­¢ÚÇæ!Ø€Ûô¢ªÓ—ÿõ¥ì{æƒQÕ% Ã, ?ÃâÖ¶Ÿ:%p±Ät—‚>9Í ƒìî!mä^¬x‹ð›k¤¾¦ÏŒýæâ›”TSûâ«yäÓ`ECW -ãà× ±/%â^¾ ´÷Z/ Þß3 DÞ-1«èwÉ5­#üä. ÀÑ k¯<³‚^xƒ/®/«ú²0\¢Ô`ÁŽÂo*#Š;ÜÒ¸ÜÑK†;&¬mïA±Ó‡?}›˜TÝ^ÜNÍlýà=“À¥¯£ ÷jsO|JÚ[²‘¡ ŠŽ|%ýÐÄÜÃ;MƒÙÿÎzˆ/´~é_>¨kÜ7 @°'N‰¾9Í1åÝüä.µÔ|Ë*zÿà#ô¢%øò ÓCú² 0n0v †’ြæÀüV‰wIì f˜=€aXÃ//®²çâút§šG{· /_LK~™h´ñöxeI^²™Sø7`Ð>ª½‘ú'-ºsòÿšWúmVò«ÇïÕµÄÌÂØ+«1¬¸ƒнÔÅûÔ)q}{>z…Ð@/Öƒ/ßé{`Ü`˜ ÆB9:¬¨Í#£á±C'g3È$WË›»ðì~xµÄÂQ.)µ‰Õ½ŠŸ®\8RÑàƒ¼¡Û-³PêW\ÕÕ{¥ýÒ lö”4Ðòùä˜Àk–sòd€c_J¼ÖwvWS–ú™Vß›k¾f‘ï–¬$©ëxŒIþnŒÌ¥»”&liRÔ3A0zù¬ìŒ=}/쇩AÑüa0º¦˜ÍE¤¡cXÄ"RÓ7wdvæ}ˆbüÀ>>¶¢;¾²ç®mì•çý¸W’ùJwŒt,˜P¢°¶®]üuª ±nä|zJ§½·³òþÍœÌ?ÀÍÊD ”îŒKþt¡æ¼yzH"Ï!^œYP¿AÍÁŠ·o™†<À»K °]lEeÏ$´îò%½°•Q_àæe€qƒ‘–…"ƒ#JÚ=3iæâQæá%Õ½Sp,rÉ Æ¯½²“ª{ß%Õ°bpØ&ûç'µ7Ê.wMƒî›¦ª<ž’üá|(ÖßÛùÑ'« >ÝÛÞ­Î&›JoÛj;œ¥þàÊÛ—´ËJk[\8-0Càî× >óÈÈÒNpÉcäå ½˜ ¾Wyf°@ÄsÎpjmŸ{zý=Û®¶Tâœáð3€#a˜e‰íã+À¯½²X´I‰JĜյ_ë;û«*õW¡¿œz8Þw¼¾|²½q²¹z85¸Sœ@Ô½uaŸ†Ëm·"ítw x}¼<¿hô€¶'¸CæÄ Ñ(Jt/T\RëúɾQD/ƒ/¾¨Þe[}y 0n0*.ë·+‡fgCN†`¦‹[E´&Võ>tˆg¥Ï˜ 0•á:¹ë9J÷zi&¤’ûç²­ìf¼ûVfðV²Ï²üœüÏÌéý‚·¦ÐNaÜ~[Åz˜#uKj+P¼ýÄ*ì¶M ?ÁFãâc jÕ:2o^ qµ™WôòMðåw}™ŒÌ]ÂlÌÀažVÌX•XÌ2Ò*ª´ºwú­–XÀXæCj\E·gV‹}Ưe©Õf$[Ÿô/M²U(ˆ8{ÇjäÃÍá3ç$ßÜæàÂ6þ@÷Àó+¯¯˜Ì&½|QsF·¾AX×—9ÀX48_ æìÌÃ,bA?¦Õæµ Ãµã!ÓfVœZ×oVÄ"jªƒÒÿF’Þi‰ï+„ÝÕT µ- ÝÒ*Úƒ àv1RÎ- Ä_÷Œ^Š Ë ‘b–QGÇw¬c q—ŸéÅF§/Vô½`~3½Ã²x…M¸†A»mYÚßûÞÃôÆãxd4¤×õK¹¤°ØaüVC»Kæ?HꛫxWÑàƒðùŒ©òî‰÷É5p¬ì‘YÚi[(·°¡KÛž¿M¼4é<©È ½ ¾¸¾lŒŒ.ƒáŽÂì =÷˜ ¯Äâ£Ëº¢J;A*b±ÛØPÇ¢Nî:bWÉ I~¦™²Ü66¯T€J€#8oH<„Í" C {&‰ˆG^”Ò‹éN_léË"À¸ÁŒDfÈ0ˆž¥c61eÐî1Ì®ÄT€Y2 mS÷ÉI¬êuˆ¯d½ÛXÎÀµ@ñ62úŽHýÓDÛB„¦Ü5A$oÅK€# hf¼iÂæŽñ•Ý8½¬Ò‹•!WO7‚^_Ö@ƒ1 ˸$çµ ›„q}vàŠá ³À0dÛÅV¤Ôô½fgQ~1ÓаW²—Ѐ£%©<§Yr‹¼i±EäÜʹ`´¤Û¦Á”U©iÛŸœøªòPaH¸å¸JÍàõÆVt†ˆ»°Ò‹æà‹ë +À¸Á|…?¦¥×õëåCsšàô$uËê à¼öçs%ñ-«hÿÜ–¤êÞöqlý ¹–I“ì_pë; ýoƒwÂæá´Œ€ŽOX^hó Á?5ö±×ÔsUW—0ò¤ý–~pAVãàÙÜhìrK§‹\Ð:ò)½Ž%w™^ •1¢/[ã£Ô`þp`>;rÎ0€0¶¼‹À,KÌ6ÆÒ.)Q¥^Yìþà #Ï4åÇpOF {%#nr¶ÇŽñÛ{P¥Ò{¦N:Ò¿ôKÿþZVMßéyÛ¥/§7 (¹g`ÍÚ+†V‰˜GôM/éæ¡Ú]DkÎX ¾˜Ö ùÿ®éùAf°F 6ä‰Áhž¤ô…á‹›@wî`çœuÇ::¯yø}R5+C¦!”X' ?¾²ÛŒ¥.6[Mƒ6Ù?áÓ·Cæ9× ñ4M¿ÜÑùUHô1¥ÿ¶FþËÒ˜’?VÊ »¨kÊ¸Š›†„f7}°&ÚŸ ‹ˆ•­=ùiP»‹½(¾¸¾Wè{0n0$c? Ó˜ ßµ‰i hùå²>s ‰ß&V¥Õõ+¸¥qp¢bìþJöÂFFPµ)‰ï]ÕÔÅLC/«iUÚ84Mü5 |¯®yᡇ¤þ•®üÐ^Cß; ®¨±ÿ¹s¸K-5?vŒß;8ÂéE_ðåù€gØõ¥Xà Æf9b†?¦Òb†Ã8J‰/b|Ç&&¤°-¥¦üg'}eý÷©ÊǤþ9ÀùŠ·ùÒ}Pï¬Æœæ!HÐ’4tOWzH÷ †;Í•jƒ½ÎÒ0ÖÑ¥m~9Ó‹¹‹z1|±­ïëÓ7ýåh˜£ð9Ày¬/ÜÃW ƒÄ Óâ*º=2¸šÅ¤ë˜¥ôZƒ+ä…ßè9Š˜…Ñ}ĤêÞ ‚VH{©ÿ®[ú·/+õÜÂ/srßúA©+ +M#òø,Œ»Km¶±åÕ½S(riz¡ ¾();cC_nÆ®Áˆ ËÂfþàP^1ÌÀÐIlR˜PÕ£\À¥jºŽ1/%{¤›‘ø}µulDMÃ=\eÏäÛ„*ÖC6 3жüº„úÍõp§è«žKÏçU~§| ñ]‡Ìïa¯e_ë93yVh@÷êñÌgy7(¿5¥¦§‰à‹ë«Ï`Ü`¬ Ïà,z#ÆpW³,1#Œß'W§ÕõI¾Oâ~RÓ #ÏjEŠâ 2rÌð”ÄÅŠâÚ:¶¢¦¡LkpfEÓ/—{Òî˜9ªëP}ÙNþdkíóÉÉñúò~Gõf¢ç’ìœâ/”ïŽKþ”¯xGWÇÙr4Dè~[gÎiòȨ类pÒ‹à+púRöÅ Æj9êŠ4c€e˜+€Ù‘˜Šñ›èÀü–¸Šn1ËHH&5‰™†ªê9y¾y•£t¯Sæw¶f(MmhõRêµÞÛ+SæÆÎþ (FÑŽÀš“ýÇš·ñgšãt—Ô׼갠)t…¿/UÓÒµƒ3‡³ÞØu—Úg–MB‹^Þ_4 xFZ_*À¸Áü…o@0B ßµ‰†`v0–ÿ˜UÖé–VËÎIŸ%†õ]4ôB^˧+?*Sm—ù£[ú·ËIþÔ+ýkƒÜßùJwÀ´-î_õ(OÈ“€¡ÐŽày•ß7c]?_:ŽW¶³BPsp’Ê3ÃO<—t©MÈ4|}g_æC Üåz*;#2äŠúÒŒLßàëÈÌ{†Y˜)Ã&ÐÌõÓ¬IlRPÕ£”Ïæè-V=KºkèÚÛj8©ëø«*ei›÷›WÎêZ&ÚfJúïŘ֜i›†oÎÈÜ*bƒãd{}§,™jp—Ìïo5t—UtYÌüÄ1~k„´»0Ó‹TÍ™ŸÊμÑ÷ÀÜìÏ;ƒpƒ¡2˜€adøÀaÐKü-Æï’ªÓëû_¼Kâb(5Ò;'‚f[QÓ;…$Àdƒ·Ö·s#æ_ÿRˆŽùâ¾IÀ7+zš¿0ôPÖ§ªçÚ+=g)ÃO·L‚8{oB.mW0ó+(ˆ¼ˆÓ‹Šà+èú^X` äÚ`~`˜}€aa˜1À00l~Ç&&¨ 5©ºWÔ"’ã1\ÈžSø÷zÍgÆÇÑìøš·1寅з”õßSîä®I šžã'µ7q*/r”î)Þ-_ñN¢Ê3W5µ—zoYaø&ÌèÒ¶w‰Õeã8½( ¾‚ /pó2À¸ÁØÂœ2Ì)À3|ÀK¬à–_Ñí•ÕÈÖè-ˆ<æÊæ¼–wî&.S›¸iˆ¹–Éù$àïWœ_ìl2øôèp·g⊘…Ý1 ¤ýÊk½·Ô¥4z˜„àý¶ ¢¶(¸eü }K ¯ƒ†nƒÜß´èÎÉþcþå OSþ9-ñ}¾âmu]{aÓP¢KÛª{&â*pzQ¥/o‚//ôe0n0_”£ÙdX€!ÄìÌ•Äö±iuý²®©PMmBŒäÍ]Ò³· œýìcoW5µFԯȸ–+ˆP»7¢]NI{ n)[и n Ð÷óIíÍ}Ïë¡öÛ1›±nDƒ»Ô Â^É<7òà•¸êÌ“ÄõWº ½7ù‘^¬èËâ:ÏWê À|`0ß1ÌšÄà4Èæ<s0Û$ß²ŠöËiJ­í¿e…À´cÍ~æ”æoE—~é_"^I«ê9Š‘×Ó “òZŽZ…^4y”¥_‚ÞßÝ΋¢,T9(õ¯z¹k=Ô5,ÏÛš¿ùñÊÂÙ ­µÍøOóJ_nÐ"û_-Ó/!رFç³!n¹ptß6Cè²ç.Šèå(øb®Ó—M}ÉÿÍ`Ü`´ Sþʰ̇䜦A£‚ž2ØeR€¯ÀXâ]RdIGP~+,ç}3›^P>y/ ŠÓýø|M«ÛNêÚR†ÅLƒ µÍû¤¿,w|]y§z0Ø~ztxAßýÖòe;yæË‰lÆ}<=>¢üÈNq‚Úuj!:Q婬+¯Ü¥6·Ô¹•-ìÓË£Ô‹Éà‹.}¿Ì§c­Íã(LfÈWÒ>jU é6Ãl—¦a˜ŽÄo¼³ªzÎ:‘Jcü)½®´sŒã§L™JÔ-ó[ŠòãjêŽ:E b_;q]v~½S’x8Þw´8s´0u0ܹ¹d+;'ý#s€W\5ÁOƒ—ç×CæäÿEýÖ€ô¿ý_+>7ô@]Ú~éÕ½“èwqz ¾‚¬ïW€qƒÙ0˜¢0c†Ë:ÇìbË¡Ýf˜Ý@ ?À_›YxIz]¿ºO‚åPhl&à-éà`J›‘ønXêçz¹k-²ÿý†Ré4…WÞ¿Yõ2Zõ4X~«² ~“•5ç_ÿoåƒÆḞ5Ó-‘ ßí’ùµ†¨IÂèÒ¶ðâvðâô¢+ø ’¾ßŒŒµ( Ãt†aúßµF`óp×ÔÚŒúv±pÌ0†•ꪞI{Ü!±6ÿòÏ^»¹¯ži™‰ñp¢Òαiuèt—ô LðE¾æƒQÝ%Œ¾Š´ñe€Ë˜Œ”F –;6àn`^Kly2+~@ÛæW·ÜÒ8þq·îK#§`mÓß—É‹T{¼M ×¶ò¼oä'lÆÃ]¦ˆëºyܹ‹zQ|q}YÕ—À¸Á\ŒÕ(l|àÄ¥0\Û.‘‡áD–t¸¥Ö"0ÛÚöÀ.n—txË*šã{xaèQ¤ ޤ¾ ·ô´-cò‚ ZÙÇñfë¡óvëlôÇ8ô¸+¸ô¢µì ·¾ôÆ Æf††áKó€a†C-±N@^bUaHœ`m¯=3ÇæÉÛ0p|¼cU^ p½ì5sMcq“ ð†ûç6“WýDÛËMécq}›rw¶)ÏiRø˜ŠÀ„chÛ‡”š¢¶Qn¾mè ®ƒŒ¾ƒRÿòVUyhä{Ï66µ¶ïczòâ^hŽñ­#sBf¼t—wôò ø"[væ¹¾¬šÈÀ¼4Õòø" G–´{fÖ?²aeÞ0L ÓÌÚ4bŽ$³ŒôÎjÈkºc…À|'h[rMoXQ»kY›†½Ô{Û>ëÖ–¯xû¥®xC¤Þ'ƒì_ÉCz)-¢¸=½¾_È”7îò½¨/;£X_fóÒ`Ì æE9f†ÃŠÚ<2êÙŰ¾|äÓ˜e‰YÆø©S|Hakdiâgh1¶‹-âîNžz%)?[ß>é_\ÔÔo€×®ê•_Ùm^Ì3zÏ?$eãoªw—“Ž^$éåYðÅÈ+Hõt2˜¯ æi—0ï¢p0#Î0S€Yfø*‰•>¥ô6÷iŒžÖ¶å]Ó¸T\Ì$Ø@ÛbD꟰œ¦üPVÿåÕÄ”uêäñÊ]j›Z<[îb‘^_ìéK؇Góu—0º¢0 æ5ûç6=wŠçl1KHf`6%¦‡±~P~bU–.ʾº½pN\ÞܽmÅ}ž!8Aå|ú¶Ëüa«¡'jLyæàr'¶¼ë%äû°9’ù–eÔé¼ 4üîòš^ÞÔœ¾ØruA_*À¸Á˜ÂPW¤ß%V…µÉ}HæfMi.%f`Î1¶-Ïi”x—ˆ9€Á¥Cßô¢ˆ9ƒ˜:¶ r×àÐw\ò§ˆ—RÏ Ý©çž^QÜ.í’Ìw©MùSúøÂšˆY8é5F–^<øòN_Z€qƒñ(Ln6Ñ¥à©è–ÊÅšÒÜbNfCbq‹H¯Ì†Üæ!1ò|Œì‘QŸÙ0 lÍ(âÛÆVšÒÿàb1u;að¡}*i)h½ÉDlOúvÝRk+ºÆ…MÃø4òòŒ^\_¶ô½°  c—0ú£p04sÁð x¾ã§ŽñÁ­Q%°.ôS+jõÊj6ƒlÏ=#?'5­zHspÜusM£[Æ_Ó¶EDjm_@^34ÏÜ„mw©-¥¦7²¤r€o`ˆ^cÒËOúúq£/ óÀX5˜¯£0¢ $Uõ¼ñÊ„h‡%N1¤Ó—XécZTi‡Kr5Ük}Àцf–B ¾Ìa…¢ ™†ƒµÌònOJü…¾×¬5ôïûÑ>Ê3§°kj OÐ¥mÕ=“6ÑeàUãôb6øBÐéËs}ÏÖõÁ æ·(Ìï<ÒÓëúµýr Þë@ Àß`¬íŸ›TÝk\É€j$Ûm«¨ÒÇxÈïYÜ$襮“§êKnº„§%¾/—Ù÷‚¾ä…??¦÷ülçG˜Äe5Ñ×·å>$ó‹»ìЋ_ž xf ï9ÀPì ¯ÁúØ7Qø+à n)`]ÿ\x¶fIbøµŒ(ÉjwMaÿÏc’UÜ3FfWD-"à¸saÓЇF>š:¶^ª*ÀQ¶f(zeÿò­øF×þޱ?Ý…?cʺ ‚ —í2²ä»ÄÅõÛV‘°¹+(ô¢"øbY_€Ü`”£Q°ôû¤ü–a£àÈ÷Yba¸1 sM©ÉkºeÉùPj‘ü6¡²¬s&€© ?0òy©÷Öÿí‡áH8•çÅ bm2ÐõxHêç y¡•§ïÔ4ÔtíyÑŽº¢mÖQ¥Ñeo¼³¸ã–Û‰CAù=“DQópD#/fèEsðE¤ìŒ ¾ßŒŒ‚(ÌóŠ´¸ExYç˜Ud ”' 61H'9MƒRªaÚïá¡]Œ_NS|Edóš$9¡²;¢¤]Äö…”Å,"bJk[û$ >*é9«ëÚéj[i›_hº:V*zo% >ÒM½´Ö~H® +j—qIA]Úæ•YŸ^×.°é.ïéÅnðEzÀóUú^X— €Qn0vËÑpEa–®è·.…áÄÁªÄâ–‘ *ùç5ôִì‡äðâ6Œz¸æà sÓÐŒMt„C µ‡ö±ž™õ)5½P“ .h +j{h‹°¸ZIǨKr5+C oàô¢3øò‹¾ôF‘Á<–%ð µ¼K¬5ƒl§a6ƒw`¨$~í™WÑeSÓ'Xy^ÙÜ}þ‰ÅC¤]’C‹Ú>¦ÕAÑMKnqå]Ay-"fÈ/¿LÛ¦7tr…Œ>wa¥å5g”tú¢/+Cj°n0: fÊp\yç§´šû¶QÐî4̺Äâ–ÌæRbý üäêU¯L8ÆWÃÚ”>¥O×ÄÉ]×\ë«ë¥{FjmŸiX$Ïü©c|RUkJ-ÂÜ^h·-#wö;IJîUîò/½||y§/€1g0&»„! ÃáÅ­îéµí¢!ßl˜E†ÏnbeÔ4;Ä•·>sŒGê¼ÀΉUå]bæpKšŽx,U¯,®ïŠü&(¸¥€ã*xE/¥½òÈ ,‰YD Þ]§=úúÁ§/c€ùÎ`œaÖþ˜ZVÔ*ó>Žý†Y‘øÀ!¬K|%Æâîéu¹MCœƒå-Ì •=aEm"ˆlZTß?}Ç*’.[ÿÜ貃 |Þ¾çàWŸÓ4(bŽbwÑM/?é {ð½Bß¿™ŒŒ2ƒcØ>¶,²¤]Á5Žý†YiŒ†@âGö±ÞY Åí¼Ö—¡›‡f¬)#°`Ö÷®u´KrMNÓT}´V‘%1”9HMß,ÎÖÒ⾉˜…^Ü>ÊòÀi6$V÷ÉJ¬ê1#-˜¾*îécó«Ü,áÄzStKM­é}ŸTÕF·ƒüÀ.†‡;‚·ncgÿ‘C,«èÂî.ô VÍ[ú²0ê æïr4Li6VtMÉkÒ Èeûìæa¦a…Õ½“ìOaºcý ü”š^ôXø]bUiǘøù"Xۯ̜¦A ŸlHîMÌ<<¹ª'¤ UØ, atiÛ+Ï p#n=wù™^T_Dõe`¸ËÑØ2à ³ôw+n^Þ9n^ÄÑb–0Ì `®%¶-/j¹g Ó*ðµÄÊîÐÂ6dÆŽç×÷O?„(°¾x›[Þùº<Í:º´a×#£¾¬cLÌ"œw^6kÎð_lëëË–¾lŒŒƒ©HWvOXG–p±¦4W³0Gƒôó1­6§iˆ^/ Ú=î™X°Ž.1ƒ}ím«È· %í£Pí˜ûÒ==¾¢Ë&ºAqéT˜s›C‹ZEÌðá.¯èÅZðÅ„¾Œˆd`,Ë£0û §Õô~J­¹gÉõîœ0Ì6À,KüÐ>Æ3³>¼¸Ý³9Ïõ½c¹¶½÷Ü ‰¹ËOã|s£K;¡ºC½À¼¨Òð_˜Å½¢[·zÑ*ªDÈ,)tqzQ|Q¬/`oŒ,Q˜Õ­…¡b8ª¤Ý=­ö¡m4D›,±'1ç_…±Ì‡¤°¢ÖOéµìÝâ9ɪ^™] w¥àš’ZÓûºâΉ•Ñ¥Šn©PsËòX*“ÛVë;ûOãøÎ]X»{!øú#ÙéK`Ü`È æefŸá‹»¥ÔD·‘×â€r¯CV%>…›2·ºùJ[/=Òã*ºlcʸJ<É ¸g6 ˆ["1KÍ;«¤}Tݲ9»õÑe’ï‘÷B…ùµgÆðìÊmËHœ^Ñ‹ù²3WúÒŒŒÙ( Ãäµ8ŠÛä?$óëðÕ ?qˆ]ÛÚƒü䨘›RÛû’<Ê©M¨\Ö9æ•YÌ,ƒ ü–á™¶MŠ,i)lemý)(Ä=GW[Ë2BEò±¾ûMã`ÏŒú¬†1ðP宠Ћlðň¾ÀMZ€yk0Ròø! Ãΰ¦ovf}¿ºw&L»_)ñ#»86/ÊkQŒÍÑ[yÌ1ÌSÄuuï,¨FE1iwm¢\’«Á»$ÄþcÑ}¥ícã+»A†WÜKݺښ–M²ÿ“üG®â`p^Ó 0XÄ,LpÜEGw/:ƒ/*ô½ 0,8QF†•ÝR [†uýs8g°ǯBÎ5ü6¡bn™¤z¨ïQ'w ñݬÄÿMJþ§x{¨¾FÏ?GÈ4”Çî ½P_4éë ‰¾t†Ý`A-G#Ȱ· ‹š†Vu›‡rq²à†á`8~`í—Ó˜VÛݼ&„H¶Œ,©ë›¾m«÷”&ïš’RÓk[ÕêäÆUt…B .Ë£—ÃT¤Æ%úRÚ”äsºw\´ôDŒƒ0è.ÜôòEð…©ì §¾Œƒa-G£µ"Í"Ã%í£Îñbf¡®)ÍÄ÷m¢ú¦_y¤Cð3§¸À¼æ°¢6Èg7Á 3xα]gK8Á°ºOve÷„‚[*÷F~ᖑűåj>Yðq{9þ¶Éü9s®ï—&ùýÔ¿R”>×s»‰¤»‚H/¿_ˆõe0n0¬ òpÕŽ-ëpK©¾oÉíî1|Ï&²qpZã›õ¨¹XÁ-%¼¨Íd;¨70†ÛæÆA‚Ut)ƒ˜XmÂfafáE-Ã3ÂfáPõ×¾Kª /n“zŸˆØÚËÎoÔ†¥þ9{à³6)ùc“Ìíßh ±ô‰â¡»|D/*‚/:}/ê Üd0Ï æ—.ažGaŽöά-h‘tއf“%6%¾gY?0¥ÁpCNÎËo¼2“ªzLB áÛÉŽvÇ*res÷©SÜ]Π=°‹ù”^—ZÛáóúF•¶ß¢»3<’Ó•LJþ@—¨{{Í×dAK$`ÊWf$¾–ú9Vùù~vãô ‚¾W̽ÁPË£0R ;Æ•E·É¹$B¹×!Ë_0'ëä¦Õö)}LEh)ˆ{ãÙ7½xÏ6 Væ)Mâ]Bdi»gf=Twx×&2¾¢+ ·é&R‹OÝ2ôk•ù“y·ÒŽ×—@Ûk.Y4{JexBòÇ*¹2ºï Aw1M/_õ=XÇ7˜£0· kødf7¨{eÀ²ëð%‰Á <"hÚ~Ù~9¡…-“ĵ´Ú^ðÿŒšGzap¾†Oh¬°jYRÑ5.霈à2„Øì•ÕV×wË*€UÜÓ Z‡ur¡'%áœYÒîœX‰Ø{«¨ëÔ#ý+EÙyÅ_Žg>Ÿž~þüùôèðdkm+#hNæËà,‚ÄwmÒœŒ¥ÈËßôb+ør©ï9À‚b0Î0 K¿K(ëÓçb¨·;¼c¡áéšRíŸÓXÝ=Ñ62·ºµÚÖ.‰ÜöH{‡ûGÇ'§¤Ã#ðÿŒÚ.éܘòS›»û”;!,mT÷L–vŒàå“Õà[þÆ+óÅÛò¤˜2ðŠ ›ˆ‚Ðåã0ÑË[ÀÐtrÛGçîÙDAÕM«í—[ÞiR€Ø[g©®?(õ/ ±K/ºŸiŽSÒ>©¯iþÕ©åh`ðý˜ˆ¼|O/?êëÃD_€¯f؇/†e¡Æ`D+Òœ0,d\Ó;y6 ‚õ¥å?$8[Þa€°´¾½¿½w°G"+ ˜=>9ù Ýqzz îóðø„tx î ks—´¼¹Ká9®¼Ë5¥FÇ?ç™S<$6Y\ßQóÊDàºá®uxgÊ:Ç ,[FÇ•wª{g!öv½}£1$õ3Å×§Ó½‹‘ãブù—Rsp†â=dÝå„Þ袗¿‚/ô½0ìQØKåh~‹ÂŒf q.yñ ºûÖ‘/‚Ÿ9ľO¬è7@TOÎê<9ÀƒGÑ<“}rzžYÞqìœP)ïšç:…6ð¬FçVÙÅ ðXÏãBΖà€ð>ß%’‡@]z þæüFc˜ pôûÓý:…“ãƒÁÖY©¨ýÁ2ºÎð£Ë¡»|O¯@túêÑ'òÀ‚b0Ê£0*Ž)ígägޱl-¤%ç’œßÜ2<»±³O:$gÜSÞ¡{U\þ . ɇG»û‡‹ëÛm#³”k%œÐðû¤ªüæá;Vl!@ž¦•Ý8` é(ñð¢6ð)·@ìÊ&ØùúÕŸ¼™à>{¶TÁ>¯øÂ]§¾,Œ̾Á|ɰc\9eO$V¦?µqN¨h lîvÉQ÷3ÖrD>9=+_í‘'Ö2ã*^¼åY±:§qÐ#½N À4|²ÛGçd]’!¬iÇ•wæ5³·Œ†]ô-‹ŽWÉ`àÏŸ7Væ•ÿCé ÎU¸ƒ»üD/jÎØ+;³¡/c€ñaY…¯`X?0·°uXÍ+ƒùxéWîià<»¼¹ƒQw™t'ƒ×C)YŒë¬"K"R ¦6p`”/lûìˈ·ñ• ýÓäeŸ!ºO 焈âöw‰U¬ÿˆQp~|E—ªg‹âÚ¨ëHè}ŸCz/¿{}²½Áä7¼æcB8_Aü‚B†òÚN¯µl¥tÞ#殀ÐËûà‹}™Œƒñ( /ÃR ÒvŽëä0:)˜†ÔõMmï@; ­Åjr8ÞÚ%µÏzeÖ+¸¦ˆšÁë"xˆÙåÍ'±HÿØ>Ö/»1¦¬ÂûÔñÏekô‡äêéÅ ðÞ^Úµ—aïl¢ò“.éß 4LDü)_1Ö0ú÷—iHÊÿ9Y_fòkÝJöþ°ü€…Œ55-3ïMHþ8)ùÃYûqTò5²×>½Vy¤÷ iwyÙ×Ë;za ¾¼rÅ&À¸Á¼ŠÂ¼aø¢Ä7 ƒ€¯@ÙËÝÃÆ!ùí£s{‡¨íß…;ƒ´?HX -lUù˜&Ä.IU]ãäIAð,ë’”^Ûg] á}ÚÅ”¥T÷°2ZÜ"âSj-ai£k|¼ &Ëc’känA‡$¦,­û®[ú7êB;1§$†§øÐ,bàûZaZòû™³¾aÚ¾Bøž‚=„îr:³“ô PðÕcÕÄ«†Ü`]4Œ²(Œ†SkzÁ™ñ¾u$µ.­é›Õ24³p$xòÒV 0´*¹¥B+qRUO@nyGøVǫ̃°4·Ô€%¯Î,n]Ö±±³ÞRŸ,ÃYÔ÷¡¾{ƒì_ÔÙDa/¥îz¯—Ê‹LK|Yñj^å÷£…©Ï >¬äµ±Î~6𥌤Îûb9‘Ëô^h2¿+i;Âë./#/zñà ƒ¾d€ÿÒñâ ƒQ…a«H#Ä0eEh §xJE:»a`k—ô?èÕ¨A2î›sO¯}æ `½“DýÀ<:€EÍÃ-#ŠÐÞmXQ[DqóJ2YßÒŽ]²¾Ýãó>lÄ_E]ÇVÙ?iBêÿ„êõJ9ZåÅÍ^„‹F–f/¼[9+ùõg/Ó;'óÓÊû7ûÍ%»iDý»ç;~Ÿ¯p .wù‘^T_ÔtúÒãQ ;Ä”eÔõkxez¥×-®oãвr¬oï´ ëä€0w“Óõ«Ÿ;ÅO/n‚¾8ø‰CLlY‡wV=AÁ›ã’T9³üeœTpAËY½C€™´EÃûûm•§G‡ŸOO@;œXù¨MÕ—~“üލwûdwû|íŽVê·z¤=+D#y‘¡—§5gô•‘Ñ÷+À¸ÁˆÂ¼`XÙ-¥¶or~u‹txŒËÊîÑ?½ø!¥ú±}Œ ëËýŸw F—•vŒÞ·F`—$p™eËFðÕ/DåSjruÏ;ò*Ð ô5 !ë»ôEßIâšaP[‹A²0µ-ÛÈÌ«üÎÊ-Aü]ý¨MÍÍGÄiê·Æ%ŠSzzöÈ‹ÓËŸegšæý`( Fɰ,œaÚ ÃÀ»–á¹MK;8¥ÜkÛ{±eä®PaÓЛ&¬ê’Û4Ût›ÜÌî2ÅlóùÚ3½q ó>‚MΛŽNDq›n@#}íbÊÆV©ïÐú9¹tÏÆbŠ:Ž´AÞæ_þ ²2ˆ¿§û»»UYz‚U´íasÛô¢8ø¢Kß‹óÆ`XVêàwƒaŸ®îeß'Vv“pA!9öŽ [‡U=ÓÅ-Âo^ˆÁ ÆçW ‚òDÌB!D‘n3³Œ(C{·Î qr®Ét_–ovçØí5ŠUd1»Ë@*è8µÈü>€g%¿[xsm#ÌaÍß|^ñWÚoMHþ˜¦øPÈ(mwqz‘ ¾úH•¹Ð—À|n0Î0 MØ$Ø88odvWòcïਠeXÕ#ý–%3†•>¦Nן9ÆÁ­/hì£ýs£K; ½[ÿܦԚÞÇö1—û}Ü’ëú¦hß–êž åO©,DE™†„|#H~ß-û‡¾¦)Ö"/¯GZ±G/rúþT§ï+éÌ’Á˜éFuF!â¦!>™õÄ5|¼œ “Žò[†Ã·-Ãév»¦T—´>$wð܇¤â¶›¨ïSÜ<,º´ýlôÅo=qˆÉi8<úºrËÉé©oVÃ-‹pÖzÌT¼7)ùbîÎHüߤäýÒ¿T¨>rÔ05°æÚ]~ ÝÁ½ú27{Q˜ë¾apß:"­¦w{ï7!†›‡ÎÓðÅ`J9êf»©yetO,HCÚ,ù.!¼¨õ}Rå…Jòˈˆ¢6Ê”_ê1±°f”ÏÙbËî¯_Rwÿ…=õJ|×)ó{5ͦv1¥m#sqsôòyÙ™%€yf0Ÿ•£1ÂðM£ §¸¬ú~\_äŽ)ítN5 £ÌY2 [QóÎÿ·¾À~ûØ²Š®qÈîóÌE¿œäêˈ"Z,…MBß%TN/®_x@ –~—ÀÀ¯µíÚà‡EmÓßWÊÝÐyp}î—ß2ä™Q‡zwÑA/Ÿ_èô½`4u DæÃ@_ùI5½“GÇ'¸ˆ<9f–7ÝRªŸ:Ä¥^~Jë™Xxæ‹@ü}âVØ”×í^ôáEñåê^™_÷601 ʯë ?>9qO«1 åxÇ¡ ø«Ð3ßµËü¡¨ãˆ2 ÖôÉì$>¶aÇ]œ^,_HÊÎ>Lp¼`þ7eQ~†/ê«ð!©ºg×—çG×ø‚QP^pAKf}ÿ›(H÷Å£ßd]ÈÀFÁùÐÞ­kruBE—ÄÛxÊ?oK¿K,ë»ü’ Kz¹Üì÷g¥®Û-ýÛ œ÷KÿÛNM‹bí=›È ¼æŒº>Œ¹Ë¯ôb°ìÌ6À2íQe ß4&ë[…닚cek¿atÑ/§ñ¾5ìß4ÖðÎ>¶‹†ðnAØ Éo‰/ï"ïuö•{V‘±e»¤Ã˯7·iØÌåN±ÊÏÇiÖž„¶{ŽR~NÝ…SÁ5¹ojÑ((eîÂN/êjΘ-;m:,Ìw]Â…é1|Ó(¬o7®/ŠŽÑÅ­ÄÖ‰ö±y»èÒ‡¶Ñ7Càø®U¤KRU^ó´wûÔ>6ª¤Ý'«Úõû6¾bêR×/yüóÉ©NãU㟯^mê…®KÜuÂUû(p4ðêû ¹›õ>Qòî-óp—ĪšÞI4¹·» ¾ØÓ—=€Ñd0…¹eø†Q€„SlIû®/ªŽ’ùÚ±EÒÑ1%ʾO⦔y{áŸVÛçž^ íݾü”ò®ClÙYÈyã™Ñ00M÷ÅίlYFC²µŸ–¦E£ì_Ð<#ñ]§ôÞhZS}•pЬï*Ñá.N/:—¸bU_¶†È`„VêàQÆÃí"“ªº¶öð­PtœœžÆ4O®ìŸ|Y‚˜°´aRpÏ:ò¦1ô+¹¥4 묄 •‚¤åÇ–wêøå€ÿæ›Q×wxD!ñ¦A¯ .÷õ£5¸NîT²f$þ¯OúgÕ7TeÁ•yXáðÌò-ó0”ºË÷ôb øú°Hï9ÀÚ^˜1X—O FœáÛæ¡Ñ%íøÆ‚h;ÖvI‘ cßÎÛ#F·´*le9pbt6,r×߯WÄ”vH¼3 óL¯c²–xjMïsÇX¨¦Ô¢³UN*ý1+ù=—úöKýÛý• mÌ}jSÒ>ÛÄ;wÑG/Ÿ_DËΗfß`ž Ë£0× ‹™†¸§VÏ®lâà¡íè ¬÷ÏíÐY»¾êG†¸y8TL>´ÊkJ®êè¿(dœßœVÓ R»A`n×ø<ørê•Q'b!À i~Lèˆ éz%<$õó´Ä÷œUž{¤½ ¯q°–Ofÿôâ#Û(œ^<øB¢/ À¸ÁpŒ.†…Œ‚,  K¸vh;NO?çôÌtά0è•',mØE—Ø !SÒ9!¿yÈ:²˜ã±ÇtÛS‡˜øŠÎüfmÓkŸÁ±ºµgSʽ¸–Âø˜V‚µ¬¥ÿÛ7j%ò"]Ò¿ Ký“u‰Á›dÿgûFûB‘ùMdZmoju_º‹5zùDßoæˆal•£ù¯"ÍÃ7 ]“j{'qíPx쎂k†‰›{ç[ÐÒ9öH‡~9 9.ѺiüÚ#­o’(Ižª eUù˜šPÑå–Rý)µ†ùF–C3Kä €¹÷BËorI®·£üóµ–çkåR9á6™?@®ú÷¸äOæ,wÁweÿçùJù¡î§Ë«´*º&÷L,(»%ãô¢¼æŒ!}éŒaƒù+ ÃÀðcÛ¨Ôšž=zÓ1ñƒçÇq3¹mrsÿêßNNã€SÈ„ó1÷,Â)+PBª/hºþ9‘ä9Hõö;º|ÔôN¾rOƒfOûó&b:HXRóÊoÎ……2^è¼×S7ux££ô,Véiƒìß²Ö ûø§÷+E]uq}oºÞ± /j-lâ±»‚C/¿_Z€=Ð`dXÜ,Ô;³Ž¸Žos„Þ HucKû‡Ç¬Ü¸¾JÍ3]˜SƒA†N®îñÏi„`§¸òÌúþüæ¡«®$ÀÍ$èåïë\4 zÛÈìsÇ8ÖÖ¨bi$3xJò.‰Àuý€þˆ¼|I/õ¥Œqƒá¾0Œ4Ã7MCòû§qçÐyœÆ6OL,oS' ]y–6Ô<3DÙÄtÓ8HÉ-@¥ê™­¾BÆÁ¾Ù ãó«“ĵ+Ÿbe×7Ë)sÜh4ý”Z“\ÕóÀ& Âeªn™‡ùfÕWvóAä…Ÿ^”_té ܤ Áx†×`.–z—ß™uøØ+”û‡Çõ£Ó«;' iŽõ}»˜Ò/ËP\j7Œƒ•?¦vO,߬ÈVõHoèŸfëy–wŽ)¹B³´²qPÓà´MT1TÀl£ªº'ì£KQè.—ôRZ|Eçìʦ†Wú+ªÐ~xð…¼ìÌÀØ/Gs…±U‘ÖöÍìÃyCù±wxÓ4>¾ÄÆX¬Ík:iš‘y—x¡J,ï’Ô=¾ ò1:z¿L×qŠ+[Þd¯³£ЍçÍâŽNqƒÓKr.‰PÅ_ëÈbzñ7€·îBB/¥¥Õöìì€|Û<ôb:ø²¨/»ók9šß*Ò·ÌBC šñø‹þc˜¸™Ô:µºsù=µŽ<±¡b)jjQÜ=>Õ´ ¢JÚØ2¶ÿ.¡â¬TÎ-™oãË󛇞9Ä@1÷—ÌyËÐŒ]t Â.çî2ÞœÓØÎå£Ï죤ãÁWJz9mc0 CÆ0C‰µ}ðø‹£r˜X;º¸ËþX, ï:8 +l½mFä¾Md|Egxa+äK*¾ü”ZÝÃÉ`ûÄŠ®ÇvÑÜ?Ôš^æîZ†sW"&Á^uí£³âf!ÊÁÑqE׸Üûİ–¨’6Èãïm‹°°‚ŽŸ^ëð¬¦wæM.VÏðH«‰+ïd³”M'×Þ0 xáÓ=¾`K ÐM/'Ûú«º§LžW,Ê;GŸÙGa•^Ì_оÜÌ/åhD+Ò0ŽÏ’tŠÉkÀmÃ@ýùè$±u²žÃ Ø:vö’«º[†fŒƒó XÚ9>¯i‹Áb'ñåOí9?UÜ6ü>±òö1úêTBÆAþÙõåcäøkÀW‘÷Â+ã Ü™óåi§—ÖeßÅ XÍ™×úÒpÉ=ÀÈŒGaÆí†¿]Ta _ùõgðÒö>u|r:·¾S?4{Ï*r€5¹ñ7¿ºåš\u‡£!T÷­#z&´|²ŸœLÕ¥‰¿ò.‰Ã3KšÞ¨v—;z)Í+½få|ÎéðèGê ´ÒËŸÁ—`( öäkƒ±Áð}«°˜Ò6~pT ˶ö‘+G::®^©è{Åã Í$$‚£XFcYEqÐ ½´}TÊ9Ž]q/”—…Œ‚’«ºË:GùÑÝ‹¸&Uumï}y`Q(b(ô¢N_*ÀðŒ3Œ,ÚÞéí#³¸mè?HÖŸÁ±±w×<ÑEX Ìm†bÞ-m³*a} B&GÇØ0˜Í]Úšß|¶!ç«d€ø«êž6<³¬á•Ž:w!¥—Ò*»Æ¾®¼Æê8,Dé…|° õ%£I7zƒ‘dXÈ(àSjÕÖ ç ýÇÔÊNRëäÒõç“ÓÓ‰åíÚ‘½ƒ#ÂÒÆthþ\ÕeÈÁ®ÉUOícŒÉº¨©˜YHãÀ´Yh¾¨i07³†ÄLCÊ;ÇâË;ùÛ]J»gÖ?E¤}Û [†ÛFÂJ/|éê{`>6+Q˜s†%£³úqÛðúóå´]9B,ì'wÓîå7‰C·c.Ò#½Âg;¿º Ôñ˺cveœUrMjUtMâfÊÐ ƒ߬ѹÙwñØw÷ê®\mŸŒ)âÚ·Ñg^8Dó)½¨Ö÷2ÀxÆ*æÁycs+¸m˜¨?ƒøÛ‡Týysÿ¼Üôò—W6w- ¡øŽEx(sŒ‹>îŸ÷ͪ ?¶‹:]EàÉ•©5=Ïc¸ñòŽEXmï$x8» ?½”æ’XN\Û¦}ÃV·è „Fš^TלaÒ÷ `-A2Ci61 ôάÝ?8ÂyCÿ1¹B^áú3u·% ~óÐÌCÛ(H~j\Õ Ç3ß%öN.$Vt½K(×óÏ~ù)EÂ)ö¡M„0Åã3óò›?¦TßY™ 8cˆg–ï[…ó·»Ô–PÑy¹£JÉ5]ô"PsÖå1½4óÁXˆÂp0,í NF¸mX©?×-Á½þå88:©^(êÿfšÐêÖÞ»„ H~î“VÓï²ýþ)bMïdf}_\Y‡Of{j ¥M/®gÔõz¥×R¿Bm’*­"ŠL‚óÔ<ÓÁ“¼ ž-=>ŸÙG÷Mí£K0è.'K7‹š5 LŸ\,½èûg‘¤äz±|/LŸax ÆzFÃg›çŽÏãõgLÔŸAü[Ú‚iýç ÇÖþatã8ÁßÔx› 8 Áß>$•uŒ¢ñ}><š[Ù›_i"¤×özgÔ™…(~H¼ qhAsãà´˜i0BèòÈ]j{ù1i”^GÕû„r1“` îàËŽ¾—†Ë`Á‰Â<`XƼ€-^ÆÄ1¶´ÙI@¬þ<~V&ÑÌ99Á»ï+Øž8{©æ Ï,aâŸXX× îi5^¢gâÊ»$N,¬êøfaÄ]v+ú˜R¹¸¾}ùÍ Êm¼cнxð¥øF}9šÿ¢0— ¿pˆÎ¬ëÃmÃÄQÜ?W;¶ˆPýùø¤âRý™:Щq`ú–y(7úÞ4 |—P¾©™o ·Ïøç4¼vOÍkȪïw©3ó›öéí“N ­Â9 —ÿ‚/’ú~˜—£% c˜a-¯ôN|÷_,[û‡‰­“#‹ÈÕŸ£ǦW鯒±°¶e”Ë À÷¬ÂCò›I‡ÇØë8<ªë›ÜÜ%)~H„]ÈÜõ‡n«4r“qŽ$,Ò}CÈSm"0H/:‚/§ú~Aƒù4 óˆáþÎq¥ëˆ,)Œ\ó¹=3ËÛHDFÊøgðì÷ó›…M‚8^¿Bî}B\YÇ…I¥ØbØ;³î€‡¯Ý¥¶÷ñå «[tߊÖá™çöQ|H/o‚¯ë~˜ŽÁZ|d0Ÿ2|Ï"4ª¸· ýH½ù½³mS+{ˆDƃã“ÒÁùÚ±EF78==[Qø6²Õ´}3+»*»Æ1\“Ø%Å–u<äÆ`}´»K™Y$fTм°åSjµ¶oV÷ø<¦;à"…°´®å“?ºÈE^Ú&éÓ2D¸¼þí¡àϵ»¼¦kú2Ùr4¿3 ]ß0­ÄwÌC špÞÐÌoì¥wLÖvà/?“9YÙ!…Ö¬í^}e¶°¶eQÄI°OfRe—¾ŽÜû„¢Öa¬ÿ‚NOO›‡g»òa‡Û«ü2§È7³nùª-#©£É]èS/zè½`ÞGatU¤QǰŒsl¾%Žº±ÅÊaâÆÛŸœ¶O¯&µN²X}A–€m£Šsž9Dßµ ‹ä‹a€‡GÇN±¥C+døÄ.JÂ)†ÚžÙG‰›óÈݯÓy¥œ®Ž¿€!£W R¯$ê€ÝÑd0ú£0ŠÖöÉè›\ÀyCù±wxœÑIèŸß@fû£ƒã“ä¶©žÙu–n|t\Ñ9Æ®¾·ÍC=Ók’«º…Œƒnº&UòA?ÁýSD¶B0@WÒ)Ö$8Ï#­&¡¢3¿y°¸m˜ÚÀÅqJuwH~“CL‰ª{ê]V6½‡Î]J2ôÉk\Ýܽòå³°|¹n€Ù7˜/£0’i(¶‰(\ÝÚÅ…Cù1²¸•Ó=CÜÜGD‘Ïsë»!µ£»Ç,ªÓ=>Ïq0åŸÆAy£|±&¸yWÆ ½¢&ÁÚ>™¹¥í#Ó‹Lþ I‡GÓ‹ëMƒÓcp¥¢ìš$d€½”¦á™Ú7µÀÊÀ{vzaÖ—à«þ ÂEa–$Æî©UG''¸p(?Šæ'–vY¬ûøä´ft1·g†õv>³f `-ŸÌ¤ªn}ÿlÊ?\C|ð›PõMÉS’Ó+l¤æ™UÒÖ1:ÇÖü«£ãâÚv]ß$ÈÄšÞéb¦A¹ËpñÈG6áÙõ},'Xôêò^/é¥ 0êËѨ‹ÂÆãôÂ¥/#€Ñf0Î0†5¼ÒºÆð=PÞ§HžÛ9ƒÐôßã“Ó¾يaöÆå-mì¸$U°°ü‡„¸²öO©Õ´_”sI(á—*ôðÌò…éC¢&AvQÅí#3‡ÇPþONNAB-j—/¾nFĽ}í¢Šú¦ˆ‡ì|ê.ì3½|ÉíÌMFãóÔ`6Ê%,­ãÈ¡ù˜\ÙÎê" 3ý÷óÙöGUC‹ln6 "OVëëúge5ôÿÒ~QÄ4Ø+£v{Ö„ÙÙ?tŠ¥ê+f®6àevpx<6·’PÞ©æ‘*dÀ±»Üè{pt,÷>©Ô‹߯h2gÕ ;DsÓ…eC •ÃÄÍ}$~M ºõÌ­Ç5O°»×áÖ)¾¼ƒE}o8Æ–´ Þ·¿ð--ß̾(Éì…þ¢¯GZ5Õõ­]RóÁ7«NéCâ9ÃìîOêûØ&Ü-¹bpzñÍŠ aiCÊ)æ%5ÐJ/¼Á—™¾¬Ìÿc‘a!#p^À…Có±¾wÚ>Ý?¿q„Èî¿ÀÝÄÖɶi¶ƒ|iµ=, Üõɬ‹-k¿ü­»–aa…-ûˆ ö†»8¹ª‹RyesHõmŸœœ.mìTw»&UH:F ú³N/¸±ºgjju×ìòÆ1û3#¦_8Da‘^Œ_€5Ý1h0¯£0¯¾gQÔŒ#‡æ£{v­ oŽÝ‚0gžYÞ¨ê ÌiPý”,jxåhgMïô°‚æ¶‘™í=ÇúUtŽ>¶ ç=½|)í_fÉ`< sc0Ä ?wˆL¯íÁ‘CíqptœÓ=òè>"»ÿžœžÖŽ.æõÌræM]ß$‹;æä4¼ü˜B÷»w,‚óš8f%Çéééô⺶OÆð̯žHÃ+›»£³àÏÜ#µÊ80GÅ5ñ™]$ðXÌ$ð…}Ô«I¦Á¹Þ5Ùõ}à¢g}g›ynI•÷,C›^/„éýß7³Ê0ÿGaL0¬ð>ßÍÇÄòvf'aj¡áW€ù šaðpœýxïä+Ë? 9Ç—å4ö‹™†0ºª{jCÿæ«ÐÇ'-C4<Òáqmkˆ°Ø6\×;Ù>2 ®–Ö·¡` ¿e„ zÑ]sfOßK#g0ü ë ¶" Ãàú·q` wµGùЈ¤[ˆ ¿Ä/o…Öp¼Ö4‹?³Éo +har1Ó`·äÊùÕ->(D ÎÇUÇ'㆟Ӌ>}é …Á…düÁ –pçÐy,o“2:§‡ˆ›Çˆ ¿:9=ÍìšÞs|,üÚ=5©²Ë<¬€ùÍ^8ÆdÖõ `˜>V6vdcqz¦—1ÀXí † ²§ˆkø¹GÛôJéàüòö>2·¶{àW5´ÁÅÜAÂâ‹°+6 ÎËo<›#Ëìf7 ôü³;ñUb0r´Ì<·ä[zQ¬/c€ñ(Œn†q€Q{ìçôÌtVIGHD@±ëF—Ò;¦¹¹“±ù¹÷ ÌY½mú)µ:³¾OØ8èJªo™…¸&U×ñÏú¤ÊÎû–¡HÐ+Á—}¯Ã£# ÃÆ°¶wúÀô"~î@á1DÜÌí™Alõ+ð(!µ##‹\õ¹N,¬¾ü˜ÌÜTÙwñ±¥ížé5,î•ûÐ&"¼°em{ÿH üpˆ.1 ÀéE2ø² 0|åh^Ea¾`ø‰Mx\Yû!"+ ãëÇÑÉiAßlýøÒ.RëQL®lÕ s™¶YXÛ'3·q@×7ëÂ.LšÔÛØ´š¬ÏJâïcycç¥[â5=_þ¡ Á—€ñ(Œ>†oèûix¦6NãgT„µÝ¬.ÂØB›‚#»›P=JäòNÎfH©°q s|YiûÈ‹PÖ7¿A^¸ƒ¼U0> µGCÿ$;À8½žPÑ{ÖÜÀŸÎš;Ï¢°6Î0'‹:Dã=Á¨:jF«FˆëHíIr¶_å÷{Î.o˜ç2¡ô±-yÜÈâVÖõ¥4!£u¯´ÚÞ Ü`t^éÕ·Lƒø—^”_о´#g0º¢0–Óð]óפ Ü`”KÛû„¾ù df£~l)©u’û´M\Ûv>ß~€nù8¥ºË6²ˆ]€)éYÓ;7ŸØõmÕOÉׯ¨?£ž^Ô߿ء÷2ÀŸÐWŽÆLæÃ¬Bƒó6ð¡.(8Ú§WJæ‘YüùóÙfÃA5ÃÃD–¼X\ß~ŸPÎQ£ œâ¶a©·±L1XÅ-)§±Ÿ?ö+䛣¨eè‰m4î²O/†kÎ\_FCh0š£0ÿ0|MÏ÷™]dTQ n0oÍýÃìî™öéÕƒ#„rÞØÒVxý($Çà{–ažé5©5ÝBFœLé–}—RݽŽPQsØDùãô"|=.+y`t–£±T‘F˜aŠÁ~Yux-š‡ÇÀÂFQÿÜÌÚî)R˜Ú>U?ÍT´Õ­]¿¬zFvʽ‹+ëpO­æX_ªÁÏ¢¼3jñ*޾ɹwq׬6cª»Þà{%À¼.Gó6 óªcX‡ýkÏsƒïYàýÁ<;HGÇù½³Í“ËÈì}ôùlõ+ŸŠÁ-4kMoí‘*:Á©ã›YÜ:¬æ‘Æ%ÀÔшyc0 ÊÑ8Ãì0,f¨í^Ñ9Š¯ÑØqtrZ:8_?¾´ƒÔâG' þÖv ºCÒáQIÛ],Ÿ;Dç5æ6@¥/µýÄ6Ò2¬ q`<:þ)BøpO­¼eˆqzÑW F}YXà£0¦2ô“yUܲ¼±ƒŸh8¦WwòzfG—¶Z{ãs×ÌZlóø!t%ÜÓÓÓö‘YºRª{¦å5 èúerh­³&j$ý6Ö#µzxf ¯H#vôNÌ+}ˆg#þ &½ÚðÒKA“E€‘6˜F@bð§õÀ2ä]\)¾e!ñ·bh¡|haÁ 6Ñã½sëÐrß=1™Oã@§ØÒÚÞ‰ûVaìâÊz»mòÒ-)(·q|~õègÞcÿðÈ5©\œÅø+(ô"|©b²0Ò#³x=8 ó ‹›ª{¤4ì’ñóLÇìúnnÏÌÀÂbkOÖvª‡÷ í5:»,ãwÆÇ6~YuQÅ­7ôý¡â–n÷Ï"0œ×0±°zŒ3 ÛQÓ3.ësEüÕá)½:<¥—«àËž¾Œ´Á¼ŽÂØfø¦¯„C¤wz58©ñß©dk—Ô80ÅÛçP?¶T9L\ßE.þfw@æ†Üûñùפ .*»&¥Tu™çA-®/ÝvCßï®EˆKByûÈ,qmëï†úX\Û2 È2ðÃéEr¨3]z9åh40¬ƒ†Á¥îm³ …sú6w÷ùêl²¾]ÏÃß·öAüí›_G,þîý«†–·¡ß_hvyÃ<$Ÿ–É›þ–aù5=¬Â¡"–•]ÒWÚ®íî]RÚ6²±³Ã ÕœÛpÏ"uÕfÌל9Ô÷ `OŒGa,1|ÃÀ÷¡u¨ctQ×øÜá1Ÿ ÞÞ#%Wu©y¤ò*7Œ/öÍ!¶öägòì#bZÇ4ã•@â$/Mƒè#ëˆ ÜÆÌºÞëßÔŸ}amm"Ê:F좊„ ýÅLŸØF¼ú˜TÑ9 žÞÒÆ>¶Ÿ›£¬}Dî]ìõ Åg§—Á÷[€yo0Æ£0F5ö—~”[âœP@îžYRú(û..¬ y}Ñ5»Y]„Ι5Ķ^ ,þLXÝ#ooî’@PùC"Ð×>ªnti›UxAnc¿ºG*õ+êž©í#3^é5Š´¼Ó¢‹Ã šR«»3j{¨íSJ•s|™¶O:¸‚KÅ­ÃÎðâÚ–]T¡¨q€ÓË’¾HÒ{ `< £a¶$–rŒJªè›[)ï± Ëc2Óà†>yéJ]ßôª®±ý ‘>==]ÛÞKªì<;ÿúݵ UpIøX^Ý=¾¸£Ä_â/¹øûùlöQß<\íÁ½‚ I…ðže¨gZMV}ßM?Äô^æ7€|ãìAŸÚE¶ ¦VwÉ8Ç}©¸²Õ€Ê¬Ãl#‹Kë§§§¨ïþá‘GZÕ]ó œ^ô_ÆÃm0¿Ea1 Îo'™ƒ£cnëû&-CóÄM™Œ‘~`jžß<4½p„iƒA~îN¸g+>´—tŠÑòNwK®Œ-mO­î¦4°Â ›ú§¸\} ùø;º´X3² ç¯idf™¼:ÿ™…òïâ+:‘¬?ƒßCLIFmÏëOÉàÿïZ„f7ô¥Tu)¸ÄÓF[Κ°q üûøâÖ!A›àô ÎkxdJÞt·î ½,ë Ü„Î`Daœaj»©ïëžR¹½÷eˆì!`x{0l’+nÀˆaaC¿‡g ·`–a`ðÞÁáðÌR`NÃËÉ´é`|Û<䎹)~H+hî›$ C”øÛAX=F0Q%·M6L,Á¸g–6,Bò(êødTw?·„ÉZº \!äÔß· 1ˆ(l©ê×ðJã^_J;Û"4$¿Ip–Ü"ë›ÛðØ:Œ}±O/BÛqL/¥Qþ)Ã…yϰ»¸òŽÚ?BÀðúö^Cߤ9`ؘìBíÃŒ®Í{rrº³°²¹;±° ÎÝ ÀygÔ€æ—U_ÞÞ'¡ùMçõçê̺ޜ֟9RÁ%¡¬cÄ*¼\3뤊ÎQß !ÃHô¥6óÐüÁèú†p¤/N/bú^ÂXb˜®Ä7ô|­ÂòÆæ–/ü5oìì† ü3… |Õ2ô»ob˜]Ò6„ÝIà ݂ˎýƒCà1¥| Uî!‚øÛMŽ¿'ÆßÂþ¹ÒÁy¸£¸ð*j|*º$dÕõÚEqi*[ím\itI«‚K¼wF-¸Z2ʽièÑûP¸„ þسë[±¡/äg'œÞ+õ½ 0/ Ɔ”á[&¾5tG8ƒSÏÒÆv^S¿š{²>C†oøÞ1 ÒöNKªìÀwt¸p4N,—-¬!¸ôÕ6é0°fxiknñÁÝwÏ?² 7 Émžyjù7üîRšˆq@F]{Zõ§”ª¦Ái‡˜bƒ!÷BK­éfÞ ||rÚ3±Ð56—Uß—XÑ[ÒfU^ØœRÕUÓ;±²‰?‡Åµí·±Å·MYÔ—ŸéEkðe° Ea1 ›Ä×t¼ŸÙF¤UwÑ-µ’§“†«ºÆL³ÅŒM^º¡ï+n ÷.Ö7³fba_ž÷óÙÆG”¥¯N[9LÌì$Žxÿ ‹ë. åA¹ Ùõ}<æ ©º§”´ —uŒ6L;Æ‹™AÂíåVÛ;q |½º{ü‘uØ]‹»æ!·LƒÄMÅL… ÉsŸÀÿß6 ~nù!¡|dfµQpå¤ã.là'Hô²|ÿBMðý ð5>þ%ómFšáëº>/ì#3jºuwž¥áí=RCߤq`¶¨Q£iÄ×ô|DŒüïšÛD4Líî¾G'§UÃÄ’y$7>îúT’·þE¦â½¶½WÖ1’ÓÐoYˆ˜¾ }L®Ÿ_™"®9Æ”\¥¯çMׇÉ–à/"4¿ ܆I™RØÐÿ™]d`NÚö8Ù?¿º‰äüWôÄߜ9DãoÛôjvaÿ¡qCà׺¾K*ë¿c‚˜¾ q‚ø <û˜Rù­¾>ܶoù81¹‚):>Ìþ°žÈÄÚ>é#³h‰Â}“ ”?áëLËκ˿ôB§ï730µåhœá«¢°®÷s»ˆÌ« >;ížì‘û§<Óª[‡1YZëúY ~lfUXÓ3.8’ŽŽË‡ªGˆ{ñ7¤vd`a±Ëƒ£Ò¾™7þù׌¿ õÏ,…4=Ÿ=HŽÐ\Ë™ü-ìÝÐ÷c`J»¡ï+é^ÛÃÛOæÌÒzPn½¤cÔM}_tD^Ñ‹‘š33€)G‚Ô`Œv #Ä0 ó0¸®‡•©'§§‡GsË›‘…Í2o£éü=SëÒg˜²²´Víèì2ß,"nævÏŒ,n!ù Ý³k -»NÎ^ØÜ‹¨vJª†ÇZ:dÚGͯÆ$¢¯éCÉíåVо¼Øƒ‚ÌÝ4ìG.QíVëÇ–ÀçÄ3½‚.X¦Í.ª¨š86·RÜ:üÆ=Zk/7ÿ,&Àà¢SÛ;ý»¥~þÉ5¡ö‘…Ís°¥á•¼Æ~ãÀì!7õ}¯é ‚»¼îî…Sß+Æ`ÆfØ®ëùX†æ Ï,±õ7zzzt|B\ÝJ¯éVý”ÄpzM'18 ú‰³ê{W¶v±¾þÊ© w¶ft±z”˜Ü65”ÁÀûæÉåCkûs{ñ-“„Õð¯î5 €Ußα٠܆âÖ¡³]âC`r—Ú’«º˜ì„ ÂëuâÙt÷┳É{·Í5©n›Y„}8ˆ¿¡u£[ûÈq#tV3: §_†ölØGA>™Òì"‹š¦ßÅ—ª~J.i&Oy‚Yß[¦LêÏà“™ÓÐϸL6ý¼®ïsÃÀ÷žE0øü¿/M,o¯èí[f²âúÎþÁèìróàTN}¯{J¥¾oÆS›p€î =DKÍ8½šHè ܼ`tEaT0ì‰i†ŸQE-ëÛœl_zv¶ZZßÎkPý˜$Ä|¾ÿy, œ”?Ä{¦Uµ0$1eåžÙµóBåIÓÄrdÃøïÞ\ýÁݳkeÞƒÛÖŸWw úæºÏ_)¸Øªíx` y§,à¶yp˜$lèï–TWÚ®ð>n€Áƒî1±.§œbK¸D—I,ŸòŸÀy»An¾ ÚÙmtÉí¹!8ªùjwƒ^D‚/E_6Æfæ†áªKfL¹9eF§‰kþYuÏí"À‰ãJ‰©ç£ÛffÁ99}s+àNP«1éè¸bx¡t`þBGìøòv\óDVòý@äÍïu+îúúVµL­ S‚—Dg/j‡F©Õ­ÝàÜF1òÌ©&,½/2ô1 ÈkìÈ©#ï˜ /ÀC„E&—}àjã¶Y„è~Ót k0º‹ŠÈËë‘VÈÒË6À˜ÂüÎ0§?¶ K(o_ÛÞãžÀö‘¯´j­)Wî,bLž©láWRÕ=¶±³Α§(ê2îŸßÈè$Œ,nÒ•²lp>¬~¤n (|ÈåS/yÿðpP=œ×3 vëÔ ˆÝ!µ£È„à݃£†ñ¥’¹ _ï›\Pt&žŠd××õN˜…ä}ÁWt}3Òkzôý2áÖ×>ªˆÉ„uðæ—wŒàîò)½(«9k^„’m€1˜ÇiTŽÏ‚+›‘£ð š;¤ƒÊÎѳ…àƒnèù^gGâkz>*® ÞéÕU]c³Ë ”ŸPDæ¾ë{…}s5£‹GŒß™ÙõÝä¶©°º‘ºÑÅõݶž-¸%¸=hàNJæ=ÊÒ:¦6ö¦×vÀ›g½¿I­“µc‹ð‡`âÖ>x¬ñ勳œI‡GÍâ¦\%TpAöÔ6"±¢£ypÚÀ?‹úõ Ü†È–çv‘°ê{]ÏwiüßrŒ)Bº8½ÈÑ«Åz9˜r4–+ÒXe˜}‰ŸØ„Gµ×¶ êÝÙ?¨èuŠ!KL·©çsù¹F÷âz[’ŽQïâK“«º† ‹‡Ç‡Çà@dð æôÌ\Yd><>™^ÝIïœö©LiŸjŸ^Ÿœ‚Fñ•¶Ÿ’¿Dߨ;XØ(îŸ «©7¿wvasïäìµeuêÇIg£ä–·IÕÃãËðή/¡gvL¿ox“\ˆfg„ðÅ¥*¤brújzÆÕ° ¥ý–˜q@JU—of-ï2yCß· y€ù"¬àÓ¢H¾2à_tÑå.:èE¬æ¬ÉŒÞË `Ʀ?O)¢°y~u¦ž·÷ú'ãJÛL‚²o›‰œ{ì{M—m¯ëû<²5ðÏ$ƒÓzËÐ4= y•÷Î`f½| nÓ3»–Ó=B0½΄µÝкQâæþå§™Ü6I6x‡yâß=8ª§7üŠÎÔdÙ`V¶+¸¦ç{Ë4èSJeçè¬wz øÿ 7PóHÍkì· Ë‡ÊZ:Ÿ =ǘâ­=Òãì&Gîò½ ¾Œ†Ö`Þ †3 £uùˆ%–yÄÚÖ.Ü-ŒÍ-µ d×›f?·‹¸C&9PÔÈŸR²f¨2Óó¯˜I€Šk¼Q@–GjUtqKiûpëÀ¼¹»¿½GÚ=ãØ||iìÙìúnbëdQÿÂË>Y³Aü!2z\ƒ#Ç&–·¡˜´¸µŸÐ:Áâò^C„EÀl惔üÂ>¤Þö‘û¨"á³ÏxöL«‰)i“vŠjá‹Kú¼_LšY¾¢ø ¾é]„Œ¸È¹‹•ÈËÇôj²DïÿÎÜüÿUw»d0¿DaAg‚!Óšž©£«g #0ü <0²ct6£¦'¦¸Õ1ºÈ80ë…}Ä=óËo›Þ2 7!óLi”è œ¾i@§ ƒÛi€äÛf I;E›‡ä¾-I©ê¢h¶Ü;8ª!úW $Z7¶ˆ¤Á„µØæ‰u¦u`Ê<¥Ú±E[!ùmì·N¯$0~E÷œ^4Ì6 ¸Æ ì¬ú)¹°e°ª{\Ó+.®¬BÓk{@>&¯âü[ ï›°É…Õ+ +›;àóÀ'èb(ò ½ŸèÒû߯Ãn0O£0Î0לL+;G×¶÷@däɤ ×·÷ºÇçºÆf«»ÇÊÚ) ¤[·¤r‹ÐÜËÍ.ªÐ?»Žz˼Æ~ðã ×=DïÜzf'axq³on=®y¼îŒ:†]œfwÚ¦WHGW¼½ËÛ¤ÄÖ‰àš‘î™5ðÜ@æ¬Ãüéèx|y+¬~¤d`ž­»˜_Ýô˪{`J;4úy£èÓà܆þÉ”ª.šÉE´/k{§Á¡ïu=Ÿ§¶á-CÓ¬”m‚rê¯a]4º‹&zÑWsþß·\žLß`ÁŒÂüÊ0W‹ùÛE¶Ì†iGîòÅqzV|Îîž©[¢LüXÞNh™Ìï›%níÀ; Ð 2÷ê‰ÕJ܈l ©i_šßØÇ„_ÝÉ nnïàx~c¯tpÞ½¬ß­¸/®™í-‡·÷H¹ }JâÁ§$Îú¾OlÃý²j»Ææ|3jȱ’7 |cJ[ÃòÉˉC­/x ïãÚ†L6] âüÜ.w—·½|B/ûÁ—À˜ŒÂXg}ø*‰Avixyc‡ŸÕŒ·{‡´q³ o6©u$ã­ýCÈkðà÷'–½ÊÉ+?“g±óãà!·wÆ«|0¦i¼ftqdq ` žçÎÁÑM:Zß;[Únž\Îì"„ÖŽ¤´MÅ7OôÎæöÌ´N­p¤§ׂà{Ï<8(§~s‡Õ¥¹÷_ØGb],º eµ>zy|™,Qg ‰Ãµ=3Kë».ßhñù”¼ìFN÷LÛô “E6š&–AИuϬ­ì€”äqP§ì>ÖéÁñÉéhly;»›V7Z20QO^ùyli ÜÿÔê—k‚RÖ¶¼Ð€²«;ß ïÚ;8ÞçõÎ|>[׺t`DaŽ×¼Ü#6N;ƽpˆ7 ¼®Oó#›°Ôê.´*!_HÖœº®çsÇ4HÛ+­¦{|Ÿ*zjU× =_T‹‹vwqz¹ ¾,,Q˜‡ ó‘Äòïã¢KZ&V·v÷y5J‹ãccï°r˜XÜ?å²;G=³ë)íSQc…}³½sëÄÍ}`óîÁÑ>y±Ì“£³(Oi¸¥ô¹‚ nn Bgûô*ˆÚáõ£U#D€"P?³‹°¾GÖ±z„˜ÑIXÛ=€ûJæôlöQTãøäÊ6åy‚'²8—›/Í-‡4©~JzdvË4ð†¾/íàdǘâìú^-V†_]%¢ß]óà×n‰é5ÝÛ{ìe÷ý ‡Èk¨Eíî¢^-LÒËÀHŒÌ‚Ã`œaH|ß2äSreçØÜÒY÷0&ôp’ûD; &²þS«;$Y– ¼Æ5Oä÷΂4Ù=»6HÜœXÙ¶­î€6·±;²´œn_Êëmžî‚,lP&8m“Žb›Æûæ×)ì$µM˜ÉÛ+Ái0éè\¤wNÓ–ÄÇ—·ÀkÏ–û½vI]ãs¡ùÚ>i/ì#X…‚X|Ï"8¾¬- »NÌ$€ãy·7õ}ï˜=µ0 ΖoîîsP!ˆ(lfy‰.?º‹½H.kµ¾,Œá(Œ3ŒˆÄßb,jäoàŸYÝ56·²±µGBs]¨3¸°rì÷ÂÆ@«vt± w6»‹ ® ¬<ëÖ±|$ìÂ*0ž6_ š&—³@ü¥™û þ?¡åÜ`Øâïò6)©ur˜¸y¡7wˆHî Ouï²…H—Ö·«ºÆ€»>5¥mÃnI¬Âî[„—#5"Ïáf²y%ø–°Ÿ¸Ià]³àÇÖaQú¾ eíãó+_áåË´ˆ‹ wùƒ^w´ÑËÀPGaôV¤ág˜ÓîaŒI¬èœÛ02»´²‰Æ@ €"æôÌÔÏ;BøXÙ&톉[j0Lµh³Û « ­“—«Íà+#‹[‰­“àŠae‡ùÛ²³w0¹°Z×;«VíÛØbd_¹%Ê9ÇRš¤CÔs»i§hÊ?_º&X†åù¤×$–w´ Mƒ—GÇʯëùàîâô¢A_vÆ£0b £7³±¨±¿ux~MÏøÌòÆæî>JòðéY×oqÿ|JÛÔ…ÑIˆ…ïò¡…âþ9ʾ¿`pRÛdnÏ qsïàâ>õ½ƒì®™¾ù FZð 9Ý3éÓcÄ!aøäô”•!k³ËSD Ë,@qa#?Ü]4¹+¸ôr0†£0Ÿ1Œ1‰•>ć€@<³D\Û¢]ý‘'ÇÞáqËäJHíHRëdÏìúá1ÒÇ@øŽo™˜\Ùf4§ ¸[68nÓ6½J^ò ¢0ztr2¸°î–ùKÞ?<î ¬Æ4ç÷ÎŽ,n³ÉÏà”óߨ›YÛExyí‹W;ûZÞi×ôðID8½¨ —S€‘‹Â8ØÄ,K¬MÄÆÙE-ƒãó+k[{<)M{zçÖAÂëžY¼¥vLcެBƒ'×C·µsÕÌ™!â&À2«‹0Dܱ˜Ë4 ]ØÜKh¬åÆ+;¤êblóxv7¡{vmncH¼{Àêü«Ó³W 24x‰­“)mS3ìŒtƒöÏ9¬ IÈÀeèbÁ]œ^Øônr 0¶£0JÆx f㇖¡^iÕµ=ã“ « š æx ÑÅ­Ôö©æÉeê¶IGuc‹™]FËÁC ›ÉmSs뻬ŒPè6Œ/EÔåöÌtά·ÈŸØ’àq@è‚‚WêY>PÔ?Çz¤Þ!uÍ®eu¢ÇÁuCãÄ2ÄÙ¥íýÕÒúÞxi|qy›®~£t`>±e2»{\F€ë^ ÊëŸdú7ŠÜõHwQO¯&rôRØ•sƒ¡ŽÂ|ǰ`b6$–vŒÍkl™™YZ‡[bÜ€ ù½³C ¤óðM™LYè ­öŽAønZa QÀpÏìzZÇt|Ëdqÿ<øqà7 Äâ-Ò!ø.hÞ:ðOÒÑ xEkä Q{@ñئñ%}™Ó Ô‚ ¶,oÝæ9Ë‚àždÃXBËDFç4e mofAßlJû<áÖéð<ÁÓ«&–.l“xÐû°¾½§í“ãØ+mÌå]þ£×;ô~¤å’°+W k`º"^†ù"³„ñß:ÞÚ^i¡ù­Ãä]{7vö —bYÉÀ|^ïì…57Hg]ž •¥€0EaŠaµ£‹ñÍ‹[Ž3š}sº áõ£¹Â¾¹ª"H– .nÒ®~5²¸ ÌnœX±5¡eX2tTãåÀÏ®p´ö$µ¢ ¶ ®Z@.¿ÐF·–¶öÁ¥íŒ/oƒg žÂ!˜tx–ß(lèÇ#q½Pö—È¡»ÈU›QD/ŒÁ—.À˜Âºg7NO×Ö·9±uz¶ŠdËäJzÇôôê“[ÀÍ] ,öœ ;™•Äæ¢ÏGgµßmÒ@wasXÛ>½’ß;Ó4î]1þ0î„ल Èô-S+ SÂ=xXÁµÙà=ä8— y½³à"±.ÿ±ù•Wn‰×9ùŒmtyy1B¯&OéÕø‚&]€!Â|]‘FU]Z s _ñM}_]ŸôмƪÎÑ‘ò²l-»z6Œ¨mš¬ï…µŸvî}Y¢9£s$¶Âêøò6 te›<æ$é „Ë¥­}êÜÆ.amgˆH®ý6Œ/öÏ¥¶O'%ѾùõNÂ* \€øU.nì @ðéÙÚ™qÍ㠴òÀËÉê& ž?2—Àݦ‰eðn7‘˜>*v‘…ì|Öætyå.½HÓ Sð¥6Fc¥"3Ìg3ôdbÅwq>é5ÍSŕͭݫ{1)SZ“Ú&6ÙMó»g+EOƒì0¦Tt/Œ9­lp’kSÚ§(ôÍ€‰‹[_z”ÁE@N7¡qbi÷ìêPÖAîr¢ÃxM“ËI—–¾»¼MÊî&€'?s6׉ñP{àm¬!n“àMÞkÛ{9õ¢Æþ0ˆë…â?þ¼°Ò‹tðe`tEalt #Ë0?–¦¯Àøº®Ï »H‡¨¢„²öŽÑÙ‰ùUF«]T@v¶œM:âfá`ÕØò6ˆ¶—[ÿü¾Ä­ý òºU'Œ’ˆÔK4ÝÏÀàôÎiƒA„¯$ ”=Ûøhlli‹îw¼%óàÒ¼®(…è¬.»ãÀÙj~[Ò*n âòÖ]œ^Îée`ÔEaħ*!É0.1{‹ùëùdøeÖ–·ôNÌO/®Ÿm‰x ¡¾ÜÀZ‹/o4h¹9¯wv|y{÷àûÀ¥CÙà|NÏ ó"A;a‘ø¢Ç7ôȱØ24/®´­¶w¢or¡ul!±yœçúc ûȵkºCŽ·ökF‰à*Dä¹õ=ÒÑ1„ÏÄYjHíÈòU3Ž(Q¸j„˜Ö1]1¼0¸°±´½¿ËÅ@pð£ó{õcKÚÒÁù… ðO°wÈ+uÌ®ï‚Ù0Ö5³¶©Á@ßâÖ¡g}ùP\ÜåAäå!½šè¥—`V ÆÆL]ZÀ$þÆca?9çX-ß,‡Äê†þ©!ÂâÂêÖ.éy}`}së™]ÂÚ.ÌÆ–¶@HÍïí ¬ÖvÎJÙ§\ÐS`~zçtLÓ8‹Ž‚l B9¸VHn›*ìŸkœXYÜvƒ<ü„•;÷|ÖY³»gÀ‹êž]ׄܞÙêÑÅ–©•³Ý‘gÀ{¢?`¸sfeHÒÿ¹¾,ë‹­7oÝÅéåj°ÕU³Á0º faM,2ŒK̹ÇbÆjîÉ®‰åiÕ]ÍÓgoî!…1ð,µc °Jºje+@ Vyÿà…žÙµ™õ]J9Xœ dî•ÒèâÐ7 z8¢al‰u?NÏ ‚æõ̤´M˂ڱEð@,y<+rUy‡DÛ–·I]ðÝþùº±%@/·uj…ú±+Û­Ó+Õ#Ħ³Å,7É£Óȵh qÓäòêΗuoð;-jznÇ\_,~ŒÊ],v÷r|ŒÙ(ü_ÞDa,1,Ài·LÔ=RÜÎ0n˜œ^œ[ÞÑøž5 ¦d`¾¨nu—ÕJ@8pRë$ˆ®‰›S+Û VA;Sù˜¶¯€¯ìÁm€»@¾ÒùкQÏòàhÙàxGìï¤ "/ˆ³à² yr0œÒ>•y¶ödqÿÜ…qàÃDð2Á¥CzÇtÅq˜¸¹ÃÚ’“ÝáÅMˆË‡¦œŽÄÞ%ë;ø‚¬/Ö¹E»Œ¼˜¢—ÀÈDaœa\bž¶Û¦).ñ¥±%­U]£ä\ĵµ­½#ˆÖ¡zQö\šZÝá 'uïðhÚ>½ `Kë˜Îê&€No4»³xAl%níS’.m—€OJ¨åàžÁ}‚— ž6Äàb…Ý;YßÞ+hxaOÑ—¯ÑeÁ]žE^LÑËÚóE€ÿ¤ 0Faþc—š&fì¯ò!Þ.² 4¯¡°y e\©ž_ÝÜ?8䦸 ô@B2Ð\àèàÂæÀÂFÛ¹KÛ&–À×Ï:mì›aõ£ÄÍ=Jª™8¹m’ã¨8»„Õø–‰Üž™‘ÅÍm«ã¿ˆk[àê©M–õE‰»Ø¬6£„^ $Li‚…q†á“˜0¾¡ç Îæz>énIå©Õ]µ=ãÝãsSÄÕ•ÍÝ–×Â7-œ/˜_åbÃnÖ½Šmož\þf$vÿ\f'aåb8òÇúîANÏ ëàyÖŽ.Ž/omí2aøøäd|~Å7£æŽY ¢‹rwqz¹£÷"À¼ŒÂ8Ã’X`0¦t¿rMá8 ».³¶§®w¢javycsgŸQ±úøä´sf5»{†°¶s‚øö·G'åC |Ó®{u¶ÅøbÙà< s0x—@į&/(6½º3²¸þDaÀ0ˆòKÛû¤KƒÂwI-CÓÖáùbFþ¸»Øq§÷Bsý`TFad;†!f˜'U™˜O$¦´ûÁZ^©ïãK# ›òûëû&ú'¿x|| $«‹Ð3·ŽÌâŽ$#ŸëF‰›û—¿è-˜Ëë™"Oüë¹Q¦7G—¶–¶Ï¼EãÙ8¯Òù‚¾ÙÙõ/“µŽŽÁÛX1´.œo›^™\ÙwKé^XÝC¯Ünêûº¹‹Ó‹})€Ô`”Fa¬2Ìë@ ©Ä|…ñ =Ÿ'Ö¡ÚÞid š²ë{kzÆ;Çæ›Fòº¦V¶÷‘/>/oïG7·L­0ºÁÖþaõÙžŒmS+ ›8£Ò»M:šXÞp&µN‚G)\OH<·¾»¾{ا¶õ½ƒ¹ÝÁ… ð|2»à¿K—¶‡¢ÌKn9ƒ]ÔOÞù¸“°Ú:2ë^}Ï<ˆÐÕF]Œ»ËwôÒLÇ`œa~aA‰cJ{dòêSÒ߬w‰©U•£mÄÁiò2 Û{$¸÷àªö‘—¶8dÊ*øîÀÂFv÷LAïlûôÊÜÆ‹S†˜G'§ žŽ,nÖ-‚{î‚À îè r-à|¥nl©yr™ÚÀ-KæAÀ-Z_Þf>O|\Ѥ5Ú%Õ(»& úò=º¨p§zzÝ.@I}ó-Ø—ǘ•vÏ,HåC¼‘æ§äЍ¢æœ†¾š³!]c³Ë‹k[ûä6 #dY Z\ó+sŽAÐy´er%§›\à­]$Ï®ï®ìX\<ñƒ£p'à§€»„Õªa"¸·âyjwiö‹Þ“W!oмÚ0¾Dm ‚7WvH¬¬ùµ´±SÝ=æ_оàë»+(ôj@Lïe€1…q†ùUb¾õø¦¾Ï3Ûp ËÐ\ÔÊø²¶Üƾšî±î±¹Q@òúöþ!‡+2‚YÜb´åD”ƒÄ `0©à¿à õãK]3kÀãÑÅ­‰erŠ]Ø$·¹³…®À·ýóë@Sà}íØ"ø©Â¾¹³u+—§Ww ß\ayc§¡Ò7³FÆ)ú†ž7váu=‘—gô~DŒ^F Vf›aTÕ¥1'1Ž1MÒ÷yn®éù…ä¸Ò6’AÔk& LAJ^ßÞce5qs?¡e²q|‰ã¡[g#¡6©”½©@VðÿÔý«Fˆà+ •œ–¢T•[ÏRìò6éðú!]dzû&}3jdߢ^è“.¹Ëcz±Usf`œaä<‰9Á˜Ÿ=¦üÂ.âµ[¢¡¦{Je`v]ZuWaóP¹klެòú6PùôÛý”²ºEýsP)xtrº±w¸ºs\]Ú¢´±å­Ùõ]ðEж¹î3fÖÝ{x4>¿RÞ1â^-û6憞Ž® ¸+`ô^ ðHã ÃÌ0š$fcÜcF«fšH8Djy¥UȪK­ê*h¨êk"ä·û—÷׎?cö8>9× ú§TvÚ†ç?¶½¦ë…jqy‰.×îb&òòˆ^ $èe` Ea~b˜çØò³ü „ÇçkYJ:D‚¬¬ô1Ù$4ß#µ2¶´5µª³¤uÀÜ56Û?Eœ"®-mloî xJÒ!aq½yp:½¦ûSr…êÇ$dÖ€K\þu—÷ôþíô²¬ïš¬Œ3ŒY†¡‘˜×ã³ÖþÖñzl*åEŽËþ™öQ… 1ûgÕ&Ut€Ð\Ñ1RÙ5Ú24Ý79?8½'àykéÅ2·÷HàÊ }˜PØ<QÐäSüÊ-AÌØuÜräîÿpwqzYÖ—-€á0» D–a¾•AŒ‘dÚ5®%ì#€Íª ü2Lƒ²?&•ƒÐ]—PÞ„Ϊë)k­¦g¼wb´¾É…ñù•ÅÿßÎý´ÈQEQÏ—š® nÜé7p#˜tODĨËÌdúO  ¢!ˆAAnuë7ÈBwêšéd˜Iª{êÏ»÷ž{ï³í†yÕïþú¼ªé'mòäï~?ÜñÏ¿ÿ5/i^ؼIón¿þþçwÿh¾|òí/Í7ƒYýÕ«ï}úÒ[Áq !îI™Ý è®1½+zL†ýb`‰‡`<Öã¼$?W_y÷^#t“×oñöÇ_7yçÞ7Ü´øòÇMî>üéóï?øá·ŽiÚí݇?7/üðþ£æÝÞXMi†«ì {.Ä…%®FÛõñ¹%ú*“qݺ¾Ý @o±âûÀ2 c·a‰e1.çqy’ë}¥ñWˆg=ªÓ§èÅÚWMÊm-8d Ð…v·Ú‚cãæe€3¶a5†Wv •Ø9ÆR*Óf;e¸•A׋»¤w½›4ß)m°ÐóYn.ÄøÛ`,HrB¤U–qß2àèÖâcd»aéõ¢wqÑÊ Àw^ød£»“8Æ0cšmý·c|j©ørwRy¥é/¾­›Vaýi2ìIb ±lް+[ûA×]Ò»ƒÞV€É°Õ¹tD‰e1Fô˜<;ñUW\tÍÝŨ¼è]ìÀ±à6†§Š'Ò& ÏȰkŒxÒi·Ë^ûD·Všø•ׄÞY1z¯X© ÝVd8µÄû&™ñÇmtGTÞ´ôVCéí°¯é| XÕc’Lq¡›Ö]…½öôvغ #2œYâ0SeZ‹&n­º‘G¸KzÇëÛ`2 Âp&‰Í<¦Ê´V]]wUÞ¸ô¸Í`2,ÀpB¬-± Æ–æÐꉫŽ.¢»yé°P&Ãb…Ø@â<ÓfçÊj‹kî¼Ãˆ ½ò·{[rs Àª W€ Sb4Œ=ÎŒ4ü…˜kfMwÃÑ»Iï&cöx"í›aç¯u§ž’ñÙ±†óèÒ]pz§—¸ °Ói÷ û—Xãh$38Öº@×ê©fÒÛNoA€É0r!Æ—xm71ɹu‹®kwÓÓ[`¡i2œJbk 3­Eׇ»š•žÞ­úž¢Y`¹*Œa£`Œá1aN-ºÞÝ%½—é}ð# ƒÓ2lTˆƒJŒç1mŽ£,ž¸]Ñ]wÙ줷½ iz/¼‰‚ÁnŽSˆ K ‡ñ{ŽgEÚ×E™ã}ªén4z[¡¼°Z–¼1ŒÎ°]!î,ñÊ­Ä=Æg;äzb~tË¡+ï.|å5¡wÚƒÞ6€5ž’á(ãbÔc&·ýÐMënXzŸ¼÷"À"ƒ1 r{ØZâdSerë ]'î’ÞAú>¸Ý`g'Ò^餼Ä>0&É´–èBUÞô^˜ SâþGŘ0ZPténGwñémXÑ`2ì@bbL›i­$ºhe×ê¨9#½í“a? ÃJ¼ê=†æñBJ#úªˆnw]Ñ;-Iï.€·2,b°èóYš §˜Óé,²]oî"Ò{<Ò¾]ëVai†‡0ŒVˆÁ$Ç8Çš¢s­ ĵpweç.éíp¬é<…_âAÓcW\|tm+oáÓfïôö˜ »exi±É`Lâ†@×[åAoo€!N¤3œQbÕrL’qn×¾\VIÝuxÚ¬Hï€É0t!†—Xµ“d¦·ŽÄuîn2zOsãhÀd½{x(Æ£=&Éä¶´¸Ö肸ëó´Ù„Þ3}G¬n°1à w•Øã“dZk .ºÏUIU^%z§fôž|8Æà  ‡+Ä~jñhŒWåæ2‘ í(naÄuÞwG¹‡Þ‹5˜ —cGâ%̸éñªô§ÍøÊàI\œ²ë¿òbÐ;9sóàC©*šaß…Ø¡ÄåH^‰M| ­¯lk!ÅÅ)»!*/ ½“gh>0Fcx¡·»Üb\Ècy’£:m°n« ÜvF×…»ÉéÝ^|÷vìñDZaJŒŽqQ’í`fÊA‹Ím:wUO›QéÝ 0†eXQâY‰eH&Ï Êúᶺ^Ü…ª¼¦ÿ_t%½]Ç0%Î]‹U¦Ð²¾:´]ÛÊ™ÞÉN»,f0ö(q?Œ—•¿ù¨£²k°Í§òXt“T^8z{L† 0,_ˆ»7:ÆH0gI!=·F,wIoG¯í½yx2ÌBLŒÉ3‰ Žn8w éíy»w'Àý>"Ã…دĽ1^Va‡rF¤«,Y¦@·€»¤· ÀºUØèù,JŒñ²J4Äqåæ²»­¹JîÚTÞôn„a ƒ2ì]âÓc†5WÑ]V^Û½}& ƒH €1=fp{°„ØJÝHo€HïdYâY‰‡cL’uq#¡‹ìn\zÏrxÀéF,Ĺ:qI2S”Û¤­¡å.jå@ï&Ý&à CI †qI2­õ+n9tÁÝ5¯¼Zôž|»‡ÁdCâJUb<Œ‹‘L•i-&·Ú7wíÝMFï&ÿM~`µIEND®B`‚less.js-1.4.2/test/data/image.jpg000066400000000000000000000000311217256642200165540ustar00rootroot00000000000000not actually a jpeg file less.js-1.4.2/test/data/page.html000066400000000000000000000000441217256642200165760ustar00rootroot00000000000000

    This page is 100% Awesome.

    less.js-1.4.2/test/less-test.js000066400000000000000000000153401217256642200163510ustar00rootroot00000000000000var path = require('path'), fs = require('fs'), sys = require('util'); var less = require('../lib/less'); var stylize = require('../lib/less/lessc_helper').stylize; var globals = Object.keys(global); var oneTestOnly = process.argv[2]; var totalTests = 0, failedTests = 0, passedTests = 0; less.tree.functions.add = function (a, b) { return new(less.tree.Dimension)(a.value + b.value); }; less.tree.functions.increment = function (a) { return new(less.tree.Dimension)(a.value + 1); }; less.tree.functions._color = function (str) { if (str.value === "evil red") { return new(less.tree.Color)("600") } }; sys.puts("\n" + stylize("LESS", 'underline') + "\n"); runTestSet({strictMath: true, relativeUrls: true, silent: true}); runTestSet({strictMath: true, strictUnits: true}, "errors/", function(name, err, compiledLess, doReplacements) { fs.readFile(path.join('test/less/', name) + '.txt', 'utf8', function (e, expectedErr) { sys.print("- " + name + ": "); expectedErr = doReplacements(expectedErr, 'test/less/errors/'); if (!err) { if (compiledLess) { fail("No Error", 'red'); } else { fail("No Error, No Output"); } } else { var errMessage = less.formatError(err); if (errMessage === expectedErr) { ok('OK'); } else { difference("FAIL", expectedErr, errMessage); } } sys.puts(""); });}, null, function(input, directory) { return input.replace( "{path}", path.join(process.cwd(), "/test/less/errors/")) .replace("{pathrel}", path.join("test", "less", "errors/")) .replace("{pathhref}", "") .replace("{404status}", "") .replace(/\r\n/g, '\n'); }); runTestSet({strictMath: true, dumpLineNumbers: 'comments'}, "debug/", null, function(name) { return name + '-comments'; }); runTestSet({strictMath: true, dumpLineNumbers: 'mediaquery'}, "debug/", null, function(name) { return name + '-mediaquery'; }); runTestSet({strictMath: true, dumpLineNumbers: 'all'}, "debug/", null, function(name) { return name + '-all'; }); runTestSet({strictMath: true, relativeUrls: false, rootpath: "folder (1)/"}, "static-urls/"); runTestSet({strictMath: true, compress: true}, "compression/"); runTestSet({ }, "legacy/"); testNoOptions(); function globalReplacements(input, directory) { var p = path.join(process.cwd(), directory), pathimport = path.join(process.cwd(), directory + "import/"), pathesc = p.replace(/[.:/\\]/g, function(a) { return '\\' + (a=='\\' ? '\/' : a); }), pathimportesc = pathimport.replace(/[.:/\\]/g, function(a) { return '\\' + (a=='\\' ? '\/' : a); }); return input.replace(/\{path\}/g, p) .replace(/\{pathesc\}/g, pathesc) .replace(/\{pathimport\}/g, pathimport) .replace(/\{pathimportesc\}/g, pathimportesc) .replace(/\r\n/g, '\n'); } function checkGlobalLeaks() { return Object.keys(global).filter(function(v) { return globals.indexOf(v) < 0; }); } function runTestSet(options, foldername, verifyFunction, nameModifier, doReplacements) { foldername = foldername || ""; if(!doReplacements) doReplacements = globalReplacements; fs.readdirSync(path.join('test/less/', foldername)).forEach(function (file) { if (! /\.less/.test(file)) { return } var name = foldername + path.basename(file, '.less'); if (oneTestOnly && name !== oneTestOnly) { return; } totalTests++; toCSS(options, path.join('test/less/', foldername + file), function (err, less) { if (verifyFunction) { return verifyFunction(name, err, less, doReplacements); } var css_name = name; if(nameModifier) css_name=nameModifier(name); fs.readFile(path.join('test/css', css_name) + '.css', 'utf8', function (e, css) { sys.print("- " + css_name + ": ") css = css && doReplacements(css, 'test/less/' + foldername); if (less === css) { ok('OK'); } else if (err) { fail("ERROR: " + (err && err.message)); } else { difference("FAIL", css, less); } sys.puts(""); }); }); }); } function diff(left, right) { sys.puts(""); require('diff').diffLines(left, right).forEach(function(item) { if(item.added || item.removed) { sys.print(stylize(item.value, item.added ? 'green' : 'red')); } else { sys.print(item.value); } }); } function fail(msg) { sys.print(stylize(msg, 'red')); failedTests++; endTest(); } function difference(msg, left, right) { sys.print(stylize(msg, 'yellow')); failedTests++; diff(left, right); endTest(); } function ok(msg) { sys.print(stylize(msg, 'green')); passedTests++; endTest(); } function endTest() { var leaked = checkGlobalLeaks(); if (failedTests + passedTests === totalTests) { sys.puts(""); sys.puts(""); if (failedTests > 0) { sys.print(failedTests); sys.print(stylize(" Failed", "red")); sys.print(", " + passedTests + " passed"); } else { sys.print(stylize("All Passed ", "green")); sys.print(passedTests + " run"); } if (leaked.length > 0) { sys.puts(""); sys.puts(""); sys.print(stylize("Global leak detected: ", "red") + leaked.join(', ')); sys.print("\n"); } } } function toCSS(options, path, callback) { var tree, css; options = options || {}; fs.readFile(path, 'utf8', function (e, str) { if (e) { return callback(e) } options.paths = [require('path').dirname(path)]; options.filename = require('path').resolve(process.cwd(), path); options.optimization = options.optimization || 0; new(less.Parser)(options).parse(str, function (err, tree) { if (err) { callback(err); } else { try { css = tree.toCSS(options); callback(null, css); } catch (e) { callback(e); } } }); }); } function testNoOptions() { totalTests++; try { sys.print("- Integration - creating parser without options: "); new(less.Parser); } catch(e) { fail(stylize("FAIL\n", "red")); return; } ok(stylize("OK\n", "green")); } less.js-1.4.2/test/less/000077500000000000000000000000001217256642200150335ustar00rootroot00000000000000less.js-1.4.2/test/less/charsets.less000066400000000000000000000000701217256642200175340ustar00rootroot00000000000000@charset "UTF-8"; @import "import/import-charset-test";less.js-1.4.2/test/less/colors.less000066400000000000000000000025151217256642200172270ustar00rootroot00000000000000#yelow { #short { color: #fea; } #long { color: #ffeeaa; } #rgba { color: rgba(255, 238, 170, 0.1); } #argb { color: argb(rgba(255, 238, 170, 0.1)); } } #blue { #short { color: #00f; } #long { color: #0000ff; } #rgba { color: rgba(0, 0, 255, 0.1); } #argb { color: argb(rgba(0, 0, 255, 0.1)); } } #alpha #hsla { color: hsla(11, 20%, 20%, 0.6); } #overflow { .a { color: (#111111 - #444444); } // #000000 .b { color: (#eee + #fff); } // #ffffff .c { color: (#aaa * 3); } // #ffffff .d { color: (#00ee00 + #009900); } // #00ff00 } #grey { color: rgb(200, 200, 200); } #333333 { color: rgb(20%, 20%, 20%); } #808080 { color: hsl(50, 0%, 50%); } #00ff00 { color: hsl(120, 100%, 50%); } .lightenblue { color: lighten(blue, 10%); } .darkenblue { color: darken(blue, 10%); } .unknowncolors { color: blue2; border: 2px solid superred; } .transparent { color: transparent; background-color: rgba(0, 0, 0, 0); } #alpha { @colorvar: rgba(150, 200, 150, 0.7); #fromvar { opacity: alpha(@colorvar); } #short { opacity: alpha(#aaa); } #long { opacity: alpha(#bababa); } #rgba { opacity: alpha(rgba(50, 120, 95, 0.2)); } #hsl { opacity: alpha(hsl(120, 100%, 50%)); } } less.js-1.4.2/test/less/comments.less000066400000000000000000000024471217256642200175570ustar00rootroot00000000000000/******************\ * * * Comment Header * * * \******************/ /* Comment */ /* * Comment Test * * - cloudhead (http://cloudhead.net) * */ //////////////// @var: "content"; //////////////// /* Colors * ------ * #EDF8FC (background blue) * #166C89 (darkest blue) * * Text: * #333 (standard text) // A comment within a comment! * #1F9EC9 (standard link) * */ /* @group Variables ------------------- */ #comments /* boo */ { /**/ // An empty comment color: red; /* A C-style comment */ /* A C-style comment */ background-color: orange; // A little comment font-size: 12px; /* lost comment */ content: @var; border: 1px solid black; // padding & margin // padding: 0; // }{ '" margin: 2em; } // /* commented out #more-comments { color: grey; } */ .selector /* .with */, .lots, /* of */ .comments { color: grey, /* blue */ orange; -webkit-border-radius: 2px /* webkit only */; -moz-border-radius: (2px * 4) /* moz only with operation */; } .mixin_def_with_colors(@a: white, // in @b: 1px //put in @b - causes problems! ---> ) // the when (@a = white) { .test { color: @b; } } .mixin_def_with_colors(); #last { color: blue } // /* *//* { *//* *//* *//* */#div { color:#A33; }/* } */ less.js-1.4.2/test/less/compression/000077500000000000000000000000001217256642200173745ustar00rootroot00000000000000less.js-1.4.2/test/less/compression/compression.less000066400000000000000000000003661217256642200226320ustar00rootroot00000000000000#colours { color1: #fea; color2: #ffeeaa; color3: rgba(255, 238, 170, 0.1); @color1: #fea; string: "@{color1}"; } dimensions { val: 0.1px; val: 0em; val: 4cm; val: 0.2; val: 5; angles-must-have-unit: 0deg; width: auto\9; }less.js-1.4.2/test/less/css-3.less000066400000000000000000000036051217256642200166570ustar00rootroot00000000000000.comma-delimited { text-shadow: -1px -1px 1px red, 6px 5px 5px yellow; -moz-box-shadow: 0pt 0pt 2px rgba(255, 255, 255, 0.4) inset, 0pt 4px 6px rgba(255, 255, 255, 0.4) inset; -webkit-transform: rotate(-0.0000000001deg); } @font-face { font-family: Headline; unicode-range: U+??????, U+0???, U+0-7F, U+A5; } .other { -moz-transform: translate(0, 11em) rotate(-90deg); transform: rotateX(45deg); } .item[data-cra_zy-attr1b-ut3=bold] { font-weight: bold; } p:not([class*="lead"]) { color: black; } input[type="text"].class#id[attr=32]:not(1) { color: white; } div#id.class[a=1][b=2].class:not(1) { color: white; } ul.comma > li:not(:only-child)::after { color: white; } ol.comma > li:nth-last-child(2)::after { color: white; } li:nth-child(4n+1), li:nth-child(-5n), li:nth-child(-n+2) { color: white; } a[href^="http://"] { color: black; } a[href$="http://"] { color: black; } form[data-disabled] { color: black; } p::before { color: black; } #issue322 { -webkit-animation: anim2 7s infinite ease-in-out; } @-webkit-keyframes frames { 0% { border: 1px } 5.5% { border: 2px } 100% { border: 3px } } @keyframes fontbulger1 { to { font-size: 15px; } from,to { font-size: 12px; } 0%,100% { font-size: 12px; } } .units { font: 1.2rem/2rem; font: 8vw/9vw; font: 10vh/12vh; font: 12vm/15vm; font: 12vmin/15vmin; font: 1.2ch/1.5ch; } @supports ( box-shadow: 2px 2px 2px black ) or ( -moz-box-shadow: 2px 2px 2px black ) { .outline { box-shadow: 2px 2px 2px black; -moz-box-shadow: 2px 2px 2px black; } } @-x-document url-prefix(""github.com"") { h1 { color: red; } } @viewport { font-size: 10px; } @namespace foo url(http://www.example.com); foo|h1 { color: blue; } foo|* { color: yellow; } |h1 { color: red; } *|h1 { color: green; } h1 { color: green; } .upper-test { UpperCaseProperties: allowed; }less.js-1.4.2/test/less/css-escapes.less000066400000000000000000000006671217256642200201450ustar00rootroot00000000000000@ugly: fuchsia; .escape\|random\|char { color: red; } .mixin\!tUp { font-weight: bold; } // class="404" .\34 04 { background: red; strong { color: @ugly; .mixin\!tUp; } } .trailingTest\+ { color: red; } /* This hideous test of hideousness checks for the selector "blockquote" with various permutations of hex escapes */ \62\6c\6f \63 \6B \0071 \000075o\74 e { color: silver; } [ng\:cloak], ng\:form { display: none; } less.js-1.4.2/test/less/css.less000066400000000000000000000025461217256642200165220ustar00rootroot00000000000000@charset "utf-8"; div { color: black; } div { width: 99%; } * { min-width: 45em; } h1, h2 > a > p, h3 { color: none; } div.class { color: blue; } div#id { color: green; } .class#id { color: purple; } .one.two.three { color: grey; } @media print { * { font-size: 3em; } } @media screen { * { font-size: 10px; } } @font-face { font-family: 'Garamond Pro'; } a:hover, a:link { color: #999; } p, p:first-child { text-transform: none; } q:lang(no) { quotes: none; } p + h1 { font-size: +2.2em; } #shorthands { border: 1px solid #000; font: 12px/16px Arial; font: 100%/16px Arial; margin: 1px 0; padding: 0 auto; } #more-shorthands { margin: 0; padding: 1px 0 2px 0; font: normal small/20px 'Trebuchet MS', Verdana, sans-serif; font: 0/0 a; border-radius: 5px / 10px; } .misc { -moz-border-radius: 2px; display: -moz-inline-stack; width: .1em; background-color: #009998; background: -webkit-gradient(linear, left top, left bottom, from(red), to(blue)); margin: ; .nested-multiple { multiple-semi-colons: yes;;;;;; }; filter: alpha(opacity=100); width: auto\9; } #important { color: red !important; width: 100%!important; height: 20px ! important; } .def-font(@name) { @font-face { font-family: @name } } .def-font(font-a); .def-font(font-b); .æøå { margin: 0; } less.js-1.4.2/test/less/debug/000077500000000000000000000000001217256642200161215ustar00rootroot00000000000000less.js-1.4.2/test/less/debug/import/000077500000000000000000000000001217256642200174335ustar00rootroot00000000000000less.js-1.4.2/test/less/debug/import/test.less000066400000000000000000000005421217256642200213030ustar00rootroot00000000000000@charset "ISO-8859-1"; .mixin_import1() { @media all { .tst { color: black; @media screen { color: red; .tst3 { color: white; } } } } } .mixin_import2() { .tst2 { color: white; } } .tst3 { color: grey; }less.js-1.4.2/test/less/debug/linenumbers.less000066400000000000000000000003021217256642200213270ustar00rootroot00000000000000@charset "UTF-8"; @import "import/test.less"; .start() { .test2 { color: red; } } .mix() { color: black; } .test1 { .mix(); } .start(); .mixin_import1(); .mixin_import2();less.js-1.4.2/test/less/errors/000077500000000000000000000000001217256642200163475ustar00rootroot00000000000000less.js-1.4.2/test/less/errors/add-mixed-units.less000066400000000000000000000000341217256642200222300ustar00rootroot00000000000000.a { error: (1px + 3em); }less.js-1.4.2/test/less/errors/add-mixed-units.txt000066400000000000000000000002641217256642200221060ustar00rootroot00000000000000SyntaxError: Incompatible units. Change the units or use the unit function. Bad units: 'px' and 'em'. in {path}add-mixed-units.less on line null, column 0: 1 error: (1px + 3em); less.js-1.4.2/test/less/errors/add-mixed-units2.less000066400000000000000000000000541217256642200223140ustar00rootroot00000000000000.a { error: ((1px * 2px) + (3em * 3px)); }less.js-1.4.2/test/less/errors/add-mixed-units2.txt000066400000000000000000000003131217256642200221630ustar00rootroot00000000000000SyntaxError: Incompatible units. Change the units or use the unit function. Bad units: 'px*px' and 'em*px'. in {path}add-mixed-units2.less on line null, column 0: 1 error: ((1px * 2px) + (3em * 3px)); less.js-1.4.2/test/less/errors/bad-variable-declaration1.less000066400000000000000000000000151217256642200241100ustar00rootroot00000000000000@@demo: "hi";less.js-1.4.2/test/less/errors/bad-variable-declaration1.txt000066400000000000000000000001541217256642200237650ustar00rootroot00000000000000ParseError: Unrecognised input in {path}bad-variable-declaration1.less on line 1, column 1: 1 @@demo: "hi"; less.js-1.4.2/test/less/errors/color-operation-error.less000066400000000000000000000000321217256642200234750ustar00rootroot00000000000000.a { prop: (3 / #fff); }less.js-1.4.2/test/less/errors/color-operation-error.txt000066400000000000000000000002221217256642200233470ustar00rootroot00000000000000OperationError: Can't substract or divide a color from a number in {path}color-operation-error.less on line null, column 0: 1 prop: (3 / #fff); less.js-1.4.2/test/less/errors/comment-in-selector.less000066400000000000000000000000471217256642200231240ustar00rootroot00000000000000#gaga /* Comment */ span { color: red }less.js-1.4.2/test/less/errors/comment-in-selector.txt000066400000000000000000000002011217256642200227650ustar00rootroot00000000000000ParseError: Unrecognised input in {path}comment-in-selector.less on line 1, column 21: 1 #gaga /* Comment */ span { color: red } less.js-1.4.2/test/less/errors/divide-mixed-units.less000066400000000000000000000000341217256642200227440ustar00rootroot00000000000000.a { error: (1px / 3em); }less.js-1.4.2/test/less/errors/divide-mixed-units.txt000066400000000000000000000002771217256642200226260ustar00rootroot00000000000000SyntaxError: Multiple units in dimension. Correct the units or use the unit function. Bad unit: px/em in {path}divide-mixed-units.less on line 2, column 3: 1 .a { 2 error: (1px / 3em); 3 } less.js-1.4.2/test/less/errors/extend-no-selector.less000066400000000000000000000000441217256642200227540ustar00rootroot00000000000000:extend(.a all) { property: red; }less.js-1.4.2/test/less/errors/extend-no-selector.txt000066400000000000000000000002621217256642200226270ustar00rootroot00000000000000SyntaxError: Extend must be used to extend a selector, it cannot be used on its own in {path}extend-no-selector.less on line 1, column 17: 1 :extend(.a all) { 2 property: red; less.js-1.4.2/test/less/errors/extend-not-at-end.less000066400000000000000000000000501217256642200224650ustar00rootroot00000000000000.a:extend(.b all).c { property: red; }less.js-1.4.2/test/less/errors/extend-not-at-end.txt000066400000000000000000000002351217256642200223430ustar00rootroot00000000000000SyntaxError: Extend can only be used at the end of selector in {path}extend-not-at-end.less on line 1, column 21: 1 .a:extend(.b all).c { 2 property: red; less.js-1.4.2/test/less/errors/import-missing.less000066400000000000000000000001631217256642200222200ustar00rootroot00000000000000.a { color: green; // tests line number for import reference is correct } @import "file-does-not-exist.less";less.js-1.4.2/test/less/errors/import-missing.txt000066400000000000000000000002431217256642200220700ustar00rootroot00000000000000FileError: '{pathhref}file-does-not-exist.less' wasn't found{404status} in {path}import-missing.less on line 6, column 1: 5 6 @import "file-does-not-exist.less"; less.js-1.4.2/test/less/errors/import-no-semi.less000066400000000000000000000000501217256642200221110ustar00rootroot00000000000000@import "this-statement-is-invalid.less"less.js-1.4.2/test/less/errors/import-no-semi.txt000066400000000000000000000001741217256642200217710ustar00rootroot00000000000000ParseError: Unrecognised input in {path}import-no-semi.less on line 1, column 1: 1 @import "this-statement-is-invalid.less" less.js-1.4.2/test/less/errors/import-subfolder1.less000066400000000000000000000000511217256642200226110ustar00rootroot00000000000000@import "imports/import-subfolder1.less";less.js-1.4.2/test/less/errors/import-subfolder1.txt000066400000000000000000000001761217256642200224720ustar00rootroot00000000000000NameError: .mixin-not-defined is undefined in {path}mixin-not-defined.less on line 11, column 1: 10 11 .mixin-not-defined(); less.js-1.4.2/test/less/errors/import-subfolder2.less000066400000000000000000000000511217256642200226120ustar00rootroot00000000000000@import "imports/import-subfolder2.less";less.js-1.4.2/test/less/errors/import-subfolder2.txt000066400000000000000000000001421217256642200224640ustar00rootroot00000000000000ParseError: missing opening `{` in {path}parse-error-curly-bracket.less on line 1, column 2: 1 }} less.js-1.4.2/test/less/errors/imports/000077500000000000000000000000001217256642200200445ustar00rootroot00000000000000less.js-1.4.2/test/less/errors/imports/import-subfolder1.less000066400000000000000000000000531217256642200243100ustar00rootroot00000000000000@import "subfolder/mixin-not-defined.less";less.js-1.4.2/test/less/errors/imports/import-subfolder2.less000066400000000000000000000000631217256642200243120ustar00rootroot00000000000000@import "subfolder/parse-error-curly-bracket.less";less.js-1.4.2/test/less/errors/imports/import-test.less000066400000000000000000000000451217256642200232220ustar00rootroot00000000000000.someclass { font-weight: bold; }less.js-1.4.2/test/less/errors/imports/subfolder/000077500000000000000000000000001217256642200220315ustar00rootroot00000000000000less.js-1.4.2/test/less/errors/imports/subfolder/mixin-not-defined.less000066400000000000000000000000471217256642200262400ustar00rootroot00000000000000@import "../../mixin-not-defined.less";less.js-1.4.2/test/less/errors/imports/subfolder/parse-error-curly-bracket.less000066400000000000000000000000571217256642200277310ustar00rootroot00000000000000@import "../../parse-error-curly-bracket.less";less.js-1.4.2/test/less/errors/javascript-error.less000066400000000000000000000000471217256642200225350ustar00rootroot00000000000000.scope { var: `this.foo.toJS()`; } less.js-1.4.2/test/less/errors/javascript-error.txt000066400000000000000000000003001217256642200223760ustar00rootroot00000000000000SyntaxError: JavaScript evaluation error: 'TypeError: Cannot call method 'toJS' of undefined' in {path}javascript-error.less on line 2, column 27: 1 .scope { 2 var: `this.foo.toJS()`; 3 } less.js-1.4.2/test/less/errors/mixed-mixin-definition-args-1.less000066400000000000000000000001421217256642200247020ustar00rootroot00000000000000.mixin(@a : 4, @b : 3, @c: 2) { will: fail; } .mixin-test { .mixin(@a: 5; @b: 6, @c: 7); }less.js-1.4.2/test/less/errors/mixed-mixin-definition-args-1.txt000066400000000000000000000002541217256642200245570ustar00rootroot00000000000000SyntaxError: Cannot mix ; and , as delimiter types in {path}mixed-mixin-definition-args-1.less on line 5, column 30: 4 .mixin-test { 5 .mixin(@a: 5; @b: 6, @c: 7); 6 } less.js-1.4.2/test/less/errors/mixed-mixin-definition-args-2.less000066400000000000000000000001431217256642200247040ustar00rootroot00000000000000.mixin(@a : 4, @b : 3, @c: 2) { will: fail; } .mixin-test { .mixin(@a: 5, @b: 6; @c: 7); } less.js-1.4.2/test/less/errors/mixed-mixin-definition-args-2.txt000066400000000000000000000002541217256642200245600ustar00rootroot00000000000000SyntaxError: Cannot mix ; and , as delimiter types in {path}mixed-mixin-definition-args-2.less on line 5, column 26: 4 .mixin-test { 5 .mixin(@a: 5, @b: 6; @c: 7); 6 } less.js-1.4.2/test/less/errors/mixin-not-defined.less000066400000000000000000000001731217256642200225560ustar00rootroot00000000000000 .error-is-further-on() { } .pad-here-to-reproduce-error-in() { } .the-import-subfolder-test() { } .mixin-not-defined();less.js-1.4.2/test/less/errors/mixin-not-defined.txt000066400000000000000000000001761217256642200224320ustar00rootroot00000000000000NameError: .mixin-not-defined is undefined in {path}mixin-not-defined.less on line 11, column 1: 10 11 .mixin-not-defined(); less.js-1.4.2/test/less/errors/mixin-not-matched.less000066400000000000000000000000721217256642200225630ustar00rootroot00000000000000@saxofon:trumpete; .mixin(saxofon) { } .mixin(@saxofon);less.js-1.4.2/test/less/errors/mixin-not-matched.txt000066400000000000000000000002221217256642200224310ustar00rootroot00000000000000RuntimeError: No matching definition was found for `.mixin(trumpete)` in {path}mixin-not-matched.less on line 6, column 1: 5 6 .mixin(@saxofon); less.js-1.4.2/test/less/errors/mixin-not-matched2.less000066400000000000000000000000751217256642200226500ustar00rootroot00000000000000@saxofon:trumpete; .mixin(@a, @b) { } .mixin(@a: @saxofon);less.js-1.4.2/test/less/errors/mixin-not-matched2.txt000066400000000000000000000002321217256642200225140ustar00rootroot00000000000000RuntimeError: No matching definition was found for `.mixin(@a:trumpete)` in {path}mixin-not-matched2.less on line 6, column 1: 5 6 .mixin(@a: @saxofon); less.js-1.4.2/test/less/errors/multiply-mixed-units.less000066400000000000000000000000731217256642200233620ustar00rootroot00000000000000/* Test */ #blah { // blah } .a { error: (1px * 1em); }less.js-1.4.2/test/less/errors/multiply-mixed-units.txt000066400000000000000000000003011217256642200232250ustar00rootroot00000000000000SyntaxError: Multiple units in dimension. Correct the units or use the unit function. Bad unit: em*px in {path}multiply-mixed-units.less on line 6, column 3: 5 .a { 6 error: (1px * 1em); 7 } less.js-1.4.2/test/less/errors/parens-error-1.less000066400000000000000000000000521217256642200220110ustar00rootroot00000000000000.a { something: (12 (13 + 5 -23) + 5); }less.js-1.4.2/test/less/errors/parens-error-1.txt000066400000000000000000000002061217256642200216630ustar00rootroot00000000000000SyntaxError: expected ')' got '(' in {path}parens-error-1.less on line 2, column 18: 1 .a { 2 something: (12 (13 + 5 -23) + 5); 3 } less.js-1.4.2/test/less/errors/parens-error-2.less000066400000000000000000000000501217256642200220100ustar00rootroot00000000000000.a { something: (12 * (13 + 5 -23)); }less.js-1.4.2/test/less/errors/parens-error-2.txt000066400000000000000000000002041217256642200216620ustar00rootroot00000000000000SyntaxError: expected ')' got '-' in {path}parens-error-2.less on line 2, column 28: 1 .a { 2 something: (12 * (13 + 5 -23)); 3 } less.js-1.4.2/test/less/errors/parens-error-3.less000066400000000000000000000000511217256642200220120ustar00rootroot00000000000000.a { something: (12 + (13 + 10 -23)); }less.js-1.4.2/test/less/errors/parens-error-3.txt000066400000000000000000000002051217256642200216640ustar00rootroot00000000000000SyntaxError: expected ')' got '-' in {path}parens-error-3.less on line 2, column 29: 1 .a { 2 something: (12 + (13 + 10 -23)); 3 } less.js-1.4.2/test/less/errors/parse-error-curly-bracket.less000066400000000000000000000000021217256642200242350ustar00rootroot00000000000000}}less.js-1.4.2/test/less/errors/parse-error-curly-bracket.txt000066400000000000000000000001421217256642200241130ustar00rootroot00000000000000ParseError: missing opening `{` in {path}parse-error-curly-bracket.less on line 1, column 2: 1 }} less.js-1.4.2/test/less/errors/parse-error-missing-bracket.less000066400000000000000000000000411217256642200245530ustar00rootroot00000000000000body { background-color: #fff; less.js-1.4.2/test/less/errors/parse-error-missing-bracket.txt000066400000000000000000000001761217256642200244350ustar00rootroot00000000000000ParseError: missing closing `}` in {path}parse-error-missing-bracket.less on line 3, column 1: 2 background-color: #fff; 3 less.js-1.4.2/test/less/errors/parse-error-with-import.less000066400000000000000000000002001217256642200237510ustar00rootroot00000000000000@import 'import/import-test.less'; body { font-family: arial, sans-serif; } nonsense; .clickable { cursor: pointer; }less.js-1.4.2/test/less/errors/parse-error-with-import.txt000066400000000000000000000001541217256642200236320ustar00rootroot00000000000000ParseError: Unrecognised input in {path}parse-error-with-import.less on line 8, column 9: 7 8 nonsense; 9 less.js-1.4.2/test/less/errors/property-ie5-hack.less000066400000000000000000000000601217256642200225030ustar00rootroot00000000000000.test { display/*/: block; /*sorry for IE5*/ }less.js-1.4.2/test/less/errors/property-ie5-hack.txt000066400000000000000000000002131217256642200223540ustar00rootroot00000000000000ParseError: Unrecognised input in {path}property-ie5-hack.less on line 2, column 3: 1 .test { 2 display/*/: block; /*sorry for IE5*/ 3 } less.js-1.4.2/test/less/errors/property-in-root.less000066400000000000000000000000301217256642200225010ustar00rootroot00000000000000.a() { prop:1; } .a();less.js-1.4.2/test/less/errors/property-in-root.txt000066400000000000000000000002411217256642200223560ustar00rootroot00000000000000SyntaxError: properties must be inside selector blocks, they cannot be in the root. in {path}property-in-root.less on line 2, column 3: 1 .a() { 2 prop:1; 3 } less.js-1.4.2/test/less/errors/property-in-root2.less000066400000000000000000000000331217256642200225660ustar00rootroot00000000000000@import "property-in-root";less.js-1.4.2/test/less/errors/property-in-root2.txt000066400000000000000000000002411217256642200224400ustar00rootroot00000000000000SyntaxError: properties must be inside selector blocks, they cannot be in the root. in {path}property-in-root.less on line 2, column 3: 1 .a() { 2 prop:1; 3 } less.js-1.4.2/test/less/errors/property-in-root3.less000066400000000000000000000000301217256642200225640ustar00rootroot00000000000000prop:1; .a { prop:1; }less.js-1.4.2/test/less/errors/property-in-root3.txt000066400000000000000000000002321217256642200224410ustar00rootroot00000000000000SyntaxError: properties must be inside selector blocks, they cannot be in the root. in {path}property-in-root3.less on line 1, column 1: 1 prop:1; 2 .a { less.js-1.4.2/test/less/errors/recursive-variable.less000066400000000000000000000000441217256642200230270ustar00rootroot00000000000000@bodyColor: darken(@bodyColor, 30%);less.js-1.4.2/test/less/errors/recursive-variable.txt000066400000000000000000000002261217256642200227020ustar00rootroot00000000000000NameError: Recursive variable definition for @bodyColor in {path}recursive-variable.less on line 1, column 20: 1 @bodyColor: darken(@bodyColor, 30%); less.js-1.4.2/test/less/extend-chaining.less000066400000000000000000000022111217256642200207640ustar00rootroot00000000000000//very simple chaining .a { color: black; } .b:extend(.a) {} .c:extend(.b) {} //very simple chaining, ordering not important .d:extend(.e) {} .e:extend(.f) {} .f { color: black; } //extend with all .g.h { color: black; } .i.j:extend(.g all) { color: white; } .k:extend(.i all) {} //extend multi-chaining .l { color: black; } .m:extend(.l){} .n:extend(.m){} .o:extend(.n){} .p:extend(.o){} .q:extend(.p){} .r:extend(.q){} .s:extend(.r){} .t:extend(.s){} // self referencing is ignored .u {color: black;} .v.u.v:extend(.u all){} // circular reference because the new extend product will match the existing extend .w:extend(.w) {color: black;} .v.w.v:extend(.w all){} // classic circular references .x:extend(.z) { color: x; } .y:extend(.x) { color: y; } .z:extend(.y) { color: z; } // media queries - dont extend outside, do extend inside @media tv { .ma:extend(.a,.b,.c,.d,.e,.f,.g,.h,.i,.j,.k,.l,.m,.n,.o,.p,.q,.r,.s,.t,.u,.v,.w,.x,.y,.z,.md) { color: black; } .md { color: white; } @media plasma { .me, .mf { &:extend(.mb,.md); background: red; } } } .mb:extend(.ma) {}; .mc:extend(.mb) {};less.js-1.4.2/test/less/extend-clearfix.less000066400000000000000000000003261217256642200210060ustar00rootroot00000000000000.clearfix { *zoom: 1; &:after { content: ''; display: block; clear: both; height: 0; } } .foo { &:extend(.clearfix all); color: red; } .bar { &:extend(.clearfix all); color: blue; } less.js-1.4.2/test/less/extend-exact.less000066400000000000000000000010171217256642200203130ustar00rootroot00000000000000.replace.replace, .c.replace + .replace { .replace, .c { prop: copy-paste-replace; } } .rep_ace:extend(.replace.replace .replace) {} .a .b .c { prop: not_effected; } .a { prop: is_effected; .b { prop: not_effected; } .b.c { prop: not_effected; } } .c, .a { .b, .a { .a, .c { prop: not_effected; } } } .effected { &:extend(.a); &:extend(.b); &:extend(.c); } .e { && { prop: extend-double; &:hover { hover: not-extended; } } } .dbl:extend(.e.e) {} less.js-1.4.2/test/less/extend-media.less000066400000000000000000000004631217256642200202720ustar00rootroot00000000000000.ext1 .ext2 { background: black; } @media tv { .ext1 .ext3 { color: white; } .tv-lowres :extend(.ext1 all) { background: blue; } @media hires { .ext1 .ext4 { color: green; } .tv-hires :extend(.ext1 all) { background: red; } } } .all:extend(.ext1 all) { }less.js-1.4.2/test/less/extend-nest.less000066400000000000000000000015241217256642200201630ustar00rootroot00000000000000.sidebar { width: 300px; background: red; .box { background: #FFF; border: 1px solid #000; margin: 10px 0; } } .sidebar2 { &:extend(.sidebar all); background: blue; } .type1 { .sidebar3 { &:extend(.sidebar all); background: green; } } .type2 { &.sidebar4 { &:extend(.sidebar all); background: red; } } .button { color: black; &:hover { color: white; } } .submit { &:extend(.button); &:hover:extend(.button:hover) {} } .nomatch { &:hover:extend(.button :hover) {} } .button2 { :hover { nested: white; } } .button2 :hover { notnested: black; } .nomatch :extend(.button2:hover) {} .amp-test-a, .amp-test-b { .amp-test-c &.amp-test-d&.amp-test-e { .amp-test-f&+&.amp-test-g:extend(.amp-test-h) {} } } .amp-test-h { test: extended by masses of selectors; }less.js-1.4.2/test/less/extend-selector.less000066400000000000000000000022551217256642200210340ustar00rootroot00000000000000.error { border: 1px #f00; background: #fdd; } .error.intrusion { font-size: 1.3em; font-weight: bold; } .intrusion .error { display: none; } .badError:extend(.error all) { border-width: 3px; } .foo .bar, .foo .baz { display: none; } .ext1 .ext2 :extend(.foo all) { } .ext3:extend(.foo all), .ext4:extend(.foo all) { } div.ext5, .ext6 > .ext5 { width: 100px; } .should-not-exist-in-output, .ext7:extend(.ext5 all) { } .ext { test: 1; } // same as // .a .c:extend(.ext all) // .b .c:extend(.ext all) // .a .c .d // .b .c .d .a, .b { test: 2; .c:extend(.ext all) { test: 3; .d { test: 4; } } } .replace.replace, .c.replace + .replace { .replace, .c { prop: copy-paste-replace; } } .rep_ace:extend(.replace all) {} .attributes { [data="test"] { extend: attributes; } .attribute-test { &:extend([data="test"] all); } [data] { extend: attributes2; } .attribute-test2 { &:extend([data] all); //you could argue it should match [data="test"]... not for now though... } @attr-data: "test3"; [data=@{attr-data}] { extend: attributes2; } .attribute-test { &:extend([data="test3"] all); } }less.js-1.4.2/test/less/extend.less000066400000000000000000000017641217256642200172220ustar00rootroot00000000000000.error { border: 1px #f00; background: #fdd; } .error.intrusion { font-size: 1.3em; font-weight: bold; } .intrusion .error { display: none; } .badError { &:extend(.error all); border-width: 3px; } .foo .bar, .foo .baz { display: none; } .ext1 .ext2 { &:extend(.foo all); } .ext3, .ext4 { &:extend(.foo all); &:extend(.bar all); } div.ext5, .ext6 > .ext5 { width: 100px; } .ext7 { &:extend(.ext5 all); } .ext8.ext9 { result: add-foo; } .ext8 .ext9, .ext8 + .ext9, .ext8 > .ext9 { result: bar-matched; } .ext8.nomatch { result: none; } .ext8 { .ext9 { result: match-nested-bar; } } .ext8 { &.ext9 { result: match-nested-foo; } } .fuu:extend(.ext8.ext9 all) {} .buu:extend(.ext8 .ext9 all) {} .zap:extend(.ext8 + .ext9 all) {} .zoo:extend(.ext8 > .ext9 all) {} .aa { color: black; .dd { background: red; } } .bb { background: red; .bb { color: black; } } .cc:extend(.aa,.bb) {} .ee:extend(.dd all,.bb) {} .ff:extend(.dd,.bb all) {}less.js-1.4.2/test/less/functions.less000066400000000000000000000105761217256642200177440ustar00rootroot00000000000000#functions { @var: 10; @colors: #000, #fff; color: _color("evil red"); // #660000 width: increment(15); height: undefined("self"); border-width: add(2, 3); variable: increment(@var); background: linear-gradient(@colors); } #built-in { @r: 32; escaped: e("-Some::weird(#thing, y)"); lighten: lighten(#ff0000, 40%); darken: darken(#ff0000, 40%); saturate: saturate(#29332f, 20%); desaturate: desaturate(#203c31, 20%); greyscale: greyscale(#203c31); hsl-clamp: hsl(380, 150%, 150%); spin-p: spin(hsl(340, 50%, 50%), 40); spin-n: spin(hsl(30, 50%, 50%), -40); luma-white: luma(#fff); luma-black: luma(#000); luma-black-alpha: luma(rgba(0,0,0,0.5)); luma-red: luma(#ff0000); luma-green: luma(#00ff00); luma-blue: luma(#0000ff); luma-yellow: luma(#ffff00); luma-cyan: luma(#00ffff); luma-white-alpha: luma(rgba(255,255,255,0.5)); contrast-filter: contrast(30%); contrast-white: contrast(#fff); contrast-black: contrast(#000); contrast-red: contrast(#ff0000); contrast-green: contrast(#00ff00); contrast-blue: contrast(#0000ff); contrast-yellow: contrast(#ffff00); contrast-cyan: contrast(#00ffff); contrast-light: contrast(#fff, #111111, #eeeeee); contrast-dark: contrast(#000, #111111, #eeeeee); contrast-wrongorder: contrast(#fff, #eeeeee, #111111, 0.5); contrast-light-thresh: contrast(#fff, #111111, #eeeeee, 0.5); contrast-dark-thresh: contrast(#000, #111111, #eeeeee, 0.5); contrast-high-thresh: contrast(#555, #111111, #eeeeee, 0.6); contrast-low-thresh: contrast(#555, #111111, #eeeeee, 0.1); contrast-light-thresh-per: contrast(#fff, #111111, #eeeeee, 50%); contrast-dark-thresh-per: contrast(#000, #111111, #eeeeee, 50%); contrast-high-thresh-per: contrast(#555, #111111, #eeeeee, 60%); contrast-low-thresh-per: contrast(#555, #111111, #eeeeee, 10%); format: %("rgb(%d, %d, %d)", @r, 128, 64); format-string: %("hello %s", "world"); format-multiple: %("hello %s %d", "earth", 2); format-url-encode: %('red is %A', #ff0000); eformat: e(%("rgb(%d, %d, %d)", @r, 128, 64)); unitless: unit(12px); unit: unit((13px + 1px), em); hue: hue(hsl(98, 12%, 95%)); saturation: saturation(hsl(98, 12%, 95%)); lightness: lightness(hsl(98, 12%, 95%)); hsvhue: hsvhue(hsv(98, 12%, 95%)); hsvsaturation: hsvsaturation(hsv(98, 12%, 95%)); hsvvalue: hsvvalue(hsv(98, 12%, 95%)); red: red(#f00); green: green(#0f0); blue: blue(#00f); rounded: round((@r/3)); rounded-two: round((@r/3), 2); roundedpx: round((10px / 3)); roundedpx-three: round((10px / 3), 3); rounded-percentage: round(10.2%); ceil: ceil(10.1px); floor: floor(12.9px); sqrt: sqrt(25px); pi: pi(); mod: mod(13m, 11cm); // could take into account units, doesn't at the moment abs: abs(-4%); tan: tan(42deg); sin: sin(10deg); cos: cos(12); atan: atan(tan(0.1rad)); atan: convert(acos(cos(34deg)), deg); atan: convert(acos(cos(50grad)), deg); pow: pow(8px, 2); pow: pow(4, 3); pow: pow(3, 3em); percentage: percentage((10px / 50)); color: color("#ff0011"); tint: tint(#777777, 13); tint-full: tint(#777777, 100); tint-percent: tint(#777777, 13%); shade: shade(#777777, 13); shade-full: shade(#777777, 100); shade-percent: shade(#777777, 13%); fade-out: fadeOut(red, 5%); // support fadeOut and fadeout fade-in: fadein(fadeout(red, 10%), 5%); hsv: hsv(5, 50%, 30%); hsva: hsva(3, 50%, 30%, 0.2); mix: mix(#ff0000, #ffff00, 80); mix-0: mix(#ff0000, #ffff00, 0); mix-100: mix(#ff0000, #ffff00, 100); mix-weightless: mix(#ff0000, #ffff00); .is-a { color: iscolor(#ddd); color1: iscolor(red); color2: iscolor(rgb(0, 0, 0)); keyword: iskeyword(hello); number: isnumber(32); string: isstring("hello"); pixel: ispixel(32px); percent: ispercentage(32%); em: isem(32em); cat: isunit(32cat, cat); } } #alpha { alpha: darken(hsla(25, 50%, 50%, 0.6), 10%); } #blendmodes { multiply: multiply(#f60000, #f60000); screen: screen(#f60000, #0000f6); overlay: overlay(#f60000, #0000f6); softlight: softlight(#f60000, #ffffff); hardlight: hardlight(#f60000, #0000f6); difference: difference(#f60000, #0000f6); exclusion: exclusion(#f60000, #0000f6); average: average(#f60000, #0000f6); negation: negation(#f60000, #313131); } #extract { @anon: A B C 1 2 3; result: extract(@anon, 6) extract(@anon, 5) extract(@anon, 4) extract(@anon, 3) extract(@anon, 2) extract(@anon, 1); } less.js-1.4.2/test/less/ie-filters.less000066400000000000000000000006521217256642200177710ustar00rootroot00000000000000@fat: 0; @cloudhead: "#000000"; .nav { filter: progid:DXImageTransform.Microsoft.Alpha(opacity = 20); filter: progid:DXImageTransform.Microsoft.Alpha(opacity=@fat); filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="#333333", endColorstr=@cloudhead, GradientType=@fat); } .evalTest(@arg) { filter: progid:DXImageTransform.Microsoft.Alpha(opacity=@arg); } .evalTest1 { .evalTest(30); .evalTest(5); }less.js-1.4.2/test/less/import-interpolation.less000066400000000000000000000002331217256642200221200ustar00rootroot00000000000000@my_theme: "test"; @import "import/import-@{my_theme}-e.less"; @import "import/import-@{in}@{terpolation}.less"; @in: "in"; @terpolation: "terpolation";less.js-1.4.2/test/less/import-once.less000066400000000000000000000002401217256642200201530ustar00rootroot00000000000000@import "import/import-once-test-c"; @import "import/import-once-test-c"; @import "import/import-once-test-c.less"; @import "import/deeper/import-once-test-a"; less.js-1.4.2/test/less/import.less000066400000000000000000000011611217256642200172340ustar00rootroot00000000000000@import url(http://fonts.googleapis.com/css?family=Open+Sans); @import url(/absolute/something.css) screen and (color) and (max-width: 600px); @var: 100px; @import url("//ha.com/file.css") (min-width:@var); #import-test { .mixin; width: 10px; height: (@a + 10%); } @import "import/import-test-e" screen and (max-width: 600px); @import url("import/import-test-a.less"); @import (less, multiple) "import/import-test-d.css" screen and (max-width: 601px); @import (multiple) "import/import-test-e" screen and (max-width: 602px); @import (less, multiple) url("import/import-test-d.css") screen and (max-width: 603px);less.js-1.4.2/test/less/import/000077500000000000000000000000001217256642200163455ustar00rootroot00000000000000less.js-1.4.2/test/less/import/deeper/000077500000000000000000000000001217256642200176115ustar00rootroot00000000000000less.js-1.4.2/test/less/import/deeper/import-once-test-a.less000066400000000000000000000000401217256642200241220ustar00rootroot00000000000000@import "../import-once-test-c";less.js-1.4.2/test/less/import/import-and-relative-paths-test.less000066400000000000000000000001601217256642200252070ustar00rootroot00000000000000@import "../css/background.css"; @import "import-test-d.css"; @import "imports/logo"; @import "imports/font"; less.js-1.4.2/test/less/import/import-charset-test.less000066400000000000000000000000261217256642200231510ustar00rootroot00000000000000@charset "ISO-8859-1";less.js-1.4.2/test/less/import/import-interpolation.less000066400000000000000000000000531217256642200234320ustar00rootroot00000000000000@import "import-@{in}@{terpolation}2.less";less.js-1.4.2/test/less/import/import-interpolation2.less000066400000000000000000000000631217256642200235150ustar00rootroot00000000000000.a { var: test; } @in: "redefined-does-nothing";less.js-1.4.2/test/less/import/import-once-test-c.less000066400000000000000000000000441217256642200226640ustar00rootroot00000000000000 @c: red; #import { color: @c; } less.js-1.4.2/test/less/import/import-test-a.less000066400000000000000000000000731217256642200217420ustar00rootroot00000000000000@import "import-test-b.less"; @a: 20%; @import "urls.less";less.js-1.4.2/test/less/import/import-test-b.less000066400000000000000000000001151217256642200217400ustar00rootroot00000000000000@import "import-test-c"; @b: 100%; .mixin { height: 10px; color: @c; } less.js-1.4.2/test/less/import/import-test-c.less000066400000000000000000000000441217256642200217420ustar00rootroot00000000000000 @c: red; #import { color: @c; } less.js-1.4.2/test/less/import/import-test-d.css000066400000000000000000000000301217256642200215600ustar00rootroot00000000000000#css { color: yellow; } less.js-1.4.2/test/less/import/import-test-e.less000066400000000000000000000000261217256642200217440ustar00rootroot00000000000000 body { width: 100% } less.js-1.4.2/test/less/import/imports/000077500000000000000000000000001217256642200200425ustar00rootroot00000000000000less.js-1.4.2/test/less/import/imports/font.less000066400000000000000000000001671217256642200217040ustar00rootroot00000000000000@font-face { font-family: xecret; src: url('../assets/xecret.ttf'); } #secret { font-family: xecret, sans-serif; } less.js-1.4.2/test/less/import/imports/logo.less000066400000000000000000000001241217256642200216670ustar00rootroot00000000000000#logo { width: 100px; height: 100px; background: url('../assets/logo.png'); } less.js-1.4.2/test/less/import/urls.less000066400000000000000000000001011217256642200202120ustar00rootroot00000000000000// empty file showing that it loads from the relative path first less.js-1.4.2/test/less/javascript.less000066400000000000000000000010721217256642200200710ustar00rootroot00000000000000.eval { js: `42`; js: `1 + 1`; js: `"hello world"`; js: `[1, 2, 3]`; title: `typeof process.title`; ternary: `(1 + 1 == 2 ? true : false)`; multiline: `(function(){var x = 1 + 1; return x})()`; } .scope { @foo: 42; var: `parseInt(this.foo.toJS())`; escaped: ~`2 + 5 + 'px'`; } .vars { @var: `4 + 4`; width: @var; } .escape-interpol { @world: "world"; width: ~`"hello" + " " + @{world}`; } .arrays { @ary: 1, 2, 3; @ary2: 1 2 3; ary: `@{ary}.join(', ')`; ary1: `@{ary2}.join(', ')`; } less.js-1.4.2/test/less/lazy-eval.less000066400000000000000000000000631217256642200176260ustar00rootroot00000000000000@var: @a; @a: 100%; .lazy-eval { width: @var; } less.js-1.4.2/test/less/legacy/000077500000000000000000000000001217256642200162775ustar00rootroot00000000000000less.js-1.4.2/test/less/legacy/legacy.less000066400000000000000000000002341217256642200204320ustar00rootroot00000000000000@media (-o-min-device-pixel-ratio: 2/1) { .test-math-and-units { font: ignores 0/0 rules; test-division: 4 / 2 + 5em; simple: 1px + 1px; } }less.js-1.4.2/test/less/media.less000066400000000000000000000060571217256642200170120ustar00rootroot00000000000000 // For now, variables can't be declared inside @media blocks. @var: 42; @media print { .class { color: blue; .sub { width: @var; } } .top, header > h1 { color: (#222 * 2); } } @media screen { @base: 8; body { max-width: (@base * 60); } } @ratio_large: 16; @ratio_small: 9; @media all and (device-aspect-ratio: @ratio_large / @ratio_small) { body { max-width: 800px; } } @media all and (orientation:portrait) { aside { float: none; } } @media handheld and (min-width: @var), screen and (min-width: 20em) { body { max-width: 480px; } } body { @media print { padding: 20px; header { background-color: red; } @media (orientation:landscape) { margin-left: 20px; } } } @media screen { .sidebar { width: 300px; @media (orientation: landscape) { width: 500px; } } } @media a { .first { @media b { .second { .third { width: 300px; @media c { width: 500px; } } .fourth { width: 3; } } } } } body { @media a, b and c { width: 95%; @media x, y { width: 100%; } } } .mediaMixin(@fallback: 200px) { background: black; @media handheld { background: white; @media (max-width: @fallback) { background: red; } } } .a { .mediaMixin(100px); } .b { .mediaMixin(); } @smartphone: ~"only screen and (max-width: 200px)"; @media @smartphone { width: 480px; } @media print { @page :left { margin: 0.5cm; } @page :right { margin: 0.5cm; } @page Test:first { margin: 1cm; } @page :first { size: 8.5in 11in; @top-left { margin: 1cm; } @top-left-corner { margin: 1cm; } @top-center { margin: 1cm; } @top-right { margin: 1cm; } @top-right-corner { margin: 1cm; } @bottom-left { margin: 1cm; } @bottom-left-corner { margin: 1cm; } @bottom-center { margin: 1cm; } @bottom-right { margin: 1cm; } @bottom-right-corner { margin: 1cm; } @left-top { margin: 1cm; } @left-middle { margin: 1cm; } @left-bottom { margin: 1cm; } @right-top { margin: 1cm; } @right-middle { content: "Page " counter(page); } @right-bottom { margin: 1cm; } } } @media (-webkit-min-device-pixel-ratio: 2), (min--moz-device-pixel-ratio: 2), (-o-min-device-pixel-ratio: 2/1), (min-resolution: 2dppx), (min-resolution: 128dpcm) { .b { background: red; } } .bg() { background: red; @media (max-width: 500px) { background: green; } } body { .bg(); } @bpMedium: 1000px; @media (max-width: @bpMedium) { body { .bg(); background: blue; } } @media (max-width: 1200px) { /* a comment */ @media (max-width: 900px) { body { font-size: 11px; } } } less.js-1.4.2/test/less/mixins-args.less000066400000000000000000000056701217256642200201740ustar00rootroot00000000000000.mixin (@a: 1px, @b: 50%) { width: (@a * 5); height: (@b - 1%); } .mixina (@style, @width, @color: black) { border: @width @style @color; } .mixiny (@a: 0, @b: 0) { margin: @a; padding: @b; } .hidden() { color: transparent; // asd } #hidden { .hidden; } #hidden1 { .hidden(); } .two-args { color: blue; .mixin(2px, 100%); .mixina(dotted, 2px); } .one-arg { .mixin(3px); } .no-parens { .mixin; } .no-args { .mixin(); } .var-args { @var: 9; .mixin(@var, (@var * 2)); } .multi-mix { .mixin(2px, 30%); .mixiny(4, 5); } .maxa(@arg1: 10, @arg2: #f00) { padding: (@arg1 * 2px); color: @arg2; } body { .maxa(15); } @glob: 5; .global-mixin(@a:2) { width: (@glob + @a); } .scope-mix { .global-mixin(3); } .nested-ruleset (@width: 200px) { width: @width; .column { margin: @width; } } .content { .nested-ruleset(600px); } // .same-var-name2(@radius) { radius: @radius; } .same-var-name(@radius) { .same-var-name2(@radius); } #same-var-name { .same-var-name(5px); } // .var-inside () { @var: 10px; width: @var; } #var-inside { .var-inside; } .mixin-arguments (@width: 0px, ...) { border: @arguments; width: @width; } .arguments { .mixin-arguments(1px, solid, black); } .arguments2 { .mixin-arguments(); } .arguments3 { .mixin-arguments; } .mixin-arguments2 (@width, @rest...) { border: @arguments; rest: @rest; width: @width; } .arguments4 { .mixin-arguments2(0, 1, 2, 3, 4); } // Edge cases .edge-case { .mixin-arguments("{"); } // Division vs. Literal Slash .border-radius(@r: 2px/5px) { border-radius: @r; } .slash-vs-math { .border-radius(); .border-radius(5px/10px); .border-radius((3px * 2)); } // semi-colon vs comma for delimiting .mixin-takes-one(@a) { one: @a; } .mixin-takes-two(@a; @b) { one: @a; two: @b; } .comma-vs-semi-colon { .mixin-takes-two(@a : a; @b : b, c); .mixin-takes-two(@a : d, e; @b : f); .mixin-takes-one(@a: g); .mixin-takes-one(@a : h;); .mixin-takes-one(i); .mixin-takes-one(j;); .mixin-takes-two(k, l); .mixin-takes-one(m, n;); .mixin-takes-two(o, p; q); .mixin-takes-two(r, s; t;); } .mixin-conflict(@a:defA, @b:defB, @c:defC) { three: @a, @b, @c; } .mixin-conflict(@a:defA, @b:defB, @c:defC, @d:defD) { four: @a, @b, @c, @d; } #named-conflict { .mixin-conflict(11, 12, 13, @a:a); .mixin-conflict(@a:a, 21, 22, 23); } @a: 3px; .mixin-default-arg(@a: 1px, @b: @a, @c: @b) { defaults: 1px 1px 1px; defaults: 2px 2px 2px; } .test-mixin-default-arg { .mixin-default-arg(); .mixin-default-arg(2px); } .mixin-comma-default1(@color; @padding; @margin: 2, 2, 2, 2) { margin: @margin; } .selector { .mixin-comma-default1(#33acfe; 4); } .mixin-comma-default2(@margin: 2, 2, 2, 2;) { margin: @margin; } .selector2 { .mixin-comma-default2(); } .mixin-comma-default3(@margin: 2, 2, 2, 2) { margin: @margin; } .selector3 { .mixin-comma-default3(4,2,2,2); }less.js-1.4.2/test/less/mixins-closure.less000066400000000000000000000004451217256642200207070ustar00rootroot00000000000000.scope { @var: 99px; .mixin () { width: @var; } } .class { .scope > .mixin; } .overwrite { @var: 0px; .scope > .mixin; } .nested { @var: 5px; .mixin () { width: @var; } .class { @var: 10px; .mixin; } } less.js-1.4.2/test/less/mixins-guards.less000066400000000000000000000070421217256642200205200ustar00rootroot00000000000000 // Stacking, functions.. .light (@a) when (lightness(@a) > 50%) { color: white; } .light (@a) when (lightness(@a) < 50%) { color: black; } .light (@a) { margin: 1px; } .light1 { .light(#ddd) } .light2 { .light(#444) } // Arguments against each other .max (@a, @b) when (@a > @b) { width: @a; } .max (@a, @b) when (@a < @b) { width: @b; } .max1 { .max(3, 6) } .max2 { .max(8, 1) } // Globals inside guards @g: auto; .glob (@a) when (@a = @g) { margin: @a @g; } .glob1 { .glob(auto) } // Other operators .ops (@a) when (@a >= 0) { height: gt-or-eq; } .ops (@a) when (@a =< 0) { height: lt-or-eq; } .ops (@a) when not(@a = 0) { height: not-eq; } .ops1 { .ops(0) } .ops2 { .ops(1) } .ops3 { .ops(-1) } // Scope and default values @a: auto; .default (@a: inherit) when (@a = inherit) { content: default; } .default1 { .default } // true & false keywords .test (@a) when (@a) { content: "true."; } .test (@a) when not (@a) { content: "false."; } .test1 { .test(true) } .test2 { .test(false) } .test3 { .test(1) } .test4 { .test(boo) } .test5 { .test("true") } // Boolean expressions .bool () when (true) and (false) { content: true and false } // FALSE .bool () when (true) and (true) { content: true and true } // TRUE .bool () when (true) { content: true } // TRUE .bool () when (false) and (false) { content: true } // FALSE .bool () when (false), (true) { content: false, true } // TRUE .bool () when (false) and (true) and (true), (true) { content: false and true and true, true } // TRUE .bool () when (true) and (true) and (false), (false) { content: true and true and false, false } // FALSE .bool () when (false), (true) and (true) { content: false, true and true } // TRUE .bool () when (false), (false), (true) { content: false, false, true } // TRUE .bool () when (false), (false) and (true), (false) { content: false, false and true, false } // FALSE .bool () when (false), (true) and (true) and (true), (false) { content: false, true and true and true, false } // TRUE .bool () when not (false) { content: not false } .bool () when not (true) and not (false) { content: not true and not false } .bool () when not (true) and not (true) { content: not true and not true } .bool () when not (false) and (false), not (false) { content: not false and false, not false } .bool1 { .bool } .equality-unit-test(@num) when (@num = 1%) { test: fail; } .equality-unit-test(@num) when (@num = 2) { test: pass; } .equality-units { .equality-unit-test(1px); .equality-unit-test(2px); } .colorguard(@col) when (@col = red) { content: is @col; } .colorguard(@col) when not (blue = @col) { content: is not blue its @col; } .colorguard(@col) {} .colorguardtest { .colorguard(red); .colorguard(blue); .colorguard(purple); } .stringguard(@str) when (@str = "theme1") { content: is theme1; } .stringguard(@str) when not ("theme2" = @str) { content: is not theme2; } .stringguard(@str) when (~"theme1" = @str) { content: is theme1 no quotes; } .stringguard(@str) {} .stringguardtest { .stringguard("theme1"); .stringguard("theme2"); .stringguard(theme1); } .mixin(...) { catch:all; } .mixin(@var) when (@var=4) { declare: 4; } .mixin(@var) when (@var=4px) { declare: 4px; } #tryNumberPx { .mixin(4px); }less.js-1.4.2/test/less/mixins-important.less000066400000000000000000000004071217256642200212460ustar00rootroot00000000000000 .mixin (9) { border: 9 !important; } .mixin (@a: 0) { border: @a; boxer: @a; .inner { test: @a; } // comment } .class { .mixin(1); .mixin(2) !important; .mixin(3); .mixin(4) !important; .mixin(5); .mixin !important; .mixin(9); } less.js-1.4.2/test/less/mixins-named-args.less000066400000000000000000000007731217256642200212550ustar00rootroot00000000000000.mixin (@a: 1px, @b: 50%) { width: (@a * 5); height: (@b - 1%); args: @arguments; } .mixin (@a: 1px, @b: 50%) when (@b > 75%){ text-align: center; } .named-arg { color: blue; .mixin(@b: 100%); } .class { @var: 20%; .mixin(@b: @var); } .all-args-wrong-args { .mixin(@b: 10%, @a: 2px); } .mixin2 (@a: 1px, @b: 50%, @c: 50) { width: (@a * 5); height: (@b - 1%); color: (#000000 + @c); } .named-args2 { .mixin2(3px, @c: 100); } .named-args3 { .mixin2(@b: 30%, @c: #123456); }less.js-1.4.2/test/less/mixins-nested.less000066400000000000000000000003341217256642200205120ustar00rootroot00000000000000.mix-inner (@var) { border-width: @var; } .mix (@a: 10) { .inner { height: (@a * 10); .innest { width: @a; .mix-inner((@a * 2)); } } } .class { .mix(30); } .class2 { .mix(60); } less.js-1.4.2/test/less/mixins-pattern.less000066400000000000000000000020451217256642200207060ustar00rootroot00000000000000.mixin (...) { variadic: true; } .mixin () { zero: 0; } .mixin (@a: 1px) { one: 1; } .mixin (@a) { one-req: 1; } .mixin (@a: 1px, @b: 2px) { two: 2; } .mixin (@a, @b, @c) { three-req: 3; } .mixin (@a: 1px, @b: 2px, @c: 3px) { three: 3; } .zero { .mixin(); } .one { .mixin(1); } .two { .mixin(1, 2); } .three { .mixin(1, 2, 3); } // .mixout ('left') { left: 1; } .mixout ('right') { right: 1; } .left { .mixout('left'); } .right { .mixout('right'); } // .border (@side, @width) { color: black; .border-side(@side, @width); } .border-side (left, @w) { border-left: @w; } .border-side (right, @w) { border-right: @w; } .border-right { .border(right, 4px); } .border-left { .border(left, 4px); } // .border-radius (@r) { both: (@r * 10); } .border-radius (@r, left) { left: @r; } .border-radius (@r, right) { right: @r; } .only-right { .border-radius(33, right); } .only-left { .border-radius(33, left); } .left-right { .border-radius(33); } less.js-1.4.2/test/less/mixins.less000066400000000000000000000031721217256642200172350ustar00rootroot00000000000000.mixin { border: 1px solid black; } .mixout { border-color: orange; } .borders { border-style: dashed; } #namespace { .borders { border-style: dotted; } .biohazard { content: "death"; .man { color: transparent; } } } #theme { > .mixin { background-color: grey; } } #container { color: black; .mixin; .mixout; #theme > .mixin; } #header { .milk { color: white; .mixin; #theme > .mixin; } #cookie { .chips { #namespace .borders; .calories { #container; } } .borders; } } .secure-zone { #namespace .biohazard .man; } .direct { #namespace > .borders; } .bo, .bar { width: 100%; } .bo { border: 1px; } .ar.bo.ca { color: black; } .jo.ki { background: none; } .amp { &.support { color: orange; } } .extended { .bo; .jo.ki; .amp.support; } .foo .bar { .bar; } .has_parents() { & .underParents { color: red; } } .has_parents(); .parent { .has_parents(); } .margin_between(@above, @below) { * + & { margin-top: @above; } legend + & { margin-top: 0; } & + * { margin-top: @below; } } h1 { .margin_between(25px, 10px); } h2 { .margin_between(20px, 8px); } h3 { .margin_between(15px, 5px); } .mixin_def(@url, @position){ background-image: @url; background-position: @position; } .error{ @s: "/"; .mixin_def( "@{s}a.png", center center); } .recursion() { color: black; } .test-rec { .recursion { .recursion(); } } .paddingFloat(@padding) { padding-left: @padding; } .button { .paddingFloat(((10px + 12) * 2)); &.large { .paddingFloat(((10em * 2) * 2)); } } less.js-1.4.2/test/less/operations.less000066400000000000000000000023451217256642200201120ustar00rootroot00000000000000#operations { color: (#110000 + #000011 + #001100); // #111111 height: (10px / 2px + 6px - 1px * 2); // 9px width: (2 * 4 - 5em); // 3em .spacing { height: (10px / 2px+6px-1px*2); width: (2 * 4-5em); } substraction: (20 - 10 - 5 - 5); // 0 division: (20 / 5 / 4); // 1 } @x: 4; @y: 12em; .with-variables { height: (@x + @y); // 16em width: (12 + @y); // 24em size: (5cm - @x); // 1cm } .with-functions { color: (rgb(200, 200, 200) / 2); color: (2 * hsl(0, 50%, 50%)); color: (rgb(10, 10, 10) + hsl(0, 50%, 50%)); } @z: -2; .negative { height: (2px + @z); // 0px width: (2px - @z); // 4px } .shorthands { padding: -1px 2px 0 -4px; // } .rem-dimensions { font-size: (20rem / 5 + 1.5rem); // 5.5rem } .colors { color: #123; // #112233 border-color: (#234 + #111111); // #334455 background-color: (#222222 - #fff); // #000000 .other { color: (2 * #111); // #222222 border-color: (#333333 / 3 + #111); // #222222 } } .negations { @var: 4px; variable: (-@var); // 4 variable1: (-@var + @var); // 0 variable2: (@var + -@var); // 0 variable3: (@var - -@var); // 8 variable4: (-@var - -@var); // 0 paren: (-(@var)); // -4px paren2: (-(2 + 2) * -@var); // 16 } less.js-1.4.2/test/less/parens.less000066400000000000000000000020111217256642200172050ustar00rootroot00000000000000.parens { @var: 1px; border: (@var * 2) solid black; margin: (@var * 1) (@var + 2) (4 * 4) 3; width: (6 * 6); padding: 2px (6 * 6px); } .more-parens { @var: (2 * 2); padding: (2 * @var) 4 4 (@var * 1px); width-all: ((@var * @var) * 6); width-first: ((@var * @var)) * 6; width-keep: (@var * @var) * 6; height-keep: (7 * 7) + (8 * 8); height-all: ((7 * 7) + (8 * 8)); height-parts: ((7 * 7)) + ((8 * 8)); margin-keep: (4 * (5 + 5) / 2) - (@var * 2); margin-parts: ((4 * (5 + 5) / 2)) - ((@var * 2)); margin-all: ((4 * (5 + 5) / 2) + (-(@var * 2))); border-radius-keep: 4px * (1 + 1) / @var + 3px; border-radius-parts: ((4px * (1 + 1))) / ((@var + 3px)); border-radius-all: (4px * (1 + 1) / @var + 3px); //margin: (6 * 6)px; } .negative { @var: 1; neg-var: -@var; // -1 ? neg-var-paren: -(@var); // -(1) ? } .nested-parens { width: 2 * (4 * (2 + (1 + 6))) - 1; height: ((2 + 3) * (2 + 3) / (9 - 4)) + 1; } .mixed-units { margin: 2px 4em 1 5pc; padding: (2px + 4px) 1em 2px 2; } less.js-1.4.2/test/less/rulesets.less000066400000000000000000000010011217256642200175610ustar00rootroot00000000000000#first > .one { > #second .two > #deux { width: 50%; #third { &:focus { color: black; #fifth { > #sixth { .seventh #eighth { + #ninth { color: purple; } } } } } height: 100%; } #fourth, #five, #six { color: #110000; .seven, .eight > #nine { border: 1px solid black; } #ten { color: red; } } } font-size: 2em; } less.js-1.4.2/test/less/scope.less000066400000000000000000000025761217256642200170460ustar00rootroot00000000000000@x: red; @x: blue; @z: transparent; @mix: none; .mixin { @mix: #989; } @mix: blue; .tiny-scope { color: @mix; // #989 .mixin; } .scope1 { @y: orange; @z: black; color: @x; // blue border-color: @z; // black .hidden { @x: #131313; } .scope2 { @y: red; color: @x; // blue .scope3 { @local: white; color: @y; // red border-color: @z; // black background-color: @local; // white } } } #namespace { .scoped_mixin() { @local-will-be-made-global: green; .scope { scoped-val: @local-will-be-made-global; } } } #namespace > .scoped_mixin(); .setHeight(@h) { @height: 1024px; } .useHeightInMixinCall(@h) { .useHeightInMixinCall { mixin-height: @h; } } @mainHeight: 50%; .setHeight(@mainHeight); .heightIsSet { height: @height; } .useHeightInMixinCall(@height); .importRuleset() { .imported { exists: true; } } .importRuleset(); .testImported { .imported; } @parameterDefault: 'top level'; @anotherVariable: 'top level'; //mixin uses top-level variables .mixinNoParam(@parameter: @parameterDefault) when (@parameter = 'top level') { default: @parameter; scope: @anotherVariable; sub-scope-only: @subScopeOnly; } #allAreUsedHere { //redefine top-level variables in different scope @parameterDefault: 'inside'; @anotherVariable: 'inside'; @subScopeOnly: 'inside'; //use the mixin .mixinNoParam(); }less.js-1.4.2/test/less/selectors.less000066400000000000000000000030551217256642200177310ustar00rootroot00000000000000h1, h2, h3 { a, p { &:hover { color: red; } } } #all { color: blue; } #the { color: blue; } #same { color: blue; } ul, li, div, q, blockquote, textarea { margin: 0; } td { margin: 0; padding: 0; } td, input { line-height: 1em; } a { color: red; &:hover { color: blue; } div & { color: green; } p & span { color: yellow; } } .foo { .bar, .baz { & .qux { display: block; } .qux & { display: inline; } .qux& { display: inline-block; } .qux & .biz { display: none; } } } .b { &.c { .a& { color: red; } } } .b { .c & { &.a { color: red; } } } .p { .foo &.bar { color: red; } } .p { .foo&.bar { color: red; } } .foo { .foo + & { background: amber; } & + & { background: amber; } } .foo, .bar { & + & { background: amber; } } .foo, .bar { a, b { & > & { background: amber; } } } .other ::fnord { color: red } .other::fnord { color: red } .other { ::bnord {color: red } &::bnord {color: red } } // selector interpolation @theme: blood; @selector: ~".@{theme}"; @{selector} { color:red; } @{selector}red { color: green; } .red { #@{theme}.@{theme}&.black { color:black; } } @num: 3; :nth-child(@{num}) { selector: interpolated; } .test { &:nth-child(odd):not(:nth-child(3)) { color: #ff0000; } } [prop], [prop="value@{num}"], [prop*="val@{num}"], [|prop~="val@{num}"], [*|prop$="val@{num}"], [ns|prop^="val@{num}"], [@{num}^="val@{num}"], [@{num}=@{num}], [@{num}] { attributes: yes; }less.js-1.4.2/test/less/static-urls/000077500000000000000000000000001217256642200173055ustar00rootroot00000000000000less.js-1.4.2/test/less/static-urls/urls.less000066400000000000000000000017571217256642200211740ustar00rootroot00000000000000@font-face { src: url("/fonts/garamond-pro.ttf"); src: local(Futura-Medium), url(fonts.svg#MyGeometricModern) format("svg"); } #shorthands { background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px; } #misc { background-image: url(images/image.jpg); } #data-uri { background: url(data:image/png;charset=utf-8;base64, kiVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/ k//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U kg9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC); background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==); background-image: url(http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700); } #svg-data-uri { background: transparent url('data:image/svg+xml, '); } .comma-delimited { background: url(bg.jpg) no-repeat, url(bg.png) repeat-x top left, url(bg); } .values { @a: 'Trebuchet'; url: url(@a); } @import "../import/import-and-relative-paths-test"; less.js-1.4.2/test/less/strings.less000066400000000000000000000017641217256642200174240ustar00rootroot00000000000000#strings { background-image: url("http://son-of-a-banana.com"); quotes: "~" "~"; content: "#*%:&^,)!.(~*})"; empty: ""; brackets: "{" "}"; escapes: "\"hello\" \\world"; escapes2: "\"llo"; } #comments { content: "/* hello */ // not-so-secret"; } #single-quote { quotes: "'" "'"; content: '""#!&""'; empty: ''; semi-colon: ';'; } #escaped { filter: ~"DX.Transform.MS.BS.filter(opacity=50)"; } #one-line { image: url(http://tooks.com) } #crazy { image: url(http://), "}", url("http://}") } #interpolation { @var: '/dev'; url: "http://lesscss.org@{var}/image.jpg"; @var2: 256; url2: "http://lesscss.org/image-@{var2}.jpg"; @var3: #456; url3: "http://lesscss.org@{var3}"; @var4: hello; url4: "http://lesscss.org/@{var4}"; @var5: 54.4px; url5: "http://lesscss.org/@{var5}"; } // multiple calls with string interpolation .mix-mul (@a: green) { color: ~"@{a}"; } .mix-mul-class { .mix-mul(blue); .mix-mul(red); .mix-mul(black); .mix-mul(orange); } less.js-1.4.2/test/less/urls.less000066400000000000000000000030201217256642200167030ustar00rootroot00000000000000@font-face { src: url("/fonts/garamond-pro.ttf"); src: local(Futura-Medium), url(fonts.svg#MyGeometricModern) format("svg"); } #shorthands { background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px; background: url("img.jpg") center / 100px; background: #fff url(image.png) center / 1px 100px repeat-x scroll content-box padding-box; } #misc { background-image: url(images/image.jpg); } #data-uri { background: url(data:image/png;charset=utf-8;base64, kiVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/ k//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U kg9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC); background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==); background-image: url(http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700); } #svg-data-uri { background: transparent url('data:image/svg+xml, '); } .comma-delimited { background: url(bg.jpg) no-repeat, url(bg.png) repeat-x top left, url(bg); } .values { @a: 'Trebuchet'; url: url(@a); } @import "import/import-and-relative-paths-test"; #data-uri { uri: data-uri('image/jpeg;base64', '../data/image.jpg'); } #data-uri-guess { uri: data-uri('../data/image.jpg'); } #data-uri-ascii { uri-1: data-uri('text/html', '../data/page.html'); uri-2: data-uri('../data/page.html'); } #data-uri-toobig { uri: data-uri('../data/data-uri-fail.png'); } .add_an_import(@file_to_import) { @import "@{file_to_import}"; } .add_an_import("file.css"); less.js-1.4.2/test/less/variables.less000066400000000000000000000025111217256642200176720ustar00rootroot00000000000000@a: 2; @x: (@a * @a); @y: (@x + 1); @z: (@x * 2 + @y); @var: -1; .variables { width: (@z + 1cm); // 14cm } @b: @a * 10; @c: #888; @fonts: "Trebuchet MS", Verdana, sans-serif; @f: @fonts; @quotes: "~" "~"; @q: @quotes; @onePixel: 1px; .variables { height: (@b + @x + 0px); // 24px color: @c; font-family: @f; quotes: @q; } .redef { @var: 0; .inition { @var: 4; @var: 2; three: @var; @var: 3; } zero: @var; } .values { minus-one: @var; @a: 'Trebuchet'; @multi: 'A', B, C; font-family: @a, @a, @a; color: @c !important; multi: something @multi, @a; } .variable-names { @var: 'hello'; @name: 'var'; name: @@name; } .alpha { @var: 42; filter: alpha(opacity=@var); } .polluteMixin() { @a: 'pollution'; } .testPollution { @a: 'no-pollution'; a: @a; .polluteMixin(); a: @a; } .units { width: @onePixel; same-unit-as-previously: (@onePixel / @onePixel); square-pixel-divided: (@onePixel * @onePixel / @onePixel); odd-unit: unit((@onePixel * 4em / 2cm)); percentage: (10 * 50%); pixels: (50px * 10); conversion-metric-a: (20mm + 1cm); conversion-metric-b: (1cm + 20mm); conversion-imperial: (1in + 72pt + 6pc); custom-unit: (42octocats * 10); custom-unit-cancelling: (8cats * 9dogs / 4cats); mix-units: (1px + 1em); invalid-units: (1px * 1px); } less.js-1.4.2/test/less/whitespace.less000066400000000000000000000010401217256642200200520ustar00rootroot00000000000000 .whitespace { color: white; } .whitespace { color: white; } .whitespace { color: white; } .whitespace{color:white;} .whitespace { color : white ; } .white, .space, .mania { color: white; } .no-semi-column { color: white } .no-semi-column { color: white; white-space: pre } .no-semi-column {border: 2px solid white} .newlines { background: the, great, wall; border: 2px solid black; } .empty { } .sel .newline_ws .tab_ws { color: white; background-position: 45 -23; }