├── log └── .gitkeep ├── public └── root │ ├── robots.txt │ ├── favicon.ico │ └── snippet.png ├── assets ├── vendor │ ├── bootstrap │ │ ├── README.md │ │ ├── src │ │ │ ├── js │ │ │ │ ├── .jshintrc │ │ │ │ ├── bootstrap-transition.js │ │ │ │ ├── bootstrap-alert.js │ │ │ │ ├── bootstrap-button.js │ │ │ │ └── bootstrap-popover.js │ │ │ └── less │ │ │ │ ├── layouts.less │ │ │ │ ├── component-animations.less │ │ │ │ ├── utilities.less │ │ │ │ ├── breadcrumbs.less │ │ │ │ ├── grid.less │ │ │ │ ├── hero-unit.less │ │ │ │ ├── responsive-768px-979px.less │ │ │ │ ├── wells.less │ │ │ │ ├── responsive-1200px-min.less │ │ │ │ ├── close.less │ │ │ │ ├── accordion.less │ │ │ │ ├── pager.less │ │ │ │ ├── scaffolding.less │ │ │ │ ├── responsive.less │ │ │ │ ├── responsive-utilities.less │ │ │ │ ├── thumbnails.less │ │ │ │ ├── alerts.less │ │ │ │ ├── code.less │ │ │ │ ├── pagination.less │ │ │ │ ├── bootstrap.less │ │ │ │ ├── tooltip.less │ │ │ │ ├── labels-badges.less │ │ │ │ ├── modals.less │ │ │ │ ├── carousel.less │ │ │ │ ├── progress-bars.less │ │ │ │ ├── reset.less │ │ │ │ └── popovers.less │ │ ├── bootstrap.js │ │ ├── bootstrap-responsive.less │ │ ├── bootstrap.less │ │ └── var_override.less │ ├── fontello │ │ ├── src │ │ │ ├── font │ │ │ │ ├── icons.eot │ │ │ │ ├── icons.ttf │ │ │ │ ├── icons.woff │ │ │ │ └── icons.svg │ │ │ ├── css │ │ │ │ ├── icons-codes.css │ │ │ │ ├── icons-ie7-codes.css │ │ │ │ ├── icons-ie7.css │ │ │ │ └── icons.css │ │ │ ├── LICENSE.txt │ │ │ ├── config.json │ │ │ └── README.txt │ │ └── icons.css.ejs │ ├── jquery-ui │ │ ├── README.md │ │ └── images │ │ │ ├── ui-icons_222222_256x240.png │ │ │ ├── ui-icons_2e83ff_256x240.png │ │ │ ├── ui-icons_454545_256x240.png │ │ │ ├── ui-icons_888888_256x240.png │ │ │ ├── ui-icons_cd0a0a_256x240.png │ │ │ ├── ui-icons_f6cf3b_256x240.png │ │ │ ├── ui-bg_flat_0_aaaaaa_40x100.png │ │ │ ├── ui-bg_glass_55_fbf9ee_1x400.png │ │ │ ├── ui-bg_glass_65_ffffff_1x400.png │ │ │ ├── ui-bg_glass_75_dadada_1x400.png │ │ │ ├── ui-bg_glass_75_e6e6e6_1x400.png │ │ │ ├── ui-bg_glass_75_ffffff_1x400.png │ │ │ ├── ui-bg_inset-soft_95_fef1ec_1x100.png │ │ │ └── ui-bg_highlight-soft_75_cccccc_1x100.png │ ├── jquery.noty │ │ ├── noty.css │ │ └── src │ │ │ └── css │ │ │ └── jquery.noty.css │ └── jade │ │ └── runtime.js ├── embedded_fonts │ ├── entypo.eot │ ├── entypo.ttf │ ├── iconic.eot │ ├── iconic.ttf │ ├── brandico.eot │ ├── brandico.ttf │ ├── entypo.woff │ ├── fontello.eot │ ├── fontello.ttf │ ├── iconic.woff │ ├── typicons.eot │ ├── typicons.ttf │ ├── brandico.woff │ ├── fontawesome.eot │ ├── fontawesome.ttf │ ├── fontello.woff │ ├── modernpics.eot │ ├── modernpics.ttf │ ├── modernpics.woff │ ├── typicons.woff │ ├── websymbols.eot │ ├── websymbols.ttf │ ├── websymbols.woff │ ├── fontawesome.woff │ ├── fontface-fontello.css.ejs │ └── fontface-embedded.css.ejs ├── javascripts │ ├── app.js │ ├── loader.js.ejs │ └── nodeca.js.ejs └── stylesheets │ ├── ui │ ├── tabs.styl │ ├── panes │ │ ├── preview.styl │ │ ├── codes_editor.styl │ │ └── selector.styl │ └── toolbar.styl │ ├── variables.styl │ ├── bootstrap_override.styl │ └── app.styl ├── views ├── errors │ ├── read-config.jade │ ├── fatal.jade │ ├── version-mismatch.jade │ ├── no-file-reader.jade │ └── max-glyphs.jade ├── preview │ └── glyph.jade ├── result │ └── download-banner.jade ├── code-editor │ └── glyph.jade ├── selector │ ├── font-item.jade │ └── font-info.jade └── app.jade ├── config ├── production.yml ├── router.yml ├── application.yml └── logger.yml ├── .jshintignore ├── .gitignore ├── support ├── font-templates │ ├── css │ │ ├── css-ie7-codes.jade │ │ ├── css-codes.jade │ │ ├── css-ie7.jade │ │ └── css.jade │ ├── LICENSE.jade │ ├── demo.jade │ └── README.txt └── forever.sh ├── lib ├── filters.js ├── init │ ├── server │ │ ├── http │ │ │ └── compression.js │ │ └── http.js │ ├── assets │ │ ├── build_i18n_files.js │ │ ├── compile_views.js │ │ ├── mincer.js │ │ ├── mincer │ │ │ ├── manifest.js │ │ │ ├── stylus │ │ │ │ └── import-dir.js │ │ │ └── environment.js │ │ └── build_api_tree.js │ ├── assets.js │ ├── cronjob.js │ └── server.js ├── filters │ ├── renderer │ │ └── helpers.js │ ├── fix_vhost.js │ └── renderer.js ├── stats.js ├── stylus │ └── import-dir.js └── env.js ├── etc ├── init │ └── fontello.conf └── certs │ ├── fontello-dev.cert │ └── fontello-dev.key ├── DEV-NOTES.md ├── client ├── models │ ├── source_font.js │ ├── font.js │ └── glyph.js ├── ui │ ├── panes │ │ ├── selector.js │ │ ├── codes_editor.js │ │ ├── preview.js │ │ ├── selector_glyph.js │ │ ├── preview_glyph.js │ │ ├── selector_font.js │ │ └── codes_editor_glyph.js │ ├── tabs.js │ └── toolbar.js ├── util.js ├── init.js └── render.js ├── cli ├── server.js └── font_config.js ├── shared ├── getByPath.js └── render.js ├── .gitmodules ├── server ├── app.js ├── assets.js └── static.js ├── LICENSE ├── INSTALL.md ├── fontello.js ├── package.json ├── bin ├── tpl-render.js ├── font_copy_to_assets.py ├── build_embedded_fonts_css.py ├── build_common_font.py └── generate_font.sh ├── HISTORY.md └── README.md /log/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/root/robots.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/vendor/bootstrap/README.md: -------------------------------------------------------------------------------- 1 | To update - just refresh files in `./src` fonder. 2 | -------------------------------------------------------------------------------- /views/errors/read-config.jade: -------------------------------------------------------------------------------- 1 | | Failed read your config file: #{self.error}. 2 | -------------------------------------------------------------------------------- /config/production.yml: -------------------------------------------------------------------------------- 1 | ^production: 2 | listen: 3 | host: fontello.com 4 | port: 80 5 | -------------------------------------------------------------------------------- /public/root/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msurguy/fontello/master/public/root/favicon.ico -------------------------------------------------------------------------------- /public/root/snippet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msurguy/fontello/master/public/root/snippet.png -------------------------------------------------------------------------------- /assets/embedded_fonts/entypo.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msurguy/fontello/master/assets/embedded_fonts/entypo.eot -------------------------------------------------------------------------------- /assets/embedded_fonts/entypo.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msurguy/fontello/master/assets/embedded_fonts/entypo.ttf -------------------------------------------------------------------------------- /assets/embedded_fonts/iconic.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msurguy/fontello/master/assets/embedded_fonts/iconic.eot -------------------------------------------------------------------------------- /assets/embedded_fonts/iconic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msurguy/fontello/master/assets/embedded_fonts/iconic.ttf -------------------------------------------------------------------------------- /views/preview/glyph.jade: -------------------------------------------------------------------------------- 1 | span.font-fontello.icon #{self.chr} 2 | span.prefix icon- 3 | span.glyph-name #{self.css} 4 | -------------------------------------------------------------------------------- /assets/embedded_fonts/brandico.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msurguy/fontello/master/assets/embedded_fonts/brandico.eot -------------------------------------------------------------------------------- /assets/embedded_fonts/brandico.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msurguy/fontello/master/assets/embedded_fonts/brandico.ttf -------------------------------------------------------------------------------- /assets/embedded_fonts/entypo.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msurguy/fontello/master/assets/embedded_fonts/entypo.woff -------------------------------------------------------------------------------- /assets/embedded_fonts/fontello.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msurguy/fontello/master/assets/embedded_fonts/fontello.eot -------------------------------------------------------------------------------- /assets/embedded_fonts/fontello.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msurguy/fontello/master/assets/embedded_fonts/fontello.ttf -------------------------------------------------------------------------------- /assets/embedded_fonts/iconic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msurguy/fontello/master/assets/embedded_fonts/iconic.woff -------------------------------------------------------------------------------- /assets/embedded_fonts/typicons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msurguy/fontello/master/assets/embedded_fonts/typicons.eot -------------------------------------------------------------------------------- /assets/embedded_fonts/typicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msurguy/fontello/master/assets/embedded_fonts/typicons.ttf -------------------------------------------------------------------------------- /assets/embedded_fonts/brandico.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msurguy/fontello/master/assets/embedded_fonts/brandico.woff -------------------------------------------------------------------------------- /assets/embedded_fonts/fontawesome.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msurguy/fontello/master/assets/embedded_fonts/fontawesome.eot -------------------------------------------------------------------------------- /assets/embedded_fonts/fontawesome.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msurguy/fontello/master/assets/embedded_fonts/fontawesome.ttf -------------------------------------------------------------------------------- /assets/embedded_fonts/fontello.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msurguy/fontello/master/assets/embedded_fonts/fontello.woff -------------------------------------------------------------------------------- /assets/embedded_fonts/modernpics.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msurguy/fontello/master/assets/embedded_fonts/modernpics.eot -------------------------------------------------------------------------------- /assets/embedded_fonts/modernpics.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msurguy/fontello/master/assets/embedded_fonts/modernpics.ttf -------------------------------------------------------------------------------- /assets/embedded_fonts/modernpics.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msurguy/fontello/master/assets/embedded_fonts/modernpics.woff -------------------------------------------------------------------------------- /assets/embedded_fonts/typicons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msurguy/fontello/master/assets/embedded_fonts/typicons.woff -------------------------------------------------------------------------------- /assets/embedded_fonts/websymbols.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msurguy/fontello/master/assets/embedded_fonts/websymbols.eot -------------------------------------------------------------------------------- /assets/embedded_fonts/websymbols.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msurguy/fontello/master/assets/embedded_fonts/websymbols.ttf -------------------------------------------------------------------------------- /assets/embedded_fonts/websymbols.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msurguy/fontello/master/assets/embedded_fonts/websymbols.woff -------------------------------------------------------------------------------- /assets/embedded_fonts/fontawesome.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msurguy/fontello/master/assets/embedded_fonts/fontawesome.woff -------------------------------------------------------------------------------- /assets/vendor/fontello/src/font/icons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msurguy/fontello/master/assets/vendor/fontello/src/font/icons.eot -------------------------------------------------------------------------------- /assets/vendor/fontello/src/font/icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msurguy/fontello/master/assets/vendor/fontello/src/font/icons.ttf -------------------------------------------------------------------------------- /assets/vendor/fontello/src/font/icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msurguy/fontello/master/assets/vendor/fontello/src/font/icons.woff -------------------------------------------------------------------------------- /assets/vendor/jquery-ui/README.md: -------------------------------------------------------------------------------- 1 | custom jquery-ui. contains only: 2 | 3 | - core 4 | - widget 5 | - mouse 6 | - selectable 7 | - slider 8 | -------------------------------------------------------------------------------- /views/errors/fatal.jade: -------------------------------------------------------------------------------- 1 | | Internal error happened during processing your request: 2 | | "#{self.error}". Please, try again later. 3 | -------------------------------------------------------------------------------- /views/errors/version-mismatch.jade: -------------------------------------------------------------------------------- 1 | | Application is outdated. Please 2 | | reload 3 | | the page. 4 | -------------------------------------------------------------------------------- /.jshintignore: -------------------------------------------------------------------------------- 1 | .git/ 2 | doc/ 3 | node_modules/ 4 | tmp/ 5 | bin/ 6 | fonts/ 7 | assets/vendor/ 8 | assets/embedded_fonts/ 9 | public/ 10 | src/ 11 | support/ 12 | -------------------------------------------------------------------------------- /assets/vendor/jquery-ui/images/ui-icons_222222_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msurguy/fontello/master/assets/vendor/jquery-ui/images/ui-icons_222222_256x240.png -------------------------------------------------------------------------------- /assets/vendor/jquery-ui/images/ui-icons_2e83ff_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msurguy/fontello/master/assets/vendor/jquery-ui/images/ui-icons_2e83ff_256x240.png -------------------------------------------------------------------------------- /assets/vendor/jquery-ui/images/ui-icons_454545_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msurguy/fontello/master/assets/vendor/jquery-ui/images/ui-icons_454545_256x240.png -------------------------------------------------------------------------------- /assets/vendor/jquery-ui/images/ui-icons_888888_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msurguy/fontello/master/assets/vendor/jquery-ui/images/ui-icons_888888_256x240.png -------------------------------------------------------------------------------- /assets/vendor/jquery-ui/images/ui-icons_cd0a0a_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msurguy/fontello/master/assets/vendor/jquery-ui/images/ui-icons_cd0a0a_256x240.png -------------------------------------------------------------------------------- /assets/vendor/jquery-ui/images/ui-icons_f6cf3b_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msurguy/fontello/master/assets/vendor/jquery-ui/images/ui-icons_f6cf3b_256x240.png -------------------------------------------------------------------------------- /assets/vendor/jquery-ui/images/ui-bg_flat_0_aaaaaa_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msurguy/fontello/master/assets/vendor/jquery-ui/images/ui-bg_flat_0_aaaaaa_40x100.png -------------------------------------------------------------------------------- /assets/vendor/jquery-ui/images/ui-bg_glass_55_fbf9ee_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msurguy/fontello/master/assets/vendor/jquery-ui/images/ui-bg_glass_55_fbf9ee_1x400.png -------------------------------------------------------------------------------- /assets/vendor/jquery-ui/images/ui-bg_glass_65_ffffff_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msurguy/fontello/master/assets/vendor/jquery-ui/images/ui-bg_glass_65_ffffff_1x400.png -------------------------------------------------------------------------------- /assets/vendor/jquery-ui/images/ui-bg_glass_75_dadada_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msurguy/fontello/master/assets/vendor/jquery-ui/images/ui-bg_glass_75_dadada_1x400.png -------------------------------------------------------------------------------- /assets/vendor/jquery-ui/images/ui-bg_glass_75_e6e6e6_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msurguy/fontello/master/assets/vendor/jquery-ui/images/ui-bg_glass_75_e6e6e6_1x400.png -------------------------------------------------------------------------------- /assets/vendor/jquery-ui/images/ui-bg_glass_75_ffffff_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msurguy/fontello/master/assets/vendor/jquery-ui/images/ui-bg_glass_75_ffffff_1x400.png -------------------------------------------------------------------------------- /views/result/download-banner.jade: -------------------------------------------------------------------------------- 1 | | Are you designer? You can help us improve fontello! 2 | 3 | -------------------------------------------------------------------------------- /assets/vendor/jquery-ui/images/ui-bg_inset-soft_95_fef1ec_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msurguy/fontello/master/assets/vendor/jquery-ui/images/ui-bg_inset-soft_95_fef1ec_1x100.png -------------------------------------------------------------------------------- /assets/vendor/jquery-ui/images/ui-bg_highlight-soft_75_cccccc_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msurguy/fontello/master/assets/vendor/jquery-ui/images/ui-bg_highlight-soft_75_cccccc_1x100.png -------------------------------------------------------------------------------- /views/code-editor/glyph.jade: -------------------------------------------------------------------------------- 1 | .top 2 | span.char-editable !{self.top} 3 | 4 | .center.font-fontello !{self.chr} 5 | 6 | .bottom 7 | span.code-prefix U+ 8 | span.code-editable !{self.bottom} 9 | -------------------------------------------------------------------------------- /views/selector/font-item.jade: -------------------------------------------------------------------------------- 1 | h2.src-font-head 2 | a.label.label-important.font-info(href="#") info 3 | a.src-font-name._collapser(href="#") #{self.fontname} 4 | ul.unstyled.font-glyphs.font-fontello 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | config/*.local.yml 2 | node_modules/ 3 | doc/ 4 | tmp/ 5 | log/ 6 | 7 | *.log 8 | *.swp 9 | *.sublime-project 10 | *.sublime-workspace 11 | 12 | /public/assets/ 13 | /public/download/ 14 | -------------------------------------------------------------------------------- /assets/vendor/fontello/src/css/icons-codes.css: -------------------------------------------------------------------------------- 1 | 2 | .icon-settings:before { content: '\2699'; } /* '⚙' */ 3 | .icon-download:before { content: '\f000'; } /* '' */ 4 | .icon-search:before { content: '\f001'; } /* '' */ -------------------------------------------------------------------------------- /views/errors/no-file-reader.jade: -------------------------------------------------------------------------------- 1 | | Config importer requires modern browser. 2 | | Please, upgrade 3 | | your browser to be able import your previous configurations. 4 | -------------------------------------------------------------------------------- /views/errors/max-glyphs.jade: -------------------------------------------------------------------------------- 1 | | You can't select more than #{self.max} icons at once. 2 | | If you have a real use-case, please, 3 | | create 4 | | ticket in issue tracker. 5 | -------------------------------------------------------------------------------- /assets/vendor/bootstrap/src/js/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "validthis": true, 3 | "laxcomma" : true, 4 | "laxbreak" : true, 5 | "browser" : true, 6 | "debug" : true, 7 | "boss" : true, 8 | "expr" : true, 9 | "asi" : true 10 | } -------------------------------------------------------------------------------- /assets/vendor/jquery.noty/noty.css: -------------------------------------------------------------------------------- 1 | /* 2 | *= require ./src/css/jquery.noty 3 | *= require ./src/css/noty_theme_twitter 4 | */ 5 | 6 | .noty_bar.noty_theme_twitter.noty_information { 7 | font-size: 24px; 8 | font-weight: bold; 9 | padding: 10px; 10 | } -------------------------------------------------------------------------------- /assets/vendor/fontello/src/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Font license info 2 | 3 | 4 | ## Entypo 5 | 6 | Copyright (C) 2012 by Daniel Bruce 7 | 8 | Author: Daniel Buce 9 | License: SIL (http://scripts.sil.org/OFL) 10 | Homepage: http://www.entypo.com 11 | 12 | 13 | -------------------------------------------------------------------------------- /config/router.yml: -------------------------------------------------------------------------------- 1 | router: 2 | map: 3 | app: 4 | "/": ~ 5 | font.download: 6 | "/download/{file}": 7 | file: /.+/ 8 | assets: 9 | "/assets/{path}": 10 | path: /.+/ 11 | static: 12 | "/{file}": 13 | file: /favicon.ico|robots.txt|snippet.png|fuckup.log/ 14 | -------------------------------------------------------------------------------- /support/font-templates/css/css-ie7-codes.jade: -------------------------------------------------------------------------------- 1 | - var i, g, css, hex, chr 2 | - for (i in glyphs) 3 | - g = glyphs[i] 4 | - css = meta.css_prefix + g.css 5 | - hex = g.code.toString(16) 6 | - chr = unichr(g.code) 7 | != '\n' 8 | | .#{css} { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#x#{hex}; '); } 9 | -------------------------------------------------------------------------------- /assets/vendor/fontello/src/css/icons-ie7-codes.css: -------------------------------------------------------------------------------- 1 | 2 | .icon-settings { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '⚙ '); } 3 | .icon-download { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } 4 | .icon-search { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -------------------------------------------------------------------------------- /lib/filters.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | var path = require('path'); 5 | var fs = require('fs'); 6 | 7 | 8 | //////////////////////////////////////////////////////////////////////////////// 9 | 10 | 11 | fs.readdirSync(path.join(__dirname, 'filters')).forEach(function (file) { 12 | if ('.js' === path.extname(file)) { 13 | require(path.join(__dirname, 'filters', file)); 14 | } 15 | }); 16 | -------------------------------------------------------------------------------- /support/font-templates/LICENSE.jade: -------------------------------------------------------------------------------- 1 | | Font license info 2 | != '\n\n\n' 3 | 4 | - var i, f 5 | - for (i in used_fonts) 6 | - f = used_fonts[i] 7 | | ## #{f.font.fullname} 8 | != '\n\n' 9 | | #{f.font.copyright} 10 | != '\n\n' 11 | | Author: #{f.meta.author} 12 | | License: #{f.meta.license} (#{f.meta.license_url}) 13 | | Homepage: #{f.meta.homepage} 14 | != '\n\n\n' 15 | -------------------------------------------------------------------------------- /etc/init/fontello.conf: -------------------------------------------------------------------------------- 1 | # fontello.com upstart script 2 | description "Fontello - Iconic fonts scissors" 3 | author "Nodeca" 4 | 5 | start on startup 6 | stop on shutdown 7 | 8 | # production|staging|development 9 | env NODECA_ENV="production" 10 | 11 | script 12 | /bin/bash <&1 17 | EOT 18 | end script 19 | -------------------------------------------------------------------------------- /assets/vendor/bootstrap/src/less/layouts.less: -------------------------------------------------------------------------------- 1 | // 2 | // Layouts 3 | // -------------------------------------------------- 4 | 5 | 6 | // Container (centered, fixed-width layouts) 7 | .container { 8 | .container-fixed(); 9 | } 10 | 11 | // Fluid layouts (left aligned, with sidebar, min- & max-width content) 12 | .container-fluid { 13 | padding-right: @gridGutterWidth; 14 | padding-left: @gridGutterWidth; 15 | .clearfix(); 16 | } -------------------------------------------------------------------------------- /assets/vendor/bootstrap/src/less/component-animations.less: -------------------------------------------------------------------------------- 1 | // 2 | // Component animations 3 | // -------------------------------------------------- 4 | 5 | 6 | .fade { 7 | opacity: 0; 8 | .transition(opacity .15s linear); 9 | &.in { 10 | opacity: 1; 11 | } 12 | } 13 | 14 | .collapse { 15 | position: relative; 16 | height: 0; 17 | overflow: hidden; 18 | .transition(height .35s ease); 19 | &.in { 20 | height: auto; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /assets/javascripts/app.js: -------------------------------------------------------------------------------- 1 | //= require store 2 | //= require jquery/jquery 3 | //= require jquery-ui/jquery-ui 4 | //= require jquery.noty/src/js/jquery.noty 5 | //= require underscore 6 | //= require bootstrap/bootstrap 7 | //= require backbone 8 | //= require jquery.collapser 9 | //= require jquery.inplaceEditor 10 | //= require jade/runtime 11 | //= require babelfish-runtime 12 | //= require nodeca 13 | //= require i18n 14 | //= require views 15 | //= require api 16 | -------------------------------------------------------------------------------- /config/application.yml: -------------------------------------------------------------------------------- 1 | app: 2 | builder_concurrency: 4 # Default: amount of CPUs 3 | max_glyphs: ~ # Max allowed glyphs per download. Unlimited if null. 4 | glyph_size: 5 | min: 12 # minimal size 6 | val: 16 # default size 7 | max: 30 # miximum size 8 | autoguess_charcode: 9 | min: 0xe800 10 | max: 0xf8ff 11 | locales: 12 | enabled: [en] 13 | default: en 14 | listen: 15 | host: localhost 16 | port: 3000 17 | -------------------------------------------------------------------------------- /assets/vendor/bootstrap/src/less/utilities.less: -------------------------------------------------------------------------------- 1 | // 2 | // Utility classes 3 | // -------------------------------------------------- 4 | 5 | 6 | // Quick floats 7 | .pull-right { 8 | float: right; 9 | } 10 | .pull-left { 11 | float: left; 12 | } 13 | 14 | // Toggling content 15 | .hide { 16 | display: none; 17 | } 18 | .show { 19 | display: block; 20 | } 21 | 22 | // Visibility 23 | .invisible { 24 | visibility: hidden; 25 | } 26 | 27 | // For Affix plugin 28 | .affix { 29 | position: fixed; 30 | } 31 | -------------------------------------------------------------------------------- /views/app.jade: -------------------------------------------------------------------------------- 1 | .container 2 | #myTabContent.tab-content 3 | // tab0 `Loading` 4 | #loading.tab-pane.fade.active.in Loading... 5 | 6 | // tab1 `Select 7 | #selector.tab-pane.fade 8 | ul#selector-fonts.unstyled 9 | 10 | // tab2 `Preview` 11 | #preview.tab-pane.fade 12 | p.note Click glyph name to edit 13 | #preview-font.row 14 | 15 | // tab3 `Download` 16 | #codes-editor.tab-pane.fade 17 | p.note Click symbol codes on black lines to edit 18 | #result-font 19 | -------------------------------------------------------------------------------- /support/font-templates/css/css-codes.jade: -------------------------------------------------------------------------------- 1 | - if (_.any(glyphs, function (g) { return 0xffff < g.code; })) 2 | | @charset "UTF-8"; 3 | != '\n' 4 | != '\n' 5 | 6 | - var i, g, css, hex, chr 7 | - for (i in glyphs) 8 | - g = glyphs[i] 9 | - css = meta.css_prefix + g.css 10 | - hex = '\\' + g.code.toString(16) 11 | - chr = unichr(g.code) 12 | != '\n' 13 | - if (0xffff < g.code) 14 | | .#{css}:before { content: '#{chr}'; } /* '#{hex}' */ 15 | - else 16 | | .#{css}:before { content: '#{hex}'; } /* '#{chr}' */ 17 | -------------------------------------------------------------------------------- /assets/vendor/bootstrap/src/less/breadcrumbs.less: -------------------------------------------------------------------------------- 1 | // 2 | // Breadcrumbs 3 | // -------------------------------------------------- 4 | 5 | 6 | .breadcrumb { 7 | padding: 8px 15px; 8 | margin: 0 0 @baseLineHeight; 9 | list-style: none; 10 | background-color: #f5f5f5; 11 | .border-radius(4px); 12 | li { 13 | display: inline-block; 14 | .ie7-inline-block(); 15 | text-shadow: 0 1px 0 @white; 16 | } 17 | .divider { 18 | padding: 0 5px; 19 | color: #ccc; 20 | } 21 | .active { 22 | color: @grayLight; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /assets/embedded_fonts/fontface-fontello.css.ejs: -------------------------------------------------------------------------------- 1 | .font-fontello { font-family: 'fontello'; } 2 | 3 | @font-face { 4 | font-family: 'fontello'; 5 | src: url('<%= asset_path("fontello.eot") %>'); 6 | src: url('<%= asset_path("fontello.eot") %>?#iefix') format('embedded-opentype'), 7 | url('<%= asset_path("fontello.woff") %>') format('woff'), 8 | url('<%= asset_path("fontello.ttf") %>') format('truetype'), 9 | url('<%= asset_path("fontello.svg") %>#entypo') format('svg'); 10 | font-weight: normal; 11 | font-style: normal; 12 | } 13 | -------------------------------------------------------------------------------- /assets/vendor/bootstrap/src/less/grid.less: -------------------------------------------------------------------------------- 1 | // 2 | // Grid system 3 | // -------------------------------------------------- 4 | 5 | 6 | // Fixed (940px) 7 | #grid > .core(@gridColumnWidth, @gridGutterWidth); 8 | 9 | // Fluid (940px) 10 | #grid > .fluid(@fluidGridColumnWidth, @fluidGridGutterWidth); 11 | 12 | // Reset utility classes due to specificity 13 | [class*="span"].hide, 14 | .row-fluid [class*="span"].hide { 15 | display: none; 16 | } 17 | 18 | [class*="span"].pull-right, 19 | .row-fluid [class*="span"].pull-right { 20 | float: right; 21 | } 22 | -------------------------------------------------------------------------------- /assets/vendor/bootstrap/src/less/hero-unit.less: -------------------------------------------------------------------------------- 1 | // 2 | // Hero unit 3 | // -------------------------------------------------- 4 | 5 | 6 | .hero-unit { 7 | padding: 60px; 8 | margin-bottom: 30px; 9 | background-color: @heroUnitBackground; 10 | .border-radius(6px); 11 | h1 { 12 | margin-bottom: 0; 13 | font-size: 60px; 14 | line-height: 1; 15 | color: @heroUnitHeadingColor; 16 | letter-spacing: -1px; 17 | } 18 | p { 19 | font-size: 18px; 20 | font-weight: 200; 21 | line-height: @baseLineHeight * 1.5; 22 | color: @heroUnitLeadColor; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /assets/vendor/bootstrap/src/less/responsive-768px-979px.less: -------------------------------------------------------------------------------- 1 | // 2 | // Responsive: Tablet to desktop 3 | // -------------------------------------------------- 4 | 5 | 6 | @media (min-width: 768px) and (max-width: 979px) { 7 | 8 | // Fixed grid 9 | #grid > .core(@gridColumnWidth768, @gridGutterWidth768); 10 | 11 | // Fluid grid 12 | #grid > .fluid(@fluidGridColumnWidth768, @fluidGridGutterWidth768); 13 | 14 | // Input grid 15 | #grid > .input(@gridColumnWidth768, @gridGutterWidth768); 16 | 17 | // No need to reset .thumbnails here since it's the same @gridGutterWidth 18 | 19 | } 20 | -------------------------------------------------------------------------------- /assets/vendor/bootstrap/bootstrap.js: -------------------------------------------------------------------------------- 1 | //= //require ./src/js/bootstrap-alert 2 | //= //require ./src/js/bootstrap-button 3 | //= //require ./src/js/bootstrap-carousel 4 | //= require ./src/js/bootstrap-collapse 5 | //= require ./src/js/bootstrap-dropdown 6 | //= require ./src/js/bootstrap-modal 7 | //= //require ./src/js/bootstrap-scrollspy 8 | //= require ./src/js/bootstrap-tab 9 | //= require ./src/js/bootstrap-tooltip 10 | //= require ./src/js/bootstrap-transition 11 | //= require ./src/js/bootstrap-typeahead 12 | 13 | // Popover must go AFTER tooltip 14 | //= //require ./src/js/bootstrap-popover 15 | 16 | -------------------------------------------------------------------------------- /DEV-NOTES.md: -------------------------------------------------------------------------------- 1 | Developers Notes 2 | ---------------- 3 | 4 | You can run font generator manually from command line: 5 | 6 | ./bin/generate_font.sh FONTNAME TMPDIR ZIPBALL 7 | 8 | - `FONTNAME`: generated font filename 9 | - `TMPDIR`: path where `config.json` (with user config) is placed 10 | - `ZIPBALL`: output archive with generated font and demo 11 | 12 | 13 | If you are debugging font merger or builder, you might want to generate 14 | *generator config* manually on base of user config (you can get it from the 15 | generated zipball): 16 | 17 | ./fontello.js font_config --input config.json --output builder-config.json 18 | -------------------------------------------------------------------------------- /assets/javascripts/loader.js.ejs: -------------------------------------------------------------------------------- 1 | //= require modernizr.custom 2 | //= require yepnope 3 | //= require_self 4 | 5 | 6 | /*jshint browser:true,node:false*/ 7 | /*global yepnope, window*/ 8 | 9 | 10 | yepnope([ 11 | { 12 | // JSON is required for Opera < 11 + IE < 8 13 | // See: http://caniuse.com/json 14 | test: !!window.JSON, 15 | nope: <%- JSON.stringify(asset_path('json2.js')) %> 16 | }, 17 | { 18 | load: <%- JSON.stringify(asset_path('app.js')) %>, 19 | complete: function () { 20 | window.nodeca.client.init(); 21 | } 22 | } 23 | ]); 24 | 25 | 26 | // vim: filetype=javascript:syntax=javascript 27 | -------------------------------------------------------------------------------- /assets/vendor/fontello/src/css/icons-ie7.css: -------------------------------------------------------------------------------- 1 | [class^="icon-"], 2 | [class*=" icon-"] { 3 | font-family: 'icons'; 4 | font-style: normal; 5 | font-weight: normal; 6 | /* fix buttons height */ 7 | line-height: 1em; 8 | /* you can be more comfortable with increased icons size */ 9 | /* font-zize: 120%; */ 10 | } 11 | 12 | .icon-settings { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '⚙ '); } 13 | .icon-download { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } 14 | .icon-search { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -------------------------------------------------------------------------------- /client/models/source_font.js: -------------------------------------------------------------------------------- 1 | /*global window, nodeca, jQuery, Handlebars, Backbone, $, _*/ 2 | 3 | "use strict"; 4 | 5 | module.exports = Backbone.Model.extend({ 6 | defaults: function () { 7 | return { 8 | font: {fontname: "unknown"}, 9 | glyphs: [] 10 | }; 11 | }, 12 | 13 | 14 | getGlyph: function (glyph_id) { 15 | return this.get("glyphs")[glyph_id]; 16 | }, 17 | 18 | 19 | // Stub to prevent Backbone from reading or saving the model to the server. 20 | // Backbone calls `Backbone.sync()` function (on fetch/save/destroy) 21 | // if model doesn't have own `sync()` method. 22 | sync: function () {} 23 | }); 24 | -------------------------------------------------------------------------------- /support/font-templates/css/css-ie7.jade: -------------------------------------------------------------------------------- 1 | :stylus_nowrap 2 | [class^="icon-"], [class*=" icon-"] 3 | font-family '#{font.fontname}' 4 | font-style normal 5 | font-weight normal 6 | 7 | /* fix buttons height */ 8 | line-height 1em 9 | 10 | /* you can be more comfortable with increased icons size */ 11 | /* font-size: 120%; */ 12 | 13 | - var i, g, css, hex, chr 14 | - for (i in glyphs) 15 | - g = glyphs[i] 16 | - css = meta.css_prefix + g.css 17 | - hex = g.code.toString(16) 18 | - chr = unichr(g.code) 19 | != '\n' 20 | | .#{css} { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#x#{hex}; '); } 21 | -------------------------------------------------------------------------------- /client/ui/panes/selector.js: -------------------------------------------------------------------------------- 1 | /*global window, nodeca, jQuery, Handlebars, Backbone, $, _*/ 2 | 3 | 4 | "use strict"; 5 | 6 | 7 | module.exports = Backbone.View.extend({ 8 | el: '#selector', 9 | 10 | 11 | initialize: function (attributes) { 12 | this.changeGlyphSize(nodeca.config.app.glyph_size.val); 13 | this.model.each(this.addFont, this); 14 | }, 15 | 16 | 17 | changeGlyphSize: function (size) { 18 | this.$el.css('font-size', size); 19 | }, 20 | 21 | 22 | addFont: function (font) { 23 | var view = new nodeca.client.ui.panes.selector_font({model: font}); 24 | this.$('#selector-fonts').append(view.render().el); 25 | } 26 | }); 27 | -------------------------------------------------------------------------------- /assets/vendor/bootstrap/src/less/wells.less: -------------------------------------------------------------------------------- 1 | // 2 | // Wells 3 | // -------------------------------------------------- 4 | 5 | 6 | // Base class 7 | .well { 8 | min-height: 20px; 9 | padding: 19px; 10 | margin-bottom: 20px; 11 | background-color: @wellBackground; 12 | border: 1px solid darken(@wellBackground, 7%); 13 | .border-radius(4px); 14 | .box-shadow(inset 0 1px 1px rgba(0,0,0,.05)); 15 | blockquote { 16 | border-color: #ddd; 17 | border-color: rgba(0,0,0,.15); 18 | } 19 | } 20 | 21 | // Sizes 22 | .well-large { 23 | padding: 24px; 24 | .border-radius(6px); 25 | } 26 | .well-small { 27 | padding: 9px; 28 | .border-radius(3px); 29 | } 30 | -------------------------------------------------------------------------------- /support/forever.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | FONTELLO_PID="" 4 | WATCH_PATHS="assets client config node_modules shared server src support views" 5 | 6 | start_fontello() { 7 | test "x" != "x$FONTELLO_PID" && kill -9 $FONTELLO_PID 8 | node ./fontello.js server & FONTELLO_PID=$! 9 | } 10 | 11 | # Initial start 12 | start_fontello 13 | 14 | inotifywait -m -r --format '%w%f' -e modify -e move -e create -e delete $WATCH_PATHS | while read f ; do 15 | # when not excluded 16 | (echo $f | egrep -v -q '\.swpx?$|/\.git/') && \ 17 | # and actually included 18 | (echo $f | egrep -q '\.(js|css|styl|less|ejs|jade)$') && \ 19 | # restart server 20 | start_fontello 21 | done 22 | -------------------------------------------------------------------------------- /client/ui/panes/codes_editor.js: -------------------------------------------------------------------------------- 1 | /*global window, nodeca, jQuery, Handlebars, Backbone, $, _*/ 2 | 3 | "use strict"; 4 | 5 | 6 | module.exports = Backbone.View.extend({ 7 | el: '#codes-editor', 8 | 9 | 10 | initialize: function () { 11 | var $glyphs = this.$('#result-font'), views = {}; 12 | 13 | function add(glyph) { 14 | var v = new nodeca.client.ui.panes.codes_editor_glyph({model: glyph}); 15 | views[glyph.cid] = v; 16 | $glyphs.append(v.render().el); 17 | } 18 | 19 | this.model.each(add); 20 | this.model.on('add', add); 21 | 22 | this.model.on('remove', function (glyph) { 23 | views[glyph.cid].remove(); 24 | delete views[glyph.cid]; 25 | }); 26 | } 27 | }); 28 | -------------------------------------------------------------------------------- /assets/vendor/bootstrap/src/less/responsive-1200px-min.less: -------------------------------------------------------------------------------- 1 | // 2 | // Responsive: Large desktop and up 3 | // -------------------------------------------------- 4 | 5 | 6 | @media (min-width: 1200px) { 7 | 8 | // Fixed grid 9 | #grid > .core(@gridColumnWidth1200, @gridGutterWidth1200); 10 | 11 | // Fluid grid 12 | #grid > .fluid(@fluidGridColumnWidth1200, @fluidGridGutterWidth1200); 13 | 14 | // Input grid 15 | #grid > .input(@gridColumnWidth1200, @gridGutterWidth1200); 16 | 17 | // Thumbnails 18 | .thumbnails { 19 | margin-left: -@gridGutterWidth1200; 20 | } 21 | .thumbnails > li { 22 | margin-left: @gridGutterWidth1200; 23 | } 24 | .row-fluid .thumbnails { 25 | margin-left: 0; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /assets/vendor/fontello/src/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "icons", 3 | "glyphs": [ 4 | { 5 | "uid": "7222571caa5c15f83dcfd447c58d68d9", 6 | "orig_css": "search", 7 | "orig_code": 61441, 8 | "css": "search", 9 | "code": 61441, 10 | "src": "entypo" 11 | }, 12 | { 13 | "uid": "b08cfe8039de2ce815686aced2caef06", 14 | "orig_css": "download", 15 | "orig_code": 61440, 16 | "css": "download", 17 | "code": 61440, 18 | "src": "entypo" 19 | }, 20 | { 21 | "uid": "bc64550dd022ce21604f97309b346cea", 22 | "orig_css": "cog", 23 | "orig_code": 9881, 24 | "css": "settings", 25 | "code": 9881, 26 | "src": "entypo" 27 | } 28 | ] 29 | } -------------------------------------------------------------------------------- /assets/stylesheets/ui/tabs.styl: -------------------------------------------------------------------------------- 1 | //=== Fix tab styles 2 | .nav-tabs 3 | margin-bottom 0 4 | 5 | .nav-tabs .disabled 6 | .nav-tabs .disabled:hover 7 | opacity 0.3 8 | cursor default 9 | 10 | .nav-tabs > li > a 11 | outline: none 12 | transition background-color .5s ease-in-out 13 | 14 | .nav-tabs > .active > a, 15 | .nav-tabs > .active > a:hover 16 | font-weight: bold; 17 | border-color #aaa #aaa transparent 18 | box-shadow -2px -2px 2px -2px #ccc, 2px -2px 2px -2px #ccc 19 | 20 | .nav-tabs 21 | border-bottom: 1px solid #aaa 22 | box-shadow 0 10px 15px 10px #fff; 23 | 24 | //====== users counter ============ 25 | .stats 26 | text-align center 27 | font-size 10px 28 | color #888 29 | position absolute 30 | right 0 31 | bottom 0 32 | -------------------------------------------------------------------------------- /assets/vendor/bootstrap/src/less/close.less: -------------------------------------------------------------------------------- 1 | // 2 | // Close icons 3 | // -------------------------------------------------- 4 | 5 | 6 | .close { 7 | float: right; 8 | font-size: 20px; 9 | font-weight: bold; 10 | line-height: @baseLineHeight; 11 | color: @black; 12 | text-shadow: 0 1px 0 rgba(255,255,255,1); 13 | .opacity(20); 14 | &:hover { 15 | color: @black; 16 | text-decoration: none; 17 | cursor: pointer; 18 | .opacity(40); 19 | } 20 | } 21 | 22 | // Additional properties for button version 23 | // iOS requires the button element instead of an anchor tag. 24 | // If you want the anchor version, it requires `href="#"`. 25 | button.close { 26 | padding: 0; 27 | cursor: pointer; 28 | background: transparent; 29 | border: 0; 30 | -webkit-appearance: none; 31 | } -------------------------------------------------------------------------------- /assets/vendor/bootstrap/src/less/accordion.less: -------------------------------------------------------------------------------- 1 | // 2 | // Accordion 3 | // -------------------------------------------------- 4 | 5 | 6 | // Parent container 7 | .accordion { 8 | margin-bottom: @baseLineHeight; 9 | } 10 | 11 | // Group == heading + body 12 | .accordion-group { 13 | margin-bottom: 2px; 14 | border: 1px solid #e5e5e5; 15 | .border-radius(4px); 16 | } 17 | .accordion-heading { 18 | border-bottom: 0; 19 | } 20 | .accordion-heading .accordion-toggle { 21 | display: block; 22 | padding: 8px 15px; 23 | } 24 | 25 | // General toggle styles 26 | .accordion-toggle { 27 | cursor: pointer; 28 | } 29 | 30 | // Inner needs the styles because you can't animate properly with any styles on the element 31 | .accordion-inner { 32 | padding: 9px 15px; 33 | border-top: 1px solid #e5e5e5; 34 | } 35 | -------------------------------------------------------------------------------- /etc/certs/fontello-dev.cert: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICATCCAWoCCQDrxv/Pozx1tTANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJS 3 | VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 4 | cyBQdHkgTHRkMB4XDTEyMDYwNzIyMTUzOFoXDTEzMDYwNzIyMTUzOFowRTELMAkG 5 | A1UEBhMCUlUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0 6 | IFdpZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAxNy0 7 | 3QpTO58fS0ApducrCum5lIJHHCoY6TqMfH9sE+MsQXzDpvPU2dhqfTQonLX6LU0B 8 | Su9PYt9va13Yz7rLet9N/yqhmH5pbZuo4iC8y11nYaUtgW6XjboBxnzewJPUkySJ 9 | m9ZbempfIYfCWDFaYgQiYvgls3qx2oBZg4pZVpsCAwEAATANBgkqhkiG9w0BAQUF 10 | AAOBgQB2rAHylGkCdt4wKIj5kx4MP/ktrZ3vkvnaEmEVlrcNJo3HCsATq4waJAdI 11 | SMXtuLaKIqa3GQ3QLR1MbWJvvHL4hkPxiGyxvF/52F25tPWxiX0FXrx0AWePSMV8 12 | UHbVJHhGMPP5nAup418mee6quX3GntTOgf7z9KJTR8MrgZjivA== 13 | -----END CERTIFICATE----- 14 | -------------------------------------------------------------------------------- /assets/vendor/bootstrap/src/less/pager.less: -------------------------------------------------------------------------------- 1 | // 2 | // Pager pagination 3 | // -------------------------------------------------- 4 | 5 | 6 | .pager { 7 | margin: @baseLineHeight 0; 8 | list-style: none; 9 | text-align: center; 10 | .clearfix(); 11 | } 12 | .pager li { 13 | display: inline; 14 | } 15 | .pager a, 16 | .pager span { 17 | display: inline-block; 18 | padding: 5px 14px; 19 | background-color: #fff; 20 | border: 1px solid #ddd; 21 | .border-radius(15px); 22 | } 23 | .pager a:hover { 24 | text-decoration: none; 25 | background-color: #f5f5f5; 26 | } 27 | .pager .next a, 28 | .pager .next span { 29 | float: right; 30 | } 31 | .pager .previous a { 32 | float: left; 33 | } 34 | .pager .disabled a, 35 | .pager .disabled a:hover, 36 | .pager .disabled span { 37 | color: @grayLight; 38 | background-color: #fff; 39 | cursor: default; 40 | } -------------------------------------------------------------------------------- /cli/server.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | 4 | /*global nodeca*/ 5 | 6 | 7 | // nodeca 8 | var NLib = require('nlib'); 9 | 10 | 11 | // 3rd-party 12 | var Async = NLib.Vendor.Async; 13 | var FsTools = NLib.Vendor.FsTools; 14 | 15 | 16 | module.exports.parserParameters= { 17 | version: nodeca.runtime.version, 18 | addHelp: true, 19 | help: 'start fontello server', 20 | description: 'Start fontello server' 21 | }; 22 | 23 | 24 | module.exports.run = function (args, callback) { 25 | Async.series([ 26 | NLib.InitStages.loadServerApiSubtree, 27 | NLib.InitStages.loadSharedApiSubtree, 28 | NLib.InitStages.loadClientApiSubtree, 29 | NLib.InitStages.initRouter, 30 | NLib.InitStages.initTranslations, 31 | 32 | require('../lib/init/cronjob'), 33 | require('../lib/init/assets'), 34 | require('../lib/init/server') 35 | ], callback); 36 | }; 37 | -------------------------------------------------------------------------------- /client/ui/panes/preview.js: -------------------------------------------------------------------------------- 1 | /*global window, nodeca, jQuery, Handlebars, Backbone, $, _*/ 2 | 3 | 4 | "use strict"; 5 | 6 | 7 | module.exports = Backbone.View.extend({ 8 | el: '#preview', 9 | 10 | 11 | initialize: function () { 12 | var $glyphs = this.$('#preview-font'), views = {}; 13 | 14 | this.changeGlyphSize(nodeca.config.app.glyph_size.val); 15 | 16 | function add(glyph) { 17 | var v = new nodeca.client.ui.panes.preview_glyph({model: glyph}); 18 | views[glyph.cid] = v; 19 | $glyphs.append(v.render().el); 20 | } 21 | 22 | this.model.each(add); 23 | this.model.on('add', add); 24 | 25 | this.model.on('remove', function (glyph) { 26 | views[glyph.cid].remove(); 27 | delete views[glyph.cid]; 28 | }); 29 | }, 30 | 31 | 32 | changeGlyphSize: function (size) { 33 | this.$el.css('font-size', size); 34 | } 35 | }); 36 | -------------------------------------------------------------------------------- /client/ui/panes/selector_glyph.js: -------------------------------------------------------------------------------- 1 | /*global window, nodeca, jQuery, Handlebars, Backbone, $, _*/ 2 | 3 | 4 | "use strict"; 5 | 6 | 7 | module.exports = Backbone.View.extend({ 8 | tagName: 'li', 9 | className: 'glyph', 10 | 11 | 12 | events: { 13 | click: function () { 14 | this.model.toggle('selected'); 15 | } 16 | }, 17 | 18 | 19 | initialize: function () { 20 | var self = this, 21 | font = this.model.get('font').getName(), 22 | uid = this.model.get('source').uid, 23 | code = nodeca.shared.glyphs_map[font][uid], 24 | text = nodeca.client.util.fixedFromCharCode(code); 25 | 26 | this.$el.data('model', this.model); 27 | this.$el.text(text); 28 | 29 | // 30 | // Listen to the model changes 31 | // 32 | 33 | this.model.on('change:selected', function (g, v) { 34 | self.$el.toggleClass('selected', v); 35 | }); 36 | } 37 | }); 38 | -------------------------------------------------------------------------------- /assets/stylesheets/variables.styl: -------------------------------------------------------------------------------- 1 | black = #000 2 | grayDarker = #222 3 | grayDark = #444 4 | gray = #666 5 | grayLight = #999 6 | grayLighter = #ccc 7 | grayLightest = #eee 8 | white = #fff 9 | 10 | 11 | // Accent colors 12 | // ------------------------- 13 | blue = #049cdb 14 | blueDark = #0064cd 15 | green = #46a546 16 | red = #9d261d 17 | yellow = #ffc40d 18 | orange = #f89406 19 | pink = #c3325f 20 | purple = #7a43b6 21 | 22 | baseFontSize = 14px 23 | baseLineHeight = 20px 24 | 25 | sansFontFamily = "Helvetica Neue", Helvetica, Arial, sans-serif; 26 | sansWideFontFamily = Verdana, sans-serif; 27 | serifFontFamily = Georgia, "Times New Roman", Times, serif; 28 | monoFontFamily = Menlo, Monaco, Consolas, "Courier New", monospace; 29 | 30 | navbarText = #bbb 31 | navbarLinkColor = #bbb 32 | 33 | -------------------------------------------------------------------------------- /shared/getByPath.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | /** 5 | * shared 6 | **/ 7 | 8 | 9 | /*global nodeca, _*/ 10 | 11 | 12 | //////////////////////////////////////////////////////////////////////////////// 13 | 14 | 15 | /** 16 | * shared.getByPath(obj, path) -> Mixed 17 | * - obj (Object): Object to get value from 18 | * - path (String): Path of a property 19 | * 20 | * Extracts property from more than one level down, via a `.` delimited 21 | * string of property names. 22 | * 23 | * 24 | * ##### Example 25 | * 26 | * shared.getByPath({foo: {bar: 123}}, 'foo.bar'); 27 | * // => 123 28 | **/ 29 | module.exports = function getByPath(obj, path) { 30 | var parts = path.split('.'); 31 | 32 | // this is the fastest way to find nested value: 33 | // http://jsperf.com/find-object-deep-nested-value 34 | 35 | while (obj && parts.length) { 36 | obj = obj[parts.shift()]; 37 | } 38 | 39 | return obj; 40 | }; 41 | -------------------------------------------------------------------------------- /etc/certs/fontello-dev.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIICXwIBAAKBgQDE3LTdClM7nx9LQCl25ysK6bmUgkccKhjpOox8f2wT4yxBfMOm 3 | 89TZ2Gp9NCictfotTQFK709i329rXdjPust6303/KqGYfmltm6jiILzLXWdhpS2B 4 | bpeNugHGfN7Ak9STJImb1lt6al8hh8JYMVpiBCJi+CWzerHagFmDillWmwIDAQAB 5 | AoGBALtCRjjMjYf1QMtP6SFVm7fxw7nkgsfjs3aHXwM+Igx416wjhejVn+7o0cLv 6 | ToJjB+r3iPdC1Hz0lQPIbWiMAujcm/yQ2uHqbvgUODJj85RmL1PLPmzXQmIMIXjW 7 | TBC3Z7WOXaP8fM/Bc+jmXANE+qQS5wTFxF89rPzYk7+70uihAkEA+0O3TQ3/6Qtn 8 | ok++bJI/GxRcOFSZi2yg9Gt9DUPzFay5wX5EP6fvv0TB3HhKekV20X/M3cv6OhCq 9 | SfldNgmi9wJBAMiSg3jjGmjZWzIZXOHa+olNaWqarv8+NCYsmQEzleBZTdbNTsaM 10 | EaHGPwmjAqgHETe/URw8GnQTOVr0Nn6MXH0CQQDxTstPeU54pbdVrngXFSz9+MPI 11 | ZZdAy4aYtlJW1xcxjbyoE3fAGqypaIM2FWCRpPzDnpVFvYwHD9I7UP0v1HlpAkEA 12 | lYSbG4f4zQaTNDKyCfAq6iXaGs06/S2KxJZkbP/ej4MjQqiEPAB4uGdH4NAzD71M 13 | +YjWVzz632LhU8tPwGC0JQJBAL3Q1WCPMFHqhoKCs3YPAP6BUBgmrRych4c2ErtL 14 | Fo9/q2zikU7t2fZjGIybud6cMKdt5s7FRacq7xL0S8KC79g= 15 | -----END RSA PRIVATE KEY----- 16 | -------------------------------------------------------------------------------- /lib/init/server/http/compression.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | 4 | /*global nodeca, _*/ 5 | 6 | 7 | // stdlib 8 | var zlib = require('zlib'); 9 | 10 | 11 | //////////////////////////////////////////////////////////////////////////////// 12 | 13 | 14 | // Returns whenever or not compression is allowed by client 15 | // 16 | // - `'gzip'` if GZip allowed 17 | // - `'deflate'` if Deflate allowed 18 | // - `false` otherwise 19 | // 20 | module.exports.is_allowed = function get_allowed_compression(req) { 21 | var accept = req.headers['accept-encoding'] || ''; 22 | 23 | if ('*' === accept || 0 <= accept.indexOf('gzip')) { 24 | return 'gzip'; 25 | } 26 | 27 | if (0 <= accept.indexOf('deflate')) { 28 | return 'deflate'; 29 | } 30 | 31 | return false; 32 | }; 33 | 34 | 35 | // small helper to run compressor 36 | // 37 | module.exports.process = function compress(algo, source, callback) { 38 | ('gzip' === algo ? zlib.gzip : zlib.deflate)(source, callback); 39 | }; 40 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src/iconic-uni.font"] 2 | path = src/iconic-uni.font 3 | url = git://github.com/fontello/iconic-uni.font.git 4 | [submodule "src/awesome-uni.font"] 5 | path = src/awesome-uni.font 6 | url = git://github.com/fontello/awesome-uni.font.git 7 | [submodule "src/websymbols-uni.font"] 8 | path = src/websymbols-uni.font 9 | url = git://github.com/fontello/websymbols-uni.font.git 10 | [submodule "src/entypo"] 11 | path = src/entypo 12 | url = git://github.com/fontello/entypo.git 13 | [submodule "src/brandico.font"] 14 | path = src/brandico.font 15 | url = git://github.com/fontello/brandico.font.git 16 | [submodule "support/font-builder"] 17 | path = support/font-builder 18 | url = git://github.com/fontello/font-builder.git 19 | [submodule "src/modernpics.font"] 20 | path = src/modernpics.font 21 | url = git://github.com/fontello/modernpics.font.git 22 | [submodule "src/typicons.font"] 23 | path = src/typicons.font 24 | url = git://github.com/fontello/typicons.font.git 25 | -------------------------------------------------------------------------------- /server/app.js: -------------------------------------------------------------------------------- 1 | /*global nodeca*/ 2 | 3 | 4 | "use strict"; 5 | 6 | 7 | //////////////////////////////////////////////////////////////////////////////// 8 | 9 | 10 | function hash(str) { 11 | return require('crypto').createHash('md5').update(str).digest('hex'); 12 | } 13 | 14 | 15 | //////////////////////////////////////////////////////////////////////////////// 16 | 17 | 18 | // FIXME: this works for single-process model only. 19 | // switch to shared cache in future. 20 | var etag = hash('fontello-app-' + Date.now()); 21 | 22 | 23 | //////////////////////////////////////////////////////////////////////////////// 24 | 25 | 26 | module.exports = function app(params, callback) { 27 | if (!this.origin.http) { 28 | callback('HTTP only'); 29 | return; 30 | } 31 | 32 | // set headers 33 | this.response.headers['ETag'] = etag; 34 | this.response.headers['Cache-Control'] = 'private, max-age=0, must-revalidate'; 35 | 36 | // done 37 | callback(); 38 | }; 39 | -------------------------------------------------------------------------------- /client/ui/panes/preview_glyph.js: -------------------------------------------------------------------------------- 1 | /*global window, nodeca, jQuery, Handlebars, Backbone, $, _*/ 2 | 3 | 4 | "use strict"; 5 | 6 | 7 | module.exports = Backbone.View.extend({ 8 | tagName: "div", 9 | className: "preview-glyph span3", 10 | 11 | 12 | render: function () { 13 | var self = this, 14 | font = this.model.get('font').getName(), 15 | uid = this.model.get('source').uid, 16 | code = nodeca.shared.glyphs_map[font][uid]; 17 | 18 | this.$el.html(nodeca.client.render('preview.glyph', { 19 | css: this.model.get('css'), 20 | chr: nodeca.client.util.fixedFromCharCode(code) 21 | })); 22 | 23 | 24 | this.$el.find('.glyph-name').inplaceEditor({ 25 | noPaste: true, 26 | validateChar: function (char) { 27 | return /[a-zA-Z0-9\-\_]/.test(char) && 20 > this.getValue().length; 28 | } 29 | }).on('change', function (event, value) { 30 | self.model.set( 'css', value ); 31 | }); 32 | 33 | return this; 34 | } 35 | }); 36 | -------------------------------------------------------------------------------- /support/font-templates/demo.jade: -------------------------------------------------------------------------------- 1 | !!! 5 2 | html 3 | head 4 | //if lt IE 9 5 | script(src='http://html5shim.googlecode.com/svn/trunk/html5.js') 6 | 7 | :stylus 8 | @import "_demo" 9 | 10 | link(rel='stylesheet', href='css/#{font.fontname}.css') 11 | //if IE 7 12 | link(rel='stylesheet', href='css/#{font.fontname}-ie7.css') 13 | 14 | body 15 | .container 16 | .page-header 17 | h1 #{font.fullname} font icons demo 18 | .row 19 | - var col_class = "span" + Math.ceil(12 / meta.columns) 20 | - var chunk_size = Math.ceil(glyphs.length / meta.columns) 21 | - for (var i = 0; i < meta.columns; i++) 22 | div(class=col_class) 23 | ul.the-icons 24 | - var offset = i * chunk_size 25 | - for (var c = 0; c < chunk_size && glyphs[offset + c]; c++) 26 | - var g = glyphs[offset + c] 27 | - var css_class = meta.css_prefix + (g.css || g.file) 28 | |
  • #{css_class}
  • 29 | -------------------------------------------------------------------------------- /lib/filters/renderer/helpers.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | 4 | /*global nodeca, _*/ 5 | 6 | 7 | // nodeca 8 | var JASON = require('nlib').Vendor.JASON; 9 | 10 | 11 | //////////////////////////////////////////////////////////////////////////////// 12 | 13 | 14 | var helpers = module.exports = {}; 15 | 16 | 17 | //////////////////////////////////////////////////////////////////////////////// 18 | 19 | 20 | // returns asset source 21 | helpers.asset_include = function asset_include(path) { 22 | var asset = nodeca.runtime.assets.environment.findAsset(path); 23 | return !asset ? "" : asset.toString(); 24 | }; 25 | 26 | 27 | // returns link for the api path `name` 28 | helpers.link_to = function (name, params) { 29 | return nodeca.runtime.router.linkTo(name, params) || '#'; 30 | }; 31 | 32 | 33 | // nodeca reference 34 | helpers.nodeca = function (path) { 35 | return !path ? nodeca : nodeca.shared.getByPath(nodeca, path); 36 | }; 37 | 38 | 39 | // JSON alike serializer (but that treats RegExps, Function as they are) 40 | helpers.jason = JASON.stringify; 41 | -------------------------------------------------------------------------------- /assets/stylesheets/ui/panes/preview.styl: -------------------------------------------------------------------------------- 1 | #preview 2 | padding-bottom 10px // to show shadow of bottom row elements 3 | 4 | .preview-glyph 5 | line-height 1.5em 6 | height 1.5em 7 | white-space nowrap 8 | background-color white 9 | 10 | span.icon 11 | display inline-block 12 | width 1.1em 13 | text-align center 14 | cursor default 15 | 16 | span.prefix 17 | margin-left 0.5em 18 | cursor default 19 | 20 | &:hover .glyph-name 21 | background-color lighten(yellow, 70%) 22 | //box-shadow 0 0 0px 2px rgba(168, 82, 82, 0.6) inset 23 | border-radius 4px 24 | cursor pointer 25 | 26 | .glyph-name 27 | display inline-block 28 | 29 | &:focus 30 | outline none 31 | box-shadow 0 0 8px rgba(168, 82, 82, 0.6), 0 0 0 2px rgba(168, 82, 82, 0.6) 32 | background-color lighten(rgb(168, 82, 82), 95%) 33 | border-radius 4px 34 | position relative 35 | z-index 1000 36 | cursor auto 37 | 38 | 39 | ._3d .preview-glyph span.icon 40 | text-shadow 1px 1px 1px rgba(127, 127, 127, 0.3) 41 | -------------------------------------------------------------------------------- /assets/vendor/fontello/icons.css.ejs: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | *= require_self 4 | *= require ./src/css/icons-codes 5 | 6 | **/ 7 | 8 | @font-face { 9 | font-family: 'icons'; 10 | src: url(<%= asset_path('fontello/src/font/icons.eot') %>); 11 | src: url(<%= asset_path('fontello/src/font/icons.eot') %>?#iefix) format('embedded-opentype'), 12 | url(<%= asset_path('fontello/src/font/icons.woff') %>) format('woff'), 13 | url(<%= asset_path('fontello/src/font/icons.ttf') %>) format('truetype'), 14 | url(<%= asset_path('fontello/src/font/icons.svg') %>#icons) format('svg'); 15 | font-weight: normal; font-style: normal; 16 | } 17 | 18 | [class^="icon-"]:before, [class*=" icon-"]:before { 19 | font-family: "icons"; 20 | speak: none; 21 | font-size: 120%; 22 | opacity: .7; 23 | text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); 24 | 25 | display: inline-block; 26 | width: 1em; 27 | margin-right: .2em; 28 | text-align: center; 29 | line-height: 1em; 30 | 31 | font-style: normal !important; 32 | font-weight: normal !important; 33 | } 34 | -------------------------------------------------------------------------------- /assets/vendor/fontello/src/css/icons.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'icons'; 3 | src: url("../font/icons.eot"); 4 | src: url("../font/icons.eot?#iefix") format('embedded-opentype'), url("../font/icons.woff") format('woff'), url("../font/icons.ttf") format('truetype'), url("../font/icons.svg#icons") format('svg'); 5 | font-weight: normal; 6 | font-style: normal; 7 | } 8 | [class^="icon-"]:before, 9 | [class*=" icon-"]:before { 10 | font-family: 'icons'; 11 | font-style: normal; 12 | font-weight: normal; 13 | speak: none; 14 | display: inline-block; 15 | text-decoration: inherit; 16 | width: 1em; 17 | margin-right: 0.2em; 18 | text-align: center; 19 | opacity: 0.7; 20 | /* Uncomment for 3D effect */ 21 | /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */ 22 | /* fix buttons height */ 23 | line-height: 1em; 24 | /* you can be more comfortable with increased icons size */ 25 | /* font-size: 120%; */ 26 | } 27 | 28 | .icon-settings:before { content: '\2699'; } /* '⚙' */ 29 | .icon-download:before { content: '\f000'; } /* '' */ 30 | .icon-search:before { content: '\f001'; } /* '' */ -------------------------------------------------------------------------------- /views/selector/font-info.jade: -------------------------------------------------------------------------------- 1 | .modal.fade 2 | .modal-header 3 | a.close(data-dismiss="modal") × 4 | h3 #{self.font.fullname} 5 | .modal-body 6 | dl.dl-horizontal 7 | - if (self.meta) 8 | - var meta = self.meta 9 | - if (meta.license) 10 | dt License: 11 | dd 12 | - if (meta.license_meta) 13 | a(href=meta.license_meta, target="_blank") #{meta.license} 14 | - else 15 | | #{meta.license} 16 | - if (meta.author) 17 | dt Author: 18 | dd #{meta.author} 19 | - if (meta.email) 20 | dt Email: 21 | dd: a(href="mailto:#{meta.email}") #{meta.email} 22 | - if (meta.homepage) 23 | dt Homepage: 24 | dd: a(href="#{meta.homepage}", target="_blank") #{meta.homepage} 25 | - if (meta.twitter) 26 | dd: a(href="#{meta.twitter}", target="_blank") Twitter 27 | - if (meta.dribble) 28 | dd: a(href="#{meta.dribble}", target="_blank") Dribble 29 | - if (meta.github) 30 | dd: a(href="#{meta.github}", target="_blank") Github 31 | -------------------------------------------------------------------------------- /assets/vendor/bootstrap/src/less/scaffolding.less: -------------------------------------------------------------------------------- 1 | // 2 | // Scaffolding 3 | // -------------------------------------------------- 4 | 5 | 6 | // Body reset 7 | // ------------------------- 8 | 9 | body { 10 | margin: 0; 11 | font-family: @baseFontFamily; 12 | font-size: @baseFontSize; 13 | line-height: @baseLineHeight; 14 | color: @textColor; 15 | background-color: @bodyBackground; 16 | } 17 | 18 | 19 | // Links 20 | // ------------------------- 21 | 22 | a { 23 | color: @linkColor; 24 | text-decoration: none; 25 | } 26 | a:hover { 27 | color: @linkColorHover; 28 | text-decoration: underline; 29 | } 30 | 31 | 32 | // Images 33 | // ------------------------- 34 | 35 | // Rounded corners 36 | .img-rounded { 37 | .border-radius(6px); 38 | } 39 | 40 | // Add polaroid-esque trim 41 | .img-polaroid { 42 | padding: 4px; 43 | background-color: #fff; 44 | border: 1px solid #ccc; 45 | border: 1px solid rgba(0,0,0,.2); 46 | .box-shadow(0 1px 3px rgba(0,0,0,.1)); 47 | } 48 | 49 | // Perfect circle 50 | .img-circle { 51 | .border-radius(500px); // crank the border-radius so it works with most reasonably sized images 52 | } 53 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | (The MIT License) 2 | 3 | Copyright (C) 2011 by Vitaly Puzrin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /lib/init/assets/build_i18n_files.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | /*global nodeca, _*/ 5 | 6 | 7 | // stdlib 8 | var fs = require('fs'); 9 | var path = require('path'); 10 | 11 | 12 | // 3rd-party 13 | var async = require('nlib').Vendor.Async; 14 | var fstools = require('nlib').Vendor.FsTools; 15 | var JASON = require('nlib').Vendor.JASON; 16 | 17 | 18 | //////////////////////////////////////////////////////////////////////////////// 19 | 20 | 21 | // buildI18nFiles(root, callback(err)) -> Void 22 | // - root (String): Pathname where to save i18n.js files. 23 | // - callback (Function): Executed once everything is done. 24 | // 25 | // Writes i18n.js file. 26 | // 27 | module.exports = function buildI18nFiles(root, callback) { 28 | var chunks = []; 29 | 30 | nodeca.config.locales.enabled.forEach(function (lang) { 31 | var data = nodeca.runtime.i18n.getCompiledData(lang); 32 | chunks.push( 33 | 'nodeca.runtime.i18n.load(' + 34 | JSON.stringify(lang) + ',' + 35 | JASON.stringify(data) + 36 | ');' 37 | ); 38 | }); 39 | 40 | fs.writeFile(path.join(root, 'i18n.js'), chunks.join('\n'), callback); 41 | }; 42 | -------------------------------------------------------------------------------- /INSTALL.md: -------------------------------------------------------------------------------- 1 | installation instruction 2 | 3 | ## Install node.js 4 | 5 | Install build dependencies of node: 6 | 7 | sudo apt-get install build-essential libssl-dev 8 | sudo apt-get install git curl 9 | git clone git://github.com/creationix/nvm.git ~/.nvm 10 | 11 | Add following code into the end of your shell startup script (`.bashrc` for BASH): 12 | 13 | if [ -s "$HOME/.nvm/nvm.sh" ] ; then 14 | . ~/.nvm/nvm.sh # Loads NVM into a shell session. 15 | fi 16 | 17 | Reopen terminal. Install node (long), and set default version: 18 | 19 | nvm install v0.8.8 20 | nvm alias default 0.8 21 | 22 | ## Install Fontomas 23 | 24 | sudo apt-get install zip 25 | git clone git://github.com/nodeca/fontomas.git fontomas 26 | cd fontomas 27 | git submodule init 28 | git submodule update 29 | cd support/font-builder 30 | sudo make dev-deps 31 | make support 32 | 33 | Then, depending on your installation type, run: 34 | 35 | - `npm install` for production 36 | - `make dev-setup` for development 37 | 38 | ## Run Fontomas server 39 | 40 | make app-start 41 | 42 | Now you can point your browser to the page http://localhost:3000 43 | 44 | ## Rebuilding embedded fonts 45 | 46 | Detailed description will be added soon. 47 | 48 | make rebuild-fonts 49 | -------------------------------------------------------------------------------- /lib/stats.js: -------------------------------------------------------------------------------- 1 | /*global nodeca*/ 2 | 3 | 4 | 'use strict'; 5 | 6 | 7 | // stdlib 8 | var path = require('path'); 9 | var fs = require('fs'); 10 | 11 | 12 | function start_logger(file) { 13 | var size = path.existsSync(file) ? fs.statSync(file).size : 0; 14 | 15 | return {write: function (str) { 16 | fs.open(file, 'a', function (err, fd) { 17 | if (err) { 18 | nodeca.logger.error("Failed open stats log file: " + err); 19 | return; 20 | } 21 | 22 | fs.write(fd, str, size, Buffer.byteLength(str), function (err) { 23 | if (err) { 24 | nodeca.logger.error("Failed write to stats log file: " + err); 25 | } 26 | 27 | fs.close(fd); 28 | }); 29 | }); 30 | }}; 31 | } 32 | 33 | 34 | var logfile = path.join(nodeca.runtime.apps[0].root, 'log/fontello-stats.log'); 35 | var logger = start_logger(logfile); 36 | 37 | 38 | module.exports.push = function (stats) { 39 | var parts = []; 40 | 41 | try { 42 | parts.push((new Date).toISOString()); 43 | parts.push(stats.user); 44 | parts.push(stats.glyphs); 45 | parts.push(stats.time); 46 | 47 | logger.write(parts.join('\t') + "\n"); 48 | } catch (err) { 49 | nodeca.logger.warn("Failed write stat results"); 50 | nodeca.logger.error(err); 51 | } 52 | }; 53 | -------------------------------------------------------------------------------- /assets/vendor/bootstrap/src/less/responsive.less: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Responsive v2.1.1 3 | * 4 | * Copyright 2012 Twitter, Inc 5 | * Licensed under the Apache License v2.0 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Designed and built with all the love in the world @twitter by @mdo and @fat. 9 | */ 10 | 11 | 12 | // Responsive.less 13 | // For phone and tablet devices 14 | // ------------------------------------------------------------- 15 | 16 | 17 | // REPEAT VARIABLES & MIXINS 18 | // ------------------------- 19 | // Required since we compile the responsive stuff separately 20 | 21 | @import "variables.less"; // Modify this for custom colors, font-sizes, etc 22 | @import "mixins.less"; 23 | 24 | 25 | // RESPONSIVE CLASSES 26 | // ------------------ 27 | 28 | @import "responsive-utilities.less"; 29 | 30 | 31 | // MEDIA QUERIES 32 | // ------------------ 33 | 34 | // Large desktops 35 | @import "responsive-1200px-min.less"; 36 | 37 | // Tablets to regular desktops 38 | @import "responsive-768px-979px.less"; 39 | 40 | // Phones to portrait tablets and narrow desktops 41 | @import "responsive-767px-max.less"; 42 | 43 | 44 | // RESPONSIVE NAVBAR 45 | // ------------------ 46 | 47 | // From 979px and below, show a button to toggle navbar contents 48 | @import "responsive-navbar.less"; 49 | -------------------------------------------------------------------------------- /lib/init/assets/compile_views.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | /*global nodeca*/ 5 | 6 | 7 | // stdlib 8 | var fs = require('fs'); 9 | var path = require('path'); 10 | 11 | 12 | // 3rd-party 13 | var views = require('nlib').Views; 14 | var async = require('nlib').Vendor.Async; 15 | var _ = require('nlib').Vendor.Underscore; 16 | 17 | 18 | //////////////////////////////////////////////////////////////////////////////// 19 | 20 | 21 | // compileViews(root, callback(err)) -> Void 22 | // - root (String): Pathname containing views directories. 23 | // - callback (Function): Executed once everything is done. 24 | // 25 | // Compiles all views, inject them into `nodeca.runtime.views` for the 26 | // server and writes browserified versions into `views.js`. 27 | // 28 | module.exports = function compileViews(root, callback) { 29 | views.collect(path.join(nodeca.runtime.apps[0].root, 'views'), function (err, tree) { 30 | if (err) { 31 | callback(err); 32 | return; 33 | } 34 | 35 | // set server-side views tree 36 | nodeca.runtime.views = views.buildServerTree(tree); 37 | 38 | // write client-side views tree 39 | views.writeClientTree( 40 | path.join(root, 'views.js'), 41 | tree, 42 | 'this.nodeca.views', 43 | callback 44 | ); 45 | }); 46 | }; 47 | -------------------------------------------------------------------------------- /assets/stylesheets/ui/panes/codes_editor.styl: -------------------------------------------------------------------------------- 1 | .result-glyph 2 | float left 3 | width 64px 4 | margin 0 10px 10px 0 5 | color #fff 6 | //background-color #888 7 | //border-left 1px solid #888 8 | //border-right 1px solid #888 9 | background-color #444 10 | border-left 1px solid #444 11 | border-right 1px solid #444 12 | border-radius 6px 13 | 14 | .top 15 | text-align center 16 | line-height 16px 17 | font-size 14px 18 | 19 | .center 20 | height 64px 21 | line-height 64px 22 | text-align center 23 | background-color #fff 24 | color #444 25 | font-size 24px 26 | 27 | .bottom 28 | text-align center 29 | line-height 16px 30 | font-size 10px 31 | 32 | 33 | //&.mapping-matched 34 | // border-color #444 35 | // background-color #444 36 | 37 | .code-prefix, .code-editable, .char-editable 38 | display inline-block 39 | margin 3px 0 40 | .char-editable 41 | padding 0 3px 42 | 43 | 44 | &:hover 45 | .char-editable, .code-editable 46 | background-color #888 47 | border-radius 2px 48 | cursor pointer 49 | 50 | .char-editable, .code-editable 51 | &:focus 52 | outline none 53 | box-shadow 0 0 2px #fff 54 | background-color white 55 | color grayDark 56 | border-radius 2px 57 | cursor auto 58 | -------------------------------------------------------------------------------- /client/util.js: -------------------------------------------------------------------------------- 1 | /*global window, nodeca, jQuery, Handlebars, Backbone, $, _*/ 2 | 3 | "use strict"; 4 | 5 | 6 | module.exports.notify = function (type, options, message) { 7 | if (!message) { 8 | message = options; 9 | options = {}; 10 | } 11 | 12 | $.noty(_.extend({layout: 'topRight'}, options, { 13 | type: type, 14 | text: message, 15 | theme: 'noty_theme_twitter' 16 | })); 17 | }; 18 | 19 | 20 | // Int to char, with fix for big numbers 21 | // see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/String/fromCharCode 22 | module.exports.fixedFromCharCode = function (code) { 23 | /*jshint bitwise: false*/ 24 | if (code > 0xffff) { 25 | code -= 0x10000; 26 | var surrogate1 = 0xd800 + (code >> 10), 27 | surrogate2 = 0xdc00 + (code & 0x3ff); 28 | return String.fromCharCode(surrogate1, surrogate2); 29 | } else { 30 | return String.fromCharCode(code); 31 | } 32 | }; 33 | 34 | 35 | // Char to Int, with fix for big numbers 36 | module.exports.fixedCharCodeAt = function (char) { 37 | /*jshint bitwise: false*/ 38 | var char1 = char.charCodeAt(0), 39 | char2 = char.charCodeAt(1); 40 | 41 | if ((char.length >= 2) && 42 | ((char1 & 0xfc00) === 0xd800) && 43 | ((char2 & 0xfc00) === 0xdc00)) { 44 | return 0x10000 + ((char1 - 0xd800) << 10) + (char2 - 0xdc00); 45 | } else { 46 | return char1; 47 | } 48 | }; 49 | -------------------------------------------------------------------------------- /assets/stylesheets/bootstrap_override.styl: -------------------------------------------------------------------------------- 1 | // Buttons tweaks 2 | // 3 | .btn 4 | font-family sansWideFontFamily 5 | background-image none 6 | transition background-color 0.5s ease 7 | &:hover 8 | transition background-color 0.5s ease 9 | .btn-icon-only 10 | min-width 40px 11 | &:before 12 | margin 0 13 | .btn-info 14 | font-weight bold 15 | .btn.disabled, .btn[disabled] 16 | opacity .4 17 | 18 | .input-append 19 | whitespace nowrap 20 | 21 | 22 | // Focus style tweak 23 | // 24 | input, textarea 25 | box-shadow 0 1px 1px rgba(0, 0, 0, .3) inset 26 | input:focus, 27 | textarea:focus 28 | border-color rgba(168,82,82,.8) 29 | outline 0 30 | /* IE6-9 */ 31 | outline thin dotted \9 32 | box-shadow 0 1px 1px rgba(0, 0, 0, .075) inset, 0 0 8px rgba(168, 82, 82, .6) 33 | 34 | 35 | // Search icon tweak 36 | // 37 | .search-form 38 | .search-query 39 | padding-left 25px 40 | .icon-search 41 | position absolute 42 | color gray 43 | top 6px 44 | left 8px 45 | // restore font size 46 | font-size 14px 47 | 48 | // Fix vertical offset for toolbar inputs 49 | // 50 | .btn-group > input 51 | margin-bottom 0 52 | 53 | // When we like to hide ugly file input, but can't use display:none, because 54 | // Chromium will miss events. So, use .invisible, but position out of screen 55 | // 56 | input[type="file"].invisible 57 | position absolute 58 | left -10000px 59 | 60 | -------------------------------------------------------------------------------- /assets/vendor/bootstrap/bootstrap-responsive.less: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Responsive v2.0.3 3 | * 4 | * Copyright 2012 Twitter, Inc 5 | * Licensed under the Apache License v2.0 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Designed and built with all the love in the world @twitter by @mdo and @fat. 9 | */ 10 | 11 | 12 | // Responsive.less 13 | // For phone and tablet devices 14 | // ------------------------------------------------------------- 15 | 16 | 17 | // REPEAT VARIABLES & MIXINS 18 | // ------------------------- 19 | // Required since we compile the responsive stuff separately 20 | 21 | @import "src/less/variables.less"; 22 | @import "var_override.less"; // Modify this for custom colors, font-sizes, etc 23 | @import "src/less/mixins.less"; 24 | 25 | 26 | // RESPONSIVE CLASSES 27 | // ------------------ 28 | 29 | @import "src/less/responsive-utilities.less"; 30 | 31 | 32 | // MEDIA QUERIES 33 | // ------------------ 34 | 35 | // Phones to portrait tablets and narrow desktops 36 | //@import "src/less/responsive-767px-max.less"; 37 | 38 | // Tablets to regular desktops 39 | //@import "src/less/responsive-768px-979px.less"; 40 | 41 | // Large desktops 42 | @import "src/less/responsive-1200px-min.less"; 43 | 44 | 45 | // RESPONSIVE NAVBAR 46 | // ------------------ 47 | 48 | // From 979px and below, show a button to toggle navbar contents 49 | //@import "src/less/responsive-navbar.less"; 50 | -------------------------------------------------------------------------------- /assets/vendor/bootstrap/src/less/responsive-utilities.less: -------------------------------------------------------------------------------- 1 | // 2 | // Responsive: Utility classes 3 | // -------------------------------------------------- 4 | 5 | 6 | // Hide from screenreaders and browsers 7 | // Credit: HTML5 Boilerplate 8 | .hidden { 9 | display: none; 10 | visibility: hidden; 11 | } 12 | 13 | // Visibility utilities 14 | 15 | // For desktops 16 | .visible-phone { display: none !important; } 17 | .visible-tablet { display: none !important; } 18 | .hidden-phone { } 19 | .hidden-tablet { } 20 | .hidden-desktop { display: none !important; } 21 | .visible-desktop { display: inherit !important; } 22 | 23 | // Tablets & small desktops only 24 | @media (min-width: 768px) and (max-width: 979px) { 25 | // Hide everything else 26 | .hidden-desktop { display: inherit !important; } 27 | .visible-desktop { display: none !important ; } 28 | // Show 29 | .visible-tablet { display: inherit !important; } 30 | // Hide 31 | .hidden-tablet { display: none !important; } 32 | } 33 | 34 | // Phones only 35 | @media (max-width: 767px) { 36 | // Hide everything else 37 | .hidden-desktop { display: inherit !important; } 38 | .visible-desktop { display: none !important; } 39 | // Show 40 | .visible-phone { display: inherit !important; } // Use inherit to restore previous behavior 41 | // Hide 42 | .hidden-phone { display: none !important; } 43 | } 44 | -------------------------------------------------------------------------------- /assets/vendor/bootstrap/src/less/thumbnails.less: -------------------------------------------------------------------------------- 1 | // 2 | // Thumbnails 3 | // -------------------------------------------------- 4 | 5 | 6 | // Note: `.thumbnails` and `.thumbnails > li` are overriden in responsive files 7 | 8 | // Make wrapper ul behave like the grid 9 | .thumbnails { 10 | margin-left: -@gridGutterWidth; 11 | list-style: none; 12 | .clearfix(); 13 | } 14 | // Fluid rows have no left margin 15 | .row-fluid .thumbnails { 16 | margin-left: 0; 17 | } 18 | 19 | // Float li to make thumbnails appear in a row 20 | .thumbnails > li { 21 | float: left; // Explicity set the float since we don't require .span* classes 22 | margin-bottom: @baseLineHeight; 23 | margin-left: @gridGutterWidth; 24 | } 25 | 26 | // The actual thumbnail (can be `a` or `div`) 27 | .thumbnail { 28 | display: block; 29 | padding: 4px; 30 | line-height: @baseLineHeight; 31 | border: 1px solid #ddd; 32 | .border-radius(4px); 33 | .box-shadow(0 1px 3px rgba(0,0,0,.055)); 34 | .transition(all .2s ease-in-out); 35 | } 36 | // Add a hover state for linked versions only 37 | a.thumbnail:hover { 38 | border-color: @linkColor; 39 | .box-shadow(0 1px 4px rgba(0,105,214,.25)); 40 | } 41 | 42 | // Images and captions 43 | .thumbnail > img { 44 | display: block; 45 | max-width: 100%; 46 | margin-left: auto; 47 | margin-right: auto; 48 | } 49 | .thumbnail .caption { 50 | padding: 9px; 51 | color: @gray; 52 | } 53 | -------------------------------------------------------------------------------- /assets/vendor/bootstrap/src/less/alerts.less: -------------------------------------------------------------------------------- 1 | // 2 | // Alerts 3 | // -------------------------------------------------- 4 | 5 | 6 | // Base styles 7 | // ------------------------- 8 | 9 | .alert { 10 | padding: 8px 35px 8px 14px; 11 | margin-bottom: @baseLineHeight; 12 | text-shadow: 0 1px 0 rgba(255,255,255,.5); 13 | background-color: @warningBackground; 14 | border: 1px solid @warningBorder; 15 | .border-radius(4px); 16 | color: @warningText; 17 | } 18 | .alert h4 { 19 | margin: 0; 20 | } 21 | 22 | // Adjust close link position 23 | .alert .close { 24 | position: relative; 25 | top: -2px; 26 | right: -21px; 27 | line-height: @baseLineHeight; 28 | } 29 | 30 | 31 | // Alternate styles 32 | // ------------------------- 33 | 34 | .alert-success { 35 | background-color: @successBackground; 36 | border-color: @successBorder; 37 | color: @successText; 38 | } 39 | .alert-danger, 40 | .alert-error { 41 | background-color: @errorBackground; 42 | border-color: @errorBorder; 43 | color: @errorText; 44 | } 45 | .alert-info { 46 | background-color: @infoBackground; 47 | border-color: @infoBorder; 48 | color: @infoText; 49 | } 50 | 51 | 52 | // Block alerts 53 | // ------------------------- 54 | 55 | .alert-block { 56 | padding-top: 14px; 57 | padding-bottom: 14px; 58 | } 59 | .alert-block > p, 60 | .alert-block > ul { 61 | margin-bottom: 0; 62 | } 63 | .alert-block p + p { 64 | margin-top: 5px; 65 | } 66 | -------------------------------------------------------------------------------- /lib/init/assets/mincer.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | 4 | /*global nodeca, _*/ 5 | 6 | 7 | // stdlib 8 | var fs = require('fs'); 9 | var path = require('path'); 10 | 11 | 12 | // 3rd-party 13 | var Mincer = require('mincer'); 14 | var nib = require('nib'); 15 | 16 | 17 | // internal 18 | var environment = require('./mincer/environment'); 19 | var manifest = require('./mincer/manifest'); 20 | 21 | 22 | //////////////////////////////////////////////////////////////////////////////// 23 | 24 | 25 | // 26 | // set custom logger for the Mincer 27 | // 28 | 29 | Mincer.logger.use(nodeca.logger.getLogger('system')); 30 | 31 | // 32 | // Add some funky stuff to Stylus 33 | // 34 | 35 | Mincer.StylusEngine.registerConfigurator(function (style) { 36 | style.use(nib()); 37 | style.define('import-dir', require('./mincer/stylus/import-dir')); 38 | }); 39 | 40 | 41 | //////////////////////////////////////////////////////////////////////////////// 42 | 43 | 44 | module.exports = function mincer(root, callback) { 45 | var env = environment.configure(root).index, 46 | output = path.join(nodeca.runtime.apps[0].root, 'public', 'assets'); 47 | 48 | // 49 | // compile assets 50 | // 51 | 52 | manifest.compile(output, env, function (err, data) { 53 | if (err) { 54 | callback(err); 55 | return; 56 | } 57 | 58 | nodeca.runtime.assets = { environment: env, manifest: data }; 59 | callback(); 60 | }); 61 | }; 62 | -------------------------------------------------------------------------------- /client/ui/tabs.js: -------------------------------------------------------------------------------- 1 | /*global window, nodeca, jQuery, Handlebars, Backbone, $, _*/ 2 | 3 | 4 | "use strict"; 5 | 6 | 7 | // prevent the event from bubbling to ancestor elements 8 | function stopPropagation(event) { 9 | event.preventDefault(); 10 | event.stopPropagation(); 11 | } 12 | 13 | 14 | module.exports = Backbone.View.extend({ 15 | el: '#tabs', 16 | 17 | $preview_tab: null, 18 | $editor_tab: null, 19 | 20 | initialize: function () { 21 | // init tabs plugin 22 | this.$el.tab('show'); 23 | 24 | // add submenu activation 25 | this.$('a[data-toggle="tab"]').on('shown', function (event) { 26 | var $curr = $(event.target), 27 | $prev = $(event.relatedTarget); 28 | 29 | $($prev.data('submenu')).removeClass('active'); 30 | $($curr.data('submenu')).addClass('active'); 31 | }); 32 | 33 | this.$preview_tab = this.$('a[href="#preview"]'); 34 | this.$editor_tab = this.$('a[href="#codes-editor"]'); 35 | 36 | // disable click handler of tabs plugin on preview and result tabs 37 | this.$preview_tab.add(this.$editor_tab).on('click', stopPropagation); 38 | }, 39 | 40 | activate: function (id) { 41 | this.$('a[href="' + id + '"]').tab('show'); 42 | }, 43 | 44 | setGlyphsCount: function (count) { 45 | var $tabs = this.$preview_tab.add(this.$editor_tab); 46 | 47 | $tabs.toggleClass('disabled', !count); 48 | $tabs[!count ? 'on' : 'off']('click', stopPropagation); 49 | } 50 | }); 51 | -------------------------------------------------------------------------------- /assets/vendor/bootstrap/src/less/code.less: -------------------------------------------------------------------------------- 1 | // 2 | // Code (inline and blocK) 3 | // -------------------------------------------------- 4 | 5 | 6 | // Inline and block code styles 7 | code, 8 | pre { 9 | padding: 0 3px 2px; 10 | #font > #family > .monospace; 11 | font-size: @baseFontSize - 2; 12 | color: @grayDark; 13 | .border-radius(3px); 14 | } 15 | 16 | // Inline code 17 | code { 18 | padding: 2px 4px; 19 | color: #d14; 20 | background-color: #f7f7f9; 21 | border: 1px solid #e1e1e8; 22 | } 23 | 24 | // Blocks of code 25 | pre { 26 | display: block; 27 | padding: (@baseLineHeight - 1) / 2; 28 | margin: 0 0 @baseLineHeight / 2; 29 | font-size: @baseFontSize - 1; // 14px to 13px 30 | line-height: @baseLineHeight; 31 | word-break: break-all; 32 | word-wrap: break-word; 33 | white-space: pre; 34 | white-space: pre-wrap; 35 | background-color: #f5f5f5; 36 | border: 1px solid #ccc; // fallback for IE7-8 37 | border: 1px solid rgba(0,0,0,.15); 38 | .border-radius(4px); 39 | 40 | // Make prettyprint styles more spaced out for readability 41 | &.prettyprint { 42 | margin-bottom: @baseLineHeight; 43 | } 44 | 45 | // Account for some code outputs that place code tags in pre tags 46 | code { 47 | padding: 0; 48 | color: inherit; 49 | background-color: transparent; 50 | border: 0; 51 | } 52 | } 53 | 54 | // Enable scrollable blocks of code 55 | .pre-scrollable { 56 | max-height: 340px; 57 | overflow-y: scroll; 58 | } -------------------------------------------------------------------------------- /client/init.js: -------------------------------------------------------------------------------- 1 | /*global $, nodeca*/ 2 | 3 | 4 | "use strict"; 5 | 6 | 7 | module.exports = function () { 8 | $(function () { 9 | nodeca.client.init.app(); 10 | 11 | // 12 | // Social buttons defered load - after all 13 | // 14 | 15 | setTimeout(function () { 16 | 17 | // Twitter buttons 18 | 19 | (function(d,s,id) { 20 | var js, fjs = d.getElementsByTagName(s)[0]; 21 | 22 | if (!d.getElementById(id)) { 23 | js = d.createElement(s); 24 | js.id = id; 25 | js.src = "//platform.twitter.com/widgets.js"; 26 | 27 | fjs.parentNode.insertBefore(js,fjs); 28 | } 29 | }(document, "script", "twitter-wjs")); 30 | 31 | // Google +1 32 | 33 | (function() { 34 | var po = document.createElement('script'); 35 | 36 | po.type = 'text/javascript'; 37 | po.async = true; 38 | po.src = 'https://apis.google.com/js/plusone.js'; 39 | 40 | var s = document.getElementsByTagName('script')[0]; 41 | s.parentNode.insertBefore(po, s); 42 | }()); 43 | 44 | // Flattr 45 | /* 46 | 47 | (function() { 48 | var s = document.createElement('script'), t = document.getElementsByTagName('script')[0]; 49 | s.type = 'text/javascript'; 50 | s.async = true; 51 | s.src = '//api.flattr.com/js/0.6/load.js?mode=auto'; 52 | t.parentNode.insertBefore(s, t); 53 | }()); 54 | */ 55 | 56 | }, 2000); 57 | }); 58 | }; 59 | -------------------------------------------------------------------------------- /config/logger.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Logger configuration 3 | # 4 | 5 | logger: 6 | 7 | options: 8 | 9 | # 10 | # Global minimal error level 11 | # 12 | 13 | level: debug 14 | 15 | # 16 | # Appenders options 17 | # 18 | 19 | file: 20 | logSize: 10 # Max MB per log file 21 | backups: 5 # Amount of "old" log files 22 | 23 | # 24 | # Logger categories 25 | # 26 | 27 | system: 28 | - level: debug 29 | file: log/system.log 30 | - level: error 31 | file: log/system-error.log 32 | 33 | server.static: 34 | - level: debug 35 | file: log/static.log 36 | - level: error 37 | file: log/static-error.log 38 | 39 | server.assets: 40 | - level: debug 41 | file: log/static.log 42 | - level: error 43 | file: log/static-error.log 44 | 45 | server.font.download: 46 | - level: debug 47 | file: log/static.log 48 | - level: error 49 | file: log/static-error.log 50 | 51 | server.font: 52 | - level: debug 53 | file: log/generator.log 54 | - level: error 55 | file: log/generator-error.log 56 | 57 | server: 58 | - level: debug 59 | file: log/server.log 60 | - level: error 61 | file: log/server-error.log 62 | 63 | rpc: 64 | - level: debug 65 | file: log/rpc.log 66 | - level: error 67 | file: log/rpc-error.log 68 | 69 | 70 | #^production: 71 | # options: 72 | # logger: 73 | # level: info 74 | 75 | 76 | # 77 | # vim:syntax=yaml 78 | -------------------------------------------------------------------------------- /server/assets.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | /*global nodeca*/ 5 | 6 | 7 | // 3rd-party 8 | var Mincer = require('mincer'); 9 | 10 | 11 | // internal 12 | var logger = nodeca.logger.getLogger('server.assets'); 13 | 14 | 15 | //////////////////////////////////////////////////////////////////////////////// 16 | 17 | 18 | var server; 19 | 20 | 21 | 22 | 23 | // Formats and writes log event into our logger 24 | // 25 | function assets_logger(level, event) { 26 | logger[level]('%s - "%s %s HTTP/%s" %d "%s" - %s', 27 | event.remoteAddress, 28 | event.method, 29 | event.url, 30 | event.httpVersion, 31 | event.code, 32 | event.headers['user-agent'], 33 | event.message); 34 | } 35 | 36 | 37 | 38 | // helper to pass request to the lazy-loaded miner server 39 | function call_mincer_server(req, res) { 40 | var assets; 41 | 42 | if (!server) { 43 | assets = nodeca.runtime.assets, 44 | server = new Mincer.Server(assets.environment, assets.manifest); 45 | server.log = assets_logger; 46 | } 47 | 48 | server.handle(req, res); 49 | } 50 | 51 | 52 | //////////////////////////////////////////////////////////////////////////////// 53 | 54 | 55 | module.exports = function (params, callback) { 56 | if (!this.origin.http) { 57 | callback({statusCode: 400, body: "HTTP ONLY"}); 58 | return; 59 | } 60 | 61 | this.origin.http.req.url = params.path; 62 | call_mincer_server(this.origin.http.req, this.origin.http.res); 63 | }; 64 | -------------------------------------------------------------------------------- /lib/init/assets.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | 4 | /*global nodeca, _*/ 5 | 6 | 7 | // 3rd-party 8 | var async = require('nlib').Vendor.Async; 9 | var fstools = require('nlib').Vendor.FsTools; 10 | 11 | 12 | //////////////////////////////////////////////////////////////////////////////// 13 | 14 | 15 | /** 16 | * 17 | * RESULTING STRUCTURE 18 | * 19 | * . 20 | * ├╴ i18n.js 21 | * ├╴ views.js 22 | * ╰╴ api.js 23 | * 24 | **/ 25 | 26 | //////////////////////////////////////////////////////////////////////////////// 27 | 28 | 29 | module.exports = function (next) { 30 | var tmp, environment; 31 | 32 | try { 33 | tmp = fstools.tmpdir('/tmp/fontello.XXXXX'); 34 | } catch (err) { 35 | next(err); 36 | return; 37 | } 38 | 39 | // schedule files cleanup upon normal exit 40 | process.on('exit', function (code) { 41 | if (0 !== +code) { 42 | console.warn("Unclean exit. Bundled files left in '" + tmp + "'"); 43 | return; 44 | } 45 | 46 | try { 47 | console.warn("Removing '" + tmp + "'..."); 48 | fstools.removeSync(tmp); 49 | } catch(err) { 50 | console.warn("Failed remove '" + tmp + "'... " + String(err)); 51 | } 52 | }); 53 | 54 | async.series([ 55 | async.apply(fstools.mkdir, tmp), 56 | async.apply(require('./assets/build_api_tree'), tmp), 57 | async.apply(require('./assets/build_i18n_files'), tmp), 58 | async.apply(require('./assets/compile_views'), tmp), 59 | async.apply(require('./assets/mincer'), tmp) 60 | ], function (err/*, results*/) { 61 | next(err); 62 | }); 63 | }; 64 | -------------------------------------------------------------------------------- /lib/init/server/http.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | 4 | /*global nodeca, _*/ 5 | 6 | 7 | // stdlib 8 | var url = require('url'); 9 | 10 | 11 | // 3rd-party 12 | var qs = require('qs'); 13 | 14 | 15 | // internal 16 | var env = require('../../env'); 17 | var handle_http = require('./http/handle_http'); 18 | var handle_rpc = require('./http/handle_rpc'); 19 | 20 | 21 | //////////////////////////////////////////////////////////////////////////////// 22 | 23 | 24 | // Attach HTTP application server to the given `server` 25 | // 26 | module.exports.attach = function attach(server, next) { 27 | 28 | // 29 | // For each connection - update timeout & disable buffering 30 | // 31 | 32 | server.addListener("connection", function (socket) { 33 | socket.setTimeout(15 * 1000); 34 | socket.setNoDelay(); 35 | }); 36 | 37 | // 38 | // Define application runner 39 | // 40 | 41 | server.on('request', function (req, res) { 42 | var parsed = url.parse(req.url), 43 | handle = ('/rpc' === parsed.pathname) ? handle_rpc : handle_http, 44 | data = ''; 45 | 46 | req.query = qs.parse(parsed.query || ''); 47 | req.pathname = parsed.pathname; 48 | 49 | // start harvesting POST data 50 | req.on('data', function (chunk) { 51 | data += chunk; 52 | }); 53 | 54 | // when done, merge post params and handle request 55 | req.on('end', function () { 56 | req.params = _.defaults(qs.parse(data), req.query); 57 | handle(req, res); 58 | }); 59 | }); 60 | 61 | // 62 | // HTTP server is ready 63 | // 64 | 65 | next(); 66 | 67 | }; 68 | -------------------------------------------------------------------------------- /fontello.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | 4 | /*global nodeca*/ 5 | 6 | 7 | "use strict"; 8 | 9 | 10 | var app = require('nlib').Application.create({ 11 | name: 'fontomas', 12 | root: __dirname 13 | }); 14 | 15 | 16 | // 17 | // Preset application version 18 | // 19 | 20 | 21 | nodeca.runtime.version = require('./package.json').version; 22 | 23 | 24 | // 25 | // Catch unexpected exceptions 26 | // 27 | 28 | 29 | process.on('uncaughtException', function (err) { 30 | var msg, stack; 31 | 32 | try { 33 | msg = 'UNCAUGHT EXCEPTION !!! ' + String(err); 34 | stack = err.stack || ''; 35 | 36 | if (err.original) { 37 | msg += '\n' + String(err.original); 38 | stack = err.original.stack || stack; 39 | } 40 | 41 | msg += '\n' + stack.split('\n').slice(1).join('\n'); 42 | 43 | nodeca.logger.fatal(msg); 44 | } catch (loggerError) { 45 | // THIS SHOULD NEVER-EVER-EVER HAPPEN -- THIS IS A WORST CASE SCENARIO 46 | // USAGE: ./nodeca.js 2>/var/log/nodeca-cf.log 47 | process.stderr.write('\nLogger failed write: ' + loggerError.stack); 48 | process.stderr.write('\nOriginal error happened: ' + msg); 49 | } 50 | }); 51 | 52 | 53 | // 54 | // Handle SIGnals 55 | // 56 | 57 | 58 | function shutdown_gracefully() { 59 | nodeca.logger.info('Shutting down...'); 60 | process.exit(0); 61 | } 62 | 63 | 64 | // shutdown gracefully on SIGTERM : 65 | process.on('SIGTERM', shutdown_gracefully); 66 | process.on('SIGINT', shutdown_gracefully); 67 | 68 | 69 | // 70 | // Register filters 71 | // 72 | 73 | 74 | require('./lib/filters'); 75 | 76 | 77 | // 78 | // Run application 79 | // 80 | 81 | 82 | app.run(); 83 | -------------------------------------------------------------------------------- /support/font-templates/css/css.jade: -------------------------------------------------------------------------------- 1 | - if (_.any(glyphs, function (g) { return 0xffff < g.code; })) 2 | | @charset "UTF-8"; 3 | != '\n' 4 | != '\n' 5 | 6 | :stylus_nowrap 7 | @font-face { 8 | font-family: '#{font.fontname}'; 9 | src: url('../font/#{font.fontname}.eot'); 10 | src: url('../font/#{font.fontname}.eot?#iefix') format('embedded-opentype'), 11 | url('../font/#{font.fontname}.woff') format('woff'), 12 | url('../font/#{font.fontname}.ttf') format('truetype'), 13 | url('../font/#{font.fontname}.svg##{font.fontname}') format('svg'); 14 | font-weight: normal; 15 | font-style: normal; 16 | } 17 | 18 | [class^="icon-"], [class*=" icon-"] 19 | &:before 20 | font-family '#{font.fontname}' 21 | font-style normal 22 | font-weight normal 23 | speak none 24 | 25 | display inline-block 26 | text-decoration inherit 27 | width 1em 28 | margin-right .2em 29 | text-align center 30 | opacity .7 31 | 32 | /* Uncomment for 3D effect */ 33 | /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */ 34 | 35 | /* fix buttons height */ 36 | line-height 1em 37 | 38 | /* you can be more comfortable with increased icons size */ 39 | /* font-size: 120%; */ 40 | 41 | - var i, g, css, hex, chr 42 | - for (i in glyphs) 43 | - g = glyphs[i] 44 | - css = meta.css_prefix + g.css 45 | - hex = '\\' + g.code.toString(16) 46 | - chr = unichr(g.code) 47 | != '\n' 48 | - if (0xffff < g.code) 49 | | .#{css}:before { content: '#{chr}'; } /* '#{hex}' */ 50 | - else 51 | | .#{css}:before { content: '#{hex}'; } /* '#{chr}' */ 52 | -------------------------------------------------------------------------------- /client/render.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | /** 5 | * client 6 | **/ 7 | 8 | 9 | /*global window, $, _, JASON, nodeca*/ 10 | 11 | 12 | //////////////////////////////////////////////////////////////////////////////// 13 | 14 | 15 | var tzOffset = (new Date).getTimezoneOffset(); 16 | var helpers = {}; 17 | 18 | 19 | //////////////////////////////////////////////////////////////////////////////// 20 | 21 | 22 | helpers.t = nodeca.runtime.t; 23 | 24 | 25 | _.each(['asset_path', 'asset_include'], function (method) { 26 | helpers[method] = function () { 27 | throw method + '() is a server-side only helper, thus can be used in base layouts only.'; 28 | }; 29 | }); 30 | 31 | helpers.link_to = function (name, params) { 32 | return nodeca.runtime.router.linkTo(name, params) || '#'; 33 | }; 34 | 35 | helpers.nodeca = function (path) { 36 | return !path ? nodeca : nodeca.shared.getByPath(nodeca, path); 37 | }; 38 | 39 | // substitute JASON with JSON 40 | helpers.jason = JSON.stringify; 41 | 42 | 43 | //////////////////////////////////////////////////////////////////////////////// 44 | 45 | 46 | /** 47 | * client.render(apiPath[, locals[, layout]]) -> Void 48 | * - apiPath (String): Server method API path. 49 | * - locals (Object): Locals data for the renderer 50 | * - layout (String): Layout or layouts stack 51 | * 52 | * Renders view. 53 | **/ 54 | module.exports = function render(apiPath, locals, layout) { 55 | if (!nodeca.shared.getByPath(nodeca.views, apiPath)) { 56 | throw new Error("View " + apiPath + " not found"); 57 | } 58 | 59 | locals = _.extend(locals || {}, helpers); 60 | return nodeca.shared.render(nodeca.views, apiPath, locals, layout, true); 61 | }; 62 | -------------------------------------------------------------------------------- /assets/vendor/bootstrap/src/less/pagination.less: -------------------------------------------------------------------------------- 1 | // 2 | // Pagination (multiple pages) 3 | // -------------------------------------------------- 4 | 5 | 6 | .pagination { 7 | height: @baseLineHeight * 2; 8 | margin: @baseLineHeight 0; 9 | } 10 | .pagination ul { 11 | display: inline-block; 12 | .ie7-inline-block(); 13 | margin-left: 0; 14 | margin-bottom: 0; 15 | .border-radius(3px); 16 | .box-shadow(0 1px 2px rgba(0,0,0,.05)); 17 | } 18 | .pagination ul > li { 19 | display: inline; 20 | } 21 | .pagination ul > li > a, 22 | .pagination ul > li > span { 23 | float: left; 24 | padding: 0 14px; 25 | line-height: (@baseLineHeight * 2) - 2; 26 | text-decoration: none; 27 | background-color: @paginationBackground; 28 | border: 1px solid @paginationBorder; 29 | border-left-width: 0; 30 | } 31 | .pagination ul > li > a:hover, 32 | .pagination ul > .active > a, 33 | .pagination ul > .active > span { 34 | background-color: #f5f5f5; 35 | } 36 | .pagination ul > .active > a, 37 | .pagination ul > .active > span { 38 | color: @grayLight; 39 | cursor: default; 40 | } 41 | .pagination ul > .disabled > span, 42 | .pagination ul > .disabled > a, 43 | .pagination ul > .disabled > a:hover { 44 | color: @grayLight; 45 | background-color: transparent; 46 | cursor: default; 47 | } 48 | .pagination ul > li:first-child > a, 49 | .pagination ul > li:first-child > span { 50 | border-left-width: 1px; 51 | .border-radius(3px 0 0 3px); 52 | } 53 | .pagination ul > li:last-child > a, 54 | .pagination ul > li:last-child > span { 55 | .border-radius(0 3px 3px 0); 56 | } 57 | 58 | // Centered 59 | .pagination-centered { 60 | text-align: center; 61 | } 62 | .pagination-right { 63 | text-align: right; 64 | } 65 | -------------------------------------------------------------------------------- /assets/vendor/bootstrap/src/less/bootstrap.less: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v2.1.1 3 | * 4 | * Copyright 2012 Twitter, Inc 5 | * Licensed under the Apache License v2.0 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Designed and built with all the love in the world @twitter by @mdo and @fat. 9 | */ 10 | 11 | // CSS Reset 12 | @import "reset.less"; 13 | 14 | // Core variables and mixins 15 | @import "variables.less"; // Modify this for custom colors, font-sizes, etc 16 | @import "mixins.less"; 17 | 18 | // Grid system and page structure 19 | @import "scaffolding.less"; 20 | @import "grid.less"; 21 | @import "layouts.less"; 22 | 23 | // Base CSS 24 | @import "type.less"; 25 | @import "code.less"; 26 | @import "forms.less"; 27 | @import "tables.less"; 28 | 29 | // Components: common 30 | @import "sprites.less"; 31 | @import "dropdowns.less"; 32 | @import "wells.less"; 33 | @import "component-animations.less"; 34 | @import "close.less"; 35 | 36 | // Components: Buttons & Alerts 37 | @import "buttons.less"; 38 | @import "button-groups.less"; 39 | @import "alerts.less"; // Note: alerts share common CSS with buttons and thus have styles in buttons.less 40 | 41 | // Components: Nav 42 | @import "navs.less"; 43 | @import "navbar.less"; 44 | @import "breadcrumbs.less"; 45 | @import "pagination.less"; 46 | @import "pager.less"; 47 | 48 | // Components: Popovers 49 | @import "modals.less"; 50 | @import "tooltip.less"; 51 | @import "popovers.less"; 52 | 53 | // Components: Misc 54 | @import "thumbnails.less"; 55 | @import "labels-badges.less"; 56 | @import "progress-bars.less"; 57 | @import "accordion.less"; 58 | @import "carousel.less"; 59 | @import "hero-unit.less"; 60 | 61 | // Utility classes 62 | @import "utilities.less"; // Has to be last to override when necessary 63 | -------------------------------------------------------------------------------- /cli/font_config.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | 4 | /*global nodeca*/ 5 | 6 | 7 | // nodeca 8 | var NLib = require('nlib'); 9 | 10 | 11 | // 3rd-party 12 | var Async = NLib.Vendor.Async; 13 | var FsTools = NLib.Vendor.FsTools; 14 | 15 | 16 | // internal 17 | var fontConfig = require('../lib/font_config'); 18 | 19 | 20 | module.exports.parserParameters= { 21 | version: nodeca.runtime.version, 22 | addHelp: true, 23 | help: 'prepare font configuration', 24 | description: 'prepare font configuration' 25 | }; 26 | 27 | 28 | module.exports.commandLineArguments = [ 29 | { 30 | args: ['-i', '--input'], 31 | options: { 32 | dest: 'input', 33 | help: 'user config', 34 | type: 'string', 35 | metavar: 'FILE', 36 | required: true 37 | } 38 | }, 39 | { 40 | args: ['-o', '--output'], 41 | options: { 42 | dest: 'output', 43 | help: 'resulting config', 44 | type: 'string', 45 | metavar: 'FILE', 46 | required: true 47 | } 48 | } 49 | ]; 50 | 51 | 52 | module.exports.run = function (args, callback) { 53 | Async.series([ 54 | NLib.InitStages.loadServerApiSubtree, 55 | NLib.InitStages.loadSharedApiSubtree, 56 | NLib.InitStages.loadClientApiSubtree 57 | ], function (err) { 58 | var input, config; 59 | 60 | if (err) { 61 | callback(err); 62 | return; 63 | } 64 | 65 | try { 66 | input = require(args.input); 67 | } catch (err) { 68 | callback(err); 69 | return; 70 | } 71 | 72 | try { 73 | config = JSON.stringify(fontConfig(input)); 74 | require('fs').writeFileSync(args.output, config); 75 | } catch (err) { 76 | callback(err); 77 | return; 78 | } 79 | 80 | callback(); 81 | }); 82 | }; 83 | -------------------------------------------------------------------------------- /lib/filters/fix_vhost.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | /*global nodeca*/ 5 | 6 | 7 | //////////////////////////////////////////////////////////////////////////////// 8 | 9 | 10 | // TODO: test before assigning this middleware 11 | var NOHOST_RE = new RegExp( 12 | '^(?:' + 13 | [ 'localhost', 14 | '\\d{1,3}(?:\\.\\d{1,3}){3}', 15 | '(?::1|[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){4,7})' 16 | ].join('|') + 17 | ')$', 'i'); 18 | 19 | //////////////////////////////////////////////////////////////////////////////// 20 | 21 | 22 | // Filter middleware that interrupts request and sends redirect response with 23 | // new `Location` to default host if `Host` of request is unknown. 24 | // 25 | nodeca.filters.before('', { weight: -900 }, function fix_vhost(params, callback) { 26 | var http = this.origin.http, host; 27 | 28 | if (!http) { 29 | callback(); 30 | return; 31 | } 32 | 33 | // if no host in config - then we accept any host 34 | if (!nodeca.config.listen.host || NOHOST_RE.test(nodeca.config.listen.host)) { 35 | callback(); 36 | return; 37 | } 38 | 39 | host = (http.req.headers.host || '').split(':')[0]; 40 | 41 | // known hostname 42 | if (host === nodeca.config.listen.host) { 43 | callback(); 44 | return; 45 | } 46 | 47 | // fix hostname by redirect 48 | host = nodeca.config.listen.host; 49 | if (nodeca.config.listen.port && 80 !== nodeca.config.listen.port) { 50 | host += ':' + nodeca.config.listen.port; 51 | } 52 | 53 | // Don't use 301 redirect, because it locks browsers forever, 54 | // and can make troubles with adding new domains to project. 55 | // But add cache for 1 day as compensation. 56 | callback({ statusCode: 302, 57 | headers: { 58 | 'Location': 'http://' + host, 59 | 'Cache-Control': 'public, max-age=' + 60*60*24 60 | } 61 | }); 62 | }); 63 | -------------------------------------------------------------------------------- /client/models/font.js: -------------------------------------------------------------------------------- 1 | /*global window, nodeca, jQuery, Handlebars, Backbone, $, _*/ 2 | 3 | 4 | "use strict"; 5 | 6 | 7 | module.exports = Backbone.Model.extend({ 8 | defaults: function () { 9 | return { 10 | id : null, 11 | font : null, 12 | meta : null, 13 | collapsed : false 14 | }; 15 | }, 16 | 17 | 18 | initialize: function (attributes) { 19 | this._glyphs = new (Backbone.Collection.extend({ 20 | model: nodeca.client.models.glyph 21 | }))(); 22 | 23 | // remove glyphs data array 24 | this.unset('glyphs', {silent: true}); 25 | 26 | // process each glyph data 27 | _.each(attributes.glyphs || [], this.addGlyph, this); 28 | }, 29 | 30 | 31 | getName: function () { 32 | return this.get('font').fontname; 33 | }, 34 | 35 | 36 | addGlyph: function (data) { 37 | return this._glyphs.create({ 38 | uid : data.uid, 39 | source : data, 40 | font : this 41 | }); 42 | }, 43 | 44 | 45 | eachGlyph: function (iterator, thisArg) { 46 | this._glyphs.each(iterator, thisArg); 47 | }, 48 | 49 | 50 | getGlyph: function (criteria) { 51 | var g; 52 | 53 | if (criteria.uid) { 54 | g = this._glyphs.get(criteria.uid); 55 | } 56 | 57 | if (!g && criteria.code) { 58 | g = this._glyphs.find(function (g) { 59 | return criteria.code === g.get('source').code; 60 | }); 61 | } 62 | 63 | if (!g && criteria.css) { 64 | g = this._glyphs.find(function (g) { 65 | return criteria.css === g.get('source').css; 66 | }); 67 | } 68 | 69 | return g; 70 | }, 71 | 72 | 73 | // Stub to prevent Backbone from reading or saving the model to the server. 74 | // Backbone calls `Backbone.sync()` function (on fetch/save/destroy) 75 | // if model doesn't have own `sync()` method. 76 | sync: function sync() {} 77 | }); 78 | -------------------------------------------------------------------------------- /assets/vendor/bootstrap/src/less/tooltip.less: -------------------------------------------------------------------------------- 1 | // 2 | // Tooltips 3 | // -------------------------------------------------- 4 | 5 | 6 | // Base class 7 | .tooltip { 8 | position: absolute; 9 | z-index: @zindexTooltip; 10 | display: block; 11 | visibility: visible; 12 | padding: 5px; 13 | font-size: 11px; 14 | .opacity(0); 15 | &.in { .opacity(80); } 16 | &.top { margin-top: -3px; } 17 | &.right { margin-left: 3px; } 18 | &.bottom { margin-top: 3px; } 19 | &.left { margin-left: -3px; } 20 | } 21 | 22 | // Wrapper for the tooltip content 23 | .tooltip-inner { 24 | max-width: 200px; 25 | padding: 3px 8px; 26 | color: @tooltipColor; 27 | text-align: center; 28 | text-decoration: none; 29 | background-color: @tooltipBackground; 30 | .border-radius(4px); 31 | } 32 | 33 | // Arrows 34 | .tooltip-arrow { 35 | position: absolute; 36 | width: 0; 37 | height: 0; 38 | border-color: transparent; 39 | border-style: solid; 40 | } 41 | .tooltip { 42 | &.top .tooltip-arrow { 43 | bottom: 0; 44 | left: 50%; 45 | margin-left: -@tooltipArrowWidth; 46 | border-width: @tooltipArrowWidth @tooltipArrowWidth 0; 47 | border-top-color: @tooltipArrowColor; 48 | } 49 | &.right .tooltip-arrow { 50 | top: 50%; 51 | left: 0; 52 | margin-top: -@tooltipArrowWidth; 53 | border-width: @tooltipArrowWidth @tooltipArrowWidth @tooltipArrowWidth 0; 54 | border-right-color: @tooltipArrowColor; 55 | } 56 | &.left .tooltip-arrow { 57 | top: 50%; 58 | right: 0; 59 | margin-top: -@tooltipArrowWidth; 60 | border-width: @tooltipArrowWidth 0 @tooltipArrowWidth @tooltipArrowWidth; 61 | border-left-color: @tooltipArrowColor; 62 | } 63 | &.bottom .tooltip-arrow { 64 | top: 0; 65 | left: 50%; 66 | margin-left: -@tooltipArrowWidth; 67 | border-width: 0 @tooltipArrowWidth @tooltipArrowWidth; 68 | border-bottom-color: @tooltipArrowColor; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /support/font-templates/README.txt: -------------------------------------------------------------------------------- 1 | This webfont is generated by http://fontello.com open source project. 2 | 3 | 4 | ================================================================================ 5 | Please, note, that you should obey original font licences, used to make this 6 | webfont pack. Details available in LICENSE.txt file. 7 | 8 | - Usually, it's enougth to publish content of LICENSE.txt file somewhere on your 9 | site in "About" section. 10 | 11 | - If your project is open-source, usually, it will be ok to make LICENSE.txt 12 | file publically available in your repository. 13 | 14 | - Fonts, used in Fontello, don't require to make clickable links on your site. 15 | But any kind of additional authors crediting is welcome. 16 | ================================================================================ 17 | 18 | 19 | Attention for server setup (IE users and others) 20 | ------------------------------------------------ 21 | 22 | You MUST setup server to reply with proper `mime-types` for font files. In other 23 | case, some browsers will fail to show fonts. 24 | 25 | Usually, `apache` already has necessary settings, but `nginx` and other 26 | webservers should be tuned. Here is list of mime types for our file extentions: 27 | 28 | - `application/vnd.ms-fontobject` - eot 29 | - `application/x-font-woff` - woff 30 | - `application/x-font-ttf` - ttf 31 | - `image/svg+xml` - svg 32 | 33 | 34 | Comments on archive content 35 | --------------------------- 36 | 37 | - /font/* - fonts in different formats 38 | 39 | - /css/* - different kinds of css, for all situations. Should be ok with 40 | twitter bootstrap. Also, you can skip style and assign icon classes 41 | directly to text elements 42 | 43 | - demo.html - demo file, to show your webfont content 44 | 45 | - LICENSE.txt - license info about source fonts, used to build your one. 46 | 47 | - config.json - keeps your settings. You can import it back to fontello anytime, 48 | to continue your work 49 | -------------------------------------------------------------------------------- /assets/vendor/fontello/src/README.txt: -------------------------------------------------------------------------------- 1 | This webfont is generated by http://fontello.com open source project. 2 | 3 | 4 | ================================================================================ 5 | Please, note, that you should obey original font licences, used to make this 6 | webfont pack. Details available in LICENSE.txt file. 7 | 8 | - Usually, it's enougth to publish content of LICENSE.txt file somewhere on your 9 | site in "About" section. 10 | 11 | - If your project is open-source, usually, it will be ok to make LICENSE.txt 12 | file publically available in your repository. 13 | 14 | - Fonts, used in Fontello, don't require to make clickable links on your site. 15 | But any kind of additional authors crediting is welcome. 16 | ================================================================================ 17 | 18 | 19 | Attention for server setup (IE users and others) 20 | ------------------------------------------------ 21 | 22 | You MUST setup server to reply with proper `mime-types` for font files. In other 23 | case, some browsers will fail to show fonts. 24 | 25 | Usually, `apache` already has necessary settings, but `nginx` and other 26 | webservers should be tuned. Here is list of mime types for our file extentions: 27 | 28 | - `application/vnd.ms-fontobject` - eot 29 | - `application/x-font-woff` - woff 30 | - `application/x-font-ttf` - ttf 31 | - `image/svg+xml` - svg 32 | 33 | 34 | Comments on archive content 35 | --------------------------- 36 | 37 | - /font/* - fonts in different formats 38 | 39 | - /css/* - different kinds of css, for all situations. Should be ok with 40 | twitter bootstrap. Also, you can skip style and assign icon classes 41 | directly to text elements 42 | 43 | - demo.html - demo file, to show your webfont content 44 | 45 | - LICENSE.txt - license info about source fonts, used to build your one. 46 | 47 | - config.json - keeps your settings. You can import it back to fontello anytime, 48 | to continue your work 49 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "fontello", 3 | "version" : "2.0.4", 4 | "description" : "Iconic fonts scissors", 5 | "keywords" : ["icon", "font", "editor"], 6 | "homepage" : "https://github.com/nodeca/fontomas", 7 | 8 | "authors" : [ 9 | "Roman I Shmelev (https://github.com/shmelev)", 10 | "Aleksey Zapparov (https://github.com/ixti)", 11 | "Vitaly Puzrin (https://github.com/puzrin)" 12 | ], 13 | 14 | "bugs" : { "url": "https://github.com/fontello/fontello/issues" }, 15 | "license" : { "type": "MIT", "url": "https://github.com/fontello/fontello/blob/master/LICENSE" }, 16 | "repository" : { "type": "git", "url": "git://github.com/fontello/fontello.git" }, 17 | 18 | "main" : "./index.js", 19 | 20 | "dependencies" : { 21 | "nlib" : "git://github.com/nodeca/nlib.git#95cd4ca92ca8d3b2d251830c01a277202e7dc09d", 22 | "argparse" : "~0.1.3", 23 | "underscore" : "~1.3.3", 24 | "send" : "~0.0.3", 25 | "qs" : "~0.5.0", 26 | "mincer" : "~0.2.5", 27 | "stylus" : "~0.29.0", 28 | "nib" : "~0.8.1", 29 | "less" : "~1.3.0", 30 | "ejs" : "~0.8.2", 31 | "uglify-js" : "~1.3.1", 32 | "csso" : "~1.2.14", 33 | "jade" : "~0.27.2", 34 | "neuron" : "~0.4.5", 35 | "cron" : "~1.0.0" 36 | }, 37 | "devDependencies" : { 38 | "webkit-devtools-agent" : "~ 0.0.4" 39 | }, 40 | "engines" : { "node": ">= 0.8.0" } 41 | } 42 | -------------------------------------------------------------------------------- /server/static.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | 4 | /** 5 | * server 6 | **/ 7 | 8 | 9 | /*global nodeca, _*/ 10 | 11 | 12 | // stdlib 13 | var path = require('path'); 14 | var http = require('http'); 15 | 16 | 17 | // 3rd-party 18 | var send = require('send'); 19 | 20 | 21 | //////////////////////////////////////////////////////////////////////////////// 22 | 23 | 24 | var root = path.join(nodeca.runtime.apps[0].root, 'public/root'); 25 | var logger = nodeca.logger.getLogger('server.static'); 26 | 27 | 28 | //////////////////////////////////////////////////////////////////////////////// 29 | 30 | 31 | /** 32 | * server.static(params, callback) -> Void 33 | * 34 | * - **HTTP only** 35 | * 36 | * Middleware that serves static assets from `public/root` directory under the 37 | * main application root path. 38 | **/ 39 | module.exports = function (params, callback) { 40 | var req, res; 41 | 42 | if (!this.origin.http) { 43 | callback({statusCode: 400, body: "HTTP ONLY"}); 44 | return; 45 | } 46 | 47 | req = this.origin.http.req; 48 | res = this.origin.http.res; 49 | 50 | if ('GET' !== req.method && 'HEAD' !== req.method) { 51 | callback({statusCode: 400}); 52 | return; 53 | } 54 | 55 | send(req, params.file) 56 | .root(root) 57 | .on('error', function (err) { 58 | if (404 === err.status) { 59 | callback({statusCode: 404}); 60 | return; 61 | } 62 | 63 | callback(err); 64 | }) 65 | .on('directory', function () { 66 | callback({statusCode: 400}); 67 | }) 68 | .on('end', function() { 69 | logger.info('%s - "%s %s HTTP/%s" %d "%s" - %s', 70 | req.connection.remoteAddress, 71 | req.method, 72 | req.url, 73 | req.httpVersion, 74 | res.statusCode, 75 | req.headers['user-agent'], 76 | http.STATUS_CODES[res.statusCode]); 77 | }) 78 | .pipe(res); 79 | }; 80 | -------------------------------------------------------------------------------- /assets/javascripts/nodeca.js.ejs: -------------------------------------------------------------------------------- 1 | /*global window, nodeca*/ 2 | 3 | //= require_self 4 | //= require_tree ./nodeca 5 | 6 | var nodeca = window.nodeca = (function (nodeca) { 7 | 'use strict'; 8 | 9 | nodeca.config = {}; 10 | nodeca.config.app = <%- JSON.stringify(nodeca('config.app')) %> 11 | nodeca.views = {}; 12 | nodeca.server = {}; 13 | nodeca.shared = {}; 14 | nodeca.client = {}; 15 | 16 | nodeca.runtime = {}; 17 | nodeca.runtime.env = "<%= nodeca('runtime.env') %>"; 18 | nodeca.runtime.version = "<%= nodeca('runtime.version') %>"; 19 | nodeca.runtime.i18n = new BabelFish({}); 20 | 21 | // translations injector 22 | nodeca.runtime.i18n.load = function loadTranslations(lang, data) { 23 | nodeca.runtime.i18n._storage[lang] = data; 24 | }; 25 | 26 | // some defaults 27 | nodeca.runtime.locale = "<%= nodeca('config.locales.default') %>"; 28 | 29 | // translation helper with active locale 30 | nodeca.runtime.t = function (phrase, params) { 31 | return nodeca.runtime.i18n.t(nodeca.runtime.locale, phrase, params); 32 | }; 33 | 34 | (function (c) { 35 | var log = c.log || $.noop; 36 | 37 | nodeca.logger = {}; 38 | 39 | _.each(['assert', 'error', 'info', 'debug'], function (level) { 40 | var logger = c[level]; // try to get console. 41 | 42 | // we deal with IE6-7 where no console exist at all 43 | // or we deal with IE8 where console.log or whatever might be an object 44 | if (!_.isFunction(logger)) { 45 | logger = function () { 46 | log([level].concat(_.toArray(arguments))); 47 | }; 48 | } 49 | 50 | // logger is now a function for sure, so we can safely bind a console 51 | // context, which is needed for Chrome 52 | nodeca.logger[level] = _.bind(logger, c); 53 | }); 54 | }(window.console || {})); 55 | 56 | return nodeca; 57 | }({})); 58 | 59 | // vim: syntax=javascript 60 | -------------------------------------------------------------------------------- /lib/init/assets/mincer/manifest.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | 4 | /*global nodeca, _*/ 5 | 6 | 7 | // stdlib 8 | var path = require('path'); 9 | 10 | 11 | // 3rd-party 12 | var Mincer = require('mincer'); 13 | 14 | 15 | //////////////////////////////////////////////////////////////////////////////// 16 | 17 | 18 | // compile(output, environment, callback(err, manifest)) -> Void 19 | // - output (String): Root of the manifest file. 20 | // 21 | // Compiles and outputs files and manifest data for the `environment` into the 22 | // given manifest `root`. 23 | // 24 | function compile(output, environment, callback) { 25 | var manifest = new Mincer.Manifest(environment, output), 26 | filters = [], 27 | blacklist = [], 28 | files = []; 29 | 30 | filters.push('app.css', 'app.js'); 31 | filters.push('loader.js', 'json2.js', 'es5-shim.js'); 32 | blacklist.push(/^faye-browser/); 33 | 34 | // 35 | // function that mathces any non-js or non-css files 36 | // 37 | 38 | filters.push(function nonAsset(logicalPath) { 39 | var extname = path.extname(logicalPath), 40 | ignore = _.any(blacklist, function (re) { 41 | return re.test(logicalPath); 42 | }); 43 | 44 | // - logicalPath should not be ignored 45 | // - extension must exist (e.g. logicalPath of `layout.ejs` is `layout`) 46 | // - extension must be anything but .js or .css 47 | return !(ignore || !extname || /\.(?:js|css)$/.test(extname)); 48 | }); 49 | 50 | // 51 | // collect assets that must be compiled 52 | // 53 | 54 | try { 55 | environment.eachLogicalPath(filters, function (logicalPath) { 56 | files.push(logicalPath); 57 | }); 58 | } catch (err) { 59 | callback(err); 60 | return; 61 | } 62 | 63 | // 64 | // run compiler 65 | // 66 | 67 | manifest.compile(files, callback); 68 | } 69 | 70 | 71 | //////////////////////////////////////////////////////////////////////////////// 72 | 73 | 74 | module.exports.compile = compile; 75 | -------------------------------------------------------------------------------- /lib/stylus/import-dir.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | /** 5 | * lib 6 | **/ 7 | 8 | /** 9 | * lib.stylus 10 | **/ 11 | 12 | 13 | // stdlib 14 | var path = require('path'); 15 | var fs = require('fs'); 16 | 17 | 18 | // 3rd-party 19 | var stylus = require('stylus'); 20 | 21 | 22 | //////////////////////////////////////////////////////////////////////////////// 23 | 24 | 25 | // returns list of files under given pathname, but not deeper (no recursion) 26 | function find_files(pathname) { 27 | var files = []; 28 | 29 | fs.readdirSync(pathname).forEach(function (filename) { 30 | filename = path.join(pathname, filename); 31 | 32 | if (fs.statSync(filename).isFile()) { 33 | // we are interested in a first level child files only 34 | files.push(filename); 35 | return; 36 | } 37 | }); 38 | 39 | return files.sort(); 40 | } 41 | 42 | 43 | //////////////////////////////////////////////////////////////////////////////// 44 | 45 | 46 | /** 47 | * lib.stylus.import_dir(expr) -> Array 48 | * 49 | * Stylus extensions that allows to mixin all files in the specified directory. 50 | * 51 | * 52 | * ##### Usage 53 | * 54 | * Assuming `source` is a stylus file: 55 | * 56 | * import-dir('./foobar') 57 | * 58 | * We can define `import-dir` function like this: 59 | * 60 | * stylus(source).define('import-dir', lib.stylus.import_dir); 61 | **/ 62 | module.exports = function import_dir(expr) { 63 | var block = this.currentBlock, 64 | vals = [stylus.nodes['null']], 65 | pathname = path.resolve(path.dirname(this.filename), expr.val); 66 | 67 | find_files(pathname).forEach(function (file) { 68 | var expr = new stylus.nodes.Expression(), 69 | node = new stylus.nodes.String(file), 70 | body; 71 | 72 | expr.push(node); 73 | 74 | body = this.visitImport(new stylus.nodes.Import(expr)); 75 | vals = vals.concat(body.nodes); 76 | }, this); 77 | 78 | this.mixin(vals, block); 79 | return vals; 80 | }; 81 | -------------------------------------------------------------------------------- /lib/init/cronjob.js: -------------------------------------------------------------------------------- 1 | /*global nodeca*/ 2 | 3 | 4 | "use strict"; 5 | 6 | 7 | // 3rd-party 8 | var cron = require('cron'); 9 | 10 | 11 | // nodeca 12 | var NLib = require('nlib'); 13 | 14 | 15 | //////////////////////////////////////////////////////////////////////////////// 16 | 17 | 18 | var DOWNLOADS_PATH = require('path').resolve(__dirname, '../../public/download'); 19 | 20 | 21 | //////////////////////////////////////////////////////////////////////////////// 22 | 23 | 24 | module.exports = function (next) { 25 | nodeca.logger.warn("Purging obsolet downloads. Removing: " + DOWNLOADS_PATH); 26 | NLib.Vendor.FsTools.remove(DOWNLOADS_PATH, function (err) { 27 | var job; 28 | 29 | if (err) { 30 | next(err); 31 | return; 32 | } 33 | 34 | try { 35 | job = new cron.CronJob({ 36 | // run every day at 00:00:00 37 | cronTime: '0 0 0 * * *', 38 | onTick: function () { 39 | var now = Date.now(), // current timestamp in ms 40 | max_age = 60 * 60 * 24 * 1000; // 1 day in ms 41 | 42 | nodeca.logger.warn("Cleaning downloads..."); 43 | NLib.Vendor.FsTools.walk(DOWNLOADS_PATH, function (file, stat, next) { 44 | if (max_age > now - Date.parse(stat.mtime)) { 45 | // file is fresh - no need to cleanup 46 | nodeca.logger.debug("Skipping file: " + file); 47 | next(); 48 | return; 49 | } 50 | 51 | nodeca.logger.warn("Removing file: " + file); 52 | NLib.Vendor.FsTools.remove(file, next); 53 | }, function (err) { 54 | if (err) { 55 | nodeca.logger.warn("Failed cleanup downloads"); 56 | nodeca.logger.error(err); 57 | } 58 | }); 59 | }, 60 | // do not start immediately 61 | start: false 62 | }); 63 | } catch (err) { 64 | next(err); 65 | return; 66 | } 67 | 68 | job.start(); 69 | next(); 70 | }); 71 | }; 72 | -------------------------------------------------------------------------------- /lib/init/assets/mincer/stylus/import-dir.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | /** 5 | * lib 6 | **/ 7 | 8 | /** 9 | * lib.stylus 10 | **/ 11 | 12 | 13 | // stdlib 14 | var path = require('path'); 15 | var fs = require('fs'); 16 | 17 | 18 | // 3rd-party 19 | var stylus = require('stylus'); 20 | 21 | 22 | //////////////////////////////////////////////////////////////////////////////// 23 | 24 | 25 | // returns list of files under given pathname, but not deeper (no recursion) 26 | function find_files(pathname) { 27 | var files = []; 28 | 29 | fs.readdirSync(pathname).forEach(function (filename) { 30 | filename = path.join(pathname, filename); 31 | 32 | if (fs.statSync(filename).isFile()) { 33 | // we are interested in a first level child files only 34 | files.push(filename); 35 | return; 36 | } 37 | }); 38 | 39 | return files.sort(); 40 | } 41 | 42 | 43 | //////////////////////////////////////////////////////////////////////////////// 44 | 45 | 46 | /** 47 | * lib.stylus.import_dir(expr) -> Array 48 | * 49 | * Stylus extensions that allows to mixin all files in the specified directory. 50 | * 51 | * 52 | * ##### Usage 53 | * 54 | * Assuming `source` is a stylus file: 55 | * 56 | * import-dir('./foobar') 57 | * 58 | * We can define `import-dir` function like this: 59 | * 60 | * stylus(source).define('import-dir', lib.stylus.import_dir); 61 | **/ 62 | module.exports = function import_dir(expr) { 63 | var block = this.currentBlock, 64 | vals = [stylus.nodes['null']], 65 | pathname = path.resolve(path.dirname(this.filename), expr.val); 66 | 67 | find_files(pathname).forEach(function (file) { 68 | var expr = new stylus.nodes.Expression(), 69 | node = new stylus.nodes.String(file), 70 | body; 71 | 72 | expr.push(node); 73 | 74 | body = this.visitImport(new stylus.nodes.Import(expr)); 75 | vals = vals.concat(body.nodes); 76 | }, this); 77 | 78 | this.mixin(vals, block); 79 | return vals; 80 | }; 81 | -------------------------------------------------------------------------------- /lib/init/assets/build_api_tree.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | /*global nodeca, _*/ 5 | 6 | 7 | // stdlib 8 | var fs = require('fs'); 9 | var path = require('path'); 10 | 11 | 12 | // 3rd-party 13 | var apiTree = require('nlib').ApiTree; 14 | var async = require('nlib').Vendor.Async; 15 | var fstools = require('nlib').Vendor.FsTools; 16 | 17 | 18 | //////////////////////////////////////////////////////////////////////////////// 19 | 20 | 21 | // internal 22 | // browserify(callback(err, str)) -> Void 23 | // - callback (Function): Executed once all namespaces were browserified 24 | // 25 | // Makes browserified client/shared/server trees. 26 | // 27 | function browserify(callback) { 28 | var parts = []; 29 | 30 | // browserify server tree 31 | parts.push(apiTree.browserifyServerTree(nodeca.server, 'this.nodeca.server', { 32 | method: 'nodeca.io.apiTree' 33 | })); 34 | 35 | // browserify client and shared trees 36 | async.forEach(['client', 'shared'], function (part, next) { 37 | var pathname = path.join(nodeca.runtime.apps[0].root, part); 38 | 39 | apiTree.browserifySources(pathname, 'this.nodeca.' + part, function (err, str) { 40 | if (err) { 41 | next(err); 42 | return; 43 | } 44 | 45 | parts.push(str); 46 | next(); 47 | }); 48 | }, function (err) { 49 | callback(err, parts.join('\n\n')); 50 | }); 51 | } 52 | 53 | 54 | //////////////////////////////////////////////////////////////////////////////// 55 | 56 | 57 | // buildApiTree(root, callback(err)) -> Void 58 | // - root (String): Pathname where to save browserified api.js. 59 | // - callback (Function): Executed once everything is done. 60 | // 61 | // Browserifies server/shared/client trees into api.js file. 62 | // 63 | module.exports = function buildApiTree(root, callback) { 64 | browserify(function (err, str) { 65 | if (err) { 66 | callback(err); 67 | return; 68 | } 69 | 70 | fs.writeFile(path.join(root, 'api.js'), str, callback); 71 | }); 72 | }; 73 | -------------------------------------------------------------------------------- /assets/vendor/bootstrap/src/js/bootstrap-transition.js: -------------------------------------------------------------------------------- 1 | /* =================================================== 2 | * bootstrap-transition.js v2.1.1 3 | * http://twitter.github.com/bootstrap/javascript.html#transitions 4 | * =================================================== 5 | * Copyright 2012 Twitter, Inc. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ========================================================== */ 19 | 20 | 21 | !function ($) { 22 | 23 | $(function () { 24 | 25 | "use strict"; // jshint ;_; 26 | 27 | 28 | /* CSS TRANSITION SUPPORT (http://www.modernizr.com/) 29 | * ======================================================= */ 30 | 31 | $.support.transition = (function () { 32 | 33 | var transitionEnd = (function () { 34 | 35 | var el = document.createElement('bootstrap') 36 | , transEndEventNames = { 37 | 'WebkitTransition' : 'webkitTransitionEnd' 38 | , 'MozTransition' : 'transitionend' 39 | , 'OTransition' : 'oTransitionEnd otransitionend' 40 | , 'transition' : 'transitionend' 41 | } 42 | , name 43 | 44 | for (name in transEndEventNames){ 45 | if (el.style[name] !== undefined) { 46 | return transEndEventNames[name] 47 | } 48 | } 49 | 50 | }()) 51 | 52 | return transitionEnd && { 53 | end: transitionEnd 54 | } 55 | 56 | })() 57 | 58 | }) 59 | 60 | }(window.jQuery); -------------------------------------------------------------------------------- /assets/vendor/bootstrap/src/less/labels-badges.less: -------------------------------------------------------------------------------- 1 | // 2 | // Labels and badges 3 | // -------------------------------------------------- 4 | 5 | 6 | // Base classes 7 | .label, 8 | .badge { 9 | font-size: @baseFontSize * .846; 10 | font-weight: bold; 11 | line-height: 14px; // ensure proper line-height if floated 12 | color: @white; 13 | vertical-align: baseline; 14 | white-space: nowrap; 15 | text-shadow: 0 -1px 0 rgba(0,0,0,.25); 16 | background-color: @grayLight; 17 | } 18 | // Set unique padding and border-radii 19 | .label { 20 | padding: 1px 4px 2px; 21 | .border-radius(3px); 22 | } 23 | .badge { 24 | padding: 1px 9px 2px; 25 | .border-radius(9px); 26 | } 27 | 28 | // Hover state, but only for links 29 | a { 30 | &.label:hover, 31 | &.badge:hover { 32 | color: @white; 33 | text-decoration: none; 34 | cursor: pointer; 35 | } 36 | } 37 | 38 | // Colors 39 | // Only give background-color difference to links (and to simplify, we don't qualifty with `a` but [href] attribute) 40 | .label, 41 | .badge { 42 | // Important (red) 43 | &-important { background-color: @errorText; } 44 | &-important[href] { background-color: darken(@errorText, 10%); } 45 | // Warnings (orange) 46 | &-warning { background-color: @orange; } 47 | &-warning[href] { background-color: darken(@orange, 10%); } 48 | // Success (green) 49 | &-success { background-color: @successText; } 50 | &-success[href] { background-color: darken(@successText, 10%); } 51 | // Info (turquoise) 52 | &-info { background-color: @infoText; } 53 | &-info[href] { background-color: darken(@infoText, 10%); } 54 | // Inverse (black) 55 | &-inverse { background-color: @grayDark; } 56 | &-inverse[href] { background-color: darken(@grayDark, 10%); } 57 | } 58 | 59 | // Quick fix for labels/badges in buttons 60 | .btn { 61 | .label, 62 | .badge { 63 | position: relative; 64 | top: -1px; 65 | } 66 | } 67 | .btn-mini { 68 | .label, 69 | .badge { 70 | top: 0; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /bin/tpl-render.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | 4 | 'use strict'; 5 | 6 | 7 | // stdlib 8 | var fs = require('fs'); 9 | 10 | 11 | // 3rd-party 12 | var _ = require('underscore'); 13 | var jade = require('jade'); 14 | 15 | 16 | //////////////////////////////////////////////////////////////////////////////// 17 | 18 | 19 | var options = (function (cli) { 20 | cli.addArgument(['--locals'], {action: 'store', required: false}); 21 | cli.addArgument(['--output'], {action: 'store', required: true}); 22 | cli.addArgument(['--input'], {action: 'store', required: true, dest: 'filename'}); 23 | cli.addArgument(['--pretty'], {action: 'storeTrue', defaultValue: false}); 24 | 25 | return cli.parseArgs(); 26 | }(new (require('argparse').ArgumentParser))); 27 | 28 | 29 | //////////////////////////////////////////////////////////////////////////////// 30 | 31 | 32 | var jade_filters = require('jade/lib/filters'); 33 | 34 | jade_filters.stylus_nowrap = function(str, options){ 35 | var ret; 36 | str = str.replace(/\\n/g, '\n'); 37 | var stylus = require('stylus'); 38 | stylus(str, options).render(function(err, css){ 39 | if (err) throw err; 40 | ret = css.replace(/\n/g, '\\n'); 41 | }); 42 | return ret; 43 | } 44 | 45 | 46 | //////////////////////////////////////////////////////////////////////////////// 47 | 48 | var locals = options.locals ? require(options.locals) : {}; 49 | var source = fs.readFileSync(options.filename, 'utf8'); 50 | var result = jade.compile(source, options)(_.extend({ 51 | _: _, 52 | unichr: function unichr(code) { 53 | /*jshint bitwise: false*/ 54 | if (code > 0xffff) { 55 | code -= 0x10000; 56 | var surrogate1 = 0xd800 + (code >> 10), 57 | surrogate2 = 0xdc00 + (code & 0x3ff); 58 | return String.fromCharCode(surrogate1, surrogate2); 59 | } else { 60 | return String.fromCharCode(code); 61 | } 62 | } 63 | }, locals)); 64 | 65 | 66 | //////////////////////////////////////////////////////////////////////////////// 67 | 68 | 69 | fs.writeFileSync(options.output, result); 70 | -------------------------------------------------------------------------------- /lib/filters/renderer.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | /*global nodeca, _*/ 5 | 6 | 7 | // 3rd-party 8 | var treeHas = require('nlib').Support.tree.cache.has; 9 | 10 | 11 | // internals 12 | var helpers = require('./renderer/helpers'); 13 | 14 | 15 | //////////////////////////////////////////////////////////////////////////////// 16 | 17 | 18 | // Filter middleware that renders view and required layout and sets 19 | // 20 | // - `response.headers` with approprite headers 21 | // - `response.body` with rendered (and compressed if allowed) html 22 | // 23 | nodeca.filters.after('', { weight: 900 }, function renderer(params, callback) { 24 | var http = this.origin.http, 25 | headers = this.response.headers, 26 | layout = this.response.layout, 27 | viewsTree, locals; 28 | 29 | if (!http) { 30 | // skip non-http requests 31 | callback(); 32 | return; 33 | } 34 | 35 | // 36 | // Prepare variables 37 | // 38 | 39 | viewsTree = nodeca.runtime.views; 40 | 41 | if (!treeHas(viewsTree, this.response.view)) { 42 | callback(new Error("View " + this.response.view + " not found")); 43 | return; 44 | } 45 | 46 | // 47 | // Set Content-Type and charset 48 | // 49 | 50 | headers['Content-Type'] = 'text/html; charset=UTF-8'; 51 | 52 | // 53 | // 304 Not Modified 54 | // 55 | 56 | if (headers['ETag'] && headers['ETag'] === http.req.headers['if-none-match']) { 57 | // The one who sets `ETag` header must set also (by it's own): 58 | // - `Last-Modified` 59 | // - `Cache-Control` 60 | this.response.statusCode = 304; 61 | callback(); 62 | return; 63 | } 64 | 65 | // 66 | // HEAD requested - no need for real rendering 67 | // 68 | 69 | if ('HEAD' === http.req.method) { 70 | callback(); 71 | return; 72 | } 73 | 74 | try { 75 | locals = _.extend(this.response.data, helpers, this.helpers); 76 | this.response.body = nodeca.shared.render(viewsTree, this.response.view, locals, layout); 77 | } catch (err) { 78 | callback(err); 79 | return; 80 | } 81 | 82 | callback(); 83 | }); 84 | -------------------------------------------------------------------------------- /assets/vendor/bootstrap/bootstrap.less: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v2.0.3 3 | * 4 | * Copyright 2012 Twitter, Inc 5 | * Licensed under the Apache License v2.0 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Designed and built with all the love in the world @twitter by @mdo and @fat. 9 | */ 10 | 11 | // CSS Reset 12 | @import "src/less/reset.less"; 13 | 14 | // Core variables and mixins 15 | @import "src/less/variables.less"; 16 | @import "var_override.less"; // Modify this for custom colors, font-sizes, etc 17 | 18 | @import "src/less/mixins.less"; 19 | 20 | // Grid system and page structure 21 | @import "src/less/scaffolding.less"; 22 | @import "src/less/grid.less"; 23 | @import "src/less/layouts.less"; 24 | 25 | // Base CSS 26 | @import "src/less/type.less"; 27 | //@import "src/less/code.less"; 28 | @import "src/less/forms.less"; 29 | //@import "src/less/tables.less"; 30 | 31 | // Components: common 32 | //@import "src/less/sprites.less"; 33 | @import "src/less/dropdowns.less"; 34 | @import "src/less/wells.less"; 35 | @import "src/less/component-animations.less"; 36 | @import "src/less/close.less"; 37 | 38 | // Components: Buttons & Alerts 39 | @import "src/less/buttons.less"; 40 | @import "src/less/button-groups.less"; 41 | @import "src/less/alerts.less"; // Note: alerts share common CSS with buttons and thus have styles in buttons.less 42 | 43 | // Components: Nav 44 | @import "src/less/navs.less"; 45 | @import "src/less/navbar.less"; 46 | //@import "src/less/breadcrumbs.less"; 47 | //@import "src/less/pagination.less"; 48 | //@import "src/less/pager.less"; 49 | 50 | // Components: Popovers 51 | @import "src/less/modals.less"; 52 | @import "src/less/tooltip.less"; 53 | @import "src/less/popovers.less"; 54 | 55 | // Components: Misc 56 | //@import "src/less/thumbnails.less"; 57 | @import "src/less/labels-badges.less"; 58 | //@import "src/less/progress-bars.less"; 59 | //@import "src/less/accordion.less"; 60 | //@import "src/less/carousel.less"; 61 | //@import "src/less/hero-unit.less"; 62 | 63 | // Utility classes 64 | @import "src/less/utilities.less"; // Has to be last to override when necessary 65 | -------------------------------------------------------------------------------- /assets/vendor/bootstrap/var_override.less: -------------------------------------------------------------------------------- 1 | // Overrides for Variables.less 2 | // to automatically keep new vars on bootstrap updates 3 | // ----------------------------------------------------- 4 | 5 | 6 | // Grays 7 | // ------------------------- 8 | 9 | @black: #000; 10 | @grayDarker: #222; 11 | //@grayDark: #333; 12 | @grayDark: #444; 13 | //@gray: #555; 14 | @gray: #666; 15 | @grayLight: #999; 16 | @grayLighter: #eee; 17 | @white: #fff; 18 | 19 | 20 | // Typography 21 | // ------------------------- 22 | 23 | @sansFontFamily: "Helvetica Neue", Helvetica, Arial, sans-serif; 24 | @serifFontFamily: Georgia, "Times New Roman", Times, serif; 25 | @monoFontFamily: Menlo, Monaco, Consolas, "Courier New", monospace; 26 | 27 | //@baseFontSize: 13px; 28 | @baseFontSize: 14px; 29 | @baseFontFamily: @sansFontFamily; 30 | //@baseLineHeight: 18px; 31 | @baseLineHeight: 20px; 32 | @altFontFamily: @serifFontFamily; 33 | 34 | @headingsFontFamily: inherit; // empty to use BS default, @baseFontFamily 35 | @headingsFontWeight: bold; // instead of browser default, bold 36 | @headingsColor: inherit; // empty to use BS default, @textColor 37 | 38 | 39 | // Navbar 40 | // ------------------------- 41 | 42 | //@navbarText: @grayLight; 43 | @navbarText: #bbb; 44 | //@navbarLinkColor: @grayLight; 45 | @navbarLinkColor: #bbb; 46 | 47 | 48 | // Links 49 | // ------------------------- 50 | 51 | @linkColor: #953B39; 52 | 53 | 54 | // Buttons 55 | // ------------------------- 56 | 57 | //@btnBackground: @white; 58 | @btnBackground: darken(@white, 5%); 59 | //@btnBackgroundHighlight: darken(@white, 10%); 60 | @btnBackgroundHighlight: darken(@white, 5%); 61 | @btnBorder: #ccc; 62 | 63 | @btnInfoBackground: #dd4226; 64 | @btnInfoBackgroundHighlight: #ac301a; 65 | 66 | -------------------------------------------------------------------------------- /bin/font_copy_to_assets.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | import os 5 | import shutil 6 | import argparse 7 | import yaml 8 | 9 | 10 | error = sys.stderr.write 11 | 12 | 13 | if __name__ == '__main__': 14 | parser = argparse.ArgumentParser(description='Font copier tool') 15 | parser.add_argument('-c', '--config', type=str, required=True, 16 | help='Config example: src/awesome-uni.font/config.yml') 17 | parser.add_argument('-o', '--fonts_dir', type=str, required=True, 18 | help='Output fonts directory') 19 | 20 | args = parser.parse_args() 21 | 22 | try: 23 | config = yaml.load(open(args.config, 'r')) 24 | except IOError as (errno, strerror): 25 | error('Cannot open %s: %s\n' % (args.config, strerror)) 26 | sys.exit(1) 27 | except yaml.YAMLError, e: 28 | if hasattr(e, 'problem_mark'): 29 | mark = e.problem_mark 30 | error('YAML parser error in file %s at line %d, col %d\n' % 31 | (args.config, mark.line + 1, mark.column + 1)) 32 | else: 33 | error('YAML parser error in file %s: %s\n' % (args.config, e)) 34 | sys.exit(1) 35 | 36 | fontname = config.get('font', {}).get('fontname', None) 37 | if not fontname: 38 | error('Error: cannot find "font: fontname" in file %s\n' % args.config) 39 | sys.exit(1) 40 | 41 | if not os.path.exists(args.fonts_dir): 42 | error('Error: directory "%s" does not exist\n' % args.fonts_dir) 43 | sys.exit(1) 44 | 45 | if not os.path.isdir(args.fonts_dir): 46 | error('Error: path "%s" is not a directory\n' % args.fonts_dir) 47 | sys.exit(1) 48 | 49 | ext_list = ('.eot', '.svg', '.ttf', '.woff') 50 | for ext in ext_list: 51 | src = '%s/font/%s%s' % (os.path.dirname(args.config), fontname, ext) 52 | try: 53 | shutil.copy(src, args.fonts_dir) 54 | except IOError as (errno, strerror): 55 | error('Cannot copy "%s" to "%s": %s\n' % (args.config, 56 | args.fonts_dir, strerror)) 57 | sys.exit(1) 58 | 59 | sys.exit(0) 60 | -------------------------------------------------------------------------------- /client/ui/panes/selector_font.js: -------------------------------------------------------------------------------- 1 | /*global window, nodeca, jQuery, Handlebars, Backbone, $, _*/ 2 | 3 | "use strict"; 4 | 5 | module.exports = Backbone.View.extend({ 6 | tagName: "li", 7 | 8 | 9 | initialize: function () { 10 | var self = this; 11 | 12 | this.$el.attr("id", "font-id-" + this.model.id); 13 | 14 | this.model.on("change", this.render, this); 15 | this.model.on("destroy", this.remove, this); 16 | 17 | // activate selectable plugin 18 | this.$el.selectable({ 19 | filter: 'li.glyph:visible', 20 | distance: 5, 21 | stop: function () { 22 | var $els = self.$('.glyph.ui-selected'); 23 | 24 | // prevent from double-triggering event, 25 | // otherwise click event will be fired as well 26 | if (1 === $els.length) { 27 | return; 28 | } 29 | 30 | self.trigger('before:batch-select'); 31 | $els.each(function () { 32 | $(this).data('model').toggle('selected'); 33 | }); 34 | self.trigger('after:batch-select'); 35 | } 36 | }); 37 | }, 38 | 39 | render: function () { 40 | var $info; 41 | 42 | this.$el.html(nodeca.client.render('selector.font-item', { 43 | id: this.model.id, 44 | fontname: this.model.get("font").fullname, 45 | css_class: "font-embedded-" + this.model.get("id") 46 | })); 47 | 48 | // render info html 49 | $info = $(nodeca.client.render('selector.font-info', this.model.toJSON())); 50 | 51 | // assign modal window popup handler 52 | this.$('.font-info').click(function () { 53 | $info.appendTo(window.document.body).modal(); 54 | // prevent default browser behavior - jump to the top 55 | return false; 56 | }); 57 | 58 | // process each glyph 59 | this.model.eachGlyph(function (glyph) { 60 | var view = new nodeca.client.ui.panes.selector_glyph({model: glyph}); 61 | this.$(".font-glyphs").append(view.render().el); 62 | }, this); 63 | 64 | return this; 65 | }, 66 | 67 | 68 | remove: function () { 69 | this.$el.remove(); 70 | this.trigger("remove", this.model); 71 | } 72 | }); 73 | -------------------------------------------------------------------------------- /lib/init/server.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | 4 | /*global nodeca, _*/ 5 | 6 | 7 | // 3rd-party 8 | var Async = require('nlib').Vendor.Async; 9 | 10 | 11 | //////////////////////////////////////////////////////////////////////////////// 12 | 13 | 14 | // helper that starts http server and waits for it to bind to specified host and 15 | // port (see configuration listen section). 16 | // 17 | function start_server(next) { 18 | var server, host, port, err_handler; 19 | 20 | try { 21 | // add support for webkit devtools 22 | require('webkit-devtools-agent'); 23 | nodeca.logger.info('webkit-devtools-agent enabled'); 24 | } catch (err) { 25 | // do nothing 26 | nodeca.logger.warn('webkit-devtools-agent disabled'); 27 | } 28 | 29 | // create server 30 | host = nodeca.config.listen.host || 'localhost'; 31 | port = nodeca.config.listen.port || 3000; 32 | server = require('http').createServer(); 33 | 34 | err_handler = function (err) { 35 | var err_prefix = "Can't bind to <" + host + "> with port <" + port + ">: "; 36 | 37 | if ('EADDRINUSE' === err.code) { 38 | next(err_prefix + 'Address in use...'); 39 | return; 40 | } 41 | 42 | if ('EADDRNOTAVAIL' === err.code) { 43 | // system has no such ip address 44 | next(err_prefix + 'Address is not available...'); 45 | return; 46 | } 47 | 48 | if ('ENOENT' === err.code) { 49 | // failed resolve hostname to ip address 50 | next(err_prefix + "Failed to resolve IP address..."); 51 | return; 52 | } 53 | 54 | // unexpected / unknown error 55 | next(err_prefix + err); 56 | }; 57 | 58 | server.on('error', err_handler); 59 | 60 | // start server 61 | server.listen(port, host, function () { 62 | server.removeListener('error', err_handler); 63 | next(null, server); 64 | }); 65 | } 66 | 67 | 68 | // MODULE EXPORTS ////////////////////////////////////////////////////////////// 69 | 70 | 71 | // starts http server and attach application HTTP server and Faye realtime 72 | // servers to it 73 | // 74 | module.exports = function (next) { 75 | start_server(function (err, server) { 76 | if (err) { 77 | next(err); 78 | return; 79 | } 80 | 81 | require('./server/http').attach(server, next); 82 | }); 83 | }; 84 | -------------------------------------------------------------------------------- /assets/vendor/fontello/src/font/icons.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Created by FontForge 20100429 at Sat Aug 25 01:06:27 2012 6 | By root 7 | Copyright (C) 2012 by original authors @ fontello.com 8 | 9 | 10 | 11 | 24 | 26 | 28 | 30 | 32 | 35 | 38 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /client/ui/panes/codes_editor_glyph.js: -------------------------------------------------------------------------------- 1 | /*global window, nodeca, jQuery, Handlebars, Backbone, $, _*/ 2 | 3 | "use strict"; 4 | 5 | module.exports = Backbone.View.extend({ 6 | tagName: "div", 7 | className: "result-glyph", 8 | 9 | 10 | initialize: function () { 11 | this.model.on("change", this.render, this); 12 | this.model.on("destroy", this.remove, this); 13 | }, 14 | 15 | 16 | render: function () { 17 | var model = this.model, 18 | source = model.get('source'), 19 | font = model.get('font').getName(), 20 | uid = source.uid, 21 | code = nodeca.shared.glyphs_map[font][uid], 22 | char = nodeca.client.util.fixedFromCharCode(model.get("code")); 23 | 24 | this.$el.html(nodeca.client.render('code-editor.glyph', { 25 | top: model.get("code") === 32 ? "space" : char, 26 | chr: nodeca.client.util.fixedFromCharCode(code), 27 | bottom: this.toUnicode(model.get("code")), 28 | css_class: "font-embedded-" + model.get('font').get('id') 29 | })); 30 | 31 | this.$el.find('.char-editable').inplaceEditor({ 32 | validateChar: function (char) { 33 | this.setValue(char); 34 | return false; 35 | }, 36 | filterValue: function (val) { 37 | var code = nodeca.client.util.fixedCharCodeAt(val); 38 | return nodeca.client.util.fixedFromCharCode(code); 39 | } 40 | }).on('change', function (event, val) { 41 | model.set("code", nodeca.client.util.fixedCharCodeAt(val)); 42 | }); 43 | 44 | this.$el.find('.code-editable').inplaceEditor({ 45 | noPaste: true, 46 | validateChar: function (char) { 47 | return /[0-9a-fA-F]/.test(char) && 6 > this.getValue().length; 48 | } 49 | }).on('change', function (event, val) { 50 | model.set("code", parseInt(val, 16)); 51 | }); 52 | 53 | this.$el.toggleClass("mapping-matched", model.get("code") === source.code); 54 | 55 | return this; 56 | }, 57 | 58 | 59 | // return char in CharRef notation 60 | toCharRef: function (char) { 61 | return "&#x" + char.charCodeAt(0).toString(16) + ";"; 62 | }, 63 | 64 | 65 | // return unicode code point in U+ notation 66 | toUnicode: function (code) { 67 | var c = code.toString(16).toUpperCase(); 68 | return "0000".substr(0, Math.max(4 - c.length, 0)) + c; 69 | } 70 | }); 71 | -------------------------------------------------------------------------------- /assets/stylesheets/app.styl: -------------------------------------------------------------------------------- 1 | //= require bootstrap/bootstrap 2 | //= require bootstrap/bootstrap-responsive 3 | //= require jquery.noty/noty 4 | //= require fontello/icons 5 | //= require fontface-fontello 6 | 7 | @import nib 8 | @import variables 9 | @import bootstrap_override 10 | 11 | html 12 | overflow-y scroll // remove glitch on step 3, when scroller disappears 13 | 14 | body 15 | padding-top 180px // make the container go all the way to the bottom of the topbar 16 | padding-bottom 30px 17 | 18 | .navbar 19 | box-shadow 0 0 4px #444 20 | 21 | .brand 22 | line-height 20px 23 | padding-top 0 !important 24 | padding-bottom 0 !important 25 | 26 | //======== Github ribbon ======== 27 | .gh-ribbon 28 | position fixed 29 | right -60px 30 | top 44px 31 | z-index 10000 32 | background-color #686868 33 | padding 1px 0 34 | transform rotate(45deg) 35 | width 230px 36 | box-shadow 0 0 2px #6666 37 | display none 38 | a 39 | display: block; 40 | color #fff 41 | border 1px solid #aaa 42 | font-size 13px 43 | font-weight bold 44 | padding 4px 50px 2px 45 | text-align center 46 | outline none 47 | &:hover 48 | text-decoration none 49 | 50 | // use moderniser to show only fo browsers, 51 | // wich supports rotation 52 | .csstransforms .gh-ribbon 53 | display block 54 | 55 | //======== Social buttons ======== 56 | iframe 57 | &.twitter-follow-button 58 | &.twitter-share-button 59 | margin-left 10px 60 | margin-top 9px 61 | &.FlattrButton 62 | margin-top 10px 63 | 64 | .gplus > div 65 | top 9px 66 | position relative 67 | 68 | .nav 69 | .twitter-follow-button 70 | .twitter-share-button 71 | .gplus 72 | .FlattrButton 73 | transition: opacity .5s ease; 74 | opacity: .6 75 | 76 | .nav:hover 77 | .twitter-follow-button 78 | .twitter-share-button 79 | .gplus 80 | .FlattrButton 81 | opacity: 1 82 | 83 | //====== warning for disabled JS === 84 | .js .jsnotice 85 | display none 86 | 87 | 88 | .no-js .jsnotice 89 | position absolute 90 | left 30% 91 | right 30% 92 | top 90px 93 | z-index 10000 94 | font-size 54px 95 | line-height 81px 96 | font-weight bold 97 | 98 | 99 | p.note 100 | color #888 101 | 102 | @import "ui/tabs" 103 | @import "ui/toolbar" 104 | @import "ui/panes/selector" 105 | @import "ui/panes/preview" 106 | @import "ui/panes/codes_editor" 107 | -------------------------------------------------------------------------------- /HISTORY.md: -------------------------------------------------------------------------------- 1 | 2.0.4 / Rolling on website 2 | -------------------------- 3 | 4 | * ... 5 | 6 | 7 | 2.0.3 / 2012-09-07 8 | ------------------ 9 | 10 | * Preview tab content now resizeable too 11 | * You can edit glyph names 12 | * Codes edit improved 13 | * Fixed EOT fonts generation for customised font names 14 | * Added switchable '3D' shadow effect for icons 15 | * Fixed work with Opera 12 16 | * Tweaked styles again :) 17 | * Improved work with proxies (switched back data exchange from realtime to ajax) 18 | * Optimized page loading speed - merged all embedded fonts into single file 19 | * Synked libraries codebase with nodeca mainstream 20 | 21 | 22 | 2.0.2 / 2012-06-27 23 | ------------------ 24 | 25 | * Added configuration import/export 26 | * Improved CSS generation 27 | - use escaped chars when possible (for codes <= 0xFFFF) 28 | - add encoding (first line) only when needed 29 | - ie7 support 30 | - plains css with codes only, for automated asset build systems 31 | * Added README & LICENSE files to generated webfonts 32 | * Demo data bundled to single file now 33 | * Minor UI tweaks (inputs, buttons) 34 | * Fixed server stability issues (increased open file descriptors limit) 35 | * Migrated to node.js v0.8 36 | 37 | 38 | 2.0.1 / 2012-06-03 39 | ------------------ 40 | 41 | * Reworked interface logic & look 42 | * Added search 43 | * Added multiselect (click+drag) 44 | * Added field to select file name 45 | * Autosave for all changes 46 | * Number of small fixes 47 | * Internal refactoring (continue switching to new nodeca libraries) 48 | * Returned back WebSymbols font 49 | * Added Modern Pictograms font 50 | * Added Typicons font 51 | 52 | 53 | 2.0.0 / 2012-05-08 54 | ------------------ 55 | 56 | * Uses new [Font Builder](https://github.com/fontello/font-builder) system 57 | - All your files in single archive - no needs to use fontsquirrel generator. 58 | - Better glyphs mapping: follow Unicode 6.1 standard where possible. 59 | - Embedded fonts realligned to middleline of small letters. 60 | - Integrated ttfautohint, to significantly improve hinting. 61 | * Added `Font Awesome` 62 | * Added `Brandico` 63 | * Removed `WebSymbols` 64 | * Editable glyph codes. 65 | * Auto-generated CSS for bootstrap. 66 | * Nice preview tab & auto-generated demo-page. 67 | * Using @fonf-face instead of cufon to display glyths - mush better quality. 68 | * Removed external font loading, until we do something better. 69 | 70 | 71 | 0.0.1 / 2012-02-23 72 | ------------------ 73 | 74 | * First release 75 | -------------------------------------------------------------------------------- /bin/build_embedded_fonts_css.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | import os 5 | import argparse 6 | import json 7 | import yaml 8 | import fontforge 9 | 10 | 11 | error = sys.stderr.write 12 | 13 | 14 | if __name__ == '__main__': 15 | parser = argparse.ArgumentParser(description='Css generator') 16 | parser.add_argument('config', nargs='+', type=str, 17 | help='Config example: src/font1/config.yml src/font2/config.yml') 18 | parser.add_argument('-o', '--dst_file', type=str, required=True, 19 | help='Output css file') 20 | 21 | args = parser.parse_args() 22 | 23 | css_class = [] 24 | css_fontface = [] 25 | 26 | tpl_class = ".font-embedded-{i} {{ font-family: '{fontname}'; }}" 27 | tpl_fontface = """@font-face {{ 28 | font-family: '{fontname}'; 29 | src: url('<%= asset_path("{fontname}.eot") %>'); 30 | src: url('<%= asset_path("{fontname}.eot") %>?#iefix') format('embedded-opentype'), 31 | url('<%= asset_path("{fontname}.woff") %>') format('woff'), 32 | url('<%= asset_path("{fontname}.ttf") %>') format('truetype'), 33 | url('<%= asset_path("{fontname}.svg") %>#{fontname}') format('svg'); 34 | font-weight: normal; 35 | font-style: normal; 36 | }}""" 37 | 38 | for i, config_path in enumerate(args.config): 39 | try: 40 | config = yaml.load(open(config_path, 'r')) 41 | except IOError as (errno, strerror): 42 | error('Cannot open %s: %s\n' % (config_path, strerror)) 43 | sys.exit(1) 44 | except yaml.YAMLError, e: 45 | if hasattr(e, 'problem_mark'): 46 | mark = e.problem_mark 47 | error('YAML parser error in file %s at line %d, col %d\n' % 48 | (config_path, mark.line + 1, mark.column + 1)) 49 | else: 50 | error('YAML parser error in file %s: %s\n' % (config_path, e)) 51 | sys.exit(1) 52 | 53 | fontname = config.get('font', {}).get('fontname', None) 54 | if not fontname: 55 | error('Error: cannot find "font: fontname" in file %s\n' % 56 | config_path) 57 | sys.exit(1) 58 | 59 | css_class.append(tpl_class.format(i=i, fontname=fontname)) 60 | css_fontface.append(tpl_fontface.format(fontname=fontname)) 61 | 62 | css = '\n'.join(css_class) + '\n\n' + '\n\n'.join(css_fontface) 63 | 64 | try: 65 | open(args.dst_file, 'w').write(css) 66 | except: 67 | error('Cannot write to file %s\n' % args.dst_file) 68 | sys.exit(1) 69 | 70 | sys.exit(0) 71 | -------------------------------------------------------------------------------- /client/ui/toolbar.js: -------------------------------------------------------------------------------- 1 | /*global window, nodeca, jQuery, Handlebars, Backbone, $, _*/ 2 | 3 | 4 | "use strict"; 5 | 6 | 7 | // prevent the event from bubbling to ancestor elements 8 | function stopPropagation(event) { 9 | event.preventDefault(); 10 | event.stopPropagation(); 11 | } 12 | 13 | 14 | module.exports = Backbone.View.extend({ 15 | el: '#toolbar', 16 | 17 | 18 | $download_btn: null, 19 | $glyphs_count: null, 20 | keywords: [], 21 | 22 | 23 | initialize: function () { 24 | var self = this, $glyph_size_value, $search, on_search_change; 25 | 26 | // cache some inner elements 27 | this.$download_btn = this.$('#result-download'); 28 | this.$glyphs_count = this.$('#selected-glyphs-count'); 29 | 30 | // initialize glyph-size slider 31 | $glyph_size_value = $('#glyph-size-value'); 32 | $('#glyph-size-slider').slider({ 33 | orientation: 'horizontal', 34 | range: 'min', 35 | value: nodeca.config.app.glyph_size.val, 36 | min: nodeca.config.app.glyph_size.min, 37 | max: nodeca.config.app.glyph_size.max, 38 | slide: function (event, ui) { 39 | /*jshint bitwise:false*/ 40 | var val = ~~ui.value; 41 | $glyph_size_value.text(val + 'px'); 42 | self.trigger("change:glyph-size", val); 43 | } 44 | }); 45 | 46 | // search query change event listener 47 | on_search_change = function (event) { 48 | self.trigger('change:search', $search.val()); 49 | }; 50 | 51 | // init search input 52 | $search = $('#search') 53 | .on('change', on_search_change) 54 | .on('keyup', _.debounce(on_search_change, 250)) 55 | .on('focus keyup', _.debounce(function () { 56 | $search.typeahead('hide'); 57 | }, 5000)) 58 | .typeahead({ 59 | source: this.keywords 60 | }); 61 | 62 | // bind download button click event 63 | this.$download_btn.click(function (event) { 64 | event.preventDefault(); 65 | self.trigger('click:download'); 66 | }); 67 | 68 | // initial setup 69 | this.setGlyphsCount(0); 70 | }, 71 | 72 | 73 | setGlyphsCount: function (count) { 74 | this.$download_btn.toggleClass('disabled', !count); 75 | this.$download_btn[!count ? 'on' : 'off']('click', stopPropagation); 76 | 77 | this.$glyphs_count.text(+count); 78 | }, 79 | 80 | addKeywords: function (tags) { 81 | _.each(tags, function (tag) { 82 | if (_.isString(tag) && !_.include(this.keywords, tag)) { 83 | this.keywords.push(tag); 84 | } 85 | }, this); 86 | } 87 | }); 88 | -------------------------------------------------------------------------------- /lib/init/assets/mincer/environment.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | 4 | /*global nodeca, _*/ 5 | 6 | 7 | // stdlib 8 | var fs = require('fs'); 9 | var path = require('path'); 10 | 11 | 12 | // 3rd-party 13 | var Mincer = require('mincer'); 14 | var JASON = require('nlib').Vendor.JASON; 15 | var treeGet = require('nlib').Support.tree.get; 16 | 17 | 18 | // internal 19 | var compression = require('./compression'); 20 | 21 | 22 | //////////////////////////////////////////////////////////////////////////////// 23 | 24 | 25 | // configure(root) -> Mincer.Environment 26 | // - root (String): Root pathname of the environment 27 | // 28 | // Preconfigures Mincer environment 29 | // 30 | function configure(root) { 31 | var environment = new Mincer.Environment(root); 32 | 33 | // 34 | // Provide some helpers to EJS and Stylus 35 | // 36 | 37 | environment.registerHelper({ 38 | asset_path: function (pathname) { 39 | var asset = environment.findAsset(pathname); 40 | return !asset ? null : ("/assets/" + asset.digestPath); 41 | }, 42 | nodeca: function (path) { 43 | return treeGet(nodeca, path); 44 | }, 45 | jason: JASON.stringify 46 | }); 47 | 48 | // 49 | // fill in 3rd-party modules paths 50 | // 51 | 52 | environment.appendPath(path.resolve(__dirname, '../../../../node_modules/nlib/node_modules/pointer/browser')); 53 | environment.appendPath(path.resolve(__dirname, '../../../../node_modules/nlib/node_modules/babelfish/browser')); 54 | 55 | // 56 | // fill in base assets (non-themable) of all apps 57 | // 58 | 59 | _.each(nodeca.runtime.apps, function (app) { 60 | environment.appendPath(path.join(app.root, 'assets/javascripts')); 61 | environment.appendPath(path.join(app.root, 'assets/stylesheets')); 62 | environment.appendPath(path.join(app.root, 'assets/vendor')); 63 | }); 64 | 65 | // 66 | // add embedded fonts path 67 | // 68 | 69 | environment.appendPath(path.join( 70 | nodeca.runtime.apps[0].root, 'assets/embedded_fonts' 71 | )); 72 | 73 | // 74 | // add root path itself 75 | // 76 | 77 | environment.appendPath('.'); 78 | 79 | // 80 | // Set JS/CSS compression if it was not explicitly disabled 81 | // USAGE: SKIP_ASSETS_COMPRESSION=1 ./nodeca.js server 82 | // 83 | 84 | if (!process.env.SKIP_ASSETS_COMPRESSION) { 85 | environment.jsCompressor = compression.js; 86 | environment.cssCompressor = compression.css; 87 | } 88 | 89 | return environment; 90 | } 91 | 92 | 93 | //////////////////////////////////////////////////////////////////////////////// 94 | 95 | 96 | module.exports.configure = configure; 97 | -------------------------------------------------------------------------------- /assets/vendor/bootstrap/src/less/modals.less: -------------------------------------------------------------------------------- 1 | // 2 | // Modals 3 | // -------------------------------------------------- 4 | 5 | 6 | // Recalculate z-index where appropriate, 7 | // but only apply to elements within modal 8 | .modal-open .modal { 9 | .dropdown-menu { z-index: @zindexDropdown + @zindexModal; } 10 | .dropdown.open { *z-index: @zindexDropdown + @zindexModal; } 11 | .popover { z-index: @zindexPopover + @zindexModal; } 12 | .tooltip { z-index: @zindexTooltip + @zindexModal; } 13 | } 14 | 15 | // Background 16 | .modal-backdrop { 17 | position: fixed; 18 | top: 0; 19 | right: 0; 20 | bottom: 0; 21 | left: 0; 22 | z-index: @zindexModalBackdrop; 23 | background-color: @black; 24 | // Fade for backdrop 25 | &.fade { opacity: 0; } 26 | } 27 | 28 | .modal-backdrop, 29 | .modal-backdrop.fade.in { 30 | .opacity(80); 31 | } 32 | 33 | // Base modal 34 | .modal { 35 | position: fixed; 36 | top: 50%; 37 | left: 50%; 38 | z-index: @zindexModal; 39 | overflow: auto; 40 | width: 560px; 41 | margin: -250px 0 0 -280px; 42 | background-color: @white; 43 | border: 1px solid #999; 44 | border: 1px solid rgba(0,0,0,.3); 45 | *border: 1px solid #999; /* IE6-7 */ 46 | .border-radius(6px); 47 | .box-shadow(0 3px 7px rgba(0,0,0,0.3)); 48 | .background-clip(padding-box); 49 | &.fade { 50 | .transition(e('opacity .3s linear, top .3s ease-out')); 51 | top: -25%; 52 | } 53 | &.fade.in { top: 50%; } 54 | } 55 | .modal-header { 56 | padding: 9px 15px; 57 | border-bottom: 1px solid #eee; 58 | // Close icon 59 | .close { margin-top: 2px; } 60 | // Heading 61 | h3 { 62 | margin: 0; 63 | line-height: 30px; 64 | } 65 | } 66 | 67 | // Body (where all modal content resides) 68 | .modal-body { 69 | overflow-y: auto; 70 | max-height: 400px; 71 | padding: 15px; 72 | } 73 | // Remove bottom margin if need be 74 | .modal-form { 75 | margin-bottom: 0; 76 | } 77 | 78 | // Footer (for actions) 79 | .modal-footer { 80 | padding: 14px 15px 15px; 81 | margin-bottom: 0; 82 | text-align: right; // right align buttons 83 | background-color: #f5f5f5; 84 | border-top: 1px solid #ddd; 85 | .border-radius(0 0 6px 6px); 86 | .box-shadow(inset 0 1px 0 @white); 87 | .clearfix(); // clear it in case folks use .pull-* classes on buttons 88 | 89 | // Properly space out buttons 90 | .btn + .btn { 91 | margin-left: 5px; 92 | margin-bottom: 0; // account for input[type="submit"] which gets the bottom margin like all other inputs 93 | } 94 | // but override that for button groups 95 | .btn-group .btn + .btn { 96 | margin-left: -1px; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /shared/render.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | /** 5 | * shared 6 | **/ 7 | 8 | 9 | /*global nodeca, _*/ 10 | 11 | 12 | //////////////////////////////////////////////////////////////////////////////// 13 | 14 | 15 | // get_layout_stack(layout) -> Array 16 | // - layout (string): Full layout path 17 | // 18 | // Returns stack of layouts. 19 | // 20 | // get_layout_stack('foo.bar.baz') // => ['foo', 'foo.bar', 'foo.bar.baz'] 21 | // 22 | function get_layout_stack(layout) { 23 | var stack = layout.split('.'), i, l; 24 | 25 | for (i = 1, l = stack.length; i < l; i++) { 26 | stack[i] = stack[i - 1] + '.' + stack[i]; 27 | } 28 | 29 | return stack; 30 | } 31 | 32 | 33 | //////////////////////////////////////////////////////////////////////////////// 34 | 35 | 36 | /** 37 | * shared.render(views, path, locals, layout, skipBaseLayout) -> String 38 | * - viewsTree (Object): Views tree (without locale and/or theme subpaths). 39 | * - path (String): View name to render, e.g. `forums.index` 40 | * - locals (Object): Locals data to pass to the renderer function 41 | * - layout (String): Layout to render, e.g. `default.blogs` 42 | * - skipBaseLayout (Boolean): Whenever to skip rendering base layout or not 43 | * 44 | * Renders view registered as `path` with given `layout` and returns result. 45 | * 46 | * render(views, 'blogs.post.show', 'default.blogs'); 47 | * 48 | * In the example above, it will render `blogs.post.show` view with given 49 | * `data`, then will render `default.blogs` layout with `data` where `content` 50 | * property will be rendered view, then `default` layout with `data` where 51 | * `content` property will be previously rendered layout. 52 | **/ 53 | module.exports = function render(viewsTree, path, locals, layout, skipBaseLayout) { 54 | var html, view = nodeca.shared.getByPath(viewsTree, path); 55 | 56 | if (!!view) { 57 | html = view(locals); 58 | } else { 59 | // Here we just notify that view not found. 60 | // This should never happen - one must check path existance before render() 61 | nodeca.logger.warn("View " + path + " not found"); 62 | html = ''; 63 | } 64 | 65 | if (layout) { 66 | layout = (_.isArray(layout) ? layout.slice() : get_layout_stack(layout)); 67 | layout = (!!skipBaseLayout ? layout.slice(1) : layout).reverse(); 68 | 69 | _.each(layout, function (path) { 70 | var fn = nodeca.shared.getByPath(viewsTree.layouts, path); 71 | 72 | if (!_.isFunction(fn)) { 73 | nodeca.logger.warn("Layout " + path + " not found"); 74 | return; 75 | } 76 | 77 | locals.content = html; 78 | html = fn(locals); 79 | }); 80 | } 81 | 82 | return html; 83 | }; 84 | -------------------------------------------------------------------------------- /assets/vendor/jquery.noty/src/css/jquery.noty.css: -------------------------------------------------------------------------------- 1 | 2 | /* CORE STYLES */ 3 | 4 | /* noty bar */ 5 | .noty_bar { 6 | position: fixed; 7 | display: none; 8 | z-index: 9999999; 9 | } 10 | 11 | /* noty_message */ 12 | .noty_bar .noty_message { 13 | text-align: center; 14 | } 15 | 16 | /* noty close button */ 17 | .noty_bar .noty_close { 18 | cursor: pointer; 19 | } 20 | 21 | /* noty modal */ 22 | .noty_modal { 23 | position: fixed; 24 | width: 100%; 25 | height: 100%; 26 | background-color: #000; 27 | z-index: 10000; 28 | opacity: 0.6; 29 | display: none; 30 | left: 0; 31 | top: 0; 32 | } 33 | 34 | /* noty container for noty_layout_topLeft & noty_layout_topRight */ 35 | ul.noty_cont { 36 | position: fixed; 37 | z-index: 10000000; 38 | margin: 0px; 39 | padding: 0px; 40 | list-style: none; 41 | width: 300px; 42 | } 43 | ul.noty_cont li { 44 | position: relative; 45 | float: left; 46 | clear: both; 47 | list-style: none; 48 | padding: 0px; 49 | margin: 10px 0 0 0; 50 | width: 300px; /* Fix for: http://bugs.jquery.com/ticket/2278 */ 51 | } 52 | ul.noty_cont.noty_layout_topLeft {left:20px; top:20px;} 53 | ul.noty_cont.noty_layout_topRight {right:40px; top:20px;} 54 | ul.noty_cont.noty_layout_bottomLeft {left:20px; bottom:20px} 55 | ul.noty_cont.noty_layout_bottomRight {right:40px; bottom:20px} 56 | ul.noty_cont.noty_layout_topRight li {float:right} 57 | 58 | /* LAYOUTS */ 59 | 60 | /* noty_layout_top */ 61 | .noty_bar.noty_layout_top { 62 | top: 0; 63 | left: 0; 64 | width: 100%; 65 | -webkit-border-radius: 0px; 66 | -moz-border-radius: 0px; 67 | border-radius: 0px; 68 | } 69 | 70 | /* noty_layout_bottom */ 71 | .noty_bar.noty_layout_bottom { 72 | bottom: 0; 73 | left: 0; 74 | width: 100%; 75 | -webkit-border-radius: 0px; 76 | -moz-border-radius: 0px; 77 | border-radius: 0px; 78 | } 79 | 80 | /* noty_layout_center */ 81 | .noty_bar.noty_layout_center { 82 | top: 40%; 83 | } 84 | 85 | /* noty_layout_topLeft & noty_layout_topRight */ 86 | .noty_bar.noty_layout_topLeft, 87 | .noty_bar.noty_layout_topRight, 88 | .noty_bar.noty_layout_bottomLeft, 89 | .noty_bar.noty_layout_bottomRight { 90 | width: 100%; 91 | clear: both; 92 | position: relative; 93 | } 94 | 95 | .noty_bar.noty_layout_topLeft .noty_message, 96 | .noty_bar.noty_layout_topRight .noty_message, 97 | .noty_bar.noty_layout_bottomLeft .noty_message, 98 | .noty_bar.noty_layout_bottomRight .noty_message { 99 | text-align: left; 100 | } 101 | 102 | /* noty_layout_topCenter */ 103 | .noty_bar.noty_layout_topCenter { 104 | top: 20px; 105 | } -------------------------------------------------------------------------------- /assets/vendor/bootstrap/src/less/carousel.less: -------------------------------------------------------------------------------- 1 | // 2 | // Carousel 3 | // -------------------------------------------------- 4 | 5 | 6 | .carousel { 7 | position: relative; 8 | margin-bottom: @baseLineHeight; 9 | line-height: 1; 10 | } 11 | 12 | .carousel-inner { 13 | overflow: hidden; 14 | width: 100%; 15 | position: relative; 16 | } 17 | 18 | .carousel { 19 | 20 | .item { 21 | display: none; 22 | position: relative; 23 | .transition(.6s ease-in-out left); 24 | } 25 | 26 | // Account for jankitude on images 27 | .item > img { 28 | display: block; 29 | line-height: 1; 30 | } 31 | 32 | .active, 33 | .next, 34 | .prev { display: block; } 35 | 36 | .active { 37 | left: 0; 38 | } 39 | 40 | .next, 41 | .prev { 42 | position: absolute; 43 | top: 0; 44 | width: 100%; 45 | } 46 | 47 | .next { 48 | left: 100%; 49 | } 50 | .prev { 51 | left: -100%; 52 | } 53 | .next.left, 54 | .prev.right { 55 | left: 0; 56 | } 57 | 58 | .active.left { 59 | left: -100%; 60 | } 61 | .active.right { 62 | left: 100%; 63 | } 64 | 65 | } 66 | 67 | // Left/right controls for nav 68 | // --------------------------- 69 | 70 | .carousel-control { 71 | position: absolute; 72 | top: 40%; 73 | left: 15px; 74 | width: 40px; 75 | height: 40px; 76 | margin-top: -20px; 77 | font-size: 60px; 78 | font-weight: 100; 79 | line-height: 30px; 80 | color: @white; 81 | text-align: center; 82 | background: @grayDarker; 83 | border: 3px solid @white; 84 | .border-radius(23px); 85 | .opacity(50); 86 | 87 | // we can't have this transition here 88 | // because webkit cancels the carousel 89 | // animation if you trip this while 90 | // in the middle of another animation 91 | // ;_; 92 | // .transition(opacity .2s linear); 93 | 94 | // Reposition the right one 95 | &.right { 96 | left: auto; 97 | right: 15px; 98 | } 99 | 100 | // Hover state 101 | &:hover { 102 | color: @white; 103 | text-decoration: none; 104 | .opacity(90); 105 | } 106 | } 107 | 108 | 109 | // Caption for text below images 110 | // ----------------------------- 111 | 112 | .carousel-caption { 113 | position: absolute; 114 | left: 0; 115 | right: 0; 116 | bottom: 0; 117 | padding: 15px; 118 | background: @grayDark; 119 | background: rgba(0,0,0,.75); 120 | } 121 | .carousel-caption h4, 122 | .carousel-caption p { 123 | color: @white; 124 | line-height: @baseLineHeight; 125 | } 126 | .carousel-caption h4 { 127 | margin: 0 0 5px; 128 | } 129 | .carousel-caption p { 130 | margin-bottom: 0; 131 | } 132 | -------------------------------------------------------------------------------- /assets/stylesheets/ui/panes/selector.styl: -------------------------------------------------------------------------------- 1 | #selector 2 | margin-top -20px 3 | position relative 4 | 5 | .src-font-head 6 | margin-top 20px 7 | font-size 30px 8 | line-height 45px 9 | 10 | a.font-info 11 | transition all .5s ease 12 | vertical-align top 13 | display inline-block 14 | margin-top 10px 15 | margin-right 5px 16 | 17 | /* Collapser & animations */ 18 | a.src-font-name 19 | color inherit 20 | text-decoration none 21 | outline 0 none 22 | 23 | .src-font-name:after 24 | transition all .5s ease 25 | border-left 6px solid transparent 26 | border-right 6px solid transparent 27 | border-bottom 6px solid #333 28 | content "" 29 | display inline-block 30 | height 0 31 | width 0 32 | margin-left 10px 33 | vertical-align middle 34 | margin-left 8px 35 | opacity 0 36 | 37 | .src-font-head:hover .src-font-name:after 38 | opacity 1 39 | 40 | .src-font-head 41 | transition all .5s ease 42 | 43 | ._collapsed .src-font-head 44 | font-size 18px 45 | line-height 24px 46 | opacity .2 47 | 48 | ._collapsed .src-font-head:hover 49 | opacity .7 50 | 51 | ._collapsed .src-font-name:after 52 | border-bottom 0 none 53 | border-top 3px solid #333 54 | border-left 3px solid transparent 55 | border-right 3px solid transparent 56 | margin-left 5px 57 | 58 | ._collapsed a.font-info 59 | margin-top 2px 60 | 61 | 62 | 63 | #local-files 64 | /* chrome/opera doesn't trigger events on "display: none;" elements */ 65 | /* so, do some tricks to safely hide element */ 66 | 67 | /* display: none; */ 68 | width 0px 69 | height 0px 70 | position absolute 71 | top -100px 72 | visibility hidden 73 | 74 | .font-glyphs 75 | display inline-block 76 | user-select none 77 | 78 | .glyph 79 | position relative 80 | float left 81 | border 1px #ccc solid 82 | border-radius 6px 83 | cursor pointer 84 | text-align center 85 | width 48px 86 | height 48px 87 | line-height 48px 88 | margin 0 0 8px 8px 89 | transition all .1s ease 90 | box-shadow 1px 1px 3px #eee 91 | 92 | &:hover 93 | background #333 94 | color #fff 95 | //opacity .8 96 | 97 | &.selected 98 | background-color #fffdfd 99 | border-color #d88 100 | box-shadow 0 0 0px 2px #d88 inset, 1px 1px 3px 1px #eee 101 | 102 | &:hover 103 | background #666 104 | 105 | &.ui-selecting 106 | background-color #eeffee 107 | border-color #8d8 108 | //box-shadow 0 0 3px #ada inset 109 | 110 | &.selected.ui-selecting 111 | background-color #eeffee 112 | border-color #666 113 | box-shadow 0 0 3px #666 inset 114 | 115 | ._3d .glyph 116 | text-shadow 1px 1px 1px rgba(127, 127, 127, 0.3) 117 | -------------------------------------------------------------------------------- /assets/vendor/bootstrap/src/js/bootstrap-alert.js: -------------------------------------------------------------------------------- 1 | /* ========================================================== 2 | * bootstrap-alert.js v2.1.1 3 | * http://twitter.github.com/bootstrap/javascript.html#alerts 4 | * ========================================================== 5 | * Copyright 2012 Twitter, Inc. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ========================================================== */ 19 | 20 | 21 | !function ($) { 22 | 23 | "use strict"; // jshint ;_; 24 | 25 | 26 | /* ALERT CLASS DEFINITION 27 | * ====================== */ 28 | 29 | var dismiss = '[data-dismiss="alert"]' 30 | , Alert = function (el) { 31 | $(el).on('click', dismiss, this.close) 32 | } 33 | 34 | Alert.prototype.close = function (e) { 35 | var $this = $(this) 36 | , selector = $this.attr('data-target') 37 | , $parent 38 | 39 | if (!selector) { 40 | selector = $this.attr('href') 41 | selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 42 | } 43 | 44 | $parent = $(selector) 45 | 46 | e && e.preventDefault() 47 | 48 | $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent()) 49 | 50 | $parent.trigger(e = $.Event('close')) 51 | 52 | if (e.isDefaultPrevented()) return 53 | 54 | $parent.removeClass('in') 55 | 56 | function removeElement() { 57 | $parent 58 | .trigger('closed') 59 | .remove() 60 | } 61 | 62 | $.support.transition && $parent.hasClass('fade') ? 63 | $parent.on($.support.transition.end, removeElement) : 64 | removeElement() 65 | } 66 | 67 | 68 | /* ALERT PLUGIN DEFINITION 69 | * ======================= */ 70 | 71 | $.fn.alert = function (option) { 72 | return this.each(function () { 73 | var $this = $(this) 74 | , data = $this.data('alert') 75 | if (!data) $this.data('alert', (data = new Alert(this))) 76 | if (typeof option == 'string') data[option].call($this) 77 | }) 78 | } 79 | 80 | $.fn.alert.Constructor = Alert 81 | 82 | 83 | /* ALERT DATA-API 84 | * ============== */ 85 | 86 | $(function () { 87 | $('body').on('click.alert.data-api', dismiss, Alert.prototype.close) 88 | }) 89 | 90 | }(window.jQuery); -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Fontello - iconic fonts scissors 2 | ================================ 3 | 4 | Website: [fontello.com](http://fontello.com/) 5 | 6 | This tool lets you combine iconic webfonts for your own project. With fontello you can: 7 | 8 | 1. shrink glyph collections, minimizing font size 9 | 2. merge symbols from several fonts into a single file 10 | 3. access large sets of professional-grade open source icons 11 | 12 | Now it's trivial to make a custom iconic webfont, exactly for your needs. 13 | First, select the icons you like. Then update glyph codes (optional), and 14 | download your webfont bundle. We generate everything you need, ready for publishing 15 | on your website! 16 | 17 | Don't forget about donations... These are some awesome icons, available with an 18 | open source license :) . A donation is the best way to express gratitude for our work. 19 | 20 | 21 | ## Embedded Fonts 22 | 23 | Fontello comes with the following embedded set of iconic fonts: 24 | 25 | - [__Entypo__](http://www.entypo.com/) by Daniel Bruce (CC BY-SA license) 26 | - [__Font Awesome__](http://fortawesome.github.com/Font-Awesome//) by Dave Gandy (CC BY-SA license) 27 | - [__Iconic__](https://github.com/somerandomdude/Iconic) by P.J. Onori (SIL OFL) 28 | - [__Brandico__](https://github.com/fontello/brandico.font) by... all :) (SIL OFL) 29 | 30 | Please, note that these embedded fonts differ from the original files. We did some 31 | modifications to unify characteristics such as scale, ascent/descent andalignment. 32 | If you need specific details on modifications, take a look into the updated fonts repos 33 | at [github](https://github.com/fontello/). 34 | 35 | 36 | ## Contacts 37 | 38 | - Questions: [Google group](https://groups.google.com/group/fontello/) 39 | - Bug reports: [Issue tracker](https://github.com/nodeca/fontomas/issues) 40 | - Suggestion for adding your OFL fonts or other collaborations: vitaly@rcdesign.ru 41 | 42 | 43 | ## Authors 44 | 45 | - Roman Shmelev ([shmelev](https://github.com/shmelev)) 46 | - Vitaly Puzrin ([puzrin](https://github.com/puzrin)). 47 | [Follow](https://twitter.com/puzrin) on twitter. 48 | - Aleksey Zapparov ([ixti](https://github.com/ixti)). 49 | Follow [@zapparov](https://twitter.com/zapparov) on twitter. 50 | 51 | 52 | ## License 53 | 54 | Fontello's code (all files, except fonts) is distributed under MIT license. See 55 | [LICENSE](https://github.com/fontello/fontello/blob/master/LICENSE) file for details. 56 | 57 | Embedded fonts are distributed under their primary licenses (SIL OFL / CC BY / CC BY-SA). 58 | See section [Embedded Fonts](#embedded) above for credits & links to font homepages. 59 | 60 | Generated fonts are intended for web usage, and should not be 61 | considered/distributed as independent artwork. Consider fontello a 62 | font archiver and credit original font creators according to their respective license. 63 | 64 | Crediting fontello is not required :) 65 | -------------------------------------------------------------------------------- /bin/build_common_font.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os 4 | import sys 5 | from sys import stderr 6 | import argparse 7 | import yaml 8 | import json 9 | import fontforge 10 | from pprint import pprint 11 | 12 | GLYPHS_CODE_START = 0xE800 13 | 14 | def read_config(config_path): 15 | try: 16 | return yaml.load(open(config_path, 'r')) 17 | except IOError as (errno, strerror): 18 | stderr.write("Cannot open %s: %s\n" % (args.config, strerror)) 19 | sys.exit(1) 20 | except yaml.YAMLError, e: 21 | if hasattr(e, 'problem_mark'): 22 | mark = e.problem_mark 23 | stderr.write("YAML parser error in file %s at line %d, col %d\n" % 24 | (args.config, mark.line + 1, mark.column + 1)) 25 | else: 26 | stderr.write("YAML parser error in file %s: %s\n" % (args.config, e)) 27 | sys.exit(1) 28 | 29 | parser = argparse.ArgumentParser(description='Merge glyphs from ' 30 | 'several fonts to single font') 31 | parser.add_argument('-i', '--input_fonts', type=str, required=True, 32 | action='append', nargs='+', help='Input fonts') 33 | parser.add_argument('-o', '--dst_font', type=str, required=True, 34 | help='Output font') 35 | parser.add_argument('-c', '--remap_config', type=argparse.FileType('wb', 0), 36 | required=True, 37 | help='Output font remap config file') 38 | 39 | args = parser.parse_args() 40 | 41 | input_fonts = [] 42 | for item in args.input_fonts: 43 | input_fonts += item 44 | 45 | new_font_config = {} 46 | 47 | # init new font 48 | new_font = fontforge.font() 49 | new_font.encoding = 'UnicodeFull' 50 | 51 | new_glyph_code = GLYPHS_CODE_START 52 | 53 | for path in input_fonts: 54 | if os.path.isdir(path): 55 | config = read_config(os.path.join(path, 'config.yml')) 56 | 57 | if not config.get('font', {}).has_key('fontname'): 58 | stderr.write("Bad config format %s: \n" % os.path.join(path, 'config.yml') ) 59 | 60 | font_name = config.get('font', {}).get('fontname', None) 61 | font_path = os.path.join(path, 'font', font_name + '.ttf') 62 | src_font = fontforge.open(font_path) 63 | 64 | new_font_config[font_name] = {} 65 | 66 | for glyph in config['glyphs']: 67 | new_font_config[font_name][glyph['uid']] = new_glyph_code 68 | 69 | # cp glyph 70 | src_font.selection.select(("unicode",), glyph['code']) 71 | src_font.copy() 72 | new_font.selection.select(("unicode",), new_glyph_code) 73 | new_font.paste() 74 | 75 | new_glyph_code += 1 76 | 77 | try: 78 | new_font.generate(args.dst_font) 79 | except: 80 | stderr.write("Cannot write to file %s\n" %args.dst_font) 81 | sys.exit(1) 82 | 83 | 84 | json_data = json.dumps(new_font_config, indent = 2) 85 | args.remap_config.write("// THIS IS AUTOGENERATED FILE. DO NOT EDIT\n" + 86 | "module.exports = " + json_data) 87 | -------------------------------------------------------------------------------- /assets/stylesheets/ui/toolbar.styl: -------------------------------------------------------------------------------- 1 | .toolbar 2 | position relative 3 | 4 | //== Make toolbar background non-transparent 5 | .navbar-fixed-top 6 | background-color #fff 7 | 8 | //== Dirty fix typeahead & tooltip z-index, to be over static container 9 | .typeahead.dropdown-menu 10 | .tooltip 11 | z-index 1050 12 | 13 | #glyph-size-slider 14 | width: 100px 15 | display inline-block 16 | float: left 17 | margin-top 11px 18 | margin-left .5em 19 | 20 | #glyph-size-value 21 | display inline-block 22 | float left 23 | //height 29px 24 | line-height 30px 25 | margin 0 1em 26 | color #888 27 | font-size 11px 28 | 29 | //== "3D" switch 30 | .btn-group .switch-3d 31 | display inline-block 32 | float left 33 | font-size 11px 34 | color grayLight 35 | line-height 30px 36 | input 37 | vertical-align top 38 | margin-top 7px 39 | 40 | 41 | /* 42 | * jQuery UI Slider 1.8.16 43 | * 44 | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) 45 | * Dual licensed under the MIT or GPL Version 2 licenses. 46 | * http://jquery.org/license 47 | * 48 | * http://docs.jquery.com/UI/Slider#theming 49 | */ 50 | .ui-slider 51 | position relative 52 | text-align left 53 | 54 | border 1px solid 55 | border-color #bbb #bbb #ddd #ddd 56 | border-radius 1em 57 | background #ddd 58 | background-image: linear-gradient(top, #bbb 0%, #fff 80%, #ddd 100%); 59 | 60 | // fix toolbar fontsize reset 61 | font-size 14px 62 | 63 | .ui-slider .ui-slider-handle 64 | position absolute 65 | z-index 2 66 | width 1.2em 67 | height 1.2em 68 | cursor default 69 | 70 | border-radius 2em 71 | border 1px solid #aaa 72 | background #aaa 73 | background-image: linear-gradient(top, #fff 0%, #eee 50%, #aaa 100%); 74 | 75 | outline none 76 | 77 | &:after 78 | position absolute 79 | content "" 80 | width .5em 81 | height .5em 82 | top .35em 83 | left .35em 84 | // background-color #000 85 | border-radius 1em 86 | box-shadow 0 0.2em 0.15em #888888 inset 87 | 88 | 89 | 90 | .ui-slider .ui-slider-range 91 | display none; 92 | /* 93 | position: absolute; 94 | z-index: 1; 95 | font-size: .7em; 96 | display: block; 97 | border: 0; 98 | background-position: 0 0 99 | color: #ffffff; 100 | background-color: #0064cd; 101 | background-repeat: repeat-x; 102 | background-image: linear-gradient(top, #049cdb, #0064cd); 103 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); 104 | border-color: #0064cd #0064cd #003f81; 105 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); 106 | */ 107 | 108 | .ui-slider-horizontal 109 | height .4em 110 | 111 | .ui-slider-handle 112 | top -.45em 113 | margin-left -.6em 114 | .ui-slider-range 115 | top 0 116 | height 100% 117 | .ui-slider-range-min 118 | left 0 119 | .ui-slider-range-max 120 | right 0 121 | 122 | .donate 123 | display block 124 | position absolute 125 | right 0 126 | bottom 8px 127 | font-size 12px 128 | opacity .7 -------------------------------------------------------------------------------- /assets/vendor/bootstrap/src/js/bootstrap-button.js: -------------------------------------------------------------------------------- 1 | /* ============================================================ 2 | * bootstrap-button.js v2.1.1 3 | * http://twitter.github.com/bootstrap/javascript.html#buttons 4 | * ============================================================ 5 | * Copyright 2012 Twitter, Inc. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ============================================================ */ 19 | 20 | 21 | !function ($) { 22 | 23 | "use strict"; // jshint ;_; 24 | 25 | 26 | /* BUTTON PUBLIC CLASS DEFINITION 27 | * ============================== */ 28 | 29 | var Button = function (element, options) { 30 | this.$element = $(element) 31 | this.options = $.extend({}, $.fn.button.defaults, options) 32 | } 33 | 34 | Button.prototype.setState = function (state) { 35 | var d = 'disabled' 36 | , $el = this.$element 37 | , data = $el.data() 38 | , val = $el.is('input') ? 'val' : 'html' 39 | 40 | state = state + 'Text' 41 | data.resetText || $el.data('resetText', $el[val]()) 42 | 43 | $el[val](data[state] || this.options[state]) 44 | 45 | // push to event loop to allow forms to submit 46 | setTimeout(function () { 47 | state == 'loadingText' ? 48 | $el.addClass(d).attr(d, d) : 49 | $el.removeClass(d).removeAttr(d) 50 | }, 0) 51 | } 52 | 53 | Button.prototype.toggle = function () { 54 | var $parent = this.$element.closest('[data-toggle="buttons-radio"]') 55 | 56 | $parent && $parent 57 | .find('.active') 58 | .removeClass('active') 59 | 60 | this.$element.toggleClass('active') 61 | } 62 | 63 | 64 | /* BUTTON PLUGIN DEFINITION 65 | * ======================== */ 66 | 67 | $.fn.button = function (option) { 68 | return this.each(function () { 69 | var $this = $(this) 70 | , data = $this.data('button') 71 | , options = typeof option == 'object' && option 72 | if (!data) $this.data('button', (data = new Button(this, options))) 73 | if (option == 'toggle') data.toggle() 74 | else if (option) data.setState(option) 75 | }) 76 | } 77 | 78 | $.fn.button.defaults = { 79 | loadingText: 'loading...' 80 | } 81 | 82 | $.fn.button.Constructor = Button 83 | 84 | 85 | /* BUTTON DATA-API 86 | * =============== */ 87 | 88 | $(function () { 89 | $('body').on('click.button.data-api', '[data-toggle^=button]', function ( e ) { 90 | var $btn = $(e.target) 91 | if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') 92 | $btn.button('toggle') 93 | }) 94 | }) 95 | 96 | }(window.jQuery); -------------------------------------------------------------------------------- /lib/env.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | /** 5 | * lib 6 | **/ 7 | 8 | 9 | /*global nodeca, _*/ 10 | 11 | 12 | //////////////////////////////////////////////////////////////////////////////// 13 | 14 | 15 | var tzOffset = (new Date).getTimezoneOffset(); 16 | 17 | 18 | //////////////////////////////////////////////////////////////////////////////// 19 | 20 | 21 | /** 22 | * lib.env(options) -> Object 23 | * - options (Object): Environment options. 24 | * 25 | * Create new request environment object. 26 | * 27 | * 28 | * ##### Options 29 | * 30 | * - **http**: HTTP origin object that contains `req` and `res`. 31 | * - **rpc**: API3 (Ajax) origin that contains `req` and `res`. 32 | * - **skip**: Array of middlewares to skip 33 | * - **session**: Session object 34 | * - **theme**: Theme name as String 35 | * - **locale**: Locale name as String 36 | * - **method**: Name of the server method, e.g. `'forums.posts.show'` 37 | * - **layout**: Layout name as String 38 | **/ 39 | module.exports = function env(options) { 40 | var ctx = { 41 | extras: {}, 42 | helpers: { 43 | asset_path: function asset_path(path) { 44 | var asset = nodeca.runtime.assets.manifest.assets[path]; 45 | return !asset ? "#" : ("/assets/" + asset); 46 | } 47 | }, 48 | origin: { 49 | http: options.http, 50 | rpc: options.rpc 51 | }, 52 | skip: (options.skip || []).slice(), 53 | // FIXME: should be filled by session middleware 54 | session: options.session || { 55 | theme: 'desktop', 56 | locale: nodeca.config.locales['default'] 57 | }, 58 | request: { 59 | // FIXME: should be deprecated in flavour of env.origin 60 | origin: !!options.rpc ? 'RPC' : 'HTTP', 61 | method: options.method, 62 | namespace: String(options.method).split('.').shift() 63 | }, 64 | data: {}, 65 | response: { 66 | data: { 67 | head: { 68 | title: null, // should be filled with default value 69 | apiPath: options.method, 70 | // List of assets for yepnope, 71 | // Each element is an object with properties: 72 | // 73 | // type: css|js 74 | // link: asset_url 75 | // 76 | // example: assets.push({type: 'js', link: '//example.com/foo.js'}); 77 | assets: [] 78 | }, 79 | menus: {}, 80 | widgets: {} 81 | }, 82 | headers: {}, 83 | // Layouts are supporting "nesting" via `dots: 84 | // 85 | // default.blogs 86 | // 87 | // In the example above, `default.blogs` will be rendered first and the 88 | // result will be provided for rendering to `default`. 89 | layout: options.layout || 'default', 90 | view: options.method 91 | } 92 | }; 93 | 94 | // 95 | // env-dependent helper needs to be bounded to env 96 | // 97 | 98 | ctx.helpers.t = function (phrase, params) { 99 | return nodeca.runtime.i18n.t(this.session.locale, phrase, params); 100 | }.bind(ctx); 101 | 102 | return ctx; 103 | }; 104 | -------------------------------------------------------------------------------- /bin/generate_font.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | 4 | set -e # die on any unexpected error 5 | 6 | 7 | ## INIT ######################################################################## 8 | 9 | 10 | FONTNAME=$1 11 | TMPDIR=$2 12 | ZIPBALL=$3 13 | 14 | USER_CONFIG=$TMPDIR/config.json 15 | CONFIG=$TMPDIR/generator-config.json 16 | FONT_TEMPLATES="$PWD/support/font-templates" 17 | 18 | 19 | mkdir $TMPDIR/css $TMPDIR/font 20 | 21 | 22 | ## HELPERS ##################################################################### 23 | 24 | 25 | require() 26 | { 27 | if ! $( which $1 > /dev/null ) ; then 28 | echo "Can't find required command: $1" >&2 29 | exit 128 30 | fi 31 | return 0 32 | } 33 | 34 | 35 | ## PREPARE PATHS ############################################################### 36 | 37 | 38 | export PATH="$PWD/bin:$PATH" 39 | export PATH="$PWD/node_modules/.bin:$PATH" 40 | export PATH="$PWD/support/font-builder/bin:$PATH" 41 | export PATH="$PWD/support/font-builder/support/ttf2eot:$PATH" 42 | export PATH="$PWD/support/font-builder/support/ttfautohint/frontend:$PATH" 43 | 44 | 45 | ## CHECK DEPENDENCIES ########################################################## 46 | 47 | 48 | for dep in font_merge.py fontconvert.py fontdemo.py ttfautohint ttf2eot jade zip; do 49 | require $dep 50 | done 51 | 52 | 53 | ## BUILD FONT CONFIG ########################################################### 54 | 55 | 56 | node ./fontello.js font_config --input $USER_CONFIG --output $CONFIG 57 | 58 | 59 | ## BUILD FONT ################################################################## 60 | 61 | 62 | font_merge.py --config "$CONFIG" --dst_font "$TMPDIR/font/$FONTNAME.ttf" 63 | ttfautohint --latin-fallback --hinting-limit=200 --hinting-range-max=50 \ 64 | --symbol "$TMPDIR/font/$FONTNAME.ttf" "$TMPDIR/font/$FONTNAME-hinted.ttf" 65 | mv "$TMPDIR/font/$FONTNAME-hinted.ttf" "$TMPDIR/font/$FONTNAME.ttf" 66 | fontconvert.py --src_font "$TMPDIR/font/$FONTNAME.ttf" --fonts_dir "$TMPDIR/font" 67 | ttf2eot < "$TMPDIR/font/$FONTNAME.ttf" > "$TMPDIR/font/$FONTNAME.eot" 68 | 69 | 70 | ## BUILD TEMPLATES ############################################################# 71 | 72 | 73 | tpl-render.js --locals "$CONFIG" --input "$FONT_TEMPLATES/demo.jade" \ 74 | --output "$TMPDIR/demo.html" --pretty 75 | 76 | tpl-render.js --locals "$CONFIG" --input "$FONT_TEMPLATES/css/css.jade" \ 77 | --output "$TMPDIR/css/$FONTNAME.css" 78 | 79 | tpl-render.js --locals "$CONFIG" --input "$FONT_TEMPLATES/css/css-ie7.jade" \ 80 | --output "$TMPDIR/css/$FONTNAME-ie7.css" 81 | 82 | tpl-render.js --locals "$CONFIG" --input "$FONT_TEMPLATES/css/css-codes.jade" \ 83 | --output "$TMPDIR/css/$FONTNAME-codes.css" 84 | 85 | tpl-render.js --locals "$CONFIG" --input "$FONT_TEMPLATES/css/css-ie7-codes.jade" \ 86 | --output "$TMPDIR/css/$FONTNAME-ie7-codes.css" 87 | 88 | tpl-render.js --locals "$CONFIG" --input "$FONT_TEMPLATES/LICENSE.jade" \ 89 | --output "$TMPDIR/LICENSE.txt" 90 | 91 | cp "$FONT_TEMPLATES/README.txt" "$TMPDIR/" 92 | 93 | 94 | ## BUILD ZIPBALL ############################################################### 95 | 96 | 97 | MAXLEN=$(expr $(echo -n $TMPDIR | wc -c) - 24) 98 | FIXDIR=$(echo -n $TMPDIR | cut -c-$MAXLEN) 99 | 100 | rm $CONFIG && rm -rf $ZIPBALL && mkdir -p $(dirname $ZIPBALL) 101 | cd $(dirname $TMPDIR) 102 | 103 | cp -r "$TMPDIR" "$FIXDIR" 104 | zip $ZIPBALL -r ./$(basename $FIXDIR) 105 | rm -rf $FIXDIR 106 | 107 | exit 0 108 | -------------------------------------------------------------------------------- /assets/vendor/jade/runtime.js: -------------------------------------------------------------------------------- 1 | 2 | jade = (function(exports){ 3 | /*! 4 | * Jade - runtime 5 | * Copyright(c) 2010 TJ Holowaychuk 6 | * MIT Licensed 7 | */ 8 | 9 | /** 10 | * Lame Array.isArray() polyfill for now. 11 | */ 12 | 13 | if (!Array.isArray) { 14 | Array.isArray = function(arr){ 15 | return '[object Array]' == Object.prototype.toString.call(arr); 16 | }; 17 | } 18 | 19 | /** 20 | * Lame Object.keys() polyfill for now. 21 | */ 22 | 23 | if (!Object.keys) { 24 | Object.keys = function(obj){ 25 | var arr = []; 26 | for (var key in obj) { 27 | if (obj.hasOwnProperty(key)) { 28 | arr.push(key); 29 | } 30 | } 31 | return arr; 32 | } 33 | } 34 | 35 | /** 36 | * Render the given attributes object. 37 | * 38 | * @param {Object} obj 39 | * @param {Object} escaped 40 | * @return {String} 41 | * @api private 42 | */ 43 | 44 | exports.attrs = function attrs(obj, escaped){ 45 | var buf = [] 46 | , terse = obj.terse; 47 | 48 | delete obj.terse; 49 | var keys = Object.keys(obj) 50 | , len = keys.length; 51 | 52 | if (len) { 53 | buf.push(''); 54 | for (var i = 0; i < len; ++i) { 55 | var key = keys[i] 56 | , val = obj[key]; 57 | 58 | if ('boolean' == typeof val || null == val) { 59 | if (val) { 60 | terse 61 | ? buf.push(key) 62 | : buf.push(key + '="' + key + '"'); 63 | } 64 | } else if (0 == key.indexOf('data') && 'string' != typeof val) { 65 | buf.push(key + "='" + JSON.stringify(val) + "'"); 66 | } else if ('class' == key && Array.isArray(val)) { 67 | buf.push(key + '="' + exports.escape(val.join(' ')) + '"'); 68 | } else if (escaped[key]) { 69 | buf.push(key + '="' + exports.escape(val) + '"'); 70 | } else { 71 | buf.push(key + '="' + val + '"'); 72 | } 73 | } 74 | } 75 | 76 | return buf.join(' '); 77 | }; 78 | 79 | /** 80 | * Escape the given string of `html`. 81 | * 82 | * @param {String} html 83 | * @return {String} 84 | * @api private 85 | */ 86 | 87 | exports.escape = function escape(html){ 88 | return String(html) 89 | .replace(/&(?!\w+;)/g, '&') 90 | .replace(//g, '>') 92 | .replace(/"/g, '"'); 93 | }; 94 | 95 | /** 96 | * Re-throw the given `err` in context to the 97 | * the jade in `filename` at the given `lineno`. 98 | * 99 | * @param {Error} err 100 | * @param {String} filename 101 | * @param {String} lineno 102 | * @api private 103 | */ 104 | 105 | exports.rethrow = function rethrow(err, filename, lineno){ 106 | if (!filename) throw err; 107 | 108 | var context = 3 109 | , str = require('fs').readFileSync(filename, 'utf8') 110 | , lines = str.split('\n') 111 | , start = Math.max(lineno - context, 0) 112 | , end = Math.min(lines.length, lineno + context); 113 | 114 | // Error context 115 | var context = lines.slice(start, end).map(function(line, i){ 116 | var curr = i + start + 1; 117 | return (curr == lineno ? ' > ' : ' ') 118 | + curr 119 | + '| ' 120 | + line; 121 | }).join('\n'); 122 | 123 | // Alter exception message 124 | err.path = filename; 125 | err.message = (filename || 'Jade') + ':' + lineno 126 | + '\n' + context + '\n\n' + err.message; 127 | throw err; 128 | }; 129 | 130 | return exports; 131 | 132 | })({}); -------------------------------------------------------------------------------- /assets/vendor/bootstrap/src/less/progress-bars.less: -------------------------------------------------------------------------------- 1 | // 2 | // Progress bars 3 | // -------------------------------------------------- 4 | 5 | 6 | // ANIMATIONS 7 | // ---------- 8 | 9 | // Webkit 10 | @-webkit-keyframes progress-bar-stripes { 11 | from { background-position: 40px 0; } 12 | to { background-position: 0 0; } 13 | } 14 | 15 | // Firefox 16 | @-moz-keyframes progress-bar-stripes { 17 | from { background-position: 40px 0; } 18 | to { background-position: 0 0; } 19 | } 20 | 21 | // IE9 22 | @-ms-keyframes progress-bar-stripes { 23 | from { background-position: 40px 0; } 24 | to { background-position: 0 0; } 25 | } 26 | 27 | // Opera 28 | @-o-keyframes progress-bar-stripes { 29 | from { background-position: 0 0; } 30 | to { background-position: 40px 0; } 31 | } 32 | 33 | // Spec 34 | @keyframes progress-bar-stripes { 35 | from { background-position: 40px 0; } 36 | to { background-position: 0 0; } 37 | } 38 | 39 | 40 | 41 | // THE BARS 42 | // -------- 43 | 44 | // Outer container 45 | .progress { 46 | overflow: hidden; 47 | height: @baseLineHeight; 48 | margin-bottom: @baseLineHeight; 49 | #gradient > .vertical(#f5f5f5, #f9f9f9); 50 | .box-shadow(inset 0 1px 2px rgba(0,0,0,.1)); 51 | .border-radius(4px); 52 | } 53 | 54 | // Bar of progress 55 | .progress .bar { 56 | width: 0%; 57 | height: 100%; 58 | color: @white; 59 | float: left; 60 | font-size: 12px; 61 | text-align: center; 62 | text-shadow: 0 -1px 0 rgba(0,0,0,.25); 63 | #gradient > .vertical(#149bdf, #0480be); 64 | .box-shadow(inset 0 -1px 0 rgba(0,0,0,.15)); 65 | .box-sizing(border-box); 66 | .transition(width .6s ease); 67 | } 68 | .progress .bar + .bar { 69 | .box-shadow(inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15)); 70 | } 71 | 72 | // Striped bars 73 | .progress-striped .bar { 74 | #gradient > .striped(#149bdf); 75 | .background-size(40px 40px); 76 | } 77 | 78 | // Call animation for the active one 79 | .progress.active .bar { 80 | -webkit-animation: progress-bar-stripes 2s linear infinite; 81 | -moz-animation: progress-bar-stripes 2s linear infinite; 82 | -ms-animation: progress-bar-stripes 2s linear infinite; 83 | -o-animation: progress-bar-stripes 2s linear infinite; 84 | animation: progress-bar-stripes 2s linear infinite; 85 | } 86 | 87 | 88 | 89 | // COLORS 90 | // ------ 91 | 92 | // Danger (red) 93 | .progress-danger .bar, .progress .bar-danger { 94 | #gradient > .vertical(#ee5f5b, #c43c35); 95 | } 96 | .progress-danger.progress-striped .bar, .progress-striped .bar-danger { 97 | #gradient > .striped(#ee5f5b); 98 | } 99 | 100 | // Success (green) 101 | .progress-success .bar, .progress .bar-success { 102 | #gradient > .vertical(#62c462, #57a957); 103 | } 104 | .progress-success.progress-striped .bar, .progress-striped .bar-success { 105 | #gradient > .striped(#62c462); 106 | } 107 | 108 | // Info (teal) 109 | .progress-info .bar, .progress .bar-info { 110 | #gradient > .vertical(#5bc0de, #339bb9); 111 | } 112 | .progress-info.progress-striped .bar, .progress-striped .bar-info { 113 | #gradient > .striped(#5bc0de); 114 | } 115 | 116 | // Warning (orange) 117 | .progress-warning .bar, .progress .bar-warning { 118 | #gradient > .vertical(lighten(@orange, 15%), @orange); 119 | } 120 | .progress-warning.progress-striped .bar, .progress-striped .bar-warning { 121 | #gradient > .striped(lighten(@orange, 15%)); 122 | } 123 | -------------------------------------------------------------------------------- /assets/vendor/bootstrap/src/js/bootstrap-popover.js: -------------------------------------------------------------------------------- 1 | /* =========================================================== 2 | * bootstrap-popover.js v2.1.1 3 | * http://twitter.github.com/bootstrap/javascript.html#popovers 4 | * =========================================================== 5 | * Copyright 2012 Twitter, Inc. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * =========================================================== */ 19 | 20 | 21 | !function ($) { 22 | 23 | "use strict"; // jshint ;_; 24 | 25 | 26 | /* POPOVER PUBLIC CLASS DEFINITION 27 | * =============================== */ 28 | 29 | var Popover = function (element, options) { 30 | this.init('popover', element, options) 31 | } 32 | 33 | 34 | /* NOTE: POPOVER EXTENDS BOOTSTRAP-TOOLTIP.js 35 | ========================================== */ 36 | 37 | Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype, { 38 | 39 | constructor: Popover 40 | 41 | , setContent: function () { 42 | var $tip = this.tip() 43 | , title = this.getTitle() 44 | , content = this.getContent() 45 | 46 | $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title) 47 | $tip.find('.popover-content > *')[this.options.html ? 'html' : 'text'](content) 48 | 49 | $tip.removeClass('fade top bottom left right in') 50 | } 51 | 52 | , hasContent: function () { 53 | return this.getTitle() || this.getContent() 54 | } 55 | 56 | , getContent: function () { 57 | var content 58 | , $e = this.$element 59 | , o = this.options 60 | 61 | content = $e.attr('data-content') 62 | || (typeof o.content == 'function' ? o.content.call($e[0]) : o.content) 63 | 64 | return content 65 | } 66 | 67 | , tip: function () { 68 | if (!this.$tip) { 69 | this.$tip = $(this.options.template) 70 | } 71 | return this.$tip 72 | } 73 | 74 | , destroy: function () { 75 | this.hide().$element.off('.' + this.type).removeData(this.type) 76 | } 77 | 78 | }) 79 | 80 | 81 | /* POPOVER PLUGIN DEFINITION 82 | * ======================= */ 83 | 84 | $.fn.popover = function (option) { 85 | return this.each(function () { 86 | var $this = $(this) 87 | , data = $this.data('popover') 88 | , options = typeof option == 'object' && option 89 | if (!data) $this.data('popover', (data = new Popover(this, options))) 90 | if (typeof option == 'string') data[option]() 91 | }) 92 | } 93 | 94 | $.fn.popover.Constructor = Popover 95 | 96 | $.fn.popover.defaults = $.extend({} , $.fn.tooltip.defaults, { 97 | placement: 'right' 98 | , trigger: 'click' 99 | , content: '' 100 | , template: '

    ' 101 | }) 102 | 103 | }(window.jQuery); -------------------------------------------------------------------------------- /assets/vendor/bootstrap/src/less/reset.less: -------------------------------------------------------------------------------- 1 | // 2 | // Modals 3 | // Adapted from http://github.com/necolas/normalize.css 4 | // -------------------------------------------------- 5 | 6 | 7 | // Display in IE6-9 and FF3 8 | // ------------------------- 9 | 10 | article, 11 | aside, 12 | details, 13 | figcaption, 14 | figure, 15 | footer, 16 | header, 17 | hgroup, 18 | nav, 19 | section { 20 | display: block; 21 | } 22 | 23 | // Display block in IE6-9 and FF3 24 | // ------------------------- 25 | 26 | audio, 27 | canvas, 28 | video { 29 | display: inline-block; 30 | *display: inline; 31 | *zoom: 1; 32 | } 33 | 34 | // Prevents modern browsers from displaying 'audio' without controls 35 | // ------------------------- 36 | 37 | audio:not([controls]) { 38 | display: none; 39 | } 40 | 41 | // Base settings 42 | // ------------------------- 43 | 44 | html { 45 | font-size: 100%; 46 | -webkit-text-size-adjust: 100%; 47 | -ms-text-size-adjust: 100%; 48 | } 49 | // Focus states 50 | a:focus { 51 | .tab-focus(); 52 | } 53 | // Hover & Active 54 | a:hover, 55 | a:active { 56 | outline: 0; 57 | } 58 | 59 | // Prevents sub and sup affecting line-height in all browsers 60 | // ------------------------- 61 | 62 | sub, 63 | sup { 64 | position: relative; 65 | font-size: 75%; 66 | line-height: 0; 67 | vertical-align: baseline; 68 | } 69 | sup { 70 | top: -0.5em; 71 | } 72 | sub { 73 | bottom: -0.25em; 74 | } 75 | 76 | // Img border in a's and image quality 77 | // ------------------------- 78 | 79 | img { 80 | /* Responsive images (ensure images don't scale beyond their parents) */ 81 | max-width: 100%; /* Part 1: Set a maxium relative to the parent */ 82 | width: auto\9; /* IE7-8 need help adjusting responsive images */ 83 | height: auto; /* Part 2: Scale the height according to the width, otherwise you get stretching */ 84 | 85 | vertical-align: middle; 86 | border: 0; 87 | -ms-interpolation-mode: bicubic; 88 | } 89 | 90 | // Prevent max-width from affecting Google Maps 91 | #map_canvas img { 92 | max-width: none; 93 | } 94 | 95 | // Forms 96 | // ------------------------- 97 | 98 | // Font size in all browsers, margin changes, misc consistency 99 | button, 100 | input, 101 | select, 102 | textarea { 103 | margin: 0; 104 | font-size: 100%; 105 | vertical-align: middle; 106 | } 107 | button, 108 | input { 109 | *overflow: visible; // Inner spacing ie IE6/7 110 | line-height: normal; // FF3/4 have !important on line-height in UA stylesheet 111 | } 112 | button::-moz-focus-inner, 113 | input::-moz-focus-inner { // Inner padding and border oddities in FF3/4 114 | padding: 0; 115 | border: 0; 116 | } 117 | button, 118 | input[type="button"], 119 | input[type="reset"], 120 | input[type="submit"] { 121 | cursor: pointer; // Cursors on all buttons applied consistently 122 | -webkit-appearance: button; // Style clickable inputs in iOS 123 | } 124 | input[type="search"] { // Appearance in Safari/Chrome 125 | -webkit-box-sizing: content-box; 126 | -moz-box-sizing: content-box; 127 | box-sizing: content-box; 128 | -webkit-appearance: textfield; 129 | } 130 | input[type="search"]::-webkit-search-decoration, 131 | input[type="search"]::-webkit-search-cancel-button { 132 | -webkit-appearance: none; // Inner-padding issues in Chrome OSX, Safari 5 133 | } 134 | textarea { 135 | overflow: auto; // Remove vertical scrollbar in IE6-9 136 | vertical-align: top; // Readability and alignment cross-browser 137 | } 138 | -------------------------------------------------------------------------------- /client/models/glyph.js: -------------------------------------------------------------------------------- 1 | /*global window, nodeca, jQuery, Handlebars, Backbone, $, _*/ 2 | 3 | 4 | "use strict"; 5 | 6 | 7 | // SEE: http://www.unicode.org/versions/Unicode6.0.0/ch02.pdf 8 | // 9 | // In the Unicode Standard, the codespace consists of the integers 10 | // from 0 to 10FFFF16, comprising 1,114,112 code points available for 11 | // assigning the repertoire of abstract characters. 12 | // ... 13 | // Noncharacters. Sixty-six code points are not used to encode characters. 14 | // Noncharacters consist of U+FDD0..U+FDEF and any code point ending in the 15 | // value FFFE16 or FFFF16- that is, U+FFFE, U+FFFF, U+1FFFE, U+1FFFF, ... 16 | // U+10FFFE, U+10FFFF. 17 | function is_valid_code(code) { 18 | var valid = (0 <= code && code <= 0x10ffff); 19 | 20 | valid = (valid && (0xfdd0 > code || code > 0xfdef)); 21 | valid = (valid && code % 0x10000 !== 0xfffe); 22 | valid = (valid && code % 0x10000 !== 0xffff); 23 | 24 | return valid; 25 | } 26 | 27 | 28 | // resets (from source) `name` attribute, if it was provided as null 29 | function preprocess_attribute(source, attrs, name, options) { 30 | if (null === attrs[name]) { 31 | attrs[name] = source[name]; 32 | // `options = {unset: true}` when `#unset()` 33 | delete options.unset; 34 | } 35 | } 36 | 37 | 38 | module.exports = Backbone.Model.extend({ 39 | defaults: function () { 40 | return { 41 | font : null, 42 | source : null, 43 | code : null, 44 | css : null, 45 | selected : false 46 | }; 47 | }, 48 | 49 | 50 | idAttribute: 'uid', 51 | 52 | 53 | initialize: function (attributes) { 54 | var tags = (attributes.source || {}).search || attributes.search || []; 55 | this.keywords = tags.join(' '); 56 | }, 57 | 58 | 59 | set: function(key, value, options) { 60 | var attrs, source; 61 | 62 | if (_.isObject(key) || null === key) { 63 | attrs = key; 64 | options = value; 65 | } else { 66 | attrs = {}; 67 | attrs[key] = value; 68 | } 69 | 70 | // make sure options is an object 71 | options = options || {}; 72 | 73 | // reset code and css to source values if unset 74 | source = this.get('source') || attrs.source || {}; 75 | preprocess_attribute(source, attrs, 'code', options); 76 | preprocess_attribute(source, attrs, 'css', options); 77 | 78 | return Backbone.Model.prototype.set.call(this, attrs, options); 79 | }, 80 | 81 | 82 | isModified: function isModified() { 83 | var source = this.get('source'), 84 | modified = false; 85 | 86 | modified = modified || this.get('code') !== source.code; 87 | modified = modified || this.get('css') !== source.css; 88 | 89 | return modified; 90 | }, 91 | 92 | 93 | validate: function validate(attributes) { 94 | if (!is_valid_code(attributes.code)) { 95 | nodeca.logger.debug("models.glyph.validate: bad char code:", 96 | attributes.code); 97 | return "Bad char code: " + attributes.code; 98 | } 99 | 100 | return null; 101 | }, 102 | 103 | 104 | toggle: function (key, val) { 105 | if (undefined === val) { 106 | val = !this.get(key); 107 | } 108 | 109 | this.set(key, !!val); 110 | }, 111 | 112 | 113 | // Stub to prevent Backbone from reading or saving the model to the server. 114 | // Backbone calls `Backbone.sync()` function (on fetch/save/destroy) 115 | // if model doesn't have own `sync()` method. 116 | sync: function sync() {} 117 | }); 118 | -------------------------------------------------------------------------------- /assets/vendor/bootstrap/src/less/popovers.less: -------------------------------------------------------------------------------- 1 | // 2 | // Popovers 3 | // -------------------------------------------------- 4 | 5 | 6 | .popover { 7 | position: absolute; 8 | top: 0; 9 | left: 0; 10 | z-index: @zindexPopover; 11 | display: none; 12 | width: 236px; 13 | padding: 1px; 14 | background-color: @popoverBackground; 15 | -webkit-background-clip: padding-box; 16 | -moz-background-clip: padding; 17 | background-clip: padding-box; 18 | border: 1px solid #ccc; 19 | border: 1px solid rgba(0,0,0,.2); 20 | .border-radius(6px); 21 | .box-shadow(0 5px 10px rgba(0,0,0,.2)); 22 | 23 | // Offset the popover to account for the popover arrow 24 | &.top { margin-bottom: 10px; } 25 | &.right { margin-left: 10px; } 26 | &.bottom { margin-top: 10px; } 27 | &.left { margin-right: 10px; } 28 | 29 | } 30 | 31 | .popover-title { 32 | margin: 0; // reset heading margin 33 | padding: 8px 14px; 34 | font-size: 14px; 35 | font-weight: normal; 36 | line-height: 18px; 37 | background-color: @popoverTitleBackground; 38 | border-bottom: 1px solid darken(@popoverTitleBackground, 5%); 39 | .border-radius(5px 5px 0 0); 40 | } 41 | 42 | .popover-content { 43 | padding: 9px 14px; 44 | p, ul, ol { 45 | margin-bottom: 0; 46 | } 47 | } 48 | 49 | // Arrows 50 | .popover .arrow, 51 | .popover .arrow:after { 52 | position: absolute; 53 | display: inline-block; 54 | width: 0; 55 | height: 0; 56 | border-color: transparent; 57 | border-style: solid; 58 | } 59 | .popover .arrow:after { 60 | content: ""; 61 | z-index: -1; 62 | } 63 | 64 | .popover { 65 | &.top .arrow { 66 | bottom: -@popoverArrowWidth; 67 | left: 50%; 68 | margin-left: -@popoverArrowWidth; 69 | border-width: @popoverArrowWidth @popoverArrowWidth 0; 70 | border-top-color: @popoverArrowColor; 71 | &:after { 72 | border-width: @popoverArrowOuterWidth @popoverArrowOuterWidth 0; 73 | border-top-color: @popoverArrowOuterColor; 74 | bottom: -1px; 75 | left: -@popoverArrowOuterWidth; 76 | } 77 | } 78 | &.right .arrow { 79 | top: 50%; 80 | left: -@popoverArrowWidth; 81 | margin-top: -@popoverArrowWidth; 82 | border-width: @popoverArrowWidth @popoverArrowWidth @popoverArrowWidth 0; 83 | border-right-color: @popoverArrowColor; 84 | &:after { 85 | border-width: @popoverArrowOuterWidth @popoverArrowOuterWidth @popoverArrowOuterWidth 0; 86 | border-right-color: @popoverArrowOuterColor; 87 | bottom: -@popoverArrowOuterWidth; 88 | left: -1px; 89 | } 90 | } 91 | &.bottom .arrow { 92 | top: -@popoverArrowWidth; 93 | left: 50%; 94 | margin-left: -@popoverArrowWidth; 95 | border-width: 0 @popoverArrowWidth @popoverArrowWidth; 96 | border-bottom-color: @popoverArrowColor; 97 | &:after { 98 | border-width: 0 @popoverArrowOuterWidth @popoverArrowOuterWidth; 99 | border-bottom-color: @popoverArrowOuterColor; 100 | top: -1px; 101 | left: -@popoverArrowOuterWidth; 102 | } 103 | } 104 | &.left .arrow { 105 | top: 50%; 106 | right: -@popoverArrowWidth; 107 | margin-top: -@popoverArrowWidth; 108 | border-width: @popoverArrowWidth 0 @popoverArrowWidth @popoverArrowWidth; 109 | border-left-color: @popoverArrowColor; 110 | &:after { 111 | border-width: @popoverArrowOuterWidth 0 @popoverArrowOuterWidth @popoverArrowOuterWidth; 112 | border-left-color: @popoverArrowOuterColor; 113 | bottom: -@popoverArrowOuterWidth; 114 | right: -1px; 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /assets/embedded_fonts/fontface-embedded.css.ejs: -------------------------------------------------------------------------------- 1 | .font-embedded-0 { font-family: 'entypo'; } 2 | .font-embedded-1 { font-family: 'fontawesome'; } 3 | .font-embedded-2 { font-family: 'iconic'; } 4 | .font-embedded-3 { font-family: 'typicons'; } 5 | .font-embedded-4 { font-family: 'modernpics'; } 6 | .font-embedded-5 { font-family: 'websymbols'; } 7 | .font-embedded-6 { font-family: 'brandico'; } 8 | 9 | @font-face { 10 | font-family: 'entypo'; 11 | src: url('<%= asset_path("entypo.eot") %>'); 12 | src: url('<%= asset_path("entypo.eot") %>?#iefix') format('embedded-opentype'), 13 | url('<%= asset_path("entypo.woff") %>') format('woff'), 14 | url('<%= asset_path("entypo.ttf") %>') format('truetype'), 15 | url('<%= asset_path("entypo.svg") %>#entypo') format('svg'); 16 | font-weight: normal; 17 | font-style: normal; 18 | } 19 | 20 | @font-face { 21 | font-family: 'fontawesome'; 22 | src: url('<%= asset_path("fontawesome.eot") %>'); 23 | src: url('<%= asset_path("fontawesome.eot") %>?#iefix') format('embedded-opentype'), 24 | url('<%= asset_path("fontawesome.woff") %>') format('woff'), 25 | url('<%= asset_path("fontawesome.ttf") %>') format('truetype'), 26 | url('<%= asset_path("fontawesome.svg") %>#fontawesome') format('svg'); 27 | font-weight: normal; 28 | font-style: normal; 29 | } 30 | 31 | @font-face { 32 | font-family: 'iconic'; 33 | src: url('<%= asset_path("iconic.eot") %>'); 34 | src: url('<%= asset_path("iconic.eot") %>?#iefix') format('embedded-opentype'), 35 | url('<%= asset_path("iconic.woff") %>') format('woff'), 36 | url('<%= asset_path("iconic.ttf") %>') format('truetype'), 37 | url('<%= asset_path("iconic.svg") %>#iconic') format('svg'); 38 | font-weight: normal; 39 | font-style: normal; 40 | } 41 | 42 | @font-face { 43 | font-family: 'typicons'; 44 | src: url('<%= asset_path("typicons.eot") %>'); 45 | src: url('<%= asset_path("typicons.eot") %>?#iefix') format('embedded-opentype'), 46 | url('<%= asset_path("typicons.woff") %>') format('woff'), 47 | url('<%= asset_path("typicons.ttf") %>') format('truetype'), 48 | url('<%= asset_path("typicons.svg") %>#typicons') format('svg'); 49 | font-weight: normal; 50 | font-style: normal; 51 | } 52 | 53 | @font-face { 54 | font-family: 'modernpics'; 55 | src: url('<%= asset_path("modernpics.eot") %>'); 56 | src: url('<%= asset_path("modernpics.eot") %>?#iefix') format('embedded-opentype'), 57 | url('<%= asset_path("modernpics.woff") %>') format('woff'), 58 | url('<%= asset_path("modernpics.ttf") %>') format('truetype'), 59 | url('<%= asset_path("modernpics.svg") %>#modernpics') format('svg'); 60 | font-weight: normal; 61 | font-style: normal; 62 | } 63 | 64 | @font-face { 65 | font-family: 'websymbols'; 66 | src: url('<%= asset_path("websymbols.eot") %>'); 67 | src: url('<%= asset_path("websymbols.eot") %>?#iefix') format('embedded-opentype'), 68 | url('<%= asset_path("websymbols.woff") %>') format('woff'), 69 | url('<%= asset_path("websymbols.ttf") %>') format('truetype'), 70 | url('<%= asset_path("websymbols.svg") %>#websymbols') format('svg'); 71 | font-weight: normal; 72 | font-style: normal; 73 | } 74 | 75 | @font-face { 76 | font-family: 'brandico'; 77 | src: url('<%= asset_path("brandico.eot") %>'); 78 | src: url('<%= asset_path("brandico.eot") %>?#iefix') format('embedded-opentype'), 79 | url('<%= asset_path("brandico.woff") %>') format('woff'), 80 | url('<%= asset_path("brandico.ttf") %>') format('truetype'), 81 | url('<%= asset_path("brandico.svg") %>#brandico') format('svg'); 82 | font-weight: normal; 83 | font-style: normal; 84 | } --------------------------------------------------------------------------------